tlspretense 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|