diff --git a/client.py b/client.py index af07910..158f338 100644 --- a/client.py +++ b/client.py @@ -96,17 +96,20 @@ def original_dst(sock): class FirewallClient: - def __init__(self, port, subnets_include, subnets_exclude, dnsport): + def __init__(self, port, subnets_include, subnets_exclude, dnsport, dns_hosts): self.port = port self.auto_nets = [] self.subnets_include = subnets_include self.subnets_exclude = subnets_exclude self.dnsport = dnsport + self.dns_hosts = dns_hosts argvbase = ([sys.argv[1], sys.argv[0], sys.argv[1]] + ['-v'] * (helpers.verbose or 0) + ['--firewall', str(port), str(dnsport)]) if ssyslog._p: argvbase += ['--syslog'] + if dnsport: + argvbase += ['--dns-hosts', ','.join(dns_hosts)] argv_tries = [ ['sudo', '-p', '[local sudo] Password: '] + argvbase, ['su', '-c', ' '.join(argvbase)], @@ -337,7 +340,8 @@ def onhostlist(hostlist): mux.callback() -def main(listenip, ssh_cmd, remotename, python, latency_control, dns, +def main(listenip, ssh_cmd, remotename, python, latency_control, + dns, dns_hosts, seed_hosts, auto_nets, subnets_include, subnets_exclude, syslog, daemon, pidfile): if syslog: @@ -378,15 +382,18 @@ def main(listenip, ssh_cmd, remotename, python, latency_control, dns, listenip = listener.getsockname() debug1('Listening on %r.\n' % (listenip,)) - if dns: + if dns or dns_hosts: dnsip = dnslistener.getsockname() debug1('DNS listening on %r.\n' % (dnsip,)) dnsport = dnsip[1] + if dns: + dns_hosts += resolvconf_nameservers() else: dnsport = 0 dnslistener = None + dns_hosts = [] - fw = FirewallClient(listenip[1], subnets_include, subnets_exclude, dnsport) + fw = FirewallClient(listenip[1], subnets_include, subnets_exclude, dnsport, dns_hosts) try: return _main(listener, fw, ssh_cmd, remotename, diff --git a/firewall.py b/firewall.py index cbc3312..bec024c 100644 --- a/firewall.py +++ b/firewall.py @@ -70,7 +70,7 @@ def ipt_ttl(*args): # multiple copies shouldn't have overlapping subnets, or only the most- # recently-started one will win (because we use "-I OUTPUT 1" instead of # "-A OUTPUT"). -def do_iptables(port, dnsport, subnets): +def do_iptables(port, dnsport, nslist, subnets): chain = 'sshuttle-%s' % port # basic cleanup/setup of chains @@ -104,7 +104,6 @@ def do_iptables(port, dnsport, subnets): '--to-ports', str(port)) if dnsport: - nslist = resolvconf_nameservers() for ip in nslist: ipt_ttl('-A', chain, '-j', 'REDIRECT', '--dest', '%s/32' % ip, @@ -255,7 +254,7 @@ def ipfw(*args): _call(argv) -def do_ipfw(port, dnsport, subnets): +def do_ipfw(port, dnsport, nslist, subnets): sport = str(port) xsport = str(port+1) @@ -354,7 +353,6 @@ def do_ipfw(port, dnsport, subnets): IPPROTO_DIVERT) divertsock.bind(('0.0.0.0', port)) # IP field is ignored - nslist = resolvconf_nameservers() for ip in nslist: # relabel and then catch outgoing DNS requests ipfw('add', sport, 'divert', sport, @@ -451,7 +449,7 @@ def ip_in_subnets(ip, subnets): # exit. In case that fails, it's not the end of the world; future runs will # supercede it in the transproxy list, at least, so the leftover rules # are hopefully harmless. -def main(port, dnsport, syslog): +def main(port, dnsport, nslist, syslog): assert(port > 0) assert(port <= 65535) assert(dnsport >= 0) @@ -516,7 +514,7 @@ def main(port, dnsport, syslog): try: if line: debug1('firewall manager: starting transproxy.\n') - do_wait = do_it(port, dnsport, subnets) + do_wait = do_it(port, dnsport, nslist, subnets) sys.stdout.write('STARTED\n') try: @@ -546,5 +544,5 @@ def main(port, dnsport, syslog): debug1('firewall manager: undoing changes.\n') except: pass - do_it(port, 0, []) + do_it(port, 0, [], []) restore_etc_hosts(port) diff --git a/main.py b/main.py index 34d9fb1..6493506 100755 --- a/main.py +++ b/main.py @@ -54,6 +54,7 @@ def parse_ipport(s): H,auto-hosts scan for remote hostnames and update local /etc/hosts N,auto-nets automatically determine subnets to route dns capture local DNS requests and forward to the remote DNS server +dns-hosts= capture DNS requests to these servers and forward (comma-separated) python= path to python interpreter on the remote server r,remote= ssh hostname (and optional username) of remote sshuttle server x,exclude= exclude this subnet (can be used more than once) @@ -94,7 +95,9 @@ def parse_ipport(s): elif opt.firewall: if len(extra) != 2: o.fatal('exactly two arguments expected') - sys.exit(firewall.main(int(extra[0]), int(extra[1]), opt.syslog)) + port, dnsport = int(extra[0]), int(extra[1]) + nslist = re.split(r'[\s,]+', opt.dns_hosts.strip()) if dnsport else [] + sys.exit(firewall.main(port, dnsport, nslist, opt.syslog)) elif opt.hostwatch: sys.exit(hostwatch.hw_main(extra)) else: @@ -110,6 +113,7 @@ def parse_ipport(s): remotename = opt.remote if remotename == '' or remotename == '-': remotename = None + nslist = re.split(r'[\s,]+', opt.dns_hosts.strip()) if opt.dns_hosts else [] if opt.seed_hosts and not opt.auto_hosts: o.fatal('--seed-hosts only works if you also use -H') if opt.seed_hosts: @@ -124,6 +128,7 @@ def parse_ipport(s): opt.python, opt.latency_control, opt.dns, + nslist, sh, opt.auto_nets, parse_subnets(includes),