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: ref_iv = [0] data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 0, data, ref_iv) # decrypt data if not data: logging.debug('UDP handle_server: data is empty after decrypt') return self._protocol.obfs.server_info.recv_iv = ref_iv[0] data, uid = self._protocol.server_udp_post_decrypt(data) #logging.info("UDP data %s" % (binascii.hexlify(data),)) if not self._is_local: data = pre_parse_header(data) if data is None: return 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)) 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)) else: self._handle_server_dns_resolved("", (server_addr, server_port), server_addr, (data, r_addr, uid, header_length))
def _handle_stage_addr(self, data): try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return if False and ord(data[0]) != 0x88: # force new header raise Exception('can not parse header') 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', 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) self._remote_udp = (connecttype != 0) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
def _handle_server(self): server = self._server_socket data, r_addr = server.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_server: data is empty') 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: data = encrypt.encrypt_all(self._password, self._method, 0, data) # decrypt data if not data: logging.debug('UDP handle_server: data is empty after decrypt') return if not self._is_local: data = pre_parse_header(data) if data is None: return header_result = parse_header(data) if header_result is None: return connecttype, dest_addr, dest_port, header_length = header_result if self._is_local: server_addr, server_port = self._get_a_server() key = client_key(r_addr[0], r_addr[1], dest_addr, dest_port) else: server_addr, server_port = dest_addr, dest_port addrs = socket.getaddrinfo(dest_addr, dest_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if addrs: af, socktype, proto, canonname, sa = addrs[0] key = client_key(r_addr[0], r_addr[1], af, 0) else: key = None 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)) addrs = socket.getaddrinfo(server_addr, server_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if addrs: af, socktype, proto, canonname, sa = addrs[0] 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 client = socket.socket(af, socktype, proto) client.setblocking(False) self._cache[key] = client self._client_fd_to_server_addr[client.fileno()] = r_addr else: # drop return self._sockets.add(client.fileno()) self._eventloop.add(client, eventloop.POLL_IN) if self._is_local: data = encrypt.encrypt_all(self._password, self._method, 1, data) if not data: return else: data = data[header_length:] if not data: return try: client.sendto(data, (server_addr, server_port)) except IOError as e: err = eventloop.errno_from_exception(e) 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))
def _handle_stage_addr(self, ogn_data, data): try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug("UDP associate") if self._local_sock.family == socket.AF_INET6: header = b"\x05\x00\x00\x04" else: header = b"\x05\x00\x00\x01" addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack(">H", port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error("unknown command %d", cmd) self.destroy() return before_parse_data = data if self._is_local: header_result = parse_header(data) else: if ( data is None or FORCE_NEW_PROTOCOL and common.ord(data[0]) != 0x88 and (~common.ord(data[0]) & 0xFF) != 0x88 ): data = self._handel_protocol_error(self._client_address, ogn_data) data = pre_parse_header(data) if data is None: data = self._handel_protocol_error(self._client_address, ogn_data) header_result = parse_header(data) if header_result is None: data = self._handel_protocol_error(self._client_address, ogn_data) header_result = parse_header(data) connecttype, remote_addr, remote_port, header_length = header_result logging.info( "%s connecting %s:%d from %s:%d" % ( (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) self._remote_udp = connecttype != 0 # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote self._write_to_sock((b"\x05\x00\x00\x01" b"\x00\x00\x00\x00\x10\x10"), self._local_sock) if CLIENT_NEW_PROTOCOL: rnd_len = random.randint(1, 32) total_len = 7 + rnd_len + len(data) data = b"\x88" + struct.pack(">H", total_len) + chr(rnd_len) + (b" " * (rnd_len - 1)) + data crc = (0xFFFFFFFF - binascii.crc32(data)) & 0xFFFFFFFF data += struct.pack("<I", crc) data = self._obfs.client_pre_encrypt(data) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config["verbose"]: traceback.print_exc() self.destroy()
def _handle_stage_addr(self, ogn_data, data): try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return before_parse_data = data if self._is_local: header_result = parse_header(data) else: if data is None or FORCE_NEW_PROTOCOL and common.ord( data[0]) != 0x88 and (~common.ord(data[0]) & 0xff) != 0x88: data = self._handel_protocol_error(self._client_address, ogn_data) data = pre_parse_header(data) if data is None: data = self._handel_protocol_error(self._client_address, ogn_data) header_result = parse_header(data) if header_result is None: data = self._handel_protocol_error(self._client_address, ogn_data) header_result = parse_header(data) connecttype, remote_addr, remote_port, header_length = header_result logging.info('%s connecting %s:%d from %s:%d' % ((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) self._remote_udp = (connecttype != 0) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) if CLIENT_NEW_PROTOCOL: rnd_len = random.randint(1, 32) total_len = 7 + rnd_len + len(data) data = b'\x88' + struct.pack( '>H', total_len) + chr(rnd_len) + (b' ' * (rnd_len - 1)) + data crc = (0xffffffff - binascii.crc32(data)) & 0xffffffff data += struct.pack('<I', crc) data = self._obfs.client_pre_encrypt(data) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
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: ref_iv = [0] data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 0, data, ref_iv) # decrypt data if not data: logging.debug('UDP handle_server: data is empty after decrypt') return 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.get_ip_md5( r_addr[0], self._config['ip_md5_salt'] ) not in self.mu_connected_iplist[uid]: self.mu_connected_iplist[uid].append( common.get_ip_md5(r_addr[0], self._config['ip_md5_salt'])) 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, dest_addr, dest_port, header_length = header_result if self._is_local: connecttype = 3 server_addr, server_port = self._get_a_server() else: server_addr, server_port = dest_addr, dest_port if (connecttype & 7) == 3: 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: # 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 af, socktype, proto, canonname, sa = addrs[0] key = client_key(r_addr, af) client_pair = self._cache.get(key, None) if not client_pair: client_pair = self._cache_dns_client.get(key, None) if not client_pair: 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_relay) 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 #logging.info("unknown data %s" % (binascii.hexlify(data),)) 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'], common.to_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.get_ip_md5( r_addr[0], self._config['ip_md5_salt'] ) not in self.connected_iplist and r_addr[ 0] != 0 and self.is_cleaning_connected_iplist == False: self.connected_iplist.append( common.get_ip_md5(r_addr[0], self._config['ip_md5_salt'])) else: client, client_uid = client_pair 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)] 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_iv(self._protocol.obfs.server_info.key, self._method, 1, data, ref_iv) if not data: return else: data = data[header_length:] if not data: return try: #logging.info('UDP handle_server sendto %s:%d %d bytes' % (common.to_str(server_addr), server_port, len(data))) client.sendto(data, (server_addr, server_port)) self.add_transfer_u(client_uid, len(data)) except IOError as e: err = eventloop.errno_from_exception(e) 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: ref_iv = [0] data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 0, data, ref_iv) # decrypt data if not data: logging.debug('UDP handle_server: data is empty after decrypt') return self._protocol.obfs.server_info.recv_iv = ref_iv[0] data, uid = self._protocol.server_udp_post_decrypt(data) #logging.info("UDP data %s" % (binascii.hexlify(data),)) if not self._is_local: data = pre_parse_header(data) data = self._pre_parse_udp_header(data) if data is None: return if type(data) is tuple: return #return self._handle_tcp_over_udp(data, r_addr) 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, dest_addr, dest_port, header_length = header_result if self._is_local: connecttype = 3 server_addr, server_port = self._get_a_server() else: server_addr, server_port = dest_addr, dest_port if (connecttype & 7) == 3: 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: # 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 af, socktype, proto, canonname, sa = addrs[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) > 20 and data[ 11:19] == b"\x00\x01\x00\x00\x00\x00\x00\x00": is_dns = True else: pass #logging.info("unknown data %s" % (binascii.hexlify(data),)) 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 uid is None: user_id = self._listen_port else: user_id = struct.unpack('<I', client_uid)[0] else: client, client_uid = client_pair 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)] 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_iv(self._protocol.obfs.server_info.key, self._method, 1, data, ref_iv) if not data: return else: data = data[header_length:] if not data: return try: #logging.info('UDP handle_server sendto %s:%d %d bytes' % (common.to_str(server_addr), server_port, len(data))) client.sendto(data, (server_addr, server_port)) if client_pair is None: # new request addr, port = client.getsockname()[:2] common.connect_log('UDP data to %s:%d from %s:%d by UID %d' % (common.to_str(server_addr), server_port, addr, port, user_id)) self.add_transfer_u(client_uid, len(data)) except IOError as e: err = eventloop.errno_from_exception(e) 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) if not data: logging.debug('UDP handle_server: data is empty') 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: data = encrypt.encrypt_all(self._password, self._method, 0, data) # decrypt data if not data: logging.debug('UDP handle_server: data is empty after decrypt') return if not self._is_local: data = pre_parse_header(data) if data is None: return header_result = parse_header(data) if header_result is None: return connecttype, dest_addr, dest_port, header_length = header_result if self._is_local: server_addr, server_port = self._get_a_server() else: server_addr, server_port = dest_addr, dest_port addrs = self._dns_cache.get(server_addr, None) if addrs is None: addrs = socket.getaddrinfo(server_addr, server_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if not addrs: # drop return else: self._dns_cache[server_addr] = addrs af, socktype, proto, canonname, sa = addrs[0] key = client_key(r_addr, af) logging.debug(key) 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' % common.to_str(sa[0])) # drop return client = socket.socket(af, socktype, proto) client.setblocking(False) self._cache[key] = client self._client_fd_to_server_addr[client.fileno()] = r_addr self._sockets.add(client.fileno()) self._eventloop.add(client, eventloop.POLL_IN) if self._is_local: data = encrypt.encrypt_all(self._password, self._method, 1, data) if not data: return else: data = data[header_length:] if not data: return try: client.sendto(data, (server_addr, server_port)) except IOError as e: err = eventloop.errno_from_exception(e) if err in (errno.EINPROGRESS, errno.EAGAIN): pass else: shell.print_exception(e)