Exemplo n.º 1
0
    def get_next_link(self, request: Request) -> Optional[Link]:
        if not self.should_accept_request(request):
            logger.error(str(self), "Request {} rejected.".format(request))
            return None

        high_priority, normal_priority, low_priority = self.get_link_ids_for_request(
            request)

        if len(high_priority) != 0:
            links_id = high_priority
        elif len(normal_priority) != 0:
            links_id = normal_priority
        elif len(low_priority) != 0:
            links_id = low_priority
        else:
            logger.error(
                str(self),
                "No link available to take this request ({}).".format(request))
            return None

        links = [self.links[link_id] for link_id in links_id]

        self._last_link = get_next_link(links, self._last_link, self.strategy)

        return self._last_link
Exemplo n.º 2
0
    def _socks_request(self, socket_client: socket) -> (Optional[Link], Optional[int], Optional[socks.socksocket]):
        (domain, port) = self._socks_request_get_dest(socket_client)
        request = Request(domain, port)
        link = self.balancer.get_next_link(request)
        if link is None:
            logger.error(str(self), "No Link available to handle the request.")
            return None
        connection_id = self.generate_connection_id()
        socket_link = link.open_connection(connection_id)
        if socket_link is None:
            link.close_connection(connection_id)
            return None
        try:
            socket_link.connect((domain, port))
        except socket.error as err:
            logger.error(str(self),
                         "Socket error while trying to connect to {}:{}: \"{}\".".format(domain, port, err))
            link.close_connection(connection_id)
            self._socks_request_send_reply(socket_client, SocksReply.NETWORK_UNREACHABLE)
            return None

        if not self._socks_request_send_reply(socket_client, SocksReply.SUCCEEDED):
            link.close_connection(connection_id)
            return None

        return link, connection_id, socket_link
Exemplo n.º 3
0
 def _socks_sub_negotiation_send_chosen_method(self, socket_client: socket, method: SocksMethod) -> bool:
     chosen_method_packet = b'\x05' + method.value
     try:
         socket_client.sendall(chosen_method_packet)
     except socket.error as err:
         logger.error(str(self), "Socket error while trying to communicate with client: \"{}\".".format(err))
         return False
     return True
Exemplo n.º 4
0
 def open_connection(self,
                     connection_id: str) -> Optional[socks.socksocket]:
     if connection_id in self.connections:
         logger.error(
             str(self),
             "Connection id '{}' already in use for this link.".format(
                 connection_id))
         return None
     self.connections[connection_id] = self._build_socket()
     return self.connections[connection_id]
Exemplo n.º 5
0
 def _socks_request_send_reply(self, socket_client: socket, reply: SocksReply) -> bool:
     reply_packet = b'\x05' + reply.value + b'\x00' + SocksAddressType.IPV4.value + \
                    b'\x00' + b'\x00' + b'\x00' + b'\x00' + \
                    b'\x00' + b'\x00'
     try:
         socket_client.sendall(reply_packet)
     except socket.error as err:
         logger.error(str(self), "Socket error while trying to communicate with client: \"{}\".".format(err))
         return False
     return True
Exemplo n.º 6
0
    def _accept_client_loop(self, server_socket: socket):
        logger.info(str(self), "Ready to receive requests.")
        while not self.STOP:
            if threading.active_count() > self.max_threads:
                sleep(5)  # It means that the thread will take 5 seconds maximum to return
                continue

            try:
                client_socket, _ = server_socket.accept()
                client_socket.setblocking(True)
            except socket.timeout:
                continue
            except socket.error:
                continue
            except TypeError as err:
                logger.error(str(self), "Error: \"{}\".".format(err))
                return
            exchange_thread = threading.Thread(target=self.handle_request, args=(client_socket,))
            exchange_thread.start()
        server_socket.close()
        logger.info(str(self), "Stopping server.")
Exemplo n.º 7
0
    def start(self) -> bool:
        self.STOP = False
        try:
            server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            server_socket.settimeout(self.timeout)
        except socket.error as err:
            logger.error(str(self), "Failed to create the socket server, error: \"{}\".".format(err))
            return False

        try:
            server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            server_socket.bind((self.domain, self.port))
            logger.info(str(self), 'Bind {}.'.format(str(self.port)))
        except socket.error as err:
            server_socket.close()
            logger.error(str(self), "Cannot bind {}:{}, error: \"{}\".".format(self.domain, self.port, err))
            return False

        try:
            server_socket.listen(10)
        except socket.error as err:
            server_socket.close()
            logger.error(str(self), "Listen failed, error: \"{}\".".format(err))
            return False

        self._server_thread = threading.Thread(target=self._accept_client_loop, args=(server_socket,))
        self._server_thread.start()

        self._balancer_thread = threading.Thread(target=self._balancer_loop)
        self._balancer_thread.start()

        return True
Exemplo n.º 8
0
 def _exchange_with_client(self, socket_client: socket, socket_link: socks.socksocket):
     while not self.STOP:
         try:
             reader, _, _ = select.select([socket_client, socket_link], [], [], socket_link.gettimeout())
         except select.error as err:
             logger.error(str(self), "Select failed: \"{}\".".format(err))
             return
         if not reader:
             return
         try:
             for sock in reader:
                 data = sock.recv(2048)
                 if not data:
                     return
                 if sock is socket_link:
                     socket_client.send(data)
                 else:
                     socket_link.send(data)
         except socket.error as err:
             logger.error(str(self),
                          "Socket error while trying to communicate with client: \"{}\".".format(err))
             return
Exemplo n.º 9
0
    def _socks_request_get_dest(self, socket_client: socket) -> (Optional[str], Optional[int]):
        try:
            request_packet = socket_client.recv(2048)
        except socket.error:
            logger.error(str(self), "Socket error while trying to communicate with client.")
            self._socks_request_send_reply(socket_client, SocksReply.SERVER_FAILURE)
            raise Exception()

        ver = request_packet[0]
        cmd = request_packet[1]
        atyp = request_packet[3]

        if ver != 5:
            logger.error(str(self), "SOCKS version '{}' not supported.".format(ver))
            self._socks_request_send_reply(socket_client, SocksReply.CONNECTION_REFUSED)
            return None

        if cmd != ord(SocksCommand.CONNECT.value):
            logger.error(str(self), "SOCKS command '{}' not supported.".format(cmd))
            self._socks_request_send_reply(socket_client, SocksReply.COMMAND_NOT_SUPPORTED)
            return None

        if atyp == ord(SocksAddressType.IPV4.value):
            dst_addr = socket.inet_ntop(socket.AF_INET, request_packet[4:-2])
        elif atyp == ord(SocksAddressType.DOMAINNAME.value):
            dst_addr = request_packet[5:-2].decode()
        elif atyp == ord(SocksAddressType.IPV6.value):
            dst_addr = socket.inet_ntop(socket.AF_INET6, request_packet[4:-2])
        else:
            logger.error(str(self), "SOCKS address type '{}' not supported.".format(atyp))
            self._socks_request_send_reply(socket_client, SocksReply.ADDRESS_TYPE_NOT_SUPPORTED)
            return None

        dst_port = unpack('>H', request_packet[-2:])[0]

        return dst_addr, dst_port
Exemplo n.º 10
0
    def _socks_sub_negotiation_choose_method(self, socket_client: socket) -> SocksMethod:
        try:
            methods_packet = socket_client.recv(2048)
        except socket.error:
            logger.error(str(self), "Socket error while trying to communicate with client.")
            return SocksMethod.NO_ACCEPTABLE_METHODS

        ver = methods_packet[0]
        nmethods = methods_packet[1]
        methods = methods_packet[2:]

        if ver != 5:
            logger.error(str(self), "SOCKS version '{}' not supported.".format(ver))
            return SocksMethod.NO_ACCEPTABLE_METHODS

        if nmethods != len(methods):
            logger.error(str(self), "Malformed SOCKS packet received from client.")
            return SocksMethod.NO_ACCEPTABLE_METHODS

        if ord(SocksMethod.NO_AUTH.value) in methods:
            return SocksMethod.NO_AUTH

        return SocksMethod.NO_ACCEPTABLE_METHODS