def handle_event(self, sock, event): logging.debug("Running in the TCPRelayHandler class. [handle_event]") # handle all events in this handler and dispatch them to methods if self._stage == STAGE_DESTROYED: logging.debug('ignore handle_event: destroyed') return # order is important if sock == self._remote_sock: if event & eventloop.POLL_ERR: self._on_remote_error() if self._stage == STAGE_DESTROYED: return if event & (eventloop.POLL_IN | eventloop.POLL_HUP): self._on_remote_read() if self._stage == STAGE_DESTROYED: return if event & eventloop.POLL_OUT: self._on_remote_write() elif sock == self._local_sock: if event & eventloop.POLL_ERR: self._on_local_error() if self._stage == STAGE_DESTROYED: return if event & (eventloop.POLL_IN | eventloop.POLL_HUP): self._on_local_read() if self._stage == STAGE_DESTROYED: return if event & eventloop.POLL_OUT: self._on_local_write() else: logging.warn('unknown socket') common.error_to_file('unknown socket',self._config)
def handle_event(self, sock, fd, event): if sock == self._control_socket and event == eventloop.POLL_IN: data, self._control_client_addr = sock.recvfrom(BUF_SIZE) parsed = self._parse_command(data) if parsed: command, config = parsed a_config = self._config.copy() if config: a_config.update(config) if 'server_port' not in a_config: logging.error('can not find server_port in config', self._config) common.error_to_file('can not find server_port in config', self._config) else: if command == 'add': self.add_port(a_config) elif command == 'remove': self.remove_port(a_config) elif command == 'ping': self._send_control_data(b'pong') else: logging.error('unknown command %s' % command) common.error_to_file('unknown command %s' % command, self._config)
def handle_event(self, sock, fd, event): if sock == self._server_socket: if event & eventloop.POLL_ERR: logging.error('UDP server_socket err') common.error_to_file('UDP server_socket err', self._config) self._handle_server() elif sock and (fd in self._sockets): if event & eventloop.POLL_ERR: logging.error('UDP client_socket err') common.error_to_file('UDP client_socket err', self._config) if not self._is_local: if self._config.has_key('port_limit') and self._config[ 'port_limit'] != "" and os.path.exists( self._config['port_limit']): port_limits = json.loads( open(self._config['port_limit']).read()) if str(self._listen_port ) in port_limits and port_limits[ '%s' % self._listen_port]['used'] >= port_limits[ '%s' % self._listen_port]['total']: logging.warn( '[UDP] server listen port [%s] used traffic is over the setting value' % self._listen_port) self.close() self._handle_client(sock)
def _write_to_sock(self, data, sock): logging.debug("Running in the TCPRelayHandler class. [_write_to_sock]") # write data to sock # if only some of the data are written, put remaining in the buffer # and update the stream to wait for writing if not data or not sock: return False uncomplete = False try: l = len(data) if sock == self._local_sock and self._is_local and self._stage == STAGE_INIT: logging.info("[Client] Received data from browser and just sending 'hello' back to [browser] ! data length is: [%s]" % l) elif sock == self._remote_sock and self._is_local and self._stage == STAGE_STREAM: logging.info("[Client] Received data from browser and just sending -encrypted- data to [VPS] ! data length is: [%s]" % l) elif sock == self._local_sock and self._is_local and self._stage == STAGE_STREAM: logging.info("[Client] Received data from VPS and just sending -decrypted- data to [browser] ! data length is: [%s]" % l) elif sock == self._remote_sock and not self._is_local and self._stage == STAGE_STREAM: logging.info("[Server] Received data from client and going to send -decrypted- data to [INTERNET] ! data length is: [%s]" % l) elif sock == self._local_sock and not self._is_local and self._stage == STAGE_STREAM: logging.info("[Server] Received data from INTERNET and going to send -encrypted- data to [client] ! data length is: [%s]" % l) if self._config.has_key("limit"): if self._config['limit'].has_key(str(self._server._listen_port)): self._config['limit'][str(self._server._listen_port)]['used'] += l #if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']): # port_limits = json.loads(open(self._config['port_limit']).read()) # if str(self._server._listen_port) in port_limits: # port_limits['%s' % self._server._listen_port]['used'] = port_limits['%s' % self._server._listen_port]['used'] + l # open('%s' % self._config['port_limit'],"w").write("%s" % json.dumps(port_limits,indent=4,ensure_ascii=False,sort_keys=True)) s = sock.send(data) if s < l: data = data[s:] uncomplete = True except (OSError, IOError) as e: error_no = eventloop.errno_from_exception(e) if error_no in (errno.EAGAIN, errno.EINPROGRESS, errno.EWOULDBLOCK): uncomplete = True else: shell.print_exception(e) self.destroy() return False if uncomplete: if sock == self._local_sock: self._data_to_write_to_local.append(data) self._update_stream(STREAM_DOWN, WAIT_STATUS_WRITING) elif sock == self._remote_sock: self._data_to_write_to_remote.append(data) self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) else: logging.error('write_all_to_sock:unknown socket') common.error_to_file('write_all_to_sock:unknown socket',self._config) else: if sock == self._local_sock: self._update_stream(STREAM_DOWN, WAIT_STATUS_READING) elif sock == self._remote_sock: self._update_stream(STREAM_UP, WAIT_STATUS_READING) else: logging.error('write_all_to_sock:unknown socket') common.error_to_file('write_all_to_sock:unknown socket',self._config) return True
def _on_remote_error(self): logging.debug("Running in the TCPRelayHandler class. [_on_remote_error]") logging.warn('got remote error') common.error_to_file('got remote error',self._config) if self._remote_sock: logging.error(eventloop.get_sock_error(self._remote_sock)) common.error_to_file(eventloop.get_sock_error(self._remote_sock),self._config) self.destroy()
def _write_to_sock(self, data, sock): logging.debug("Running in the TCPRelayHandler class. [_write_to_sock]") # write data to sock # if only some of the data are written, put remaining in the buffer # and update the stream to wait for writing if not data or not sock: return False uncomplete = False try: l = len(data) if sock == self._local_sock and self._is_local and self._stage == STAGE_INIT: logging.info("[Client] Received data from browser and just sending 'hello' back to [browser] ! data length is: [%s]" % l) elif sock == self._remote_sock and self._is_local and self._stage == STAGE_STREAM: logging.info("[Client] Received data from browser and just sending -encrypted- data to [VPS] ! data length is: [%s]" % l) elif sock == self._local_sock and self._is_local and self._stage == STAGE_STREAM: logging.info("[Client] Received data from VPS and just sending -decrypted- data to [browser] ! data length is: [%s]" % l) elif sock == self._remote_sock and not self._is_local and self._stage == STAGE_STREAM: logging.info("[Server] Received data from client and going to send -decrypted- data to [INTERNET] ! data length is: [%s]" % l) elif sock == self._local_sock and not self._is_local and self._stage == STAGE_STREAM: logging.info("[Server] Received data from INTERNET and going to send -encrypted- data to [client] ! data length is: [%s]" % l) if not self._is_local: if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']): port_limits = json.loads(open(self._config['port_limit']).read()) if str(self._server._listen_port) in port_limits: port_limits['%s' % self._server._listen_port]['used'] = port_limits['%s' % self._server._listen_port]['used'] + len(data) open('%s' % self._config['port_limit'],"w").write("%s" % json.dumps(port_limits,indent=4,ensure_ascii=False,sort_keys=True)) s = sock.send(data) if s < l: data = data[s:] uncomplete = True except (OSError, IOError) as e: error_no = eventloop.errno_from_exception(e) if error_no in (errno.EAGAIN, errno.EINPROGRESS, errno.EWOULDBLOCK): uncomplete = True else: shell.print_exception(e) self.destroy() return False if uncomplete: if sock == self._local_sock: self._data_to_write_to_local.append(data) self._update_stream(STREAM_DOWN, WAIT_STATUS_WRITING) elif sock == self._remote_sock: self._data_to_write_to_remote.append(data) self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) else: logging.error('write_all_to_sock:unknown socket') common.error_to_file('write_all_to_sock:unknown socket',self._config) else: if sock == self._local_sock: self._update_stream(STREAM_DOWN, WAIT_STATUS_READING) elif sock == self._remote_sock: self._update_stream(STREAM_UP, WAIT_STATUS_READING) else: logging.error('write_all_to_sock:unknown socket') common.error_to_file('write_all_to_sock:unknown socket',self._config) return True
def remove_port(self, config): port = int(config['server_port']) servers = self._relays.get(port, None) if servers: logging.info("removing server at %s:%d" % (config['server'], port)) t, u = servers t.close(next_tick=False) u.close(next_tick=False) del self._relays[port] else: logging.error("server not exist at %s:%d" % (config['server'], port)) common.error_to_file( "server not exist at %s:%d" % (config['server'], port), self._config)
def _parse_command(self, data): # commands: # add: {"server_port": 8000, "password": "******"} # remove: {"server_port": 8000"} data = common.to_str(data) parts = data.split(':', 1) if len(parts) < 2: return data, None command, config_json = parts try: config = json.loads(config_json) return command, config except Exception as e: logging.error(e) common.error_to_file('%s' % str(e), self._config) return None
def __init__(self, config, dns_resolver, is_local, stat_callback=None): logging.debug("Running in the TCPRelay class. [init]") self._config = config self._config_file = "config.json" self._is_local = is_local self._dns_resolver = dns_resolver self._closed = False self._eventloop = None self._fd_to_handlers = {} self._check_need_save_config_timestamp = "check_point" self._timeout = config['timeout'] self._timeouts = [] # a list for all the handlers # we trim the timeouts once a while self._timeout_offset = 0 # last checked position for timeout self._handler_to_timeouts = {} # key: handler value: index in timeouts self._config_tmp = {} if is_local: listen_addr = config['local_address'] listen_port = config['local_port'] else: listen_addr = config['server'] listen_port = config['server_port'] self._listen_port = listen_port addrs = socket.getaddrinfo( listen_addr, listen_port, 0, socket.SOCK_STREAM, socket.SOL_TCP) if len(addrs) == 0: raise Exception("can't get addrinfo for %s:%d" % (listen_addr, listen_port)) af, socktype, proto, canonname, sa = addrs[0] server_socket = socket.socket(af, socktype, proto) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(sa) server_socket.setblocking(False) if config['fast_open']: try: server_socket.setsockopt(socket.SOL_TCP, 23, 5) except socket.error: logging.error('warning: fast open is not available') common.error_to_file('warning: fast open is not available',self._config) self._config['fast_open'] = False server_socket.listen(1024) self._server_socket = server_socket self._stat_callback = stat_callback
def handle_event(self, sock, fd, event): if sock == self._server_socket: if event & eventloop.POLL_ERR: logging.error('UDP server_socket err') common.error_to_file('UDP server_socket err',self._config) self._handle_server() elif sock and (fd in self._sockets): if event & eventloop.POLL_ERR: logging.error('UDP client_socket err') common.error_to_file('UDP client_socket err',self._config) if not self._is_local: if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']): port_limits = json.loads(open(self._config['port_limit']).read()) if str(self._listen_port) in port_limits and port_limits['%s' % self._listen_port]['used'] >= port_limits['%s' % self._listen_port]['total']: logging.warn('[UDP] server listen port [%s] used traffic is over the setting value' % self._listen_port) self.close() self._handle_client(sock)
def handle_event(self, sock, fd, event): logging.debug("Running in the TCPRelay class....[_handle_events]") if not self._is_local: if self._config.has_key("limit"): if self._config['limit'].has_key(str(self._listen_port)): if int(self._config['limit'][str(self._listen_port)]['total']) > 0: if self._config['limit'][str(self._listen_port)]['used'] >= self._config['limit'][str(self._listen_port)]['total']: logging.error('[TCP] server listen port [%s] used traffic is over the setting value' % self._listen_port) self.close() #if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']): # port_limits = json.loads(open(self._config['port_limit']).read()) # if str(self._listen_port) in port_limits and port_limits['%s' % self._listen_port]['used'] >= port_limits['%s' % self._listen_port]['total']: # logging.warn('[TCP] server listen port [%s] used traffic is over the setting value' % self._listen_port) # self.close() # handle events and dispatch to handlers if sock: logging.debug("LOGGING fd %d %s" % (fd, eventloop.EVENT_NAMES.get(event, event))) if sock == self._server_socket: if event & eventloop.POLL_ERR: # TODO raise Exception('server_socket error') common.error_to_file("server_socket error",self._config) try: logging.debug('accept') conn = self._server_socket.accept() TCPRelayHandler(self, self._fd_to_handlers, self._eventloop, conn[0], self._config, self._dns_resolver, self._is_local) except (OSError, IOError) as e: error_no = eventloop.errno_from_exception(e) if error_no in (errno.EAGAIN, errno.EINPROGRESS, errno.EWOULDBLOCK): return else: shell.print_exception(e) if self._config['verbose']: traceback.print_exc() else: if sock: handler = self._fd_to_handlers.get(fd, None) if handler: handler.handle_event(sock, event) else: logging.warn('poll removed fd') common.error_to_file('poll removed fd',self._config)
def add_port(self, config): port = int(config['server_port']) servers = self._relays.get(port, None) if servers: logging.error("server already exists at %s:%d" % (config['server'], port)) common.error_to_file( "server already exists at %s:%d" % (config['server'], port), self._config) return logging.info("adding server at %s:%d" % (config['server'], port)) t = tcprelay.TCPRelay(config, self._dns_resolver, False, self.stat_callback) u = udprelay.UDPRelay(config, self._dns_resolver, False, self.stat_callback) t.add_to_loop(self._loop) u.add_to_loop(self._loop) self._relays[port] = (t, u)
def __init__(self, config, dns_resolver, is_local, stat_callback=None): logging.debug("Running in the TCPRelay class. [init]") self._config = config self._is_local = is_local self._dns_resolver = dns_resolver self._closed = False self._eventloop = None self._fd_to_handlers = {} self._timeout = config['timeout'] self._timeouts = [] # a list for all the handlers # we trim the timeouts once a while self._timeout_offset = 0 # last checked position for timeout self._handler_to_timeouts = {} # key: handler value: index in timeouts if is_local: listen_addr = config['local_address'] listen_port = config['local_port'] else: listen_addr = config['server'] listen_port = config['server_port'] self._listen_port = listen_port addrs = socket.getaddrinfo( listen_addr, listen_port, 0, socket.SOCK_STREAM, socket.SOL_TCP) if len(addrs) == 0: raise Exception("can't get addrinfo for %s:%d" % (listen_addr, listen_port)) af, socktype, proto, canonname, sa = addrs[0] server_socket = socket.socket(af, socktype, proto) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(sa) server_socket.setblocking(False) if config['fast_open']: try: server_socket.setsockopt(socket.SOL_TCP, 23, 5) except socket.error: logging.error('warning: fast open is not available') common.error_to_file('warning: fast open is not available',self._config) self._config['fast_open'] = False server_socket.listen(1024) self._server_socket = server_socket self._stat_callback = stat_callback
def handle_event(self, sock, fd, event): if sock != self._sock: return if event & eventloop.POLL_ERR: logging.error('dns socket err') common.error_to_file('dns socket err',self._config) self._loop.remove(self._sock, self) self._sock.close() # TODO when dns server is IPv6 self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.SOL_UDP) self._sock.setblocking(False) self._loop.add(self._sock, eventloop.POLL_IN, self) else: data, addr = sock.recvfrom(1024) if addr[0] not in self._servers: logging.warn('received a packet other than our dns') common.error_to_file('received a packet other than our dns',self._config) return self._handle_data(data)
def handle_event(self, sock, fd, event): if sock != self._sock: return if event & eventloop.POLL_ERR: logging.error('dns socket err') common.error_to_file('dns socket err', self._config) self._loop.remove(self._sock, self) self._sock.close() # TODO when dns server is IPv6 self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.SOL_UDP) self._sock.setblocking(False) self._loop.add(self._sock, eventloop.POLL_IN, self) else: data, addr = sock.recvfrom(1024) if addr[0] not in self._servers: logging.warn('received a packet other than our dns') common.error_to_file('received a packet other than our dns', self._config) return self._handle_data(data)
def handle_event(self, sock, fd, event): logging.debug("Running in the TCPRelay class....[_handle_events]") # handle events and dispatch to handlers if sock: logging.debug("LOGGING fd %d %s" % (fd, eventloop.EVENT_NAMES.get(event, event))) if not self._is_local: if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']): port_limits = json.loads(open(self._config['port_limit']).read()) if str(self._listen_port) in port_limits and port_limits['%s' % self._listen_port]['used'] >= port_limits['%s' % self._listen_port]['total']: logging.warn('[TCP] server listen port [%s] used traffic is over the setting value' % self._listen_port) self.close() if sock == self._server_socket: if event & eventloop.POLL_ERR: # TODO raise Exception('server_socket error') common.error_to_file("server_socket error",self._config) try: logging.debug('accept') conn = self._server_socket.accept() TCPRelayHandler(self, self._fd_to_handlers, self._eventloop, conn[0], self._config, self._dns_resolver, self._is_local) except (OSError, IOError) as e: error_no = eventloop.errno_from_exception(e) if error_no in (errno.EAGAIN, errno.EINPROGRESS, errno.EWOULDBLOCK): return else: shell.print_exception(e) if self._config['verbose']: traceback.print_exc() else: if sock: handler = self._fd_to_handlers.get(fd, None) if handler: handler.handle_event(sock, event) else: logging.warn('poll removed fd') common.error_to_file('poll removed fd',self._config)
def _sweep_timeout(self): logging.debug("Running in the TCPRelay class [_sweep_timeout]") # tornado's timeout memory management is more flexible than we need # we just need a sorted last_activity queue and it's faster than heapq # in fact we can do O(1) insertion/remove so we invent our own if self._timeouts: logging.debug("LOGGING sweeping timeouts") now = time.time() length = len(self._timeouts) # print("length of server._timeouts is: %s" % length) pos = self._timeout_offset while pos < length: handler = self._timeouts[pos] if handler: if now - handler.last_activity < self._timeout: break else: if handler.remote_address: logging.warn('timed out: %s:%d' % (handler.remote_address)) common.error_to_file('timed out: %s:%d' % (handler.remote_address),self._config) else: logging.warn('timed out some handler') common.error_to_file('timed out some handler',self._config) handler.destroy() self._timeouts[pos] = None # free memory pos += 1 else: pos += 1 if pos > TIMEOUTS_CLEAN_SIZE and pos > length >> 1: # clean up the timeout queue when it gets larger than half # of the queue self._timeouts = self._timeouts[pos:] for key in self._handler_to_timeouts: self._handler_to_timeouts[key] -= pos pos = 0 self._timeout_offset = pos
def _handle_stage_connecting(self, data): logging.debug("Running in the TCPRelayHandler class. [_handle_stage_connecting]") if self._is_local: data = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data) if self._is_local and not self._fastopen_connected and self._config['fast_open']: # for sslocal and fastopen, we basically wait for data and use # sendto to connect try: # only connect once self._fastopen_connected = True remote_sock = self._create_remote_socket( self._chosen_server[0], self._chosen_server[1]) self._loop.add(remote_sock, eventloop.POLL_ERR, self._server) data = b''.join(self._data_to_write_to_remote) l = len(data) s = remote_sock.sendto(data, MSG_FASTOPEN, self._chosen_server) if s < l: data = data[s:] self._data_to_write_to_remote = [data] else: self._data_to_write_to_remote = [] self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING) except (OSError, IOError) as e: if eventloop.errno_from_exception(e) == errno.EINPROGRESS: # in this case data is not sent at all self._update_stream(STREAM_UP, WAIT_STATUS_READWRITING) elif eventloop.errno_from_exception(e) == errno.ENOTCONN: logging.error('fast open not supported on this OS') common.error_to_file('fast open not supported on this OS',self._config) self._config['fast_open'] = False self.destroy() else: shell.print_exception(e) if self._config['verbose']: traceback.print_exc() self.destroy()
def __init__(self, config): self._config = config self._relays = {} # (tcprelay, udprelay) self._loop = eventloop.EventLoop() self._dns_resolver = asyncdns.DNSResolver() self._dns_resolver.add_to_loop(self._loop) self._statistics = collections.defaultdict(int) self._control_client_addr = None try: manager_address = config['manager_address'] if ':' in manager_address: addr = manager_address.split(':') addr = addr[0], int(addr[1]) family = socket.AF_INET else: addr = manager_address family = socket.AF_UNIX self._control_socket = socket.socket(family, socket.SOCK_DGRAM) self._control_socket.bind(addr) self._control_socket.setblocking(False) except (OSError, IOError) as e: logging.error(e) logging.error('can not bind to manager address') common.error_to_file('can not bind to manager address', self._config) exit(1) self._loop.add(self._control_socket, eventloop.POLL_IN, self) self._loop.add_periodic(self.handle_periodic) port_password = config['port_password'] del config['port_password'] for port, password in port_password.items(): a_config = config.copy() a_config['server_port'] = int(port) a_config['password'] = password self.add_port(a_config)
def _log_error(self, e): logging.error('%s when handling connection from %s:%d' % ( common.to_str(e.message), self._client_address[0], self._client_address[1])) common.error_to_file('%s when handling connection from %s:%d' % (common.to_str(e.message), self._client_address[0], self._client_address[1]),self._config)
def _handle_stage_addr(self, data): logging.debug("Running in the TCPRelayHandler class. [_handle_stage_addr]") 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) common.error_to_file('unknown command %d' % cmd,self._config) self.destroy() return header_result = parse_header(data,self._config) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d from %s:%d' % (common.to_str( remote_addr), remote_port, self._client_address[0], self._client_address[1])) if self._server._listen_port in self._config['forbid']['port']: for i in self._config['forbid']['site']: if str(i) in common.to_str(remote_addr): self.destroy() try: if common.to_str(self._config['log']['log_enable']) == "True": log_str_one_line = '''[%s]\t%s:%d\t%s:%d [server_port: %s]\n''' % (time.strftime( "%Y-%m-%d %H:%M:%S"), common.to_str(remote_addr), remote_port, self._client_address[0], self._client_address[1],self._server._listen_port) log_str_buf.append(log_str_one_line) if os.path.exists(os.path.split(self._config['log']['log_path'])[0]) is False: os.makedirs(os.path.split(self._config['log']['log_path'])[0]) if len(log_str_buf) == 10: f = open("%s" % self._config['log']['log_path'], 'a+') f.write("".join(log_str_buf)) f.close() del log_str_buf[:] except Exception as e: logging.error( "Sorry.Some ERROR happend when I try to log something to file : info: %s" % str(e)) common.error_to_file("Sorry.Some ERROR happend when I try to log something to file : info: %s" % str(e),self._config) self._remote_address = (common.to_str(remote_addr), remote_port) # 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() # TODO use logging when debug completed 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') common.error_to_file('drop a message since frag is not 0',self._config) 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 header_result = parse_header(data,self._config) if header_result is None: return addrtype, 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) 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, self) if self._stat_callback: self._stat_callback(self._listen_port, len(data)) 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)) if not self._is_local: if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']): port_limits = json.loads(open(self._config['port_limit']).read()) if str(self._listen_port) in port_limits: port_limits['%s' % self._listen_port]['used'] = port_limits['%s' % self._listen_port]['used'] + len(data) + BUF_SIZE open('%s' % self._config['port_limit'],"w").write("%s" % json.dumps(port_limits,indent=4,ensure_ascii=False,sort_keys=True)) except IOError as e: err = eventloop.errno_from_exception(e) if err in (errno.EINPROGRESS, errno.EAGAIN): pass else: shell.print_exception(e)