mirror of
https://github.com/sshuttle/sshuttle.git
synced 2025-05-30 14:48:51 +02: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:
|
class FirewallClient:
|
||||||
def __init__(self, port, subnets):
|
def __init__(self, port, subnets_include, subnets_exclude):
|
||||||
self.port = port
|
self.port = port
|
||||||
self.auto_nets = []
|
self.auto_nets = []
|
||||||
self.subnets = subnets
|
self.subnets_include = subnets_include
|
||||||
|
self.subnets_exclude = subnets_exclude
|
||||||
argvbase = ([sys.argv[0]] +
|
argvbase = ([sys.argv[0]] +
|
||||||
['-v'] * (helpers.verbose or 0) +
|
['-v'] * (helpers.verbose or 0) +
|
||||||
['--firewall', str(port)])
|
['--firewall', str(port)])
|
||||||
@ -67,8 +68,10 @@ class FirewallClient:
|
|||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.pfile.write('ROUTES\n')
|
self.pfile.write('ROUTES\n')
|
||||||
for (ip,width) in self.subnets+self.auto_nets:
|
for (ip,width) in self.subnets_include+self.auto_nets:
|
||||||
self.pfile.write('%s,%d\n' % (ip, width))
|
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.write('GO\n')
|
||||||
self.pfile.flush()
|
self.pfile.flush()
|
||||||
line = self.pfile.readline()
|
line = self.pfile.readline()
|
||||||
@ -185,7 +188,8 @@ def _main(listener, fw, use_server, remotename, seed_hosts, auto_nets):
|
|||||||
mux.check_fullness()
|
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')
|
debug1('Starting sshuttle proxy.\n')
|
||||||
listener = socket.socket()
|
listener = socket.socket()
|
||||||
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
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()
|
listenip = listener.getsockname()
|
||||||
debug1('Listening on %r.\n' % (listenip,))
|
debug1('Listening on %r.\n' % (listenip,))
|
||||||
|
|
||||||
fw = FirewallClient(listenip[1], subnets)
|
fw = FirewallClient(listenip[1], subnets_include, subnets_exclude)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return _main(listener, fw, use_server, remotename,
|
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', 'OUTPUT', '1', '-j', chain)
|
||||||
ipt('-I', 'PREROUTING', '1', '-j', chain)
|
ipt('-I', 'PREROUTING', '1', '-j', chain)
|
||||||
|
|
||||||
# create new subnet entries
|
# create new subnet entries. Note that we're sorting in a very
|
||||||
for snet,swidth in subnets:
|
# particular order: we need to go from most-specific (largest swidth)
|
||||||
ipt('-A', chain, '-j', 'REDIRECT',
|
# to least-specific, and at any given level of specificity, we want
|
||||||
'--dest', '%s/%s' % (snet,swidth),
|
# excludes to come first. That's why the columns are in such a non-
|
||||||
'-p', 'tcp',
|
# intuitive order.
|
||||||
'--to-ports', str(port),
|
for swidth,sexclude,snet in sorted(subnets, reverse=True):
|
||||||
'-m', 'ttl', '!', '--ttl', '42' # to prevent infinite loops
|
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):
|
def ipfw_rule_exists(n):
|
||||||
@ -103,6 +112,7 @@ def ipfw(*args):
|
|||||||
|
|
||||||
def do_ipfw(port, subnets):
|
def do_ipfw(port, subnets):
|
||||||
sport = str(port)
|
sport = str(port)
|
||||||
|
xsport = str(port+1)
|
||||||
|
|
||||||
# cleanup any existing rules
|
# cleanup any existing rules
|
||||||
if ipfw_rule_exists(port):
|
if ipfw_rule_exists(port):
|
||||||
@ -120,11 +130,16 @@ def do_ipfw(port, subnets):
|
|||||||
'from', 'any', 'to', 'any', 'established')
|
'from', 'any', 'to', 'any', 'established')
|
||||||
|
|
||||||
# create new subnet entries
|
# create new subnet entries
|
||||||
for snet,swidth in subnets:
|
for swidth,sexclude,snet in sorted(subnets, reverse=True):
|
||||||
ipfw('add', sport, 'fwd', '127.0.0.1,%d' % port,
|
if sexclude:
|
||||||
'log', 'tcp',
|
ipfw('add', sport, 'skipto', xsport,
|
||||||
'from', 'any', 'to', '%s/%s' % (snet,swidth),
|
'log', 'tcp',
|
||||||
'not', 'ipttl', '42')
|
'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):
|
def program_exists(name):
|
||||||
@ -228,10 +243,11 @@ def main(port):
|
|||||||
elif line == 'GO\n':
|
elif line == 'GO\n':
|
||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
(ip,width) = line.strip().split(',', 1)
|
(width,exclude,ip) = line.strip().split(',', 2)
|
||||||
except:
|
except:
|
||||||
raise Fatal('firewall: expected route or GO but got %r' % line)
|
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:
|
try:
|
||||||
if line:
|
if line:
|
||||||
debug1('firewall manager: starting transproxy.\n')
|
debug1('firewall manager: starting transproxy.\n')
|
||||||
@ -258,7 +274,6 @@ def main(port):
|
|||||||
raise Fatal('expected EOF, got %r' % line)
|
raise Fatal('expected EOF, got %r' % line)
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
debug1('firewall manager: undoing changes.\n')
|
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
|
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
|
||||||
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)
|
||||||
v,verbose increase debug message verbosity
|
v,verbose increase debug message verbosity
|
||||||
seed-hosts= with -H, use these hostnames for initial scan (comma-separated)
|
seed-hosts= with -H, use these hostnames for initial scan (comma-separated)
|
||||||
noserver don't use a separate server process (mostly for debugging)
|
noserver don't use a separate server process (mostly for debugging)
|
||||||
@ -79,6 +80,11 @@ try:
|
|||||||
else:
|
else:
|
||||||
if len(extra) < 1 and not opt.auto_nets:
|
if len(extra) < 1 and not opt.auto_nets:
|
||||||
o.fatal('at least one subnet (or -N) expected')
|
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
|
remotename = opt.remote
|
||||||
if remotename == '' or remotename == '-':
|
if remotename == '' or remotename == '-':
|
||||||
remotename = None
|
remotename = None
|
||||||
@ -95,7 +101,8 @@ try:
|
|||||||
remotename,
|
remotename,
|
||||||
sh,
|
sh,
|
||||||
opt.auto_nets,
|
opt.auto_nets,
|
||||||
parse_subnets(extra)))
|
parse_subnets(includes),
|
||||||
|
parse_subnets(excludes)))
|
||||||
except Fatal, e:
|
except Fatal, e:
|
||||||
log('fatal: %s\n' % e)
|
log('fatal: %s\n' % e)
|
||||||
sys.exit(99)
|
sys.exit(99)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user