Simplify nftables based method

This commit is contained in:
Julian Wollrath 2020-01-10 14:09:54 +01:00 committed by Brian May
parent 6e9c58b4b4
commit 3edeb726b8
3 changed files with 13 additions and 68 deletions

View File

@ -44,7 +44,7 @@ Options
to during startup will be routed over the VPN. Valid examples are to during startup will be routed over the VPN. Valid examples are
example.com, example.com:8000 and example.com:8000-9000. example.com, example.com:8000 and example.com:8000-9000.
.. option:: --method [auto|nat|tproxy|pf] .. option:: --method [auto|nat|nft|tproxy|pf]
Which firewall method should sshuttle use? For auto, sshuttle attempts to Which firewall method should sshuttle use? For auto, sshuttle attempts to
guess the appropriate method depending on what it can find in PATH. The guess the appropriate method depending on what it can find in PATH. The

View File

@ -1,8 +1,6 @@
import re
import os import os
import socket import socket
import subprocess as ssubprocess import subprocess as ssubprocess
from sshuttle.helpers import log, debug1, Fatal, family_to_string from sshuttle.helpers import log, debug1, Fatal, family_to_string
@ -52,10 +50,8 @@ def ipt(family, table, *args):
def nft(family, table, action, *args): def nft(family, table, action, *args):
if family == socket.AF_INET: if family in (socket.AF_INET, socket.AF_INET6):
argv = ['nft', action, 'ip', table] + list(args) argv = ['nft', action, 'inet', table] + list(args)
elif family == socket.AF_INET6:
argv = ['nft', action, 'ip6', table] + list(args)
else: else:
raise Exception('Unsupported family "%s"' % family_to_string(family)) raise Exception('Unsupported family "%s"' % family_to_string(family))
debug1('>> %s\n' % ' '.join(argv)) debug1('>> %s\n' % ' '.join(argv))
@ -68,48 +64,6 @@ def nft(family, table, action, *args):
raise Fatal('%r returned %d' % (argv, rv)) raise Fatal('%r returned %d' % (argv, rv))
def nft_chain_exists(family, table, name):
if family == socket.AF_INET:
fam = 'ip'
elif family == socket.AF_INET6:
fam = 'ip6'
else:
raise Exception('Unsupported family "%s"' % family_to_string(family))
argv = ['nft', 'list', 'chain', fam, table, name]
debug1('>> %s\n' % ' '.join(argv))
env = {
'PATH': os.environ['PATH'],
'LC_ALL': "C",
}
try:
table_exists = False
output = ssubprocess.check_output(argv, env=env,
stderr=ssubprocess.STDOUT)
for line in output.decode('ASCII').split('\n'):
if line.startswith('table %s %s ' % (fam, table)):
table_exists = True
if table_exists and ('chain %s {' % name) in line:
return True
except ssubprocess.CalledProcessError:
return False
def nft_get_handle(expression, chain):
cmd = 'nft'
argv = [cmd, 'list', expression, '-a']
env = {
'PATH': os.environ['PATH'],
'LC_ALL': "C",
}
try:
output = ssubprocess.check_output(argv, env=env)
for line in output.decode('utf-8').split('\n'):
if ('jump %s' % chain) in line:
return re.sub('.*# ', '', line)
except ssubprocess.CalledProcessError as e:
raise Fatal('%r returned %d' % (argv, e.returncode))
_no_ttl_module = False _no_ttl_module = False

View File

@ -1,6 +1,6 @@
import socket import socket
from sshuttle.firewall import subnet_weight from sshuttle.firewall import subnet_weight
from sshuttle.linux import nft, nft_get_handle, nft_chain_exists, nonfatal from sshuttle.linux import nft, nonfatal
from sshuttle.methods import BaseMethod from sshuttle.methods import BaseMethod
@ -16,22 +16,19 @@ class Method(BaseMethod):
if udp: if udp:
raise Exception("UDP not supported by nft") raise Exception("UDP not supported by nft")
table = "nat" table = 'sshuttle-%s' % port
def _nft(action, *args): def _nft(action, *args):
return nft(family, table, action, *args) return nft(family, table, action, *args)
chain = table
# basic cleanup/setup of chains # basic cleanup/setup of chains
_nft('add table', '') _nft('add table', '')
# prerouting, postrouting, and output chains may already exist _nft('add chain', 'prerouting',
for chain in ['prerouting', 'postrouting', 'output']: '{ type nat hook prerouting priority -100; policy accept; }')
rules = '{{ type nat hook {} priority -100; policy accept; }}' \ _nft('add chain', 'output',
.format(chain) '{ type nat hook output priority -100; policy accept; }')
if not nft_chain_exists(family, table, chain):
_nft('add chain', chain, rules)
chain = 'sshuttle-%s' % port
_nft('add chain', chain) _nft('add chain', chain)
_nft('flush chain', chain) _nft('flush chain', chain)
_nft('add rule', 'output jump %s' % chain) _nft('add rule', 'output jump %s' % chain)
@ -70,16 +67,10 @@ class Method(BaseMethod):
if udp: if udp:
raise Exception("UDP not supported by nft method_name") raise Exception("UDP not supported by nft method_name")
table = "nat" table = 'sshuttle-%s' % port
def _nft(action, *args): def _nft(action, *args):
return nft(family, table, action, *args) return nft(family, table, action, *args)
chain = 'sshuttle-%s' % port
# basic cleanup/setup of chains # basic cleanup/setup of chains
handle = nft_get_handle('chain ip nat output', chain) nonfatal(_nft, 'delete table', '')
nonfatal(_nft, 'delete rule', 'output', handle)
handle = nft_get_handle('chain ip nat prerouting', chain)
nonfatal(_nft, 'delete rule', 'prerouting', handle)
nonfatal(_nft, 'delete chain', chain)