2011-01-26 11:34:12 +01:00
|
|
|
import struct, socket, select, errno, re, signal, time
|
2010-10-01 21:06:56 +02:00
|
|
|
import compat.ssubprocess as ssubprocess
|
2011-01-01 09:06:04 +01:00
|
|
|
import helpers, ssnet, ssh, ssyslog
|
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 *
|
|
|
|
|
2011-01-01 06:32:51 +01:00
|
|
|
_extra_fd = os.open('/dev/null', os.O_RDONLY)
|
2010-10-02 02:36:09 +02:00
|
|
|
|
2011-01-01 07:54:07 +01:00
|
|
|
def got_signal(signum, frame):
|
|
|
|
log('exiting on signal %d\n' % signum)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
_pidname = None
|
|
|
|
def check_daemon(pidfile):
|
|
|
|
global _pidname
|
|
|
|
_pidname = os.path.abspath(pidfile)
|
|
|
|
try:
|
|
|
|
oldpid = open(_pidname).read(1024)
|
|
|
|
except IOError, e:
|
|
|
|
if e.errno == errno.ENOENT:
|
|
|
|
return # no pidfile, ok
|
|
|
|
else:
|
|
|
|
raise Fatal("can't read %s: %s" % (_pidname, e))
|
|
|
|
if not oldpid:
|
|
|
|
os.unlink(_pidname)
|
|
|
|
return # invalid pidfile, ok
|
|
|
|
oldpid = int(oldpid.strip() or 0)
|
|
|
|
if oldpid <= 0:
|
|
|
|
os.unlink(_pidname)
|
|
|
|
return # invalid pidfile, ok
|
|
|
|
try:
|
|
|
|
os.kill(oldpid, 0)
|
|
|
|
except OSError, e:
|
|
|
|
if e.errno == errno.ESRCH:
|
|
|
|
os.unlink(_pidname)
|
|
|
|
return # outdated pidfile, ok
|
|
|
|
elif e.errno == errno.EPERM:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
raise
|
|
|
|
raise Fatal("%s: sshuttle is already running (pid=%d)"
|
|
|
|
% (_pidname, oldpid))
|
|
|
|
|
|
|
|
|
|
|
|
def daemonize():
|
|
|
|
if os.fork():
|
|
|
|
os._exit(0)
|
|
|
|
os.setsid()
|
|
|
|
if os.fork():
|
|
|
|
os._exit(0)
|
|
|
|
|
|
|
|
outfd = os.open(_pidname, os.O_WRONLY|os.O_CREAT|os.O_EXCL, 0666)
|
|
|
|
try:
|
|
|
|
os.write(outfd, '%d\n' % os.getpid())
|
|
|
|
finally:
|
|
|
|
os.close(outfd)
|
|
|
|
os.chdir("/")
|
|
|
|
|
|
|
|
# Normal exit when killed, or try/finally won't work and the pidfile won't
|
|
|
|
# be deleted.
|
|
|
|
signal.signal(signal.SIGTERM, got_signal)
|
|
|
|
|
|
|
|
si = open('/dev/null', 'r+')
|
|
|
|
os.dup2(si.fileno(), 0)
|
2011-01-01 09:06:04 +01:00
|
|
|
os.dup2(si.fileno(), 1)
|
2011-01-01 07:54:07 +01:00
|
|
|
si.close()
|
|
|
|
|
2011-01-01 09:06:04 +01:00
|
|
|
ssyslog.stderr_to_syslog()
|
2011-01-01 07:54:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
def daemon_cleanup():
|
|
|
|
try:
|
|
|
|
os.unlink(_pidname)
|
|
|
|
except OSError, e:
|
|
|
|
if e.errno == errno.ENOENT:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
raise
|
|
|
|
|
2010-10-02 02:36:09 +02:00
|
|
|
|
2010-05-02 00:03:45 +02:00
|
|
|
def original_dst(sock):
|
2010-05-05 00:24:43 +02:00
|
|
|
try:
|
|
|
|
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)
|
|
|
|
except socket.error, e:
|
|
|
|
if e.args[0] == errno.ENOPROTOOPT:
|
|
|
|
return sock.getsockname()
|
|
|
|
raise
|
2010-05-02 00:03:45 +02:00
|
|
|
|
|
|
|
|
2010-05-05 04:05:49 +02:00
|
|
|
class FirewallClient:
|
2011-01-26 11:00:19 +01:00
|
|
|
def __init__(self, port, subnets_include, subnets_exclude, dnsport):
|
2010-05-03 01:29:03 +02:00
|
|
|
self.port = port
|
2010-05-08 02:02:04 +02:00
|
|
|
self.auto_nets = []
|
2010-07-15 20:07:01 +02:00
|
|
|
self.subnets_include = subnets_include
|
|
|
|
self.subnets_exclude = subnets_exclude
|
2011-01-26 11:00:19 +01:00
|
|
|
self.dnsport = dnsport
|
2010-05-03 02:54:10 +02:00
|
|
|
argvbase = ([sys.argv[0]] +
|
|
|
|
['-v'] * (helpers.verbose or 0) +
|
2011-01-26 11:00:19 +01:00
|
|
|
['--firewall', str(port), str(dnsport)])
|
2011-01-01 09:06:04 +01:00
|
|
|
if ssyslog._p:
|
|
|
|
argvbase += ['--syslog']
|
2010-05-03 02:54:10 +02:00
|
|
|
argv_tries = [
|
2010-11-09 08:27:02 +01:00
|
|
|
['sudo', '-p', '[local sudo] Password: '] + argvbase,
|
2010-05-03 02:54:10 +02:00
|
|
|
['su', '-c', ' '.join(argvbase)],
|
|
|
|
argvbase
|
|
|
|
]
|
|
|
|
|
|
|
|
# we can't use stdin/stdout=subprocess.PIPE here, as we normally would,
|
|
|
|
# because stupid Linux 'su' requires that stdin be attached to a tty.
|
|
|
|
# Instead, attach a *bidirectional* socket to its stdout, and use
|
|
|
|
# that for talking in both directions.
|
|
|
|
(s1,s2) = socket.socketpair()
|
|
|
|
def setup():
|
|
|
|
# run in the child process
|
|
|
|
s2.close()
|
|
|
|
e = None
|
2010-11-09 08:27:02 +01:00
|
|
|
if os.getuid() == 0:
|
|
|
|
argv_tries = argv_tries[-1:] # last entry only
|
2010-05-03 02:54:10 +02:00
|
|
|
for argv in argv_tries:
|
|
|
|
try:
|
2010-11-09 08:27:02 +01:00
|
|
|
if argv[0] == 'su':
|
|
|
|
sys.stderr.write('[local su] ')
|
2010-10-01 21:06:56 +02:00
|
|
|
self.p = ssubprocess.Popen(argv, stdout=s1, preexec_fn=setup)
|
2010-05-03 02:54:10 +02:00
|
|
|
e = None
|
|
|
|
break
|
|
|
|
except OSError, e:
|
|
|
|
pass
|
|
|
|
self.argv = argv
|
|
|
|
s1.close()
|
|
|
|
self.pfile = s2.makefile('wb+')
|
|
|
|
if e:
|
2010-05-05 04:05:49 +02:00
|
|
|
log('Spawning firewall manager: %r\n' % self.argv)
|
2010-05-03 02:54:10 +02:00
|
|
|
raise Fatal(e)
|
|
|
|
line = self.pfile.readline()
|
2010-05-03 01:29:03 +02:00
|
|
|
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):
|
2010-05-08 02:02:04 +02:00
|
|
|
self.pfile.write('ROUTES\n')
|
2010-07-15 20:07:01 +02:00
|
|
|
for (ip,width) in self.subnets_include+self.auto_nets:
|
|
|
|
self.pfile.write('%d,0,%s\n' % (width, ip))
|
|
|
|
for (ip,width) in self.subnets_exclude:
|
|
|
|
self.pfile.write('%d,1,%s\n' % (width, ip))
|
2010-05-03 02:54:10 +02:00
|
|
|
self.pfile.write('GO\n')
|
|
|
|
self.pfile.flush()
|
|
|
|
line = self.pfile.readline()
|
|
|
|
self.check()
|
|
|
|
if line != 'STARTED\n':
|
|
|
|
raise Fatal('%r expected STARTED, got %r' % (self.argv, line))
|
2010-05-03 01:29:03 +02:00
|
|
|
|
Added new --auto-hosts and --seed-hosts options to the client.
Now if you use --auto-hosts (-H), the client will ask the server to spawn a
hostwatcher to add names. That, in turn, will send names back to the
server, which sends them back to the client, which sends them to the
firewall subprocess, which will write them to /etc/hosts. Whew!
Only the firewall process can write to /etc/hosts, of course, because only
he's running as root.
Since the name discovery process is kind of slow, we cache the names in
~/.sshuttle.hosts on the remote server.
Right now, most of the names are discovered using nmblookup and smbclient,
as well as by reading the existing entries in /etc/hosts. What would really
be nice would be to query active directory or mdns somehow... but I don't
really know how those work, so this is what you get for now :) It's pretty
neat, at least.
2010-05-08 09:03:12 +02:00
|
|
|
def sethostip(self, hostname, ip):
|
|
|
|
assert(not re.search(r'[^-\w]', hostname))
|
|
|
|
assert(not re.search(r'[^0-9.]', ip))
|
|
|
|
self.pfile.write('HOST %s,%s\n' % (hostname, ip))
|
|
|
|
self.pfile.flush()
|
|
|
|
|
2010-05-03 01:29:03 +02:00
|
|
|
def done(self):
|
2010-05-03 02:54:10 +02:00
|
|
|
self.pfile.close()
|
2010-05-03 01:29:03 +02:00
|
|
|
rv = self.p.wait()
|
|
|
|
if rv:
|
|
|
|
raise Fatal('cleanup: %r returned %d' % (self.argv, rv))
|
2010-05-02 03:14:19 +02:00
|
|
|
|
|
|
|
|
2011-01-26 06:07:01 +01:00
|
|
|
def _main(listener, fw, ssh_cmd, remotename, python, latency_control,
|
2011-01-26 11:00:19 +01:00
|
|
|
dnslistener, seed_hosts, auto_nets,
|
2011-01-01 07:54:07 +01:00
|
|
|
syslog, daemon):
|
2010-05-02 02:03:50 +02:00
|
|
|
handlers = []
|
2010-11-09 08:59:26 +01:00
|
|
|
if helpers.verbose >= 1:
|
|
|
|
helpers.logprefix = 'c : '
|
|
|
|
else:
|
|
|
|
helpers.logprefix = 'client: '
|
|
|
|
debug1('connecting to server...\n')
|
2010-12-05 13:05:35 +01:00
|
|
|
|
2010-11-09 08:59:26 +01:00
|
|
|
try:
|
2011-01-01 07:54:07 +01:00
|
|
|
(serverproc, serversock) = ssh.connect(ssh_cmd, remotename, python,
|
2011-01-26 06:07:01 +01:00
|
|
|
stderr=ssyslog._p and ssyslog._p.stdin,
|
|
|
|
options=dict(latency_control=latency_control))
|
2010-11-09 08:59:26 +01:00
|
|
|
except socket.error, e:
|
2011-01-01 06:05:41 +01:00
|
|
|
if e.args[0] == errno.EPIPE:
|
2011-01-01 08:46:47 +01:00
|
|
|
raise Fatal("failed to establish ssh session (1)")
|
2010-05-02 08:23:42 +02:00
|
|
|
else:
|
2010-11-09 08:59:26 +01:00
|
|
|
raise
|
|
|
|
mux = Mux(serversock, serversock)
|
|
|
|
handlers.append(mux)
|
|
|
|
|
|
|
|
expected = 'SSHUTTLE0001'
|
2011-01-01 08:46:47 +01:00
|
|
|
try:
|
|
|
|
initstring = serversock.recv(len(expected))
|
|
|
|
except socket.error, e:
|
|
|
|
if e.args[0] == errno.ECONNRESET:
|
|
|
|
raise Fatal("failed to establish ssh session (2)")
|
|
|
|
else:
|
|
|
|
raise
|
2010-11-09 08:59:26 +01:00
|
|
|
|
|
|
|
rv = serverproc.poll()
|
|
|
|
if rv:
|
|
|
|
raise Fatal('server died with error code %d' % rv)
|
2010-05-02 08:23:42 +02:00
|
|
|
|
2010-11-09 08:59:26 +01:00
|
|
|
if initstring != expected:
|
|
|
|
raise Fatal('expected server init string %r; got %r'
|
|
|
|
% (expected, initstring))
|
|
|
|
debug1('connected.\n')
|
2011-01-19 04:11:44 +01:00
|
|
|
print 'Connected.'
|
|
|
|
sys.stdout.flush()
|
2011-01-01 07:54:07 +01:00
|
|
|
if daemon:
|
|
|
|
daemonize()
|
2011-01-01 09:06:04 +01:00
|
|
|
log('daemonizing (%s).\n' % _pidname)
|
2011-01-01 07:54:07 +01:00
|
|
|
elif syslog:
|
2011-01-01 09:06:04 +01:00
|
|
|
debug1('switching to syslog.\n')
|
|
|
|
ssyslog.stderr_to_syslog()
|
2010-05-02 08:23:42 +02:00
|
|
|
|
2010-05-08 02:02:04 +02:00
|
|
|
def onroutes(routestr):
|
|
|
|
if auto_nets:
|
|
|
|
for line in routestr.strip().split('\n'):
|
|
|
|
(ip,width) = line.split(',', 1)
|
|
|
|
fw.auto_nets.append((ip,int(width)))
|
|
|
|
|
|
|
|
# we definitely want to do this *after* starting ssh, or we might end
|
|
|
|
# up intercepting the ssh connection!
|
|
|
|
#
|
|
|
|
# Moreover, now that we have the --auto-nets option, we have to wait
|
|
|
|
# for the server to send us that message anyway. Even if we haven't
|
|
|
|
# set --auto-nets, we might as well wait for the message first, then
|
|
|
|
# ignore its contents.
|
|
|
|
mux.got_routes = None
|
|
|
|
fw.start()
|
|
|
|
mux.got_routes = onroutes
|
2010-05-02 05:14:42 +02:00
|
|
|
|
Added new --auto-hosts and --seed-hosts options to the client.
Now if you use --auto-hosts (-H), the client will ask the server to spawn a
hostwatcher to add names. That, in turn, will send names back to the
server, which sends them back to the client, which sends them to the
firewall subprocess, which will write them to /etc/hosts. Whew!
Only the firewall process can write to /etc/hosts, of course, because only
he's running as root.
Since the name discovery process is kind of slow, we cache the names in
~/.sshuttle.hosts on the remote server.
Right now, most of the names are discovered using nmblookup and smbclient,
as well as by reading the existing entries in /etc/hosts. What would really
be nice would be to query active directory or mdns somehow... but I don't
really know how those work, so this is what you get for now :) It's pretty
neat, at least.
2010-05-08 09:03:12 +02:00
|
|
|
def onhostlist(hostlist):
|
|
|
|
debug2('got host list: %r\n' % hostlist)
|
|
|
|
for line in hostlist.strip().split():
|
|
|
|
if line:
|
|
|
|
name,ip = line.split(',', 1)
|
|
|
|
fw.sethostip(name, ip)
|
|
|
|
mux.got_host_list = onhostlist
|
|
|
|
|
2010-05-02 02:03:50 +02:00
|
|
|
def onaccept():
|
2011-01-01 06:32:51 +01:00
|
|
|
global _extra_fd
|
|
|
|
try:
|
|
|
|
sock,srcip = listener.accept()
|
|
|
|
except socket.error, e:
|
|
|
|
if e.args[0] in [errno.EMFILE, errno.ENFILE]:
|
|
|
|
debug1('Rejected incoming connection: too many open files!\n')
|
|
|
|
# free up an fd so we can eat the connection
|
|
|
|
os.close(_extra_fd)
|
|
|
|
try:
|
|
|
|
sock,srcip = listener.accept()
|
|
|
|
sock.close()
|
|
|
|
finally:
|
|
|
|
_extra_fd = os.open('/dev/null', os.O_RDONLY)
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
raise
|
2010-05-02 02:03:50 +02:00
|
|
|
dstip = original_dst(sock)
|
2011-01-01 05:53:42 +01:00
|
|
|
debug1('Accept: %s:%r -> %s:%r.\n' % (srcip[0],srcip[1],
|
|
|
|
dstip[0],dstip[1]))
|
2011-01-26 13:32:00 +01:00
|
|
|
if dstip[1] == listener.getsockname()[1] and islocal(dstip[0]):
|
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-11-09 08:59:26 +01:00
|
|
|
chan = mux.next_channel()
|
2011-02-02 11:32:46 +01:00
|
|
|
if not chan:
|
|
|
|
log('warning: too many open channels. Discarded connection.\n')
|
|
|
|
sock.close()
|
|
|
|
return
|
2010-11-09 08:59:26 +01:00
|
|
|
mux.send(chan, ssnet.CMD_CONNECT, '%s,%s' % dstip)
|
|
|
|
outwrap = MuxWrapper(mux, chan)
|
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))
|
Added new --auto-hosts and --seed-hosts options to the client.
Now if you use --auto-hosts (-H), the client will ask the server to spawn a
hostwatcher to add names. That, in turn, will send names back to the
server, which sends them back to the client, which sends them to the
firewall subprocess, which will write them to /etc/hosts. Whew!
Only the firewall process can write to /etc/hosts, of course, because only
he's running as root.
Since the name discovery process is kind of slow, we cache the names in
~/.sshuttle.hosts on the remote server.
Right now, most of the names are discovered using nmblookup and smbclient,
as well as by reading the existing entries in /etc/hosts. What would really
be nice would be to query active directory or mdns somehow... but I don't
really know how those work, so this is what you get for now :) It's pretty
neat, at least.
2010-05-08 09:03:12 +02:00
|
|
|
|
2011-01-26 11:34:12 +01:00
|
|
|
dnsreqs = {}
|
2011-01-26 11:00:19 +01:00
|
|
|
def dns_done(chan, data):
|
2011-01-26 14:19:03 +01:00
|
|
|
peer,timeout = dnsreqs.get(chan) or (None,None)
|
2011-01-26 11:34:12 +01:00
|
|
|
debug3('dns_done: channel=%r peer=%r\n' % (chan, peer))
|
2011-01-26 11:00:19 +01:00
|
|
|
if peer:
|
2011-01-26 11:34:12 +01:00
|
|
|
del dnsreqs[chan]
|
|
|
|
debug3('doing sendto %r\n' % (peer,))
|
2011-01-26 11:00:19 +01:00
|
|
|
dnslistener.sendto(data, peer)
|
|
|
|
def ondns():
|
|
|
|
pkt,peer = dnslistener.recvfrom(4096)
|
2011-01-26 11:34:12 +01:00
|
|
|
now = time.time()
|
2011-01-26 11:00:19 +01:00
|
|
|
if pkt:
|
2011-01-26 11:34:12 +01:00
|
|
|
debug1('DNS request from %r: %d bytes\n' % (peer, len(pkt)))
|
2011-01-26 11:00:19 +01:00
|
|
|
chan = mux.next_channel()
|
2011-01-26 11:34:12 +01:00
|
|
|
dnsreqs[chan] = peer,now+30
|
2011-01-26 11:00:19 +01:00
|
|
|
mux.send(chan, ssnet.CMD_DNS_REQ, pkt)
|
|
|
|
mux.channels[chan] = lambda cmd,data: dns_done(chan,data)
|
2011-01-26 11:34:12 +01:00
|
|
|
for chan,(peer,timeout) in dnsreqs.items():
|
|
|
|
if timeout < now:
|
|
|
|
del dnsreqs[chan]
|
|
|
|
debug3('Remaining DNS requests: %d\n' % len(dnsreqs))
|
2011-01-26 11:00:19 +01:00
|
|
|
if dnslistener:
|
|
|
|
handlers.append(Handler([dnslistener], ondns))
|
|
|
|
|
Added new --auto-hosts and --seed-hosts options to the client.
Now if you use --auto-hosts (-H), the client will ask the server to spawn a
hostwatcher to add names. That, in turn, will send names back to the
server, which sends them back to the client, which sends them to the
firewall subprocess, which will write them to /etc/hosts. Whew!
Only the firewall process can write to /etc/hosts, of course, because only
he's running as root.
Since the name discovery process is kind of slow, we cache the names in
~/.sshuttle.hosts on the remote server.
Right now, most of the names are discovered using nmblookup and smbclient,
as well as by reading the existing entries in /etc/hosts. What would really
be nice would be to query active directory or mdns somehow... but I don't
really know how those work, so this is what you get for now :) It's pretty
neat, at least.
2010-05-08 09:03:12 +02:00
|
|
|
if seed_hosts != None:
|
|
|
|
debug1('seed_hosts: %r\n' % seed_hosts)
|
|
|
|
mux.send(0, ssnet.CMD_HOST_REQ, '\n'.join(seed_hosts))
|
2010-05-02 02:03:50 +02:00
|
|
|
|
|
|
|
while 1:
|
2010-11-09 08:59:26 +01:00
|
|
|
rv = serverproc.poll()
|
|
|
|
if rv:
|
|
|
|
raise Fatal('server died with error code %d' % rv)
|
2010-05-02 06:52:06 +02:00
|
|
|
|
2010-10-02 02:36:09 +02:00
|
|
|
ssnet.runonce(handlers, mux)
|
2011-01-26 06:07:01 +01:00
|
|
|
if latency_control:
|
|
|
|
mux.check_fullness()
|
2010-11-09 08:59:26 +01:00
|
|
|
mux.callback()
|
2010-05-02 03:30:59 +02:00
|
|
|
|
|
|
|
|
2011-01-26 11:00:19 +01:00
|
|
|
def main(listenip, ssh_cmd, remotename, python, latency_control, dns,
|
2011-01-26 06:07:01 +01:00
|
|
|
seed_hosts, auto_nets,
|
2011-01-01 07:54:07 +01:00
|
|
|
subnets_include, subnets_exclude, syslog, daemon, pidfile):
|
|
|
|
if syslog:
|
2011-01-01 09:06:04 +01:00
|
|
|
ssyslog.start_syslog()
|
2011-01-01 07:54:07 +01:00
|
|
|
if daemon:
|
|
|
|
try:
|
|
|
|
check_daemon(pidfile)
|
|
|
|
except Fatal, e:
|
|
|
|
log("%s\n" % e)
|
|
|
|
return 5
|
2010-05-02 08:14:20 +02:00
|
|
|
debug1('Starting sshuttle proxy.\n')
|
2011-01-26 11:00:19 +01:00
|
|
|
|
2010-05-02 03:50:43 +02:00
|
|
|
if listenip[1]:
|
|
|
|
ports = [listenip[1]]
|
|
|
|
else:
|
2010-05-05 00:24:43 +02:00
|
|
|
ports = xrange(12300,9000,-1)
|
2010-05-02 03:50:43 +02:00
|
|
|
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)
|
2011-01-26 13:44:32 +01:00
|
|
|
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)
|
2010-05-02 03:50:43 +02:00
|
|
|
try:
|
|
|
|
listener.bind((listenip[0], port))
|
2011-01-26 13:44:32 +01:00
|
|
|
dnslistener.bind((listenip[0], port))
|
2010-05-02 03:50:43 +02:00
|
|
|
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
|
|
|
|
2011-01-26 11:00:19 +01:00
|
|
|
if dns:
|
|
|
|
dnsip = dnslistener.getsockname()
|
|
|
|
debug1('DNS listening on %r.\n' % (dnsip,))
|
|
|
|
dnsport = dnsip[1]
|
2011-01-26 13:44:32 +01:00
|
|
|
else:
|
|
|
|
dnsport = 0
|
|
|
|
dnslistener = None
|
2011-01-26 11:00:19 +01:00
|
|
|
|
|
|
|
fw = FirewallClient(listenip[1], subnets_include, subnets_exclude, dnsport)
|
2010-05-03 01:29:03 +02:00
|
|
|
|
2010-05-02 03:30:59 +02:00
|
|
|
try:
|
2010-11-09 09:17:01 +01:00
|
|
|
return _main(listener, fw, ssh_cmd, remotename,
|
2011-01-26 11:00:19 +01:00
|
|
|
python, latency_control, dnslistener,
|
2011-01-26 06:07:01 +01:00
|
|
|
seed_hosts, auto_nets, syslog, daemon)
|
2010-05-02 03:30:59 +02:00
|
|
|
finally:
|
2011-01-01 07:54:07 +01:00
|
|
|
try:
|
|
|
|
if daemon:
|
|
|
|
# it's not our child anymore; can't waitpid
|
|
|
|
fw.p.returncode = 0
|
|
|
|
fw.done()
|
|
|
|
finally:
|
|
|
|
if daemon:
|
|
|
|
daemon_cleanup()
|