Ejemplo n.º 1
0
 def test_encode_quic_version_negotiation(self):
     data = encode_quic_version_negotiation(
         destination_cid=binascii.unhexlify("dae1889b81a91c26"),
         source_cid=binascii.unhexlify("f49243784f9bf3be"),
         supported_versions=[QuicProtocolVersion.DRAFT_18, 0x1A2A3A4A],
     )
     self.assertEqual(data[1:], load("version_negotiation.bin")[1:])
Ejemplo n.º 2
0
    def datagram_received(self, datagram, addr):
        buf = Buffer(data=datagram)
        header = pull_quic_header(buf, host_cid_length=8)

        # version negotiation
        if (header.version is not None
                and header.version not in QuicConnection.supported_versions):
            self._transport.sendto(
                encode_quic_version_negotiation(
                    source_cid=header.destination_cid,
                    destination_cid=header.source_cid,
                    supported_versions=QuicConnection.supported_versions,
                ),
                addr,
            )
            return

        connection = self._connections.get(header.destination_cid, None)
        if connection is None and header.packet_type == PACKET_TYPE_INITIAL:
            # create new connection
            connection = QuicConnection(is_client=False, **self._kwargs)
            connection.connection_made(QuicConnectionTransport(self, addr))
            connection.stream_created_cb = self.stream_created
            self._connections[connection.host_cid] = connection
            logger.info("%s New connection from %s" %
                        (connection_id(connection), addr))

        if connection is not None:
            connection.datagram_received(datagram, addr)
Ejemplo n.º 3
0
    def test_version_negotiation_ok(self):
        client = create_standalone_client(self)

        # found a common version, retry
        client.receive_datagram(
            encode_quic_version_negotiation(
                source_cid=client._peer_cid,
                destination_cid=client.host_cid,
                supported_versions=[QuicProtocolVersion.DRAFT_19],
            ),
            SERVER_ADDR,
            now=time.time(),
        )
        self.assertEqual(drop(client), 1)
Ejemplo n.º 4
0
    def test_version_negotiation_ok(self):
        client, client_transport = create_standalone_client()
        self.assertEqual(client_transport.sent, 1)

        # found a common version, retry
        client.datagram_received(
            encode_quic_version_negotiation(
                source_cid=client.peer_cid,
                destination_cid=client.host_cid,
                supported_versions=[QuicProtocolVersion.DRAFT_19],
            ),
            SERVER_ADDR,
        )
        self.assertEqual(client_transport.sent, 2)
Ejemplo n.º 5
0
    def test_version_negotiation_fail(self):
        client, client_transport = create_standalone_client()
        self.assertEqual(client_transport.sent, 1)

        # no common version, no retry
        client.datagram_received(
            encode_quic_version_negotiation(
                source_cid=client.peer_cid,
                destination_cid=client.host_cid,
                supported_versions=[0xFF000011],  # DRAFT_16
            ),
            SERVER_ADDR,
        )
        self.assertEqual(client_transport.sent, 1)
Ejemplo n.º 6
0
    def test_version_negotiation_ok(self):
        client = QuicConnection(is_client=True)

        client_transport = FakeTransport()
        client.connection_made(client_transport)
        self.assertEqual(client_transport.sent, 1)

        # found a common version, retry
        client.datagram_received(
            encode_quic_version_negotiation(
                source_cid=client.peer_cid,
                destination_cid=client.host_cid,
                supported_versions=[QuicProtocolVersion.DRAFT_19],
            ),
            None,
        )
        self.assertEqual(client_transport.sent, 2)
Ejemplo n.º 7
0
    def test_version_negotiation_fail(self):
        client = QuicConnection(is_client=True)

        client_transport = FakeTransport()
        client.connection_made(client_transport)
        self.assertEqual(client_transport.sent, 1)

        # no common version, no retry
        client.datagram_received(
            encode_quic_version_negotiation(
                source_cid=client.peer_cid,
                destination_cid=client.host_cid,
                supported_versions=[0xFF000011],  # DRAFT_16
            ),
            None,
        )
        self.assertEqual(client_transport.sent, 1)
Ejemplo n.º 8
0
    def test_version_negotiation_fail(self):
        client = create_standalone_client(self)

        # no common version, no retry
        client.receive_datagram(
            encode_quic_version_negotiation(
                source_cid=client._peer_cid,
                destination_cid=client.host_cid,
                supported_versions=[0xFF000011],  # DRAFT_16
            ),
            SERVER_ADDR,
            now=time.time(),
        )
        self.assertEqual(drop(client), 0)

        event = client.next_event()
        self.assertEqual(type(event), events.ConnectionTerminated)
        self.assertEqual(event.error_code, QuicErrorCode.INTERNAL_ERROR)
        self.assertEqual(event.frame_type, None)
        self.assertEqual(event.reason_phrase,
                         "Could not find a common protocol version")
Ejemplo n.º 9
0
    def test_version_negotiation_fail(self):
        client, client_transport = create_standalone_client()
        self.assertEqual(client_transport.sent, 1)

        # no common version, no retry
        client.datagram_received(
            encode_quic_version_negotiation(
                source_cid=client._peer_cid,
                destination_cid=client.host_cid,
                supported_versions=[0xFF000011],  # DRAFT_16
            ),
            SERVER_ADDR,
        )
        self.assertEqual(client_transport.sent, 1)

        with self.assertRaises(QuicConnectionError) as cm:
            run(client.wait_connected())
        self.assertEqual(cm.exception.error_code, QuicErrorCode.INTERNAL_ERROR)
        self.assertEqual(cm.exception.frame_type, None)
        self.assertEqual(cm.exception.reason_phrase,
                         "Could not find a common protocol version")
Ejemplo n.º 10
0
    def datagram_received(self, data: Union[bytes, Text],
                          addr: NetworkAddress) -> None:
        data = cast(bytes, data)
        buf = Buffer(data=data)
        header = pull_quic_header(buf, host_cid_length=8)

        # version negotiation
        if (header.version is not None and header.version
                not in self._configuration.supported_versions):
            self._transport.sendto(
                encode_quic_version_negotiation(
                    source_cid=header.destination_cid,
                    destination_cid=header.source_cid,
                    supported_versions=self._configuration.supported_versions,
                ),
                addr,
            )
            return

        connection = self._connections.get(header.destination_cid, None)
        original_connection_id: Optional[bytes] = None
        if connection is None and header.packet_type == PACKET_TYPE_INITIAL:
            # stateless retry
            if self._retry is not None:
                if not header.token:
                    # create a retry token
                    self._transport.sendto(
                        encode_quic_retry(
                            version=header.version,
                            source_cid=os.urandom(8),
                            destination_cid=header.source_cid,
                            original_destination_cid=header.destination_cid,
                            retry_token=self._retry.create_token(
                                addr, header.destination_cid),
                        ),
                        addr,
                    )
                    return
                else:
                    # validate retry token
                    try:
                        original_connection_id = self._retry.validate_token(
                            addr, header.token)
                    except ValueError:
                        return

            # create new connection
            connection = QuicConnection(
                configuration=self._configuration,
                original_connection_id=original_connection_id,
                session_ticket_fetcher=self._session_ticket_fetcher,
                session_ticket_handler=self._session_ticket_handler,
            )

            self._connections[header.destination_cid] = connection
            self._connections[connection.host_cid] = connection

        if connection is not None:
            connection.receive_datagram(cast(bytes, data),
                                        addr,
                                        now=self._loop.time())
            self._consume_events(connection)