2015-11-17 06:51:22 +01:00
|
|
|
import socket
|
2017-09-24 14:11:26 +02:00
|
|
|
from socket import AF_INET, AF_INET6
|
2015-11-17 06:51:22 +01:00
|
|
|
import struct
|
|
|
|
|
2019-02-10 23:59:13 +01:00
|
|
|
import pytest
|
2021-01-16 01:59:28 +01:00
|
|
|
from unittest.mock import Mock, patch, call
|
2015-12-15 01:40:55 +01:00
|
|
|
from sshuttle.helpers import Fatal
|
2015-11-17 06:51:22 +01:00
|
|
|
from sshuttle.methods import get_method
|
|
|
|
|
|
|
|
|
|
|
|
def test_get_supported_features():
|
|
|
|
method = get_method('nat')
|
|
|
|
features = method.get_supported_features()
|
2021-05-28 23:55:17 +02:00
|
|
|
assert features.ipv6
|
2015-11-17 06:51:22 +01:00
|
|
|
assert not features.udp
|
2015-12-15 01:40:55 +01:00
|
|
|
assert features.dns
|
2015-11-17 06:51:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_get_tcp_dstip():
|
|
|
|
sock = Mock()
|
2020-10-21 05:38:27 +02:00
|
|
|
sock.family = AF_INET
|
2015-11-17 06:51:22 +01:00
|
|
|
sock.getsockopt.return_value = struct.pack(
|
2017-09-24 14:11:26 +02:00
|
|
|
'!HHBBBB', socket.ntohs(AF_INET), 1024, 127, 0, 0, 1)
|
2015-11-17 06:51:22 +01:00
|
|
|
method = get_method('nat')
|
|
|
|
assert method.get_tcp_dstip(sock) == ('127.0.0.1', 1024)
|
|
|
|
assert sock.mock_calls == [call.getsockopt(0, 80, 16)]
|
|
|
|
|
2020-10-21 05:38:27 +02:00
|
|
|
sock = Mock()
|
|
|
|
sock.family = AF_INET6
|
|
|
|
sock.getsockopt.return_value = struct.pack(
|
|
|
|
'!HH4xBBBBBBBBBBBBBBBB', socket.ntohs(AF_INET6),
|
|
|
|
1024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)
|
|
|
|
method = get_method('nft')
|
|
|
|
assert method.get_tcp_dstip(sock) == ('::1', 1024)
|
|
|
|
assert sock.mock_calls == [call.getsockopt(41, 80, 64)]
|
|
|
|
|
2015-11-17 06:51:22 +01:00
|
|
|
|
|
|
|
def test_recv_udp():
|
|
|
|
sock = Mock()
|
|
|
|
sock.recvfrom.return_value = "11111", "127.0.0.1"
|
|
|
|
method = get_method('nat')
|
|
|
|
result = method.recv_udp(sock, 1024)
|
|
|
|
assert sock.mock_calls == [call.recvfrom(1024)]
|
|
|
|
assert result == ("127.0.0.1", None, "11111")
|
|
|
|
|
|
|
|
|
|
|
|
def test_send_udp():
|
|
|
|
sock = Mock()
|
|
|
|
method = get_method('nat')
|
|
|
|
method.send_udp(sock, None, "127.0.0.1", "22222")
|
|
|
|
assert sock.mock_calls == [call.sendto("22222", "127.0.0.1")]
|
|
|
|
|
|
|
|
|
|
|
|
def test_setup_tcp_listener():
|
|
|
|
listener = Mock()
|
|
|
|
method = get_method('nat')
|
|
|
|
method.setup_tcp_listener(listener)
|
|
|
|
assert listener.mock_calls == []
|
|
|
|
|
|
|
|
|
|
|
|
def test_setup_udp_listener():
|
|
|
|
listener = Mock()
|
|
|
|
method = get_method('nat')
|
|
|
|
method.setup_udp_listener(listener)
|
|
|
|
assert listener.mock_calls == []
|
|
|
|
|
|
|
|
|
2015-12-15 01:40:55 +01:00
|
|
|
def test_assert_features():
|
2015-11-17 06:51:22 +01:00
|
|
|
method = get_method('nat')
|
2015-12-15 01:40:55 +01:00
|
|
|
features = method.get_supported_features()
|
|
|
|
method.assert_features(features)
|
|
|
|
|
|
|
|
features.udp = True
|
|
|
|
with pytest.raises(Fatal):
|
|
|
|
method.assert_features(features)
|
|
|
|
|
|
|
|
features.ipv6 = True
|
|
|
|
with pytest.raises(Fatal):
|
|
|
|
method.assert_features(features)
|
2015-11-17 06:51:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_firewall_command():
|
|
|
|
method = get_method('nat')
|
|
|
|
assert not method.firewall_command("somthing")
|
|
|
|
|
|
|
|
|
|
|
|
@patch('sshuttle.methods.nat.ipt')
|
|
|
|
@patch('sshuttle.methods.nat.ipt_chain_exists')
|
2021-06-01 05:33:55 +02:00
|
|
|
def test_setup_firewall(mock_ipt_chain_exists, mock_ipt):
|
2015-11-17 06:51:22 +01:00
|
|
|
mock_ipt_chain_exists.return_value = True
|
|
|
|
method = get_method('nat')
|
|
|
|
assert method.name == 'nat'
|
|
|
|
|
2021-05-28 23:55:17 +02:00
|
|
|
assert mock_ipt_chain_exists.mock_calls == []
|
|
|
|
assert mock_ipt.mock_calls == []
|
|
|
|
method.setup_firewall(
|
|
|
|
1024, 1026,
|
|
|
|
[(AF_INET6, u'2404:6800:4004:80c::33')],
|
|
|
|
AF_INET6,
|
|
|
|
[(AF_INET6, 64, False, u'2404:6800:4004:80c::', 0, 0),
|
|
|
|
(AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 80, 80)],
|
|
|
|
False,
|
|
|
|
None,
|
2021-06-01 05:33:55 +02:00
|
|
|
'0x01')
|
2021-05-28 23:55:17 +02:00
|
|
|
|
|
|
|
assert mock_ipt_chain_exists.mock_calls == [
|
|
|
|
call(AF_INET6, 'nat', 'sshuttle-1024')
|
|
|
|
]
|
|
|
|
assert mock_ipt.mock_calls == [
|
|
|
|
call(AF_INET6, 'nat', '-D', 'OUTPUT', '-j', 'sshuttle-1024'),
|
|
|
|
call(AF_INET6, 'nat', '-D', 'PREROUTING', '-j', 'sshuttle-1024'),
|
|
|
|
call(AF_INET6, 'nat', '-F', 'sshuttle-1024'),
|
|
|
|
call(AF_INET6, 'nat', '-X', 'sshuttle-1024'),
|
|
|
|
call(AF_INET6, 'nat', '-N', 'sshuttle-1024'),
|
|
|
|
call(AF_INET6, 'nat', '-F', 'sshuttle-1024'),
|
|
|
|
call(AF_INET6, 'nat', '-I', 'OUTPUT', '1', '-j', 'sshuttle-1024'),
|
|
|
|
call(AF_INET6, 'nat', '-I', 'PREROUTING', '1', '-j', 'sshuttle-1024'),
|
|
|
|
call(AF_INET6, 'nat', '-A', 'sshuttle-1024', '-j', 'REDIRECT',
|
|
|
|
'--dest', u'2404:6800:4004:80c::33', '-p', 'udp',
|
|
|
|
'--dport', '53', '--to-ports', '1026'),
|
|
|
|
call(AF_INET6, 'nat', '-A', 'sshuttle-1024', '-j', 'RETURN',
|
|
|
|
'-m', 'addrtype', '--dst-type', 'LOCAL'),
|
|
|
|
call(AF_INET6, 'nat', '-A', 'sshuttle-1024', '-j', 'RETURN',
|
|
|
|
'--dest', u'2404:6800:4004:80c::101f/128', '-p', 'tcp',
|
|
|
|
'--dport', '80:80'),
|
|
|
|
call(AF_INET6, 'nat', '-A', 'sshuttle-1024', '-j', 'REDIRECT',
|
|
|
|
'--dest', u'2404:6800:4004:80c::/64', '-p', 'tcp',
|
|
|
|
'--to-ports', '1024')
|
|
|
|
]
|
|
|
|
mock_ipt_chain_exists.reset_mock()
|
|
|
|
mock_ipt.reset_mock()
|
|
|
|
|
2015-11-17 06:51:22 +01:00
|
|
|
assert mock_ipt_chain_exists.mock_calls == []
|
|
|
|
assert mock_ipt.mock_calls == []
|
|
|
|
|
|
|
|
with pytest.raises(Exception) as excinfo:
|
|
|
|
method.setup_firewall(
|
|
|
|
1025, 1027,
|
2017-09-24 14:11:26 +02:00
|
|
|
[(AF_INET, u'1.2.3.33')],
|
|
|
|
AF_INET,
|
|
|
|
[(AF_INET, 24, False, u'1.2.3.0', 8000, 9000),
|
|
|
|
(AF_INET, 32, True, u'1.2.3.66', 8080, 8080)],
|
2017-09-08 03:17:37 +02:00
|
|
|
True,
|
2021-01-18 21:28:52 +01:00
|
|
|
None,
|
2021-06-01 05:33:55 +02:00
|
|
|
'0x01')
|
2015-11-17 06:51:22 +01:00
|
|
|
assert str(excinfo.value) == 'UDP not supported by nat method_name'
|
|
|
|
assert mock_ipt_chain_exists.mock_calls == []
|
|
|
|
assert mock_ipt.mock_calls == []
|
|
|
|
|
|
|
|
method.setup_firewall(
|
|
|
|
1025, 1027,
|
2017-09-24 14:11:26 +02:00
|
|
|
[(AF_INET, u'1.2.3.33')],
|
|
|
|
AF_INET,
|
|
|
|
[(AF_INET, 24, False, u'1.2.3.0', 8000, 9000),
|
|
|
|
(AF_INET, 32, True, u'1.2.3.66', 8080, 8080)],
|
2017-09-08 03:17:37 +02:00
|
|
|
False,
|
2021-01-18 21:28:52 +01:00
|
|
|
None,
|
2021-06-01 05:33:55 +02:00
|
|
|
'0x01')
|
2015-11-17 06:51:22 +01:00
|
|
|
assert mock_ipt_chain_exists.mock_calls == [
|
2017-09-24 14:11:26 +02:00
|
|
|
call(AF_INET, 'nat', 'sshuttle-1025')
|
2015-11-17 06:51:22 +01:00
|
|
|
]
|
|
|
|
assert mock_ipt.mock_calls == [
|
2017-09-24 14:11:26 +02:00
|
|
|
call(AF_INET, 'nat', '-D', 'OUTPUT', '-j', 'sshuttle-1025'),
|
|
|
|
call(AF_INET, 'nat', '-D', 'PREROUTING', '-j', 'sshuttle-1025'),
|
|
|
|
call(AF_INET, 'nat', '-F', 'sshuttle-1025'),
|
|
|
|
call(AF_INET, 'nat', '-X', 'sshuttle-1025'),
|
|
|
|
call(AF_INET, 'nat', '-N', 'sshuttle-1025'),
|
|
|
|
call(AF_INET, 'nat', '-F', 'sshuttle-1025'),
|
|
|
|
call(AF_INET, 'nat', '-I', 'OUTPUT', '1', '-j', 'sshuttle-1025'),
|
|
|
|
call(AF_INET, 'nat', '-I', 'PREROUTING', '1', '-j', 'sshuttle-1025'),
|
2020-10-21 05:38:27 +02:00
|
|
|
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'REDIRECT',
|
2021-05-28 23:55:17 +02:00
|
|
|
'--dest', u'1.2.3.33', '-p', 'udp',
|
2020-10-21 05:38:27 +02:00
|
|
|
'--dport', '53', '--to-ports', '1027'),
|
2019-06-08 04:12:21 +02:00
|
|
|
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'RETURN',
|
2020-10-21 05:38:27 +02:00
|
|
|
'-m', 'addrtype', '--dst-type', 'LOCAL'),
|
2017-09-24 14:11:26 +02:00
|
|
|
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'RETURN',
|
2020-10-21 05:38:27 +02:00
|
|
|
'--dest', u'1.2.3.66/32', '-p', 'tcp', '--dport', '8080:8080'),
|
|
|
|
call(AF_INET, 'nat', '-A', 'sshuttle-1025', '-j', 'REDIRECT',
|
|
|
|
'--dest', u'1.2.3.0/24', '-p', 'tcp', '--dport', '8000:9000',
|
|
|
|
'--to-ports', '1025')
|
2015-11-17 06:51:22 +01:00
|
|
|
]
|
|
|
|
mock_ipt_chain_exists.reset_mock()
|
|
|
|
mock_ipt.reset_mock()
|
|
|
|
|
2017-09-24 14:11:26 +02:00
|
|
|
method.restore_firewall(1025, AF_INET, False, None)
|
2015-11-17 06:51:22 +01:00
|
|
|
assert mock_ipt_chain_exists.mock_calls == [
|
2017-09-24 14:11:26 +02:00
|
|
|
call(AF_INET, 'nat', 'sshuttle-1025')
|
2015-11-17 06:51:22 +01:00
|
|
|
]
|
|
|
|
assert mock_ipt.mock_calls == [
|
2021-05-28 23:55:17 +02:00
|
|
|
call(AF_INET, 'nat', '-D', 'OUTPUT', '-j',
|
|
|
|
'sshuttle-1025'),
|
|
|
|
call(AF_INET, 'nat', '-D', 'PREROUTING', '-j',
|
|
|
|
'sshuttle-1025'),
|
2017-09-24 14:11:26 +02:00
|
|
|
call(AF_INET, 'nat', '-F', 'sshuttle-1025'),
|
|
|
|
call(AF_INET, 'nat', '-X', 'sshuttle-1025')
|
2015-11-17 06:51:22 +01:00
|
|
|
]
|
|
|
|
mock_ipt_chain_exists.reset_mock()
|
|
|
|
mock_ipt.reset_mock()
|
2021-05-28 23:55:17 +02:00
|
|
|
|
|
|
|
method.restore_firewall(1025, AF_INET6, False, None)
|
|
|
|
assert mock_ipt_chain_exists.mock_calls == [
|
|
|
|
call(AF_INET6, 'nat', 'sshuttle-1025')
|
|
|
|
]
|
|
|
|
assert mock_ipt.mock_calls == [
|
|
|
|
call(AF_INET6, 'nat', '-D', 'OUTPUT', '-j', 'sshuttle-1025'),
|
|
|
|
call(AF_INET6, 'nat', '-D', 'PREROUTING', '-j',
|
|
|
|
'sshuttle-1025'),
|
|
|
|
call(AF_INET6, 'nat', '-F', 'sshuttle-1025'),
|
|
|
|
call(AF_INET6, 'nat', '-X', 'sshuttle-1025')
|
|
|
|
]
|
|
|
|
mock_ipt_chain_exists.reset_mock()
|
|
|
|
mock_ipt.reset_mock()
|