mirror of
https://github.com/sshuttle/sshuttle.git
synced 2025-07-04 16:50:34 +02:00
Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
abb48f1996 | |||
1c27a6cad0 | |||
8a2d5802c1 | |||
e7d4931b3d | |||
1e364b2c0b | |||
8816dbfd23 | |||
98d052d19e | |||
be4b081a0d | |||
9c5f1f5bbf | |||
33d09ffcaf | |||
45f8cce2f8 | |||
d4001c11f9 | |||
450ad79b18 | |||
5debf1f11a | |||
79181043bc | |||
c0a81353ab | |||
5bdf36152a | |||
a9ee66d905 | |||
094d3d9b97 | |||
19b677892e | |||
319c122861 | |||
f4bd290919 | |||
f353701f24 | |||
3037a91e51 | |||
cdd1e2c538 | |||
eb01c0b184 |
15
CHANGES.rst
15
CHANGES.rst
@ -9,6 +9,21 @@ adheres to `Semantic Versioning`_.
|
||||
.. _`Semantic Versioning`: http://semver.org/
|
||||
|
||||
|
||||
1.0.3 - 2020-08-24
|
||||
------------------
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
* Allow Mux() flush/fill to work with python < 3.5
|
||||
* Fix parse_hostport to always return string for host.
|
||||
* Require -r/--remote parameter.
|
||||
* Add missing package in OpenWRT documentation.
|
||||
* Fix doc about --listen option.
|
||||
* README: add Ubuntu.
|
||||
* Increase IP4 ttl to 63 hops instead of 42.
|
||||
* Fix formatting in installation.rst
|
||||
|
||||
|
||||
1.0.3 - 2020-07-12
|
||||
------------------
|
||||
|
||||
|
@ -30,6 +30,10 @@ common case:
|
||||
Obtaining sshuttle
|
||||
------------------
|
||||
|
||||
- Ubuntu 16.04 or later::
|
||||
|
||||
apt-get install sshuttle
|
||||
|
||||
- Debian stretch or later::
|
||||
|
||||
apt-get install sshuttle
|
||||
|
@ -6,7 +6,8 @@ Installation
|
||||
pip install sshuttle
|
||||
|
||||
- Debain package manager::
|
||||
sudo apt install sshuttle
|
||||
|
||||
sudo apt install sshuttle
|
||||
|
||||
- Clone::
|
||||
|
||||
@ -18,5 +19,6 @@ Installation
|
||||
Optionally after installation
|
||||
-----------------------------
|
||||
|
||||
- Add to sudoers file
|
||||
sshuttle --sudoers
|
||||
- Add to sudoers file::
|
||||
|
||||
sshuttle --sudoers
|
||||
|
@ -65,7 +65,8 @@ Options
|
||||
:program:`sshuttle`, e.g. ``--listen localhost``.
|
||||
|
||||
For the tproxy and pf methods this can be an IPv6 address. Use this option
|
||||
twice if required, to provide both IPv4 and IPv6 addresses.
|
||||
with comma separated values if required, to provide both IPv4 and IPv6
|
||||
addresses, e.g. ``--listen 127.0.0.1:0,[::1]:0``.
|
||||
|
||||
.. option:: -H, --auto-hosts
|
||||
|
||||
|
@ -3,6 +3,6 @@ OpenWRT
|
||||
|
||||
Run::
|
||||
|
||||
opkg install python3 python3-pip iptables-mod-nat-extra iptables-mod-ipopt
|
||||
opkg install python3 python3-pip iptables-mod-extra iptables-mod-nat-extra iptables-mod-ipopt
|
||||
python3 /usr/bin/pip3 install sshuttle
|
||||
sshuttle -l 0.0.0.0 -r <IP> -x 192.168.1.1 0/0
|
||||
|
@ -1,7 +1,7 @@
|
||||
-r requirements.txt
|
||||
attrs==19.3.0
|
||||
pytest==5.4.3
|
||||
pytest-cov==2.10.0
|
||||
attrs==20.1.0
|
||||
pytest==6.0.1
|
||||
pytest-cov==2.10.1
|
||||
mock==2.0.0
|
||||
flake8==3.8.3
|
||||
pyflakes==2.2.0
|
||||
|
@ -557,6 +557,11 @@ def main(listenip_v6, listenip_v4,
|
||||
subnets_include, subnets_exclude, daemon, to_nameserver, pidfile,
|
||||
user, sudo_pythonpath):
|
||||
|
||||
if not remotename:
|
||||
# XXX: We can't make it required at the argparse level,
|
||||
# because sshuttle calls out to itself in FirewallClient.
|
||||
raise Fatal("You must specify -r/--remote.")
|
||||
|
||||
if daemon:
|
||||
try:
|
||||
check_daemon(pidfile)
|
||||
|
@ -71,10 +71,10 @@ 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
|
||||
# with ttl 63. This makes the client side not recapture those
|
||||
# connections, in case client == server.
|
||||
try:
|
||||
argsplus = list(args) + ['-m', 'ttl', '!', '--ttl', '42']
|
||||
argsplus = list(args) + ['-m', 'ttl', '!', '--ttl', '63']
|
||||
ipt(family, *argsplus)
|
||||
except Fatal:
|
||||
ipt(family, *args)
|
||||
|
@ -70,7 +70,7 @@ def ipfw_rule_exists(n):
|
||||
found = False
|
||||
for line in p.stdout:
|
||||
if line.startswith(b'%05d ' % n):
|
||||
if not ('ipttl 42' in line or 'check-state' in line):
|
||||
if not ('ipttl 63' in line or 'check-state' in line):
|
||||
log('non-sshuttle ipfw rule: %r\n' % line.strip())
|
||||
raise Fatal('non-sshuttle ipfw rule #%d already exists!' % n)
|
||||
found = True
|
||||
@ -185,7 +185,7 @@ class Method(BaseMethod):
|
||||
sender.setsockopt(socket.SOL_IP, IP_BINDANY, 1)
|
||||
sender.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sender.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
|
||||
sender.setsockopt(socket.SOL_IP, socket.IP_TTL, 42)
|
||||
sender.setsockopt(socket.SOL_IP, socket.IP_TTL, 63)
|
||||
sender.bind(srcip)
|
||||
sender.sendto(data, dstip)
|
||||
sender.close()
|
||||
@ -224,7 +224,7 @@ class Method(BaseMethod):
|
||||
ipfw('add', '1', 'fwd', '127.0.0.1,%d' % port,
|
||||
'tcp',
|
||||
'from', 'any', 'to', 'table(126)',
|
||||
'not', 'ipttl', '42', 'keep-state', 'setup')
|
||||
'not', 'ipttl', '63', 'keep-state', 'setup')
|
||||
|
||||
ipfw_noexit('table', '124', 'flush')
|
||||
dnscount = 0
|
||||
@ -235,11 +235,11 @@ class Method(BaseMethod):
|
||||
ipfw('add', '1', 'fwd', '127.0.0.1,%d' % dnsport,
|
||||
'udp',
|
||||
'from', 'any', 'to', 'table(124)',
|
||||
'not', 'ipttl', '42')
|
||||
'not', 'ipttl', '63')
|
||||
ipfw('add', '1', 'allow',
|
||||
'udp',
|
||||
'from', 'any', 'to', 'any',
|
||||
'ipttl', '42')
|
||||
'ipttl', '63')
|
||||
|
||||
if subnets:
|
||||
# create new subnet entries
|
||||
|
@ -50,17 +50,17 @@ class Method(BaseMethod):
|
||||
'ip daddr %s/%s' % (snet, swidth), 'return')))
|
||||
else:
|
||||
_nft('add rule', chain, *(tcp_ports + (
|
||||
'ip daddr %s/%s' % (snet, swidth), 'ip ttl != 42',
|
||||
'ip daddr %s/%s' % (snet, swidth), 'ip ttl != 63',
|
||||
('redirect to :' + str(port)))))
|
||||
|
||||
for _, ip in [i for i in nslist if i[0] == family]:
|
||||
if family == socket.AF_INET:
|
||||
_nft('add rule', chain, 'ip protocol udp ip daddr %s' % ip,
|
||||
'udp dport { 53 }', 'ip ttl != 42',
|
||||
'udp dport { 53 }', 'ip ttl != 63',
|
||||
('redirect to :' + str(dnsport)))
|
||||
elif family == socket.AF_INET6:
|
||||
_nft('add rule', chain, 'ip6 protocol udp ip6 daddr %s' % ip,
|
||||
'udp dport { 53 }', 'ip ttl != 42',
|
||||
'udp dport { 53 }', 'ip ttl != 63',
|
||||
('redirect to :' + str(dnsport)))
|
||||
|
||||
def restore_firewall(self, port, family, udp, user):
|
||||
|
@ -195,7 +195,7 @@ class DnsProxy(Handler):
|
||||
|
||||
family, sockaddr = self._addrinfo(peer, port)
|
||||
sock = socket.socket(family, socket.SOCK_DGRAM)
|
||||
sock.setsockopt(socket.SOL_IP, socket.IP_TTL, 42)
|
||||
sock.setsockopt(socket.SOL_IP, socket.IP_TTL, 63)
|
||||
sock.connect(sockaddr)
|
||||
|
||||
self.peers[sock] = peer
|
||||
@ -252,7 +252,7 @@ class UdpProxy(Handler):
|
||||
self.chan = chan
|
||||
self.sock = sock
|
||||
if family == socket.AF_INET:
|
||||
self.sock.setsockopt(socket.SOL_IP, socket.IP_TTL, 42)
|
||||
self.sock.setsockopt(socket.SOL_IP, socket.IP_TTL, 63)
|
||||
|
||||
def send(self, dstip, data):
|
||||
debug2('UDP: sending to %r port %d\n' % dstip)
|
||||
|
@ -65,12 +65,12 @@ def parse_hostport(rhostport):
|
||||
try:
|
||||
# try to parse host as an IP adress,
|
||||
# if that works it is an IPv6 address
|
||||
host = ipaddress.ip_address(host)
|
||||
host = str(ipaddress.ip_address(host))
|
||||
except ValueError:
|
||||
# if that fails parse as URL to get the port
|
||||
parsed = urlparse('//{}'.format(host))
|
||||
try:
|
||||
host = ipaddress.ip_address(parsed.hostname)
|
||||
host = str(ipaddress.ip_address(parsed.hostname))
|
||||
except ValueError:
|
||||
# else if both fails, we have a hostname with port
|
||||
host = parsed.hostname
|
||||
|
@ -4,6 +4,7 @@ import socket
|
||||
import errno
|
||||
import select
|
||||
import os
|
||||
import fcntl
|
||||
|
||||
from sshuttle.helpers import b, log, debug1, debug2, debug3, Fatal
|
||||
|
||||
@ -436,7 +437,13 @@ class Mux(Handler):
|
||||
callback(cmd, data)
|
||||
|
||||
def flush(self):
|
||||
os.set_blocking(self.wfile.fileno(), False)
|
||||
try:
|
||||
os.set_blocking(self.wfile.fileno(), False)
|
||||
except AttributeError:
|
||||
# python < 3.5
|
||||
flags = fcntl.fcntl(self.wfile.fileno(), fcntl.F_GETFL)
|
||||
flags |= os.O_NONBLOCK
|
||||
flags = fcntl.fcntl(self.wfile.fileno(), fcntl.F_SETFL, flags)
|
||||
if self.outbuf and self.outbuf[0]:
|
||||
wrote = _nb_clean(os.write, self.wfile.fileno(), self.outbuf[0])
|
||||
debug2('mux wrote: %r/%d\n' % (wrote, len(self.outbuf[0])))
|
||||
@ -446,7 +453,13 @@ class Mux(Handler):
|
||||
self.outbuf[0:1] = []
|
||||
|
||||
def fill(self):
|
||||
os.set_blocking(self.rfile.fileno(), False)
|
||||
try:
|
||||
os.set_blocking(self.rfile.fileno(), False)
|
||||
except AttributeError:
|
||||
# python < 3.5
|
||||
flags = fcntl.fcntl(self.rfile.fileno(), fcntl.F_GETFL)
|
||||
flags |= os.O_NONBLOCK
|
||||
flags = fcntl.fcntl(self.rfile.fileno(), fcntl.F_SETFL, flags)
|
||||
try:
|
||||
read = _nb_clean(os.read, self.rfile.fileno(), LATENCY_BUFFER_SIZE)
|
||||
except OSError:
|
||||
@ -570,7 +583,7 @@ class MuxWrapper(SockWrapper):
|
||||
def connect_dst(family, ip, port):
|
||||
debug2('Connecting to %s:%d\n' % (ip, port))
|
||||
outsock = socket.socket(family)
|
||||
outsock.setsockopt(socket.SOL_IP, socket.IP_TTL, 42)
|
||||
outsock.setsockopt(socket.SOL_IP, socket.IP_TTL, 63)
|
||||
return SockWrapper(outsock, outsock,
|
||||
connect_to=(ip, port),
|
||||
peername='%s:%d' % (ip, port))
|
||||
|
20
tests/ssh/test_parse_hostport.py
Normal file
20
tests/ssh/test_parse_hostport.py
Normal file
@ -0,0 +1,20 @@
|
||||
from sshuttle.ssh import parse_hostport
|
||||
|
||||
|
||||
def test_host_only():
|
||||
assert parse_hostport("host") == (None, None, None, "host")
|
||||
assert parse_hostport("1.2.3.4") == (None, None, None, "1.2.3.4")
|
||||
assert parse_hostport("2001::1") == (None, None, None, "2001::1")
|
||||
assert parse_hostport("[2001::1]") == (None, None, None, "2001::1")
|
||||
|
||||
|
||||
def test_host_and_port():
|
||||
assert parse_hostport("host:22") == (None, None, 22, "host")
|
||||
assert parse_hostport("1.2.3.4:22") == (None, None, 22, "1.2.3.4")
|
||||
assert parse_hostport("[2001::1]:22") == (None, None, 22, "2001::1")
|
||||
|
||||
|
||||
def test_username_and_host():
|
||||
assert parse_hostport("user@host") == ("user", None, None, "host")
|
||||
assert parse_hostport("user:@host") == ("user", None, None, "host")
|
||||
assert parse_hostport("user:pass@host") == ("user", "pass", None, "host")
|
Reference in New Issue
Block a user