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()
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
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)
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()
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
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
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
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)
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
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)
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
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)
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,
# 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,
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)
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()
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)