summaryrefslogtreecommitdiffstats
path: root/client.py
diff options
context:
space:
mode:
Diffstat (limited to 'client.py')
-rw-r--r--client.py73
1 files changed, 48 insertions, 25 deletions
diff --git a/client.py b/client.py
index e584933..0835cbe 100644
--- a/client.py
+++ b/client.py
@@ -1,4 +1,4 @@
-import struct, socket, select, errno, re, signal
+import struct, socket, select, errno, re, signal, time
import compat.ssubprocess as ssubprocess
import helpers, ssnet, ssh, ssyslog
from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper
@@ -6,21 +6,6 @@ from helpers import *
_extra_fd = os.open('/dev/null', os.O_RDONLY)
-def _islocal(ip):
- sock = socket.socket()
- try:
- try:
- sock.bind((ip, 0))
- except socket.error, e:
- if e.args[0] == errno.EADDRNOTAVAIL:
- return False # not a local IP
- else:
- raise
- finally:
- sock.close()
- return True # it's a local IP, or there would have been an error
-
-
def got_signal(signum, frame):
log('exiting on signal %d\n' % signum)
sys.exit(1)
@@ -111,14 +96,15 @@ def original_dst(sock):
class FirewallClient:
- def __init__(self, port, subnets_include, subnets_exclude):
+ def __init__(self, port, subnets_include, subnets_exclude, dnsport):
self.port = port
self.auto_nets = []
self.subnets_include = subnets_include
self.subnets_exclude = subnets_exclude
+ self.dnsport = dnsport
argvbase = ([sys.argv[0]] +
['-v'] * (helpers.verbose or 0) +
- ['--firewall', str(port)])
+ ['--firewall', str(port), str(dnsport)])
if ssyslog._p:
argvbase += ['--syslog']
argv_tries = [
@@ -190,7 +176,7 @@ class FirewallClient:
def _main(listener, fw, ssh_cmd, remotename, python, latency_control,
- seed_hosts, auto_nets,
+ dnslistener, seed_hosts, auto_nets,
syslog, daemon):
handlers = []
if helpers.verbose >= 1:
@@ -282,7 +268,7 @@ def _main(listener, fw, ssh_cmd, remotename, python, latency_control,
dstip = original_dst(sock)
debug1('Accept: %s:%r -> %s:%r.\n' % (srcip[0],srcip[1],
dstip[0],dstip[1]))
- if dstip[1] == listener.getsockname()[1] and _islocal(dstip[0]):
+ if dstip[1] == listener.getsockname()[1] and islocal(dstip[0]):
debug1("-- ignored: that's my address!\n")
sock.close()
return
@@ -292,6 +278,30 @@ def _main(listener, fw, ssh_cmd, remotename, python, latency_control,
handlers.append(Proxy(SockWrapper(sock, sock), outwrap))
handlers.append(Handler([listener], onaccept))
+ dnsreqs = {}
+ def dns_done(chan, data):
+ peer,timeout = dnsreqs.get(chan) or (None,None)
+ debug3('dns_done: channel=%r peer=%r\n' % (chan, peer))
+ if peer:
+ del dnsreqs[chan]
+ debug3('doing sendto %r\n' % (peer,))
+ dnslistener.sendto(data, peer)
+ def ondns():
+ pkt,peer = dnslistener.recvfrom(4096)
+ now = time.time()
+ if pkt:
+ debug1('DNS request from %r: %d bytes\n' % (peer, len(pkt)))
+ chan = mux.next_channel()
+ dnsreqs[chan] = peer,now+30
+ mux.send(chan, ssnet.CMD_DNS_REQ, pkt)
+ mux.channels[chan] = lambda cmd,data: dns_done(chan,data)
+ for chan,(peer,timeout) in dnsreqs.items():
+ if timeout < now:
+ del dnsreqs[chan]
+ debug3('Remaining DNS requests: %d\n' % len(dnsreqs))
+ if dnslistener:
+ handlers.append(Handler([dnslistener], ondns))
+
if seed_hosts != None:
debug1('seed_hosts: %r\n' % seed_hosts)
mux.send(0, ssnet.CMD_HOST_REQ, '\n'.join(seed_hosts))
@@ -307,7 +317,7 @@ def _main(listener, fw, ssh_cmd, remotename, python, latency_control,
mux.callback()
-def main(listenip, ssh_cmd, remotename, python, latency_control,
+def main(listenip, ssh_cmd, remotename, python, latency_control, dns,
seed_hosts, auto_nets,
subnets_include, subnets_exclude, syslog, daemon, pidfile):
if syslog:
@@ -319,8 +329,7 @@ def main(listenip, ssh_cmd, remotename, python, latency_control,
log("%s\n" % e)
return 5
debug1('Starting sshuttle proxy.\n')
- listener = socket.socket()
- listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+
if listenip[1]:
ports = [listenip[1]]
else:
@@ -330,8 +339,13 @@ def main(listenip, ssh_cmd, remotename, python, latency_control,
debug2('Binding:')
for port in ports:
debug2(' %d' % port)
+ listener = socket.socket()
+ listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ dnslistener = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ dnslistener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
listener.bind((listenip[0], port))
+ dnslistener.bind((listenip[0], port))
bound = True
break
except socket.error, e:
@@ -344,11 +358,20 @@ def main(listenip, ssh_cmd, remotename, python, latency_control,
listenip = listener.getsockname()
debug1('Listening on %r.\n' % (listenip,))
- fw = FirewallClient(listenip[1], subnets_include, subnets_exclude)
+ if dns:
+ dnsip = dnslistener.getsockname()
+ debug1('DNS listening on %r.\n' % (dnsip,))
+ dnsport = dnsip[1]
+ else:
+ dnsport = 0
+ dnslistener = None
+ dnslistener.bind((listenip[0], 0))
+
+ fw = FirewallClient(listenip[1], subnets_include, subnets_exclude, dnsport)
try:
return _main(listener, fw, ssh_cmd, remotename,
- python, latency_control,
+ python, latency_control, dnslistener,
seed_hosts, auto_nets, syslog, daemon)
finally:
try: