Remove ttl hack & require -r option.

Previously, it was possible to run sshuttle locally without using ssh
and connecting to a remote server. In this configuration, traffic was
redirected to the sshuttle server running on the localhost. However,
the firewall needed to distinguish between traffic leaving the
sshuttle server and traffic that originated from the machine that
still needed to be routed through the sshuttle server. The TTL of the
packets leaving the sshuttle server were manipulated to indicate to
the firewall what should happen. The TTL was adjusted for all packets
leaving the sshuttle server (even if it wasn't necessary because the
server and client were running on different machines).

Changing the TTL caused trouble and some machines, and
the --ttl option was added as a workaround to change how the TTL was
set for traffic leaving sshuttle. All of this added complexity to the
code for a feature (running the server on localhost) that is likely
only used for testing and rarely used by others.

This commit updates the associated documentation, but doesn't fully
fix the ipfw method since I am unable to test that.

This change will also make sshuttle fail to work if -r is used to
specify a localhost. Pull request #610 partially addresses that issue.

For example, see: #240, #490, #660, #606.
This commit is contained in:
Scott Kuhl 2021-05-31 23:33:55 -04:00
parent 6ae0b51c61
commit bc065e368d
20 changed files with 66 additions and 160 deletions

View File

@ -4,7 +4,7 @@ sshuttle
Synopsis Synopsis
-------- --------
**sshuttle** [*options*] [**-r** *[username@]sshserver[:port]*] \<*subnets* ...\> **sshuttle** [*options*] **-r** *[username@]sshserver[:port]* \<*subnets* ...\>
Description Description
@ -441,9 +441,7 @@ Example configuration file::
Discussion Discussion
---------- ----------
When it starts, :program:`sshuttle` creates an ssh session to the When it starts, :program:`sshuttle` creates an ssh session to the
server specified by the ``-r`` option. If ``-r`` is omitted, server specified by the ``-r`` option.
it will start both its client and server locally, which is
sometimes useful for testing.
After connecting to the remote server, :program:`sshuttle` uploads its After connecting to the remote server, :program:`sshuttle` uploads its
(python) source code to the remote end and executes it (python) source code to the remote end and executes it

View File

@ -20,7 +20,7 @@ Supports:
Requires: Requires:
* iptables DNAT, REDIRECT, and ttl modules. ip6tables for IPv6. * iptables DNAT and REDIRECT modules. ip6tables for IPv6.
Linux with nft method Linux with nft method
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~

View File

@ -42,4 +42,4 @@ import sshuttle.cmdline_options as options # noqa: E402
from sshuttle.server import main # noqa: E402 from sshuttle.server import main # noqa: E402
main(options.latency_control, options.latency_buffer_size, main(options.latency_control, options.latency_buffer_size,
options.auto_hosts, options.to_nameserver, options.auto_hosts, options.to_nameserver,
options.auto_nets, options.ttl) options.auto_nets)

View File

@ -44,6 +44,7 @@ def got_signal(signum, frame):
sys.exit(1) sys.exit(1)
# Filename of the pidfile created by the sshuttle client.
_pidname = None _pidname = None
@ -198,7 +199,7 @@ class MultiListener:
class FirewallClient: class FirewallClient:
def __init__(self, method_name, sudo_pythonpath, ttl): def __init__(self, method_name, sudo_pythonpath):
self.auto_nets = [] self.auto_nets = []
argvbase = ([sys.executable, sys.argv[0]] + argvbase = ([sys.executable, sys.argv[0]] +
@ -260,7 +261,7 @@ class FirewallClient:
def setup(self, subnets_include, subnets_exclude, nslist, def setup(self, subnets_include, subnets_exclude, nslist,
redirectport_v6, redirectport_v4, dnsport_v6, dnsport_v4, udp, redirectport_v6, redirectport_v4, dnsport_v6, dnsport_v4, udp,
user, ttl, tmark): user, tmark):
self.subnets_include = subnets_include self.subnets_include = subnets_include
self.subnets_exclude = subnets_exclude self.subnets_exclude = subnets_exclude
self.nslist = nslist self.nslist = nslist
@ -271,7 +272,6 @@ class FirewallClient:
self.udp = udp self.udp = udp
self.user = user self.user = user
self.tmark = tmark self.tmark = tmark
self.ttl = ttl
def check(self): def check(self):
rv = self.p.poll() rv = self.p.poll()
@ -310,9 +310,8 @@ class FirewallClient:
else: else:
user = b'%d' % self.user user = b'%d' % self.user
self.pfile.write(b'GO %d %s %d %s\n' % self.pfile.write(b'GO %d %s %s\n' %
(udp, user, self.ttl, (udp, user, bytes(self.tmark, 'ascii')))
bytes(self.tmark, 'ascii')))
self.pfile.flush() self.pfile.flush()
line = self.pfile.readline() line = self.pfile.readline()
@ -457,7 +456,7 @@ def ondns(listener, method, mux, handlers):
def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename, def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
python, latency_control, latency_buffer_size, python, latency_control, latency_buffer_size,
dns_listener, seed_hosts, auto_hosts, auto_nets, daemon, dns_listener, seed_hosts, auto_hosts, auto_nets, daemon,
to_nameserver, ttl): to_nameserver):
helpers.logprefix = 'c : ' helpers.logprefix = 'c : '
debug1('Starting client with Python version %s' debug1('Starting client with Python version %s'
@ -476,8 +475,7 @@ def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
latency_buffer_size=latency_buffer_size, latency_buffer_size=latency_buffer_size,
auto_hosts=auto_hosts, auto_hosts=auto_hosts,
to_nameserver=to_nameserver, to_nameserver=to_nameserver,
auto_nets=auto_nets, auto_nets=auto_nets))
ttl=ttl))
except socket.error as e: except socket.error as e:
if e.args[0] == errno.EPIPE: if e.args[0] == errno.EPIPE:
raise Fatal("failed to establish ssh session (1)") raise Fatal("failed to establish ssh session (1)")
@ -587,6 +585,7 @@ def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
% (expected, initstring)) % (expected, initstring))
log('Connected to server.') log('Connected to server.')
sys.stdout.flush() sys.stdout.flush()
if daemon: if daemon:
daemonize() daemonize()
log('daemonizing (%s).' % _pidname) log('daemonizing (%s).' % _pidname)
@ -673,12 +672,11 @@ def main(listenip_v6, listenip_v4,
latency_buffer_size, dns, nslist, latency_buffer_size, dns, nslist,
method_name, seed_hosts, auto_hosts, auto_nets, method_name, seed_hosts, auto_hosts, auto_nets,
subnets_include, subnets_exclude, daemon, to_nameserver, pidfile, subnets_include, subnets_exclude, daemon, to_nameserver, pidfile,
user, sudo_pythonpath, tmark, ttl): user, sudo_pythonpath, tmark):
if not remotename: if not remotename:
print("WARNING: You must specify -r/--remote to securely route " raise Fatal("You must use -r/--remote to specify a remote "
"traffic to a remote machine. Running without -r/--remote " "host to route traffic through.")
"is only recommended for testing.")
if daemon: if daemon:
try: try:
@ -689,7 +687,7 @@ def main(listenip_v6, listenip_v4,
debug1('Starting sshuttle proxy (version %s).' % __version__) debug1('Starting sshuttle proxy (version %s).' % __version__)
helpers.logprefix = 'c : ' helpers.logprefix = 'c : '
fw = FirewallClient(method_name, sudo_pythonpath, ttl) fw = FirewallClient(method_name, sudo_pythonpath)
# nslist is the list of name severs to intercept. If --dns is # nslist is the list of name severs to intercept. If --dns is
# used, we add all DNS servers in resolv.conf. Otherwise, the list # used, we add all DNS servers in resolv.conf. Otherwise, the list
@ -1006,14 +1004,14 @@ def main(listenip_v6, listenip_v4,
# start the firewall # start the firewall
fw.setup(subnets_include, subnets_exclude, nslist, fw.setup(subnets_include, subnets_exclude, nslist,
redirectport_v6, redirectport_v4, dnsport_v6, dnsport_v4, redirectport_v6, redirectport_v4, dnsport_v6, dnsport_v4,
required.udp, user, ttl, tmark) required.udp, user, tmark)
# start the client process # start the client process
try: try:
return _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename, return _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
python, latency_control, latency_buffer_size, python, latency_control, latency_buffer_size,
dns_listener, seed_hosts, auto_hosts, auto_nets, dns_listener, seed_hosts, auto_hosts, auto_nets,
daemon, to_nameserver, ttl) daemon, to_nameserver)
finally: finally:
try: try:
if daemon: if daemon:

View File

@ -43,7 +43,7 @@ def main():
if opt.firewall: if opt.firewall:
if opt.subnets or opt.subnets_file: if opt.subnets or opt.subnets_file:
parser.error('exactly zero arguments expected') parser.error('exactly zero arguments expected')
return firewall.main(opt.method, opt.syslog, opt.ttl) return firewall.main(opt.method, opt.syslog)
elif opt.hostwatch: elif opt.hostwatch:
return hostwatch.hw_main(opt.subnets, opt.auto_hosts) return hostwatch.hw_main(opt.subnets, opt.auto_hosts)
else: else:
@ -116,8 +116,7 @@ def main():
opt.pidfile, opt.pidfile,
opt.user, opt.user,
opt.sudo_pythonpath, opt.sudo_pythonpath,
opt.tmark, opt.tmark)
opt.ttl)
if return_code == 0: if return_code == 0:
log('Normal exit code, exiting...') log('Normal exit code, exiting...')

View File

@ -121,7 +121,7 @@ def flush_systemd_dns_cache():
# exit. In case that fails, it's not the end of the world; future runs will # exit. In case that fails, it's not the end of the world; future runs will
# supercede it in the transproxy list, at least, so the leftover rules # supercede it in the transproxy list, at least, so the leftover rules
# are hopefully harmless. # are hopefully harmless.
def main(method_name, syslog, ttl): def main(method_name, syslog):
helpers.logprefix = 'fw: ' helpers.logprefix = 'fw: '
stdin, stdout = setup_daemon() stdin, stdout = setup_daemon()
hostmap = {} hostmap = {}
@ -223,13 +223,12 @@ def main(method_name, syslog, ttl):
raise Fatal('expected GO but got %r' % line) raise Fatal('expected GO but got %r' % line)
_, _, args = line.partition(" ") _, _, args = line.partition(" ")
udp, user, ttl, tmark = args.strip().split(" ", 3) udp, user, tmark = args.strip().split(" ", 2)
udp = bool(int(udp)) udp = bool(int(udp))
if user == '-': if user == '-':
user = None user = None
ttl = int(ttl) debug2('Got udp: %r, user: %r, tmark: %s' %
debug2('Got udp: %r, user: %r, ttl: %s, tmark: %s' % (udp, user, tmark))
(udp, user, ttl, tmark))
subnets_v6 = [i for i in subnets if i[0] == socket.AF_INET6] subnets_v6 = [i for i in subnets if i[0] == socket.AF_INET6]
nslist_v6 = [i for i in nslist if i[0] == socket.AF_INET6] nslist_v6 = [i for i in nslist if i[0] == socket.AF_INET6]
@ -244,14 +243,14 @@ def main(method_name, syslog, ttl):
method.setup_firewall( method.setup_firewall(
port_v6, dnsport_v6, nslist_v6, port_v6, dnsport_v6, nslist_v6,
socket.AF_INET6, subnets_v6, udp, socket.AF_INET6, subnets_v6, udp,
user, ttl, tmark) user, tmark)
if subnets_v4 or nslist_v4: if subnets_v4 or nslist_v4:
debug2('setting up IPv4.') debug2('setting up IPv4.')
method.setup_firewall( method.setup_firewall(
port_v4, dnsport_v4, nslist_v4, port_v4, dnsport_v4, nslist_v4,
socket.AF_INET, subnets_v4, udp, socket.AF_INET, subnets_v4, udp,
user, ttl, tmark) user, tmark)
flush_systemd_dns_cache() flush_systemd_dns_cache()
stdout.write('STARTED\n') stdout.write('STARTED\n')

View File

@ -49,25 +49,3 @@ def nft(family, table, action, *args):
rv = ssubprocess.call(argv, env=get_env()) rv = ssubprocess.call(argv, env=get_env())
if rv: if rv:
raise Fatal('%r returned %d' % (argv, rv)) raise Fatal('%r returned %d' % (argv, rv))
_no_ttl_module = False
def ipt_ttl(family, *args):
global _no_ttl_module
if not _no_ttl_module:
# we avoid infinite loops by generating server-side connections
# with ttl 63. This makes the client side not recapture those
# connections, in case client == server.
try:
argsplus = list(args)
ipt(family, *argsplus)
except Fatal:
ipt(family, *args)
# we only get here if the non-ttl attempt succeeds
log('WARNING: your iptables is missing '
'the ttl module.')
_no_ttl_module = True
else:
ipt(family, *args)

View File

@ -91,7 +91,7 @@ class BaseMethod(object):
(key, self.name)) (key, self.name))
def setup_firewall(self, port, dnsport, nslist, family, subnets, udp, def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
user, ttl, tmark): user, tmark):
raise NotImplementedError() raise NotImplementedError()
def restore_firewall(self, port, family, udp, user): def restore_firewall(self, port, family, udp, user):

View File

@ -177,7 +177,6 @@ class Method(BaseMethod):
sender.setsockopt(socket.SOL_IP, IP_BINDANY, 1) sender.setsockopt(socket.SOL_IP, IP_BINDANY, 1)
sender.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sender.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sender.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) sender.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
sender.setsockopt(socket.SOL_IP, socket.IP_TTL, 63)
sender.bind(srcip) sender.bind(srcip)
sender.sendto(data, dstip) sender.sendto(data, dstip)
sender.close() sender.close()
@ -189,7 +188,12 @@ class Method(BaseMethod):
# udp_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVDSTADDR, 1) # udp_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVDSTADDR, 1)
def setup_firewall(self, port, dnsport, nslist, family, subnets, udp, def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
user, ttl, tmark): user, tmark):
# TODO: The ttl hack to allow the host and server to run on
# the same machine has been removed but this method hasn't
# been updated yet.
ttl = 63
# IPv6 not supported # IPv6 not supported
if family not in [socket.AF_INET]: if family not in [socket.AF_INET]:
raise Exception( raise Exception(

View File

@ -1,7 +1,7 @@
import socket import socket
from sshuttle.firewall import subnet_weight from sshuttle.firewall import subnet_weight
from sshuttle.helpers import family_to_string, which, debug2 from sshuttle.helpers import family_to_string, which, debug2
from sshuttle.linux import ipt, ipt_ttl, ipt_chain_exists, nonfatal from sshuttle.linux import ipt, ipt_chain_exists, nonfatal
from sshuttle.methods import BaseMethod from sshuttle.methods import BaseMethod
@ -13,7 +13,7 @@ class Method(BaseMethod):
# recently-started one will win (because we use "-I OUTPUT 1" instead of # recently-started one will win (because we use "-I OUTPUT 1" instead of
# "-A OUTPUT"). # "-A OUTPUT").
def setup_firewall(self, port, dnsport, nslist, family, subnets, udp, def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
user, ttl, tmark): user, tmark):
if family != socket.AF_INET and family != socket.AF_INET6: if family != socket.AF_INET and family != socket.AF_INET6:
raise Exception( raise Exception(
'Address family "%s" unsupported by nat method_name' 'Address family "%s" unsupported by nat method_name'
@ -25,9 +25,6 @@ class Method(BaseMethod):
def _ipt(*args): def _ipt(*args):
return ipt(family, table, *args) return ipt(family, table, *args)
def _ipt_ttl(*args):
return ipt_ttl(family, table, *args)
def _ipm(*args): def _ipm(*args):
return ipt(family, "mangle", *args) return ipt(family, "mangle", *args)
@ -48,16 +45,6 @@ class Method(BaseMethod):
_ipt('-I', 'OUTPUT', '1', *args) _ipt('-I', 'OUTPUT', '1', *args)
_ipt('-I', 'PREROUTING', '1', *args) _ipt('-I', 'PREROUTING', '1', *args)
# 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.
if family == socket.AF_INET:
_ipt_ttl('-A', chain, '-j', 'RETURN', '-m', 'ttl', '--ttl',
'%s' % ttl)
else: # ipv6, ttl is renamed to 'hop limit'
_ipt_ttl('-A', chain, '-j', 'RETURN', '-m', 'hl', '--hl-eq',
'%s' % ttl)
# Redirect DNS traffic as requested. This includes routing traffic # Redirect DNS traffic as requested. This includes routing traffic
# to localhost DNS servers through sshuttle. # to localhost DNS servers through sshuttle.
for _, ip in [i for i in nslist if i[0] == family]: for _, ip in [i for i in nslist if i[0] == family]:
@ -102,9 +89,6 @@ class Method(BaseMethod):
def _ipt(*args): def _ipt(*args):
return ipt(family, table, *args) return ipt(family, table, *args)
def _ipt_ttl(*args):
return ipt_ttl(family, table, *args)
def _ipm(*args): def _ipm(*args):
return ipt(family, "mangle", *args) return ipt(family, "mangle", *args)

View File

@ -13,7 +13,7 @@ class Method(BaseMethod):
# recently-started one will win (because we use "-I OUTPUT 1" instead of # recently-started one will win (because we use "-I OUTPUT 1" instead of
# "-A OUTPUT"). # "-A OUTPUT").
def setup_firewall(self, port, dnsport, nslist, family, subnets, udp, def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
user, ttl, tmark): user, tmark):
if udp: if udp:
raise Exception("UDP not supported by nft") raise Exception("UDP not supported by nft")
@ -45,14 +45,6 @@ class Method(BaseMethod):
else: else:
_nft('add rule', chain, 'meta', 'nfproto', '!=', 'ipv6', 'return') _nft('add rule', chain, 'meta', 'nfproto', '!=', 'ipv6', 'return')
# 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.
if family == socket.AF_INET:
_nft('add rule', chain, 'ip ttl == 63 return')
elif family == socket.AF_INET6:
_nft('add rule', chain, 'ip6 hoplimit == 63 return')
# Strings to use below to simplify our code # Strings to use below to simplify our code
if family == socket.AF_INET: if family == socket.AF_INET:
ip_version_l = 'ipv4' ip_version_l = 'ipv4'

View File

@ -448,7 +448,7 @@ class Method(BaseMethod):
return sock.getsockname() return sock.getsockname()
def setup_firewall(self, port, dnsport, nslist, family, subnets, udp, def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
user, ttl, tmark): user, tmark):
if family not in [socket.AF_INET, socket.AF_INET6]: if family not in [socket.AF_INET, socket.AF_INET6]:
raise Exception( raise Exception(
'Address family "%s" unsupported by pf method_name' 'Address family "%s" unsupported by pf method_name'

View File

@ -1,7 +1,7 @@
import struct import struct
from sshuttle.firewall import subnet_weight from sshuttle.firewall import subnet_weight
from sshuttle.helpers import family_to_string from sshuttle.helpers import family_to_string
from sshuttle.linux import ipt, ipt_ttl, ipt_chain_exists from sshuttle.linux import ipt, ipt_chain_exists
from sshuttle.methods import BaseMethod from sshuttle.methods import BaseMethod
from sshuttle.helpers import debug1, debug2, debug3, Fatal, which from sshuttle.helpers import debug1, debug2, debug3, Fatal, which
@ -151,7 +151,7 @@ class Method(BaseMethod):
udp_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVORIGDSTADDR, 1) udp_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVORIGDSTADDR, 1)
def setup_firewall(self, port, dnsport, nslist, family, subnets, udp, def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
user, ttl, tmark): user, tmark):
if family not in [socket.AF_INET, socket.AF_INET6]: if family not in [socket.AF_INET, socket.AF_INET6]:
raise Exception( raise Exception(
'Address family "%s" unsupported by tproxy method' 'Address family "%s" unsupported by tproxy method'
@ -162,9 +162,6 @@ class Method(BaseMethod):
def _ipt(*args): def _ipt(*args):
return ipt(family, table, *args) return ipt(family, table, *args)
def _ipt_ttl(*args):
return ipt_ttl(family, table, *args)
def _ipt_proto_ports(proto, fport, lport): def _ipt_proto_ports(proto, fport, lport):
return proto + ('--dport', '%d:%d' % (fport, lport)) \ return proto + ('--dport', '%d:%d' % (fport, lport)) \
if fport else proto if fport else proto
@ -279,9 +276,6 @@ class Method(BaseMethod):
def _ipt(*args): def _ipt(*args):
return ipt(family, table, *args) return ipt(family, table, *args)
def _ipt_ttl(*args):
return ipt_ttl(family, table, *args)
mark_chain = 'sshuttle-m-%s' % port mark_chain = 'sshuttle-m-%s' % port
tproxy_chain = 'sshuttle-t-%s' % port tproxy_chain = 'sshuttle-t-%s' % port
divert_chain = 'sshuttle-d-%s' % port divert_chain = 'sshuttle-d-%s' % port

View File

@ -173,7 +173,7 @@ class MyArgumentParser(ArgumentParser):
parser = MyArgumentParser( parser = MyArgumentParser(
prog="sshuttle", prog="sshuttle",
usage="%(prog)s [-l [ip:]port] [-r [user@]sshserver[:port]] <subnets...>", usage="%(prog)s [-l [ip:]port] -r [user@]sshserver[:port] <subnets...>",
fromfile_prefix_chars="@" fromfile_prefix_chars="@"
) )
parser.add_argument( parser.add_argument(
@ -389,15 +389,6 @@ parser.add_argument(
(internal use only) (internal use only)
""" """
) )
parser.add_argument(
"--ttl",
type=int,
default=63,
help="""
Override the TTL for the connections made by the sshuttle server.
Default is 63.
"""
)
parser.add_argument( parser.add_argument(
"--hostwatch", "--hostwatch",
action="store_true", action="store_true",

View File

@ -152,7 +152,7 @@ class Hostwatch:
class DnsProxy(Handler): class DnsProxy(Handler):
def __init__(self, mux, chan, request, to_nameserver, ttl): def __init__(self, mux, chan, request, to_nameserver):
Handler.__init__(self, []) Handler.__init__(self, [])
self.timeout = time.time() + 30 self.timeout = time.time() + 30
self.mux = mux self.mux = mux
@ -162,7 +162,6 @@ class DnsProxy(Handler):
self.peers = {} self.peers = {}
self.to_ns_peer = None self.to_ns_peer = None
self.to_ns_port = None self.to_ns_port = None
self.ttl = ttl
if to_nameserver is None: if to_nameserver is None:
self.to_nameserver = None self.to_nameserver = None
else: else:
@ -192,7 +191,6 @@ class DnsProxy(Handler):
family, sockaddr = self._addrinfo(peer, port) family, sockaddr = self._addrinfo(peer, port)
sock = socket.socket(family, socket.SOCK_DGRAM) sock = socket.socket(family, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_IP, socket.IP_TTL, self.ttl)
sock.connect(sockaddr) sock.connect(sockaddr)
self.peers[sock] = peer self.peers[sock] = peer
@ -241,15 +239,13 @@ class DnsProxy(Handler):
class UdpProxy(Handler): class UdpProxy(Handler):
def __init__(self, mux, chan, family, ttl): def __init__(self, mux, chan, family):
sock = socket.socket(family, socket.SOCK_DGRAM) sock = socket.socket(family, socket.SOCK_DGRAM)
Handler.__init__(self, [sock]) Handler.__init__(self, [sock])
self.timeout = time.time() + 30 self.timeout = time.time() + 30
self.mux = mux self.mux = mux
self.chan = chan self.chan = chan
self.sock = sock self.sock = sock
if family == socket.AF_INET:
self.sock.setsockopt(socket.SOL_IP, socket.IP_TTL, ttl)
def send(self, dstip, data): def send(self, dstip, data):
debug2('UDP: sending to %r port %d' % dstip) debug2('UDP: sending to %r port %d' % dstip)
@ -273,7 +269,7 @@ class UdpProxy(Handler):
def main(latency_control, latency_buffer_size, auto_hosts, to_nameserver, def main(latency_control, latency_buffer_size, auto_hosts, to_nameserver,
auto_nets, ttl): auto_nets):
try: try:
helpers.logprefix = ' s: ' helpers.logprefix = ' s: '
debug1('Starting server with Python version %s' debug1('Starting server with Python version %s'
@ -350,7 +346,7 @@ def main(latency_control, latency_buffer_size, auto_hosts, to_nameserver,
def dns_req(channel, data): def dns_req(channel, data):
debug2('Incoming DNS request channel=%d.' % channel) debug2('Incoming DNS request channel=%d.' % channel)
h = DnsProxy(mux, channel, data, to_nameserver, ttl) h = DnsProxy(mux, channel, data, to_nameserver)
handlers.append(h) handlers.append(h)
dnshandlers[channel] = h dnshandlers[channel] = h
mux.got_dns_req = dns_req mux.got_dns_req = dns_req
@ -381,7 +377,7 @@ def main(latency_control, latency_buffer_size, auto_hosts, to_nameserver,
raise Fatal('UDP connection channel %d already open' % raise Fatal('UDP connection channel %d already open' %
channel) channel)
else: else:
h = UdpProxy(mux, channel, family, ttl) h = UdpProxy(mux, channel, family)
handlers.append(h) handlers.append(h)
udphandlers[channel] = h udphandlers[channel] = h
mux.got_udp_open = udp_open mux.got_udp_open = udp_open

View File

@ -586,7 +586,7 @@ class MuxWrapper(SockWrapper):
def connect_dst(family, ip, port): def connect_dst(family, ip, port):
debug2('Connecting to %s:%d' % (ip, port)) debug2('Connecting to %s:%d' % (ip, port))
outsock = socket.socket(family) outsock = socket.socket(family)
outsock.setsockopt(socket.SOL_IP, socket.IP_TTL, 63)
return SockWrapper(outsock, outsock, return SockWrapper(outsock, outsock,
connect_to=(ip, port), connect_to=(ip, port),
peername='%s:%d' % (ip, port)) peername='%s:%d' % (ip, port))

View File

@ -15,7 +15,7 @@ NSLIST
{inet},1.2.3.33 {inet},1.2.3.33
{inet6},2404:6800:4004:80c::33 {inet6},2404:6800:4004:80c::33
PORTS 1024,1025,1026,1027 PORTS 1024,1025,1026,1027
GO 1 - 63 0x01 GO 1 - 0x01
HOST 1.2.3.3,existing HOST 1.2.3.3,existing
""".format(inet=AF_INET, inet6=AF_INET6)) """.format(inet=AF_INET, inet6=AF_INET6))
stdout = Mock() stdout = Mock()
@ -100,7 +100,7 @@ def test_main(mock_get_method, mock_setup_daemon, mock_rewrite_etc_hosts):
mock_get_method("not_auto").name = "test" mock_get_method("not_auto").name = "test"
mock_get_method.reset_mock() mock_get_method.reset_mock()
sshuttle.firewall.main("not_auto", False, 63) sshuttle.firewall.main("not_auto", False)
assert mock_rewrite_etc_hosts.mock_calls == [ assert mock_rewrite_etc_hosts.mock_calls == [
call({'1.2.3.3': 'existing'}, 1024), call({'1.2.3.3': 'existing'}, 1024),
@ -126,7 +126,7 @@ def test_main(mock_get_method, mock_setup_daemon, mock_rewrite_etc_hosts):
(AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 80, 80)], (AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 80, 80)],
True, True,
None, None,
63, '0x01'), '0x01'),
call().setup_firewall( call().setup_firewall(
1025, 1027, 1025, 1027,
[(AF_INET, u'1.2.3.33')], [(AF_INET, u'1.2.3.33')],
@ -135,7 +135,7 @@ def test_main(mock_get_method, mock_setup_daemon, mock_rewrite_etc_hosts):
(AF_INET, 32, True, u'1.2.3.66', 8080, 8080)], (AF_INET, 32, True, u'1.2.3.66', 8080, 8080)],
True, True,
None, None,
63, '0x01'), '0x01'),
call().restore_firewall(1024, AF_INET6, True, None), call().restore_firewall(1024, AF_INET6, True, None),
call().restore_firewall(1025, AF_INET, True, None), call().restore_firewall(1025, AF_INET, True, None),
] ]

View File

@ -85,15 +85,13 @@ def test_firewall_command():
@patch('sshuttle.methods.nat.ipt') @patch('sshuttle.methods.nat.ipt')
@patch('sshuttle.methods.nat.ipt_ttl')
@patch('sshuttle.methods.nat.ipt_chain_exists') @patch('sshuttle.methods.nat.ipt_chain_exists')
def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt): def test_setup_firewall(mock_ipt_chain_exists, mock_ipt):
mock_ipt_chain_exists.return_value = True mock_ipt_chain_exists.return_value = True
method = get_method('nat') method = get_method('nat')
assert method.name == 'nat' assert method.name == 'nat'
assert mock_ipt_chain_exists.mock_calls == [] assert mock_ipt_chain_exists.mock_calls == []
assert mock_ipt_ttl.mock_calls == []
assert mock_ipt.mock_calls == [] assert mock_ipt.mock_calls == []
method.setup_firewall( method.setup_firewall(
1024, 1026, 1024, 1026,
@ -103,15 +101,11 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
(AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 80, 80)], (AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 80, 80)],
False, False,
None, None,
63, '0x01') '0x01')
assert mock_ipt_chain_exists.mock_calls == [ assert mock_ipt_chain_exists.mock_calls == [
call(AF_INET6, 'nat', 'sshuttle-1024') call(AF_INET6, 'nat', 'sshuttle-1024')
] ]
assert mock_ipt_ttl.mock_calls == [
call(AF_INET6, 'nat', '-A', 'sshuttle-1024', '-j', 'RETURN',
'-m', 'hl', '--hl-eq', '63')
]
assert mock_ipt.mock_calls == [ assert mock_ipt.mock_calls == [
call(AF_INET6, 'nat', '-D', 'OUTPUT', '-j', 'sshuttle-1024'), call(AF_INET6, 'nat', '-D', 'OUTPUT', '-j', 'sshuttle-1024'),
call(AF_INET6, 'nat', '-D', 'PREROUTING', '-j', 'sshuttle-1024'), call(AF_INET6, 'nat', '-D', 'PREROUTING', '-j', 'sshuttle-1024'),
@ -134,11 +128,9 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
'--to-ports', '1024') '--to-ports', '1024')
] ]
mock_ipt_chain_exists.reset_mock() mock_ipt_chain_exists.reset_mock()
mock_ipt_ttl.reset_mock()
mock_ipt.reset_mock() mock_ipt.reset_mock()
assert mock_ipt_chain_exists.mock_calls == [] assert mock_ipt_chain_exists.mock_calls == []
assert mock_ipt_ttl.mock_calls == []
assert mock_ipt.mock_calls == [] assert mock_ipt.mock_calls == []
with pytest.raises(Exception) as excinfo: with pytest.raises(Exception) as excinfo:
@ -150,10 +142,9 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
(AF_INET, 32, True, u'1.2.3.66', 8080, 8080)], (AF_INET, 32, True, u'1.2.3.66', 8080, 8080)],
True, True,
None, None,
63, '0x01') '0x01')
assert str(excinfo.value) == 'UDP not supported by nat method_name' assert str(excinfo.value) == 'UDP not supported by nat method_name'
assert mock_ipt_chain_exists.mock_calls == [] assert mock_ipt_chain_exists.mock_calls == []
assert mock_ipt_ttl.mock_calls == []
assert mock_ipt.mock_calls == [] assert mock_ipt.mock_calls == []
method.setup_firewall( method.setup_firewall(
@ -164,14 +155,10 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
(AF_INET, 32, True, u'1.2.3.66', 8080, 8080)], (AF_INET, 32, True, u'1.2.3.66', 8080, 8080)],
False, False,
None, None,
63, '0x01') '0x01')
assert mock_ipt_chain_exists.mock_calls == [ assert mock_ipt_chain_exists.mock_calls == [
call(AF_INET, 'nat', 'sshuttle-1025') call(AF_INET, 'nat', 'sshuttle-1025')
] ]
assert mock_ipt_ttl.mock_calls == [
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'RETURN',
'-m', 'ttl', '--ttl', '63')
]
assert mock_ipt.mock_calls == [ assert mock_ipt.mock_calls == [
call(AF_INET, 'nat', '-D', 'OUTPUT', '-j', 'sshuttle-1025'), call(AF_INET, 'nat', '-D', 'OUTPUT', '-j', 'sshuttle-1025'),
call(AF_INET, 'nat', '-D', 'PREROUTING', '-j', 'sshuttle-1025'), call(AF_INET, 'nat', '-D', 'PREROUTING', '-j', 'sshuttle-1025'),
@ -193,14 +180,12 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
'--to-ports', '1025') '--to-ports', '1025')
] ]
mock_ipt_chain_exists.reset_mock() mock_ipt_chain_exists.reset_mock()
mock_ipt_ttl.reset_mock()
mock_ipt.reset_mock() mock_ipt.reset_mock()
method.restore_firewall(1025, AF_INET, False, None) method.restore_firewall(1025, AF_INET, False, None)
assert mock_ipt_chain_exists.mock_calls == [ assert mock_ipt_chain_exists.mock_calls == [
call(AF_INET, 'nat', 'sshuttle-1025') call(AF_INET, 'nat', 'sshuttle-1025')
] ]
assert mock_ipt_ttl.mock_calls == []
assert mock_ipt.mock_calls == [ assert mock_ipt.mock_calls == [
call(AF_INET, 'nat', '-D', 'OUTPUT', '-j', call(AF_INET, 'nat', '-D', 'OUTPUT', '-j',
'sshuttle-1025'), 'sshuttle-1025'),
@ -210,14 +195,12 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
call(AF_INET, 'nat', '-X', 'sshuttle-1025') call(AF_INET, 'nat', '-X', 'sshuttle-1025')
] ]
mock_ipt_chain_exists.reset_mock() mock_ipt_chain_exists.reset_mock()
mock_ipt_ttl.reset_mock()
mock_ipt.reset_mock() mock_ipt.reset_mock()
method.restore_firewall(1025, AF_INET6, False, None) method.restore_firewall(1025, AF_INET6, False, None)
assert mock_ipt_chain_exists.mock_calls == [ assert mock_ipt_chain_exists.mock_calls == [
call(AF_INET6, 'nat', 'sshuttle-1025') call(AF_INET6, 'nat', 'sshuttle-1025')
] ]
assert mock_ipt_ttl.mock_calls == []
assert mock_ipt.mock_calls == [ assert mock_ipt.mock_calls == [
call(AF_INET6, 'nat', '-D', 'OUTPUT', '-j', 'sshuttle-1025'), call(AF_INET6, 'nat', '-D', 'OUTPUT', '-j', 'sshuttle-1025'),
call(AF_INET6, 'nat', '-D', 'PREROUTING', '-j', call(AF_INET6, 'nat', '-D', 'PREROUTING', '-j',
@ -226,5 +209,4 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
call(AF_INET6, 'nat', '-X', 'sshuttle-1025') call(AF_INET6, 'nat', '-X', 'sshuttle-1025')
] ]
mock_ipt_chain_exists.reset_mock() mock_ipt_chain_exists.reset_mock()
mock_ipt_ttl.reset_mock()
mock_ipt.reset_mock() mock_ipt.reset_mock()

View File

@ -187,7 +187,7 @@ def test_setup_firewall_darwin(mock_pf_get_dev, mock_ioctl, mock_pfctl):
(AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 8080, 8080)], (AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 8080, 8080)],
False, False,
None, None,
63, '0x01') '0x01')
assert mock_ioctl.mock_calls == [ assert mock_ioctl.mock_calls == [
call(mock_pf_get_dev(), 0xC4704433, ANY), call(mock_pf_get_dev(), 0xC4704433, ANY),
call(mock_pf_get_dev(), 0xCC20441A, ANY), call(mock_pf_get_dev(), 0xCC20441A, ANY),
@ -227,7 +227,7 @@ def test_setup_firewall_darwin(mock_pf_get_dev, mock_ioctl, mock_pfctl):
(AF_INET, 32, True, u'1.2.3.66', 80, 80)], (AF_INET, 32, True, u'1.2.3.66', 80, 80)],
True, True,
None, None,
63, '0x01') '0x01')
assert str(excinfo.value) == 'UDP not supported by pf method_name' assert str(excinfo.value) == 'UDP not supported by pf method_name'
assert mock_pf_get_dev.mock_calls == [] assert mock_pf_get_dev.mock_calls == []
assert mock_ioctl.mock_calls == [] assert mock_ioctl.mock_calls == []
@ -241,7 +241,7 @@ def test_setup_firewall_darwin(mock_pf_get_dev, mock_ioctl, mock_pfctl):
(AF_INET, 32, True, u'1.2.3.66', 80, 80)], (AF_INET, 32, True, u'1.2.3.66', 80, 80)],
False, False,
None, None,
63, '0x01') '0x01')
assert mock_ioctl.mock_calls == [ assert mock_ioctl.mock_calls == [
call(mock_pf_get_dev(), 0xC4704433, ANY), call(mock_pf_get_dev(), 0xC4704433, ANY),
call(mock_pf_get_dev(), 0xCC20441A, ANY), call(mock_pf_get_dev(), 0xCC20441A, ANY),
@ -302,7 +302,7 @@ def test_setup_firewall_freebsd(mock_pf_get_dev, mock_ioctl, mock_pfctl,
(AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 8080, 8080)], (AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 8080, 8080)],
False, False,
None, None,
63, '0x01') '0x01')
assert mock_pfctl.mock_calls == [ assert mock_pfctl.mock_calls == [
call('-s all'), call('-s all'),
@ -335,7 +335,7 @@ def test_setup_firewall_freebsd(mock_pf_get_dev, mock_ioctl, mock_pfctl,
(AF_INET, 32, True, u'1.2.3.66', 80, 80)], (AF_INET, 32, True, u'1.2.3.66', 80, 80)],
True, True,
None, None,
63, '0x01') '0x01')
assert str(excinfo.value) == 'UDP not supported by pf method_name' assert str(excinfo.value) == 'UDP not supported by pf method_name'
assert mock_pf_get_dev.mock_calls == [] assert mock_pf_get_dev.mock_calls == []
assert mock_ioctl.mock_calls == [] assert mock_ioctl.mock_calls == []
@ -349,7 +349,7 @@ def test_setup_firewall_freebsd(mock_pf_get_dev, mock_ioctl, mock_pfctl,
(AF_INET, 32, True, u'1.2.3.66', 80, 80)], (AF_INET, 32, True, u'1.2.3.66', 80, 80)],
False, False,
None, None,
63, '0x01') '0x01')
assert mock_ioctl.mock_calls == [ assert mock_ioctl.mock_calls == [
call(mock_pf_get_dev(), 0xC4704433, ANY), call(mock_pf_get_dev(), 0xC4704433, ANY),
call(mock_pf_get_dev(), 0xCBE0441A, ANY), call(mock_pf_get_dev(), 0xCBE0441A, ANY),
@ -408,7 +408,7 @@ def test_setup_firewall_openbsd(mock_pf_get_dev, mock_ioctl, mock_pfctl):
(AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 8080, 8080)], (AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 8080, 8080)],
False, False,
None, None,
63, '0x01') '0x01')
assert mock_ioctl.mock_calls == [ assert mock_ioctl.mock_calls == [
call(mock_pf_get_dev(), 0xcd60441a, ANY), call(mock_pf_get_dev(), 0xcd60441a, ANY),
@ -445,7 +445,7 @@ def test_setup_firewall_openbsd(mock_pf_get_dev, mock_ioctl, mock_pfctl):
(AF_INET, 32, True, u'1.2.3.66', 80, 80)], (AF_INET, 32, True, u'1.2.3.66', 80, 80)],
True, True,
None, None,
63, '0x01') '0x01')
assert str(excinfo.value) == 'UDP not supported by pf method_name' assert str(excinfo.value) == 'UDP not supported by pf method_name'
assert mock_pf_get_dev.mock_calls == [] assert mock_pf_get_dev.mock_calls == []
assert mock_ioctl.mock_calls == [] assert mock_ioctl.mock_calls == []
@ -459,7 +459,7 @@ def test_setup_firewall_openbsd(mock_pf_get_dev, mock_ioctl, mock_pfctl):
(AF_INET, 32, True, u'1.2.3.66', 80, 80)], (AF_INET, 32, True, u'1.2.3.66', 80, 80)],
False, False,
None, None,
63, '0x01') '0x01')
assert mock_ioctl.mock_calls == [ assert mock_ioctl.mock_calls == [
call(mock_pf_get_dev(), 0xcd60441a, ANY), call(mock_pf_get_dev(), 0xcd60441a, ANY),
call(mock_pf_get_dev(), 0xcd60441a, ANY), call(mock_pf_get_dev(), 0xcd60441a, ANY),

View File

@ -92,9 +92,8 @@ def test_firewall_command():
@patch('sshuttle.methods.tproxy.ipt') @patch('sshuttle.methods.tproxy.ipt')
@patch('sshuttle.methods.tproxy.ipt_ttl')
@patch('sshuttle.methods.tproxy.ipt_chain_exists') @patch('sshuttle.methods.tproxy.ipt_chain_exists')
def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt): def test_setup_firewall(mock_ipt_chain_exists, mock_ipt):
mock_ipt_chain_exists.return_value = True mock_ipt_chain_exists.return_value = True
method = get_method('tproxy') method = get_method('tproxy')
assert method.name == 'tproxy' assert method.name == 'tproxy'
@ -109,13 +108,12 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
(AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 8080, 8080)], (AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 8080, 8080)],
True, True,
None, None,
63, '0x01') '0x01')
assert mock_ipt_chain_exists.mock_calls == [ assert mock_ipt_chain_exists.mock_calls == [
call(AF_INET6, 'mangle', 'sshuttle-m-1024'), call(AF_INET6, 'mangle', 'sshuttle-m-1024'),
call(AF_INET6, 'mangle', 'sshuttle-t-1024'), call(AF_INET6, 'mangle', 'sshuttle-t-1024'),
call(AF_INET6, 'mangle', 'sshuttle-d-1024') call(AF_INET6, 'mangle', 'sshuttle-d-1024')
] ]
assert mock_ipt_ttl.mock_calls == []
assert mock_ipt.mock_calls == [ assert mock_ipt.mock_calls == [
call(AF_INET6, 'mangle', '-D', 'OUTPUT', '-j', 'sshuttle-m-1024'), call(AF_INET6, 'mangle', '-D', 'OUTPUT', '-j', 'sshuttle-m-1024'),
call(AF_INET6, 'mangle', '-F', 'sshuttle-m-1024'), call(AF_INET6, 'mangle', '-F', 'sshuttle-m-1024'),
@ -182,7 +180,6 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
'--on-port', '1024') '--on-port', '1024')
] ]
mock_ipt_chain_exists.reset_mock() mock_ipt_chain_exists.reset_mock()
mock_ipt_ttl.reset_mock()
mock_ipt.reset_mock() mock_ipt.reset_mock()
method.restore_firewall(1025, AF_INET6, True, None) method.restore_firewall(1025, AF_INET6, True, None)
@ -191,7 +188,6 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
call(AF_INET6, 'mangle', 'sshuttle-t-1025'), call(AF_INET6, 'mangle', 'sshuttle-t-1025'),
call(AF_INET6, 'mangle', 'sshuttle-d-1025') call(AF_INET6, 'mangle', 'sshuttle-d-1025')
] ]
assert mock_ipt_ttl.mock_calls == []
assert mock_ipt.mock_calls == [ assert mock_ipt.mock_calls == [
call(AF_INET6, 'mangle', '-D', 'OUTPUT', '-j', 'sshuttle-m-1025'), call(AF_INET6, 'mangle', '-D', 'OUTPUT', '-j', 'sshuttle-m-1025'),
call(AF_INET6, 'mangle', '-F', 'sshuttle-m-1025'), call(AF_INET6, 'mangle', '-F', 'sshuttle-m-1025'),
@ -203,7 +199,6 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
call(AF_INET6, 'mangle', '-X', 'sshuttle-d-1025') call(AF_INET6, 'mangle', '-X', 'sshuttle-d-1025')
] ]
mock_ipt_chain_exists.reset_mock() mock_ipt_chain_exists.reset_mock()
mock_ipt_ttl.reset_mock()
mock_ipt.reset_mock() mock_ipt.reset_mock()
# IPV4 # IPV4
@ -216,13 +211,12 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
(AF_INET, 32, True, u'1.2.3.66', 80, 80)], (AF_INET, 32, True, u'1.2.3.66', 80, 80)],
True, True,
None, None,
63, '0x01') '0x01')
assert mock_ipt_chain_exists.mock_calls == [ assert mock_ipt_chain_exists.mock_calls == [
call(AF_INET, 'mangle', 'sshuttle-m-1025'), call(AF_INET, 'mangle', 'sshuttle-m-1025'),
call(AF_INET, 'mangle', 'sshuttle-t-1025'), call(AF_INET, 'mangle', 'sshuttle-t-1025'),
call(AF_INET, 'mangle', 'sshuttle-d-1025') call(AF_INET, 'mangle', 'sshuttle-d-1025')
] ]
assert mock_ipt_ttl.mock_calls == []
assert mock_ipt.mock_calls == [ assert mock_ipt.mock_calls == [
call(AF_INET, 'mangle', '-D', 'OUTPUT', '-j', 'sshuttle-m-1025'), call(AF_INET, 'mangle', '-D', 'OUTPUT', '-j', 'sshuttle-m-1025'),
call(AF_INET, 'mangle', '-F', 'sshuttle-m-1025'), call(AF_INET, 'mangle', '-F', 'sshuttle-m-1025'),
@ -284,7 +278,6 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
'-m', 'udp', '-p', 'udp', '--on-port', '1025') '-m', 'udp', '-p', 'udp', '--on-port', '1025')
] ]
mock_ipt_chain_exists.reset_mock() mock_ipt_chain_exists.reset_mock()
mock_ipt_ttl.reset_mock()
mock_ipt.reset_mock() mock_ipt.reset_mock()
method.restore_firewall(1025, AF_INET, True, None) method.restore_firewall(1025, AF_INET, True, None)
@ -293,7 +286,6 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
call(AF_INET, 'mangle', 'sshuttle-t-1025'), call(AF_INET, 'mangle', 'sshuttle-t-1025'),
call(AF_INET, 'mangle', 'sshuttle-d-1025') call(AF_INET, 'mangle', 'sshuttle-d-1025')
] ]
assert mock_ipt_ttl.mock_calls == []
assert mock_ipt.mock_calls == [ assert mock_ipt.mock_calls == [
call(AF_INET, 'mangle', '-D', 'OUTPUT', '-j', 'sshuttle-m-1025'), call(AF_INET, 'mangle', '-D', 'OUTPUT', '-j', 'sshuttle-m-1025'),
call(AF_INET, 'mangle', '-F', 'sshuttle-m-1025'), call(AF_INET, 'mangle', '-F', 'sshuttle-m-1025'),
@ -305,5 +297,4 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
call(AF_INET, 'mangle', '-X', 'sshuttle-d-1025') call(AF_INET, 'mangle', '-X', 'sshuttle-d-1025')
] ]
mock_ipt_chain_exists.reset_mock() mock_ipt_chain_exists.reset_mock()
mock_ipt_ttl.reset_mock()
mock_ipt.reset_mock() mock_ipt.reset_mock()