MacOS precompiled app package for sshuttle-0.52

This commit is contained in:
Avery Pennarun 2011-03-20 04:13:09 -07:00
parent cd15e2eda6
commit cde9521825
23 changed files with 57 additions and 145 deletions

View File

@ -102,7 +102,7 @@ class FirewallClient:
self.subnets_include = subnets_include self.subnets_include = subnets_include
self.subnets_exclude = subnets_exclude self.subnets_exclude = subnets_exclude
self.dnsport = dnsport self.dnsport = dnsport
argvbase = ([sys.argv[0]] + argvbase = ([sys.argv[1], sys.argv[0], sys.argv[1]] +
['-v'] * (helpers.verbose or 0) + ['-v'] * (helpers.verbose or 0) +
['--firewall', str(port), str(dnsport)]) ['--firewall', str(port), str(dnsport)])
if ssyslog._p: if ssyslog._p:

View File

@ -7,6 +7,13 @@ from helpers import *
IPPROTO_DIVERT = 254 IPPROTO_DIVERT = 254
def nonfatal(func, *args):
try:
func(*args)
except Fatal, e:
log('error: %s\n' % e)
def ipt_chain_exists(name): def ipt_chain_exists(name):
argv = ['iptables', '-t', 'nat', '-nL'] argv = ['iptables', '-t', 'nat', '-nL']
p = ssubprocess.Popen(argv, stdout = ssubprocess.PIPE) p = ssubprocess.Popen(argv, stdout = ssubprocess.PIPE)
@ -57,9 +64,9 @@ def do_iptables(port, dnsport, subnets):
# basic cleanup/setup of chains # basic cleanup/setup of chains
if ipt_chain_exists(chain): if ipt_chain_exists(chain):
ipt('-D', 'OUTPUT', '-j', chain) nonfatal(ipt, '-D', 'OUTPUT', '-j', chain)
ipt('-D', 'PREROUTING', '-j', chain) nonfatal(ipt, '-D', 'PREROUTING', '-j', chain)
ipt('-F', chain) nonfatal(ipt, '-F', chain)
ipt('-X', chain) ipt('-X', chain)
if subnets or dnsport: if subnets or dnsport:
@ -143,7 +150,7 @@ def sysctl_set(name, val, permanent=False):
_fill_oldctls(PREFIX) _fill_oldctls(PREFIX)
if not (name in _oldctls): if not (name in _oldctls):
debug1('>> No such sysctl: %r\n' % name) debug1('>> No such sysctl: %r\n' % name)
return return False
oldval = _oldctls[name] oldval = _oldctls[name]
if val != oldval: if val != oldval:
rv = _sysctl_set(name, val) rv = _sysctl_set(name, val)
@ -156,6 +163,7 @@ def sysctl_set(name, val, permanent=False):
f.close() f.close()
else: else:
_changedctls.append(name) _changedctls.append(name)
return True
def _udp_unpack(p): def _udp_unpack(p):
@ -214,7 +222,18 @@ def do_ipfw(port, dnsport, subnets):
if subnets or dnsport: if subnets or dnsport:
sysctl_set('net.inet.ip.fw.enable', 1) 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', ipfw('add', sport, 'check-state', 'ip',
'from', 'any', 'to', 'any') 'from', 'any', 'to', 'any')

View File

@ -13,7 +13,11 @@ _nmb_ok = True
_smb_ok = True _smb_ok = True
hostnames = {} hostnames = {}
queue = {} 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): def _is_ip(s):

5
Sshuttle VPN.app/Contents/Resources/sshuttle/main.py Executable file → Normal file
View File

@ -1,4 +1,3 @@
#!/usr/bin/env python
import sys, os, re import sys, os, re
import helpers, options, client, server, firewall, hostwatch import helpers, options, client, server, firewall, hostwatch
import compat.ssubprocess as ssubprocess 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 H,auto-hosts scan for remote hostnames and update local /etc/hosts
N,auto-nets automatically determine subnets to route N,auto-nets automatically determine subnets to route
dns capture local DNS requests and forward to the remote DNS server 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 r,remote= ssh hostname (and optional username) of remote sshuttle server
x,exclude= exclude this subnet (can be used more than once) x,exclude= exclude this subnet (can be used more than once)
v,verbose increase debug message verbosity v,verbose increase debug message verbosity
@ -71,7 +70,7 @@ firewall (internal use only)
hostwatch (internal use only) hostwatch (internal use only)
""" """
o = options.Options(optspec) o = options.Options(optspec)
(opt, flags, extra) = o.parse(sys.argv[1:]) (opt, flags, extra) = o.parse(sys.argv[2:])
if opt.daemon: if opt.daemon:
opt.syslog = 1 opt.syslog = 1

View File

@ -119,7 +119,14 @@ class DnsProxy(Handler):
self.sock.send(request) self.sock.send(request)
def callback(self): def callback(self):
try:
data = self.sock.recv(4096) 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)) debug2('DNS response: %d bytes\n' % len(data))
self.mux.send(self.chan, ssnet.CMD_DNS_RESPONSE, data) self.mux.send(self.chan, ssnet.CMD_DNS_RESPONSE, data)
self.ok = False self.ok = False

View File

@ -73,16 +73,23 @@ def connect(ssh_cmd, rhostport, python, stderr, options):
if not rhost: 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: else:
if ssh_cmd: if ssh_cmd:
sshl = ssh_cmd.split(' ') sshl = ssh_cmd.split(' ')
else: else:
sshl = ['ssh'] 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 + argv = (sshl +
portl + portl +
ipv6flag + ipv6flag +
[rhost, '--', "'%s' -c '%s'" % (python, pyscript)]) [rhost, '--', pycmd])
(s1,s2) = socket.socketpair() (s1,s2) = socket.socketpair()
def setup(): def setup():
# runs in the child process # runs in the child process

View File

@ -1,131 +1,7 @@
#!/usr/bin/env python #!/bin/sh
import sys, os, re DIR=$(dirname "$0")
import helpers, options, client, server, firewall, hostwatch if python2 -V 2>/dev/null; then
import compat.ssubprocess as ssubprocess exec python2 "$DIR/main.py" python2 "$@"
from helpers import * else
exec python "$DIR/main.py" python "$@"
fi
# 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]] <subnets...>
sshuttle --server
sshuttle --firewall <port> <subnets...>
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)

View File

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python
import sys, os, socket, select, struct, time import sys, os, socket, select, struct, time
listener = socket.socket() listener = socket.socket()