Skip to content

Commit ba1cf58

Browse files
committed
Add Python 3.5 support.
1 parent dd8e68b commit ba1cf58

File tree

18 files changed

+146
-1429
lines changed

18 files changed

+146
-1429
lines changed

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"GNU General Public License v2 or later (GPLv2+)",
4141
"Operating System :: OS Independent",
4242
"Programming Language :: Python :: 2.7",
43+
"Programming Language :: Python :: 3.5",
4344
"Topic :: System :: Networking",
4445
],
4546
entry_points={

sshuttle/__main__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import sys
22
import re
33
import socket
4-
import helpers
5-
import options
4+
import sshuttle.helpers as helpers
5+
import sshuttle.options as options
66
import sshuttle.client as client
77
import sshuttle.server as server
88
import sshuttle.firewall as firewall
@@ -145,7 +145,7 @@ def parse_list(list):
145145
if opt.daemon:
146146
opt.syslog = 1
147147
if opt.wrap:
148-
import ssnet
148+
import sshuttle.ssnet as ssnet
149149
ssnet.MAX_CHANNEL = int(opt.wrap)
150150
helpers.verbose = opt.verbose
151151

@@ -230,7 +230,7 @@ def parse_list(list):
230230
log('Abnormal exit code detected, failing...' % return_code)
231231
sys.exit(return_code)
232232

233-
except Fatal, e:
233+
except Fatal as e:
234234
log('fatal: %s\n' % e)
235235
sys.exit(99)
236236
except KeyboardInterrupt:

sshuttle/assembler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
setattr(sys.modules[parent], parent_name, module)
1919

2020
code = compile(content, name, "exec")
21-
exec code in module.__dict__
21+
exec(code, module.__dict__)
2222
sys.modules[name] = module
2323
else:
2424
break

sshuttle/client.py

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
import re
44
import signal
55
import time
6-
import sshuttle.compat.ssubprocess as ssubprocess
7-
import helpers
6+
import subprocess as ssubprocess
7+
import sshuttle.helpers as helpers
88
import os
99
import sshuttle.ssnet as ssnet
1010
import sshuttle.ssh as ssh
11-
import ssyslog
11+
import sshuttle.ssyslog as ssyslog
1212
import sys
1313
from sshuttle.ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper
1414
from sshuttle.helpers import log, debug1, debug2, debug3, Fatal, islocal, \
@@ -124,7 +124,7 @@ def check_daemon(pidfile):
124124
_pidname = os.path.abspath(pidfile)
125125
try:
126126
oldpid = open(_pidname).read(1024)
127-
except IOError, e:
127+
except IOError as e:
128128
if e.errno == errno.ENOENT:
129129
return # no pidfile, ok
130130
else:
@@ -138,7 +138,7 @@ def check_daemon(pidfile):
138138
return # invalid pidfile, ok
139139
try:
140140
os.kill(oldpid, 0)
141-
except OSError, e:
141+
except OSError as e:
142142
if e.errno == errno.ESRCH:
143143
os.unlink(_pidname)
144144
return # outdated pidfile, ok
@@ -157,7 +157,7 @@ def daemonize():
157157
if os.fork():
158158
os._exit(0)
159159

160-
outfd = os.open(_pidname, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0666)
160+
outfd = os.open(_pidname, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o666)
161161
try:
162162
os.write(outfd, '%d\n' % os.getpid())
163163
finally:
@@ -179,7 +179,7 @@ def daemonize():
179179
def daemon_cleanup():
180180
try:
181181
os.unlink(_pidname)
182-
except OSError, e:
182+
except OSError as e:
183183
if e.errno == errno.ENOENT:
184184
pass
185185
else:
@@ -215,7 +215,7 @@ def original_dst(sock):
215215
assert(socket.htons(proto) == socket.AF_INET)
216216
ip = '%d.%d.%d.%d' % (a, b, c, d)
217217
return (ip, port)
218-
except socket.error, e:
218+
except socket.error as e:
219219
if e.args[0] == errno.ENOPROTOOPT:
220220
return sock.getsockname()
221221
raise
@@ -251,7 +251,7 @@ def listen(self, backlog):
251251
if self.v4:
252252
try:
253253
self.v4.listen(backlog)
254-
except socket.error, e:
254+
except socket.error as e:
255255
# on some systems v4 bind will fail if the v6 suceeded,
256256
# in this case the v6 socket will receive v4 too.
257257
if e.errno == errno.EADDRINUSE and self.v6:
@@ -321,17 +321,22 @@ def setup():
321321
self.p = ssubprocess.Popen(argv, stdout=s1, preexec_fn=setup)
322322
e = None
323323
break
324-
except OSError, e:
324+
except OSError as e:
325325
pass
326326
self.argv = argv
327327
s1.close()
328-
self.pfile = s2.makefile('wb+')
328+
if sys.version_info < (3, 0):
329+
# python 2.7
330+
self.pfile = s2.makefile('wb+')
331+
else:
332+
# python 3.5
333+
self.pfile = s2.makefile('rwb')
329334
if e:
330335
log('Spawning firewall manager: %r\n' % self.argv)
331336
raise Fatal(e)
332337
line = self.pfile.readline()
333338
self.check()
334-
if line[0:5] != 'READY':
339+
if line[0:5] != b'READY':
335340
raise Fatal('%r expected READY, got %r' % (self.argv, line))
336341
self.method = line[6:-1]
337342

@@ -341,22 +346,26 @@ def check(self):
341346
raise Fatal('%r returned %d' % (self.argv, rv))
342347

343348
def start(self):
344-
self.pfile.write('ROUTES\n')
345-
for (family, ip, width) in self.subnets_include + self.auto_nets:
346-
self.pfile.write('%d,%d,0,%s\n' % (family, width, ip))
347-
for (family, ip, width) in self.subnets_exclude:
348-
self.pfile.write('%d,%d,1,%s\n' % (family, width, ip))
349-
self.pfile.write('GO\n')
349+
self.pfile.write(b'ROUTES\n')
350+
try:
351+
for (family, ip, width) in self.subnets_include + self.auto_nets:
352+
self.pfile.write(b'%d,%d,0,%s\n' % (family, width, ip.encode("ASCII")))
353+
for (family, ip, width) in self.subnets_exclude:
354+
self.pfile.write(b'%d,%d,1,%s\n' % (family, width, ip.encode("ASCII")))
355+
except Exception as e:
356+
debug1("exception occured %r" % e)
357+
raise
358+
self.pfile.write(b'GO\n')
350359
self.pfile.flush()
351360
line = self.pfile.readline()
352361
self.check()
353-
if line != 'STARTED\n':
362+
if line != b'STARTED\n':
354363
raise Fatal('%r expected STARTED, got %r' % (self.argv, line))
355364

356365
def sethostip(self, hostname, ip):
357366
assert(not re.search(r'[^-\w]', hostname))
358367
assert(not re.search(r'[^0-9.]', ip))
359-
self.pfile.write('HOST %s,%s\n' % (hostname, ip))
368+
self.pfile.write(b'HOST %s,%s\n' % (hostname, ip))
360369
self.pfile.flush()
361370

362371
def done(self):
@@ -390,7 +399,7 @@ def onaccept_tcp(listener, method, mux, handlers):
390399
global _extra_fd
391400
try:
392401
sock, srcip = listener.accept()
393-
except socket.error, e:
402+
except socket.error as e:
394403
if e.args[0] in [errno.EMFILE, errno.ENFILE]:
395404
debug1('Rejected incoming connection: too many open files!\n')
396405
# free up an fd so we can eat the connection
@@ -403,9 +412,9 @@ def onaccept_tcp(listener, method, mux, handlers):
403412
return
404413
else:
405414
raise
406-
if method == "tproxy":
415+
if method == b"tproxy":
407416
dstip = sock.getsockname()
408-
elif method == "pf":
417+
elif method == b"pf":
409418
dstip = pf_dst(sock)
410419
else:
411420
dstip = original_dst(sock)
@@ -420,8 +429,8 @@ def onaccept_tcp(listener, method, mux, handlers):
420429
log('warning: too many open channels. Discarded connection.\n')
421430
sock.close()
422431
return
423-
mux.send(chan, ssnet.CMD_TCP_CONNECT, '%d,%s,%s' %
424-
(sock.family, dstip[0], dstip[1]))
432+
mux.send(chan, ssnet.CMD_TCP_CONNECT, b'%d,%s,%d' %
433+
(sock.family, dstip[0].encode("ASCII"), dstip[1]))
425434
outwrap = MuxWrapper(mux, chan)
426435
handlers.append(Proxy(SockWrapper(sock, sock), outwrap))
427436
expire_connections(time.time(), mux)
@@ -439,7 +448,7 @@ def udp_done(chan, data, method, family, dstip):
439448
sender.bind(srcip)
440449
sender.sendto(data, dstip)
441450
sender.close()
442-
except socket.error, e:
451+
except socket.error as e:
443452
debug1('-- ignored socket error sending UDP data: %r\n' % e)
444453

445454

@@ -471,7 +480,7 @@ def dns_done(chan, data, method, sock, srcip, dstip, mux):
471480
debug3('dns_done: channel=%d src=%r dst=%r\n' % (chan, srcip, dstip))
472481
del mux.channels[chan]
473482
del dnsreqs[chan]
474-
if method == "tproxy":
483+
if method == b"tproxy":
475484
debug3('doing send from %r to %r\n' % (srcip, dstip,))
476485
sender = socket.socket(sock.family, socket.SOCK_DGRAM)
477486
sender.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
@@ -487,7 +496,7 @@ def dns_done(chan, data, method, sock, srcip, dstip, mux):
487496
def ondns(listener, method, mux, handlers):
488497
now = time.time()
489498
srcip, dstip, data = recv_udp(listener, 4096)
490-
if method == "tproxy" and not dstip:
499+
if method == b"tproxy" and not dstip:
491500
debug1(
492501
"-- ignored UDP from %r: "
493502
"couldn't determine destination IP address\n" % (srcip,))
@@ -517,25 +526,25 @@ def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
517526
ssh_cmd, remotename, python,
518527
stderr=ssyslog._p and ssyslog._p.stdin,
519528
options=dict(latency_control=latency_control, method=method))
520-
except socket.error, e:
529+
except socket.error as e:
521530
if e.args[0] == errno.EPIPE:
522531
raise Fatal("failed to establish ssh session (1)")
523532
else:
524533
raise
525534
mux = Mux(serversock, serversock)
526535
handlers.append(mux)
527536

528-
expected = 'SSHUTTLE0001'
537+
expected = b'SSHUTTLE0001'
529538

530539
try:
531540
v = 'x'
532-
while v and v != '\0':
541+
while v and v != b'\0':
533542
v = serversock.recv(1)
534543
v = 'x'
535-
while v and v != '\0':
544+
while v and v != b'\0':
536545
v = serversock.recv(1)
537546
initstring = serversock.recv(len(expected))
538-
except socket.error, e:
547+
except socket.error as e:
539548
if e.args[0] == errno.ECONNRESET:
540549
raise Fatal("failed to establish ssh session (2)")
541550
else:
@@ -549,7 +558,7 @@ def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
549558
raise Fatal('expected server init string %r; got %r'
550559
% (expected, initstring))
551560
debug1('connected.\n')
552-
print 'Connected.'
561+
print('Connected.')
553562
sys.stdout.flush()
554563
if daemon:
555564
daemonize()
@@ -616,15 +625,15 @@ def main(listenip_v6, listenip_v4,
616625
if daemon:
617626
try:
618627
check_daemon(pidfile)
619-
except Fatal, e:
628+
except Fatal as e:
620629
log("%s\n" % e)
621630
return 5
622631
debug1('Starting sshuttle proxy.\n')
623632

624633
if recvmsg is not None:
625634
debug1("recvmsg %s support enabled.\n" % recvmsg)
626635

627-
if method == "tproxy":
636+
if method == b"tproxy":
628637
if recvmsg is not None:
629638
debug1("tproxy UDP support enabled.\n")
630639
udp = True
@@ -643,7 +652,7 @@ def main(listenip_v6, listenip_v4,
643652
ports = [0, ]
644653
else:
645654
# if at least one port missing, we have to search
646-
ports = xrange(12300, 9000, -1)
655+
ports = range(12300, 9000, -1)
647656

648657
# search for free ports and try to bind
649658
last_e = None
@@ -688,7 +697,7 @@ def main(listenip_v6, listenip_v4,
688697
udp_listener.bind(lv6, lv4)
689698
bound = True
690699
break
691-
except socket.error, e:
700+
except socket.error as e:
692701
if e.errno == errno.EADDRINUSE:
693702
last_e = e
694703
else:
@@ -708,7 +717,7 @@ def main(listenip_v6, listenip_v4,
708717
nslist += resolvconf_nameservers()
709718
# search for spare port for DNS
710719
debug2('Binding DNS:')
711-
ports = xrange(12300, 9000, -1)
720+
ports = range(12300, 9000, -1)
712721
for port in ports:
713722
debug2(' %d' % port)
714723
dns_listener = MultiListener(socket.SOCK_DGRAM)
@@ -731,7 +740,7 @@ def main(listenip_v6, listenip_v4,
731740
dns_listener.bind(lv6, lv4)
732741
bound = True
733742
break
734-
except socket.error, e:
743+
except socket.error as e:
735744
if e.errno == errno.EADDRINUSE:
736745
last_e = e
737746
else:
@@ -750,7 +759,7 @@ def main(listenip_v6, listenip_v4,
750759
subnets_exclude, dnsport_v6, dnsport_v4, nslist,
751760
method, udp)
752761

753-
if fw.method == "tproxy":
762+
if fw.method == b"tproxy":
754763
tcp_listener.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1)
755764
if udp_listener:
756765
udp_listener.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1)
@@ -767,7 +776,7 @@ def main(listenip_v6, listenip_v4,
767776
if dns_listener.v6 is not None:
768777
dns_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVORIGDSTADDR, 1)
769778

770-
if fw.method == "pf":
779+
if fw.method == b"pf":
771780
global pf_command_file
772781
pf_command_file = fw.pfile
773782

sshuttle/compat/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)