2015-11-17 10:52:31 +01:00
|
|
|
import socket
|
2017-09-24 14:11:26 +02:00
|
|
|
from socket import AF_INET, AF_INET6
|
2015-11-17 10:52:31 +01:00
|
|
|
|
2019-02-10 23:59:13 +01:00
|
|
|
import pytest
|
|
|
|
from mock import Mock, patch, call, ANY
|
2015-11-17 10:52:31 +01:00
|
|
|
from sshuttle.methods import get_method
|
2015-12-15 01:40:55 +01:00
|
|
|
from sshuttle.helpers import Fatal
|
2016-03-02 01:26:29 +01:00
|
|
|
from sshuttle.methods.pf import FreeBsd, Darwin, OpenBsd
|
2015-11-17 10:52:31 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_get_supported_features():
|
|
|
|
method = get_method('pf')
|
|
|
|
features = method.get_supported_features()
|
2016-07-28 00:17:02 +02:00
|
|
|
assert features.ipv6
|
2015-11-17 10:52:31 +01:00
|
|
|
assert not features.udp
|
2015-12-15 01:40:55 +01:00
|
|
|
assert features.dns
|
2015-11-17 10:52:31 +01:00
|
|
|
|
|
|
|
|
2015-12-07 03:16:47 +01:00
|
|
|
@patch('sshuttle.helpers.verbose', new=3)
|
2015-11-17 10:52:31 +01:00
|
|
|
def test_get_tcp_dstip():
|
|
|
|
sock = Mock()
|
|
|
|
sock.getpeername.return_value = ("127.0.0.1", 1024)
|
|
|
|
sock.getsockname.return_value = ("127.0.0.2", 1025)
|
2017-09-24 14:11:26 +02:00
|
|
|
sock.family = AF_INET
|
2015-11-17 10:52:31 +01:00
|
|
|
|
|
|
|
firewall = Mock()
|
|
|
|
firewall.pfile.readline.return_value = \
|
2015-12-06 21:14:26 +01:00
|
|
|
b"QUERY_PF_NAT_SUCCESS 127.0.0.3,1026\n"
|
2015-11-17 10:52:31 +01:00
|
|
|
|
|
|
|
method = get_method('pf')
|
|
|
|
method.set_firewall(firewall)
|
|
|
|
assert method.get_tcp_dstip(sock) == ('127.0.0.3', 1026)
|
|
|
|
|
|
|
|
assert sock.mock_calls == [
|
|
|
|
call.getpeername(),
|
|
|
|
call.getsockname(),
|
|
|
|
]
|
|
|
|
assert firewall.mock_calls == [
|
2015-12-06 21:14:26 +01:00
|
|
|
call.pfile.write(b'QUERY_PF_NAT 2,6,127.0.0.1,1024,127.0.0.2,1025\n'),
|
2015-11-17 10:52:31 +01:00
|
|
|
call.pfile.flush(),
|
|
|
|
call.pfile.readline()
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
def test_recv_udp():
|
|
|
|
sock = Mock()
|
|
|
|
sock.recvfrom.return_value = "11111", "127.0.0.1"
|
|
|
|
method = get_method('pf')
|
|
|
|
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('pf')
|
|
|
|
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('pf')
|
|
|
|
method.setup_tcp_listener(listener)
|
|
|
|
assert listener.mock_calls == []
|
|
|
|
|
|
|
|
|
|
|
|
def test_setup_udp_listener():
|
|
|
|
listener = Mock()
|
|
|
|
method = get_method('pf')
|
|
|
|
method.setup_udp_listener(listener)
|
|
|
|
assert listener.mock_calls == []
|
|
|
|
|
|
|
|
|
2015-12-15 01:40:55 +01:00
|
|
|
def test_assert_features():
|
2015-11-17 10:52:31 +01:00
|
|
|
method = get_method('pf')
|
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 10:52:31 +01:00
|
|
|
|
|
|
|
|
2016-03-02 00:15:52 +01:00
|
|
|
@patch('sshuttle.methods.pf.pf', Darwin())
|
2015-11-17 10:52:31 +01:00
|
|
|
@patch('sshuttle.methods.pf.sys.stdout')
|
|
|
|
@patch('sshuttle.methods.pf.ioctl')
|
|
|
|
@patch('sshuttle.methods.pf.pf_get_dev')
|
2015-12-30 03:42:11 +01:00
|
|
|
def test_firewall_command_darwin(mock_pf_get_dev, mock_ioctl, mock_stdout):
|
2015-11-17 10:52:31 +01:00
|
|
|
method = get_method('pf')
|
|
|
|
assert not method.firewall_command("somthing")
|
|
|
|
|
|
|
|
command = "QUERY_PF_NAT %d,%d,%s,%d,%s,%d\n" % (
|
2017-09-24 14:11:26 +02:00
|
|
|
AF_INET, socket.IPPROTO_TCP,
|
2015-11-17 10:52:31 +01:00
|
|
|
"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 == [
|
2015-12-30 03:42:11 +01:00
|
|
|
call(mock_pf_get_dev(), 0xc0544417, ANY),
|
|
|
|
]
|
|
|
|
assert mock_stdout.mock_calls == [
|
|
|
|
call.write('QUERY_PF_NAT_SUCCESS 0.0.0.0,0\n'),
|
|
|
|
call.flush(),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2016-03-02 00:15:52 +01:00
|
|
|
@patch('sshuttle.methods.pf.pf', FreeBsd())
|
2015-12-30 03:42:11 +01:00
|
|
|
@patch('sshuttle.methods.pf.sys.stdout')
|
|
|
|
@patch('sshuttle.methods.pf.ioctl')
|
|
|
|
@patch('sshuttle.methods.pf.pf_get_dev')
|
2016-03-02 00:15:52 +01:00
|
|
|
def test_firewall_command_freebsd(mock_pf_get_dev, mock_ioctl, mock_stdout):
|
2015-12-30 03:42:11 +01:00
|
|
|
method = get_method('pf')
|
|
|
|
assert not method.firewall_command("somthing")
|
|
|
|
|
|
|
|
command = "QUERY_PF_NAT %d,%d,%s,%d,%s,%d\n" % (
|
2017-09-24 14:11:26 +02:00
|
|
|
AF_INET, socket.IPPROTO_TCP,
|
2015-12-30 03:42:11 +01:00
|
|
|
"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(), 0xc04c4417, ANY),
|
2015-11-17 10:52:31 +01:00
|
|
|
]
|
|
|
|
assert mock_stdout.mock_calls == [
|
|
|
|
call.write('QUERY_PF_NAT_SUCCESS 0.0.0.0,0\n'),
|
|
|
|
call.flush(),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2016-03-02 01:26:29 +01:00
|
|
|
@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" % (
|
2017-09-24 14:11:26 +02:00
|
|
|
AF_INET, socket.IPPROTO_TCP,
|
2016-03-02 01:26:29 +01:00
|
|
|
"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(),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2015-12-06 01:24:38 +01:00
|
|
|
def pfctl(args, stdin=None):
|
2016-07-28 00:17:02 +02:00
|
|
|
if args == '-s Interfaces -i lo -v':
|
2016-07-28 01:06:36 +02:00
|
|
|
return (b'lo0 (skip)',)
|
2015-12-06 01:24:38 +01:00
|
|
|
if args == '-s all':
|
2015-12-13 23:28:43 +01:00
|
|
|
return (b'INFO:\nStatus: Disabled\nanother mary had a little lamb\n',
|
|
|
|
b'little lamb\n')
|
2015-12-06 01:24:38 +01:00
|
|
|
if args == '-E':
|
|
|
|
return (b'\n', b'Token : abcdefg\n')
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2015-12-13 23:21:15 +01:00
|
|
|
@patch('sshuttle.helpers.verbose', new=3)
|
2016-03-02 00:15:52 +01:00
|
|
|
@patch('sshuttle.methods.pf.pf', Darwin())
|
2015-11-17 10:52:31 +01:00
|
|
|
@patch('sshuttle.methods.pf.pfctl')
|
|
|
|
@patch('sshuttle.methods.pf.ioctl')
|
|
|
|
@patch('sshuttle.methods.pf.pf_get_dev')
|
2015-12-13 23:28:43 +01:00
|
|
|
def test_setup_firewall_darwin(mock_pf_get_dev, mock_ioctl, mock_pfctl):
|
2015-12-06 01:24:38 +01:00
|
|
|
mock_pfctl.side_effect = pfctl
|
|
|
|
|
2015-11-17 10:52:31 +01:00
|
|
|
method = get_method('pf')
|
|
|
|
assert method.name == 'pf'
|
|
|
|
|
2016-07-28 00:17:02 +02:00
|
|
|
# IPV6
|
|
|
|
|
|
|
|
method.setup_firewall(
|
|
|
|
1024, 1026,
|
2017-09-24 14:11:26 +02:00
|
|
|
[(AF_INET6, u'2404:6800:4004:80c::33')],
|
|
|
|
AF_INET6,
|
|
|
|
[(AF_INET6, 64, False, u'2404:6800:4004:80c::', 8000, 9000),
|
|
|
|
(AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 8080, 8080)],
|
2017-09-08 03:17:37 +02:00
|
|
|
False,
|
|
|
|
None)
|
2016-07-28 00:17:02 +02:00
|
|
|
assert mock_ioctl.mock_calls == [
|
|
|
|
call(mock_pf_get_dev(), 0xC4704433, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xCC20441A, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xCC20441A, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xC4704433, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xCC20441A, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xCC20441A, ANY),
|
|
|
|
]
|
|
|
|
assert mock_pfctl.mock_calls == [
|
|
|
|
call('-s Interfaces -i lo -v'),
|
2016-07-28 01:06:36 +02:00
|
|
|
call('-f /dev/stdin', b'pass on lo\n'),
|
2016-07-28 00:17:02 +02:00
|
|
|
call('-s all'),
|
|
|
|
call('-a sshuttle6-1024 -f /dev/stdin',
|
|
|
|
b'table <dns_servers> {2404:6800:4004:80c::33}\n'
|
2017-07-28 04:31:45 +02:00
|
|
|
b'rdr pass on lo0 inet6 proto tcp from ! ::1 to '
|
Adds support for tunneling specific port ranges (#144)
* Adds support for tunneling specific port ranges
This set of changes implements the ability of specifying a port or port
range for an IP or subnet to only tunnel those ports for that subnet.
Also supports excluding a port or port range for a given IP or subnet.
When, for a given subnet, there are intercepting ranges being added and
excluded, the most specific, i.e., smaller range, takes precedence. In
case of a tie the exclusion wins.
For different subnets, the most specific, i.e., largest swidth, takes
precedence independent of any eventual port ranges.
Examples:
Tunnels all traffic to the 188.0.0.0/8 subnet except those to port 443.
```
sshuttle -r <server> 188.0.0.0/8 -x 188.0.0.0/8:443
```
Only tunnels traffic to port 80 of the 188.0.0.0/8 subnet.
```
sshuttle -r <server> 188.0.0.0/8:80
```
Tunnels traffic to the 188.0.0.0/8 subnet and the port range that goes
from 80 to 89.
```
sshuttle -r <server> 188.0.0.0/8:80-89 -x 188.0.0.0/8:80-90
```
* Allow subnets to be specified with domain names
Simplifies the implementation of address parsing by using
socket.getaddrinfo(), which can handle domain resolution, IPv4 and IPv6
addresses. This was proposed and mostly implemented by @DavidBuchanan314
in #146.
Signed-off-by: David Buchanan <DavidBuchanan314@users.noreply.github.com>
Signed-off-by: João Vieira <vieira@yubo.be>
* Also use getaddrinfo for parsing listen addr:port
* Fixes tests for tunneling a port range
* Updates documentation to include port/port range
Adds some examples with subnet:port and subnet:port-port.
Also clarifies the versions of Python supported on the server while
maintaining the recommendation for Python 2.7, 3.5 or later.
Mentions support for pfSense.
* In Py2 only named arguments may follow *expression
Fixes issue in Python 2.7 where *expression may only be followed by
named arguments.
* Use right regex to extract ip4/6, mask and ports
* Tests for parse_subnetport
2017-05-07 05:18:13 +02:00
|
|
|
b'2404:6800:4004:80c::/64 port 8000:9000 -> ::1 port 1024\n'
|
2016-07-28 00:17:02 +02:00
|
|
|
b'rdr pass on lo0 inet6 proto udp '
|
|
|
|
b'to <dns_servers> port 53 -> ::1 port 1026\n'
|
Adds support for tunneling specific port ranges (#144)
* Adds support for tunneling specific port ranges
This set of changes implements the ability of specifying a port or port
range for an IP or subnet to only tunnel those ports for that subnet.
Also supports excluding a port or port range for a given IP or subnet.
When, for a given subnet, there are intercepting ranges being added and
excluded, the most specific, i.e., smaller range, takes precedence. In
case of a tie the exclusion wins.
For different subnets, the most specific, i.e., largest swidth, takes
precedence independent of any eventual port ranges.
Examples:
Tunnels all traffic to the 188.0.0.0/8 subnet except those to port 443.
```
sshuttle -r <server> 188.0.0.0/8 -x 188.0.0.0/8:443
```
Only tunnels traffic to port 80 of the 188.0.0.0/8 subnet.
```
sshuttle -r <server> 188.0.0.0/8:80
```
Tunnels traffic to the 188.0.0.0/8 subnet and the port range that goes
from 80 to 89.
```
sshuttle -r <server> 188.0.0.0/8:80-89 -x 188.0.0.0/8:80-90
```
* Allow subnets to be specified with domain names
Simplifies the implementation of address parsing by using
socket.getaddrinfo(), which can handle domain resolution, IPv4 and IPv6
addresses. This was proposed and mostly implemented by @DavidBuchanan314
in #146.
Signed-off-by: David Buchanan <DavidBuchanan314@users.noreply.github.com>
Signed-off-by: João Vieira <vieira@yubo.be>
* Also use getaddrinfo for parsing listen addr:port
* Fixes tests for tunneling a port range
* Updates documentation to include port/port range
Adds some examples with subnet:port and subnet:port-port.
Also clarifies the versions of Python supported on the server while
maintaining the recommendation for Python 2.7, 3.5 or later.
Mentions support for pfSense.
* In Py2 only named arguments may follow *expression
Fixes issue in Python 2.7 where *expression may only be followed by
named arguments.
* Use right regex to extract ip4/6, mask and ports
* Tests for parse_subnetport
2017-05-07 05:18:13 +02:00
|
|
|
b'pass out route-to lo0 inet6 proto tcp to '
|
|
|
|
b'2404:6800:4004:80c::/64 port 8000:9000 keep state\n'
|
Changes pf exclusion rules precedence
Before this change, in pf, exclusions used a pass out quick which gave
them higher precedence than any other rule independent of subnet width.
As reported in #265 this causes exclusion from one instance of sshuttle
to also take effect on other instances because quick aborts the
evaluation of rules across all anchors.
This commit changes the precedence of rules so quick can now be
dropped. The new order is defined by the following rule, from
subnet_weight:
"We need to go from smaller, more specific, port ranges, to larger,
less-specific, port ranges. At each level, we order by subnet
width, from most-specific subnets (largest swidth) to
least-specific. On ties, excludes come first."
2018-10-28 20:56:12 +01:00
|
|
|
b'pass out inet6 proto tcp to '
|
|
|
|
b'2404:6800:4004:80c::101f/128 port 8080:8080\n'
|
2016-07-28 00:17:02 +02:00
|
|
|
b'pass out route-to lo0 inet6 proto udp '
|
|
|
|
b'to <dns_servers> port 53 keep state\n'),
|
|
|
|
call('-E'),
|
|
|
|
]
|
|
|
|
mock_pf_get_dev.reset_mock()
|
|
|
|
mock_ioctl.reset_mock()
|
|
|
|
mock_pfctl.reset_mock()
|
2015-11-17 10:52:31 +01:00
|
|
|
|
|
|
|
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', 0, 0),
|
|
|
|
(AF_INET, 32, True, u'1.2.3.66', 80, 80)],
|
2017-09-08 03:17:37 +02:00
|
|
|
True,
|
|
|
|
None)
|
2015-11-17 10:52:31 +01:00
|
|
|
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,
|
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', 0, 0),
|
|
|
|
(AF_INET, 32, True, u'1.2.3.66', 80, 80)],
|
2017-09-08 03:17:37 +02:00
|
|
|
False,
|
|
|
|
None)
|
2015-11-17 10:52:31 +01:00
|
|
|
assert mock_ioctl.mock_calls == [
|
2015-12-30 03:42:11 +01:00
|
|
|
call(mock_pf_get_dev(), 0xC4704433, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xCC20441A, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xCC20441A, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xC4704433, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xCC20441A, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xCC20441A, ANY),
|
2015-11-17 10:52:31 +01:00
|
|
|
]
|
2015-12-06 01:24:38 +01:00
|
|
|
assert mock_pfctl.mock_calls == [
|
2016-07-28 00:17:02 +02:00
|
|
|
call('-s Interfaces -i lo -v'),
|
2016-07-28 01:06:36 +02:00
|
|
|
call('-f /dev/stdin', b'pass on lo\n'),
|
2015-12-06 01:24:38 +01:00
|
|
|
call('-s all'),
|
2016-05-27 13:54:49 +02:00
|
|
|
call('-a sshuttle-1025 -f /dev/stdin',
|
2015-12-06 01:24:38 +01:00
|
|
|
b'table <dns_servers> {1.2.3.33}\n'
|
2017-07-28 04:31:45 +02:00
|
|
|
b'rdr pass on lo0 inet proto tcp from ! 127.0.0.1 to 1.2.3.0/24 '
|
Adds support for tunneling specific port ranges (#144)
* Adds support for tunneling specific port ranges
This set of changes implements the ability of specifying a port or port
range for an IP or subnet to only tunnel those ports for that subnet.
Also supports excluding a port or port range for a given IP or subnet.
When, for a given subnet, there are intercepting ranges being added and
excluded, the most specific, i.e., smaller range, takes precedence. In
case of a tie the exclusion wins.
For different subnets, the most specific, i.e., largest swidth, takes
precedence independent of any eventual port ranges.
Examples:
Tunnels all traffic to the 188.0.0.0/8 subnet except those to port 443.
```
sshuttle -r <server> 188.0.0.0/8 -x 188.0.0.0/8:443
```
Only tunnels traffic to port 80 of the 188.0.0.0/8 subnet.
```
sshuttle -r <server> 188.0.0.0/8:80
```
Tunnels traffic to the 188.0.0.0/8 subnet and the port range that goes
from 80 to 89.
```
sshuttle -r <server> 188.0.0.0/8:80-89 -x 188.0.0.0/8:80-90
```
* Allow subnets to be specified with domain names
Simplifies the implementation of address parsing by using
socket.getaddrinfo(), which can handle domain resolution, IPv4 and IPv6
addresses. This was proposed and mostly implemented by @DavidBuchanan314
in #146.
Signed-off-by: David Buchanan <DavidBuchanan314@users.noreply.github.com>
Signed-off-by: João Vieira <vieira@yubo.be>
* Also use getaddrinfo for parsing listen addr:port
* Fixes tests for tunneling a port range
* Updates documentation to include port/port range
Adds some examples with subnet:port and subnet:port-port.
Also clarifies the versions of Python supported on the server while
maintaining the recommendation for Python 2.7, 3.5 or later.
Mentions support for pfSense.
* In Py2 only named arguments may follow *expression
Fixes issue in Python 2.7 where *expression may only be followed by
named arguments.
* Use right regex to extract ip4/6, mask and ports
* Tests for parse_subnetport
2017-05-07 05:18:13 +02:00
|
|
|
b'-> 127.0.0.1 port 1025\n'
|
2016-07-28 00:17:02 +02:00
|
|
|
b'rdr pass on lo0 inet proto udp '
|
2015-12-06 01:24:38 +01:00
|
|
|
b'to <dns_servers> port 53 -> 127.0.0.1 port 1027\n'
|
Adds support for tunneling specific port ranges (#144)
* Adds support for tunneling specific port ranges
This set of changes implements the ability of specifying a port or port
range for an IP or subnet to only tunnel those ports for that subnet.
Also supports excluding a port or port range for a given IP or subnet.
When, for a given subnet, there are intercepting ranges being added and
excluded, the most specific, i.e., smaller range, takes precedence. In
case of a tie the exclusion wins.
For different subnets, the most specific, i.e., largest swidth, takes
precedence independent of any eventual port ranges.
Examples:
Tunnels all traffic to the 188.0.0.0/8 subnet except those to port 443.
```
sshuttle -r <server> 188.0.0.0/8 -x 188.0.0.0/8:443
```
Only tunnels traffic to port 80 of the 188.0.0.0/8 subnet.
```
sshuttle -r <server> 188.0.0.0/8:80
```
Tunnels traffic to the 188.0.0.0/8 subnet and the port range that goes
from 80 to 89.
```
sshuttle -r <server> 188.0.0.0/8:80-89 -x 188.0.0.0/8:80-90
```
* Allow subnets to be specified with domain names
Simplifies the implementation of address parsing by using
socket.getaddrinfo(), which can handle domain resolution, IPv4 and IPv6
addresses. This was proposed and mostly implemented by @DavidBuchanan314
in #146.
Signed-off-by: David Buchanan <DavidBuchanan314@users.noreply.github.com>
Signed-off-by: João Vieira <vieira@yubo.be>
* Also use getaddrinfo for parsing listen addr:port
* Fixes tests for tunneling a port range
* Updates documentation to include port/port range
Adds some examples with subnet:port and subnet:port-port.
Also clarifies the versions of Python supported on the server while
maintaining the recommendation for Python 2.7, 3.5 or later.
Mentions support for pfSense.
* In Py2 only named arguments may follow *expression
Fixes issue in Python 2.7 where *expression may only be followed by
named arguments.
* Use right regex to extract ip4/6, mask and ports
* Tests for parse_subnetport
2017-05-07 05:18:13 +02:00
|
|
|
b'pass out route-to lo0 inet proto tcp to 1.2.3.0/24 keep state\n'
|
Changes pf exclusion rules precedence
Before this change, in pf, exclusions used a pass out quick which gave
them higher precedence than any other rule independent of subnet width.
As reported in #265 this causes exclusion from one instance of sshuttle
to also take effect on other instances because quick aborts the
evaluation of rules across all anchors.
This commit changes the precedence of rules so quick can now be
dropped. The new order is defined by the following rule, from
subnet_weight:
"We need to go from smaller, more specific, port ranges, to larger,
less-specific, port ranges. At each level, we order by subnet
width, from most-specific subnets (largest swidth) to
least-specific. On ties, excludes come first."
2018-10-28 20:56:12 +01:00
|
|
|
b'pass out inet proto tcp to 1.2.3.66/32 port 80:80\n'
|
2015-12-06 01:24:38 +01:00
|
|
|
b'pass out route-to lo0 inet proto udp '
|
|
|
|
b'to <dns_servers> port 53 keep state\n'),
|
|
|
|
call('-E'),
|
|
|
|
]
|
2015-11-17 10:52:31 +01:00
|
|
|
mock_pf_get_dev.reset_mock()
|
|
|
|
mock_ioctl.reset_mock()
|
|
|
|
mock_pfctl.reset_mock()
|
|
|
|
|
2017-09-24 14:11:26 +02:00
|
|
|
method.restore_firewall(1025, AF_INET, False, None)
|
2015-11-17 10:52:31 +01:00
|
|
|
assert mock_ioctl.mock_calls == []
|
2015-12-06 01:24:38 +01:00
|
|
|
assert mock_pfctl.mock_calls == [
|
2016-05-27 13:54:49 +02:00
|
|
|
call('-a sshuttle-1025 -F all'),
|
2015-12-06 01:45:49 +01:00
|
|
|
call("-X abcdefg"),
|
2015-12-06 01:24:38 +01:00
|
|
|
]
|
2015-11-17 10:52:31 +01:00
|
|
|
mock_pf_get_dev.reset_mock()
|
|
|
|
mock_pfctl.reset_mock()
|
|
|
|
mock_ioctl.reset_mock()
|
2015-12-13 23:28:43 +01:00
|
|
|
|
|
|
|
|
|
|
|
@patch('sshuttle.helpers.verbose', new=3)
|
2016-03-02 00:15:52 +01:00
|
|
|
@patch('sshuttle.methods.pf.pf', FreeBsd())
|
2017-10-20 06:21:35 +02:00
|
|
|
@patch('subprocess.call')
|
2015-12-13 23:28:43 +01:00
|
|
|
@patch('sshuttle.methods.pf.pfctl')
|
|
|
|
@patch('sshuttle.methods.pf.ioctl')
|
|
|
|
@patch('sshuttle.methods.pf.pf_get_dev')
|
2017-10-20 06:21:35 +02:00
|
|
|
def test_setup_firewall_freebsd(mock_pf_get_dev, mock_ioctl, mock_pfctl,
|
|
|
|
mock_subprocess_call):
|
2015-12-13 23:28:43 +01:00
|
|
|
mock_pfctl.side_effect = pfctl
|
|
|
|
|
|
|
|
method = get_method('pf')
|
|
|
|
assert method.name == 'pf'
|
|
|
|
|
2016-07-28 00:17:02 +02:00
|
|
|
method.setup_firewall(
|
|
|
|
1024, 1026,
|
2017-09-24 14:11:26 +02:00
|
|
|
[(AF_INET6, u'2404:6800:4004:80c::33')],
|
|
|
|
AF_INET6,
|
|
|
|
[(AF_INET6, 64, False, u'2404:6800:4004:80c::', 8000, 9000),
|
|
|
|
(AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 8080, 8080)],
|
2017-09-08 03:17:37 +02:00
|
|
|
False,
|
|
|
|
None)
|
2016-07-28 00:17:02 +02:00
|
|
|
|
|
|
|
assert mock_pfctl.mock_calls == [
|
|
|
|
call('-s all'),
|
|
|
|
call('-a sshuttle6-1024 -f /dev/stdin',
|
|
|
|
b'table <dns_servers> {2404:6800:4004:80c::33}\n'
|
2017-07-28 04:31:45 +02:00
|
|
|
b'rdr pass on lo0 inet6 proto tcp from ! ::1 to '
|
|
|
|
b'2404:6800:4004:80c::/64 port 8000:9000 -> ::1 port 1024\n'
|
2016-07-28 00:17:02 +02:00
|
|
|
b'rdr pass on lo0 inet6 proto udp '
|
|
|
|
b'to <dns_servers> port 53 -> ::1 port 1026\n'
|
Adds support for tunneling specific port ranges (#144)
* Adds support for tunneling specific port ranges
This set of changes implements the ability of specifying a port or port
range for an IP or subnet to only tunnel those ports for that subnet.
Also supports excluding a port or port range for a given IP or subnet.
When, for a given subnet, there are intercepting ranges being added and
excluded, the most specific, i.e., smaller range, takes precedence. In
case of a tie the exclusion wins.
For different subnets, the most specific, i.e., largest swidth, takes
precedence independent of any eventual port ranges.
Examples:
Tunnels all traffic to the 188.0.0.0/8 subnet except those to port 443.
```
sshuttle -r <server> 188.0.0.0/8 -x 188.0.0.0/8:443
```
Only tunnels traffic to port 80 of the 188.0.0.0/8 subnet.
```
sshuttle -r <server> 188.0.0.0/8:80
```
Tunnels traffic to the 188.0.0.0/8 subnet and the port range that goes
from 80 to 89.
```
sshuttle -r <server> 188.0.0.0/8:80-89 -x 188.0.0.0/8:80-90
```
* Allow subnets to be specified with domain names
Simplifies the implementation of address parsing by using
socket.getaddrinfo(), which can handle domain resolution, IPv4 and IPv6
addresses. This was proposed and mostly implemented by @DavidBuchanan314
in #146.
Signed-off-by: David Buchanan <DavidBuchanan314@users.noreply.github.com>
Signed-off-by: João Vieira <vieira@yubo.be>
* Also use getaddrinfo for parsing listen addr:port
* Fixes tests for tunneling a port range
* Updates documentation to include port/port range
Adds some examples with subnet:port and subnet:port-port.
Also clarifies the versions of Python supported on the server while
maintaining the recommendation for Python 2.7, 3.5 or later.
Mentions support for pfSense.
* In Py2 only named arguments may follow *expression
Fixes issue in Python 2.7 where *expression may only be followed by
named arguments.
* Use right regex to extract ip4/6, mask and ports
* Tests for parse_subnetport
2017-05-07 05:18:13 +02:00
|
|
|
b'pass out route-to lo0 inet6 proto tcp to '
|
|
|
|
b'2404:6800:4004:80c::/64 port 8000:9000 keep state\n'
|
Changes pf exclusion rules precedence
Before this change, in pf, exclusions used a pass out quick which gave
them higher precedence than any other rule independent of subnet width.
As reported in #265 this causes exclusion from one instance of sshuttle
to also take effect on other instances because quick aborts the
evaluation of rules across all anchors.
This commit changes the precedence of rules so quick can now be
dropped. The new order is defined by the following rule, from
subnet_weight:
"We need to go from smaller, more specific, port ranges, to larger,
less-specific, port ranges. At each level, we order by subnet
width, from most-specific subnets (largest swidth) to
least-specific. On ties, excludes come first."
2018-10-28 20:56:12 +01:00
|
|
|
b'pass out inet6 proto tcp to '
|
|
|
|
b'2404:6800:4004:80c::101f/128 port 8080:8080\n'
|
2016-07-28 00:17:02 +02:00
|
|
|
b'pass out route-to lo0 inet6 proto udp '
|
|
|
|
b'to <dns_servers> port 53 keep state\n'),
|
|
|
|
call('-e'),
|
|
|
|
]
|
2017-10-20 06:21:35 +02:00
|
|
|
assert call(['kldload', 'pf']) in mock_subprocess_call.mock_calls
|
2016-07-28 00:17:02 +02:00
|
|
|
mock_pf_get_dev.reset_mock()
|
|
|
|
mock_ioctl.reset_mock()
|
|
|
|
mock_pfctl.reset_mock()
|
2015-12-13 23:28:43 +01:00
|
|
|
|
|
|
|
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', 0, 0),
|
|
|
|
(AF_INET, 32, True, u'1.2.3.66', 80, 80)],
|
2017-09-08 03:17:37 +02:00
|
|
|
True,
|
|
|
|
None)
|
2015-12-13 23:28:43 +01:00
|
|
|
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,
|
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', 0, 0),
|
|
|
|
(AF_INET, 32, True, u'1.2.3.66', 80, 80)],
|
2017-09-08 03:17:37 +02:00
|
|
|
False,
|
|
|
|
None)
|
2015-12-13 23:28:43 +01:00
|
|
|
assert mock_ioctl.mock_calls == [
|
2015-12-30 03:42:11 +01:00
|
|
|
call(mock_pf_get_dev(), 0xC4704433, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xCBE0441A, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xCBE0441A, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xC4704433, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xCBE0441A, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xCBE0441A, ANY),
|
2015-12-13 23:28:43 +01:00
|
|
|
]
|
|
|
|
assert mock_pfctl.mock_calls == [
|
|
|
|
call('-s all'),
|
2016-05-27 13:54:49 +02:00
|
|
|
call('-a sshuttle-1025 -f /dev/stdin',
|
2015-12-13 23:28:43 +01:00
|
|
|
b'table <dns_servers> {1.2.3.33}\n'
|
2017-07-28 04:31:45 +02:00
|
|
|
b'rdr pass on lo0 inet proto tcp from ! 127.0.0.1 '
|
|
|
|
b'to 1.2.3.0/24 -> 127.0.0.1 port 1025\n'
|
2016-07-28 00:17:02 +02:00
|
|
|
b'rdr pass on lo0 inet proto udp '
|
2015-12-13 23:28:43 +01:00
|
|
|
b'to <dns_servers> port 53 -> 127.0.0.1 port 1027\n'
|
Adds support for tunneling specific port ranges (#144)
* Adds support for tunneling specific port ranges
This set of changes implements the ability of specifying a port or port
range for an IP or subnet to only tunnel those ports for that subnet.
Also supports excluding a port or port range for a given IP or subnet.
When, for a given subnet, there are intercepting ranges being added and
excluded, the most specific, i.e., smaller range, takes precedence. In
case of a tie the exclusion wins.
For different subnets, the most specific, i.e., largest swidth, takes
precedence independent of any eventual port ranges.
Examples:
Tunnels all traffic to the 188.0.0.0/8 subnet except those to port 443.
```
sshuttle -r <server> 188.0.0.0/8 -x 188.0.0.0/8:443
```
Only tunnels traffic to port 80 of the 188.0.0.0/8 subnet.
```
sshuttle -r <server> 188.0.0.0/8:80
```
Tunnels traffic to the 188.0.0.0/8 subnet and the port range that goes
from 80 to 89.
```
sshuttle -r <server> 188.0.0.0/8:80-89 -x 188.0.0.0/8:80-90
```
* Allow subnets to be specified with domain names
Simplifies the implementation of address parsing by using
socket.getaddrinfo(), which can handle domain resolution, IPv4 and IPv6
addresses. This was proposed and mostly implemented by @DavidBuchanan314
in #146.
Signed-off-by: David Buchanan <DavidBuchanan314@users.noreply.github.com>
Signed-off-by: João Vieira <vieira@yubo.be>
* Also use getaddrinfo for parsing listen addr:port
* Fixes tests for tunneling a port range
* Updates documentation to include port/port range
Adds some examples with subnet:port and subnet:port-port.
Also clarifies the versions of Python supported on the server while
maintaining the recommendation for Python 2.7, 3.5 or later.
Mentions support for pfSense.
* In Py2 only named arguments may follow *expression
Fixes issue in Python 2.7 where *expression may only be followed by
named arguments.
* Use right regex to extract ip4/6, mask and ports
* Tests for parse_subnetport
2017-05-07 05:18:13 +02:00
|
|
|
b'pass out route-to lo0 inet proto tcp to 1.2.3.0/24 keep state\n'
|
Changes pf exclusion rules precedence
Before this change, in pf, exclusions used a pass out quick which gave
them higher precedence than any other rule independent of subnet width.
As reported in #265 this causes exclusion from one instance of sshuttle
to also take effect on other instances because quick aborts the
evaluation of rules across all anchors.
This commit changes the precedence of rules so quick can now be
dropped. The new order is defined by the following rule, from
subnet_weight:
"We need to go from smaller, more specific, port ranges, to larger,
less-specific, port ranges. At each level, we order by subnet
width, from most-specific subnets (largest swidth) to
least-specific. On ties, excludes come first."
2018-10-28 20:56:12 +01:00
|
|
|
b'pass out inet proto tcp to 1.2.3.66/32 port 80:80\n'
|
2015-12-13 23:28:43 +01:00
|
|
|
b'pass out route-to lo0 inet proto udp '
|
|
|
|
b'to <dns_servers> port 53 keep state\n'),
|
|
|
|
call('-e'),
|
|
|
|
]
|
|
|
|
mock_pf_get_dev.reset_mock()
|
|
|
|
mock_ioctl.reset_mock()
|
|
|
|
mock_pfctl.reset_mock()
|
|
|
|
|
2017-09-24 14:11:26 +02:00
|
|
|
method.restore_firewall(1025, AF_INET, False, None)
|
|
|
|
method.restore_firewall(1024, AF_INET6, False, None)
|
2015-12-13 23:28:43 +01:00
|
|
|
assert mock_ioctl.mock_calls == []
|
|
|
|
assert mock_pfctl.mock_calls == [
|
2016-05-27 13:54:49 +02:00
|
|
|
call('-a sshuttle-1025 -F all'),
|
2017-10-20 06:21:35 +02:00
|
|
|
call('-a sshuttle6-1024 -F all'),
|
2015-12-13 23:28:43 +01:00
|
|
|
call("-d"),
|
|
|
|
]
|
|
|
|
mock_pf_get_dev.reset_mock()
|
|
|
|
mock_pfctl.reset_mock()
|
|
|
|
mock_ioctl.reset_mock()
|
2016-03-02 01:26:29 +01:00
|
|
|
|
|
|
|
|
|
|
|
@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'
|
|
|
|
|
2016-07-28 00:17:02 +02:00
|
|
|
method.setup_firewall(
|
|
|
|
1024, 1026,
|
2017-09-24 14:11:26 +02:00
|
|
|
[(AF_INET6, u'2404:6800:4004:80c::33')],
|
|
|
|
AF_INET6,
|
|
|
|
[(AF_INET6, 64, False, u'2404:6800:4004:80c::', 8000, 9000),
|
|
|
|
(AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 8080, 8080)],
|
2017-09-08 03:17:37 +02:00
|
|
|
False,
|
|
|
|
None)
|
2016-03-02 01:26:29 +01:00
|
|
|
|
2016-07-28 00:17:02 +02:00
|
|
|
assert mock_ioctl.mock_calls == [
|
2019-09-10 23:05:28 +02:00
|
|
|
call(mock_pf_get_dev(), 0xcd60441a, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xcd60441a, ANY),
|
2016-07-28 00:17:02 +02:00
|
|
|
]
|
|
|
|
assert mock_pfctl.mock_calls == [
|
|
|
|
call('-s Interfaces -i lo -v'),
|
2016-07-28 01:06:36 +02:00
|
|
|
call('-f /dev/stdin', b'match on lo\n'),
|
2016-07-28 00:17:02 +02:00
|
|
|
call('-s all'),
|
|
|
|
call('-a sshuttle6-1024 -f /dev/stdin',
|
|
|
|
b'table <dns_servers> {2404:6800:4004:80c::33}\n'
|
Adds support for tunneling specific port ranges (#144)
* Adds support for tunneling specific port ranges
This set of changes implements the ability of specifying a port or port
range for an IP or subnet to only tunnel those ports for that subnet.
Also supports excluding a port or port range for a given IP or subnet.
When, for a given subnet, there are intercepting ranges being added and
excluded, the most specific, i.e., smaller range, takes precedence. In
case of a tie the exclusion wins.
For different subnets, the most specific, i.e., largest swidth, takes
precedence independent of any eventual port ranges.
Examples:
Tunnels all traffic to the 188.0.0.0/8 subnet except those to port 443.
```
sshuttle -r <server> 188.0.0.0/8 -x 188.0.0.0/8:443
```
Only tunnels traffic to port 80 of the 188.0.0.0/8 subnet.
```
sshuttle -r <server> 188.0.0.0/8:80
```
Tunnels traffic to the 188.0.0.0/8 subnet and the port range that goes
from 80 to 89.
```
sshuttle -r <server> 188.0.0.0/8:80-89 -x 188.0.0.0/8:80-90
```
* Allow subnets to be specified with domain names
Simplifies the implementation of address parsing by using
socket.getaddrinfo(), which can handle domain resolution, IPv4 and IPv6
addresses. This was proposed and mostly implemented by @DavidBuchanan314
in #146.
Signed-off-by: David Buchanan <DavidBuchanan314@users.noreply.github.com>
Signed-off-by: João Vieira <vieira@yubo.be>
* Also use getaddrinfo for parsing listen addr:port
* Fixes tests for tunneling a port range
* Updates documentation to include port/port range
Adds some examples with subnet:port and subnet:port-port.
Also clarifies the versions of Python supported on the server while
maintaining the recommendation for Python 2.7, 3.5 or later.
Mentions support for pfSense.
* In Py2 only named arguments may follow *expression
Fixes issue in Python 2.7 where *expression may only be followed by
named arguments.
* Use right regex to extract ip4/6, mask and ports
* Tests for parse_subnetport
2017-05-07 05:18:13 +02:00
|
|
|
b'pass in on lo0 inet6 proto tcp to 2404:6800:4004:80c::/64 '
|
|
|
|
b'port 8000:9000 divert-to ::1 port 1024\n'
|
2016-07-28 00:17:02 +02:00
|
|
|
b'pass in on lo0 inet6 proto udp '
|
|
|
|
b'to <dns_servers> port 53 rdr-to ::1 port 1026\n'
|
Adds support for tunneling specific port ranges (#144)
* Adds support for tunneling specific port ranges
This set of changes implements the ability of specifying a port or port
range for an IP or subnet to only tunnel those ports for that subnet.
Also supports excluding a port or port range for a given IP or subnet.
When, for a given subnet, there are intercepting ranges being added and
excluded, the most specific, i.e., smaller range, takes precedence. In
case of a tie the exclusion wins.
For different subnets, the most specific, i.e., largest swidth, takes
precedence independent of any eventual port ranges.
Examples:
Tunnels all traffic to the 188.0.0.0/8 subnet except those to port 443.
```
sshuttle -r <server> 188.0.0.0/8 -x 188.0.0.0/8:443
```
Only tunnels traffic to port 80 of the 188.0.0.0/8 subnet.
```
sshuttle -r <server> 188.0.0.0/8:80
```
Tunnels traffic to the 188.0.0.0/8 subnet and the port range that goes
from 80 to 89.
```
sshuttle -r <server> 188.0.0.0/8:80-89 -x 188.0.0.0/8:80-90
```
* Allow subnets to be specified with domain names
Simplifies the implementation of address parsing by using
socket.getaddrinfo(), which can handle domain resolution, IPv4 and IPv6
addresses. This was proposed and mostly implemented by @DavidBuchanan314
in #146.
Signed-off-by: David Buchanan <DavidBuchanan314@users.noreply.github.com>
Signed-off-by: João Vieira <vieira@yubo.be>
* Also use getaddrinfo for parsing listen addr:port
* Fixes tests for tunneling a port range
* Updates documentation to include port/port range
Adds some examples with subnet:port and subnet:port-port.
Also clarifies the versions of Python supported on the server while
maintaining the recommendation for Python 2.7, 3.5 or later.
Mentions support for pfSense.
* In Py2 only named arguments may follow *expression
Fixes issue in Python 2.7 where *expression may only be followed by
named arguments.
* Use right regex to extract ip4/6, mask and ports
* Tests for parse_subnetport
2017-05-07 05:18:13 +02:00
|
|
|
b'pass out inet6 proto tcp to 2404:6800:4004:80c::/64 '
|
|
|
|
b'port 8000:9000 route-to lo0 keep state\n'
|
Changes pf exclusion rules precedence
Before this change, in pf, exclusions used a pass out quick which gave
them higher precedence than any other rule independent of subnet width.
As reported in #265 this causes exclusion from one instance of sshuttle
to also take effect on other instances because quick aborts the
evaluation of rules across all anchors.
This commit changes the precedence of rules so quick can now be
dropped. The new order is defined by the following rule, from
subnet_weight:
"We need to go from smaller, more specific, port ranges, to larger,
less-specific, port ranges. At each level, we order by subnet
width, from most-specific subnets (largest swidth) to
least-specific. On ties, excludes come first."
2018-10-28 20:56:12 +01:00
|
|
|
b'pass out inet6 proto tcp to '
|
|
|
|
b'2404:6800:4004:80c::101f/128 port 8080:8080\n'
|
2016-07-28 00:17:02 +02:00
|
|
|
b'pass out inet6 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()
|
2017-11-07 02:20:24 +01:00
|
|
|
|
2016-03-02 01:26:29 +01:00
|
|
|
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', 0, 0),
|
|
|
|
(AF_INET, 32, True, u'1.2.3.66', 80, 80)],
|
2017-09-08 03:17:37 +02:00
|
|
|
True,
|
|
|
|
None)
|
2016-03-02 01:26:29 +01:00
|
|
|
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,
|
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', 0, 0),
|
|
|
|
(AF_INET, 32, True, u'1.2.3.66', 80, 80)],
|
2017-09-08 03:17:37 +02:00
|
|
|
False,
|
|
|
|
None)
|
2016-03-02 01:26:29 +01:00
|
|
|
assert mock_ioctl.mock_calls == [
|
2019-09-10 23:05:28 +02:00
|
|
|
call(mock_pf_get_dev(), 0xcd60441a, ANY),
|
|
|
|
call(mock_pf_get_dev(), 0xcd60441a, ANY),
|
2016-03-02 01:26:29 +01:00
|
|
|
]
|
|
|
|
assert mock_pfctl.mock_calls == [
|
2016-07-28 00:17:02 +02:00
|
|
|
call('-s Interfaces -i lo -v'),
|
2016-07-28 01:06:36 +02:00
|
|
|
call('-f /dev/stdin', b'match on lo\n'),
|
2016-03-02 01:26:29 +01:00
|
|
|
call('-s all'),
|
2016-05-27 13:54:49 +02:00
|
|
|
call('-a sshuttle-1025 -f /dev/stdin',
|
2016-03-02 01:26:29 +01:00
|
|
|
b'table <dns_servers> {1.2.3.33}\n'
|
Adds support for tunneling specific port ranges (#144)
* Adds support for tunneling specific port ranges
This set of changes implements the ability of specifying a port or port
range for an IP or subnet to only tunnel those ports for that subnet.
Also supports excluding a port or port range for a given IP or subnet.
When, for a given subnet, there are intercepting ranges being added and
excluded, the most specific, i.e., smaller range, takes precedence. In
case of a tie the exclusion wins.
For different subnets, the most specific, i.e., largest swidth, takes
precedence independent of any eventual port ranges.
Examples:
Tunnels all traffic to the 188.0.0.0/8 subnet except those to port 443.
```
sshuttle -r <server> 188.0.0.0/8 -x 188.0.0.0/8:443
```
Only tunnels traffic to port 80 of the 188.0.0.0/8 subnet.
```
sshuttle -r <server> 188.0.0.0/8:80
```
Tunnels traffic to the 188.0.0.0/8 subnet and the port range that goes
from 80 to 89.
```
sshuttle -r <server> 188.0.0.0/8:80-89 -x 188.0.0.0/8:80-90
```
* Allow subnets to be specified with domain names
Simplifies the implementation of address parsing by using
socket.getaddrinfo(), which can handle domain resolution, IPv4 and IPv6
addresses. This was proposed and mostly implemented by @DavidBuchanan314
in #146.
Signed-off-by: David Buchanan <DavidBuchanan314@users.noreply.github.com>
Signed-off-by: João Vieira <vieira@yubo.be>
* Also use getaddrinfo for parsing listen addr:port
* Fixes tests for tunneling a port range
* Updates documentation to include port/port range
Adds some examples with subnet:port and subnet:port-port.
Also clarifies the versions of Python supported on the server while
maintaining the recommendation for Python 2.7, 3.5 or later.
Mentions support for pfSense.
* In Py2 only named arguments may follow *expression
Fixes issue in Python 2.7 where *expression may only be followed by
named arguments.
* Use right regex to extract ip4/6, mask and ports
* Tests for parse_subnetport
2017-05-07 05:18:13 +02:00
|
|
|
b'pass in on lo0 inet proto tcp to 1.2.3.0/24 divert-to '
|
|
|
|
b'127.0.0.1 port 1025\n'
|
2016-03-02 01:26:29 +01:00
|
|
|
b'pass in on lo0 inet proto udp to '
|
2016-07-28 00:17:02 +02:00
|
|
|
b'<dns_servers> port 53 rdr-to 127.0.0.1 port 1027\n'
|
Adds support for tunneling specific port ranges (#144)
* Adds support for tunneling specific port ranges
This set of changes implements the ability of specifying a port or port
range for an IP or subnet to only tunnel those ports for that subnet.
Also supports excluding a port or port range for a given IP or subnet.
When, for a given subnet, there are intercepting ranges being added and
excluded, the most specific, i.e., smaller range, takes precedence. In
case of a tie the exclusion wins.
For different subnets, the most specific, i.e., largest swidth, takes
precedence independent of any eventual port ranges.
Examples:
Tunnels all traffic to the 188.0.0.0/8 subnet except those to port 443.
```
sshuttle -r <server> 188.0.0.0/8 -x 188.0.0.0/8:443
```
Only tunnels traffic to port 80 of the 188.0.0.0/8 subnet.
```
sshuttle -r <server> 188.0.0.0/8:80
```
Tunnels traffic to the 188.0.0.0/8 subnet and the port range that goes
from 80 to 89.
```
sshuttle -r <server> 188.0.0.0/8:80-89 -x 188.0.0.0/8:80-90
```
* Allow subnets to be specified with domain names
Simplifies the implementation of address parsing by using
socket.getaddrinfo(), which can handle domain resolution, IPv4 and IPv6
addresses. This was proposed and mostly implemented by @DavidBuchanan314
in #146.
Signed-off-by: David Buchanan <DavidBuchanan314@users.noreply.github.com>
Signed-off-by: João Vieira <vieira@yubo.be>
* Also use getaddrinfo for parsing listen addr:port
* Fixes tests for tunneling a port range
* Updates documentation to include port/port range
Adds some examples with subnet:port and subnet:port-port.
Also clarifies the versions of Python supported on the server while
maintaining the recommendation for Python 2.7, 3.5 or later.
Mentions support for pfSense.
* In Py2 only named arguments may follow *expression
Fixes issue in Python 2.7 where *expression may only be followed by
named arguments.
* Use right regex to extract ip4/6, mask and ports
* Tests for parse_subnetport
2017-05-07 05:18:13 +02:00
|
|
|
b'pass out inet proto tcp to 1.2.3.0/24 route-to lo0 keep state\n'
|
Changes pf exclusion rules precedence
Before this change, in pf, exclusions used a pass out quick which gave
them higher precedence than any other rule independent of subnet width.
As reported in #265 this causes exclusion from one instance of sshuttle
to also take effect on other instances because quick aborts the
evaluation of rules across all anchors.
This commit changes the precedence of rules so quick can now be
dropped. The new order is defined by the following rule, from
subnet_weight:
"We need to go from smaller, more specific, port ranges, to larger,
less-specific, port ranges. At each level, we order by subnet
width, from most-specific subnets (largest swidth) to
least-specific. On ties, excludes come first."
2018-10-28 20:56:12 +01:00
|
|
|
b'pass out inet proto tcp to 1.2.3.66/32 port 80:80\n'
|
2016-03-02 01:26:29 +01:00
|
|
|
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()
|
|
|
|
|
2017-09-24 14:11:26 +02:00
|
|
|
method.restore_firewall(1025, AF_INET, False, None)
|
|
|
|
method.restore_firewall(1024, AF_INET6, False, None)
|
2016-03-02 01:26:29 +01:00
|
|
|
assert mock_ioctl.mock_calls == []
|
|
|
|
assert mock_pfctl.mock_calls == [
|
2016-05-27 13:54:49 +02:00
|
|
|
call('-a sshuttle-1025 -F all'),
|
2017-10-20 06:21:35 +02:00
|
|
|
call('-a sshuttle6-1024 -F all'),
|
|
|
|
call('-d'),
|
2016-03-02 01:26:29 +01:00
|
|
|
]
|
|
|
|
mock_pf_get_dev.reset_mock()
|
|
|
|
mock_pfctl.reset_mock()
|
|
|
|
mock_ioctl.reset_mock()
|