def on_incoming_from_tunnel(self, community, circuit, origin, data): """ We received some data from the tunnel community. Dispatch it to the right UDP SOCKS5 socket. """ if circuit.ctype in [CIRCUIT_TYPE_RP_DOWNLOADER, CIRCUIT_TYPE_RP_SEEDER]: origin = (community.circuit_id_to_ip(circuit.circuit_id), CIRCUIT_ID_PORT) try: connection = self.cid_to_con[circuit.circuit_id] except KeyError: session_hops = circuit.goal_hops if circuit.ctype != CIRCUIT_TYPE_RP_DOWNLOADER else circuit.goal_hops - 1 if session_hops > len(self.socks_servers) or not self.socks_servers[session_hops - 1].sessions: self._logger.error("No connection found for %d hops", session_hops) return False connection = next((s for s in self.socks_servers[session_hops - 1].sessions if s.udp_connection and s.udp_connection.remote_udp_address), None) if connection is None or connection.udp_connection is None: self._logger.error("Connection has closed or has not gotten an UDP associate") self.connection_dead(connection) return False packet = socks5_serializer.pack_serializable(UdpPacket(0, 0, origin, data)) connection.udp_connection.send_datagram(packet) return True
def sendto(self, data, target_addr): try: ipaddress.IPv4Address(target_addr[0]) except ipaddress.AddressValueError: target_addr = DomainAddress(*target_addr) packet = socks5_serializer.pack_serializable(UdpPacket(0, 0, target_addr, data)) self.transport.sendto(packet, self.proxy_udp_addr)
async def _login(self): self.transport, _ = await get_event_loop().create_connection(lambda: self, *self.proxy_addr) request = MethodsRequest(SOCKS_VERSION, [SOCKS_AUTH_ANON]) data = await self._send(socks5_serializer.pack_serializable(request)) response, _ = socks5_serializer.unpack_serializable(MethodsResponse, data) if response.version != SOCKS_VERSION or response.method != SOCKS_AUTH_ANON: raise Socks5Error('Unsupported proxy server')
def test_encode_decode_udp_packet(): rsv = 0 frag = 0 address = DomainAddress('tracker1.good-tracker.com', 8084) data = b'0x000' encoded = socks5_serializer.pack_serializable( UdpPacket(rsv, frag, address, data)) decoded, _ = socks5_serializer.unpack_serializable(UdpPacket, encoded) assert rsv == decoded.rsv assert frag == decoded.frag assert address == decoded.destination address = DomainAddress('tracker1.unicode-tracker\xc4\xe95\x11$\x00', 8084) encoded = socks5_serializer.pack_serializable( UdpPacket(rsv, frag, address, data)) decoded, _ = socks5_serializer.unpack_serializable(UdpPacket, encoded) assert rsv == decoded.rsv assert frag == decoded.frag assert address == decoded.destination
def test_encode_decode_command_request(): rsv = 0 address = DomainAddress('tracker1.good-tracker.com', 8084) rep = 0 version = 5 encoded = socks5_serializer.pack_serializable( CommandRequest(version, rep, rsv, address)) decoded, _ = socks5_serializer.unpack_serializable(CommandRequest, encoded) assert version == decoded.version assert rsv == decoded.rsv assert address == decoded.destination address = DomainAddress('tracker1.unicode-tracker\xc4\xe95\x11$\x00', 8084) encoded = socks5_serializer.pack_serializable( CommandResponse(version, rep, rsv, address)) decoded, _ = socks5_serializer.unpack_serializable(CommandResponse, encoded) assert version == decoded.version assert rsv == decoded.rsv assert address == decoded.bind
async def _connect_tcp(self, target_addr): try: socket.inet_aton(target_addr[0]) except (ValueError, OSError): target_addr = DomainAddress(*target_addr) request = CommandRequest(SOCKS_VERSION, REQ_CMD_CONNECT, 0, target_addr) data = await self._send(socks5_serializer.pack_serializable(request)) response, _ = socks5_serializer.unpack_serializable(CommandResponse, data) if response.version != SOCKS_VERSION: raise Socks5Error('Unsupported proxy server') if response.reply > 0: raise Socks5Error('TCP connect failed') self.connected_to = target_addr
async def _associate_udp(self, local_addr=None): local_addr = local_addr or ('127.0.0.1', 0) connection = Socks5ClientUDPConnection(self.callback) transport, _ = await get_event_loop().create_datagram_endpoint(lambda: connection, local_addr=local_addr) sock = transport.get_extra_info("socket") request = CommandRequest(SOCKS_VERSION, REQ_CMD_UDP_ASSOCIATE, 0, sock.getsockname()) data = await self._send(socks5_serializer.pack_serializable(request)) response, _ = socks5_serializer.unpack_serializable(CommandResponse, data) connection.proxy_udp_addr = response.bind if response.version != SOCKS_VERSION: raise Socks5Error('Unsupported proxy server') if response.reply > 0: raise Socks5Error('UDP associate failed') self.connection = connection
async def test_socks5_sendto_success(socks5_server): """ Test if sending/receiving a UDP packet works correctly. """ await socks5_server.start() data = b'\x00' target = ('127.0.0.1', 123) client = Socks5Client(('127.0.0.1', socks5_server.port), Mock()) await client.associate_udp() client.sendto(data, target) await sleep(0.1) socks5_server.output_stream.on_socks5_udp_data.assert_called_once() connection = socks5_server.output_stream.on_socks5_udp_data.call_args[0][0] request = socks5_server.output_stream.on_socks5_udp_data.call_args[0][1] assert request.data == data assert request.destination == target packet = socks5_serializer.pack_serializable(UdpPacket(0, 0, target, data)) client.callback.assert_not_called() connection.send_datagram(packet) await sleep(0.1) client.callback.assert_called_once_with(data, target)