| 
						
						
							
								
							
						
						
					 | 
					@ -123,11 +123,33 @@ RSP_STATE_ERROR = b"\x03" | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					RSP_STATE_DISCONNECT = b"\x04" | 
					 | 
					 | 
					RSP_STATE_DISCONNECT = b"\x04" | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					RSP_STATE_REDIRECT = b"\x05" | 
					 | 
					 | 
					RSP_STATE_REDIRECT = b"\x05" | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					class UDPAsyncDNSHandler(object): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    def __init__(self, params): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        self.params = params | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        self.remote_addr = None | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        self.call_back = None | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    def resolve(self, dns_resolver, remote_addr, call_back): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        self.call_back = call_back | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        self.remote_addr = remote_addr | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        dns_resolver.resolve(remote_addr[0], self._handle_dns_resolved) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    def _handle_dns_resolved(self, result, error): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        if error: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            logging.error("%s when resolve DNS" % (error,)) #drop | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            return | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        if result: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            ip = result[1] | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            if ip: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                if self.call_back: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    self.call_back(*self.params, self.remote_addr, None, ip, True) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    return | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        logging.warning("can't resolve %s" % (self.remote_addr,)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					def client_key(source_addr, server_af): | 
					 | 
					 | 
					def client_key(source_addr, server_af): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    # notice this is server af, not dest af | 
					 | 
					 | 
					    # notice this is server af, not dest af | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    return '%s:%s:%d' % (source_addr[0], source_addr[1], server_af) | 
					 | 
					 | 
					    return '%s:%s:%d' % (source_addr[0], source_addr[1], server_af) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					class UDPRelay(object): | 
					 | 
					 | 
					class UDPRelay(object): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    def __init__(self, config, dns_resolver, is_local, stat_callback=None, stat_counter=None): | 
					 | 
					 | 
					    def __init__(self, config, dns_resolver, is_local, stat_callback=None, stat_counter=None): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        self._config = config | 
					 | 
					 | 
					        self._config = config | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -154,7 +176,7 @@ class UDPRelay(object): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        self._cache_dns_client = lru_cache.LRUCache(timeout=10, | 
					 | 
					 | 
					        self._cache_dns_client = lru_cache.LRUCache(timeout=10, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                                         close_callback=self._close_client_pair) | 
					 | 
					 | 
					                                         close_callback=self._close_client_pair) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        self._client_fd_to_server_addr = {} | 
					 | 
					 | 
					        self._client_fd_to_server_addr = {} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        self._dns_cache = lru_cache.LRUCache(timeout=1800) | 
					 | 
					 | 
					        #self._dns_cache = lru_cache.LRUCache(timeout=1800) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        self._eventloop = None | 
					 | 
					 | 
					        self._eventloop = None | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        self._closed = False | 
					 | 
					 | 
					        self._closed = False | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        self.server_transfer_ul = 0 | 
					 | 
					 | 
					        self.server_transfer_ul = 0 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -375,97 +397,98 @@ class UDPRelay(object): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        if header_result is None: | 
					 | 
					 | 
					        if header_result is None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            self._handel_protocol_error(r_addr, ogn_data) | 
					 | 
					 | 
					            self._handel_protocol_error(r_addr, ogn_data) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            return | 
					 | 
					 | 
					            return | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        connecttype, dest_addr, dest_port, header_length = header_result | 
					 | 
					 | 
					        connecttype, addrtype, dest_addr, dest_port, header_length = header_result | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        if self._is_local: | 
					 | 
					 | 
					        if self._is_local: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            connecttype = 3 | 
					 | 
					 | 
					            addrtype = 3 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            server_addr, server_port = self._get_a_server() | 
					 | 
					 | 
					            server_addr, server_port = self._get_a_server() | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        else: | 
					 | 
					 | 
					        else: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            server_addr, server_port = dest_addr, dest_port | 
					 | 
					 | 
					            server_addr, server_port = dest_addr, dest_port | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        if (connecttype & 7) == 3: | 
					 | 
					 | 
					        if (addrtype & 7) == 3: | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            addrs = self._dns_cache.get(server_addr, None) | 
					 | 
					 | 
					            handler = UDPAsyncDNSHandler((data, r_addr, uid, header_length)) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            handler.resolve(self._dns_resolver, (server_addr, server_port), self._handle_server_dns_resolved) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        else: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            self._handle_server_dns_resolved(data, r_addr, uid, header_length, (server_addr, server_port), None, server_addr, False) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    def _handle_server_dns_resolved(self, data, r_addr, uid, header_length, remote_addr, addrs, server_addr, dns_resolved): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					        try: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            server_port = remote_addr[1] | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            if addrs is None: | 
					 | 
					 | 
					            if addrs is None: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                # TODO async getaddrinfo | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                addrs = socket.getaddrinfo(server_addr, server_port, 0, | 
					 | 
					 | 
					                addrs = socket.getaddrinfo(server_addr, server_port, 0, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                                           socket.SOCK_DGRAM, socket.SOL_UDP) | 
					 | 
					 | 
					                                            socket.SOCK_DGRAM, socket.SOL_UDP) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					                if not addrs: | 
					 | 
					 | 
					            if not addrs: # drop | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					                    # drop | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    return | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                else: | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    self._dns_cache[server_addr] = addrs | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        else: | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            addrs = socket.getaddrinfo(server_addr, server_port, 0, | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                                       socket.SOCK_DGRAM, socket.SOL_UDP) | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            if not addrs: | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                # drop | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                return | 
					 | 
					 | 
					                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._forbidden_portset: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    if sa[1] in self._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_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) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        af, socktype, proto, canonname, sa = addrs[0] | 
					 | 
					 | 
					                self._sockets.add(client.fileno()) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        key = client_key(r_addr, af) | 
					 | 
					 | 
					                self._eventloop.add(client, eventloop.POLL_IN, self) | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					        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._forbidden_portset: | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                if sa[1] in self._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_dns = False | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            if len(data) > 20 and data[11:19] == 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))) | 
					 | 
					 | 
					                logging.debug('UDP port %5d sockets %d' % (self._listen_port, len(self._sockets))) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            if uid is None: | 
					 | 
					 | 
					                if uid is None: | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					                user_id = self._listen_port | 
					 | 
					 | 
					                    user_id = self._listen_port | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                else: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                    user_id = struct.unpack('<I', client_uid)[0] | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            else: | 
					 | 
					 | 
					            else: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                user_id = struct.unpack('<I', client_uid)[0] | 
					 | 
					 | 
					                client, client_uid = client_pair | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        else: | 
					 | 
					 | 
					            self._cache.clear(self._udp_cache_size) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            client, client_uid = client_pair | 
					 | 
					 | 
					            self._cache_dns_client.clear(16) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        self._cache.clear(self._udp_cache_size) | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        self._cache_dns_client.clear(16) | 
					 | 
					 | 
					            if self._is_local: | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					
 | 
					 | 
					 | 
					                ref_iv = [encrypt.encrypt_new_iv(self._method)] | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        if self._is_local: | 
					 | 
					 | 
					                self._protocol.obfs.server_info.iv = ref_iv[0] | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            ref_iv = [encrypt.encrypt_new_iv(self._method)] | 
					 | 
					 | 
					                data = self._protocol.client_udp_pre_encrypt(data) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            self._protocol.obfs.server_info.iv = ref_iv[0] | 
					 | 
					 | 
					                #logging.debug("%s" % (binascii.hexlify(data),)) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            data = self._protocol.client_udp_pre_encrypt(data) | 
					 | 
					 | 
					                data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 1, data, ref_iv) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            #logging.debug("%s" % (binascii.hexlify(data),)) | 
					 | 
					 | 
					                if not data: | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 1, data, ref_iv) | 
					 | 
					 | 
					                    return | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            else: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					                data = data[header_length:] | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            if not data: | 
					 | 
					 | 
					            if not data: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                return | 
					 | 
					 | 
					                return | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        else: | 
					 | 
					 | 
					        except Exception as e: | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            data = data[header_length:] | 
					 | 
					 | 
					            shell.print_exception(e) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        if not data: | 
					 | 
					 | 
					            logging.error("exception from user %d" % (user_id,)) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            return | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        try: | 
					 | 
					 | 
					        try: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            client.sendto(data, (server_addr, server_port)) | 
					 | 
					 | 
					            client.sendto(data, (server_addr, server_port)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            self.add_transfer_u(client_uid, len(data)) | 
					 | 
					 | 
					            self.add_transfer_u(client_uid, len(data)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            if client_pair is None: # new request | 
					 | 
					 | 
					            if client_pair is None: # new request | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                addr, port = client.getsockname()[:2] | 
					 | 
					 | 
					                addr, port = client.getsockname()[:2] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                common.connect_log('UDP data to %s:%d from %s:%d by UID %d' % | 
					 | 
					 | 
					                common.connect_log('UDP data to %s(%s):%d from %s:%d by user %d' % | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					                        (common.to_str(server_addr), server_port, addr, port, user_id)) | 
					 | 
					 | 
					                        (common.to_str(remote_addr[0]), common.to_str(server_addr), server_port, addr, port, user_id)) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        except IOError as e: | 
					 | 
					 | 
					        except IOError as e: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            err = eventloop.errno_from_exception(e) | 
					 | 
					 | 
					            err = eventloop.errno_from_exception(e) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            logging.warning('IOError sendto %s:%d by user %d' % (server_addr, server_port, user_id)) | 
					 | 
					 | 
					            logging.warning('IOError sendto %s:%d by user %d' % (server_addr, server_port, user_id)) | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -623,7 +646,7 @@ class UDPRelay(object): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        if self._closed: | 
					 | 
					 | 
					        if self._closed: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            self._cache.clear(0) | 
					 | 
					 | 
					            self._cache.clear(0) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            self._cache_dns_client.clear(0) | 
					 | 
					 | 
					            self._cache_dns_client.clear(0) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            self._dns_cache.sweep() | 
					 | 
					 | 
					            #self._dns_cache.sweep() | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            if self._eventloop: | 
					 | 
					 | 
					            if self._eventloop: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                self._eventloop.remove_periodic(self.handle_periodic) | 
					 | 
					 | 
					                self._eventloop.remove_periodic(self.handle_periodic) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                self._eventloop.remove(self._server_socket) | 
					 | 
					 | 
					                self._eventloop.remove(self._server_socket) | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -635,7 +658,7 @@ class UDPRelay(object): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            before_sweep_size = len(self._sockets) | 
					 | 
					 | 
					            before_sweep_size = len(self._sockets) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            self._cache.sweep() | 
					 | 
					 | 
					            self._cache.sweep() | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            self._cache_dns_client.sweep() | 
					 | 
					 | 
					            self._cache_dns_client.sweep() | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            self._dns_cache.sweep() | 
					 | 
					 | 
					            #self._dns_cache.sweep() | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            if before_sweep_size != len(self._sockets): | 
					 | 
					 | 
					            if before_sweep_size != len(self._sockets): | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                logging.debug('UDP port %5d sockets %d' % (self._listen_port, len(self._sockets))) | 
					 | 
					 | 
					                logging.debug('UDP port %5d sockets %d' % (self._listen_port, len(self._sockets))) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            self._sweep_timeout() | 
					 | 
					 | 
					            self._sweep_timeout() | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					
  |