mirror of
https://github.com/sshuttle/sshuttle.git
synced 2025-02-16 10:29:36 +01:00
Backward compatibility with Python 2.4 (server)
It is often the case that the user has no administrative control over the server that is being used. As such it is important to support as many versions as possible, at least on the remote server end. These fixes will allow sshuttle to be used with servers that have only python 2.4 or python 2.6 installed while hopefully not breaking the compatibility with 2.7 and 3.5.
This commit is contained in:
parent
6e15e69029
commit
4241381d82
@ -1,6 +1,8 @@
|
|||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
|
- 2.6
|
||||||
- 2.7
|
- 2.7
|
||||||
|
- 3.4
|
||||||
- 3.5
|
- 3.5
|
||||||
- pypy
|
- pypy
|
||||||
|
|
||||||
|
10
conftest.py
Normal file
10
conftest.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 0):
|
||||||
|
good_python = sys.version_info >= (3, 5)
|
||||||
|
else:
|
||||||
|
good_python = sys.version_info >= (2, 7)
|
||||||
|
|
||||||
|
collect_ignore = []
|
||||||
|
if not good_python:
|
||||||
|
collect_ignore.append("sshuttle/tests/client")
|
@ -62,6 +62,7 @@ cmd.exe with Administrator access. See :doc:`windows` for more information.
|
|||||||
|
|
||||||
Server side Requirements
|
Server side Requirements
|
||||||
------------------------
|
------------------------
|
||||||
|
Server requirements are more relaxed, however it is recommended that you use
|
||||||
Python 2.7 or Python 3.5.
|
Python 2.7 or Python 3.5.
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,19 +4,20 @@ import imp
|
|||||||
|
|
||||||
z = zlib.decompressobj()
|
z = zlib.decompressobj()
|
||||||
while 1:
|
while 1:
|
||||||
name = stdin.readline().strip()
|
name = sys.stdin.readline().strip()
|
||||||
if name:
|
if name:
|
||||||
name = name.decode("ASCII")
|
name = name.decode("ASCII")
|
||||||
|
|
||||||
nbytes = int(stdin.readline())
|
nbytes = int(sys.stdin.readline())
|
||||||
if verbosity >= 2:
|
if verbosity >= 2:
|
||||||
sys.stderr.write('server: assembling %r (%d bytes)\n'
|
sys.stderr.write('server: assembling %r (%d bytes)\n'
|
||||||
% (name, nbytes))
|
% (name, nbytes))
|
||||||
content = z.decompress(stdin.read(nbytes))
|
content = z.decompress(sys.stdin.read(nbytes))
|
||||||
|
|
||||||
module = imp.new_module(name)
|
module = imp.new_module(name)
|
||||||
parent, _, parent_name = name.rpartition(".")
|
parents = name.rsplit(".", 1)
|
||||||
if parent != "":
|
if len(parents) == 2:
|
||||||
|
parent, parent_name = parents
|
||||||
setattr(sys.modules[parent], parent_name, module)
|
setattr(sys.modules[parent], parent_name, module)
|
||||||
|
|
||||||
code = compile(content, name, "exec")
|
code = compile(content, name, "exec")
|
||||||
|
@ -5,6 +5,16 @@ import errno
|
|||||||
logprefix = ''
|
logprefix = ''
|
||||||
verbose = 0
|
verbose = 0
|
||||||
|
|
||||||
|
if sys.version_info[0] == 3:
|
||||||
|
binary_type = bytes
|
||||||
|
|
||||||
|
def b(s):
|
||||||
|
return s.encode("ASCII")
|
||||||
|
else:
|
||||||
|
binary_type = str
|
||||||
|
|
||||||
|
def b(s):
|
||||||
|
return s
|
||||||
|
|
||||||
def log(s):
|
def log(s):
|
||||||
global logprefix
|
global logprefix
|
||||||
@ -70,7 +80,8 @@ def islocal(ip, family):
|
|||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
sock.bind((ip, 0))
|
sock.bind((ip, 0))
|
||||||
except socket.error as e:
|
except socket.error:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
if e.args[0] == errno.EADDRNOTAVAIL:
|
if e.args[0] == errno.EADDRNOTAVAIL:
|
||||||
return False # not a local IP
|
return False # not a local IP
|
||||||
else:
|
else:
|
||||||
|
@ -22,7 +22,8 @@ hostnames = {}
|
|||||||
queue = {}
|
queue = {}
|
||||||
try:
|
try:
|
||||||
null = open('/dev/null', 'wb')
|
null = open('/dev/null', 'wb')
|
||||||
except IOError as e:
|
except IOError:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
log('warning: %s\n' % e)
|
log('warning: %s\n' % e)
|
||||||
null = os.popen("sh -c 'while read x; do :; done'", 'wb', 4096)
|
null = os.popen("sh -c 'while read x; do :; done'", 'wb', 4096)
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ def write_host_cache():
|
|||||||
for name, ip in sorted(hostnames.items()):
|
for name, ip in sorted(hostnames.items()):
|
||||||
f.write(('%s,%s\n' % (name, ip)).encode("ASCII"))
|
f.write(('%s,%s\n' % (name, ip)).encode("ASCII"))
|
||||||
f.close()
|
f.close()
|
||||||
os.chmod(tmpname, 0o600)
|
os.chmod(tmpname, 384) # 600 in octal, 'rw-------'
|
||||||
os.rename(tmpname, CACHEFILE)
|
os.rename(tmpname, CACHEFILE)
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
@ -50,7 +51,8 @@ def write_host_cache():
|
|||||||
def read_host_cache():
|
def read_host_cache():
|
||||||
try:
|
try:
|
||||||
f = open(CACHEFILE)
|
f = open(CACHEFILE)
|
||||||
except IOError as e:
|
except IOError:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
if e.errno == errno.ENOENT:
|
if e.errno == errno.ENOENT:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
@ -124,7 +126,8 @@ def _check_netstat():
|
|||||||
p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null)
|
p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null)
|
||||||
content = p.stdout.read().decode("ASCII")
|
content = p.stdout.read().decode("ASCII")
|
||||||
p.wait()
|
p.wait()
|
||||||
except OSError as e:
|
except OSError:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
log('%r failed: %r\n' % (argv, e))
|
log('%r failed: %r\n' % (argv, e))
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -144,7 +147,8 @@ def _check_smb(hostname):
|
|||||||
p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null)
|
p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null)
|
||||||
lines = p.stdout.readlines()
|
lines = p.stdout.readlines()
|
||||||
p.wait()
|
p.wait()
|
||||||
except OSError as e:
|
except OSError:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
log('%r failed: %r\n' % (argv, e))
|
log('%r failed: %r\n' % (argv, e))
|
||||||
_smb_ok = False
|
_smb_ok = False
|
||||||
return
|
return
|
||||||
@ -201,7 +205,8 @@ def _check_nmb(hostname, is_workgroup, is_master):
|
|||||||
p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null)
|
p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null)
|
||||||
lines = p.stdout.readlines()
|
lines = p.stdout.readlines()
|
||||||
rv = p.wait()
|
rv = p.wait()
|
||||||
except OSError as e:
|
except OSError:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
log('%r failed: %r\n' % (argv, e))
|
log('%r failed: %r\n' % (argv, e))
|
||||||
_nmb_ok = False
|
_nmb_ok = False
|
||||||
return
|
return
|
||||||
|
@ -12,29 +12,29 @@ import sshuttle.helpers as helpers
|
|||||||
import sshuttle.hostwatch as hostwatch
|
import sshuttle.hostwatch as hostwatch
|
||||||
import subprocess as ssubprocess
|
import subprocess as ssubprocess
|
||||||
from sshuttle.ssnet import Handler, Proxy, Mux, MuxWrapper
|
from sshuttle.ssnet import Handler, Proxy, Mux, MuxWrapper
|
||||||
from sshuttle.helpers import log, debug1, debug2, debug3, Fatal, \
|
from sshuttle.helpers import b, log, debug1, debug2, debug3, Fatal, \
|
||||||
resolvconf_random_nameserver
|
resolvconf_random_nameserver
|
||||||
|
|
||||||
|
|
||||||
def _ipmatch(ipstr):
|
def _ipmatch(ipstr):
|
||||||
# FIXME: IPv4 only
|
# FIXME: IPv4 only
|
||||||
if ipstr == b'default':
|
if ipstr == 'default':
|
||||||
ipstr = b'0.0.0.0/0'
|
ipstr = '0.0.0.0/0'
|
||||||
m = re.match(b'^(\d+(\.\d+(\.\d+(\.\d+)?)?)?)(?:/(\d+))?$', ipstr)
|
m = re.match('^(\d+(\.\d+(\.\d+(\.\d+)?)?)?)(?:/(\d+))?$', ipstr)
|
||||||
if m:
|
if m:
|
||||||
g = m.groups()
|
g = m.groups()
|
||||||
ips = g[0]
|
ips = g[0]
|
||||||
width = int(g[4] or 32)
|
width = int(g[4] or 32)
|
||||||
if g[1] is None:
|
if g[1] is None:
|
||||||
ips += b'.0.0.0'
|
ips += '.0.0.0'
|
||||||
width = min(width, 8)
|
width = min(width, 8)
|
||||||
elif g[2] is None:
|
elif g[2] is None:
|
||||||
ips += b'.0.0'
|
ips += '.0.0'
|
||||||
width = min(width, 16)
|
width = min(width, 16)
|
||||||
elif g[3] is None:
|
elif g[3] is None:
|
||||||
ips += b'.0'
|
ips += '.0'
|
||||||
width = min(width, 24)
|
width = min(width, 24)
|
||||||
ips = ips.decode("ASCII")
|
ips = ips
|
||||||
return (struct.unpack('!I', socket.inet_aton(ips))[0], width)
|
return (struct.unpack('!I', socket.inet_aton(ips))[0], width)
|
||||||
|
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ def _list_routes():
|
|||||||
p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE)
|
p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE)
|
||||||
routes = []
|
routes = []
|
||||||
for line in p.stdout:
|
for line in p.stdout:
|
||||||
cols = re.split(b'\s+', line)
|
cols = re.split(r'\s+', line.decode("ASCII"))
|
||||||
ipw = _ipmatch(cols[0])
|
ipw = _ipmatch(cols[0])
|
||||||
if not ipw:
|
if not ipw:
|
||||||
continue # some lines won't be parseable; never mind
|
continue # some lines won't be parseable; never mind
|
||||||
@ -152,7 +152,8 @@ class DnsProxy(Handler):
|
|||||||
try:
|
try:
|
||||||
sock.send(self.request)
|
sock.send(self.request)
|
||||||
self.socks.append(sock)
|
self.socks.append(sock)
|
||||||
except socket.error as e:
|
except socket.error:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
if e.args[0] in ssnet.NET_ERRS:
|
if e.args[0] in ssnet.NET_ERRS:
|
||||||
# might have been spurious; try again.
|
# might have been spurious; try again.
|
||||||
# Note: these errors sometimes are reported by recv(),
|
# Note: these errors sometimes are reported by recv(),
|
||||||
@ -169,7 +170,8 @@ class DnsProxy(Handler):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
data = sock.recv(4096)
|
data = sock.recv(4096)
|
||||||
except socket.error as e:
|
except socket.error:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
self.socks.remove(sock)
|
self.socks.remove(sock)
|
||||||
del self.peers[sock]
|
del self.peers[sock]
|
||||||
|
|
||||||
@ -204,14 +206,16 @@ class UdpProxy(Handler):
|
|||||||
debug2('UDP: sending to %r port %d\n' % dstip)
|
debug2('UDP: sending to %r port %d\n' % dstip)
|
||||||
try:
|
try:
|
||||||
self.sock.sendto(data, dstip)
|
self.sock.sendto(data, dstip)
|
||||||
except socket.error as e:
|
except socket.error:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
log('UDP send to %r port %d: %s\n' % (dstip[0], dstip[1], e))
|
log('UDP send to %r port %d: %s\n' % (dstip[0], dstip[1], e))
|
||||||
return
|
return
|
||||||
|
|
||||||
def callback(self, sock):
|
def callback(self, sock):
|
||||||
try:
|
try:
|
||||||
data, peer = sock.recvfrom(4096)
|
data, peer = sock.recvfrom(4096)
|
||||||
except socket.error as e:
|
except socket.error:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
log('UDP recv from %r port %d: %s\n' % (peer[0], peer[1], e))
|
log('UDP recv from %r port %d: %s\n' % (peer[0], peer[1], e))
|
||||||
return
|
return
|
||||||
debug2('UDP response: %d bytes\n' % len(data))
|
debug2('UDP response: %d bytes\n' % len(data))
|
||||||
@ -244,26 +248,26 @@ def main(latency_control):
|
|||||||
socket.fromfd(sys.stdout.fileno(),
|
socket.fromfd(sys.stdout.fileno(),
|
||||||
socket.AF_INET, socket.SOCK_STREAM))
|
socket.AF_INET, socket.SOCK_STREAM))
|
||||||
handlers.append(mux)
|
handlers.append(mux)
|
||||||
routepkt = b''
|
routepkt = ''
|
||||||
for r in routes:
|
for r in routes:
|
||||||
routepkt += b'%d,%s,%d\n' % (r[0], r[1].encode("ASCII"), r[2])
|
routepkt += '%d,%s,%d\n' % r
|
||||||
mux.send(0, ssnet.CMD_ROUTES, routepkt)
|
mux.send(0, ssnet.CMD_ROUTES, b(routepkt))
|
||||||
|
|
||||||
hw = Hostwatch()
|
hw = Hostwatch()
|
||||||
hw.leftover = b''
|
hw.leftover = b('')
|
||||||
|
|
||||||
def hostwatch_ready(sock):
|
def hostwatch_ready(sock):
|
||||||
assert(hw.pid)
|
assert(hw.pid)
|
||||||
content = hw.sock.recv(4096)
|
content = hw.sock.recv(4096)
|
||||||
if content:
|
if content:
|
||||||
lines = (hw.leftover + content).split(b'\n')
|
lines = (hw.leftover + content).split(b('\n'))
|
||||||
if lines[-1]:
|
if lines[-1]:
|
||||||
# no terminating newline: entry isn't complete yet!
|
# no terminating newline: entry isn't complete yet!
|
||||||
hw.leftover = lines.pop()
|
hw.leftover = lines.pop()
|
||||||
lines.append(b'')
|
lines.append(b(''))
|
||||||
else:
|
else:
|
||||||
hw.leftover = b''
|
hw.leftover = b('')
|
||||||
mux.send(0, ssnet.CMD_HOST_LIST, b'\n'.join(lines))
|
mux.send(0, ssnet.CMD_HOST_LIST, b('\n').join(lines))
|
||||||
else:
|
else:
|
||||||
raise Fatal('hostwatch process died')
|
raise Fatal('hostwatch process died')
|
||||||
|
|
||||||
@ -275,7 +279,7 @@ def main(latency_control):
|
|||||||
mux.got_host_req = got_host_req
|
mux.got_host_req = got_host_req
|
||||||
|
|
||||||
def new_channel(channel, data):
|
def new_channel(channel, data):
|
||||||
(family, dstip, dstport) = data.split(b',', 2)
|
(family, dstip, dstport) = data.decode("ASCII").split(',', 2)
|
||||||
family = int(family)
|
family = int(family)
|
||||||
dstport = int(dstport)
|
dstport = int(dstport)
|
||||||
outwrap = ssnet.connect_dst(family, dstip, dstport)
|
outwrap = ssnet.connect_dst(family, dstip, dstport)
|
||||||
|
@ -95,10 +95,10 @@ def connect(ssh_cmd, rhostport, python, stderr, options):
|
|||||||
b"\n")
|
b"\n")
|
||||||
|
|
||||||
pyscript = r"""
|
pyscript = r"""
|
||||||
import sys;
|
import sys, os;
|
||||||
verbosity=%d;
|
verbosity=%d;
|
||||||
stdin=getattr(sys.stdin,"buffer",sys.stdin);
|
sys.stdin = os.fdopen(0, "rb");
|
||||||
exec(compile(stdin.read(%d), "assembler.py", "exec"))
|
exec(compile(sys.stdin.read(%d), "assembler.py", "exec"))
|
||||||
""" % (helpers.verbose or 0, len(content))
|
""" % (helpers.verbose or 0, len(content))
|
||||||
pyscript = re.sub(r'\s+', ' ', pyscript.strip())
|
pyscript = re.sub(r'\s+', ' ', pyscript.strip())
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
import sys
|
||||||
import struct
|
import struct
|
||||||
import socket
|
import socket
|
||||||
import errno
|
import errno
|
||||||
import select
|
import select
|
||||||
import os
|
import os
|
||||||
from sshuttle.helpers import log, debug1, debug2, debug3, Fatal
|
from sshuttle.helpers import b, binary_type, log, debug1, debug2, debug3, Fatal
|
||||||
|
|
||||||
MAX_CHANNEL = 65535
|
MAX_CHANNEL = 65535
|
||||||
|
|
||||||
@ -75,7 +76,8 @@ def _fds(l):
|
|||||||
def _nb_clean(func, *args):
|
def _nb_clean(func, *args):
|
||||||
try:
|
try:
|
||||||
return func(*args)
|
return func(*args)
|
||||||
except OSError as e:
|
except OSError:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
if e.errno not in (errno.EWOULDBLOCK, errno.EAGAIN):
|
if e.errno not in (errno.EWOULDBLOCK, errno.EAGAIN):
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
@ -88,7 +90,8 @@ def _try_peername(sock):
|
|||||||
pn = sock.getpeername()
|
pn = sock.getpeername()
|
||||||
if pn:
|
if pn:
|
||||||
return '%s:%s' % (pn[0], pn[1])
|
return '%s:%s' % (pn[0], pn[1])
|
||||||
except socket.error as e:
|
except socket.error:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
if e.args[0] not in (errno.ENOTCONN, errno.ENOTSOCK):
|
if e.args[0] not in (errno.ENOTCONN, errno.ENOTSOCK):
|
||||||
raise
|
raise
|
||||||
return 'unknown'
|
return 'unknown'
|
||||||
@ -144,7 +147,8 @@ class SockWrapper:
|
|||||||
self.rsock.connect(self.connect_to)
|
self.rsock.connect(self.connect_to)
|
||||||
# connected successfully (Linux)
|
# connected successfully (Linux)
|
||||||
self.connect_to = None
|
self.connect_to = None
|
||||||
except socket.error as e:
|
except socket.error:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
debug3('%r: connect result: %s\n' % (self, e))
|
debug3('%r: connect result: %s\n' % (self, e))
|
||||||
if e.args[0] == errno.EINVAL:
|
if e.args[0] == errno.EINVAL:
|
||||||
# this is what happens when you call connect() on a socket
|
# this is what happens when you call connect() on a socket
|
||||||
@ -191,7 +195,8 @@ class SockWrapper:
|
|||||||
self.shut_write = True
|
self.shut_write = True
|
||||||
try:
|
try:
|
||||||
self.wsock.shutdown(SHUT_WR)
|
self.wsock.shutdown(SHUT_WR)
|
||||||
except socket.error as e:
|
except socket.error:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
self.seterr('nowrite: %s' % e)
|
self.seterr('nowrite: %s' % e)
|
||||||
|
|
||||||
def too_full(self):
|
def too_full(self):
|
||||||
@ -203,7 +208,8 @@ class SockWrapper:
|
|||||||
self.wsock.setblocking(False)
|
self.wsock.setblocking(False)
|
||||||
try:
|
try:
|
||||||
return _nb_clean(os.write, self.wsock.fileno(), buf)
|
return _nb_clean(os.write, self.wsock.fileno(), buf)
|
||||||
except OSError as e:
|
except OSError:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
if e.errno == errno.EPIPE:
|
if e.errno == errno.EPIPE:
|
||||||
debug1('%r: uwrite: got EPIPE\n' % self)
|
debug1('%r: uwrite: got EPIPE\n' % self)
|
||||||
self.nowrite()
|
self.nowrite()
|
||||||
@ -225,9 +231,10 @@ class SockWrapper:
|
|||||||
self.rsock.setblocking(False)
|
self.rsock.setblocking(False)
|
||||||
try:
|
try:
|
||||||
return _nb_clean(os.read, self.rsock.fileno(), 65536)
|
return _nb_clean(os.read, self.rsock.fileno(), 65536)
|
||||||
except OSError as e:
|
except OSError:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
self.seterr('uread: %s' % e)
|
self.seterr('uread: %s' % e)
|
||||||
return b'' # unexpected error... we'll call it EOF
|
return b('') # unexpected error... we'll call it EOF
|
||||||
|
|
||||||
def fill(self):
|
def fill(self):
|
||||||
if self.buf:
|
if self.buf:
|
||||||
@ -235,7 +242,7 @@ class SockWrapper:
|
|||||||
rb = self.uread()
|
rb = self.uread()
|
||||||
if rb:
|
if rb:
|
||||||
self.buf.append(rb)
|
self.buf.append(rb)
|
||||||
if rb == b'': # empty string means EOF; None means temporarily empty
|
if rb == b(''): # empty string means EOF; None means temporarily empty
|
||||||
self.noread()
|
self.noread()
|
||||||
|
|
||||||
def copy_to(self, outwrap):
|
def copy_to(self, outwrap):
|
||||||
@ -333,11 +340,11 @@ class Mux(Handler):
|
|||||||
self.channels = {}
|
self.channels = {}
|
||||||
self.chani = 0
|
self.chani = 0
|
||||||
self.want = 0
|
self.want = 0
|
||||||
self.inbuf = b''
|
self.inbuf = b('')
|
||||||
self.outbuf = []
|
self.outbuf = []
|
||||||
self.fullness = 0
|
self.fullness = 0
|
||||||
self.too_full = False
|
self.too_full = False
|
||||||
self.send(0, CMD_PING, b'chicken')
|
self.send(0, CMD_PING, b('chicken'))
|
||||||
|
|
||||||
def next_channel(self):
|
def next_channel(self):
|
||||||
# channel 0 is special, so we never allocate it
|
# channel 0 is special, so we never allocate it
|
||||||
@ -357,7 +364,7 @@ class Mux(Handler):
|
|||||||
def check_fullness(self):
|
def check_fullness(self):
|
||||||
if self.fullness > 32768:
|
if self.fullness > 32768:
|
||||||
if not self.too_full:
|
if not self.too_full:
|
||||||
self.send(0, CMD_PING, b'rttest')
|
self.send(0, CMD_PING, b('rttest'))
|
||||||
self.too_full = True
|
self.too_full = True
|
||||||
# ob = []
|
# ob = []
|
||||||
# for b in self.outbuf:
|
# for b in self.outbuf:
|
||||||
@ -366,9 +373,9 @@ class Mux(Handler):
|
|||||||
# log('outbuf: %d %r\n' % (self.amount_queued(), ob))
|
# log('outbuf: %d %r\n' % (self.amount_queued(), ob))
|
||||||
|
|
||||||
def send(self, channel, cmd, data):
|
def send(self, channel, cmd, data):
|
||||||
assert isinstance(data, bytes)
|
assert isinstance(data, binary_type)
|
||||||
assert len(data) <= 65535
|
assert len(data) <= 65535
|
||||||
p = struct.pack('!ccHHH', b'S', b'S', channel, cmd, len(data)) + data
|
p = struct.pack('!ccHHH', b('S'), b('S'), channel, cmd, len(data)) + data
|
||||||
self.outbuf.append(p)
|
self.outbuf.append(p)
|
||||||
debug2(' > channel=%d cmd=%s len=%d (fullness=%d)\n'
|
debug2(' > channel=%d cmd=%s len=%d (fullness=%d)\n'
|
||||||
% (channel, cmd_to_name.get(cmd, hex(cmd)),
|
% (channel, cmd_to_name.get(cmd, hex(cmd)),
|
||||||
@ -434,14 +441,15 @@ class Mux(Handler):
|
|||||||
def fill(self):
|
def fill(self):
|
||||||
self.rsock.setblocking(False)
|
self.rsock.setblocking(False)
|
||||||
try:
|
try:
|
||||||
b = _nb_clean(os.read, self.rsock.fileno(), 32768)
|
read = _nb_clean(os.read, self.rsock.fileno(), 32768)
|
||||||
except OSError as e:
|
except OSError:
|
||||||
|
_, e = sys.exc_info()[:2]
|
||||||
raise Fatal('other end: %r' % e)
|
raise Fatal('other end: %r' % e)
|
||||||
# log('<<< %r\n' % b)
|
# log('<<< %r\n' % b)
|
||||||
if b == b'': # EOF
|
if read == b(''): # EOF
|
||||||
self.ok = False
|
self.ok = False
|
||||||
if b:
|
if read:
|
||||||
self.inbuf += b
|
self.inbuf += read
|
||||||
|
|
||||||
def handle(self):
|
def handle(self):
|
||||||
self.fill()
|
self.fill()
|
||||||
@ -451,8 +459,8 @@ class Mux(Handler):
|
|||||||
if len(self.inbuf) >= (self.want or HDR_LEN):
|
if len(self.inbuf) >= (self.want or HDR_LEN):
|
||||||
(s1, s2, channel, cmd, datalen) = \
|
(s1, s2, channel, cmd, datalen) = \
|
||||||
struct.unpack('!ccHHH', self.inbuf[:HDR_LEN])
|
struct.unpack('!ccHHH', self.inbuf[:HDR_LEN])
|
||||||
assert(s1 == b'S')
|
assert(s1 == b('S'))
|
||||||
assert(s2 == b'S')
|
assert(s2 == b('S'))
|
||||||
self.want = datalen + HDR_LEN
|
self.want = datalen + HDR_LEN
|
||||||
if self.want and len(self.inbuf) >= self.want:
|
if self.want and len(self.inbuf) >= self.want:
|
||||||
data = self.inbuf[HDR_LEN:self.want]
|
data = self.inbuf[HDR_LEN:self.want]
|
||||||
@ -496,14 +504,14 @@ class MuxWrapper(SockWrapper):
|
|||||||
if not self.shut_read:
|
if not self.shut_read:
|
||||||
debug2('%r: done reading\n' % self)
|
debug2('%r: done reading\n' % self)
|
||||||
self.shut_read = True
|
self.shut_read = True
|
||||||
self.mux.send(self.channel, CMD_TCP_STOP_SENDING, b'')
|
self.mux.send(self.channel, CMD_TCP_STOP_SENDING, b(''))
|
||||||
self.maybe_close()
|
self.maybe_close()
|
||||||
|
|
||||||
def nowrite(self):
|
def nowrite(self):
|
||||||
if not self.shut_write:
|
if not self.shut_write:
|
||||||
debug2('%r: done writing\n' % self)
|
debug2('%r: done writing\n' % self)
|
||||||
self.shut_write = True
|
self.shut_write = True
|
||||||
self.mux.send(self.channel, CMD_TCP_EOF, b'')
|
self.mux.send(self.channel, CMD_TCP_EOF, b(''))
|
||||||
self.maybe_close()
|
self.maybe_close()
|
||||||
|
|
||||||
def maybe_close(self):
|
def maybe_close(self):
|
||||||
@ -526,7 +534,7 @@ class MuxWrapper(SockWrapper):
|
|||||||
|
|
||||||
def uread(self):
|
def uread(self):
|
||||||
if self.shut_read:
|
if self.shut_read:
|
||||||
return b'' # EOF
|
return b('') # EOF
|
||||||
else:
|
else:
|
||||||
return None # no data available right now
|
return None # no data available right now
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@ from mock import patch, Mock, call
|
|||||||
|
|
||||||
|
|
||||||
def test__ipmatch():
|
def test__ipmatch():
|
||||||
assert sshuttle.server._ipmatch(b"1.2.3.4") is not None
|
assert sshuttle.server._ipmatch("1.2.3.4") is not None
|
||||||
assert sshuttle.server._ipmatch(b"::1") is None # ipv6 not supported
|
assert sshuttle.server._ipmatch("::1") is None # ipv6 not supported
|
||||||
assert sshuttle.server._ipmatch(b"42 Example Street, Melbourne") is None
|
assert sshuttle.server._ipmatch("42 Example Street, Melbourne") is None
|
||||||
|
|
||||||
|
|
||||||
def test__ipstr():
|
def test__ipstr():
|
||||||
@ -16,7 +16,7 @@ def test__ipstr():
|
|||||||
|
|
||||||
|
|
||||||
def test__maskbits():
|
def test__maskbits():
|
||||||
netmask = sshuttle.server._ipmatch(b"255.255.255.0")
|
netmask = sshuttle.server._ipmatch("255.255.255.0")
|
||||||
sshuttle.server._maskbits(netmask)
|
sshuttle.server._maskbits(netmask)
|
||||||
|
|
||||||
|
|
||||||
|
4
tox.ini
4
tox.ini
@ -1,12 +1,16 @@
|
|||||||
[tox]
|
[tox]
|
||||||
downloadcache = {toxworkdir}/cache/
|
downloadcache = {toxworkdir}/cache/
|
||||||
envlist =
|
envlist =
|
||||||
|
py26,
|
||||||
py27,
|
py27,
|
||||||
|
py34,
|
||||||
py35,
|
py35,
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
basepython =
|
basepython =
|
||||||
|
py26: python2.6
|
||||||
py27: python2.7
|
py27: python2.7
|
||||||
|
py34: python3.4
|
||||||
py35: python3.5
|
py35: python3.5
|
||||||
commands =
|
commands =
|
||||||
py.test
|
py.test
|
||||||
|
Loading…
Reference in New Issue
Block a user