Exemple #1
0
    def _try_handshake(self):
        """
        Try to read a HANDSHAKE request

        :return: False if command could not been processes due to lack of bytes, True otherwise
        """
        try:
            request, offset = socks5_serializer.unpack_serializable(
                MethodsRequest, self.buffer)
        except PackError:
            # No (complete) HANDSHAKE received, so dont do anything
            return False

        # Consume the buffer
        self.buffer = self.buffer[offset:]

        # Only accept NO AUTH
        if request.version != SOCKS_VERSION or 0x00 not in request.methods:
            self._logger.error("Client has sent INVALID METHOD REQUEST")
            self.buffer = ''
            self.close()
        else:
            self._logger.info("Client has sent METHOD REQUEST")

            # Respond that we would like to use NO AUTHENTICATION (0x00)
            if self.state is not ConnectionState.CONNECTED:
                response = socks5_serializer.pack_serializable(
                    MethodsResponse(SOCKS_VERSION, 0))
                self.transport.write(response)

            # We are connected now, the next incoming message will be a REQUEST
            self.state = ConnectionState.CONNECTED
            return True
Exemple #2
0
 def datagram_received(self, data, _):
     try:
         request, _ = socks5_serializer.unpack_serializable(UdpPacket, data)
     except PackError:
         self.logger.warning("Error while decoding packet", exc_info=True)
     else:
         self.callback(request.data, request.destination)
Exemple #3
0
    def _try_request(self):
        """
        Try to consume a REQUEST message and respond whether we will accept the
        request.

        Will setup a TCP relay or an UDP socket to accommodate TCP RELAY and
        UDP ASSOCIATE requests. After a TCP relay is set up the handler will
        deactivate itself and change the Connection to a TcpRelayConnection.
        Further data will be passed on to that handler.

        :return: False if command could not been processes due to lack of bytes, True otherwise
        """
        self._logger.debug("Client has sent PROXY REQUEST")

        try:
            request, offset = socks5_serializer.unpack_serializable(
                CommandRequest, self.buffer)
        except PackError:
            return False

        self.buffer = self.buffer[offset:]

        self.state = ConnectionState.PROXY_REQUEST_RECEIVED

        try:
            if request.cmd == REQ_CMD_UDP_ASSOCIATE:
                ensure_future(self.on_udp_associate_request(request))

            elif request.cmd == REQ_CMD_BIND:
                payload = CommandResponse(SOCKS_VERSION, REP_SUCCEEDED, 0,
                                          ("127.0.0.1", 1081))
                response = socks5_serializer.pack_serializable(payload)
                self.transport.write(response)
                self.state = ConnectionState.PROXY_REQUEST_ACCEPTED

            elif request.cmd == REQ_CMD_CONNECT:
                self._logger.info("Accepting TCP CONNECT request to %s:%d",
                                  *request.destination)
                self.connect_to = request.destination
                payload = CommandResponse(SOCKS_VERSION, REP_SUCCEEDED, 0,
                                          ("127.0.0.1", 1081))
                response = socks5_serializer.pack_serializable(payload)
                self.transport.write(response)

            else:
                self.deny_request(request, "CMD not recognized")
        except:
            payload = CommandResponse(SOCKS_VERSION, REP_COMMAND_NOT_SUPPORTED,
                                      0, ("0.0.0.0", 0))
            response = socks5_serializer.pack_serializable(payload)
            self.transport.write(response)
            self._logger.exception(
                "Exception thrown, returning unsupported command response")

        return True
Exemple #4
0
    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')
Exemple #5
0
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
Exemple #6
0
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
Exemple #7
0
    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
Exemple #8
0
def test_decode_command_request_fail():
    badly_encoded = b'\x05\x00\x00\x03 tracker1.invalid-tracker\xc4\xe95\x11$\x00\x1f\x94'
    with pytest.raises(PackError):
        socks5_serializer.unpack_serializable(CommandRequest, badly_encoded)

    with pytest.raises(PackError):
        # Invalid address type
        socks5_serializer.unpack_serializable(CommandRequest,
                                              struct.pack("!BBBB", 5, 0, 0, 5))

    with pytest.raises(PackError):
        # IPv6
        socks5_serializer.unpack_serializable(CommandRequest,
                                              struct.pack("!BBBB", 5, 0, 0, 4))
Exemple #9
0
    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
Exemple #10
0
    def datagram_received(self, data, source):
        # If remote_address was not set before, use first one
        if self.remote_udp_address is None:
            self.remote_udp_address = source

        if self.remote_udp_address == source:
            try:
                request, _ = socks5_serializer.unpack_serializable(
                    UdpPacket, data)
            except PackError:
                self._logger.warning("Cannot serialize UDP packet")
                return False

            if request.frag == 0 and request.destination:
                return self.socksconnection.socksserver.output_stream.on_socks5_udp_data(
                    self, request)
            self._logger.debug(
                "No support for fragmented data or without destination host, dropping"
            )
        else:
            self._logger.debug("Ignoring data from %s:%d, is not %s:%d",
                               *source, *self.remote_udp_address)

        return False
Exemple #11
0
def test_decode_udp_packet_fail():
    # try decoding badly encoded udp packet, should raise an exception in Python3
    badly_encoded_packet = b'\x00\x00\x00\x03 tracker1.invalid-tracker\xc4\xe95\x11$\x00\x1f\x940x000'
    with pytest.raises(PackError):
        socks5_serializer.unpack_serializable(UdpPacket, badly_encoded_packet)
Exemple #12
0
 def datagram_received(self, data, _):
     request, _ = socks5_serializer.unpack_serializable(UdpPacket, data)
     self.callback(request.data, request.destination)