mirror of
https://github.com/sshuttle/sshuttle.git
synced 2024-11-21 23:43:18 +01:00
Merge branch 'master' into nat-ipv6
This commit is contained in:
commit
3f201095ea
@ -50,6 +50,14 @@ if [ "$FILE_NAME" == "" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify that the resulting file name begins with /etc/sudoers.d
|
||||
FILE_NAME="$(realpath "/etc/sudoers.d/$FILE_NAME")"
|
||||
if [[ "$FILE_NAME" != "/etc/sudoers.d/"* ]] ; then
|
||||
echo -n "Invalid sudoers filename: Final sudoers file "
|
||||
echo "location ($FILE_NAME) does not begin with /etc/sudoers.d"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make a temp file to hold the sudoers config
|
||||
umask 077
|
||||
TEMP_FILE=$(mktemp)
|
||||
@ -62,9 +70,9 @@ visudo_code=$?
|
||||
rm "$TEMP_FILE"
|
||||
|
||||
if [ $visudo_code -eq 0 ]; then
|
||||
echo "$CONTENT" > "/etc/sudoers.d/$FILE_NAME"
|
||||
chmod 0440 "/etc/sudoers.d/$FILE_NAME"
|
||||
echo "The sudoers file /etc/sudoers.d/$FILE_NAME has been successfully created!"
|
||||
echo "$CONTENT" > "$FILE_NAME"
|
||||
chmod 0440 "$FILE_NAME"
|
||||
echo "The sudoers file $FILE_NAME has been successfully created!"
|
||||
|
||||
exit 0
|
||||
else
|
||||
|
165
docs/manpage.rst
165
docs/manpage.rst
@ -10,8 +10,8 @@ Synopsis
|
||||
Description
|
||||
-----------
|
||||
:program:`sshuttle` allows you to create a VPN connection from your
|
||||
machine to any remote server that you can connect to via
|
||||
ssh, as long as that server has python 3.6 or higher.
|
||||
machine to any remote server that you can connect to via ssh, as long
|
||||
as that server has a sufficiently new Python installation.
|
||||
|
||||
To work, you must have root access on the local machine,
|
||||
but you can have a normal account on the server.
|
||||
@ -31,22 +31,23 @@ Options
|
||||
.. option:: <subnets>
|
||||
|
||||
A list of subnets to route over the VPN, in the form
|
||||
``a.b.c.d[/width][port[-port]]``. Valid examples are 1.2.3.4 (a
|
||||
single IP address), 1.2.3.4/32 (equivalent to 1.2.3.4),
|
||||
1.2.3.0/24 (a 24-bit subnet, ie. with a 255.255.255.0
|
||||
netmask), and 0/0 ('just route everything through the
|
||||
VPN'). Any of the previous examples are also valid if you append
|
||||
a port or a port range, so 1.2.3.4:8000 will only tunnel traffic
|
||||
that has as the destination port 8000 of 1.2.3.4 and
|
||||
1.2.3.0/24:8000-9000 will tunnel traffic going to any port between
|
||||
8000 and 9000 (inclusive) for all IPs in the 1.2.3.0/24 subnet.
|
||||
A hostname can be provided instead of an IP address. If the
|
||||
hostname resolves to multiple IPs, all of the IPs are included.
|
||||
If a width is provided with a hostname that the width is applied
|
||||
to all of the hostnames IPs (if they are all either IPv4 or IPv6).
|
||||
Widths cannot be supplied to hostnames that resolve to both IPv4
|
||||
and IPv6. Valid examples are example.com, example.com:8000,
|
||||
example.com/24, example.com/24:8000 and example.com:8000-9000.
|
||||
``a.b.c.d[/width][port[-port]]``. Valid examples are 1.2.3.4 (a
|
||||
single IP address) and 1.2.3.4/32 (equivalent to 1.2.3.4),
|
||||
1.2.3.0/24 (a 24-bit subnet, ie. with a 255.255.255.0 netmask).
|
||||
Specify subnets 0/0 to match all IPv4 addresses and ::/0 to match
|
||||
all IPv6 addresses. Any of the previous examples are also valid if
|
||||
you append a port or a port range, so 1.2.3.4:8000 will only
|
||||
tunnel traffic that has as the destination port 8000 of 1.2.3.4
|
||||
and 1.2.3.0/24:8000-9000 will tunnel traffic going to any port
|
||||
between 8000 and 9000 (inclusive) for all IPs in the 1.2.3.0/24
|
||||
subnet. A hostname can be provided instead of an IP address. If
|
||||
the hostname resolves to multiple IPs, all of the IPs are
|
||||
included. If a width is provided with a hostname, the width is
|
||||
applied to all of the hostnames IPs (if they are all either IPv4
|
||||
or IPv6). Widths cannot be supplied to hostnames that resolve to
|
||||
both IPv4 and IPv6. Valid examples are example.com,
|
||||
example.com:8000, example.com/24, example.com/24:8000 and
|
||||
example.com:8000-9000.
|
||||
|
||||
.. option:: --method <auto|nat|nft|tproxy|pf|ipfw>
|
||||
|
||||
@ -141,7 +142,10 @@ Options
|
||||
The remote hostname and optional username and ssh
|
||||
port number to use for connecting to the remote server.
|
||||
For example, example.com, testuser@example.com,
|
||||
testuser@example.com:2222, or example.com:2244.
|
||||
testuser@example.com:2222, or example.com:2244. This
|
||||
hostname is passed to ssh, so it will recognize any
|
||||
aliases and settings you may have configured in
|
||||
~/.ssh/config.
|
||||
|
||||
.. option:: -x <subnet>, --exclude=<subnet>
|
||||
|
||||
@ -274,9 +278,10 @@ Options
|
||||
Set the file name for the sudoers.d file to be added. Default is
|
||||
"sshuttle_auto". Only works with --sudoers.
|
||||
|
||||
.. option:: -t, --tmark
|
||||
.. option:: -t <mark>, --tmark=<mark>
|
||||
|
||||
Transproxy optional traffic mark with provided MARK value.
|
||||
An option used by the tproxy method: Use the specified traffic
|
||||
mark. The mark must be a hexadecimal value. Defaults to 0x01.
|
||||
|
||||
.. option:: --version
|
||||
|
||||
@ -305,11 +310,8 @@ Arguments read from a file must be one per line, as shown below::
|
||||
--option2
|
||||
value2
|
||||
|
||||
Comments in config file
|
||||
.......................
|
||||
|
||||
It's possible to add comments in the configuration file. This allows annotating the
|
||||
various subnets with human-readable descriptions, like::
|
||||
The configuration file supports comments for human-readable
|
||||
annotations. For example::
|
||||
|
||||
# company-internal API
|
||||
8.8.8.8/32
|
||||
@ -319,51 +321,96 @@ various subnets with human-readable descriptions, like::
|
||||
|
||||
Examples
|
||||
--------
|
||||
Test locally by proxying all local connections, without using ssh::
|
||||
|
||||
$ sshuttle -v 0/0
|
||||
Use the following command to route all IPv4 TCP traffic through remote
|
||||
(-r) host example.com (and possibly other traffic too, depending on
|
||||
the selected --method). The 0/0 subnet, short for 0.0.0.0/0, matches
|
||||
all IPv4 addresses. The ::/0 subnet, matching all IPv6 addresses could
|
||||
be added to the example. We also exclude (-x) example.com:22 so that
|
||||
we can establish ssh connections from our local machine to the remote
|
||||
host without them being routed through sshuttle. Excluding the remote
|
||||
host may be necessary on some machines for sshuttle to work properly.
|
||||
Press Ctrl+C to exit. To also route DNS queries through sshuttle, try
|
||||
adding --dns. Add or remove -v options to see more or less
|
||||
information::
|
||||
|
||||
Starting sshuttle proxy.
|
||||
Listening on ('0.0.0.0', 12300).
|
||||
[local sudo] Password:
|
||||
firewall manager ready.
|
||||
c : connecting to server...
|
||||
s: available routes:
|
||||
s: 192.168.42.0/24
|
||||
c : connected.
|
||||
firewall manager: starting transproxy.
|
||||
c : Accept: 192.168.42.106:50035 -> 192.168.42.121:139.
|
||||
c : Accept: 192.168.42.121:47523 -> 77.141.99.22:443.
|
||||
...etc...
|
||||
$ sshuttle -r example.com -x example.com:22 0/0
|
||||
|
||||
Starting sshuttle proxy (version ...).
|
||||
[local sudo] Password:
|
||||
fw: Starting firewall with Python version 3.9.5
|
||||
fw: ready method name nat.
|
||||
c : IPv6 disabled since it isn't supported by method nat.
|
||||
c : Method: nat
|
||||
c : IPv4: on
|
||||
c : IPv6: off (not available with nat method)
|
||||
c : UDP : off (not available with nat method)
|
||||
c : DNS : off (available)
|
||||
c : User: off (available)
|
||||
c : Subnets to forward through remote host (type, IP, cidr mask width, startPort, endPort):
|
||||
c : (<AddressFamily.AF_INET: 2>, '0.0.0.0', 0, 0, 0)
|
||||
c : Subnets to exclude from forwarding:
|
||||
c : (<AddressFamily.AF_INET: 2>, '...', 32, 22, 22)
|
||||
c : (<AddressFamily.AF_INET: 2>, '127.0.0.1', 32, 0, 0)
|
||||
c : TCP redirector listening on ('127.0.0.1', 12299).
|
||||
c : Starting client with Python version 3.9.5
|
||||
c : Connecting to server...
|
||||
user@example.com's password:
|
||||
s: Starting server with Python version 3.6.8
|
||||
s: latency control setting = True
|
||||
s: auto-nets:False
|
||||
c : Connected to server.
|
||||
fw: setting up.
|
||||
fw: iptables -w -t nat -N sshuttle-12299
|
||||
fw: iptables -w -t nat -F sshuttle-12299
|
||||
...
|
||||
Accept: 192.168.42.121:60554 -> 77.141.99.22:22.
|
||||
^C
|
||||
firewall manager: undoing changes.
|
||||
KeyboardInterrupt
|
||||
c : Keyboard interrupt: exiting.
|
||||
c : SW#8:192.168.42.121:47523: deleting
|
||||
c : SW#6:192.168.42.106:50035: deleting
|
||||
c : SW'unknown':Mux#1: deleting (1 remain)
|
||||
c : SW#7:192.168.42.121:60554: deleting (0 remain)
|
||||
|
||||
Test connection to a remote server, with automatic hostname
|
||||
|
||||
Connect to a remote server, with automatic hostname
|
||||
and subnet guessing::
|
||||
|
||||
$ sshuttle -vNHr example.org
|
||||
|
||||
Starting sshuttle proxy.
|
||||
Listening on ('0.0.0.0', 12300).
|
||||
firewall manager ready.
|
||||
c : connecting to server...
|
||||
$ sshuttle -vNHr example.com -x example.com:22
|
||||
Starting sshuttle proxy (version ...).
|
||||
[local sudo] Password:
|
||||
fw: Starting firewall with Python version 3.9.5
|
||||
fw: ready method name nat.
|
||||
c : IPv6 disabled since it isn't supported by method nat.
|
||||
c : Method: nat
|
||||
c : IPv4: on
|
||||
c : IPv6: off (not available with nat method)
|
||||
c : UDP : off (not available with nat method)
|
||||
c : DNS : off (available)
|
||||
c : User: off (available)
|
||||
c : Subnets to forward through remote host (type, IP, cidr mask width, startPort, endPort):
|
||||
c : NOTE: Additional subnets to forward may be added below by --auto-nets.
|
||||
c : Subnets to exclude from forwarding:
|
||||
c : (<AddressFamily.AF_INET: 2>, '...', 32, 22, 22)
|
||||
c : (<AddressFamily.AF_INET: 2>, '127.0.0.1', 32, 0, 0)
|
||||
c : TCP redirector listening on ('127.0.0.1', 12300).
|
||||
c : Starting client with Python version 3.9.5
|
||||
c : Connecting to server...
|
||||
user@example.com's password:
|
||||
s: Starting server with Python version 3.6.8
|
||||
s: latency control setting = True
|
||||
s: auto-nets:True
|
||||
c : Connected to server.
|
||||
c : seed_hosts: []
|
||||
s: available routes:
|
||||
s: 77.141.99.0/24
|
||||
c : connected.
|
||||
c : seed_hosts: []
|
||||
firewall manager: starting transproxy.
|
||||
hostwatch: Found: testbox1: 1.2.3.4
|
||||
hostwatch: Found: mytest2: 5.6.7.8
|
||||
hostwatch: Found: domaincontroller: 99.1.2.3
|
||||
fw: setting up.
|
||||
fw: iptables -w -t nat -N sshuttle-12300
|
||||
fw: iptables -w -t nat -F sshuttle-12300
|
||||
...
|
||||
c : Accept: 192.168.42.121:60554 -> 77.141.99.22:22.
|
||||
^C
|
||||
firewall manager: undoing changes.
|
||||
c : Keyboard interrupt: exiting.
|
||||
c : SW#6:192.168.42.121:60554: deleting
|
||||
c : SW'unknown':Mux#1: deleting (1 remain)
|
||||
c : SW#7:192.168.42.121:60554: deleting (0 remain)
|
||||
|
||||
Run :program:`sshuttle` with a `/etc/sshuttle.conf` configuration file::
|
||||
|
||||
|
@ -12,7 +12,8 @@ There are some things you need to consider for TPROXY to work:
|
||||
ip -6 route add local default dev lo table 100
|
||||
ip -6 rule add fwmark {TMARK} lookup 100
|
||||
|
||||
where {TMARK} is the identifier mark passed with -t or --tmark flag (default value is 1).
|
||||
where {TMARK} is the identifier mark passed with -t or --tmark flag
|
||||
as a hexadecimal string (default value is '0x01').
|
||||
|
||||
- The ``--auto-nets`` feature does not detect IPv6 routes automatically. Add IPv6
|
||||
routes manually. e.g. by adding ``'::/0'`` to the end of the command line.
|
||||
|
@ -11,6 +11,10 @@ Forward all traffic::
|
||||
sshuttle -r username@sshserver 0.0.0.0/0
|
||||
|
||||
- Use the :option:`sshuttle -r` parameter to specify a remote server.
|
||||
One some systems, you may also need to use the :option:`sshuttle -x`
|
||||
parameter to exclude sshserver or sshserver:22 so that your local
|
||||
machine can communicate directly to sshserver without it being
|
||||
redirected by sshuttle.
|
||||
|
||||
- By default sshuttle will automatically choose a method to use. Override with
|
||||
the :option:`sshuttle --method` parameter.
|
||||
|
@ -201,12 +201,11 @@ class FirewallClient:
|
||||
|
||||
def __init__(self, method_name, sudo_pythonpath, ttl):
|
||||
self.auto_nets = []
|
||||
python_path = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
argvbase = ([sys.executable, sys.argv[0]] +
|
||||
['-v'] * (helpers.verbose or 0) +
|
||||
['--method', method_name] +
|
||||
['--firewall'] +
|
||||
['--ttl', str(ttl)])
|
||||
['--firewall'])
|
||||
if ssyslog._p:
|
||||
argvbase += ['--syslog']
|
||||
|
||||
@ -224,7 +223,8 @@ class FirewallClient:
|
||||
|
||||
if sudo_pythonpath:
|
||||
elev_prefix += ['/usr/bin/env',
|
||||
'PYTHONPATH=%s' % python_path]
|
||||
'PYTHONPATH=%s' %
|
||||
os.path.dirname(os.path.dirname(__file__))]
|
||||
argv_tries = [elev_prefix + argvbase, argvbase]
|
||||
|
||||
# we can't use stdin/stdout=subprocess.PIPE here, as we normally would,
|
||||
@ -261,7 +261,7 @@ class FirewallClient:
|
||||
|
||||
def setup(self, subnets_include, subnets_exclude, nslist,
|
||||
redirectport_v6, redirectport_v4, dnsport_v6, dnsport_v4, udp,
|
||||
user, tmark, ttl):
|
||||
user, ttl, tmark):
|
||||
self.subnets_include = subnets_include
|
||||
self.subnets_exclude = subnets_exclude
|
||||
self.nslist = nslist
|
||||
@ -311,7 +311,9 @@ class FirewallClient:
|
||||
else:
|
||||
user = b'%d' % self.user
|
||||
|
||||
self.pfile.write(b'GO %d %s\n' % (udp, user))
|
||||
self.pfile.write(b'GO %d %s %d %s\n' %
|
||||
(udp, user, self.ttl,
|
||||
bytes(self.tmark, 'ascii')))
|
||||
self.pfile.flush()
|
||||
|
||||
line = self.pfile.readline()
|
||||
@ -1003,7 +1005,7 @@ 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, tmark, ttl)
|
||||
required.udp, user, ttl, tmark)
|
||||
|
||||
# start the client process
|
||||
try:
|
||||
|
@ -20,7 +20,7 @@ def main():
|
||||
return 1
|
||||
|
||||
if not opt.sudoers_filename:
|
||||
log('--sudoers-file must be set or omited.')
|
||||
log('--sudoers-file must be set or omitted.')
|
||||
return 1
|
||||
|
||||
sudoers(
|
||||
@ -85,6 +85,13 @@ def main():
|
||||
ipport_v4 = "auto"
|
||||
# parse_ipport6('[::1]:0')
|
||||
ipport_v6 = "auto" if not opt.disable_ipv6 else None
|
||||
try:
|
||||
int(opt.tmark, 16)
|
||||
except ValueError:
|
||||
parser.error("--tmark must be a hexadecimal value")
|
||||
opt.tmark = opt.tmark.lower() # make 'x' in 0x lowercase
|
||||
if not opt.tmark.startswith("0x"): # accept without 0x prefix
|
||||
opt.tmark = "0x%s" % opt.tmark
|
||||
if opt.syslog:
|
||||
ssyslog.start_syslog()
|
||||
ssyslog.close_stdin()
|
||||
|
@ -223,11 +223,13 @@ def main(method_name, syslog, ttl):
|
||||
raise Fatal('expected GO but got %r' % line)
|
||||
|
||||
_, _, args = line.partition(" ")
|
||||
udp, user = args.strip().split(" ", 1)
|
||||
udp, user, ttl, tmark = args.strip().split(" ", 3)
|
||||
udp = bool(int(udp))
|
||||
if user == '-':
|
||||
user = None
|
||||
debug2('Got udp: %r, user: %r' % (udp, user))
|
||||
ttl = int(ttl)
|
||||
debug2('Got udp: %r, user: %r, ttl: %s, tmark: %s' %
|
||||
(udp, user, ttl, 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]
|
||||
@ -242,14 +244,14 @@ def main(method_name, syslog, ttl):
|
||||
method.setup_firewall(
|
||||
port_v6, dnsport_v6, nslist_v6,
|
||||
socket.AF_INET6, subnets_v6, udp,
|
||||
user, ttl)
|
||||
user, ttl, 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)
|
||||
user, ttl, tmark)
|
||||
|
||||
flush_systemd_dns_cache()
|
||||
stdout.write('STARTED\n')
|
||||
|
@ -16,8 +16,6 @@ NETSTAT_POLL_TIME = 30
|
||||
CACHEFILE = os.path.expanduser('~/.sshuttle.hosts')
|
||||
|
||||
|
||||
_nmb_ok = True
|
||||
_smb_ok = True
|
||||
hostnames = {}
|
||||
queue = {}
|
||||
try:
|
||||
@ -141,110 +139,11 @@ def _check_netstat():
|
||||
check_host(ip)
|
||||
|
||||
|
||||
def _check_smb(hostname):
|
||||
return
|
||||
global _smb_ok
|
||||
if not _smb_ok:
|
||||
return
|
||||
debug2(' > smb: %s' % hostname)
|
||||
argv = ['smbclient', '-U', '%', '-L', hostname]
|
||||
try:
|
||||
p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null,
|
||||
env=get_env())
|
||||
lines = p.stdout.readlines()
|
||||
p.wait()
|
||||
except OSError:
|
||||
_, e = sys.exc_info()[:2]
|
||||
log('%r failed: %r' % (argv, e))
|
||||
_smb_ok = False
|
||||
return
|
||||
|
||||
lines.reverse()
|
||||
|
||||
# junk at top
|
||||
while lines:
|
||||
line = lines.pop().strip()
|
||||
if re.match(r'Server\s+', line):
|
||||
break
|
||||
|
||||
# server list section:
|
||||
# Server Comment
|
||||
# ------ -------
|
||||
while lines:
|
||||
line = lines.pop().strip()
|
||||
if not line or re.match(r'-+\s+-+', line):
|
||||
continue
|
||||
if re.match(r'Workgroup\s+Master', line):
|
||||
break
|
||||
words = line.split()
|
||||
hostname = words[0].lower()
|
||||
debug3('< %s' % hostname)
|
||||
check_host(hostname)
|
||||
|
||||
# workgroup list section:
|
||||
# Workgroup Master
|
||||
# --------- ------
|
||||
while lines:
|
||||
line = lines.pop().strip()
|
||||
if re.match(r'-+\s+', line):
|
||||
continue
|
||||
if not line:
|
||||
break
|
||||
words = line.split()
|
||||
(workgroup, hostname) = (words[0].lower(), words[1].lower())
|
||||
debug3('< group(%s) -> %s' % (workgroup, hostname))
|
||||
check_host(hostname)
|
||||
check_workgroup(workgroup)
|
||||
|
||||
if lines:
|
||||
assert(0)
|
||||
|
||||
|
||||
def _check_nmb(hostname, is_workgroup, is_master):
|
||||
return
|
||||
global _nmb_ok
|
||||
if not _nmb_ok:
|
||||
return
|
||||
debug2(' > n%d%d: %s' % (is_workgroup, is_master, hostname))
|
||||
argv = ['nmblookup'] + ['-M'] * is_master + ['--', hostname]
|
||||
try:
|
||||
p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null,
|
||||
env=get_env)
|
||||
lines = p.stdout.readlines()
|
||||
rv = p.wait()
|
||||
except OSError:
|
||||
_, e = sys.exc_info()[:2]
|
||||
log('%r failed: %r' % (argv, e))
|
||||
_nmb_ok = False
|
||||
return
|
||||
if rv:
|
||||
log('%r returned %d' % (argv, rv))
|
||||
return
|
||||
for line in lines:
|
||||
m = re.match(r'(\d+\.\d+\.\d+\.\d+) (\w+)<\w\w>\n', line)
|
||||
if m:
|
||||
g = m.groups()
|
||||
(ip, name) = (g[0], g[1].lower())
|
||||
debug3('< %s -> %s' % (name, ip))
|
||||
if is_workgroup:
|
||||
_enqueue(_check_smb, ip)
|
||||
else:
|
||||
found_host(name, ip)
|
||||
check_host(name)
|
||||
|
||||
|
||||
def check_host(hostname):
|
||||
if _is_ip(hostname):
|
||||
_enqueue(_check_revdns, hostname)
|
||||
else:
|
||||
_enqueue(_check_dns, hostname)
|
||||
_enqueue(_check_smb, hostname)
|
||||
_enqueue(_check_nmb, hostname, False, False)
|
||||
|
||||
|
||||
def check_workgroup(hostname):
|
||||
_enqueue(_check_nmb, hostname, True, False)
|
||||
_enqueue(_check_nmb, hostname, True, True)
|
||||
|
||||
|
||||
def _enqueue(op, *args):
|
||||
@ -277,8 +176,6 @@ def hw_main(seed_hosts, auto_hosts):
|
||||
_enqueue(_check_netstat)
|
||||
check_host('localhost')
|
||||
check_host(socket.gethostname())
|
||||
check_workgroup('workgroup')
|
||||
check_workgroup('-')
|
||||
|
||||
while 1:
|
||||
now = time.time()
|
||||
|
@ -91,7 +91,7 @@ class BaseMethod(object):
|
||||
(key, self.name))
|
||||
|
||||
def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
|
||||
user):
|
||||
user, ttl, tmark):
|
||||
raise NotImplementedError()
|
||||
|
||||
def restore_firewall(self, port, family, udp, user):
|
||||
|
@ -189,7 +189,7 @@ class Method(BaseMethod):
|
||||
# udp_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVDSTADDR, 1)
|
||||
|
||||
def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
|
||||
user, ttl):
|
||||
user, ttl, tmark):
|
||||
# IPv6 not supported
|
||||
if family not in [socket.AF_INET]:
|
||||
raise Exception(
|
||||
|
@ -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):
|
||||
user, ttl, tmark):
|
||||
if family != socket.AF_INET and family != socket.AF_INET6:
|
||||
raise Exception(
|
||||
'Address family "%s" unsupported by nat method_name'
|
||||
|
@ -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):
|
||||
user, ttl, tmark):
|
||||
if udp:
|
||||
raise Exception("UDP not supported by nft")
|
||||
|
||||
|
@ -444,7 +444,7 @@ class Method(BaseMethod):
|
||||
return sock.getsockname()
|
||||
|
||||
def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
|
||||
user, ttl):
|
||||
user, ttl, tmark):
|
||||
if family not in [socket.AF_INET, socket.AF_INET6]:
|
||||
raise Exception(
|
||||
'Address family "%s" unsupported by pf method_name'
|
||||
|
@ -151,17 +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):
|
||||
if self.firewall is None:
|
||||
tmark = '1'
|
||||
else:
|
||||
tmark = self.firewall.tmark
|
||||
|
||||
self.setup_firewall_tproxy(port, dnsport, nslist, family, subnets, udp,
|
||||
user, tmark)
|
||||
|
||||
def setup_firewall_tproxy(self, port, dnsport, nslist, family, subnets,
|
||||
udp, user, tmark):
|
||||
user, ttl, tmark):
|
||||
if family not in [socket.AF_INET, socket.AF_INET6]:
|
||||
raise Exception(
|
||||
'Address family "%s" unsupported by tproxy method'
|
||||
@ -192,8 +182,8 @@ class Method(BaseMethod):
|
||||
_ipt('-F', divert_chain)
|
||||
_ipt('-N', tproxy_chain)
|
||||
_ipt('-F', tproxy_chain)
|
||||
_ipt('-I', 'OUTPUT', tmark, '-j', mark_chain)
|
||||
_ipt('-I', 'PREROUTING', tmark, '-j', tproxy_chain)
|
||||
_ipt('-I', 'OUTPUT', '1', '-j', mark_chain)
|
||||
_ipt('-I', 'PREROUTING', '1', '-j', tproxy_chain)
|
||||
|
||||
# Don't have packets sent to any of our local IP addresses go
|
||||
# through the tproxy or mark chains.
|
||||
@ -224,7 +214,7 @@ class Method(BaseMethod):
|
||||
'--dest', '%s/32' % ip,
|
||||
'-m', 'udp', '-p', 'udp', '--dport', '53')
|
||||
_ipt('-A', tproxy_chain, '-j', 'TPROXY',
|
||||
'--tproxy-mark', '0x'+tmark+'/0x'+tmark,
|
||||
'--tproxy-mark', tmark,
|
||||
'--dest', '%s/32' % ip,
|
||||
'-m', 'udp', '-p', 'udp', '--dport', '53',
|
||||
'--on-port', str(dnsport))
|
||||
@ -249,7 +239,7 @@ class Method(BaseMethod):
|
||||
'-m', 'tcp',
|
||||
*tcp_ports)
|
||||
_ipt('-A', tproxy_chain, '-j', 'TPROXY',
|
||||
'--tproxy-mark', '0x'+tmark+'/0x'+tmark,
|
||||
'--tproxy-mark', tmark,
|
||||
'--dest', '%s/%s' % (snet, swidth),
|
||||
'-m', 'tcp',
|
||||
*(tcp_ports + ('--on-port', str(port))))
|
||||
@ -273,7 +263,7 @@ class Method(BaseMethod):
|
||||
'-m', 'udp',
|
||||
*udp_ports)
|
||||
_ipt('-A', tproxy_chain, '-j', 'TPROXY',
|
||||
'--tproxy-mark', '0x'+tmark+'/0x'+tmark,
|
||||
'--tproxy-mark', tmark,
|
||||
'--dest', '%s/%s' % (snet, swidth),
|
||||
'-m', 'udp',
|
||||
*(udp_ports + ('--on-port', str(port))))
|
||||
|
@ -132,6 +132,7 @@ def parse_ipport(s):
|
||||
|
||||
|
||||
def parse_list(lst):
|
||||
"""Parse a comma separated string into a list."""
|
||||
return re.split(r'[\s,]+', lst.strip()) if lst else []
|
||||
|
||||
|
||||
@ -220,6 +221,7 @@ parser.add_argument(
|
||||
type=parse_list,
|
||||
help="""
|
||||
capture and forward DNS requests made to the following servers
|
||||
(comma separated)
|
||||
"""
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -280,7 +282,7 @@ parser.add_argument(
|
||||
action="count",
|
||||
default=0,
|
||||
help="""
|
||||
increase debug message verbosity
|
||||
increase debug message verbosity (can be used more than once)
|
||||
"""
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -445,8 +447,9 @@ parser.add_argument(
|
||||
parser.add_argument(
|
||||
"-t", "--tmark",
|
||||
metavar="[MARK]",
|
||||
default="1",
|
||||
default="0x01",
|
||||
help="""
|
||||
transproxy optional traffic mark with provided MARK value
|
||||
tproxy optional traffic mark with provided MARK value in
|
||||
hexadecimal (default '0x01')
|
||||
"""
|
||||
)
|
||||
|
@ -15,7 +15,7 @@ NSLIST
|
||||
{inet},1.2.3.33
|
||||
{inet6},2404:6800:4004:80c::33
|
||||
PORTS 1024,1025,1026,1027
|
||||
GO 1 -
|
||||
GO 1 - 63 0x01
|
||||
HOST 1.2.3.3,existing
|
||||
""".format(inet=AF_INET, inet6=AF_INET6))
|
||||
stdout = Mock()
|
||||
@ -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),
|
||||
63, '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),
|
||||
63, '0x01'),
|
||||
call().restore_firewall(1024, AF_INET6, True, None),
|
||||
call().restore_firewall(1025, AF_INET, True, None),
|
||||
]
|
||||
|
@ -103,7 +103,7 @@ 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)
|
||||
63, '0x01')
|
||||
|
||||
assert mock_ipt_chain_exists.mock_calls == [
|
||||
call(AF_INET6, 'nat', 'sshuttle-1024')
|
||||
@ -150,7 +150,7 @@ 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)
|
||||
63, '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 == []
|
||||
@ -164,7 +164,7 @@ 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)
|
||||
63, '0x01')
|
||||
assert mock_ipt_chain_exists.mock_calls == [
|
||||
call(AF_INET, 'nat', 'sshuttle-1025')
|
||||
]
|
||||
|
@ -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)
|
||||
63, '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)
|
||||
63, '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)
|
||||
63, '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)
|
||||
63, '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)
|
||||
63, '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)
|
||||
63, '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)
|
||||
63, '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)
|
||||
63, '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)
|
||||
63, '0x01')
|
||||
assert mock_ioctl.mock_calls == [
|
||||
call(mock_pf_get_dev(), 0xcd60441a, ANY),
|
||||
call(mock_pf_get_dev(), 0xcd60441a, ANY),
|
||||
|
@ -109,7 +109,7 @@ 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)
|
||||
63, '0x01')
|
||||
assert mock_ipt_chain_exists.mock_calls == [
|
||||
call(AF_INET6, 'mangle', 'sshuttle-m-1024'),
|
||||
call(AF_INET6, 'mangle', 'sshuttle-t-1024'),
|
||||
@ -139,17 +139,17 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
|
||||
call(AF_INET6, 'mangle', '-A', 'sshuttle-m-1024', '-j', 'RETURN',
|
||||
'-m', 'addrtype', '--dst-type', 'LOCAL'),
|
||||
call(AF_INET6, 'mangle', '-A', 'sshuttle-d-1024', '-j', 'MARK',
|
||||
'--set-mark', '1'),
|
||||
'--set-mark', '0x01'),
|
||||
call(AF_INET6, 'mangle', '-A', 'sshuttle-d-1024', '-j', 'ACCEPT'),
|
||||
call(AF_INET6, 'mangle', '-A', 'sshuttle-t-1024', '-m', 'socket',
|
||||
'-j', 'sshuttle-d-1024', '-m', 'tcp', '-p', 'tcp'),
|
||||
call(AF_INET6, 'mangle', '-A', 'sshuttle-t-1024', '-m', 'socket',
|
||||
'-j', 'sshuttle-d-1024', '-m', 'udp', '-p', 'udp'),
|
||||
call(AF_INET6, 'mangle', '-A', 'sshuttle-m-1024', '-j', 'MARK',
|
||||
'--set-mark', '1', '--dest', u'2404:6800:4004:80c::33/32',
|
||||
'--set-mark', '0x01', '--dest', u'2404:6800:4004:80c::33/32',
|
||||
'-m', 'udp', '-p', 'udp', '--dport', '53'),
|
||||
call(AF_INET6, 'mangle', '-A', 'sshuttle-t-1024', '-j', 'TPROXY',
|
||||
'--tproxy-mark', '0x1/0x1',
|
||||
'--tproxy-mark', '0x01',
|
||||
'--dest', u'2404:6800:4004:80c::33/32',
|
||||
'-m', 'udp', '-p', 'udp', '--dport', '53', '--on-port', '1026'),
|
||||
call(AF_INET6, 'mangle', '-A', 'sshuttle-m-1024', '-j', 'RETURN',
|
||||
@ -165,17 +165,19 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
|
||||
'--dest', u'2404:6800:4004:80c::101f/128',
|
||||
'-m', 'udp', '-p', 'udp', '--dport', '8080:8080'),
|
||||
call(AF_INET6, 'mangle', '-A', 'sshuttle-m-1024', '-j', 'MARK',
|
||||
'--set-mark', '1', '--dest', u'2404:6800:4004:80c::/64',
|
||||
'--set-mark', '0x01', '--dest', u'2404:6800:4004:80c::/64',
|
||||
'-m', 'tcp', '-p', 'tcp', '--dport', '8000:9000'),
|
||||
call(AF_INET6, 'mangle', '-A', 'sshuttle-t-1024', '-j', 'TPROXY',
|
||||
'--tproxy-mark', '0x1/0x1', '--dest', u'2404:6800:4004:80c::/64',
|
||||
'--tproxy-mark', '0x01', '--dest',
|
||||
u'2404:6800:4004:80c::/64',
|
||||
'-m', 'tcp', '-p', 'tcp', '--dport', '8000:9000',
|
||||
'--on-port', '1024'),
|
||||
call(AF_INET6, 'mangle', '-A', 'sshuttle-m-1024', '-j', 'MARK',
|
||||
'--set-mark', '1', '--dest', u'2404:6800:4004:80c::/64',
|
||||
'--set-mark', '0x01', '--dest', u'2404:6800:4004:80c::/64',
|
||||
'-m', 'udp', '-p', 'udp', '--dport', '8000:9000'),
|
||||
call(AF_INET6, 'mangle', '-A', 'sshuttle-t-1024', '-j', 'TPROXY',
|
||||
'--tproxy-mark', '0x1/0x1', '--dest', u'2404:6800:4004:80c::/64',
|
||||
'--tproxy-mark', '0x01', '--dest',
|
||||
u'2404:6800:4004:80c::/64',
|
||||
'-m', 'udp', '-p', 'udp', '--dport', '8000:9000',
|
||||
'--on-port', '1024')
|
||||
]
|
||||
@ -214,7 +216,7 @@ 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)
|
||||
63, '0x01')
|
||||
assert mock_ipt_chain_exists.mock_calls == [
|
||||
call(AF_INET, 'mangle', 'sshuttle-m-1025'),
|
||||
call(AF_INET, 'mangle', 'sshuttle-t-1025'),
|
||||
@ -244,17 +246,17 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
|
||||
call(AF_INET, 'mangle', '-A', 'sshuttle-m-1025', '-j', 'RETURN',
|
||||
'-m', 'addrtype', '--dst-type', 'LOCAL'),
|
||||
call(AF_INET, 'mangle', '-A', 'sshuttle-d-1025',
|
||||
'-j', 'MARK', '--set-mark', '1'),
|
||||
'-j', 'MARK', '--set-mark', '0x01'),
|
||||
call(AF_INET, 'mangle', '-A', 'sshuttle-d-1025', '-j', 'ACCEPT'),
|
||||
call(AF_INET, 'mangle', '-A', 'sshuttle-t-1025', '-m', 'socket',
|
||||
'-j', 'sshuttle-d-1025', '-m', 'tcp', '-p', 'tcp'),
|
||||
call(AF_INET, 'mangle', '-A', 'sshuttle-t-1025', '-m', 'socket',
|
||||
'-j', 'sshuttle-d-1025', '-m', 'udp', '-p', 'udp'),
|
||||
call(AF_INET, 'mangle', '-A', 'sshuttle-m-1025', '-j', 'MARK',
|
||||
'--set-mark', '1', '--dest', u'1.2.3.33/32',
|
||||
'--set-mark', '0x01', '--dest', u'1.2.3.33/32',
|
||||
'-m', 'udp', '-p', 'udp', '--dport', '53'),
|
||||
call(AF_INET, 'mangle', '-A', 'sshuttle-t-1025', '-j', 'TPROXY',
|
||||
'--tproxy-mark', '0x1/0x1', '--dest', u'1.2.3.33/32',
|
||||
'--tproxy-mark', '0x01', '--dest', u'1.2.3.33/32',
|
||||
'-m', 'udp', '-p', 'udp', '--dport', '53', '--on-port', '1027'),
|
||||
call(AF_INET, 'mangle', '-A', 'sshuttle-m-1025', '-j', 'RETURN',
|
||||
'--dest', u'1.2.3.66/32', '-m', 'tcp', '-p', 'tcp',
|
||||
@ -269,16 +271,16 @@ def test_setup_firewall(mock_ipt_chain_exists, mock_ipt_ttl, mock_ipt):
|
||||
'--dest', u'1.2.3.66/32', '-m', 'udp', '-p', 'udp',
|
||||
'--dport', '80:80'),
|
||||
call(AF_INET, 'mangle', '-A', 'sshuttle-m-1025', '-j', 'MARK',
|
||||
'--set-mark', '1', '--dest', u'1.2.3.0/24',
|
||||
'--set-mark', '0x01', '--dest', u'1.2.3.0/24',
|
||||
'-m', 'tcp', '-p', 'tcp'),
|
||||
call(AF_INET, 'mangle', '-A', 'sshuttle-t-1025', '-j', 'TPROXY',
|
||||
'--tproxy-mark', '0x1/0x1', '--dest', u'1.2.3.0/24',
|
||||
'--tproxy-mark', '0x01', '--dest', u'1.2.3.0/24',
|
||||
'-m', 'tcp', '-p', 'tcp', '--on-port', '1025'),
|
||||
call(AF_INET, 'mangle', '-A', 'sshuttle-m-1025', '-j', 'MARK',
|
||||
'--set-mark', '1', '--dest', u'1.2.3.0/24',
|
||||
'--set-mark', '0x01', '--dest', u'1.2.3.0/24',
|
||||
'-m', 'udp', '-p', 'udp'),
|
||||
call(AF_INET, 'mangle', '-A', 'sshuttle-t-1025', '-j', 'TPROXY',
|
||||
'--tproxy-mark', '0x1/0x1', '--dest', u'1.2.3.0/24',
|
||||
'--tproxy-mark', '0x01', '--dest', u'1.2.3.0/24',
|
||||
'-m', 'udp', '-p', 'udp', '--on-port', '1025')
|
||||
]
|
||||
mock_ipt_chain_exists.reset_mock()
|
||||
|
Loading…
Reference in New Issue
Block a user