1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
import re
import os
import socket
import subprocess as ssubprocess
from sshuttle.helpers import log, debug1, Fatal, family_to_string
def nonfatal(func, *args):
try:
func(*args)
except Fatal as e:
log('error: %s\n' % e)
def ipt_chain_exists(family, table, name):
if family == socket.AF_INET6:
cmd = 'ip6tables'
elif family == socket.AF_INET:
cmd = 'iptables'
else:
raise Exception('Unsupported family "%s"' % family_to_string(family))
argv = [cmd, '-t', table, '-nL']
env = {
'PATH': os.environ['PATH'],
'LC_ALL': "C",
}
try:
output = ssubprocess.check_output(argv, env=env)
for line in output.decode('ASCII').split('\n'):
if line.startswith('Chain %s ' % name):
return True
except ssubprocess.CalledProcessError as e:
raise Fatal('%r returned %d' % (argv, e.returncode))
def ipt(family, table, *args):
if family == socket.AF_INET6:
argv = ['ip6tables', '-t', table] + list(args)
elif family == socket.AF_INET:
argv = ['iptables', '-t', table] + list(args)
else:
raise Exception('Unsupported family "%s"' % family_to_string(family))
debug1('>> %s\n' % ' '.join(argv))
env = {
'PATH': os.environ['PATH'],
'LC_ALL': "C",
}
rv = ssubprocess.call(argv, env=env)
if rv:
raise Fatal('%r returned %d' % (argv, rv))
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)
else:
raise Exception('Unsupported family "%s"' % family_to_string(family))
debug1('>> %s\n' % ' '.join(argv))
env = {
'PATH': os.environ['PATH'],
'LC_ALL': "C",
}
rv = ssubprocess.call(argv, env=env)
if 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
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 42. This makes the client side not recapture those
# connections, in case client == server.
try:
argsplus = list(args) + ['-m', 'ttl', '!', '--ttl', '42']
ipt(family, *argsplus)
except Fatal:
ipt(family, *args)
# we only get here if the non-ttl attempt succeeds
log('sshuttle: warning: your iptables is missing '
'the ttl module.\n')
_no_ttl_module = True
else:
ipt(family, *args)
|