From ebfc3703ec209af8ec818394d5d623ead1a18d1d Mon Sep 17 00:00:00 2001 From: Avery Pennarun Date: Wed, 26 Jan 2011 03:46:59 -0800 Subject: [PATCH] dns: add support for MacOS (but it doesn't work...) ...because stupid MacOS ipfw 'fwd' rules don't work quite right with udp. It can intercept packets bound for remote hosts, but it doesn't correctly rewrite the port number from its original to the new socket, so it gets dropped by the local kernel anyway. That is, a packet to 1.2.3.4:53 should be redirected to, say, 127.0.0.1:9999, the local DNS listener socket. But instead, it gets sent to 127.0.0.1:53, which nobody is listening on, so it gets eaten. Sigh. --- firewall.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/firewall.py b/firewall.py index ed576a2..ccf576f 100644 --- a/firewall.py +++ b/firewall.py @@ -59,12 +59,13 @@ def do_iptables(port, dnsport, subnets): ipt('-F', chain) ipt('-X', chain) - if subnets: + if subnets or dnsport: ipt('-N', chain) ipt('-F', chain) ipt('-I', 'OUTPUT', '1', '-j', chain) ipt('-I', 'PREROUTING', '1', '-j', chain) + if subnets: # create new subnet entries. Note that we're sorting in a very # particular order: we need to go from most-specific (largest swidth) # to least-specific, and at any given level of specificity, we want @@ -98,6 +99,7 @@ def ipfw_rule_exists(n): for line in p.stdout: if line.startswith('%05d ' % n): if not ('ipttl 42 setup keep-state' in line + or 'ipttl 42 keep-state' in line or ('skipto %d' % (n+1)) in line or 'check-state' in line): log('non-sshuttle ipfw rule: %r\n' % line.strip()) @@ -167,13 +169,14 @@ def do_ipfw(port, dnsport, subnets): oldval = _oldctls[name] _sysctl_set(name, oldval) - if subnets: + if subnets or dnsport: sysctl_set('net.inet.ip.fw.enable', 1) sysctl_set('net.inet.ip.scopedroute', 0) ipfw('add', sport, 'check-state', 'ip', 'from', 'any', 'to', 'any') - + + if subnets: # create new subnet entries for swidth,sexclude,snet in sorted(subnets, reverse=True): if sexclude: @@ -186,6 +189,14 @@ def do_ipfw(port, dnsport, subnets): 'from', 'any', 'to', '%s/%s' % (snet,swidth), 'not', 'ipttl', '42', 'keep-state', 'setup') + if dnsport: + nslist = resolvconf_nameservers() + for ip in nslist: + ipfw('add', sport, 'fwd', '127.0.0.1,%d' % dnsport, + 'log', 'udp', + 'from', 'any', 'to', '%s/32' % ip, '53', + 'not', 'ipttl', '42', 'keep-state') + def program_exists(name): paths = (os.getenv('PATH') or os.defpath).split(os.pathsep) @@ -194,6 +205,7 @@ def program_exists(name): if os.path.exists(fn): return not os.path.isdir(fn) and os.access(fn, os.X_OK) + hostmap = {} def rewrite_etc_hosts(port): HOSTSFILE='/etc/hosts'