mirror of
https://github.com/sshuttle/sshuttle.git
synced 2024-11-24 17:04:36 +01:00
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:
parent
6ae0b51c61
commit
bc065e368d
@ -4,7 +4,7 @@ sshuttle
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
**sshuttle** [*options*] [**-r** *[username@]sshserver[:port]*] \<*subnets* ...\>
|
||||
**sshuttle** [*options*] **-r** *[username@]sshserver[:port]* \<*subnets* ...\>
|
||||
|
||||
|
||||
Description
|
||||
@ -441,9 +441,7 @@ Example configuration file::
|
||||
Discussion
|
||||
----------
|
||||
When it starts, :program:`sshuttle` creates an ssh session to the
|
||||
server specified by the ``-r`` option. If ``-r`` is omitted,
|
||||
it will start both its client and server locally, which is
|
||||
sometimes useful for testing.
|
||||
server specified by the ``-r`` option.
|
||||
|
||||
After connecting to the remote server, :program:`sshuttle` uploads its
|
||||
(python) source code to the remote end and executes it
|
||||
|
@ -20,7 +20,7 @@ Supports:
|
||||
|
||||
Requires:
|
||||
|
||||
* iptables DNAT, REDIRECT, and ttl modules. ip6tables for IPv6.
|
||||
* iptables DNAT and REDIRECT modules. ip6tables for IPv6.
|
||||
|
||||
Linux with nft method
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -42,4 +42,4 @@ import sshuttle.cmdline_options as options # noqa: E402
|
||||
from sshuttle.server import main # noqa: E402
|
||||
main(options.latency_control, options.latency_buffer_size,
|
||||
options.auto_hosts, options.to_nameserver,
|
||||
options.auto_nets, options.ttl)
|
||||
options.auto_nets)
|
||||
|
@ -44,6 +44,7 @@ def got_signal(signum, frame):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# Filename of the pidfile created by the sshuttle client.
|
||||
_pidname = None
|
||||
|
||||
|
||||
@ -198,7 +199,7 @@ class MultiListener:
|
||||
|
||||
class FirewallClient:
|
||||
|
||||
def __init__(self, method_name, sudo_pythonpath, ttl):
|
||||
def __init__(self, method_name, sudo_pythonpath):
|
||||
self.auto_nets = []
|
||||
|
||||
argvbase = ([sys.executable, sys.argv[0]] +
|
||||
@ -260,7 +261,7 @@ class FirewallClient:
|
||||
|
||||
def setup(self, subnets_include, subnets_exclude, nslist,
|
||||
redirectport_v6, redirectport_v4, dnsport_v6, dnsport_v4, udp,
|
||||
user, ttl, tmark):
|
||||
user, tmark):
|
||||
self.subnets_include = subnets_include
|
||||
self.subnets_exclude = subnets_exclude
|
||||
self.nslist = nslist
|
||||
@ -271,7 +272,6 @@ class FirewallClient:
|
||||
self.udp = udp
|
||||
self.user = user
|
||||
self.tmark = tmark
|
||||
self.ttl = ttl
|
||||
|
||||
def check(self):
|
||||
rv = self.p.poll()
|
||||
@ -310,9 +310,8 @@ class FirewallClient:
|
||||
else:
|
||||
user = b'%d' % self.user
|
||||
|
||||
self.pfile.write(b'GO %d %s %d %s\n' %
|
||||
(udp, user, self.ttl,
|
||||
bytes(self.tmark, 'ascii')))
|
||||
self.pfile.write(b'GO %d %s %s\n' %
|
||||
(udp, user, bytes(self.tmark, 'ascii')))
|
||||
self.pfile.flush()
|
||||
|
||||
line = self.pfile.readline()
|
||||
@ -457,7 +456,7 @@ def ondns(listener, method, mux, handlers):
|
||||
def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
|
||||
python, latency_control, latency_buffer_size,
|
||||
dns_listener, seed_hosts, auto_hosts, auto_nets, daemon,
|
||||
to_nameserver, ttl):
|
||||
to_nameserver):
|
||||
|
||||
helpers.logprefix = 'c : '
|
||||
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,
|
||||
auto_hosts=auto_hosts,
|
||||
to_nameserver=to_nameserver,
|
||||
auto_nets=auto_nets,
|
||||
ttl=ttl))
|
||||
auto_nets=auto_nets))
|
||||
except socket.error as e:
|
||||
if e.args[0] == errno.EPIPE:
|
||||
raise Fatal("failed to establish ssh session (1)")
|
||||
@ -587,6 +585,7 @@ def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
|
||||
% (expected, initstring))
|
||||
log('Connected to server.')
|
||||
sys.stdout.flush()
|
||||
|
||||
if daemon:
|
||||
daemonize()
|
||||
log('daemonizing (%s).' % _pidname)
|
||||
@ -673,12 +672,11 @@ def main(listenip_v6, listenip_v4,
|
||||
latency_buffer_size, dns, nslist,
|
||||
method_name, seed_hosts, auto_hosts, auto_nets,
|
||||
subnets_include, subnets_exclude, daemon, to_nameserver, pidfile,
|
||||
user, sudo_pythonpath, tmark, ttl):
|
||||
user, sudo_pythonpath, tmark):
|
||||
|
||||
if not remotename:
|
||||
print("WARNING: You must specify -r/--remote to securely route "
|
||||
"traffic to a remote machine. Running without -r/--remote "
|
||||
"is only recommended for testing.")
|
||||
raise Fatal("You must use -r/--remote to specify a remote "
|
||||
"host to route traffic through.")
|
||||
|
||||
if daemon:
|
||||
try:
|
||||
@ -689,7 +687,7 @@ def main(listenip_v6, listenip_v4,
|
||||
debug1('Starting sshuttle proxy (version %s).' % __version__)
|
||||
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
|
||||
# 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
|
||||
fw.setup(subnets_include, subnets_exclude, nslist,
|
||||
redirectport_v6, redirectport_v4, dnsport_v6, dnsport_v4,
|
||||
required.udp, user, ttl, tmark)
|
||||
required.udp, user, tmark)
|
||||
|
||||
# start the client process
|
||||
try:
|
||||
return _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
|
||||
python, latency_control, latency_buffer_size,
|
||||
dns_listener, seed_hosts, auto_hosts, auto_nets,
|
||||
daemon, to_nameserver, ttl)
|
||||
daemon, to_nameserver)
|
||||
finally:
|
||||
try:
|
||||
if daemon:
|
||||
|
@ -43,7 +43,7 @@ def main():
|
||||
if opt.firewall:
|
||||
if opt.subnets or opt.subnets_file:
|
||||
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:
|
||||
return hostwatch.hw_main(opt.subnets, opt.auto_hosts)
|
||||
else:
|
||||
@ -116,8 +116,7 @@ def main():
|
||||
opt.pidfile,
|
||||
opt.user,
|
||||
opt.sudo_pythonpath,
|
||||
opt.tmark,
|
||||
opt.ttl)
|
||||
opt.tmark)
|
||||
|
||||
if return_code == 0:
|
||||
log('Normal exit code, exiting...')
|
||||
|
@ -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
|
||||
# supercede it in the transproxy list, at least, so the leftover rules
|
||||
# are hopefully harmless.
|
||||
def main(method_name, syslog, ttl):
|
||||
def main(method_name, syslog):
|
||||
helpers.logprefix = 'fw: '
|
||||
stdin, stdout = setup_daemon()
|
||||
hostmap = {}
|
||||
@ -223,13 +223,12 @@ def main(method_name, syslog, ttl):
|
||||
raise Fatal('expected GO but got %r' % line)
|
||||
|
||||
_, _, args = line.partition(" ")
|
||||
udp, user, ttl, tmark = args.strip().split(" ", 3)
|
||||
udp, user, tmark = args.strip().split(" ", 2)
|
||||
udp = bool(int(udp))
|
||||
if user == '-':
|
||||
user = None
|
||||
ttl = int(ttl)
|
||||
debug2('Got udp: %r, user: %r, ttl: %s, tmark: %s' %
|
||||
(udp, user, ttl, tmark))
|
||||
debug2('Got udp: %r, user: %r, tmark: %s' %
|
||||
(udp, user, tmark))
|
||||
|
||||
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]
|
||||
@ -244,14 +243,14 @@ def main(method_name, syslog, ttl):
|
||||
method.setup_firewall(
|
||||
port_v6, dnsport_v6, nslist_v6,
|
||||
socket.AF_INET6, subnets_v6, udp,
|
||||
user, ttl, tmark)
|
||||
user, tmark)
|
||||
|
||||
if subnets_v4 or nslist_v4:
|
||||
debug2('setting up IPv4.')
|
||||
method.setup_firewall(
|
||||
port_v4, dnsport_v4, nslist_v4,
|
||||
socket.AF_INET, subnets_v4, udp,
|
||||
user, ttl, tmark)
|
||||
user, tmark)
|
||||
|
||||
flush_systemd_dns_cache()
|
||||
stdout.write('STARTED\n')
|
||||
|
@ -49,25 +49,3 @@ def nft(family, table, action, *args):
|
||||
rv = ssubprocess.call(argv, env=get_env())
|
||||
if 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)
|
||||
|
@ -91,7 +91,7 @@ class BaseMethod(object):
|
||||
(key, self.name))
|
||||
|
||||
def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
|
||||
user, ttl, tmark):
|
||||
user, tmark):
|
||||
raise NotImplementedError()
|
||||
|
||||
def restore_firewall(self, port, family, udp, user):
|
||||
|
@ -177,7 +177,6 @@ class Method(BaseMethod):
|
||||
sender.setsockopt(socket.SOL_IP, IP_BINDANY, 1)
|
||||
sender.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sender.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
|
||||
sender.setsockopt(socket.SOL_IP, socket.IP_TTL, 63)
|
||||
sender.bind(srcip)
|
||||
sender.sendto(data, dstip)
|
||||
sender.close()
|
||||
@ -189,7 +188,12 @@ class Method(BaseMethod):
|
||||
# udp_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVDSTADDR, 1)
|
||||
|
||||
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
|
||||
if family not in [socket.AF_INET]:
|
||||
raise Exception(
|
||||
|
@ -1,7 +1,7 @@
|
||||
import socket
|
||||
from sshuttle.firewall import subnet_weight
|
||||
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
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ class Method(BaseMethod):
|
||||
# recently-started one will win (because we use "-I OUTPUT 1" instead of
|
||||
# "-A OUTPUT").
|
||||
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:
|
||||
raise Exception(
|
||||
'Address family "%s" unsupported by nat method_name'
|
||||
@ -25,9 +25,6 @@ class Method(BaseMethod):
|
||||
def _ipt(*args):
|
||||
return ipt(family, table, *args)
|
||||
|
||||
def _ipt_ttl(*args):
|
||||
return ipt_ttl(family, table, *args)
|
||||
|
||||
def _ipm(*args):
|
||||
return ipt(family, "mangle", *args)
|
||||
|
||||
@ -48,16 +45,6 @@ class Method(BaseMethod):
|
||||
_ipt('-I', 'OUTPUT', '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
|
||||
# to localhost DNS servers through sshuttle.
|
||||
for _, ip in [i for i in nslist if i[0] == family]:
|
||||
@ -102,9 +89,6 @@ class Method(BaseMethod):
|
||||
def _ipt(*args):
|
||||
return ipt(family, table, *args)
|
||||
|
||||
def _ipt_ttl(*args):
|
||||
return ipt_ttl(family, table, *args)
|
||||
|
||||
def _ipm(*args):
|
||||
return ipt(family, "mangle", *args)
|
||||
|
||||
|
@ -13,7 +13,7 @@ class Method(BaseMethod):
|
||||
# recently-started one will win (because we use "-I OUTPUT 1" instead of
|
||||
# "-A OUTPUT").
|
||||
def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
|
||||
user, ttl, tmark):
|
||||
user, tmark):
|
||||
if udp:
|
||||
raise Exception("UDP not supported by nft")
|
||||
|
||||
@ -45,14 +45,6 @@ class Method(BaseMethod):
|
||||
else:
|
||||
_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
|
||||
if family == socket.AF_INET:
|
||||
ip_version_l = 'ipv4'
|
||||
|
@ -448,7 +448,7 @@ class Method(BaseMethod):
|
||||
return sock.getsockname()
|
||||
|
||||
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]:
|
||||
raise Exception(
|
||||
'Address family "%s" unsupported by pf method_name'
|
||||
|
@ -1,7 +1,7 @@
|
||||
import struct
|
||||
from sshuttle.firewall import subnet_weight
|
||||
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.helpers import debug1, debug2, debug3, Fatal, which
|
||||
|
||||
@ -151,7 +151,7 @@ class Method(BaseMethod):
|
||||
udp_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVORIGDSTADDR, 1)
|
||||
|
||||
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]:
|
||||
raise Exception(
|
||||
'Address family "%s" unsupported by tproxy method'
|
||||
@ -162,9 +162,6 @@ class Method(BaseMethod):
|
||||
def _ipt(*args):
|
||||
return ipt(family, table, *args)
|
||||
|
||||
def _ipt_ttl(*args):
|
||||
return ipt_ttl(family, table, *args)
|
||||
|
||||
def _ipt_proto_ports(proto, fport, lport):
|
||||
return proto + ('--dport', '%d:%d' % (fport, lport)) \
|
||||
if fport else proto
|
||||
@ -279,9 +276,6 @@ class Method(BaseMethod):
|
||||
def _ipt(*args):
|
||||
return ipt(family, table, *args)
|
||||
|
||||
def _ipt_ttl(*args):
|
||||
return ipt_ttl(family, table, *args)
|
||||
|
||||
mark_chain = 'sshuttle-m-%s' % port
|
||||
tproxy_chain = 'sshuttle-t-%s' % port
|
||||
divert_chain = 'sshuttle-d-%s' % port
|
||||
|
@ -173,7 +173,7 @@ class MyArgumentParser(ArgumentParser):
|
||||
|
||||
parser = MyArgumentParser(
|
||||
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="@"
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -389,15 +389,6 @@ parser.add_argument(
|
||||
(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(
|
||||
"--hostwatch",
|
||||
action="store_true",
|
||||
|
@ -152,7 +152,7 @@ class Hostwatch:
|
||||
|
||||
class DnsProxy(Handler):
|
||||
|
||||
def __init__(self, mux, chan, request, to_nameserver, ttl):
|
||||
def __init__(self, mux, chan, request, to_nameserver):
|
||||
Handler.__init__(self, [])
|
||||
self.timeout = time.time() + 30
|
||||
self.mux = mux
|
||||
@ -162,7 +162,6 @@ class DnsProxy(Handler):
|
||||
self.peers = {}
|
||||
self.to_ns_peer = None
|
||||
self.to_ns_port = None
|
||||
self.ttl = ttl
|
||||
if to_nameserver is None:
|
||||
self.to_nameserver = None
|
||||
else:
|
||||
@ -192,7 +191,6 @@ class DnsProxy(Handler):
|
||||
|
||||
family, sockaddr = self._addrinfo(peer, port)
|
||||
sock = socket.socket(family, socket.SOCK_DGRAM)
|
||||
sock.setsockopt(socket.SOL_IP, socket.IP_TTL, self.ttl)
|
||||
sock.connect(sockaddr)
|
||||
|
||||
self.peers[sock] = peer
|
||||
@ -241,15 +239,13 @@ class DnsProxy(Handler):
|
||||
|
||||
class UdpProxy(Handler):
|
||||
|
||||
def __init__(self, mux, chan, family, ttl):
|
||||
def __init__(self, mux, chan, family):
|
||||
sock = socket.socket(family, socket.SOCK_DGRAM)
|
||||
Handler.__init__(self, [sock])
|
||||
self.timeout = time.time() + 30
|
||||
self.mux = mux
|
||||
self.chan = chan
|
||||
self.sock = sock
|
||||
if family == socket.AF_INET:
|
||||
self.sock.setsockopt(socket.SOL_IP, socket.IP_TTL, ttl)
|
||||
|
||||
def send(self, dstip, data):
|
||||
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,
|
||||
auto_nets, ttl):
|
||||
auto_nets):
|
||||
try:
|
||||
helpers.logprefix = ' 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):
|
||||
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)
|
||||
dnshandlers[channel] = h
|
||||
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' %
|
||||
channel)
|
||||
else:
|
||||
h = UdpProxy(mux, channel, family, ttl)
|
||||
h = UdpProxy(mux, channel, family)
|
||||
handlers.append(h)
|
||||
udphandlers[channel] = h
|
||||
mux.got_udp_open = udp_open
|
||||
|
@ -586,7 +586,7 @@ class MuxWrapper(SockWrapper):
|
||||
def connect_dst(family, ip, port):
|
||||
debug2('Connecting to %s:%d' % (ip, port))
|
||||
outsock = socket.socket(family)
|
||||
outsock.setsockopt(socket.SOL_IP, socket.IP_TTL, 63)
|
||||
|
||||
return SockWrapper(outsock, outsock,
|
||||
connect_to=(ip, port),
|
||||
peername='%s:%d' % (ip, port))
|
||||
|
@ -15,7 +15,7 @@ NSLIST
|
||||
{inet},1.2.3.33
|
||||
{inet6},2404:6800:4004:80c::33
|
||||
PORTS 1024,1025,1026,1027
|
||||
GO 1 - 63 0x01
|
||||
GO 1 - 0x01
|
||||
HOST 1.2.3.3,existing
|
||||
""".format(inet=AF_INET, inet6=AF_INET6))
|
||||
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.reset_mock()
|
||||
|
||||
sshuttle.firewall.main("not_auto", False, 63)
|
||||
sshuttle.firewall.main("not_auto", False)
|
||||
|
||||
assert mock_rewrite_etc_hosts.mock_calls == [
|
||||
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)],
|
||||
True,
|
||||
None,
|
||||
63, '0x01'),
|
||||
'0x01'),
|
||||
call().setup_firewall(
|
||||
1025, 1027,
|
||||
[(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)],
|
||||
True,
|
||||
None,
|
||||
63, '0x01'),
|
||||
'0x01'),
|
||||
call().restore_firewall(1024, AF_INET6, True, None),
|
||||
call().restore_firewall(1025, AF_INET, True, None),
|
||||
]
|
||||
|
@ -85,15 +85,13 @@ def test_firewall_command():
|
||||
|
||||
|
||||
@patch('sshuttle.methods.nat.ipt')
|
||||
@patch('sshuttle.methods.nat.ipt_ttl')
|
||||
@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
|
||||
method = get_method('nat')
|
||||
assert method.name == 'nat'
|
||||
|
||||
assert mock_ipt_chain_exists.mock_calls == []
|
||||
assert mock_ipt_ttl.mock_calls == []
|
||||
assert mock_ipt.mock_calls == []
|
||||
method.setup_firewall(
|
||||
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)],
|
||||
False,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
|
||||
assert mock_ipt_chain_exists.mock_calls == [
|
||||
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 == [
|
||||
call(AF_INET6, 'nat', '-D', 'OUTPUT', '-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')
|
||||
]
|
||||
mock_ipt_chain_exists.reset_mock()
|
||||
mock_ipt_ttl.reset_mock()
|
||||
mock_ipt.reset_mock()
|
||||
|
||||
assert mock_ipt_chain_exists.mock_calls == []
|
||||
assert mock_ipt_ttl.mock_calls == []
|
||||
assert mock_ipt.mock_calls == []
|
||||
|
||||
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)],
|
||||
True,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
assert str(excinfo.value) == 'UDP not supported by nat method_name'
|
||||
assert mock_ipt_chain_exists.mock_calls == []
|
||||
assert mock_ipt_ttl.mock_calls == []
|
||||
assert mock_ipt.mock_calls == []
|
||||
|
||||
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)],
|
||||
False,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
assert mock_ipt_chain_exists.mock_calls == [
|
||||
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 == [
|
||||
call(AF_INET, 'nat', '-D', 'OUTPUT', '-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')
|
||||
]
|
||||
mock_ipt_chain_exists.reset_mock()
|
||||
mock_ipt_ttl.reset_mock()
|
||||
mock_ipt.reset_mock()
|
||||
|
||||
method.restore_firewall(1025, AF_INET, False, None)
|
||||
assert mock_ipt_chain_exists.mock_calls == [
|
||||
call(AF_INET, 'nat', 'sshuttle-1025')
|
||||
]
|
||||
assert mock_ipt_ttl.mock_calls == []
|
||||
assert mock_ipt.mock_calls == [
|
||||
call(AF_INET, 'nat', '-D', 'OUTPUT', '-j',
|
||||
'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')
|
||||
]
|
||||
mock_ipt_chain_exists.reset_mock()
|
||||
mock_ipt_ttl.reset_mock()
|
||||
mock_ipt.reset_mock()
|
||||
|
||||
method.restore_firewall(1025, AF_INET6, False, None)
|
||||
assert mock_ipt_chain_exists.mock_calls == [
|
||||
call(AF_INET6, 'nat', 'sshuttle-1025')
|
||||
]
|
||||
assert mock_ipt_ttl.mock_calls == []
|
||||
assert mock_ipt.mock_calls == [
|
||||
call(AF_INET6, 'nat', '-D', 'OUTPUT', '-j', 'sshuttle-1025'),
|
||||
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')
|
||||
]
|
||||
mock_ipt_chain_exists.reset_mock()
|
||||
mock_ipt_ttl.reset_mock()
|
||||
mock_ipt.reset_mock()
|
||||
|
@ -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)],
|
||||
False,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
assert mock_ioctl.mock_calls == [
|
||||
call(mock_pf_get_dev(), 0xC4704433, 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)],
|
||||
True,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
assert str(excinfo.value) == 'UDP not supported by pf method_name'
|
||||
assert mock_pf_get_dev.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)],
|
||||
False,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
assert mock_ioctl.mock_calls == [
|
||||
call(mock_pf_get_dev(), 0xC4704433, 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)],
|
||||
False,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
|
||||
assert mock_pfctl.mock_calls == [
|
||||
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)],
|
||||
True,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
assert str(excinfo.value) == 'UDP not supported by pf method_name'
|
||||
assert mock_pf_get_dev.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)],
|
||||
False,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
assert mock_ioctl.mock_calls == [
|
||||
call(mock_pf_get_dev(), 0xC4704433, 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)],
|
||||
False,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
|
||||
assert mock_ioctl.mock_calls == [
|
||||
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)],
|
||||
True,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
assert str(excinfo.value) == 'UDP not supported by pf method_name'
|
||||
assert mock_pf_get_dev.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)],
|
||||
False,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
assert mock_ioctl.mock_calls == [
|
||||
call(mock_pf_get_dev(), 0xcd60441a, ANY),
|
||||
call(mock_pf_get_dev(), 0xcd60441a, ANY),
|
||||
|
@ -92,9 +92,8 @@ def test_firewall_command():
|
||||
|
||||
|
||||
@patch('sshuttle.methods.tproxy.ipt')
|
||||
@patch('sshuttle.methods.tproxy.ipt_ttl')
|
||||
@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
|
||||
method = get_method('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)],
|
||||
True,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
assert mock_ipt_chain_exists.mock_calls == [
|
||||
call(AF_INET6, 'mangle', 'sshuttle-m-1024'),
|
||||
call(AF_INET6, 'mangle', 'sshuttle-t-1024'),
|
||||
call(AF_INET6, 'mangle', 'sshuttle-d-1024')
|
||||
]
|
||||
assert mock_ipt_ttl.mock_calls == []
|
||||
assert mock_ipt.mock_calls == [
|
||||
call(AF_INET6, 'mangle', '-D', 'OUTPUT', '-j', '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')
|
||||
]
|
||||
mock_ipt_chain_exists.reset_mock()
|
||||
mock_ipt_ttl.reset_mock()
|
||||
mock_ipt.reset_mock()
|
||||
|
||||
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-d-1025')
|
||||
]
|
||||
assert mock_ipt_ttl.mock_calls == []
|
||||
assert mock_ipt.mock_calls == [
|
||||
call(AF_INET6, 'mangle', '-D', 'OUTPUT', '-j', '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')
|
||||
]
|
||||
mock_ipt_chain_exists.reset_mock()
|
||||
mock_ipt_ttl.reset_mock()
|
||||
mock_ipt.reset_mock()
|
||||
|
||||
# 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)],
|
||||
True,
|
||||
None,
|
||||
63, '0x01')
|
||||
'0x01')
|
||||
assert mock_ipt_chain_exists.mock_calls == [
|
||||
call(AF_INET, 'mangle', 'sshuttle-m-1025'),
|
||||
call(AF_INET, 'mangle', 'sshuttle-t-1025'),
|
||||
call(AF_INET, 'mangle', 'sshuttle-d-1025')
|
||||
]
|
||||
assert mock_ipt_ttl.mock_calls == []
|
||||
assert mock_ipt.mock_calls == [
|
||||
call(AF_INET, 'mangle', '-D', 'OUTPUT', '-j', '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')
|
||||
]
|
||||
mock_ipt_chain_exists.reset_mock()
|
||||
mock_ipt_ttl.reset_mock()
|
||||
mock_ipt.reset_mock()
|
||||
|
||||
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-d-1025')
|
||||
]
|
||||
assert mock_ipt_ttl.mock_calls == []
|
||||
assert mock_ipt.mock_calls == [
|
||||
call(AF_INET, 'mangle', '-D', 'OUTPUT', '-j', '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')
|
||||
]
|
||||
mock_ipt_chain_exists.reset_mock()
|
||||
mock_ipt_ttl.reset_mock()
|
||||
mock_ipt.reset_mock()
|
||||
|
Loading…
Reference in New Issue
Block a user