Merge branch 'master' into which-fix to resolve merge conflict.

This commit is contained in:
Scott Kuhl
2020-10-26 17:24:32 -04:00
5 changed files with 97 additions and 29 deletions

View File

@ -2,24 +2,34 @@ import importlib
import socket
import struct
import errno
import ipaddress
from sshuttle.helpers import Fatal, debug3, which
def original_dst(sock):
ip = "0.0.0.0"
port = -1
try:
family = sock.family
SO_ORIGINAL_DST = 80
SOCKADDR_MIN = 16
sockaddr_in = sock.getsockopt(socket.SOL_IP,
SO_ORIGINAL_DST, SOCKADDR_MIN)
(proto, port, a, b, c, d) = struct.unpack('!HHBBBB', sockaddr_in[:8])
# FIXME: decoding is IPv4 only.
assert(socket.htons(proto) == socket.AF_INET)
ip = '%d.%d.%d.%d' % (a, b, c, d)
return (ip, port)
if family == socket.AF_INET:
SOCKADDR_MIN = 16
sockaddr_in = sock.getsockopt(socket.SOL_IP,
SO_ORIGINAL_DST, SOCKADDR_MIN)
port, raw_ip = struct.unpack_from('!2xH4s', sockaddr_in[:8])
ip = str(ipaddress.IPv4Address(raw_ip))
elif family == socket.AF_INET6:
sockaddr_in = sock.getsockopt(41, SO_ORIGINAL_DST, 64)
port, raw_ip = struct.unpack_from("!2xH4x16s", sockaddr_in)
ip = str(ipaddress.IPv6Address(raw_ip))
else:
raise Fatal("fw: Unknown family type.")
except socket.error as e:
if e.args[0] == errno.ENOPROTOOPT:
return sock.getsockname()
raise
return (ip, port)
class Features(object):

View File

@ -16,7 +16,10 @@ class Method(BaseMethod):
if udp:
raise Exception("UDP not supported by nft")
table = 'sshuttle-%s' % port
if family == socket.AF_INET:
table = 'sshuttle-ipv4-%s' % port
if family == socket.AF_INET6:
table = 'sshuttle-ipv6-%s' % port
def _nft(action, *args):
return nft(family, table, action, *args)
@ -37,7 +40,10 @@ class Method(BaseMethod):
# 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.
_nft('add rule', chain, 'ip ttl == 63 return')
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')
# Redirect DNS traffic as requested. This includes routing traffic
# to localhost DNS servers through sshuttle.
@ -57,7 +63,11 @@ class Method(BaseMethod):
# create new subnet entries.
for _, swidth, sexclude, snet, fport, lport \
in sorted(subnets, key=subnet_weight, reverse=True):
tcp_ports = ('ip', 'protocol', 'tcp')
if family == socket.AF_INET:
tcp_ports = ('ip', 'protocol', 'tcp')
elif family == socket.AF_INET6:
tcp_ports = ('ip6', 'nexthdr', 'tcp')
if fport and fport != lport:
tcp_ports = \
tcp_ports + \
@ -66,21 +76,38 @@ class Method(BaseMethod):
tcp_ports = tcp_ports + ('tcp', 'dport', '%d' % (fport))
if sexclude:
_nft('add rule', chain, *(tcp_ports + (
'ip daddr %s/%s' % (snet, swidth), 'return')))
if family == socket.AF_INET:
_nft('add rule', chain, *(tcp_ports + (
'ip daddr %s/%s' % (snet, swidth), 'return')))
elif family == socket.AF_INET6:
_nft('add rule', chain, *(tcp_ports + (
'ip6 daddr %s/%s' % (snet, swidth), 'return')))
else:
_nft('add rule', chain, *(tcp_ports + (
'ip daddr %s/%s' % (snet, swidth),
('redirect to :' + str(port)))))
if family == socket.AF_INET:
_nft('add rule', chain, *(tcp_ports + (
'ip daddr %s/%s' % (snet, swidth),
('redirect to :' + str(port)))))
elif family == socket.AF_INET6:
_nft('add rule', chain, *(tcp_ports + (
'ip6 daddr %s/%s' % (snet, swidth),
('redirect to :' + str(port)))))
def restore_firewall(self, port, family, udp, user):
if udp:
raise Exception("UDP not supported by nft method_name")
table = 'sshuttle-%s' % port
if family == socket.AF_INET:
table = 'sshuttle-ipv4-%s' % port
if family == socket.AF_INET6:
table = 'sshuttle-ipv6-%s' % port
def _nft(action, *args):
return nft(family, table, action, *args)
# basic cleanup/setup of chains
nonfatal(_nft, 'delete table', '')
def get_supported_features(self):
result = super(Method, self).get_supported_features()
result.ipv6 = True
return result