2010-05-02 03:50:43 +02:00
|
|
|
import struct, socket, select, subprocess, errno
|
2010-05-02 08:14:20 +02:00
|
|
|
import helpers, ssnet, ssh
|
2010-05-02 05:14:42 +02:00
|
|
|
from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper
|
2010-05-02 00:03:45 +02:00
|
|
|
from helpers import *
|
|
|
|
|
|
|
|
def original_dst(sock):
|
|
|
|
SO_ORIGINAL_DST = 80
|
|
|
|
SOCKADDR_MIN = 16
|
2010-05-02 02:26:16 +02:00
|
|
|
sockaddr_in = sock.getsockopt(socket.SOL_IP, SO_ORIGINAL_DST, SOCKADDR_MIN)
|
2010-05-02 05:14:42 +02:00
|
|
|
(proto, port, a,b,c,d) = struct.unpack('!HHBBBB', sockaddr_in[:8])
|
2010-05-02 02:26:16 +02:00
|
|
|
assert(socket.htons(proto) == socket.AF_INET)
|
2010-05-02 00:03:45 +02:00
|
|
|
ip = '%d.%d.%d.%d' % (a,b,c,d)
|
|
|
|
return (ip,port)
|
|
|
|
|
|
|
|
|
2010-05-03 01:29:03 +02:00
|
|
|
class IPTables:
|
|
|
|
def __init__(self, port, subnets):
|
|
|
|
self.port = port
|
|
|
|
self.subnets = subnets
|
|
|
|
subnets_str = ['%s/%d' % (ip,width) for ip,width in subnets]
|
|
|
|
self.argv = (['sudo', sys.argv[0]] +
|
|
|
|
['-v'] * (helpers.verbose or 0) +
|
|
|
|
['--iptables', str(port)] + subnets_str)
|
|
|
|
self.p = subprocess.Popen(self.argv,
|
|
|
|
stdin=subprocess.PIPE,
|
|
|
|
stdout=subprocess.PIPE)
|
|
|
|
line = self.p.stdout.readline()
|
|
|
|
self.check()
|
|
|
|
if line != 'READY\n':
|
|
|
|
raise Fatal('%r expected READY, got %r' % (self.argv, line))
|
|
|
|
|
|
|
|
def check(self):
|
|
|
|
rv = self.p.poll()
|
|
|
|
if rv:
|
|
|
|
raise Fatal('%r returned %d' % (self.argv, rv))
|
|
|
|
|
|
|
|
def start(self):
|
|
|
|
self.p.stdin.write('GO\n')
|
|
|
|
self.p.stdin.flush()
|
|
|
|
|
|
|
|
def done(self):
|
|
|
|
self.p.stdin.close()
|
|
|
|
self.p.stdout.close()
|
|
|
|
rv = self.p.wait()
|
|
|
|
if rv:
|
|
|
|
raise Fatal('cleanup: %r returned %d' % (self.argv, rv))
|
2010-05-02 03:14:19 +02:00
|
|
|
|
|
|
|
|
2010-05-03 01:29:03 +02:00
|
|
|
def _main(listener, ipt, use_server, remotename):
|
2010-05-02 02:03:50 +02:00
|
|
|
handlers = []
|
2010-05-02 05:14:42 +02:00
|
|
|
if use_server:
|
2010-05-02 08:23:42 +02:00
|
|
|
if helpers.verbose >= 1:
|
|
|
|
helpers.logprefix = 'c : '
|
|
|
|
else:
|
|
|
|
helpers.logprefix = 'client: '
|
2010-05-02 05:14:42 +02:00
|
|
|
(serverproc, serversock) = ssh.connect(remotename)
|
2010-05-02 05:32:30 +02:00
|
|
|
mux = Mux(serversock, serversock)
|
2010-05-02 05:14:42 +02:00
|
|
|
handlers.append(mux)
|
|
|
|
|
2010-05-02 06:52:06 +02:00
|
|
|
expected = 'SSHUTTLE0001'
|
|
|
|
initstring = serversock.recv(len(expected))
|
2010-05-02 08:23:42 +02:00
|
|
|
|
2010-05-02 06:52:06 +02:00
|
|
|
rv = serverproc.poll()
|
|
|
|
if rv:
|
2010-05-02 08:23:42 +02:00
|
|
|
raise Fatal('server died with error code %d' % rv)
|
2010-05-02 06:52:06 +02:00
|
|
|
|
2010-05-02 08:23:42 +02:00
|
|
|
if initstring != expected:
|
|
|
|
raise Fatal('expected server init string %r; got %r'
|
|
|
|
% (expected, initstring))
|
|
|
|
|
2010-05-02 05:14:42 +02:00
|
|
|
# we definitely want to do this *after* starting ssh, or we might end
|
|
|
|
# up intercepting the ssh connection!
|
2010-05-03 01:29:03 +02:00
|
|
|
ipt.start()
|
2010-05-02 05:14:42 +02:00
|
|
|
|
2010-05-02 02:03:50 +02:00
|
|
|
def onaccept():
|
|
|
|
sock,srcip = listener.accept()
|
|
|
|
dstip = original_dst(sock)
|
2010-05-02 08:14:20 +02:00
|
|
|
debug1('Accept: %r:%r -> %r:%r.\n' % (srcip[0],srcip[1],
|
2010-05-02 07:18:55 +02:00
|
|
|
dstip[0],dstip[1]))
|
2010-05-02 02:20:54 +02:00
|
|
|
if dstip == sock.getsockname():
|
2010-05-02 08:14:20 +02:00
|
|
|
debug1("-- ignored: that's my address!\n")
|
2010-05-02 02:20:54 +02:00
|
|
|
sock.close()
|
|
|
|
return
|
2010-05-02 05:14:42 +02:00
|
|
|
if use_server:
|
|
|
|
chan = mux.next_channel()
|
|
|
|
mux.send(chan, ssnet.CMD_CONNECT, '%s,%s' % dstip)
|
|
|
|
outwrap = MuxWrapper(mux, chan)
|
|
|
|
else:
|
2010-05-02 06:52:06 +02:00
|
|
|
outwrap = ssnet.connect_dst(dstip[0], dstip[1])
|
2010-05-02 05:32:30 +02:00
|
|
|
handlers.append(Proxy(SockWrapper(sock, sock), outwrap))
|
2010-05-02 02:03:50 +02:00
|
|
|
handlers.append(Handler([listener], onaccept))
|
|
|
|
|
|
|
|
while 1:
|
2010-05-02 06:52:06 +02:00
|
|
|
if use_server:
|
|
|
|
rv = serverproc.poll()
|
|
|
|
if rv:
|
2010-05-02 08:23:42 +02:00
|
|
|
raise Fatal('server died with error code %d' % rv)
|
2010-05-02 06:52:06 +02:00
|
|
|
|
2010-05-02 02:03:50 +02:00
|
|
|
r = set()
|
|
|
|
w = set()
|
|
|
|
x = set()
|
|
|
|
handlers = filter(lambda s: s.ok, handlers)
|
|
|
|
for s in handlers:
|
|
|
|
s.pre_select(r,w,x)
|
2010-05-02 08:14:20 +02:00
|
|
|
debug2('Waiting: %d[%d,%d,%d]...\n'
|
2010-05-02 02:03:50 +02:00
|
|
|
% (len(handlers), len(r), len(w), len(x)))
|
|
|
|
(r,w,x) = select.select(r,w,x)
|
2010-05-02 07:18:55 +02:00
|
|
|
#log('r=%r w=%r x=%r\n' % (r,w,x))
|
2010-05-02 02:03:50 +02:00
|
|
|
ready = set(r) | set(w) | set(x)
|
|
|
|
for s in handlers:
|
|
|
|
if s.socks & ready:
|
|
|
|
s.callback()
|
2010-05-02 11:06:51 +02:00
|
|
|
mux.callback()
|
|
|
|
mux.check_fullness()
|
2010-05-02 03:30:59 +02:00
|
|
|
|
|
|
|
|
2010-05-02 05:14:42 +02:00
|
|
|
def main(listenip, use_server, remotename, subnets):
|
2010-05-02 08:14:20 +02:00
|
|
|
debug1('Starting sshuttle proxy.\n')
|
2010-05-02 03:30:59 +02:00
|
|
|
listener = socket.socket()
|
|
|
|
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
2010-05-02 03:50:43 +02:00
|
|
|
if listenip[1]:
|
|
|
|
ports = [listenip[1]]
|
|
|
|
else:
|
|
|
|
ports = xrange(12300,65536)
|
|
|
|
last_e = None
|
|
|
|
bound = False
|
2010-05-02 08:14:20 +02:00
|
|
|
debug2('Binding:')
|
2010-05-02 03:50:43 +02:00
|
|
|
for port in ports:
|
2010-05-02 08:14:20 +02:00
|
|
|
debug2(' %d' % port)
|
2010-05-02 03:50:43 +02:00
|
|
|
try:
|
|
|
|
listener.bind((listenip[0], port))
|
|
|
|
bound = True
|
|
|
|
break
|
|
|
|
except socket.error, e:
|
|
|
|
last_e = e
|
2010-05-02 08:14:20 +02:00
|
|
|
debug2('\n')
|
2010-05-02 03:50:43 +02:00
|
|
|
if not bound:
|
|
|
|
assert(last_e)
|
|
|
|
raise last_e
|
2010-05-02 03:30:59 +02:00
|
|
|
listener.listen(10)
|
2010-05-02 03:50:43 +02:00
|
|
|
listenip = listener.getsockname()
|
2010-05-02 08:14:20 +02:00
|
|
|
debug1('Listening on %r.\n' % (listenip,))
|
2010-05-02 03:30:59 +02:00
|
|
|
|
2010-05-03 01:29:03 +02:00
|
|
|
ipt = IPTables(listenip[1], subnets)
|
|
|
|
|
2010-05-02 03:30:59 +02:00
|
|
|
try:
|
2010-05-03 01:29:03 +02:00
|
|
|
return _main(listener, ipt, use_server, remotename)
|
2010-05-02 03:30:59 +02:00
|
|
|
finally:
|
2010-05-03 01:29:03 +02:00
|
|
|
ipt.done()
|