def socks_auth(self, client_sock : socket.socket, client_addr : Tuple[str, int]): """ Initial greeting from client: +---------------------+ | VER | LEN | METHODS | +---------------------+ """ future = Future() reg_socket_future_read(future, client_sock) yield future greeting : bytes = client_sock.recv(4096) if greeting == b'shutdown': raise ShutdownException('') try: ver, length, methods = decode_greating(greeting) if not ver == 5 or 0 not in methods: return except ValueError as e: raise e """ The server's choice is communicated: +-----+--------+ | VER | METHOD | +--------------+ """ client_sock.send(bytes([5, 0])) future = Future() reg_socket_future_write(future, client_sock) yield future
def wait_client_connection(self, remote_socks: List[socket.socket]): future = Future() reg_multi_sockets_future_read(future, remote_socks) remote_sock = yield future local_sock, local_addr = remote_sock.accept() local_sock.setblocking(False) logging.info("Connection from %s:%d to %s:%d" % (local_addr + remote_sock.getsockname())) self.loop.add_event(self.local_handle(local_sock, local_addr))
def wait_client_connection(self, local_socks: List[socket.socket]): future = Future() reg_multi_sockets_future_read(future, local_socks) local_sock = yield future client_sock, client_addr = local_sock.accept() client_sock.setblocking(False) listen_ip, listen_port = client_sock.getsockname() dest_addr = self.port_to_address[listen_port] self.loop.add_event(self.client_handle(client_sock, client_addr, dest_addr))
def wait_client_connection(self, local_sock: socket.socket): future = Future() reg_socket_future_read(future, local_sock) yield future client_sock, client_addr = local_sock.accept() print(client_addr) print(client_sock.getsockname()) client_sock.setblocking(False) logging.info("Connection from %s:%s" % client_addr) self.loop.add_event(self.client_handle(client_sock, client_addr))
def local_relay(self, client_sock : socket.socket, client_addr : Tuple[str, int], dest_addr: Tuple[str, int] ): try: remote_sock = socket.socket() remote_sock.setblocking(False) try: if isinstance(self.remote_port, int): remote_sock.connect((self.remote_ip, self.remote_port)) elif isinstance(self.remote_port, list): port_choice = self.select_port(self.remote_port) remote_sock.connect((self.remote_ip, port_choice)) else: raise ValueError(self.remote_port) except BlockingIOError as e: pass logging.info("connected to %s" % (remote_sock.getsockname(),)) future = Future() reg_socket_future_write(future, remote_sock) yield future sock_addr = create_socks_addr(*dest_addr) remote_sock.send(self.encryptor.encode(sock_addr, 0)) len_sock_addr = len(sock_addr) def client_data_to_local_data(data : bytes, offset : int): return self.encryptor.encode(data, offset + len_sock_addr), 0 def local_data_to_client_data(data : bytes, offset : int): # return self.encryptor.decode(data, offset) decoded = self.encryptor.decode(data, offset) #logging.debug("data get from remote (%d, %d):\n%s" % (offset, len(decoded), decoded)) return decoded, 0 relay_start = time.time() yield from relay(client_sock, remote_sock, client_data_to_local_data, local_data_to_client_data) logging.info("[%s:%d] for %r relay used %f" % (client_addr + (dest_addr, time.time() - relay_start))) except ValueError as e: logging.error(str(e)) traceback.print_exc()
def relay_connection(self, client_sock : socket.socket, client_addr : Tuple[str, int]): """ Address: [1-byte type][variable-length host][2-byte port] The client's connection request is: +-----+----------+----------+-----------+-----------+----------+ | VER | CMD CODE | RESERVED | ADDR TYPE | DEST TYPE | PORT NUM | +-----+----------+----------+-----------+-----------+----------+ """ future = Future() reg_socket_future_read(future, client_sock) yield future check_socket(client_sock) request_bytes = client_sock.recv(4096) try: logging.debug(str(decode_connection_request(request_bytes))) except: pass yield from self.local_relay(client_sock, client_addr, request_bytes)
def relay( sock1: socket.socket, sock2: socket.socket, sock1_data_to_sock2_data=lambda x, offset: (x, 0), sock2_data_to_sock1_data=lambda x, offset: (x, 0), ): def relay_callback(source_sock, tg_sock, event_key, event_mask): future.set_result((source_sock, tg_sock, event_key, event_mask)) data_queues = {sock1.fileno(): [], sock2.fileno(): []} data_offset = {sock1.fileno(): 0, sock2.fileno(): 0} try: stopped = 0 while True: future = Future() register_read_write( sock1, lambda k, m: relay_callback(sock1, sock2, k, m)) register_read_write( sock2, lambda k, m: relay_callback(sock2, sock1, k, m)) source_sock, tg_sock, event_key, event_mask = yield future unregister(sock1) unregister(sock2) try: if event_mask & EVENT_WRITE != 0: # If a write is ready, write the corresponding data to it if len(data_queues[source_sock.fileno()]) > 0: data = data_queues[source_sock.fileno()][0] check_socket(source_sock) sent = source_sock.send(data) # if source_sock.fileno() == sock2.fileno(): # logging.debug("data sent to sock2 (%d):\n%s" % (sent, data[0 : sent])) if sent < len(data): data_queues[source_sock.fileno()][0] = data[sent:] else: data_queues[source_sock.fileno()].pop(0) #logging.debug("sent %d" % len(data)) if event_mask & EVENT_READ != 0: check_socket(source_sock) data = source_sock.recv(4096) if len(data) == 0: stopped += 1 if stopped >= 2: break if tg_sock.fileno() == sock2.fileno(): encoded_data, adjust = sock1_data_to_sock2_data( data, data_offset[sock1.fileno()]) data_offset[sock1.fileno()] += len(data) + adjust else: encoded_data, adjust = sock2_data_to_sock1_data( data, data_offset[sock2.fileno()]) data_offset[sock2.fileno()] += len(data) + adjust data_queues[tg_sock.fileno()].append(encoded_data) except IOError as e: if e.errno == errno.EWOULDBLOCK: pass elif e.errno == errno.ENOTCONN: pass elif e.errno == errno.EAGAIN: pass else: logging.error("relay IOError: %s" % e) break finally: check_socket(sock1) check_socket(sock2) sock1.close() sock2.close()
def local_relay(self, client_sock : socket.socket, client_addr : Tuple[str, int], request_bytes): try: try: ver, cmd_code, addr_type, dest_addr, port = decode_connection_request(request_bytes) if addr_type == 3: logging.info("[%s:%d] for %r" % (client_addr + (dest_addr,))) elif addr_type == 1: logging.info("[%s:%d] for [%s:%r]" % (client_addr + (bytes_ip_to_string(dest_addr), port))) except Exception as e: raise ValueError("Invalid request bytes %r from %s:%d" % ((request_bytes,) + client_addr)) remote_sock = socket.socket() remote_sock.setblocking(False) try: if isinstance(self.remote_port, int): remote_sock.connect((self.remote_ip, self.remote_port)) elif isinstance(self.remote_port, list): port_choice = self.select_port(self.remote_port) remote_sock.connect((self.remote_ip, port_choice)) else: raise ValueError(self.remote_port) except BlockingIOError as e: pass logging.info("connected to %s" % (remote_sock.getsockname(),)) future = Future() reg_socket_future_write(future, remote_sock) yield future future = Future() reg_socket_future_write(future, client_sock) yield future sock_name = client_sock.getsockname() client_hex_addr = socket.inet_aton(sock_name[0]) client_hex_port = port_to_hex_string(sock_name[1]) #response = encode_connection_repsonse(ver, 0, addr_type, dest_addr, port) response = b'\x05\x00\x00\x01' + client_hex_addr + client_hex_port logging.info("req bytes: %r" % request_bytes) logging.info("response: %r" % response) check_socket(client_sock) client_sock.send(response) sock_addr = get_socks_addr_bytes_from_request(request_bytes) remote_sock.send(self.encryptor.encode(sock_addr, 0)) len_sock_addr = len(sock_addr) def client_data_to_local_data(data : bytes, offset : int): return self.encryptor.encode(data, offset + len_sock_addr), 0 def local_data_to_client_data(data : bytes, offset : int): # return self.encryptor.decode(data, offset) decoded = self.encryptor.decode(data, offset) #logging.debug("data get from remote (%d, %d):\n%s" % (offset, len(decoded), decoded)) return decoded, 0 relay_start = time.time() yield from relay(client_sock, remote_sock, client_data_to_local_data, local_data_to_client_data) logging.info("[%s:%d] for %r relay used %f" % (client_addr + (dest_addr, time.time() - relay_start))) except ValueError as e: logging.error(str(e)) traceback.print_exc()