mirror of
https://github.com/sshuttle/sshuttle.git
synced 2024-11-22 16:03:57 +01:00
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.
This commit is contained in:
parent
3a25f709e5
commit
f1b33dab29
16
client.py
16
client.py
@ -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()
|
||||
@ -185,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)
|
||||
@ -212,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,
|
||||
|
47
firewall.py
47
firewall.py
@ -43,14 +43,23 @@ 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:
|
||||
ipt('-A', chain, '-j', 'REDIRECT',
|
||||
'--dest', '%s/%s' % (snet,swidth),
|
||||
'-p', 'tcp',
|
||||
'--to-ports', str(port),
|
||||
'-m', 'ttl', '!', '--ttl', '42' # to prevent infinite loops
|
||||
)
|
||||
# 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',
|
||||
'--to-ports', str(port),
|
||||
'-m', 'ttl', '!', '--ttl', '42' # to prevent infinite loops
|
||||
)
|
||||
|
||||
|
||||
def ipfw_rule_exists(n):
|
||||
@ -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,11 +130,16 @@ def do_ipfw(port, subnets):
|
||||
'from', 'any', 'to', 'any', 'established')
|
||||
|
||||
# create new subnet entries
|
||||
for snet,swidth in subnets:
|
||||
ipfw('add', sport, 'fwd', '127.0.0.1,%d' % port,
|
||||
'log', 'tcp',
|
||||
'from', 'any', 'to', '%s/%s' % (snet,swidth),
|
||||
'not', 'ipttl', '42')
|
||||
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),
|
||||
'not', 'ipttl', '42')
|
||||
|
||||
|
||||
def program_exists(name):
|
||||
@ -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')
|
||||
|
9
main.py
9
main.py
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user