mirror of
https://github.com/sshuttle/sshuttle.git
synced 2025-03-26 15:26:55 +01:00
Add support for OpenBSD
This commit is contained in:
parent
e8047ce3a9
commit
cedc8dc146
@ -198,6 +198,70 @@ class FreeBsd(Generic):
|
||||
super(FreeBsd, self).add_rules(rules)
|
||||
|
||||
|
||||
class OpenBsd(Generic):
|
||||
POOL_TICKET_OFFSET = 4
|
||||
RULE_ACTION_OFFSET = 3324
|
||||
ANCHOR_CALL_OFFSET = 1036
|
||||
|
||||
def __init__(self):
|
||||
class pfioc_natlook(Structure):
|
||||
pf_addr = Generic.pf_addr
|
||||
_fields_ = [("saddr", pf_addr),
|
||||
("daddr", pf_addr),
|
||||
("rsaddr", pf_addr),
|
||||
("rdaddr", pf_addr),
|
||||
("rdomain", c_uint16),
|
||||
("rrdomain", c_uint16),
|
||||
("sxport", c_uint16),
|
||||
("dxport", c_uint16),
|
||||
("rsxport", c_uint16),
|
||||
("rdxport", c_uint16),
|
||||
("af", c_uint8), # sa_family_t
|
||||
("proto", c_uint8),
|
||||
("proto_variant", c_uint8),
|
||||
("direction", c_uint8)]
|
||||
|
||||
self.pfioc_rule = c_char * 3400
|
||||
self.pfioc_natlook = pfioc_natlook
|
||||
super(OpenBsd, self).__init__()
|
||||
|
||||
def add_anchors(self):
|
||||
# before adding anchors and rules we must override the skip lo
|
||||
# that comes by default in openbsd pf.conf so the rules we will add,
|
||||
# which rely on translating/filtering packets on lo, can work
|
||||
pfctl('-f /dev/stdin', b'match on lo\n')
|
||||
super(OpenBsd, self).add_anchors()
|
||||
|
||||
def add_rules(self, includes, port, dnsport, nslist):
|
||||
tables = [
|
||||
b'table <forward_subnets> {%s}' % b','.join(includes)
|
||||
]
|
||||
translating_rules = [
|
||||
b'pass in on lo0 inet proto tcp '
|
||||
b'divert-to 127.0.0.1 port %r' % port
|
||||
]
|
||||
filtering_rules = [
|
||||
b'pass out inet proto tcp '
|
||||
b'to <forward_subnets> route-to lo0 keep state'
|
||||
]
|
||||
|
||||
if len(nslist) > 0:
|
||||
tables.append(
|
||||
b'table <dns_servers> {%s}' %
|
||||
b','.join([ns[1].encode("ASCII") for ns in nslist]))
|
||||
translating_rules.append(
|
||||
b'pass in on lo0 inet proto udp to <dns_servers>'
|
||||
b'port 53 rdr-to 127.0.0.1 port %r' % dnsport)
|
||||
filtering_rules.append(
|
||||
b'pass out inet proto udp to '
|
||||
b'<dns_servers> port 53 route-to lo0 keep state')
|
||||
|
||||
rules = b'\n'.join(tables + translating_rules + filtering_rules) \
|
||||
+ b'\n'
|
||||
|
||||
super(OpenBsd, self).add_rules(rules)
|
||||
|
||||
|
||||
class Darwin(FreeBsd):
|
||||
RULE_ACTION_OFFSET = 3068
|
||||
|
||||
@ -252,6 +316,8 @@ class Darwin(FreeBsd):
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
pf = Darwin()
|
||||
elif sys.platform.startswith('openbsd'):
|
||||
pf = OpenBsd()
|
||||
else:
|
||||
pf = FreeBsd()
|
||||
|
||||
|
@ -4,7 +4,7 @@ import socket
|
||||
|
||||
from sshuttle.methods import get_method
|
||||
from sshuttle.helpers import Fatal
|
||||
from sshuttle.methods.pf import FreeBsd, Darwin
|
||||
from sshuttle.methods.pf import FreeBsd, Darwin, OpenBsd
|
||||
|
||||
|
||||
def test_get_supported_features():
|
||||
@ -131,6 +131,29 @@ def test_firewall_command_freebsd(mock_pf_get_dev, mock_ioctl, mock_stdout):
|
||||
]
|
||||
|
||||
|
||||
@patch('sshuttle.methods.pf.pf', OpenBsd())
|
||||
@patch('sshuttle.methods.pf.sys.stdout')
|
||||
@patch('sshuttle.methods.pf.ioctl')
|
||||
@patch('sshuttle.methods.pf.pf_get_dev')
|
||||
def test_firewall_command_openbsd(mock_pf_get_dev, mock_ioctl, mock_stdout):
|
||||
method = get_method('pf')
|
||||
assert not method.firewall_command("somthing")
|
||||
|
||||
command = "QUERY_PF_NAT %d,%d,%s,%d,%s,%d\n" % (
|
||||
socket.AF_INET, socket.IPPROTO_TCP,
|
||||
"127.0.0.1", 1025, "127.0.0.2", 1024)
|
||||
assert method.firewall_command(command)
|
||||
|
||||
assert mock_pf_get_dev.mock_calls == [call()]
|
||||
assert mock_ioctl.mock_calls == [
|
||||
call(mock_pf_get_dev(), 0xc0504417, ANY),
|
||||
]
|
||||
assert mock_stdout.mock_calls == [
|
||||
call.write('QUERY_PF_NAT_SUCCESS 0.0.0.0,0\n'),
|
||||
call.flush(),
|
||||
]
|
||||
|
||||
|
||||
def pfctl(args, stdin=None):
|
||||
if args == '-s all':
|
||||
return (b'INFO:\nStatus: Disabled\nanother mary had a little lamb\n',
|
||||
@ -301,3 +324,80 @@ def test_setup_firewall_freebsd(mock_pf_get_dev, mock_ioctl, mock_pfctl):
|
||||
mock_pf_get_dev.reset_mock()
|
||||
mock_pfctl.reset_mock()
|
||||
mock_ioctl.reset_mock()
|
||||
|
||||
|
||||
@patch('sshuttle.helpers.verbose', new=3)
|
||||
@patch('sshuttle.methods.pf.pf', OpenBsd())
|
||||
@patch('sshuttle.methods.pf.pfctl')
|
||||
@patch('sshuttle.methods.pf.ioctl')
|
||||
@patch('sshuttle.methods.pf.pf_get_dev')
|
||||
def test_setup_firewall_openbsd(mock_pf_get_dev, mock_ioctl, mock_pfctl):
|
||||
mock_pfctl.side_effect = pfctl
|
||||
|
||||
method = get_method('pf')
|
||||
assert method.name == 'pf'
|
||||
|
||||
with pytest.raises(Exception) as excinfo:
|
||||
method.setup_firewall(
|
||||
1024, 1026,
|
||||
[(10, u'2404:6800:4004:80c::33')],
|
||||
10,
|
||||
[(10, 64, False, u'2404:6800:4004:80c::'),
|
||||
(10, 128, True, u'2404:6800:4004:80c::101f')],
|
||||
True)
|
||||
assert str(excinfo.value) \
|
||||
== 'Address family "AF_INET6" unsupported by pf method_name'
|
||||
assert mock_pf_get_dev.mock_calls == []
|
||||
assert mock_ioctl.mock_calls == []
|
||||
assert mock_pfctl.mock_calls == []
|
||||
|
||||
with pytest.raises(Exception) as excinfo:
|
||||
method.setup_firewall(
|
||||
1025, 1027,
|
||||
[(2, u'1.2.3.33')],
|
||||
2,
|
||||
[(2, 24, False, u'1.2.3.0'), (2, 32, True, u'1.2.3.66')],
|
||||
True)
|
||||
assert str(excinfo.value) == 'UDP not supported by pf method_name'
|
||||
assert mock_pf_get_dev.mock_calls == []
|
||||
assert mock_ioctl.mock_calls == []
|
||||
assert mock_pfctl.mock_calls == []
|
||||
|
||||
method.setup_firewall(
|
||||
1025, 1027,
|
||||
[(2, u'1.2.3.33')],
|
||||
2,
|
||||
[(2, 24, False, u'1.2.3.0'), (2, 32, True, u'1.2.3.66')],
|
||||
False)
|
||||
assert mock_ioctl.mock_calls == [
|
||||
call(mock_pf_get_dev(), 0xcd48441a, ANY),
|
||||
call(mock_pf_get_dev(), 0xcd48441a, ANY),
|
||||
]
|
||||
assert mock_pfctl.mock_calls == [
|
||||
call('-f /dev/stdin', b'match on lo\n'),
|
||||
call('-s all'),
|
||||
call('-a sshuttle -f /dev/stdin',
|
||||
b'table <forward_subnets> {!1.2.3.66/32,1.2.3.0/24}\n'
|
||||
b'table <dns_servers> {1.2.3.33}\n'
|
||||
b'pass in on lo0 inet proto tcp divert-to 127.0.0.1 port 1025\n'
|
||||
b'pass in on lo0 inet proto udp to '
|
||||
b'<dns_servers>port 53 rdr-to 127.0.0.1 port 1027\n'
|
||||
b'pass out inet proto tcp to '
|
||||
b'<forward_subnets> route-to lo0 keep state\n'
|
||||
b'pass out inet proto udp to '
|
||||
b'<dns_servers> port 53 route-to lo0 keep state\n'),
|
||||
call('-e'),
|
||||
]
|
||||
mock_pf_get_dev.reset_mock()
|
||||
mock_ioctl.reset_mock()
|
||||
mock_pfctl.reset_mock()
|
||||
|
||||
method.restore_firewall(1025, 2, False)
|
||||
assert mock_ioctl.mock_calls == []
|
||||
assert mock_pfctl.mock_calls == [
|
||||
call('-a sshuttle -F all'),
|
||||
call("-d"),
|
||||
]
|
||||
mock_pf_get_dev.reset_mock()
|
||||
mock_pfctl.reset_mock()
|
||||
mock_ioctl.reset_mock()
|
||||
|
Loading…
Reference in New Issue
Block a user