diff --git a/shadowsocks/shell.py b/shadowsocks/shell.py index 342b8da..775b39c 100644 --- a/shadowsocks/shell.py +++ b/shadowsocks/shell.py @@ -236,6 +236,7 @@ def get_config(is_local): config['obfs_param'] = to_str(config.get('obfs_param', '')) config['port_password'] = config.get('port_password', None) config['timeout'] = int(config.get('timeout', 300)) + config['udp_timeout'] = int(config.get('udp_timeout', config['timeout'])) config['fast_open'] = config.get('fast_open', False) config['workers'] = config.get('workers', 1) config['pid-file'] = config.get('pid-file', '/var/run/shadowsocks.pid') diff --git a/shadowsocks/udprelay.py b/shadowsocks/udprelay.py index a4587b8..713c346 100644 --- a/shadowsocks/udprelay.py +++ b/shadowsocks/udprelay.py @@ -880,7 +880,7 @@ class UDPRelay(object): self._method = config['method'] self._timeout = config['timeout'] self._is_local = is_local - self._cache = lru_cache.LRUCache(timeout=config['timeout'], + self._cache = lru_cache.LRUCache(timeout=config['udp_timeout'], close_callback=self._close_client) self._client_fd_to_server_addr = {} self._dns_cache = lru_cache.LRUCache(timeout=300) @@ -1023,69 +1023,8 @@ class UDPRelay(object): return if type(data) is tuple: - #(cmd, request_id, data) - #logging.info("UDP data %d %d %s" % (data[0], data[1], binascii.hexlify(data[2]))) - try: - self.server_transfer_ul += len(data[2]) - if data[0] == 0: - if len(data[2]) >= 4: - for i in range(64): - req_id = random.randint(1, 65535) - if req_id not in self._reqid_to_hd: - break - if req_id in self._reqid_to_hd: - for i in range(64): - req_id = random.randint(1, 65535) - if type(self._reqid_to_hd[req_id]) is tuple: - break - # return req id - self._reqid_to_hd[req_id] = (data[2][0:4], None) - rsp_data = self._pack_rsp_data(CMD_RSP_CONNECT, req_id, RSP_STATE_CONNECTED) - data_to_send = encrypt.encrypt_all(self._password, self._method, 1, rsp_data) - self.write_to_server_socket(data_to_send, r_addr) - elif data[0] == CMD_CONNECT_REMOTE: - if len(data[2]) > 4 and data[1] in self._reqid_to_hd: - # create - if type(self._reqid_to_hd[data[1]]) is tuple: - if data[2][0:4] == self._reqid_to_hd[data[1]][0]: - handle = TCPRelayHandler(self, self._reqid_to_hd, self._fd_to_handlers, - self._eventloop, self._server_socket, - self._reqid_to_hd[data[1]][0], self._reqid_to_hd[data[1]][1], - self._config, self._dns_resolver, self._is_local) - self._reqid_to_hd[data[1]] = handle - handle.handle_client(r_addr, CMD_CONNECT, data[1], data[2]) - handle.handle_client(r_addr, *data) - self.update_activity(handle) - else: - # disconnect - rsp_data = self._pack_rsp_data(CMD_DISCONNECT, data[1], RSP_STATE_EMPTY) - data_to_send = encrypt.encrypt_all(self._password, self._method, 1, rsp_data) - self.write_to_server_socket(data_to_send, r_addr) - else: - self.update_activity(self._reqid_to_hd[data[1]]) - self._reqid_to_hd[data[1]].handle_client(r_addr, *data) - else: - # disconnect - rsp_data = self._pack_rsp_data(CMD_DISCONNECT, data[1], RSP_STATE_EMPTY) - data_to_send = encrypt.encrypt_all(self._password, self._method, 1, rsp_data) - self.write_to_server_socket(data_to_send, r_addr) - elif data[0] > CMD_CONNECT_REMOTE and data[0] <= CMD_DISCONNECT: - if data[1] in self._reqid_to_hd: - if type(self._reqid_to_hd[data[1]]) is tuple: - pass - else: - self.update_activity(self._reqid_to_hd[data[1]]) - self._reqid_to_hd[data[1]].handle_client(r_addr, *data) - else: - # disconnect - rsp_data = self._pack_rsp_data(CMD_DISCONNECT, data[1], RSP_STATE_EMPTY) - data_to_send = encrypt.encrypt_all(self._password, self._method, 1, rsp_data) - self.write_to_server_socket(data_to_send, r_addr) - return - except Exception as e: - trace = traceback.format_exc() - logging.error(trace) - return + return + return self._handle_tcp_over_udp(data, r_addr) try: header_result = parse_header(data) @@ -1105,6 +1044,7 @@ class UDPRelay(object): addrs = self._dns_cache.get(server_addr, None) if addrs is None: + # TODO async getaddrinfo addrs = socket.getaddrinfo(server_addr, server_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if not addrs: @@ -1117,7 +1057,6 @@ class UDPRelay(object): key = client_key(r_addr, af) client = self._cache.get(key, None) if not client: - # TODO async getaddrinfo if self._forbidden_iplist: if common.to_str(sa[0]) in self._forbidden_iplist: logging.debug('IP %s is in forbidden list, drop' % @@ -1163,6 +1102,71 @@ class UDPRelay(object): else: shell.print_exception(e) + def _handle_tcp_over_udp(self, data, r_addr): + #(cmd, request_id, data) + #logging.info("UDP data %d %d %s" % (data[0], data[1], binascii.hexlify(data[2]))) + try: + self.server_transfer_ul += len(data[2]) + if data[0] == 0: + if len(data[2]) >= 4: + for i in range(64): + req_id = random.randint(1, 65535) + if req_id not in self._reqid_to_hd: + break + if req_id in self._reqid_to_hd: + for i in range(64): + req_id = random.randint(1, 65535) + if type(self._reqid_to_hd[req_id]) is tuple: + break + # return req id + self._reqid_to_hd[req_id] = (data[2][0:4], None) + rsp_data = self._pack_rsp_data(CMD_RSP_CONNECT, req_id, RSP_STATE_CONNECTED) + data_to_send = encrypt.encrypt_all(self._password, self._method, 1, rsp_data) + self.write_to_server_socket(data_to_send, r_addr) + elif data[0] == CMD_CONNECT_REMOTE: + if len(data[2]) > 4 and data[1] in self._reqid_to_hd: + # create + if type(self._reqid_to_hd[data[1]]) is tuple: + if data[2][0:4] == self._reqid_to_hd[data[1]][0]: + handle = TCPRelayHandler(self, self._reqid_to_hd, self._fd_to_handlers, + self._eventloop, self._server_socket, + self._reqid_to_hd[data[1]][0], self._reqid_to_hd[data[1]][1], + self._config, self._dns_resolver, self._is_local) + self._reqid_to_hd[data[1]] = handle + handle.handle_client(r_addr, CMD_CONNECT, data[1], data[2]) + handle.handle_client(r_addr, *data) + self.update_activity(handle) + else: + # disconnect + rsp_data = self._pack_rsp_data(CMD_DISCONNECT, data[1], RSP_STATE_EMPTY) + data_to_send = encrypt.encrypt_all(self._password, self._method, 1, rsp_data) + self.write_to_server_socket(data_to_send, r_addr) + else: + self.update_activity(self._reqid_to_hd[data[1]]) + self._reqid_to_hd[data[1]].handle_client(r_addr, *data) + else: + # disconnect + rsp_data = self._pack_rsp_data(CMD_DISCONNECT, data[1], RSP_STATE_EMPTY) + data_to_send = encrypt.encrypt_all(self._password, self._method, 1, rsp_data) + self.write_to_server_socket(data_to_send, r_addr) + elif data[0] > CMD_CONNECT_REMOTE and data[0] <= CMD_DISCONNECT: + if data[1] in self._reqid_to_hd: + if type(self._reqid_to_hd[data[1]]) is tuple: + pass + else: + self.update_activity(self._reqid_to_hd[data[1]]) + self._reqid_to_hd[data[1]].handle_client(r_addr, *data) + else: + # disconnect + rsp_data = self._pack_rsp_data(CMD_DISCONNECT, data[1], RSP_STATE_EMPTY) + data_to_send = encrypt.encrypt_all(self._password, self._method, 1, rsp_data) + self.write_to_server_socket(data_to_send, r_addr) + return + except Exception as e: + trace = traceback.format_exc() + logging.error(trace) + return + def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: