tlspretense 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +6 -0
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +41 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +231 -0
- data/Rakefile +44 -0
- data/bin/makeder.sh +6 -0
- data/bin/tlspretense +7 -0
- data/bin/view.sh +3 -0
- data/doc/general_setup.rdoc +288 -0
- data/doc/linux_setup.rdoc +64 -0
- data/lib/certmaker.rb +61 -0
- data/lib/certmaker/certificate_factory.rb +106 -0
- data/lib/certmaker/certificate_suite_generator.rb +120 -0
- data/lib/certmaker/ext_core/hash_indifferent_fetch.rb +12 -0
- data/lib/certmaker/runner.rb +27 -0
- data/lib/certmaker/tasks.rb +20 -0
- data/lib/packetthief.rb +167 -0
- data/lib/packetthief/handlers.rb +14 -0
- data/lib/packetthief/handlers/abstract_ssl_handler.rb +249 -0
- data/lib/packetthief/handlers/proxy_redirector.rb +26 -0
- data/lib/packetthief/handlers/ssl_client.rb +87 -0
- data/lib/packetthief/handlers/ssl_server.rb +174 -0
- data/lib/packetthief/handlers/ssl_smart_proxy.rb +143 -0
- data/lib/packetthief/handlers/ssl_transparent_proxy.rb +225 -0
- data/lib/packetthief/handlers/transparent_proxy.rb +183 -0
- data/lib/packetthief/impl.rb +11 -0
- data/lib/packetthief/impl/ipfw.rb +140 -0
- data/lib/packetthief/impl/manual.rb +54 -0
- data/lib/packetthief/impl/netfilter.rb +109 -0
- data/lib/packetthief/impl/pf_divert.rb +168 -0
- data/lib/packetthief/impl/pf_rdr.rb +192 -0
- data/lib/packetthief/logging.rb +49 -0
- data/lib/packetthief/redirect_rule.rb +29 -0
- data/lib/packetthief/util.rb +36 -0
- data/lib/ssl_test.rb +21 -0
- data/lib/ssl_test/app_context.rb +17 -0
- data/lib/ssl_test/certificate_manager.rb +33 -0
- data/lib/ssl_test/config.rb +79 -0
- data/lib/ssl_test/ext_core/io_raw_input.rb +31 -0
- data/lib/ssl_test/input_handler.rb +35 -0
- data/lib/ssl_test/runner.rb +110 -0
- data/lib/ssl_test/runner_options.rb +68 -0
- data/lib/ssl_test/ssl_test_case.rb +46 -0
- data/lib/ssl_test/ssl_test_report.rb +24 -0
- data/lib/ssl_test/ssl_test_result.rb +30 -0
- data/lib/ssl_test/test_listener.rb +140 -0
- data/lib/ssl_test/test_manager.rb +116 -0
- data/lib/tlspretense.rb +13 -0
- data/lib/tlspretense/app.rb +52 -0
- data/lib/tlspretense/init_runner.rb +115 -0
- data/lib/tlspretense/skel/ca/goodcacert.pem +19 -0
- data/lib/tlspretense/skel/ca/goodcakey.pem +27 -0
- data/lib/tlspretense/skel/config.yml +523 -0
- data/lib/tlspretense/version.rb +3 -0
- data/packetthief_examples/em_ssl_test.rb +73 -0
- data/packetthief_examples/redirector.rb +29 -0
- data/packetthief_examples/setup_iptables.sh +24 -0
- data/packetthief_examples/ssl_client_simple.rb +27 -0
- data/packetthief_examples/ssl_server_simple.rb +44 -0
- data/packetthief_examples/ssl_smart_proxy.rb +115 -0
- data/packetthief_examples/ssl_transparent_proxy.rb +97 -0
- data/packetthief_examples/transparent_proxy.rb +56 -0
- data/spec/packetthief/impl/ipfw_spec.rb +98 -0
- data/spec/packetthief/impl/manual_spec.rb +65 -0
- data/spec/packetthief/impl/netfilter_spec.rb +66 -0
- data/spec/packetthief/impl/pf_divert_spec.rb +82 -0
- data/spec/packetthief/impl/pf_rdr_spec.rb +133 -0
- data/spec/packetthief/logging_spec.rb +78 -0
- data/spec/packetthief_spec.rb +47 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/ssl_test/certificate_manager_spec.rb +222 -0
- data/spec/ssl_test/config_spec.rb +76 -0
- data/spec/ssl_test/runner_spec.rb +360 -0
- data/spec/ssl_test/ssl_test_case_spec.rb +113 -0
- data/spec/ssl_test/test_listener_spec.rb +199 -0
- data/spec/ssl_test/test_manager_spec.rb +324 -0
- data/tlspretense.gemspec +35 -0
- metadata +262 -0
@@ -0,0 +1,11 @@
|
|
1
|
+
module PacketThief
|
2
|
+
# PacketThief implementations. Each one contains the implementation details
|
3
|
+
# for working with a given firewall.
|
4
|
+
module Impl
|
5
|
+
autoload :Manual, 'packetthief/impl/manual'
|
6
|
+
autoload :Netfilter, 'packetthief/impl/netfilter'
|
7
|
+
autoload :Ipfw, 'packetthief/impl/ipfw'
|
8
|
+
autoload :PFDivert, 'packetthief/impl/pf_divert'
|
9
|
+
autoload :PFRdr, 'packetthief/impl/pf_rdr'
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module PacketThief
|
4
|
+
module Impl
|
5
|
+
# Use Ipfw to redirect traffic.
|
6
|
+
#
|
7
|
+
# Needed in at least Mac OS X 10.6 and later[1]?:
|
8
|
+
# sysctl -w net.inet.ip.scopedroute=0
|
9
|
+
#
|
10
|
+
# [1]: https://trac.macports.org/wiki/howto/SetupInterceptionSquid
|
11
|
+
#
|
12
|
+
# Sample rule:
|
13
|
+
#
|
14
|
+
# sudo ipfw add 1013 fwd 127.0.0.1,3129 tcp from any to any 80 recv INTERFACE
|
15
|
+
#
|
16
|
+
# Note that in Mac OS X 10.7 Lion, Apple still includes ipfw, but they are
|
17
|
+
# using pfctl to do network firewalling and routing.
|
18
|
+
class Ipfw
|
19
|
+
module IpfwRuleHandler
|
20
|
+
|
21
|
+
include Logging
|
22
|
+
|
23
|
+
attr_accessor :active_rules
|
24
|
+
|
25
|
+
# Executes a rule and holds onto it for later removal.
|
26
|
+
def run(rule)
|
27
|
+
@active_rules ||= []
|
28
|
+
|
29
|
+
args = ['/sbin/ipfw', 'add', 'set', '30'] # TODO: make the rule number customizable
|
30
|
+
|
31
|
+
args.concat rule.to_ipfw_command
|
32
|
+
|
33
|
+
# Lion claims net.inet.ip.scopedroute is read only. According to: http://pastebin.com/NzAARKVG it is possible to set it at boot time:
|
34
|
+
# /Library/Preferences/SystemConfiguration/com.apple.Boot.plist:
|
35
|
+
# <dict>
|
36
|
+
# <key>Kernel Flags</key>
|
37
|
+
# <string>net.inet.ip.scopedroute=0</string>
|
38
|
+
# </dict>
|
39
|
+
if /darwin/ === RUBY_PLATFORM
|
40
|
+
unless system(*%W{/usr/sbin/sysctl -w net.inet.ip.scopedroute=0})
|
41
|
+
if /darwin1[1-9]/ === RUBY_PLATFORM
|
42
|
+
logerror "Failed to set net.inet.ip.scopedroute=0. As of Lion, this is marked read-only after boot. However, you might be able to get IPFW working by setting the sysctl in /Library/Preferences/SystemConfiguration/com.apple.Boot.plist"
|
43
|
+
else
|
44
|
+
raise "Command /usr/sbin/sysctl -w net.inet.ip.scopedroute=0 exited with error code #{$?.inspect}."
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# run the command
|
50
|
+
unless system(*args)
|
51
|
+
raise "Command #{args.inspect} exited with error code #{$?.inspect}"
|
52
|
+
end
|
53
|
+
|
54
|
+
@active_rules << rule
|
55
|
+
end
|
56
|
+
|
57
|
+
# Reverts all executed rules that this handler knows about.
|
58
|
+
def revert
|
59
|
+
return if @active_rules == nil or @active_rules.empty?
|
60
|
+
|
61
|
+
# @active_rules.each do |rule|
|
62
|
+
args = ['/sbin/ipfw', 'del', 'set', '30']
|
63
|
+
# args.concat rule.to_ipfw_command
|
64
|
+
unless system(*args)
|
65
|
+
raise "Command #{args.inspect} exited with error code #{$?.inspect}"
|
66
|
+
end
|
67
|
+
# end
|
68
|
+
|
69
|
+
@active_rules = []
|
70
|
+
end
|
71
|
+
end
|
72
|
+
extend IpfwRuleHandler
|
73
|
+
|
74
|
+
class IpfwRule < RedirectRule
|
75
|
+
|
76
|
+
attr_accessor :rule_number
|
77
|
+
|
78
|
+
def initialize(handler, rule_number=nil)
|
79
|
+
super(handler)
|
80
|
+
@rule_number = rule_number
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_ipfw_command
|
84
|
+
args = []
|
85
|
+
|
86
|
+
if self.redirectspec
|
87
|
+
if self.redirectspec.has_key? :to_ports
|
88
|
+
args << 'fwd'
|
89
|
+
args << "127.0.0.1,#{self.redirectspec[:to_ports].to_s}"
|
90
|
+
else
|
91
|
+
raise "Rule lacks a valid redirect: #{self.inspect}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
if self.rulespec
|
96
|
+
args << self.rulespec.fetch(:protocol,'ip').to_s
|
97
|
+
|
98
|
+
args << 'from'
|
99
|
+
args << self.rulespec.fetch(:source_address, 'any').to_s
|
100
|
+
args << self.rulespec[:source_port].to_s if self.rulespec.has_key? :source_port
|
101
|
+
|
102
|
+
args << 'to'
|
103
|
+
args << self.rulespec.fetch(:dest_address, 'any').to_s
|
104
|
+
args << 'dst-port' << self.rulespec[:dest_port].to_s if self.rulespec.has_key? :dest_port
|
105
|
+
|
106
|
+
args << 'recv' << self.rulespec[:in_interface].to_s if self.rulespec.has_key? :in_interface
|
107
|
+
end
|
108
|
+
|
109
|
+
args
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.redirect(args={})
|
114
|
+
rule = IpfwRule.new(self)
|
115
|
+
rule.redirect(args)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns the [port, host] for the original destination of +sock+.
|
119
|
+
#
|
120
|
+
# +Sock+ can be a Ruby socket or an EventMachine::Connection (including
|
121
|
+
# handler modules, which are mixed in to an anonymous descendent of
|
122
|
+
# EM::Connection).
|
123
|
+
#
|
124
|
+
# When Ipfw uses a fwd/forward rule to redirect a connection to a local
|
125
|
+
# socket, the destination address remains unchanged, meaning that C's
|
126
|
+
# getsockname() will return the original destination.
|
127
|
+
def self.original_dest(sock)
|
128
|
+
if sock.respond_to? :getsockname
|
129
|
+
sockname = sock.getsockname
|
130
|
+
elsif sock.respond_to? :get_sockname
|
131
|
+
sockname = sock.get_sockname
|
132
|
+
else
|
133
|
+
raise ArgumentError, "#{sock.inspect} supports neither :getsockname nor :get_sockname!"
|
134
|
+
end
|
135
|
+
Socket::unpack_sockaddr_in(sockname)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module PacketThief
|
4
|
+
module Impl
|
5
|
+
# PacketThief implementation that does apply any firewall rules. Furthermore,
|
6
|
+
# Manual.original_dest will always return a pre-configured destination address.
|
7
|
+
class Manual
|
8
|
+
module NullRuleHandler
|
9
|
+
|
10
|
+
include Logging
|
11
|
+
|
12
|
+
attr_accessor :active_rules
|
13
|
+
|
14
|
+
# Executes a rule and holds onto it for later removal.
|
15
|
+
def run(rule)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Reverts all executed rules that this handler knows about.
|
19
|
+
def revert
|
20
|
+
end
|
21
|
+
end
|
22
|
+
extend NullRuleHandler
|
23
|
+
|
24
|
+
class NullRule < RedirectRule
|
25
|
+
def initialize(handler, rule_number=nil)
|
26
|
+
super(handler)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.redirect(args={})
|
31
|
+
rule = NullRule.new(self)
|
32
|
+
rule.redirect(args)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.set_dest(host, port)
|
36
|
+
@dest_host = host
|
37
|
+
@dest_port = port
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the [port, host] for the original destination of +sock+.
|
41
|
+
#
|
42
|
+
# The Manual implementation only returns a preconfigured original
|
43
|
+
# destination. Making it only good for testing clients that only talk to a
|
44
|
+
# single remote host.
|
45
|
+
def self.original_dest(sock)
|
46
|
+
raise "You must call .set_dest(host,port) to set the original_dest in the Manual PacketThief implementation!" if @dest_host == nil or @dest_port == nil
|
47
|
+
return [ @dest_port, @dest_host ]
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
|
2
|
+
module PacketThief
|
3
|
+
module Impl
|
4
|
+
# PacketThief implemented using the Linux kernel's Netfilter.
|
5
|
+
#
|
6
|
+
# This is roughly equivalent to:
|
7
|
+
#
|
8
|
+
# echo 1 > /proc/sys/net/ipv4/ip_forward
|
9
|
+
# iptables -t nat -A PREROUTING -p tcp --destination-port <DEST> -j REDIRECT --to-ports <LISTENER>
|
10
|
+
#
|
11
|
+
# Currently only implements IPv4.
|
12
|
+
#
|
13
|
+
# Note that the listening socket must have a blank hostname. If it is set to
|
14
|
+
# 127.0.0.1, then the socket will only run on the loopback device, and
|
15
|
+
# traffic that gets redirected from another device won't reach it.
|
16
|
+
class Netfilter
|
17
|
+
|
18
|
+
# Manages IPTablesRules. It actually runs the rule, and it tracks the rule
|
19
|
+
# so it can be deleted later.
|
20
|
+
module IPTablesRuleHandler
|
21
|
+
attr_accessor :active_rules
|
22
|
+
|
23
|
+
# Executes a rule and holds onto it for later removal.
|
24
|
+
def run(rule)
|
25
|
+
@active_rules ||= []
|
26
|
+
|
27
|
+
args = ['/sbin/iptables', '-t', rule.table, '-A', rule.chain]
|
28
|
+
|
29
|
+
args.concat rule.to_netfilter_command
|
30
|
+
|
31
|
+
unless system(*args)
|
32
|
+
raise "Command #{args.inspect} exited with error code #{$?.inspect}"
|
33
|
+
end
|
34
|
+
|
35
|
+
@active_rules << rule
|
36
|
+
end
|
37
|
+
|
38
|
+
# Reverts all executed rules that this handler knows about.
|
39
|
+
def revert
|
40
|
+
return if @active_rules == nil or @active_rules.empty?
|
41
|
+
|
42
|
+
@active_rules.each do |rule|
|
43
|
+
args = ['/sbin/iptables', '-t', rule.table, '-D', rule.chain]
|
44
|
+
args.concat rule.to_netfilter_command
|
45
|
+
|
46
|
+
unless system(*args)
|
47
|
+
raise "Command #{args.inspect} exited with error code #{$?.inspect}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
@active_rules = []
|
52
|
+
end
|
53
|
+
end
|
54
|
+
extend IPTablesRuleHandler
|
55
|
+
|
56
|
+
# Adds IPTables specific details to a Redirectrule.
|
57
|
+
class IPTablesRule < RedirectRule
|
58
|
+
|
59
|
+
attr_accessor :table
|
60
|
+
attr_accessor :chain
|
61
|
+
|
62
|
+
def initialize(handler, table, chain)
|
63
|
+
super(handler)
|
64
|
+
@table = table
|
65
|
+
@chain = chain
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_netfilter_command
|
69
|
+
args = []
|
70
|
+
|
71
|
+
if self.rulespec
|
72
|
+
args << '-p' << self.rulespec[:protocol].to_s if self.rulespec.has_key? :protocol
|
73
|
+
args << '--destination-port' << self.rulespec[:dest_port].to_s if self.rulespec.has_key? :dest_port
|
74
|
+
args << '--in-interface' << self.rulespec[:in_interface].to_s if self.rulespec.has_key? :in_interface
|
75
|
+
end
|
76
|
+
|
77
|
+
if self.redirectspec
|
78
|
+
args << '-j' << 'REDIRECT'
|
79
|
+
args << '--to-ports' << self.redirectspec[:to_ports].to_s if self.redirectspec.has_key? :to_ports
|
80
|
+
end
|
81
|
+
|
82
|
+
args
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.redirect(args={})
|
88
|
+
rule = IPTablesRule.new(self,'nat','PREROUTING')
|
89
|
+
rule.redirect(args)
|
90
|
+
end
|
91
|
+
|
92
|
+
#/usr/include/linux/netfilter_ipv4.h:#define SO_ORIGINAL_DST 80
|
93
|
+
SO_ORIGINAL_DST = 80
|
94
|
+
|
95
|
+
# Returns the [port, host] for a socket or EM::Connection that whose
|
96
|
+
# connection was redirected by netfilter
|
97
|
+
def self.original_dest(socket)
|
98
|
+
if socket.respond_to? :getsockopt
|
99
|
+
sockname = socket.getsockopt(Socket::IPPROTO_IP, SO_ORIGINAL_DST)
|
100
|
+
elsif socket.respond_to? :get_sock_opt
|
101
|
+
sockname = socket.get_sock_opt(Socket::IPPROTO_IP, SO_ORIGINAL_DST)
|
102
|
+
end
|
103
|
+
Socket::unpack_sockaddr_in(sockname)
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module PacketThief
|
4
|
+
module Impl
|
5
|
+
# Untested and likely broken PacketThief implementation that uses PF's
|
6
|
+
# divert-to to redirect traffic. It is currently untested, and it requires a
|
7
|
+
# newer version of PF to redirect traffic than is available in Mac OS X 10.7
|
8
|
+
# (and probably 10.8)
|
9
|
+
#
|
10
|
+
# == Capturing Traffic
|
11
|
+
#
|
12
|
+
# It works by dynamically changing the rules in the "packetthief" anchor. To
|
13
|
+
# use it, you must add the following to your /etc/pf.conf file in the
|
14
|
+
# "Packet Filtering" section::
|
15
|
+
#
|
16
|
+
# anchor "packetthief"
|
17
|
+
#
|
18
|
+
# Then you must reload your pf config by rebooting or by executing:
|
19
|
+
#
|
20
|
+
# sudo pfctl -f /etc/pf.conf
|
21
|
+
#
|
22
|
+
# When PacketThief adds a rule, it constructs a new rule set for the
|
23
|
+
# packetthief anchor and replaces the current ruleset in the anchor by
|
24
|
+
# calling:
|
25
|
+
#
|
26
|
+
# echo "#{our rules}" | pfctl -a packetthief -f -
|
27
|
+
#
|
28
|
+
# Rules look something like:
|
29
|
+
#
|
30
|
+
# pass in on en1 proto tcp from any to any port 443 divert-to 127.0.0.1 port 54321
|
31
|
+
#
|
32
|
+
# == Acquiring the original destination
|
33
|
+
#
|
34
|
+
# According to [1], if we use a divert-to rule, we can get the original
|
35
|
+
# destination using getsockname(2) instead of having to perform ioctl
|
36
|
+
# operations on the /dev/pf pseudo-device.
|
37
|
+
#
|
38
|
+
# [1]: http://www.openbsd.org/cgi-bin/man.cgi?query=pf.conf&sektion=5&arch=&apropos=0&manpath=OpenBSD+Current
|
39
|
+
#
|
40
|
+
#
|
41
|
+
# == Alternative implementations
|
42
|
+
#
|
43
|
+
# TODO:
|
44
|
+
#
|
45
|
+
# divert-to is too new of Mac OS X 10.7 (Lion is using a relatively "old"
|
46
|
+
# implementation of PF).
|
47
|
+
#
|
48
|
+
# A possible alternative is to use rdr rules:
|
49
|
+
#
|
50
|
+
# rdr on en1 proto tcp from any to any port 443 -> 127.0.0.1 port 54321
|
51
|
+
#
|
52
|
+
# This also requires:
|
53
|
+
#
|
54
|
+
# rdr-anchor "packetthief"
|
55
|
+
#
|
56
|
+
# in /etc/pf.conf in the "Translation" section of /etc/pf.conf. We can then
|
57
|
+
# use the ioctl with DIOCNATLOOK approach that Squid uses to get a
|
58
|
+
# pfioc_natlook data structure to get the original destination of the connection.
|
59
|
+
class PFDivert
|
60
|
+
module PFDivertRuleHandler
|
61
|
+
attr_accessor :active_rules
|
62
|
+
|
63
|
+
# Executes a rule and holds onto it for later removal.
|
64
|
+
def run(rule)
|
65
|
+
@active_rules ||= []
|
66
|
+
|
67
|
+
# args = ['pfctl', 'add', 'set', '30'] # TODO: make the rule number customizable
|
68
|
+
args = ['echo']
|
69
|
+
|
70
|
+
@active_rules << rule
|
71
|
+
args << @active_rules.map { |r| r.to_pf_command.join(" ") }.join("\n")
|
72
|
+
|
73
|
+
args = args + %w{| pfctl -a packetthief -f -}
|
74
|
+
|
75
|
+
# run the command
|
76
|
+
unless system(*args)
|
77
|
+
raise "Command #{args.inspect} exited with error code #{$?.inspect}"
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
# Reverts all executed rules that this handler knows about.
|
83
|
+
def revert
|
84
|
+
return if @active_rules == nil or @active_rules.empty?
|
85
|
+
|
86
|
+
args = %W{pfctl -a packetthief -F rules}
|
87
|
+
unless system(*args)
|
88
|
+
raise "Command #{args.inspect} exited with error code #{$?.inspect}"
|
89
|
+
end
|
90
|
+
# end
|
91
|
+
|
92
|
+
@active_rules = []
|
93
|
+
end
|
94
|
+
end
|
95
|
+
extend PFDivertRuleHandler
|
96
|
+
|
97
|
+
class PFDivertRule < RedirectRule
|
98
|
+
|
99
|
+
attr_accessor :rule_number
|
100
|
+
|
101
|
+
def initialize(handler, rule_number=nil)
|
102
|
+
super(handler)
|
103
|
+
@rule_number = rule_number
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_pf_command
|
107
|
+
args = []
|
108
|
+
|
109
|
+
args << "pass" << "in"
|
110
|
+
|
111
|
+
if self.rulespec
|
112
|
+
args << 'on' << self.rulespec[:in_interface].to_s if self.rulespec.has_key? :in_interface
|
113
|
+
|
114
|
+
args << "proto" << self.rulespec.fetch(:protocol,'ip').to_s
|
115
|
+
|
116
|
+
args << 'from'
|
117
|
+
args << self.rulespec.fetch(:source_address, 'any').to_s
|
118
|
+
args << 'port' << self.rulespec[:source_port].to_s if self.rulespec.has_key? :source_port
|
119
|
+
|
120
|
+
args << 'to'
|
121
|
+
args << self.rulespec.fetch(:dest_address, 'any').to_s
|
122
|
+
args << 'port' << self.rulespec[:dest_port].to_s if self.rulespec.has_key? :dest_port
|
123
|
+
end
|
124
|
+
|
125
|
+
if self.redirectspec
|
126
|
+
if self.redirectspec.has_key? :to_ports
|
127
|
+
args << 'divert-to'
|
128
|
+
args << "127.0.0.1"
|
129
|
+
args << 'port' << self.redirectspec[:to_ports].to_s if self.redirectspec.has_key? :to_ports
|
130
|
+
else
|
131
|
+
raise "Rule lacks a valid redirect: #{self.inspect}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
args
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.redirect(args={})
|
141
|
+
rule = PFDivertRule.new(self)
|
142
|
+
rule.redirect(args)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Returns the [port, host] for the original destination of +sock+.
|
146
|
+
#
|
147
|
+
# +Sock+ can be a Ruby socket or an EventMachine::Connection (including
|
148
|
+
# handler modules, which are mixed in to an anonymous descendent of
|
149
|
+
# EM::Connection).
|
150
|
+
#
|
151
|
+
# When PF uses a divert-to[1] rule to redirect a connection to a local socket,
|
152
|
+
# the destination address remains unchanged, meaning that C's getsockname()
|
153
|
+
# will return the original destination.
|
154
|
+
# [1]: http://www.openbsd.org/cgi-bin/man.cgi?query=pf.conf&sektion=5&arch=&apropos=0&manpath=OpenBSD+Current
|
155
|
+
def self.original_dest(sock)
|
156
|
+
if sock.respond_to? :getsockname
|
157
|
+
sockname = sock.getsockname
|
158
|
+
elsif sock.respond_to? :get_sockname
|
159
|
+
sockname = sock.get_sockname
|
160
|
+
else
|
161
|
+
raise ArgumentError, "#{sock.inspect} supports neither :getsockname nor :get_sockname!"
|
162
|
+
end
|
163
|
+
Socket::unpack_sockaddr_in(sockname)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|