def _handle_server_dns_resolved(self, error, remote_addr, server_addr, params): if error: return data, r_addr, uid, header_length, is_relay = params if uid is None: is_mu = False user_id = self._listen_port else: is_mu = True user_id = uid try: server_port = remote_addr[1] addrs = socket.getaddrinfo(server_addr, server_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if not addrs: # drop return af, socktype, proto, canonname, sa = addrs[0] server_addr = sa[0] key = client_key(r_addr, af) client_pair = self._cache.get(key, None) if client_pair is None: client_pair = self._cache_dns_client.get(key, None) if client_pair is None: if self._forbidden_iplist: if common.to_str(sa[0]) in self._forbidden_iplist: logging.debug('IP %s is in forbidden list, drop' % common.to_str(sa[0])) # drop return if self._disconnect_ipset: if common.to_str(sa[0]) in self._disconnect_ipset: logging.debug('IP %s is in disconnect list, drop' % common.to_str(sa[0])) # drop return if self._forbidden_portset: if sa[1] in self._forbidden_portset: logging.debug('Port %d is in forbidden list, reject' % sa[1]) # drop return if is_mu: if self.multi_user_table[uid]['_forbidden_iplist']: if common.to_str(sa[0]) in self.multi_user_table[uid]['_forbidden_iplist']: logging.debug('IP %s is in forbidden list, drop' % common.to_str(sa[0])) # drop return if self.multi_user_table[uid]['_disconnect_ipset']: if common.to_str(sa[0]) in self.multi_user_table[uid]['_disconnect_ipset']: logging.debug('IP %s is in disconnect list, drop' % common.to_str(sa[0])) # drop return if self.multi_user_table[uid]['_forbidden_portset']: if sa[1] in self.multi_user_table[uid]['_forbidden_portset']: logging.debug('Port %d is in forbidden list, reject' % sa[1]) # drop return client = socket.socket(af, socktype, proto) client_uid = uid client.setblocking(False) self._socket_bind_addr(client, af, is_relay) is_dns = False if len(data) > header_length + 13 and data[header_length + 4 : header_length + 12] == b"\x00\x01\x00\x00\x00\x00\x00\x00": is_dns = True else: pass if sa[1] == 53 and is_dns: #DNS logging.debug("DNS query %s from %s:%d" % (common.to_str(sa[0]), r_addr[0], r_addr[1])) self._cache_dns_client[key] = (client, uid) else: self._cache[key] = (client, uid) self._client_fd_to_server_addr[client.fileno()] = (r_addr, af) self._sockets.add(client.fileno()) self._eventloop.add(client, eventloop.POLL_IN, self) logging.debug('UDP port %5d sockets %d' % (self._listen_port, len(self._sockets))) if not self.is_pushing_detect_text_list: for id in self.detect_text_list: if common.match_regex( self.detect_text_list[id]['regex'], str(data)): if self._config['is_multi_user'] != 0 and uid != 0: if self.is_cleaning_mu_detect_log_list == False and id not in self.mu_detect_log_list[ uid]: self.mu_detect_log_list[uid].append(id) else: if self.is_cleaning_detect_log == False and id not in self.detect_log_list: self.detect_log_list.append(id) raise Exception( 'This connection match the regex: id:%d was reject,regex: %s ,connecting %s:%d from %s:%d via port %d' % (self.detect_text_list[id]['id'], self.detect_text_list[id]['regex'], common.to_str(server_addr), server_port, r_addr[0], r_addr[1], self._listen_port)) if not self.is_pushing_detect_hex_list: for id in self.detect_hex_list: if common.match_regex( self.detect_hex_list[id]['regex'], binascii.hexlify(data)): if self._config['is_multi_user'] != 0 and uid != 0: if self.is_cleaning_mu_detect_log_list == False and id not in self.mu_detect_log_list[ uid]: self.mu_detect_log_list[uid].append(id) else: if self.is_cleaning_detect_log == False and id not in self.detect_log_list: self.detect_log_list.append(id) raise Exception( 'This connection match the regex: id:%d was reject,regex: %s ,connecting %s:%d from %s:%d via port %d' % (self.detect_hex_list[id]['id'], self.detect_hex_list[id]['regex'], common.to_str(server_addr), server_port, r_addr[0], r_addr[1], self._listen_port)) if not self._connect_hex_data: common.connect_log('UDP data to %s:%d from %s:%d via port %d' % (common.to_str(server_addr), server_port, r_addr[0], r_addr[1], self._listen_port)) else: common.connect_log( 'UDP data to %s:%d from %s:%d via port %d,hex data : %s' % (common.to_str(server_addr), server_port, r_addr[0], r_addr[1], self._listen_port, binascii.hexlify(data))) if self._config['is_multi_user'] != 2: if common.to_str(r_addr[0]) in self.wrong_iplist and r_addr[ 0] != 0 and self.is_cleaning_wrong_iplist == False: del self.wrong_iplist[common.to_str(r_addr[0])] if common.getRealIp(r_addr[0]) not in self.connected_iplist and r_addr[ 0] != 0 and self.is_cleaning_connected_iplist == False: self.connected_iplist.append(common.getRealIp(r_addr[0])) else: client, client_uid = client_pair self._cache.clear(self._udp_cache_size) self._cache_dns_client.clear(16) if self._is_local: try: key, ref_iv, m = encrypt.gen_key_iv(self._password, self._method) self._protocol.obfs.server_info.iv = ref_iv[0] data = self._protocol.client_udp_pre_encrypt(data) #logging.debug("%s" % (binascii.hexlify(data),)) data = encrypt.encrypt_all_m(key, ref_iv, m, self._method, data) except Exception: logging.debug("UDP handle_server: encrypt data failed") return if not data: return else: data = data[header_length:] if not data: return except Exception as e: shell.print_exception(e) if self._config['verbose']: traceback.print_exc() logging.error("exception from user %d" % (user_id,)) try: client.sendto(data, (server_addr, server_port)) self.add_transfer_u(client_uid, len(data)) if client_pair is None: # new request addr, port = client.getsockname()[:2] common.connect_log('UDP data to %s(%s):%d from %s:%d by user %d' % (common.to_str(remote_addr[0]), common.to_str(server_addr), server_port, addr, port, user_id)) except IOError as e: err = eventloop.errno_from_exception(e) logging.warning('IOError sendto %s:%d by user %d' % (server_addr, server_port, user_id)) if err in (errno.EINPROGRESS, errno.EAGAIN): pass else: shell.print_exception(e)
def _handle_server(self): server = self._server_socket data, r_addr = server.recvfrom(BUF_SIZE) ogn_data = data if not data: logging.debug('UDP handle_server: data is empty') if self._stat_callback: self._stat_callback(self._listen_port, len(data)) uid = None if self._is_local: frag = common.ord(data[2]) if frag != 0: logging.warn('drop a message since frag is not 0') return else: data = data[3:] else: try: data, key, ref_iv = encrypt.decrypt_all(self._password, self._method, data) except Exception: logging.debug('UDP handle_server: decrypt data failed') return # decrypt data if not data: logging.debug('UDP handle_server: data is empty after decrypt') return ref_iv = [0] self._protocol.obfs.server_info.recv_iv = ref_iv[0] data, uid = self._protocol.server_udp_post_decrypt(data) if self._config['is_multi_user'] != 0 and data: if uid: if uid not in self.mu_server_transfer_ul: self.mu_server_transfer_ul[uid] = 0 if uid not in self.mu_server_transfer_dl: self.mu_server_transfer_dl[uid] = 0 if uid not in self.mu_connected_iplist: self.mu_connected_iplist[uid] = [] if uid not in self.mu_detect_log_list: self.mu_detect_log_list[uid] = [] if common.getRealIp(r_addr[0]) not in self.mu_connected_iplist[uid]: self.mu_connected_iplist[uid].append(common.getRealIp(r_addr[0])) else: raise Exception( 'This port is multi user in single port only,so The connection has been rejected, when connect from %s:%d via port %d' % (r_addr[0], r_addr[1], self._listen_port)) is_relay = False #logging.info("UDP data %s" % (binascii.hexlify(data),)) if not self._is_local: if not self._is_relay(r_addr, ogn_data, uid): data = pre_parse_header(data) data = self._pre_parse_udp_header(data) if data is None: return if isinstance(data, tuple): return # return self._handle_tcp_over_udp(data, r_addr) else: if self._config["is_multi_user"] == 0: data, is_relay = self._handel_normal_relay(r_addr, ogn_data) else: data, is_relay = self._handel_mu_relay(r_addr, ogn_data, uid) try: header_result = parse_header(data) except: self._handel_protocol_error(r_addr, ogn_data) return if header_result is None: self._handel_protocol_error(r_addr, ogn_data) return connecttype, addrtype, dest_addr, dest_port, header_length = header_result if self._is_local: addrtype = 3 server_addr, server_port = self._get_a_server() else: server_addr, server_port = dest_addr, dest_port if (addrtype & 7) == 3: af = common.is_ip(server_addr) if af == False: handler = common.UDPAsyncDNSHandler((data, r_addr, uid, header_length, is_relay)) handler.resolve(self._dns_resolver, (server_addr, server_port), self._handle_server_dns_resolved) else: self._handle_server_dns_resolved("", (server_addr, server_port), server_addr, (data, r_addr, uid, header_length, is_relay)) else: self._handle_server_dns_resolved("", (server_addr, server_port), server_addr, (data, r_addr, uid, header_length, is_relay))