diff --git a/Sshuttle VPN.app/Contents/Resources/English.lproj/MainMenu.nib b/Sshuttle VPN.app/Contents/Resources/English.lproj/MainMenu.nib index 42d0ed4..349dc68 100644 Binary files a/Sshuttle VPN.app/Contents/Resources/English.lproj/MainMenu.nib and b/Sshuttle VPN.app/Contents/Resources/English.lproj/MainMenu.nib differ diff --git a/Sshuttle VPN.app/Contents/Resources/askpass.pyc b/Sshuttle VPN.app/Contents/Resources/askpass.pyc deleted file mode 100644 index aa27822..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/askpass.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/models.pyc b/Sshuttle VPN.app/Contents/Resources/models.pyc deleted file mode 100644 index 11b7144..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/models.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/my.pyc b/Sshuttle VPN.app/Contents/Resources/my.pyc deleted file mode 100644 index e3c56a9..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/my.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/client.py b/Sshuttle VPN.app/Contents/Resources/sshuttle/client.py index fa93c26..0ff5f2b 100644 --- a/Sshuttle VPN.app/Contents/Resources/sshuttle/client.py +++ b/Sshuttle VPN.app/Contents/Resources/sshuttle/client.py @@ -102,7 +102,7 @@ class FirewallClient: self.subnets_include = subnets_include self.subnets_exclude = subnets_exclude self.dnsport = dnsport - argvbase = ([sys.argv[0]] + + argvbase = ([sys.argv[1], sys.argv[0], sys.argv[1]] + ['-v'] * (helpers.verbose or 0) + ['--firewall', str(port), str(dnsport)]) if ssyslog._p: diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/client.pyc b/Sshuttle VPN.app/Contents/Resources/sshuttle/client.pyc deleted file mode 100644 index 23f3bbe..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/sshuttle/client.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/compat/__init__.pyc b/Sshuttle VPN.app/Contents/Resources/sshuttle/compat/__init__.pyc deleted file mode 100644 index 463e907..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/sshuttle/compat/__init__.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/compat/ssubprocess.pyc b/Sshuttle VPN.app/Contents/Resources/sshuttle/compat/ssubprocess.pyc deleted file mode 100644 index 6509e71..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/sshuttle/compat/ssubprocess.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/firewall.py b/Sshuttle VPN.app/Contents/Resources/sshuttle/firewall.py index 7767d43..4fd8c79 100644 --- a/Sshuttle VPN.app/Contents/Resources/sshuttle/firewall.py +++ b/Sshuttle VPN.app/Contents/Resources/sshuttle/firewall.py @@ -7,6 +7,13 @@ from helpers import * IPPROTO_DIVERT = 254 +def nonfatal(func, *args): + try: + func(*args) + except Fatal, e: + log('error: %s\n' % e) + + def ipt_chain_exists(name): argv = ['iptables', '-t', 'nat', '-nL'] p = ssubprocess.Popen(argv, stdout = ssubprocess.PIPE) @@ -57,9 +64,9 @@ def do_iptables(port, dnsport, subnets): # basic cleanup/setup of chains if ipt_chain_exists(chain): - ipt('-D', 'OUTPUT', '-j', chain) - ipt('-D', 'PREROUTING', '-j', chain) - ipt('-F', chain) + nonfatal(ipt, '-D', 'OUTPUT', '-j', chain) + nonfatal(ipt, '-D', 'PREROUTING', '-j', chain) + nonfatal(ipt, '-F', chain) ipt('-X', chain) if subnets or dnsport: @@ -143,7 +150,7 @@ def sysctl_set(name, val, permanent=False): _fill_oldctls(PREFIX) if not (name in _oldctls): debug1('>> No such sysctl: %r\n' % name) - return + return False oldval = _oldctls[name] if val != oldval: rv = _sysctl_set(name, val) @@ -156,6 +163,7 @@ def sysctl_set(name, val, permanent=False): f.close() else: _changedctls.append(name) + return True def _udp_unpack(p): @@ -214,7 +222,18 @@ def do_ipfw(port, dnsport, subnets): if subnets or dnsport: sysctl_set('net.inet.ip.fw.enable', 1) - sysctl_set('net.inet.ip.scopedroute', 0, permanent=True) + changed = sysctl_set('net.inet.ip.scopedroute', 0, permanent=True) + if changed: + log("\n" + " WARNING: ONE-TIME NETWORK DISRUPTION:\n" + " =====================================\n" + "sshuttle has changed a MacOS kernel setting to work around\n" + "a bug in MacOS 10.6. This will cause your network to drop\n" + "within 5-10 minutes unless you restart your network\n" + "interface (change wireless networks or unplug/plug the\n" + "ethernet port) NOW, then restart sshuttle. The fix is\n" + "permanent; you only have to do this once.\n\n") + sys.exit(1) ipfw('add', sport, 'check-state', 'ip', 'from', 'any', 'to', 'any') diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/firewall.pyc b/Sshuttle VPN.app/Contents/Resources/sshuttle/firewall.pyc deleted file mode 100644 index 3682bb1..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/sshuttle/firewall.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/helpers.pyc b/Sshuttle VPN.app/Contents/Resources/sshuttle/helpers.pyc deleted file mode 100644 index d84b651..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/sshuttle/helpers.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/hostwatch.py b/Sshuttle VPN.app/Contents/Resources/sshuttle/hostwatch.py index d77a58f..66e7461 100644 --- a/Sshuttle VPN.app/Contents/Resources/sshuttle/hostwatch.py +++ b/Sshuttle VPN.app/Contents/Resources/sshuttle/hostwatch.py @@ -13,7 +13,11 @@ _nmb_ok = True _smb_ok = True hostnames = {} queue = {} -null = open('/dev/null', 'rb+') +try: + null = open('/dev/null', 'wb') +except IOError, e: + log('warning: %s\n' % e) + null = os.popen("sh -c 'while read x; do :; done'", 'wb', 4096) def _is_ip(s): diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/hostwatch.pyc b/Sshuttle VPN.app/Contents/Resources/sshuttle/hostwatch.pyc deleted file mode 100644 index de2a0ef..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/sshuttle/hostwatch.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/main.py b/Sshuttle VPN.app/Contents/Resources/sshuttle/main.py old mode 100755 new mode 100644 index 3fe1e53..1cf00af --- a/Sshuttle VPN.app/Contents/Resources/sshuttle/main.py +++ b/Sshuttle VPN.app/Contents/Resources/sshuttle/main.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python import sys, os, re import helpers, options, client, server, firewall, hostwatch import compat.ssubprocess as ssubprocess @@ -55,7 +54,7 @@ l,listen= transproxy to this ip address and port number [127.0.0.1:0] 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 -python= path to python interpreter on the remote server [python] +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) v,verbose increase debug message verbosity @@ -71,7 +70,7 @@ firewall (internal use only) hostwatch (internal use only) """ o = options.Options(optspec) -(opt, flags, extra) = o.parse(sys.argv[1:]) +(opt, flags, extra) = o.parse(sys.argv[2:]) if opt.daemon: opt.syslog = 1 diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/options.pyc b/Sshuttle VPN.app/Contents/Resources/sshuttle/options.pyc deleted file mode 100644 index 4a2df17..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/sshuttle/options.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/server.py b/Sshuttle VPN.app/Contents/Resources/sshuttle/server.py index 45bc2fc..37daf77 100644 --- a/Sshuttle VPN.app/Contents/Resources/sshuttle/server.py +++ b/Sshuttle VPN.app/Contents/Resources/sshuttle/server.py @@ -119,7 +119,14 @@ class DnsProxy(Handler): self.sock.send(request) def callback(self): - data = self.sock.recv(4096) + try: + data = self.sock.recv(4096) + except socket.error, e: + if e.args[0] == errno.ECONNREFUSED: + debug2('DNS response: ignoring ECONNREFUSED.\n') + return # might have been spurious; wait for a real answer + else: + raise debug2('DNS response: %d bytes\n' % len(data)) self.mux.send(self.chan, ssnet.CMD_DNS_RESPONSE, data) self.ok = False diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/server.pyc b/Sshuttle VPN.app/Contents/Resources/sshuttle/server.pyc deleted file mode 100644 index 6c46ecc..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/sshuttle/server.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/ssh.py b/Sshuttle VPN.app/Contents/Resources/sshuttle/ssh.py index 9a6270a..c7be991 100644 --- a/Sshuttle VPN.app/Contents/Resources/sshuttle/ssh.py +++ b/Sshuttle VPN.app/Contents/Resources/sshuttle/ssh.py @@ -73,16 +73,23 @@ def connect(ssh_cmd, rhostport, python, stderr, options): if not rhost: - argv = [python, '-c', pyscript] + # ignore the --python argument when running locally; we already know + # which python version works. + argv = [sys.argv[1], '-c', pyscript] else: if ssh_cmd: sshl = ssh_cmd.split(' ') else: sshl = ['ssh'] + if python: + pycmd = "'%s' -c '%s'" % (python, pyscript) + else: + pycmd = ("P=python2; $P -V 2>/dev/null || P=python; " + "\"$P\" -c '%s'") % pyscript argv = (sshl + portl + ipv6flag + - [rhost, '--', "'%s' -c '%s'" % (python, pyscript)]) + [rhost, '--', pycmd]) (s1,s2) = socket.socketpair() def setup(): # runs in the child process diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/ssh.pyc b/Sshuttle VPN.app/Contents/Resources/sshuttle/ssh.pyc deleted file mode 100644 index fbcb512..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/sshuttle/ssh.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/sshuttle b/Sshuttle VPN.app/Contents/Resources/sshuttle/sshuttle index 3fe1e53..d832198 100755 --- a/Sshuttle VPN.app/Contents/Resources/sshuttle/sshuttle +++ b/Sshuttle VPN.app/Contents/Resources/sshuttle/sshuttle @@ -1,131 +1,7 @@ -#!/usr/bin/env python -import sys, os, re -import helpers, options, client, server, firewall, hostwatch -import compat.ssubprocess as ssubprocess -from helpers import * - - -# list of: -# 1.2.3.4/5 or just 1.2.3.4 -def parse_subnets(subnets_str): - subnets = [] - for s in subnets_str: - m = re.match(r'(\d+)(?:\.(\d+)\.(\d+)\.(\d+))?(?:/(\d+))?$', s) - if not m: - raise Fatal('%r is not a valid IP subnet format' % s) - (a,b,c,d,width) = m.groups() - (a,b,c,d) = (int(a or 0), int(b or 0), int(c or 0), int(d or 0)) - if width == None: - width = 32 - else: - width = int(width) - if a > 255 or b > 255 or c > 255 or d > 255: - raise Fatal('%d.%d.%d.%d has numbers > 255' % (a,b,c,d)) - if width > 32: - raise Fatal('*/%d is greater than the maximum of 32' % width) - subnets.append(('%d.%d.%d.%d' % (a,b,c,d), width)) - return subnets - - -# 1.2.3.4:567 or just 1.2.3.4 or just 567 -def parse_ipport(s): - s = str(s) - m = re.match(r'(?:(\d+)\.(\d+)\.(\d+)\.(\d+))?(?::)?(?:(\d+))?$', s) - if not m: - raise Fatal('%r is not a valid IP:port format' % s) - (a,b,c,d,port) = m.groups() - (a,b,c,d,port) = (int(a or 0), int(b or 0), int(c or 0), int(d or 0), - int(port or 0)) - if a > 255 or b > 255 or c > 255 or d > 255: - raise Fatal('%d.%d.%d.%d has numbers > 255' % (a,b,c,d)) - if port > 65535: - raise Fatal('*:%d is greater than the maximum of 65535' % port) - if a == None: - a = b = c = d = 0 - return ('%d.%d.%d.%d' % (a,b,c,d), port) - - -optspec = """ -sshuttle [-l [ip:]port] [-r [username@]sshserver[:port]] -sshuttle --server -sshuttle --firewall -sshuttle --hostwatch --- -l,listen= transproxy to this ip address and port number [127.0.0.1:0] -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 -python= path to python interpreter on the remote server [python] -r,remote= ssh hostname (and optional username) of remote sshuttle server -x,exclude= exclude this subnet (can be used more than once) -v,verbose increase debug message verbosity -e,ssh-cmd= the command to use to connect to the remote [ssh] -seed-hosts= with -H, use these hostnames for initial scan (comma-separated) -no-latency-control sacrifice latency to improve bandwidth benchmarks -wrap= restart counting channel numbers after this number (for testing) -D,daemon run in the background as a daemon -syslog send log messages to syslog (default if you use --daemon) -pidfile= pidfile name (only if using --daemon) [./sshuttle.pid] -server (internal use only) -firewall (internal use only) -hostwatch (internal use only) -""" -o = options.Options(optspec) -(opt, flags, extra) = o.parse(sys.argv[1:]) - -if opt.daemon: - opt.syslog = 1 -if opt.wrap: - import ssnet - ssnet.MAX_CHANNEL = int(opt.wrap) -helpers.verbose = opt.verbose - -try: - if opt.server: - if len(extra) != 0: - o.fatal('no arguments expected') - server.latency_control = opt.latency_control - sys.exit(server.main()) - 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)) - elif opt.hostwatch: - sys.exit(hostwatch.hw_main(extra)) - else: - if len(extra) < 1 and not opt.auto_nets: - o.fatal('at least one subnet (or -N) expected') - includes = extra - excludes = ['127.0.0.0/8'] - for k,v in flags: - if k in ('-x','--exclude'): - excludes.append(v) - remotename = opt.remote - if remotename == '' or remotename == '-': - remotename = None - if opt.seed_hosts and not opt.auto_hosts: - o.fatal('--seed-hosts only works if you also use -H') - if opt.seed_hosts: - sh = re.split(r'[\s,]+', (opt.seed_hosts or "").strip()) - elif opt.auto_hosts: - sh = [] - else: - sh = None - sys.exit(client.main(parse_ipport(opt.listen or '0.0.0.0:0'), - opt.ssh_cmd, - remotename, - opt.python, - opt.latency_control, - opt.dns, - sh, - opt.auto_nets, - parse_subnets(includes), - parse_subnets(excludes), - opt.syslog, opt.daemon, opt.pidfile)) -except Fatal, e: - log('fatal: %s\n' % e) - sys.exit(99) -except KeyboardInterrupt: - log('\n') - log('Keyboard interrupt: exiting.\n') - sys.exit(1) +#!/bin/sh +DIR=$(dirname "$0") +if python2 -V 2>/dev/null; then + exec python2 "$DIR/main.py" python2 "$@" +else + exec python "$DIR/main.py" python "$@" +fi diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/ssnet.pyc b/Sshuttle VPN.app/Contents/Resources/sshuttle/ssnet.pyc deleted file mode 100644 index e162b8e..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/sshuttle/ssnet.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/ssyslog.pyc b/Sshuttle VPN.app/Contents/Resources/sshuttle/ssyslog.pyc deleted file mode 100644 index acbfc5e..0000000 Binary files a/Sshuttle VPN.app/Contents/Resources/sshuttle/ssyslog.pyc and /dev/null differ diff --git a/Sshuttle VPN.app/Contents/Resources/sshuttle/stresstest.py b/Sshuttle VPN.app/Contents/Resources/sshuttle/stresstest.py index f42df09..dba95ea 100755 --- a/Sshuttle VPN.app/Contents/Resources/sshuttle/stresstest.py +++ b/Sshuttle VPN.app/Contents/Resources/sshuttle/stresstest.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import sys, os, socket, select, struct, time listener = socket.socket()