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
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
guess the appropriate method depending on what it can find in PATH. The

View File

@ -1,8 +1,6 @@
import re
import os
import socket
import subprocess as ssubprocess
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):
if family == socket.AF_INET:
argv = ['nft', action, 'ip', table] + list(args)
elif family == socket.AF_INET6:
argv = ['nft', action, 'ip6', table] + list(args)
if family in (socket.AF_INET, socket.AF_INET6):
argv = ['nft', action, 'inet', table] + list(args)
else:
raise Exception('Unsupported family "%s"' % family_to_string(family))
debug1('>> %s\n' % ' '.join(argv))
@ -68,48 +64,6 @@ def nft(family, table, action, *args):
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

View File

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