Example #1
0
    def test_connect_and_serve_with_packet_loss(self, mock_sendto):
        """
        This test ensures handshake success and stream data is successfully sent
        and received in the presence of packet loss (randomized 25% in each direction).
        """
        data = b"Z" * 65536

        server_configuration = QuicConfiguration(idle_timeout=300.0,
                                                 is_client=False,
                                                 quic_logger=QuicLogger())
        server_configuration.load_cert_chain(SERVER_CERTFILE, SERVER_KEYFILE)

        server, response = run(
            asyncio.gather(
                run_server(configuration=server_configuration,
                           stateless_retry=True),
                run_client(
                    "127.0.0.1",
                    configuration=QuicConfiguration(is_client=True,
                                                    idle_timeout=300.0,
                                                    quic_logger=QuicLogger()),
                    request=data,
                ),
            ))
        self.assertEqual(response, data)
        server.close()
Example #2
0
def start(kwargs):
    configuration = QuicConfiguration(
        alpn_protocols=['wq-vvv-01'] + ['siduck'],
        is_client=False,
        max_datagram_frame_size=65536,
    )

    global handlers_path
    handlers_path = os.path.abspath(os.path.expanduser(
        kwargs['handlers_path']))
    logger.info('port = %s', kwargs['port'])
    logger.info('handlers path = %s', handlers_path)

    # load SSL certificate and key
    configuration.load_cert_chain(kwargs['certificate'], kwargs['private_key'])

    ticket_store = SessionTicketStore()

    loop = asyncio.get_event_loop()
    loop.run_until_complete(
        serve(
            kwargs['host'],
            kwargs['port'],
            configuration=configuration,
            create_protocol=QuicTransportProtocol,
            session_ticket_fetcher=ticket_store.pop,
            session_ticket_handler=ticket_store.add,
        ))
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        pass
Example #3
0
    def test_combined_key(self):
        config1 = QuicConfiguration()
        config2 = QuicConfiguration()
        config1.load_cert_chain(SERVER_CERTFILE, SERVER_KEYFILE)
        config2.load_cert_chain(SERVER_COMBINEDFILE)

        self.assertEqual(config1.certificate, config2.certificate)
Example #4
0
    def _start_on_server_thread(self) -> None:
        configuration = QuicConfiguration(
            alpn_protocols=H3_ALPN,
            is_client=False,
            max_datagram_frame_size=65536,
        )

        _logger.info("Starting WebTransport over HTTP/3 server on %s:%s",
                     self.host, self.port)

        configuration.load_cert_chain(self.cert_path, self.key_path)

        ticket_store = SessionTicketStore()

        self.loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self.loop)
        self.loop.run_until_complete(
            serve(
                self.host,
                self.port,
                configuration=configuration,
                create_protocol=WebTransportH3Protocol,
                session_ticket_fetcher=ticket_store.pop,
                session_ticket_handler=ticket_store.add,
            ))
        self.loop.run_forever()
Example #5
0
    async def create_server(cls, bind, log, loop, tman):
        self = cls()
        self.loop = loop
        self.log = log
        self.tman = tman

        bind = bind or ('::', None)
        bind = (bind[0], bind[1] + (self.default_port - COAP_PORT)
                if bind[1] else self.default_port)
        config = QuicConfiguration(is_client=False, alpn_protocols='coap')
        config.load_cert_chain("aiocoap/ssl_cert.pem", "aiocoap/ssl_key.pem")

        PORT = 5684
        PORT = 64999
        try:
            server = await self.loop.create_datagram_endpoint(
                lambda: QuicServer(configuration=config, create_protocol=Quic),
                local_addr=(bind[0], PORT),
                reuse_port=socket.SO_REUSEPORT)
            Quic.ctx = self

        except socket.gaierror:
            raise error.ResolutionError(
                "No local bindable address found for %s" % bind[0])

        self.server = server

        return self
Example #6
0
def configure_http3_server(
        listen_port,
        server_port,
        https_pem,
        ca_pem,
        listening_sentinel,
        h3_to_server=False):

    HttpQuicServerHandler.cert_file = https_pem
    HttpQuicServerHandler.ca_file = ca_pem
    HttpQuicServerHandler.h3_to_server = h3_to_server
    HttpQuicServerHandler.server_port = server_port

    try:
        os.mkdir('quic_log_directory')
    except FileExistsError:
        pass
    quic_logger = QuicDirectoryLogger('quic_log_directory')
    secrets_log_file = open('tls_secrets.log', "a", encoding='utf-8')
    configuration = QuicConfiguration(
        alpn_protocols=H3_ALPN,
        is_client=False,
        max_datagram_frame_size=65536,
        quic_logger=quic_logger,
        secrets_log_file=secrets_log_file,
    )

    configuration.load_cert_chain(https_pem, ca_pem)
    ticket_store = SessionTicketStore()

    # TODO
    # In 3.7: how about asyncio.run(serve(...))
    loop = asyncio.get_event_loop()
    server_side_proto = "HTTP/3" if h3_to_server else "HTTP/1"
    print(
        f"Serving HTTP/3 Proxy on 127.0.0.1:{listen_port} with pem '{https_pem}', "
        f"forwarding to 127.0.0.1:{server_port} over {server_side_proto}")
    loop.run_until_complete(
        serve(
            '0.0.0.0',
            listen_port,
            configuration=configuration,
            create_protocol=HttpQuicServerHandler,
            session_ticket_fetcher=ticket_store.pop,
            session_ticket_handler=ticket_store.add
        )
    )

    # Indicate to the caller that the quic socket is configured and listening.
    Path(listening_sentinel).touch()

    try:
        loop.run_forever()
    except KeyboardInterrupt as e:
        # The calling test_proxy.py will handle this.
        print("Handling KeyboardInterrupt")
        raise e
    except SystemExit:
        pass
Example #7
0
def init_context(certfile, keyfile, pass_phrase):
    from aioquic.h3.connection import H3_ALPN
    from aioquic.quic.configuration import QuicConfiguration
    import ssl

    ctx = QuicConfiguration(alpn_protocols=H3_ALPN, is_client=False)
    ctx.load_cert_chain(certfile, keyfile, pass_phrase)
    ctx.verify_mode = ssl.CERT_NONE
    return ctx
Example #8
0
async def run_server(configuration=None, **kwargs):
    if configuration is None:
        configuration = QuicConfiguration(is_client=False)
        configuration.load_cert_chain(SERVER_CERTFILE, SERVER_KEYFILE)
    return await serve(host="::",
                       port="4433",
                       configuration=configuration,
                       stream_handler=handle_stream,
                       **kwargs)
Example #9
0
 async def run_server(self, configuration=None, host="::", **kwargs):
     if configuration is None:
         configuration = QuicConfiguration(is_client=False)
         configuration.load_cert_chain(SERVER_CERTFILE, SERVER_KEYFILE)
     self.server = await serve(host=host,
                               port=self.server_port,
                               configuration=configuration,
                               stream_handler=handle_stream,
                               **kwargs)
     return self.server
Example #10
0
def run_server(server_port):
    logging.info('Starting server at localhost:%s', server_port)

    configuration = QuicConfiguration(is_client=False)

    certificates_path = Path(__file__).parent / 'certificates'
    configuration.load_cert_chain(certificates_path / 'ssl_cert.pem',
                                  certificates_path / 'ssl_key.pem')

    return rsocket_serve(host='localhost',
                         port=server_port,
                         configuration=configuration,
                         handler_factory=Handler)
Example #11
0
    def create_server(self):
        configuration = QuicConfiguration(is_client=False)
        configuration.load_cert_chain(SERVER_CERTFILE, SERVER_KEYFILE)

        server = Context(is_client=False)
        server.certificate = configuration.certificate
        server.certificate_private_key = configuration.private_key
        server.handshake_extensions = [
            (
                tls.ExtensionType.QUIC_TRANSPORT_PARAMETERS,
                SERVER_QUIC_TRANSPORT_PARAMETERS,
            )
        ]
        self.assertEqual(server.state, State.SERVER_EXPECT_CLIENT_HELLO)
        return server
Example #12
0
    def test_connect_and_serve_with_packet_loss(self, mock_sendto):
        """
        This test ensures handshake success and stream data is successfully sent
        and received in the presence of packet loss (randomized 25% in each direction).
        """
        data = b"Z" * 65536

        server_configuration = QuicConfiguration(is_client=False,
                                                 quic_logger=QuicLogger())
        server_configuration.load_cert_chain(SERVER_CERTFILE, SERVER_KEYFILE)
        run(self.run_server(configuration=server_configuration))

        response = run(
            self.run_client(
                configuration=QuicConfiguration(is_client=True,
                                                quic_logger=QuicLogger()),
                request=data,
            ))
        self.assertEqual(response, data)
Example #13
0
                        default='127.0.0.1',
                        help='router address',
                        metavar='ADDR')
    parser.add_argument('--router-port',
                        type=int,
                        default=6363,
                        help='router port',
                        metavar='PORT')
    opts = parser.parse_args()

    configuration = QuicConfiguration(
        alpn_protocols=H3_ALPN,
        is_client=False,
        max_datagram_frame_size=32 + opts.mtu,
    )
    configuration.load_cert_chain(opts.cert, opts.key)

    logging.info('Starting QUIC server at [%s]:%d', opts.listen_addr,
                 opts.listen_port)
    logging.info('NDN router is at [%s]:%d', opts.router_addr,
                 opts.router_port)

    def create_protocol(*args, **kwargs):
        return H3Server((opts.router_addr, opts.router_port), opts.mtu, *args,
                        **kwargs)

    loop = aio.new_event_loop()
    loop.run_until_complete(
        serve(
            opts.listen_addr,
            opts.listen_port,
Example #14
0
    # open SSL log file
    if args.secrets_log:
        secrets_log_file = open(args.secrets_log, "a")
    else:
        secrets_log_file = None

    configuration = QuicConfiguration(
        alpn_protocols=H3_ALPN + H0_ALPN + ["siduck"],
        is_client=False,
        max_datagram_frame_size=65536,
        quic_logger=quic_logger,
        secrets_log_file=secrets_log_file,
    )

    # load SSL certificate and key
    configuration.load_cert_chain(args.certificate, args.private_key)

    ticket_store = SessionTicketStore()

    if uvloop is not None:
        uvloop.install()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(
        serve(
            args.host,
            args.port,
            configuration=configuration,
            create_protocol=HttpServerProtocol,
            session_ticket_fetcher=ticket_store.pop,
            session_ticket_handler=ticket_store.add,
            retry=args.retry,
Example #15
0
class QuicProtocol:
    def __init__(
        self,
        config: Config,
        server: Optional[Tuple[str, int]],
        spawn_app: Callable[[dict, Callable], Awaitable[Callable]],
        send: Callable[[Event], Awaitable[None]],
        call_at: Callable[[float, Callable], None],
        now: Callable[[], float],
    ) -> None:
        self.call_at = call_at
        self.config = config
        self.connections: Dict[bytes, QuicConnection] = {}
        self.http_connections: Dict[QuicConnection, H3Protocol] = {}
        self.now = now
        self.send = send
        self.server = server
        self.spawn_app = spawn_app

        self.quic_config = QuicConfiguration(alpn_protocols=H3_ALPN, is_client=False)
        self.quic_config.load_cert_chain(certfile=config.certfile, keyfile=config.keyfile)

    async def handle(self, event: Event) -> None:
        if isinstance(event, RawData):
            try:
                header = pull_quic_header(Buffer(data=event.data), host_cid_length=8)
            except ValueError:
                return
            if (
                header.version is not None
                and header.version not in self.quic_config.supported_versions
            ):
                data = encode_quic_version_negotiation(
                    source_cid=header.destination_cid,
                    destination_cid=header.source_cid,
                    supported_versions=self.quic_config.supported_versions,
                )
                await self.send(RawData(data=data, address=event.address))
                return

            connection = self.connections.get(header.destination_cid)
            if (
                connection is None
                and len(event.data) >= 1200
                and header.packet_type == PACKET_TYPE_INITIAL
            ):
                connection = QuicConnection(
                    configuration=self.quic_config, original_connection_id=None
                )
                self.connections[header.destination_cid] = connection
                self.connections[connection.host_cid] = connection

            if connection is not None:
                connection.receive_datagram(event.data, event.address, now=self.now())
                await self._handle_events(connection, event.address)
        elif isinstance(event, Closed):
            pass

    async def send_all(self, connection: QuicConnection) -> None:
        for data, address in connection.datagrams_to_send(now=self.now()):
            await self.send(RawData(data=data, address=address))

    async def _handle_events(
        self, connection: QuicConnection, client: Optional[Tuple[str, int]] = None
    ) -> None:
        event = connection.next_event()
        while event is not None:
            if isinstance(event, ConnectionTerminated):
                pass
            elif isinstance(event, ProtocolNegotiated):
                self.http_connections[connection] = H3Protocol(
                    self.config,
                    client,
                    self.server,
                    self.spawn_app,
                    connection,
                    partial(self.send_all, connection),
                )
            elif isinstance(event, ConnectionIdIssued):
                self.connections[event.connection_id] = connection
            elif isinstance(event, ConnectionIdRetired):
                del self.connections[event.connection_id]

            if connection in self.http_connections:
                await self.http_connections[connection].handle(event)

            event = connection.next_event()

        await self.send_all(connection)

        timer = connection.get_timer()
        if timer is not None:
            self.call_at(timer, partial(self._handle_timer, connection))

    async def _handle_timer(self, connection: QuicConnection) -> None:
        if connection._close_at is not None:
            connection.handle_timer(now=self.now())
            await self._handle_events(connection, None)
Example #16
0
    def process_client_indication(self) -> None:
        indication = dict(
            self.parse_client_indication(
                io.BytesIO(self.client_indication_data)))
        origin = urllib.parse.urlparse(indication[0].decode())
        path = urllib.parse.urlparse(indication[1]).decode()

        self.handler = TestHandler(self._quic)

    def is_closing_or_closed(self) -> bool:
        return self._quic._close_pending or self._quic._state in END_STATES


if __name__ == '__main__':
    configuration = QuicConfiguration(
        alpn_protocols=['wq-vvv-01'],
        is_client=False,
        max_datagram_frame_size=1500,
    )
    configuration.load_cert_chain('localhost.crt', 'localhost.key')

    loop = asyncio.get_event_loop()
    loop.run_until_complete(
        serve(
            'localhost',
            4443,
            configuration=configuration,
            create_protocol=QuicTransportProtocol,
        ))
    loop.run_forever()
Example #17
0
def make_connection():
    server_configuration = QuicConfiguration(is_client=False)
    server_configuration.load_cert_chain(SERVER_CERTFILE, SERVER_KEYFILE)
    quic = QuicConnection(configuration=server_configuration)
    quic._ack_delay = 0
    return h3.H3Connection(quic)