def pfctl(*args): # TODO: pretty sure this doesn't work. Need to research how pf works. argv = ['pfctl', '-q', ] + list(args) debug1('>> %s\n' % ' '.join(argv)) rv = ssubprocess.call(argv) if rv: raise Fatal('%r returned %d' % (argv, rv))
def print_listening(self, what): if self.v6: listenip = self.v6.getsockname() debug1('%s listening on %r.\n' % (what, listenip)) if self.v4: listenip = self.v4.getsockname() debug1('%s listening on %r.\n' % (what, listenip))
def _ipt(family, table, *args): if family == socket.AF_INET6: argv = ['ip6tables', '-t', table] + list(args) elif family == socket.AF_INET: argv = ['iptables', '-t', table] + list(args) else: raise Exception('Unsupported family "%s"' % family_to_string(family)) debug1('>> %s\n' % ' '.join(argv)) rv = ssubprocess.call(argv) if rv: raise Fatal('%r returned %d' % (argv, rv))
def found_host(hostname, ip): hostname = re.sub(r'\..*', '', hostname) hostname = re.sub(r'[^-\w]', '_', hostname) if (ip.startswith('127.') or ip.startswith('255.') or hostname == 'localhost'): return oldip = hostnames.get(hostname) if oldip != ip: hostnames[hostname] = ip debug1('Found: %s: %s\n' % (hostname, ip)) sys.stdout.write('%s,%s\n' % (hostname, ip)) write_host_cache()
def size(self): """Get this file's size.""" if self._cached_size == None: debug1('<<<<File.size() is calculating (for %r)...\n' % self.name) if self.bupmode == git.BUP_CHUNKED: self._cached_size = _total_size(self.hash, repo_dir = self._repo_dir) else: self._cached_size = _chunk_len(self.hash, repo_dir = self._repo_dir) debug1('<<<<File.size() done.\n') return self._cached_size
def pfctl(args, stdin = None): argv = ['pfctl'] + list(args.split(" ")) debug1('>> %s\n' % ' '.join(argv)) p = ssubprocess.Popen(argv, stdin = ssubprocess.PIPE, stdout = ssubprocess.PIPE, stderr = ssubprocess.PIPE) o = p.communicate(stdin) if p.returncode: raise Fatal('%r returned %d' % (argv, p.returncode)) return o
def udp_done(chan, data, method, family, dstip): (src, srcport, data) = data.split(",", 2) srcip = (src, int(srcport)) debug3('doing send from %r to %r\n' % (srcip, dstip,)) try: sender = socket.socket(family, socket.SOCK_DGRAM) sender.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sender.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1) sender.bind(srcip) sender.sendto(data, dstip) sender.close() except socket.error, e: debug1('-- ignored socket error sending UDP data: %r\n' % e)
def ondns(listener, method, mux, handlers): now = time.time() srcip, dstip, data = recv_udp(listener, 4096) if method == "tproxy" and not dstip: debug1("-- ignored UDP from %r: " "couldn't determine destination IP address\n" % (srcip, )) return debug1('DNS request from %r to %r: %d bytes\n' % (srcip, dstip, len(data))) chan = mux.next_channel() dnsreqs[chan] = now + 30 mux.send(chan, ssnet.CMD_DNS_REQ, data) mux.channels[chan] = lambda cmd, data: dns_done( chan, data, method, listener, srcip=dstip, dstip=srcip, mux=mux) expire_connections(now, mux)
def uwrite(self, buf): if self.connect_to: return 0 # still connecting self.wsock.setblocking(False) try: return _nb_clean(os.write, self.wsock.fileno(), buf) except OSError, e: if e.errno == errno.EPIPE: debug1('%r: uwrite: got EPIPE\n' % self) self.nowrite() return 0 else: # unexpected error... stream is dead self.seterr('uwrite: %s' % e) return 0
def ondns(listener, method, mux, handlers): now = time.time() srcip, dstip, data = recv_udp(listener, 4096) if method == "tproxy" and not dstip: debug1( "-- ignored UDP from %r: " "couldn't determine destination IP address\n" % (srcip,)) return debug1('DNS request from %r to %r: %d bytes\n' % (srcip, dstip, len(data))) chan = mux.next_channel() dnsreqs[chan] = now + 30 mux.send(chan, ssnet.CMD_DNS_REQ, data) mux.channels[chan] = lambda cmd, data: dns_done( chan, data, method, listener, srcip=dstip, dstip=srcip, mux=mux) expire_connections(now, mux)
def onaccept_tcp(listener, method, mux, handlers): 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
def udp_done(chan, data, method, family, dstip): (src, srcport, data) = data.split(",", 2) srcip = (src, int(srcport)) debug3('doing send from %r to %r\n' % ( srcip, dstip, )) try: sender = socket.socket(family, socket.SOCK_DGRAM) sender.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sender.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1) sender.bind(srcip) sender.sendto(data, dstip) sender.close() except socket.error, e: debug1('-- ignored socket error sending UDP data: %r\n' % e)
def sysctl_set(name, val, permanent=False): PREFIX = 'net.inet.ip' assert (name.startswith(PREFIX + '.')) val = str(val) if not _oldctls: _fill_oldctls(PREFIX) if not (name in _oldctls): debug1('>> No such sysctl: %r\n' % name) return False oldval = _oldctls[name] if val != oldval: rv = _sysctl_set(name, val) if rv == 0 and permanent: debug1('>> ...saving permanently in /etc/sysctl.conf\n') f = open('/etc/sysctl.conf', 'a') f.write('\n' '# Added by sshuttle\n' '%s=%s\n' % (name, val)) f.close() else: _changedctls.append(name) return True
def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename, python, latency_control, dns_listener, method, seed_hosts, auto_nets, syslog, daemon): handlers = [] if helpers.verbose >= 1: helpers.logprefix = 'c : ' else: helpers.logprefix = 'client: ' debug1('connecting to server...\n') try: (serverproc, serversock) = ssh.connect( ssh_cmd, remotename, python, stderr=ssyslog._p and ssyslog._p.stdin, options=dict(latency_control=latency_control, method=method)) except socket.error, e: if e.args[0] == errno.EPIPE: raise Fatal("failed to establish ssh session (1)") else: raise
def sysctl_set(name, val, permanent=False): PREFIX = 'net.inet.ip' assert(name.startswith(PREFIX + '.')) val = str(val) if not _oldctls: _fill_oldctls(PREFIX) if not (name in _oldctls): debug1('>> No such sysctl: %r\n' % name) return False oldval = _oldctls[name] if val != oldval: rv = _sysctl_set(name, val) if rv == 0 and permanent: debug1('>> ...saving permanently in /etc/sysctl.conf\n') f = open('/etc/sysctl.conf', 'a') f.write('\n' '# Added by sshuttle\n' '%s=%s\n' % (name, val)) f.close() else: _changedctls.append(name) return True
def onaccept_udp(listener, method, mux, handlers): now = time.time() srcip, dstip, data = recv_udp(listener, 4096) if not dstip: debug1( "-- ignored UDP from %r: " "couldn't determine destination IP address\n" % (srcip,)) return debug1('Accept UDP: %r -> %r.\n' % (srcip, dstip,)) if srcip in udp_by_src: chan, timeout = udp_by_src[srcip] else: chan = mux.next_channel() mux.channels[chan] = lambda cmd, data: udp_done( chan, data, method, listener.family, dstip=srcip) mux.send(chan, ssnet.CMD_UDP_OPEN, listener.family) udp_by_src[srcip] = chan, now + 30 hdr = "%s,%r," % (dstip[0], dstip[1]) mux.send(chan, ssnet.CMD_UDP_DATA, hdr + data) expire_connections(now, mux)
def onaccept_udp(listener, method, mux, handlers): now = time.time() srcip, dstip, data = recv_udp(listener, 4096) if not dstip: debug1("-- ignored UDP from %r: " "couldn't determine destination IP address\n" % (srcip, )) return debug1('Accept UDP: %r -> %r.\n' % ( srcip, dstip, )) if srcip in udp_by_src: chan, timeout = udp_by_src[srcip] else: chan = mux.next_channel() mux.channels[chan] = lambda cmd, data: udp_done( chan, data, method, listener.family, dstip=srcip) mux.send(chan, ssnet.CMD_UDP_OPEN, listener.family) udp_by_src[srcip] = chan, now + 30 hdr = "%s,%r," % (dstip[0], dstip[1]) mux.send(chan, ssnet.CMD_UDP_DATA, hdr + data) expire_connections(now, mux)
def main(port_v6, port_v4, dnsport_v6, dnsport_v4, method, udp, syslog): assert(port_v6 >= 0) assert(port_v6 <= 65535) assert(port_v4 >= 0) assert(port_v4 <= 65535) assert(dnsport_v6 >= 0) assert(dnsport_v6 <= 65535) assert(dnsport_v4 >= 0) assert(dnsport_v4 <= 65535) if os.getuid() != 0: raise Fatal('you must be root (or enable su/sudo) to set the firewall') if method == "auto": if program_exists('ipfw'): method = "ipfw" elif program_exists('iptables'): method = "nat" elif program_exists('pfctl'): method = "pf" else: raise Fatal("can't find either ipfw, pf, or iptables; check your PATH") if method == "nat": do_it = do_iptables_nat elif method == "tproxy": do_it = do_iptables_tproxy elif method == "ipfw": do_it = do_ipfw elif method == "pf": do_it = do_pf else: raise Exception('Unknown method "%s"' % method) # because of limitations of the 'su' command, the *real* stdin/stdout # are both attached to stdout initially. Clone stdout into stdin so we # can read from it. os.dup2(1, 0) if syslog: ssyslog.start_syslog() ssyslog.stderr_to_syslog() debug1('firewall manager ready method %s.\n' % method) sys.stdout.write('READY %s\n' % method) sys.stdout.flush() # don't disappear if our controlling terminal or stdout/stderr # disappears; we still have to clean up. signal.signal(signal.SIGHUP, signal.SIG_IGN) signal.signal(signal.SIGPIPE, signal.SIG_IGN) signal.signal(signal.SIGTERM, signal.SIG_IGN) signal.signal(signal.SIGINT, signal.SIG_IGN) # ctrl-c shouldn't be passed along to me. When the main sshuttle dies, # I'll die automatically. os.setsid() # we wait until we get some input before creating the rules. That way, # sshuttle can launch us as early as possible (and get sudo password # authentication as early in the startup process as possible). line = sys.stdin.readline(128) if not line: return # parent died; nothing to do subnets = [] if line != 'ROUTES\n': raise Fatal('firewall: expected ROUTES but got %r' % line) while 1: line = sys.stdin.readline(128) if not line: raise Fatal('firewall: expected route but got %r' % line) elif line == 'GO\n': break try: (family, width, exclude, ip) = line.strip().split(',', 3) except: raise Fatal('firewall: expected route or GO but got %r' % line) subnets.append((int(family), int(width), bool(int(exclude)), ip)) try: if line: debug1('firewall manager: starting transproxy.\n') subnets_v6 = filter(lambda i: i[0] == socket.AF_INET6, subnets) if port_v6: do_wait = do_it( port_v6, dnsport_v6, socket.AF_INET6, subnets_v6, udp) elif len(subnets_v6) > 0: debug1("IPv6 subnets defined but IPv6 disabled\n") subnets_v4 = filter(lambda i: i[0] == socket.AF_INET, subnets) if port_v4: do_wait = do_it( port_v4, dnsport_v4, socket.AF_INET, subnets_v4, udp) elif len(subnets_v4) > 0: debug1('IPv4 subnets defined but IPv4 disabled\n') sys.stdout.write('STARTED\n') try: sys.stdout.flush() except IOError: # the parent process died for some reason; he's surely been loud # enough, so no reason to report another error return # Now we wait until EOF or any other kind of exception. We need # to stay running so that we don't need a *second* password # authentication at shutdown time - that cleanup is important! while 1: if do_wait: do_wait() line = sys.stdin.readline(128) if line.startswith('HOST '): (name, ip) = line[5:].strip().split(',', 1) hostmap[name] = ip rewrite_etc_hosts(port_v6 or port_v4) elif line: raise Fatal('expected EOF, got %r' % line) else: break finally: try: debug1('firewall manager: undoing changes.\n') except: pass if port_v6: do_it(port_v6, 0, socket.AF_INET6, [], udp) if port_v4: do_it(port_v4, 0, socket.AF_INET, [], udp) restore_etc_hosts(port_v6 or port_v4)
while 1: if do_wait: do_wait() line = sys.stdin.readline(128) if line.startswith('HOST '): (name, ip) = line[5:].strip().split(',', 1) hostmap[name] = ip rewrite_etc_hosts(port_v6 or port_v4) elif line.startswith('QUERY_PF_NAT '): try: dst = pf_query_nat(*(line[13:].split(','))) sys.stdout.write('QUERY_PF_NAT_SUCCESS %s,%r\n' % dst) except IOError, e: sys.stdout.write('QUERY_PF_NAT_FAILURE %s\n' % e) sys.stdout.flush() elif line: raise Fatal('expected EOF, got %r' % line) else: break finally: try: debug1('firewall manager: undoing changes.\n') except: pass if port_v6: do_it(port_v6, 0, socket.AF_INET6, [], udp) if port_v4: do_it(port_v4, 0, socket.AF_INET, [], udp) restore_etc_hosts(port_v6 or port_v4)
def _sysctl_set(name, val): argv = ['sysctl', '-w', '%s=%s' % (name, val)] debug1('>> %s\n' % ' '.join(argv)) return ssubprocess.call(argv, stdout=open('/dev/null', 'w'))
def ipfw(*args): argv = ['ipfw', '-q'] + list(args) debug1('>> %s\n' % ' '.join(argv)) rv = ssubprocess.call(argv) if rv: raise Fatal('%r returned %d' % (argv, rv))
def main(port_v6, port_v4, dnsport_v6, dnsport_v4, method, udp, syslog): assert(port_v6 >= 0) assert(port_v6 <= 65535) assert(port_v4 >= 0) assert(port_v4 <= 65535) assert(dnsport_v6 >= 0) assert(dnsport_v6 <= 65535) assert(dnsport_v4 >= 0) assert(dnsport_v4 <= 65535) if os.getuid() != 0: raise Fatal('you must be root (or enable su/sudo) to set the firewall') if method == "auto": if program_exists('ipfw'): method = "ipfw" elif program_exists('iptables'): method = "nat" elif program_exists('pfctl'): method = "pf" else: raise Fatal("can't find either ipfw, iptables or pfctl; check your PATH") if method == "nat": do_it = do_iptables_nat elif method == "tproxy": do_it = do_iptables_tproxy elif method == "ipfw": do_it = do_ipfw elif method == "pf": do_it = do_pf else: raise Exception('Unknown method "%s"' % method) # because of limitations of the 'su' command, the *real* stdin/stdout # are both attached to stdout initially. Clone stdout into stdin so we # can read from it. os.dup2(1, 0) if syslog: ssyslog.start_syslog() ssyslog.stderr_to_syslog() debug1('firewall manager ready method %s.\n' % method) sys.stdout.write('READY %s\n' % method) sys.stdout.flush() # don't disappear if our controlling terminal or stdout/stderr # disappears; we still have to clean up. signal.signal(signal.SIGHUP, signal.SIG_IGN) signal.signal(signal.SIGPIPE, signal.SIG_IGN) signal.signal(signal.SIGTERM, signal.SIG_IGN) signal.signal(signal.SIGINT, signal.SIG_IGN) # ctrl-c shouldn't be passed along to me. When the main sshuttle dies, # I'll die automatically. os.setsid() # we wait until we get some input before creating the rules. That way, # sshuttle can launch us as early as possible (and get sudo password # authentication as early in the startup process as possible). line = sys.stdin.readline(128) if not line: return # parent died; nothing to do subnets = [] if line != 'ROUTES\n': raise Fatal('firewall: expected ROUTES but got %r' % line) while 1: line = sys.stdin.readline(128) if not line: raise Fatal('firewall: expected route but got %r' % line) elif line == 'GO\n': break try: (family, width, exclude, ip) = line.strip().split(',', 3) except: raise Fatal('firewall: expected route or GO but got %r' % line) subnets.append((int(family), int(width), bool(int(exclude)), ip)) try: if line: debug1('firewall manager: starting transproxy.\n') subnets_v6 = filter(lambda i: i[0] == socket.AF_INET6, subnets) if port_v6: do_wait = do_it( port_v6, dnsport_v6, socket.AF_INET6, subnets_v6, udp) elif len(subnets_v6) > 0: debug1("IPv6 subnets defined but IPv6 disabled\n") subnets_v4 = filter(lambda i: i[0] == socket.AF_INET, subnets) if port_v4: do_wait = do_it( port_v4, dnsport_v4, socket.AF_INET, subnets_v4, udp) elif len(subnets_v4) > 0: debug1('IPv4 subnets defined but IPv4 disabled\n') sys.stdout.write('STARTED\n') try: sys.stdout.flush() except IOError: # the parent process died for some reason; he's surely been loud # enough, so no reason to report another error return # Now we wait until EOF or any other kind of exception. We need # to stay running so that we don't need a *second* password # authentication at shutdown time - that cleanup is important! while 1: if do_wait: do_wait() line = sys.stdin.readline(128) if line.startswith('HOST '): (name, ip) = line[5:].strip().split(',', 1) hostmap[name] = ip rewrite_etc_hosts(port_v6 or port_v4) elif line.startswith('QUERY_PF_NAT '): try: dst = pf_query_nat(*(line[13:].split(','))) sys.stdout.write('QUERY_PF_NAT_SUCCESS %s,%r\n' % dst) except IOError, e: sys.stdout.write('QUERY_PF_NAT_FAILURE %s\n' % e) sys.stdout.flush() elif line: raise Fatal('expected EOF, got %r' % line) else:
os.close(_extra_fd) try: sock, srcip = listener.accept() sock.close() finally: _extra_fd = os.open('/dev/null', os.O_RDONLY) return else: raise if method == "tproxy": dstip = sock.getsockname() elif method == "pf": dstip = pf_dst(sock) else: dstip = original_dst(sock) debug1('Accept TCP: %s:%r -> %s:%r.\n' % (srcip[0], srcip[1], dstip[0], dstip[1])) if dstip[1] == sock.getsockname()[1] and islocal(dstip[0], sock.family): debug1("-- ignored: that's my address!\n") sock.close() return chan = mux.next_channel() if not chan: log('warning: too many open channels. Discarded connection.\n') sock.close() return mux.send(chan, ssnet.CMD_TCP_CONNECT, '%d,%s,%s' % (sock.family, dstip[0], dstip[1])) outwrap = MuxWrapper(mux, chan) handlers.append(Proxy(SockWrapper(sock, sock), outwrap)) expire_connections(time.time(), mux)
def main(): if helpers.verbose >= 1: helpers.logprefix = ' s: ' else: helpers.logprefix = 'server: ' assert latency_control is not None debug1('latency control setting = %r\n' % latency_control) routes = list(list_routes()) debug1('available routes:\n') for r in routes: debug1(' %d/%s/%d\n' % r) # synchronization header sys.stdout.write('\0\0SSHUTTLE0001') sys.stdout.flush() handlers = [] mux = Mux(socket.fromfd(sys.stdin.fileno(), socket.AF_INET, socket.SOCK_STREAM), socket.fromfd(sys.stdout.fileno(), socket.AF_INET, socket.SOCK_STREAM)) handlers.append(mux) routepkt = '' for r in routes: routepkt += '%d,%s,%d\n' % r mux.send(0, ssnet.CMD_ROUTES, routepkt) hw = Hostwatch() hw.leftover = '' def hostwatch_ready(): assert(hw.pid) content = hw.sock.recv(4096) if content: lines = (hw.leftover + content).split('\n') if lines[-1]: # no terminating newline: entry isn't complete yet! hw.leftover = lines.pop() lines.append('') else: hw.leftover = '' mux.send(0, ssnet.CMD_HOST_LIST, '\n'.join(lines)) else: raise Fatal('hostwatch process died') def got_host_req(data): if not hw.pid: (hw.pid, hw.sock) = start_hostwatch(data.strip().split()) handlers.append(Handler(socks=[hw.sock], callback=hostwatch_ready)) mux.got_host_req = got_host_req def new_channel(channel, data): (family, dstip, dstport) = data.split(',', 2) family = int(family) dstport = int(dstport) outwrap = ssnet.connect_dst(family, dstip, dstport) handlers.append(Proxy(MuxWrapper(mux, channel), outwrap)) mux.new_channel = new_channel dnshandlers = {} def dns_req(channel, data): debug2('Incoming DNS request channel=%d.\n' % channel) h = DnsProxy(mux, channel, data) handlers.append(h) dnshandlers[channel] = h mux.got_dns_req = dns_req udphandlers = {} def udp_req(channel, cmd, data): debug2('Incoming UDP request channel=%d, cmd=%d\n' % (channel, cmd)) if cmd == ssnet.CMD_UDP_DATA: (dstip, dstport, data) = data.split(",", 2) dstport = int(dstport) debug2('is incoming UDP data. %r %d.\n' % (dstip, dstport)) h = udphandlers[channel] h.send((dstip, dstport), data) elif cmd == ssnet.CMD_UDP_CLOSE: debug2('is incoming UDP close\n') h = udphandlers[channel] h.ok = False del mux.channels[channel] def udp_open(channel, data): debug2('Incoming UDP open.\n') family = int(data) mux.channels[channel] = lambda cmd, data: udp_req(channel, cmd, data) if channel in udphandlers: raise Fatal('UDP connection channel %d already open' % channel) else: h = UdpProxy(mux, channel, family) handlers.append(h) udphandlers[channel] = h mux.got_udp_open = udp_open while mux.ok: if hw.pid: assert(hw.pid > 0) (rpid, rv) = os.waitpid(hw.pid, os.WNOHANG) if rpid: raise Fatal( 'hostwatch exited unexpectedly: code 0x%04x\n' % rv) ssnet.runonce(handlers, mux) if latency_control: mux.check_fullness() mux.callback() if dnshandlers: now = time.time() for channel, h in dnshandlers.items(): if h.timeout < now or not h.ok: debug3('expiring dnsreqs channel=%d\n' % channel) del dnshandlers[channel] h.ok = False if udphandlers: for channel, h in udphandlers.items(): if not h.ok: debug3('expiring UDP channel=%d\n' % channel) del udphandlers[channel] h.ok = False
def __del__(self): global _swcount _swcount -= 1 debug1('%r: deleting (%d remain)\n' % (self, _swcount)) if self.exc: debug1('%r: error was: %s\n' % (self, self.exc))
def main(): if helpers.verbose >= 1: helpers.logprefix = ' s: ' else: helpers.logprefix = 'server: ' assert latency_control is not None debug1('latency control setting = %r\n' % latency_control) routes = list(list_routes()) debug1('available routes:\n') for r in routes: debug1(' %d/%s/%d\n' % r) # synchronization header sys.stdout.write('\0\0SSHUTTLE0001') sys.stdout.flush() handlers = [] mux = Mux( socket.fromfd(sys.stdin.fileno(), socket.AF_INET, socket.SOCK_STREAM), socket.fromfd(sys.stdout.fileno(), socket.AF_INET, socket.SOCK_STREAM)) handlers.append(mux) routepkt = '' for r in routes: routepkt += '%d,%s,%d\n' % r mux.send(0, ssnet.CMD_ROUTES, routepkt) hw = Hostwatch() hw.leftover = '' def hostwatch_ready(): assert (hw.pid) content = hw.sock.recv(4096) if content: lines = (hw.leftover + content).split('\n') if lines[-1]: # no terminating newline: entry isn't complete yet! hw.leftover = lines.pop() lines.append('') else: hw.leftover = '' mux.send(0, ssnet.CMD_HOST_LIST, '\n'.join(lines)) else: raise Fatal('hostwatch process died') def got_host_req(data): if not hw.pid: (hw.pid, hw.sock) = start_hostwatch(data.strip().split()) handlers.append(Handler(socks=[hw.sock], callback=hostwatch_ready)) mux.got_host_req = got_host_req def new_channel(channel, data): (family, dstip, dstport) = data.split(',', 2) family = int(family) dstport = int(dstport) outwrap = ssnet.connect_dst(family, dstip, dstport) handlers.append(Proxy(MuxWrapper(mux, channel), outwrap)) mux.new_channel = new_channel dnshandlers = {} def dns_req(channel, data): debug2('Incoming DNS request channel=%d.\n' % channel) h = DnsProxy(mux, channel, data) handlers.append(h) dnshandlers[channel] = h mux.got_dns_req = dns_req udphandlers = {} def udp_req(channel, cmd, data): debug2('Incoming UDP request channel=%d, cmd=%d\n' % (channel, cmd)) if cmd == ssnet.CMD_UDP_DATA: (dstip, dstport, data) = data.split(",", 2) dstport = int(dstport) debug2('is incoming UDP data. %r %d.\n' % (dstip, dstport)) h = udphandlers[channel] h.send((dstip, dstport), data) elif cmd == ssnet.CMD_UDP_CLOSE: debug2('is incoming UDP close\n') h = udphandlers[channel] h.ok = False del mux.channels[channel] def udp_open(channel, data): debug2('Incoming UDP open.\n') family = int(data) mux.channels[channel] = lambda cmd, data: udp_req(channel, cmd, data) if channel in udphandlers: raise Fatal('UDP connection channel %d already open' % channel) else: h = UdpProxy(mux, channel, family) handlers.append(h) udphandlers[channel] = h mux.got_udp_open = udp_open while mux.ok: if hw.pid: assert (hw.pid > 0) (rpid, rv) = os.waitpid(hw.pid, os.WNOHANG) if rpid: raise Fatal('hostwatch exited unexpectedly: code 0x%04x\n' % rv) ssnet.runonce(handlers, mux) if latency_control: mux.check_fullness() mux.callback() if dnshandlers: now = time.time() for channel, h in dnshandlers.items(): if h.timeout < now or not h.ok: debug3('expiring dnsreqs channel=%d\n' % channel) del dnshandlers[channel] h.ok = False if udphandlers: for channel, h in udphandlers.items(): if not h.ok: debug3('expiring UDP channel=%d\n' % channel) del udphandlers[channel] h.ok = False
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 if method == "tproxy": dstip = sock.getsockname() else: dstip = original_dst(sock) debug1('Accept TCP: %s:%r -> %s:%r.\n' % (srcip[0], srcip[1], dstip[0], dstip[1])) if dstip[1] == sock.getsockname()[1] and islocal(dstip[0], sock.family): debug1("-- ignored: that's my address!\n") sock.close() return chan = mux.next_channel() if not chan: log('warning: too many open channels. Discarded connection.\n') sock.close() return mux.send(chan, ssnet.CMD_TCP_CONNECT, '%d,%s,%s' % (sock.family, dstip[0], dstip[1])) outwrap = MuxWrapper(mux, chan) handlers.append(Proxy(SockWrapper(sock, sock), outwrap)) expire_connections(time.time(), mux)