Ejemplo n.º 1
0
Archivo: server.py Proyecto: icing/irrd
    def handle_connection(self):
        """
        Handle an individual whois client connection.
        When this method returns, the connection is closed.
        """
        client_ip = self.client_address[0]
        self.client_str = client_ip + ':' + str(self.client_address[1])
        setproctitle(f'irrd-whois-worker-{self.client_str}')

        if not self.is_client_permitted(client_ip):
            self.wfile.write(b'%% Access denied')
            return

        self.query_parser = WhoisQueryParser(client_ip, self.client_str, self.preloader,
                                             self.database_handler)

        data = True
        while data:
            timer = threading.Timer(self.query_parser.timeout, self.close_request)
            timer.start()
            data = self.rfile.readline()
            timer.cancel()

            query = data.decode('utf-8', errors='backslashreplace').strip()
            if not query:
                continue

            logger.debug(f'{self.client_str}: processing query: {query}')

            if not self.handle_query(query):
                return
Ejemplo n.º 2
0
    def handle(self):
        """
        Handle a whois connection.
        Upon return, the connection is closed by StreamRequestHandler.
        """
        # Disable the special sigterm_handler defined in start_whois_server()
        # (signal handlers are inherited)
        signal.signal(signal.SIGTERM, signal.SIG_DFL)

        client_ip = self.client_address[0]
        self.client_str = client_ip + ':' + str(self.client_address[1])
        setproctitle(f'irrd-whois-server-{self.client_str}')

        if not self.is_client_permitted(client_ip):
            self.wfile.write(b'%% Access denied')
            return

        self.query_parser = WhoisQueryParser(client_ip, self.client_str)

        data = True
        while data:
            timer = threading.Timer(self.query_parser.timeout,
                                    self.server.shutdown_request,
                                    args=[self.request])
            timer.start()
            data = self.rfile.readline()
            timer.cancel()

            query = data.decode('utf-8', errors='backslashreplace').strip()
            if not query:
                continue

            logger.info(f'{self.client_str}: processing query: {query}')

            if not self.handle_query(query):
                return
Ejemplo n.º 3
0
class WhoisRequestHandler(socketserver.StreamRequestHandler):
    def handle(self):
        """
        Handle a whois connection.
        Upon return, the connection is closed by StreamRequestHandler.
        """
        # Disable the special sigterm_handler defined in start_whois_server()
        # (signal handlers are inherited)
        signal.signal(signal.SIGTERM, signal.SIG_DFL)

        client_ip = self.client_address[0]
        self.client_str = client_ip + ':' + str(self.client_address[1])
        setproctitle(f'irrd-whois-server-{self.client_str}')

        if not self.is_client_permitted(client_ip):
            self.wfile.write(b'%% Access denied')
            return

        self.query_parser = WhoisQueryParser(client_ip, self.client_str)

        data = True
        while data:
            timer = threading.Timer(self.query_parser.timeout,
                                    self.server.shutdown_request,
                                    args=[self.request])
            timer.start()
            data = self.rfile.readline()
            timer.cancel()

            query = data.decode('utf-8', errors='backslashreplace').strip()
            if not query:
                continue

            logger.info(f'{self.client_str}: processing query: {query}')

            if not self.handle_query(query):
                return

    def handle_query(self, query: str) -> bool:
        """
        Handle an individual query.
        Returns False when the connection should be closed,
        True when more queries should be read.
        """
        start_time = time.perf_counter()
        if query.upper() == '!Q':
            logger.debug(f'{self.client_str}: closed connection per request')
            return False

        response = self.query_parser.handle_query(query)
        response_bytes = response.generate_response().encode('utf-8')
        try:
            self.wfile.write(response_bytes)
        except OSError:
            return False

        elapsed = time.perf_counter() - start_time
        logger.info(
            f'{self.client_str}: sent answer to query, elapsed {elapsed}s, {len(response_bytes)} bytes: {query}'
        )

        if not self.query_parser.multiple_command_mode:
            logger.debug(f'{self.client_str}: auto-closed connection')
            return False
        return True

    def is_client_permitted(self, ip: str) -> bool:
        """
        Check whether a client is permitted.
        """
        return is_client_permitted(ip,
                                   'server.whois.access_list',
                                   default_deny=False)
Ejemplo n.º 4
0
Archivo: server.py Proyecto: icing/irrd
class WhoisWorker(mp.Process, socketserver.StreamRequestHandler):
    """
    A whois worker is a process that handles whois client connections,
    which are retrieved from a queue. After handling a connection,
    the process waits for the next connection from the queue.s
    """
    def __init__(self, connection_queue, *args, **kwargs):
        self.connection_queue = connection_queue
        # Note that StreamRequestHandler.__init__ is not called - the
        # input for that is not available, as it's retrieved from the queue.
        super().__init__(*args, **kwargs)

    def run(self, keep_running=True) -> None:
        """
        Whois worker run loop.
        This method does not return, except if it failed to initialise a preloader,
        or if keep_running is set, after the first request is handled. The latter
        is used in the tests.
        """
        # Disable the special sigterm_handler defined in start_whois_server()
        # (signal handlers are inherited)
        signal.signal(signal.SIGTERM, signal.SIG_DFL)

        try:
            self.preloader = Preloader()
            self.database_handler = DatabaseHandler()
        except Exception as e:
            logger.error(f'Whois worker failed to initialise preloader or database,'
                         f'unable to start, traceback follows: {e}', exc_info=e)
            return

        while True:
            try:
                setproctitle('irrd-whois-worker')
                self.request, self.client_address = self.connection_queue.get()
                self.setup()
                self.handle_connection()
                self.finish()
                self.close_request()
            except Exception as e:
                try:
                    self.close_request()
                except Exception:  # pragma: no cover
                    pass
                logger.error(f'Failed to handle whois connection, traceback follows: {e}',
                             exc_info=e)
            if not keep_running:
                break

    def close_request(self):
        # Close the connection in the same way normally done by TCPServer
        try:
            # explicitly shutdown.  socket.close() merely releases
            # the socket and waits for GC to perform the actual close.
            self.request.shutdown(socket.SHUT_WR)
        except OSError:  # pragma: no cover
            pass  # some platforms may raise ENOTCONN here
        self.request.close()

    def handle_connection(self):
        """
        Handle an individual whois client connection.
        When this method returns, the connection is closed.
        """
        client_ip = self.client_address[0]
        self.client_str = client_ip + ':' + str(self.client_address[1])
        setproctitle(f'irrd-whois-worker-{self.client_str}')

        if not self.is_client_permitted(client_ip):
            self.wfile.write(b'%% Access denied')
            return

        self.query_parser = WhoisQueryParser(client_ip, self.client_str, self.preloader,
                                             self.database_handler)

        data = True
        while data:
            timer = threading.Timer(self.query_parser.timeout, self.close_request)
            timer.start()
            data = self.rfile.readline()
            timer.cancel()

            query = data.decode('utf-8', errors='backslashreplace').strip()
            if not query:
                continue

            logger.debug(f'{self.client_str}: processing query: {query}')

            if not self.handle_query(query):
                return

    def handle_query(self, query: str) -> bool:
        """
        Handle an individual query.
        Returns False when the connection should be closed,
        True when more queries should be read.
        """
        start_time = time.perf_counter()
        if query.upper() == '!Q':
            logger.debug(f'{self.client_str}: closed connection per request')
            return False

        response = self.query_parser.handle_query(query)
        response_bytes = response.generate_response().encode('utf-8')
        try:
            self.wfile.write(response_bytes)
        except OSError:
            return False

        elapsed = time.perf_counter() - start_time
        logger.info(f'{self.client_str}: sent answer to query, elapsed {elapsed}s, '
                    f'{len(response_bytes)} bytes: {query}')

        if not self.query_parser.multiple_command_mode:
            logger.debug(f'{self.client_str}: auto-closed connection')
            return False
        return True

    def is_client_permitted(self, ip: str) -> bool:
        """
        Check whether a client is permitted.
        """
        return is_client_permitted(ip, 'server.whois.access_list', default_deny=False)