mirror of
https://github.com/sshuttle/sshuttle.git
synced 2024-11-08 09:04:29 +01:00
9f514d7a15
Now if we aren't given an explicit port, we always initiate the port search at 12300 and count upward looking for an available port. Normally the kernel will assign us a random port, but that's not ideal in our case because we'd like to use the same port numbers whenever possible; that avoids piling up crap inside iptables in the (hopefully unlikely) event that we die without cleaning up correctly.
90 lines
2.6 KiB
Python
90 lines
2.6 KiB
Python
import struct, socket, select, subprocess, errno
|
|
from ssnet import SockWrapper, Handler, Proxy
|
|
from helpers import *
|
|
|
|
|
|
def original_dst(sock):
|
|
SO_ORIGINAL_DST = 80
|
|
SOCKADDR_MIN = 16
|
|
sockaddr_in = sock.getsockopt(socket.SOL_IP, SO_ORIGINAL_DST, SOCKADDR_MIN)
|
|
(proto, port, a,b,c,d) = struct.unpack('!hhBBBB', sockaddr_in[:8])
|
|
assert(socket.htons(proto) == socket.AF_INET)
|
|
ip = '%d.%d.%d.%d' % (a,b,c,d)
|
|
return (ip,port)
|
|
|
|
|
|
def iptables_setup(port, subnets):
|
|
subnets_str = ['%s/%d' % (ip,width) for ip,width in subnets]
|
|
argv = ['sudo', sys.argv[0], '--iptables', str(port)] + subnets_str
|
|
rv = subprocess.call(argv)
|
|
if rv != 0:
|
|
raise Exception('%r returned %d' % (argv, rv))
|
|
|
|
|
|
def _main(listener, remotename, subnets):
|
|
handlers = []
|
|
def onaccept():
|
|
sock,srcip = listener.accept()
|
|
dstip = original_dst(sock)
|
|
log('Incoming connection from %r to %r.\n' % (srcip,dstip))
|
|
if dstip == sock.getsockname():
|
|
log("-- ignored: that's my address!\n")
|
|
sock.close()
|
|
return
|
|
outsock = socket.socket()
|
|
outsock.setsockopt(socket.SOL_IP, socket.IP_TTL, 42)
|
|
outsock.connect(dstip)
|
|
handlers.append(Proxy(SockWrapper(sock), SockWrapper(outsock)))
|
|
handlers.append(Handler([listener], onaccept))
|
|
|
|
while 1:
|
|
r = set()
|
|
w = set()
|
|
x = set()
|
|
handlers = filter(lambda s: s.ok, handlers)
|
|
for s in handlers:
|
|
s.pre_select(r,w,x)
|
|
log('\nWaiting: %d[%d,%d,%d]...\n'
|
|
% (len(handlers), len(r), len(w), len(x)))
|
|
(r,w,x) = select.select(r,w,x)
|
|
log('r=%r w=%r x=%r\n' % (r,w,x))
|
|
ready = set(r) | set(w) | set(x)
|
|
for s in handlers:
|
|
if s.socks & ready:
|
|
s.callback()
|
|
|
|
|
|
def main(listenip, remotename, subnets):
|
|
log('Starting sshuttle proxy.\n')
|
|
listener = socket.socket()
|
|
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
if listenip[1]:
|
|
ports = [listenip[1]]
|
|
else:
|
|
ports = xrange(12300,65536)
|
|
last_e = None
|
|
bound = False
|
|
log('Binding:')
|
|
for port in ports:
|
|
log(' %d' % port)
|
|
try:
|
|
listener.bind((listenip[0], port))
|
|
bound = True
|
|
break
|
|
except socket.error, e:
|
|
last_e = e
|
|
log('\n')
|
|
if not bound:
|
|
assert(last_e)
|
|
raise last_e
|
|
listener.listen(10)
|
|
listenip = listener.getsockname()
|
|
log('Listening on %r.\n' % (listenip,))
|
|
|
|
iptables_setup(listenip[1], subnets)
|
|
|
|
try:
|
|
return _main(listener, remotename, subnets)
|
|
finally:
|
|
iptables_setup(listenip[1], [])
|