From d4ca0d281c1e0dec4ae13b56ea358709dc0b8722 Mon Sep 17 00:00:00 2001 From: breakwa11 Date: Mon, 22 Jun 2015 19:02:46 +0800 Subject: [PATCH] always UDP on random length TCP/UDP packet --- server_pool.py | 46 +++++++++++++++++++++-------------------- shadowsocks/common.py | 14 +++++++++++++ shadowsocks/tcprelay.py | 18 ++++++---------- shadowsocks/udprelay.py | 8 +++++-- 4 files changed, 50 insertions(+), 36 deletions(-) diff --git a/server_pool.py b/server_pool.py index c75655a..566154c 100644 --- a/server_pool.py +++ b/server_pool.py @@ -46,7 +46,6 @@ class ServerPool(object): shell.print_shadowsocks() self.dns_resolver = asyncdns.DNSResolver() self.mgr = asyncmgr.ServerMgr() - self.udp_on = True ### UDP switch ===================================== self.tcp_servers_pool = {} self.tcp_ipv6_servers_pool = {} @@ -110,19 +109,21 @@ class ServerPool(object): a_config['password'] = password try: logging.info("starting server at [%s]:%d" % (a_config['server'], port)) + tcp_server = tcprelay.TCPRelay(a_config, self.dns_resolver, False) tcp_server.add_to_loop(self.loop) self.tcp_ipv6_servers_pool.update({port: tcp_server}) - if self.udp_on: - udp_server = udprelay.UDPRelay(a_config, self.dns_resolver, False) - udp_server.add_to_loop(self.loop) - self.udp_ipv6_servers_pool.update({port: udp_server}) + + udp_server = udprelay.UDPRelay(a_config, self.dns_resolver, False) + udp_server.add_to_loop(self.loop) + self.udp_ipv6_servers_pool.update({port: udp_server}) + if a_config['server_ipv6'] == "::": ipv6_ok = True except Exception, e: logging.warn("IPV6 %s " % (e,)) - if not ipv6_ok and 'server' in self.config: + if 'server' in self.config: if port in self.tcp_servers_pool: logging.info("server already at %s:%d" % (self.config['server'], port)) return 'this port server is already running' @@ -132,13 +133,16 @@ class ServerPool(object): a_config['password'] = password try: logging.info("starting server at %s:%d" % (a_config['server'], port)) - tcp_server = tcprelay.TCPRelay(a_config, self.dns_resolver, False) - tcp_server.add_to_loop(self.loop) - self.tcp_servers_pool.update({port: tcp_server}) - if self.udp_on: + + if not ipv6_ok: + tcp_server = tcprelay.TCPRelay(a_config, self.dns_resolver, False) + tcp_server.add_to_loop(self.loop) + self.tcp_servers_pool.update({port: tcp_server}) + udp_server = udprelay.UDPRelay(a_config, self.dns_resolver, False) udp_server.add_to_loop(self.loop) self.udp_servers_pool.update({port: udp_server}) + except Exception, e: logging.warn("IPV4 %s " % (e,)) @@ -167,12 +171,11 @@ class ServerPool(object): del self.tcp_servers_pool[port] except Exception, e: logging.warn(e) - if self.udp_on: - try: - self.udp_servers_pool[port].close(True) - del self.udp_servers_pool[port] - except Exception, e: - logging.warn(e) + try: + self.udp_servers_pool[port].close(True) + del self.udp_servers_pool[port] + except Exception, e: + logging.warn(e) if 'server_ipv6' in self.config: if port not in self.tcp_ipv6_servers_pool: @@ -184,12 +187,11 @@ class ServerPool(object): del self.tcp_ipv6_servers_pool[port] except Exception, e: logging.warn(e) - if self.udp_on: - try: - self.udp_ipv6_servers_pool[port].close(True) - del self.udp_ipv6_servers_pool[port] - except Exception, e: - logging.warn(e) + try: + self.udp_ipv6_servers_pool[port].close(True) + del self.udp_ipv6_servers_pool[port] + except Exception, e: + logging.warn(e) return True diff --git a/shadowsocks/common.py b/shadowsocks/common.py index d740160..605fbfa 100644 --- a/shadowsocks/common.py +++ b/shadowsocks/common.py @@ -138,6 +138,20 @@ def pack_addr(address): address = address[:255] # TODO return b'\x03' + chr(len(address)) + address +def pre_parse_header(data): + datatype = ord(data[0]) + if datatype == 0x80 : + if len(data) <= 2: + return None + rand_data_size = ord(data[1]) + if rand_data_size + 2 >= len(data): + logging.warn('header too short, maybe wrong password or ' + 'encryption method') + return None + data = data[rand_data_size + 2:] + elif datatype == 0x81: + data = data[1:] + return data def parse_header(data): addrtype = ord(data[0]) diff --git a/shadowsocks/tcprelay.py b/shadowsocks/tcprelay.py index 729aa04..6bb6bbc 100644 --- a/shadowsocks/tcprelay.py +++ b/shadowsocks/tcprelay.py @@ -27,7 +27,7 @@ import traceback import random from shadowsocks import encrypt, eventloop, shell, common -from shadowsocks.common import parse_header +from shadowsocks.common import pre_parse_header, parse_header # we clear at most TIMEOUTS_CLEAN_SIZE timeouts each time TIMEOUTS_CLEAN_SIZE = 512 @@ -320,12 +320,15 @@ class TCPRelayHandler(object): logging.error('unknown command %d', cmd) self.destroy() return + data = pre_parse_header(data) + if data is None: + raise Exception('can not parse header') header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') connecttype, remote_addr, remote_port, header_length = header_result logging.info('%s connecting %s:%d from %s:%d' % - ((connecttype == 0) and 'tcp' or 'udp', + ((connecttype == 0) and 'TCP' or 'UDP', common.to_str(remote_addr), remote_port, self._client_address[0], self._client_address[1])) self._remote_address = (common.to_str(remote_addr), remote_port) @@ -356,15 +359,6 @@ class TCPRelayHandler(object): # TODO use logging when debug completed self.destroy() - def _has_ipv6_addr(self, addr_list): - for item in addr_list: - if type(item) is list: - if self._has_ipv6_addr(item): - return True - elif ':' in item: - return True - return False - def _create_remote_socket(self, ip, port): if self._remote_udp: addrs_v6 = socket.getaddrinfo("::", 0, 0, socket.SOCK_DGRAM, socket.SOL_UDP) @@ -505,7 +499,7 @@ class TCPRelayHandler(object): except Exception as e: ip = socket.inet_pton(socket.AF_INET6, addr[0]) data = '\x00\x00\x00\x04' + ip + port + data - logging.info('udp recvfrom %s:%d %d bytes to %s:%d' % (addr[0], addr[1], len(data), self._client_address[0], self._client_address[1])) + logging.info('UDP recvfrom %s:%d %d bytes to %s:%d' % (addr[0], addr[1], len(data), self._client_address[0], self._client_address[1])) else: data = self._remote_sock.recv(BUF_SIZE) except (OSError, IOError) as e: diff --git a/shadowsocks/udprelay.py b/shadowsocks/udprelay.py index 71d7a95..09f077f 100644 --- a/shadowsocks/udprelay.py +++ b/shadowsocks/udprelay.py @@ -70,7 +70,7 @@ import errno import random from shadowsocks import encrypt, eventloop, lru_cache, common, shell -from shadowsocks.common import parse_header, pack_addr +from shadowsocks.common import pre_parse_header, parse_header, pack_addr BUF_SIZE = 65536 @@ -159,6 +159,10 @@ class UDPRelay(object): if not data: logging.debug('UDP handle_server: data is empty after decrypt') return + data = pre_parse_header(data) + if data is None: + return + header_result = parse_header(data) if header_result is None: return @@ -173,7 +177,7 @@ class UDPRelay(object): client = self._cache.get(key, None) if not client: # TODO async getaddrinfo - logging.info('UDP handle_server %s:%d from %s:%d' % (common.to_str(server_addr), server_port, self._listen_addr, self._listen_port)) + #logging.info('UDP handle_server %s:%d from %s:%d' % (common.to_str(server_addr), server_port, self._listen_addr, self._listen_port)) addrs = socket.getaddrinfo(server_addr, server_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if addrs: