Compare commits

...

6 Commits

Author SHA1 Message Date
f1b33dab29 Add a --exclude option for excluding subnets from routing.
Also, add 127.0.0.0/8 to the default list of excludes.  If you want to route
0/0, you almost certainly *don't* want to route localhost to the remote ssh
server's localhost!

Thanks to Edward for the suggestion.
2010-07-15 14:13:33 -04:00
3a25f709e5 log(): don't abort if we fail to write to stderr.
Failing to write to the log sucks, but not as much as failing to clean up
just because stderr disappeared.  So let's catch any IOError exception from
log() and just ignore it.

This should fix a problem reported by Camille Moncelier, which is that
sshuttle firewall entries stick around if your tty dies strangely (eg. your
X server aborts for some reason).
2010-05-16 17:57:18 -04:00
a8b3d69856 ssh.py: try harder to find required *.py files.
Search the entire python sys.path, not just the directory that argv[0] is
in.  That way if you symlink the sshuttle binary into (for example) ~/bin,
it'll be able to work correctly.
2010-05-12 13:53:14 -04:00
2d4f6a4308 client: add a debug1() message for connecting/connected.
If the server is going to delay us, we'd at least like to know that.
2010-05-11 19:04:44 -04:00
d435ed837d Created a googlegroups.com mailing list for sshuttle. 2010-05-11 15:30:53 -04:00
2d77403a0b Don't use try/except/finally so that python 2.4 works.
Use try/(try/except)/finally instead.  There was only once case of this.

Thanks to Wayne Scott and nisc for pointing this out.
2010-05-10 13:58:52 -04:00
7 changed files with 77 additions and 36 deletions

View File

@ -161,3 +161,6 @@ later. You're welcome.
--
Avery Pennarun <apenwarr@gmail.com>
Mailing list:
Subscribe by sending a message to <sshuttle+subscribe@googlegroups.com>
List archives are at: http://groups.google.com/group/sshuttle

View File

@ -20,10 +20,11 @@ def original_dst(sock):
class FirewallClient:
def __init__(self, port, subnets):
def __init__(self, port, subnets_include, subnets_exclude):
self.port = port
self.auto_nets = []
self.subnets = subnets
self.subnets_include = subnets_include
self.subnets_exclude = subnets_exclude
argvbase = ([sys.argv[0]] +
['-v'] * (helpers.verbose or 0) +
['--firewall', str(port)])
@ -67,8 +68,10 @@ class FirewallClient:
def start(self):
self.pfile.write('ROUTES\n')
for (ip,width) in self.subnets+self.auto_nets:
self.pfile.write('%s,%d\n' % (ip, width))
for (ip,width) in self.subnets_include+self.auto_nets:
self.pfile.write('%d,0,%s\n' % (width, ip))
for (ip,width) in self.subnets_exclude:
self.pfile.write('%d,1,%s\n' % (width, ip))
self.pfile.write('GO\n')
self.pfile.flush()
line = self.pfile.readline()
@ -96,6 +99,7 @@ def _main(listener, fw, use_server, remotename, seed_hosts, auto_nets):
helpers.logprefix = 'c : '
else:
helpers.logprefix = 'client: '
debug1('connecting to server...\n')
(serverproc, serversock) = ssh.connect(remotename)
mux = Mux(serversock, serversock)
handlers.append(mux)
@ -110,6 +114,7 @@ def _main(listener, fw, use_server, remotename, seed_hosts, auto_nets):
if initstring != expected:
raise Fatal('expected server init string %r; got %r'
% (expected, initstring))
debug1('connected.\n')
def onroutes(routestr):
if auto_nets:
@ -183,7 +188,8 @@ def _main(listener, fw, use_server, remotename, seed_hosts, auto_nets):
mux.check_fullness()
def main(listenip, use_server, remotename, seed_hosts, auto_nets, subnets):
def main(listenip, use_server, remotename, seed_hosts, auto_nets,
subnets_include, subnets_exclude):
debug1('Starting sshuttle proxy.\n')
listener = socket.socket()
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
@ -210,7 +216,7 @@ def main(listenip, use_server, remotename, seed_hosts, auto_nets, subnets):
listenip = listener.getsockname()
debug1('Listening on %r.\n' % (listenip,))
fw = FirewallClient(listenip[1], subnets)
fw = FirewallClient(listenip[1], subnets_include, subnets_exclude)
try:
return _main(listener, fw, use_server, remotename,

View File

@ -43,8 +43,17 @@ def do_iptables(port, subnets):
ipt('-I', 'OUTPUT', '1', '-j', chain)
ipt('-I', 'PREROUTING', '1', '-j', chain)
# create new subnet entries
for snet,swidth in 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
# excludes to come first. That's why the columns are in such a non-
# intuitive order.
for swidth,sexclude,snet in sorted(subnets, reverse=True):
if sexclude:
ipt('-A', chain, '-j', 'RETURN',
'--dest', '%s/%s' % (snet,swidth),
'-p', 'tcp')
else:
ipt('-A', chain, '-j', 'REDIRECT',
'--dest', '%s/%s' % (snet,swidth),
'-p', 'tcp',
@ -103,6 +112,7 @@ def ipfw(*args):
def do_ipfw(port, subnets):
sport = str(port)
xsport = str(port+1)
# cleanup any existing rules
if ipfw_rule_exists(port):
@ -120,7 +130,12 @@ def do_ipfw(port, subnets):
'from', 'any', 'to', 'any', 'established')
# create new subnet entries
for snet,swidth in subnets:
for swidth,sexclude,snet in sorted(subnets, reverse=True):
if sexclude:
ipfw('add', sport, 'skipto', xsport,
'log', 'tcp',
'from', 'any', 'to', '%s/%s' % (snet,swidth))
else:
ipfw('add', sport, 'fwd', '127.0.0.1,%d' % port,
'log', 'tcp',
'from', 'any', 'to', '%s/%s' % (snet,swidth),
@ -228,10 +243,11 @@ def main(port):
elif line == 'GO\n':
break
try:
(ip,width) = line.strip().split(',', 1)
(width,exclude,ip) = line.strip().split(',', 2)
except:
raise Fatal('firewall: expected route or GO but got %r' % line)
subnets.append((ip, int(width)))
subnets.append((int(width), bool(int(exclude)), ip))
try:
if line:
debug1('firewall manager: starting transproxy.\n')
@ -258,7 +274,6 @@ def main(port):
raise Fatal('expected EOF, got %r' % line)
else:
break
finally:
try:
debug1('firewall manager: undoing changes.\n')

View File

@ -4,9 +4,14 @@ logprefix = ''
verbose = 0
def log(s):
try:
sys.stdout.flush()
sys.stderr.write(logprefix + s)
sys.stderr.flush()
except IOError:
# this could happen if stderr gets forcibly disconnected, eg. because
# our tty closes. That sucks, but it's no reason to abort the program.
pass
def debug1(s):
if verbose >= 1:

View File

@ -53,6 +53,7 @@ l,listen= transproxy to this ip address and port number [default=0]
H,auto-hosts scan for remote hostnames and update local /etc/hosts
N,auto-nets automatically determine subnets to route
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
seed-hosts= with -H, use these hostnames for initial scan (comma-separated)
noserver don't use a separate server process (mostly for debugging)
@ -79,6 +80,11 @@ try:
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
@ -95,7 +101,8 @@ try:
remotename,
sh,
opt.auto_nets,
parse_subnets(extra)))
parse_subnets(includes),
parse_subnets(excludes)))
except Fatal, e:
log('fatal: %s\n' % e)
sys.exit(99)

View File

@ -78,6 +78,7 @@ def start_hostwatch(seed_hosts):
if not pid:
# child
rv = 99
try:
try:
s2.close()
os.dup2(s1.fileno(), 1)

6
ssh.py
View File

@ -5,8 +5,12 @@ from helpers import *
def readfile(name):
basedir = os.path.dirname(os.path.abspath(sys.argv[0]))
fullname = os.path.join(basedir, name)
path = [basedir] + sys.path
for d in path:
fullname = os.path.join(d, name)
if os.path.exists(fullname):
return open(fullname, 'rb').read()
raise Exception("can't find file %r in any of %r" % (name, path))
def empackage(z, filename):