Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sshuttle/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def ipt_ttl(family, *args):
# with ttl 63. This makes the client side not recapture those
# connections, in case client == server.
try:
argsplus = list(args) + ['-m', 'ttl', '!', '--ttl', '63']
argsplus = list(args)
ipt(family, *argsplus)
except Fatal:
ipt(family, *args)
Expand Down
38 changes: 19 additions & 19 deletions sshuttle/methods/nat.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,24 @@ def _ipm(*args):
_ipt('-I', 'OUTPUT', '1', *args)
_ipt('-I', 'PREROUTING', '1', *args)

# Firstly we always skip all LOCAL addtrype address, i.e. avoid
# tunnelling the traffic designated to all local TCP/IP addresses.
_ipt('-A', chain, '-j', 'RETURN',
'-m', 'addrtype',
'--dst-type', 'LOCAL',
'!', '-p', 'udp')
# Skip LOCAL traffic if it's not DNS.
# This TTL hack allows the client and server to run on the
# same host. The connections the sshuttle server makes will
# have TTL set to 63.
_ipt_ttl('-A', chain, '-j', 'RETURN', '-m', 'ttl', '--ttl', '63')

# Redirect DNS traffic as requested. This includes routing traffic
# to localhost DNS servers through sshuttle.
for _, ip in [i for i in nslist if i[0] == family]:
_ipt('-A', chain, '-j', 'REDIRECT',
'--dest', '%s/32' % ip,
'-p', 'udp',
'--dport', '53',
'--to-ports', str(dnsport))

# Don't route any remaining local traffic through sshuttle.
_ipt('-A', chain, '-j', 'RETURN',
'-m', 'addrtype',
'--dst-type', 'LOCAL',
'-p', 'udp', '!', '--dport', '53')
'--dst-type', 'LOCAL')

# create new subnet entries.
for _, swidth, sexclude, snet, fport, lport \
Expand All @@ -74,16 +81,9 @@ def _ipm(*args):
'--dest', '%s/%s' % (snet, swidth),
*tcp_ports)
else:
_ipt_ttl('-A', chain, '-j', 'REDIRECT',
'--dest', '%s/%s' % (snet, swidth),
*(tcp_ports + ('--to-ports', str(port))))

for _, ip in [i for i in nslist if i[0] == family]:
_ipt_ttl('-A', chain, '-j', 'REDIRECT',
'--dest', '%s/32' % ip,
'-p', 'udp',
'--dport', '53',
'--to-ports', str(dnsport))
_ipt('-A', chain, '-j', 'REDIRECT',
'--dest', '%s/%s' % (snet, swidth),
*(tcp_ports + ('--to-ports', str(port))))

def restore_firewall(self, port, family, udp, user):
# only ipv4 supported with NAT
Expand Down
32 changes: 21 additions & 11 deletions sshuttle/methods/nft.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,26 @@ def _nft(action, *args):
_nft('add rule', 'output jump %s' % chain)
_nft('add rule', 'prerouting jump %s' % chain)

# This TTL hack allows the client and server to run on the
# same host. The connections the sshuttle server makes will
# have TTL set to 63.
_nft('add rule', chain, 'ip ttl == 63 return')

# Redirect DNS traffic as requested. This includes routing traffic
# to localhost DNS servers through sshuttle.
for _, ip in [i for i in nslist if i[0] == family]:
if family == socket.AF_INET:
_nft('add rule', chain, 'ip protocol udp ip daddr %s' % ip,
'udp dport { 53 }',
('redirect to :' + str(dnsport)))
elif family == socket.AF_INET6:
_nft('add rule', chain, 'ip6 protocol udp ip6 daddr %s' % ip,
'udp dport { 53 }',
('redirect to :' + str(dnsport)))

# Don't route any remaining local traffic through sshuttle
_nft('add rule', chain, 'fib daddr type local return')

# create new subnet entries.
for _, swidth, sexclude, snet, fport, lport \
in sorted(subnets, key=subnet_weight, reverse=True):
Expand All @@ -50,19 +70,9 @@ def _nft(action, *args):
'ip daddr %s/%s' % (snet, swidth), 'return')))
else:
_nft('add rule', chain, *(tcp_ports + (
'ip daddr %s/%s' % (snet, swidth), 'ip ttl != 63',
'ip daddr %s/%s' % (snet, swidth),
('redirect to :' + str(port)))))

for _, ip in [i for i in nslist if i[0] == family]:
if family == socket.AF_INET:
_nft('add rule', chain, 'ip protocol udp ip daddr %s' % ip,
'udp dport { 53 }', 'ip ttl != 63',
('redirect to :' + str(dnsport)))
elif family == socket.AF_INET6:
_nft('add rule', chain, 'ip6 protocol udp ip6 daddr %s' % ip,
'udp dport { 53 }', 'ip ttl != 63',
('redirect to :' + str(dnsport)))

def restore_firewall(self, port, family, udp, user):
if udp:
raise Exception("UDP not supported by nft method_name")
Expand Down
22 changes: 10 additions & 12 deletions tests/client/test_methods_nat.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,8 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
call(AF_INET, 'nat', 'sshuttle-1025')
]
assert mock_ipt_ttl.mock_calls == [
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'REDIRECT',
'--dest', u'1.2.3.0/24', '-p', 'tcp', '--dport', '8000:9000',
'--to-ports', '1025'),
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'REDIRECT',
'--dest', u'1.2.3.33/32', '-p', 'udp',
'--dport', '53', '--to-ports', '1027')
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'RETURN',
'-m', 'ttl', '--ttl', '63')
]
assert mock_ipt.mock_calls == [
call(AF_INET, 'nat', '-D', 'OUTPUT', '-j', 'sshuttle-1025'),
Expand All @@ -139,14 +135,16 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
call(AF_INET, 'nat', '-F', 'sshuttle-1025'),
call(AF_INET, 'nat', '-I', 'OUTPUT', '1', '-j', 'sshuttle-1025'),
call(AF_INET, 'nat', '-I', 'PREROUTING', '1', '-j', 'sshuttle-1025'),
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'REDIRECT',
'--dest', u'1.2.3.33/32', '-p', 'udp',
'--dport', '53', '--to-ports', '1027'),
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'RETURN',
'-m', 'addrtype', '--dst-type', 'LOCAL',
'!', '-p', 'udp'),
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'RETURN',
'-m', 'addrtype', '--dst-type', 'LOCAL',
'-p', 'udp', '!', '--dport', '53'),
'-m', 'addrtype', '--dst-type', 'LOCAL'),
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'RETURN',
'--dest', u'1.2.3.66/32', '-p', 'tcp', '--dport', '8080:8080')
'--dest', u'1.2.3.66/32', '-p', 'tcp', '--dport', '8080:8080'),
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'REDIRECT',
'--dest', u'1.2.3.0/24', '-p', 'tcp', '--dport', '8000:9000',
'--to-ports', '1025')
]
mock_ipt_chain_exists.reset_mock()
mock_ipt_ttl.reset_mock()
Expand Down