Support LengthPrefixedConnectionIds in v99 This CL adds support for the invariants change from draft-22. It introduces a new parsing method QuicFramer::ParsePublicHeader which can parse both old and new formats, and uses it for v99 and also for all versions when gfe2_reloadable_flag_quic_use_parse_public_header is true. gfe-relnote: change v99 encoding, protected by disabled v99 flag and by gfe2_reloadable_flag_quic_use_parse_public_header. PiperOrigin-RevId: 260871822 Change-Id: I680d12141b2731401a818ed335af03e7c5365219
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc index be6e388..2542aca 100644 --- a/quic/core/http/end_to_end_test.cc +++ b/quic/core/http/end_to_end_test.cc
@@ -668,6 +668,7 @@ } TEST_P(EndToEndTest, SimpleRequestResponseForcedVersionNegotiation) { + SetQuicReloadableFlag(quic_use_parse_public_header, true); client_supported_versions_.insert(client_supported_versions_.begin(), QuicVersionReservedForNegotiation()); ASSERT_TRUE(Initialize()); @@ -680,6 +681,7 @@ } TEST_P(EndToEndTestWithTls, ForcedVersionNegotiation) { + SetQuicReloadableFlag(quic_use_parse_public_header, true); client_supported_versions_.insert(client_supported_versions_.begin(), QuicVersionReservedForNegotiation()); ASSERT_TRUE(Initialize()); @@ -2623,6 +2625,7 @@ QuicFramer::BuildVersionNegotiationPacket( incorrect_connection_id, EmptyQuicConnectionId(), VersionHasIetfInvariantHeader(client_connection->transport_version()), + client_connection->version().HasLengthPrefixedConnectionIds(), server_supported_versions_)); testing::NiceMock<MockQuicConnectionDebugVisitor> visitor; client_connection->set_debug_visitor(&visitor);
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index e65492f..df0d069 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -247,6 +247,7 @@ max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)), pending_version_negotiation_packet_(false), send_ietf_version_negotiation_packet_(false), + send_version_negotiation_packet_with_prefixed_lengths_(false), idle_timeout_connection_close_behavior_( ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET), close_connection_after_five_rtos_(false), @@ -1457,9 +1458,11 @@ } } -void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic) { +void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic, + bool has_length_prefix) { pending_version_negotiation_packet_ = true; send_ietf_version_negotiation_packet_ = ietf_quic; + send_version_negotiation_packet_with_prefixed_lengths_ = has_length_prefix; if (HandleWriteBlocked()) { return; @@ -1471,7 +1474,7 @@ << "}, " << (ietf_quic ? "" : "!") << "ietf_quic"; std::unique_ptr<QuicEncryptedPacket> version_packet( packet_generator_.SerializeVersionNegotiationPacket( - ietf_quic, framer_.supported_versions())); + ietf_quic, has_length_prefix, framer_.supported_versions())); QUIC_DVLOG(2) << ENDPOINT << "Sending version negotiation packet: {" << ParsedQuicVersionVectorToString(framer_.supported_versions()) << "}, " << (ietf_quic ? "" : "!") << "ietf_quic:" << std::endl @@ -1870,7 +1873,9 @@ DCHECK(!writer_->IsWriteBlocked()); if (pending_version_negotiation_packet_) { - SendVersionNegotiationPacket(send_ietf_version_negotiation_packet_); + SendVersionNegotiationPacket( + send_ietf_version_negotiation_packet_, + send_version_negotiation_packet_with_prefixed_lengths_); } QUIC_CLIENT_HISTOGRAM_COUNTS("QuicSession.NumQueuedPacketsBeforeWrite",
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h index 59a3656..45d31be 100644 --- a/quic/core/quic_connection.h +++ b/quic/core/quic_connection.h
@@ -980,7 +980,7 @@ const QuicStopWaitingFrame& stop_waiting); // Sends a version negotiation packet to the peer. - void SendVersionNegotiationPacket(bool ietf_quic); + void SendVersionNegotiationPacket(bool ietf_quic, bool has_length_prefix); // Clears any accumulated frames from the last received packet. void ClearLastFrames(); @@ -1217,6 +1217,7 @@ bool pending_version_negotiation_packet_; // Used when pending_version_negotiation_packet_ is true. bool send_ietf_version_negotiation_packet_; + bool send_version_negotiation_packet_with_prefixed_lengths_; // When packets could not be sent because the socket was not writable, // they are added to this list. All corresponding frames are in
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index ee7b651..f0152cd 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -6774,16 +6774,20 @@ } TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiation) { - // Start out with an unsupported version. - QuicConnectionPeer::GetFramer(&connection_) - ->set_version_for_tests(QuicVersionReservedForNegotiation()); + // All supported versions except the one the connection supports. + ParsedQuicVersionVector versions; + for (auto version : AllSupportedVersions()) { + if (version != connection_.version()) { + versions.push_back(version); + } + } // Send a version negotiation packet. std::unique_ptr<QuicEncryptedPacket> encrypted( QuicFramer::BuildVersionNegotiationPacket( connection_id_, EmptyQuicConnectionId(), VersionHasIetfInvariantHeader(connection_.transport_version()), - AllSupportedVersions())); + connection_.version().HasLengthPrefixedConnectionIds(), versions)); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*encrypted, QuicTime::Zero())); EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)) @@ -6804,6 +6808,7 @@ QuicFramer::BuildVersionNegotiationPacket( connection_id_, EmptyQuicConnectionId(), VersionHasIetfInvariantHeader(connection_.transport_version()), + connection_.version().HasLengthPrefixedConnectionIds(), AllSupportedVersions())); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*encrypted, QuicTime::Zero()));
diff --git a/quic/core/quic_crypto_stream_test.cc b/quic/core/quic_crypto_stream_test.cc index dd4450e..4117786 100644 --- a/quic/core/quic_crypto_stream_test.cc +++ b/quic/core/quic_crypto_stream_test.cc
@@ -519,10 +519,13 @@ SCOPED_TRACE(version); QuicByteCount expected_overhead = 48; if (VersionHasIetfInvariantHeader(version)) { - expected_overhead = 52; + expected_overhead += 4; } if (QuicVersionHasLongHeaderLengths(version)) { - expected_overhead = 55; + expected_overhead += 3; + } + if (VersionHasLengthPrefixedConnectionIds(version)) { + expected_overhead += 1; } EXPECT_EQ(expected_overhead, QuicCryptoStream::CryptoMessageFramingOverhead( version, TestConnectionId()));
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc index c6ee816..7522703 100644 --- a/quic/core/quic_dispatcher.cc +++ b/quic/core/quic_dispatcher.cc
@@ -228,11 +228,25 @@ QuicStringPiece(packet.data(), packet.length())); ReceivedPacketInfo packet_info(self_address, peer_address, packet); std::string detailed_error; - const QuicErrorCode error = QuicFramer::ProcessPacketDispatcher( - packet, expected_server_connection_id_length_, &packet_info.form, - &packet_info.version_flag, &packet_info.version_label, - &packet_info.destination_connection_id, &packet_info.source_connection_id, - &detailed_error); + QuicErrorCode error; + if (!GetQuicReloadableFlag(quic_use_parse_public_header)) { + error = QuicFramer::ProcessPacketDispatcher( + packet, expected_server_connection_id_length_, &packet_info.form, + &packet_info.version_flag, &packet_info.version_label, + &packet_info.destination_connection_id, + &packet_info.source_connection_id, &detailed_error); + } else { + QUIC_RELOADABLE_FLAG_COUNT(quic_use_parse_public_header); + bool retry_token_present; + QuicStringPiece retry_token; + error = QuicFramer::ParsePublicHeaderDispatcher( + packet, expected_server_connection_id_length_, &packet_info.form, + &packet_info.version_flag, &packet_info.use_length_prefix, + &packet_info.version_label, &packet_info.version, + &packet_info.destination_connection_id, + &packet_info.source_connection_id, &retry_token_present, &retry_token, + &detailed_error); + } if (error != QUIC_NO_ERROR) { // Packet has framing error. SetLastError(error); @@ -319,7 +333,8 @@ << " to time-wait list."; StatelesslyTerminateConnection( server_connection_id, packet_info.form, packet_info.version_flag, - packet_info.version, QUIC_HANDSHAKE_FAILED, "Reject connection", + packet_info.use_length_prefix, packet_info.version, + QUIC_HANDSHAKE_FAILED, "Reject connection", quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait( @@ -396,9 +411,12 @@ packet_info.source_connection_id; time_wait_list_manager()->SendVersionNegotiationPacket( server_connection_id, client_connection_id, - packet_info.form != GOOGLE_QUIC_PACKET, GetSupportedVersions(), - packet_info.self_address, packet_info.peer_address, - GetPerPacketContext()); + packet_info.form != GOOGLE_QUIC_PACKET, + packet_info.form != GOOGLE_QUIC_PACKET && + !QuicVersionLabelUses4BitConnectionIdLength( + packet_info.version_label), + GetSupportedVersions(), packet_info.self_address, + packet_info.peer_address, GetPerPacketContext()); } return true; } @@ -454,7 +472,8 @@ QUIC_CODE_COUNT(quic_reject_fate_time_wait); StatelesslyTerminateConnection( server_connection_id, packet_info->form, packet_info->version_flag, - packet_info->version, QUIC_HANDSHAKE_FAILED, "Reject connection", + packet_info->use_length_prefix, packet_info->version, + QUIC_HANDSHAKE_FAILED, "Reject connection", quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait( @@ -521,7 +540,9 @@ VersionHasIetfInvariantHeader(connection->transport_version()) ? IETF_QUIC_LONG_HEADER_PACKET : GOOGLE_QUIC_PACKET, - /*version_flag=*/true, connection->version(), QUIC_HANDSHAKE_FAILED, + /*version_flag=*/true, + connection->version().HasLengthPrefixedConnectionIds(), + connection->version(), QUIC_HANDSHAKE_FAILED, "Connection is closed by server before handshake confirmed", // Although it is our intention to send termination packets, the // |action| argument is not used by this call to @@ -665,6 +686,7 @@ QuicConnectionId server_connection_id, PacketHeaderFormat format, bool version_flag, + bool use_length_prefix, ParsedQuicVersion version, QuicErrorCode error_code, const std::string& error_details, @@ -707,7 +729,7 @@ std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets; termination_packets.push_back(QuicFramer::BuildVersionNegotiationPacket( server_connection_id, EmptyQuicConnectionId(), - /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, + /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, use_length_prefix, /*versions=*/{})); time_wait_list_manager()->AddConnectionIdToTimeWait( server_connection_id, /*ietf_quic=*/format != GOOGLE_QUIC_PACKET, @@ -728,8 +750,10 @@ server_connection_id, early_arrived_packets.ietf_quic ? IETF_QUIC_LONG_HEADER_PACKET : GOOGLE_QUIC_PACKET, - /*version_flag=*/true, early_arrived_packets.version, - QUIC_HANDSHAKE_FAILED, "Packets buffered for too long", + /*version_flag=*/true, + early_arrived_packets.version.HasLengthPrefixedConnectionIds(), + early_arrived_packets.version, QUIC_HANDSHAKE_FAILED, + "Packets buffered for too long", quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); } @@ -820,7 +844,8 @@ QUIC_CODE_COUNT(quic_reject_stop_accepting_new_connections); StatelesslyTerminateConnection( packet_info->destination_connection_id, packet_info->form, - /*version_flag=*/true, packet_info->version, QUIC_HANDSHAKE_FAILED, + /*version_flag=*/true, packet_info->use_length_prefix, + packet_info->version, QUIC_HANDSHAKE_FAILED, "Stop accepting new connections", quic::QuicTimeWaitListManager::SEND_STATELESS_RESET); // Time wait list will reject the packet correspondingly.
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h index cfaafa0..091e727 100644 --- a/quic/core/quic_dispatcher.h +++ b/quic/core/quic_dispatcher.h
@@ -254,6 +254,7 @@ QuicConnectionId server_connection_id, PacketHeaderFormat format, bool version_flag, + bool use_length_prefix, ParsedQuicVersion version, QuicErrorCode error_code, const std::string& error_details,
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc index b18bddb..0ac5d56 100644 --- a/quic/core/quic_dispatcher_test.cc +++ b/quic/core/quic_dispatcher_test.cc
@@ -524,13 +524,14 @@ } TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) { + SetQuicReloadableFlag(quic_use_parse_public_header, true); CreateTimeWaitListManager(); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL( *time_wait_list_manager_, - SendVersionNegotiationPacket(TestConnectionId(1), _, _, _, _, _, _)) + SendVersionNegotiationPacket(TestConnectionId(1), _, _, _, _, _, _, _)) .Times(1); // Pad the CHLO message with enough data to make the packet large enough // to trigger version negotiation. @@ -543,13 +544,14 @@ TEST_F(QuicDispatcherTest, StatelessVersionNegotiationWithClientConnectionId) { SetQuicRestartFlag(quic_do_not_override_connection_id, true); + SetQuicReloadableFlag(quic_use_parse_public_header, true); CreateTimeWaitListManager(); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(TestConnectionId(1), - TestConnectionId(2), _, _, _, _, _)) + SendVersionNegotiationPacket( + TestConnectionId(1), TestConnectionId(2), _, _, _, _, _, _)) .Times(1); // Pad the CHLO message with enough data to make the packet large enough // to trigger version negotiation. @@ -567,7 +569,7 @@ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(_, _, _, _, _, _, _)) + SendVersionNegotiationPacket(_, _, _, _, _, _, _, _)) .Times(0); std::string chlo = SerializeCHLO() + std::string(1200, 'a'); // Truncate to 1100 bytes of payload which results in a packet just @@ -583,6 +585,7 @@ // Disabling CHLO size validation allows the dispatcher to send version // negotiation packets in response to a CHLO that is otherwise too small. TEST_F(QuicDispatcherTest, VersionNegotiationWithoutChloSizeValidation) { + SetQuicReloadableFlag(quic_use_parse_public_header, true); crypto_config_.set_validate_chlo_size(false); CreateTimeWaitListManager(); @@ -590,7 +593,7 @@ EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(_, _, _, _, _, _, _)) + SendVersionNegotiationPacket(_, _, _, _, _, _, _, _)) .Times(1); std::string chlo = SerializeCHLO() + std::string(1200, 'a'); // Truncate to 1100 bytes of payload which results in a packet just @@ -927,6 +930,8 @@ } TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { + SetQuicRestartFlag(quic_dispatcher_hands_chlo_extractor_one_version, true); + SetQuicReloadableFlag(quic_use_parse_public_header, true); static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 7u, "Supported versions out of sync"); SetQuicReloadableFlag(quic_disable_version_39, false); @@ -994,7 +999,7 @@ QuicTime::Zero()); EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, - SendVersionNegotiationPacket(_, _, _, _, _, _, _)) + SendVersionNegotiationPacket(_, _, _, _, _, _, _, _)) .Times(1); dispatcher_->ProcessPacket(server_address_, client_address, packet); }
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc index 59edc79..944130d 100644 --- a/quic/core/quic_framer.cc +++ b/quic/core/quic_framer.cc
@@ -403,6 +403,7 @@ } bool AppendIetfConnectionIds(bool version_flag, + bool use_length_prefix, QuicConnectionId destination_connection_id, QuicConnectionId source_connection_id, QuicDataWriter* writer) { @@ -410,6 +411,11 @@ return writer->WriteConnectionId(destination_connection_id); } + if (use_length_prefix) { + return writer->WriteLengthPrefixedConnectionId(destination_connection_id) && + writer->WriteLengthPrefixedConnectionId(source_connection_id); + } + // Compute connection ID length byte. uint8_t dcil = GetConnectionIdLengthValue( static_cast<QuicConnectionIdLength>(destination_connection_id.length())); @@ -1396,6 +1402,7 @@ QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& versions) { ParsedQuicVersionVector wire_versions = versions; if (!GetQuicReloadableFlag(quic_version_negotiation_grease)) { @@ -1428,11 +1435,14 @@ } if (ietf_quic) { return BuildIetfVersionNegotiationPacket( - server_connection_id, client_connection_id, wire_versions); + use_length_prefix, server_connection_id, client_connection_id, + wire_versions); } // The GQUIC encoding does not support encoding client connection IDs. DCHECK(client_connection_id.IsEmpty()); + // The GQUIC encoding does not support length-prefixed connection IDs. + DCHECK(!use_length_prefix); DCHECK(!wire_versions.empty()); size_t len = kPublicFlagsSize + server_connection_id.length() + @@ -1464,10 +1474,15 @@ // static std::unique_ptr<QuicEncryptedPacket> QuicFramer::BuildIetfVersionNegotiationPacket( + bool use_length_prefix, QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, const ParsedQuicVersionVector& versions) { - QUIC_DVLOG(1) << "Building IETF version negotiation packet: " + QUIC_DVLOG(1) << "Building IETF version negotiation packet with" + << (use_length_prefix ? "" : "out") + << " length prefix, server_connection_id " + << server_connection_id << " client_connection_id " + << client_connection_id << " versions " << ParsedQuicVersionVectorToString(versions); DCHECK(client_connection_id.IsEmpty() || GetQuicRestartFlag(quic_do_not_override_connection_id)); @@ -1475,6 +1490,11 @@ size_t len = kPacketHeaderTypeSize + kConnectionIdLengthSize + client_connection_id.length() + server_connection_id.length() + (versions.size() + 1) * kQuicVersionSize; + if (use_length_prefix) { + // When using length-prefixed connection IDs, packets carry two lengths + // instead of one. + len += kConnectionIdLengthSize; + } std::unique_ptr<char[]> buffer(new char[len]); QuicDataWriter writer(len, buffer.get()); @@ -1488,8 +1508,8 @@ return nullptr; } - if (!AppendIetfConnectionIds(true, client_connection_id, server_connection_id, - &writer)) { + if (!AppendIetfConnectionIds(true, use_length_prefix, client_connection_id, + server_connection_id, &writer)) { return nullptr; } @@ -1627,17 +1647,26 @@ const QuicPacketHeader& header) { DCHECK_EQ(Perspective::IS_CLIENT, perspective_); - // Parse Original Destination Connection ID Length. - uint8_t odcil = header.type_byte & 0xf; - if (odcil != 0) { - odcil += kConnectionIdLengthAdjustment; - } - - // Parse Original Destination Connection ID. QuicConnectionId original_destination_connection_id; - if (!reader->ReadConnectionId(&original_destination_connection_id, odcil)) { - set_detailed_error("Unable to read Original Destination ConnectionId."); - return false; + if (version_.HasLengthPrefixedConnectionIds()) { + // Parse Original Destination Connection ID. + if (!reader->ReadLengthPrefixedConnectionId( + &original_destination_connection_id)) { + set_detailed_error("Unable to read Original Destination ConnectionId."); + return false; + } + } else { + // Parse Original Destination Connection ID Length. + uint8_t odcil = header.type_byte & 0xf; + if (odcil != 0) { + odcil += kConnectionIdLengthAdjustment; + } + + // Parse Original Destination Connection ID. + if (!reader->ReadConnectionId(&original_destination_connection_id, odcil)) { + set_detailed_error("Unable to read Original Destination ConnectionId."); + return false; + } } QuicStringPiece retry_token = reader->ReadRemainingPayload(); @@ -1646,42 +1675,6 @@ return true; } -bool QuicFramer::MaybeProcessIetfInitialRetryToken( - QuicDataReader* encrypted_reader, - QuicPacketHeader* header) { - if (!QuicVersionHasLongHeaderLengths(header->version.transport_version) || - header->form != IETF_QUIC_LONG_HEADER_PACKET || - header->long_packet_type != INITIAL) { - return true; - } - uint64_t retry_token_length = 0; - header->retry_token_length_length = encrypted_reader->PeekVarInt62Length(); - if (!encrypted_reader->ReadVarInt62(&retry_token_length)) { - set_detailed_error("Unable to read INITIAL retry token length."); - return RaiseError(QUIC_INVALID_PACKET_HEADER); - } - header->retry_token = encrypted_reader->PeekRemainingPayload(); - // Safety check to avoid spending ressources if malformed. - // At this point header->retry_token contains the rest of the packet - // so its length() is the amount of data remaining in the packet. - if (retry_token_length > header->retry_token.length()) { - set_detailed_error("INITIAL token length longer than packet."); - return RaiseError(QUIC_INVALID_PACKET_HEADER); - } - // Resize retry_token to make it only contain the retry token. - header->retry_token.remove_suffix(header->retry_token.length() - - retry_token_length); - // Advance encrypted_reader by retry_token_length. - uint8_t wasted_byte; - for (uint64_t i = 0; i < retry_token_length; ++i) { - if (!encrypted_reader->ReadUInt8(&wasted_byte)) { - set_detailed_error("Unable to read INITIAL retry token."); - return RaiseError(QUIC_INVALID_PACKET_HEADER); - } - } - return true; -} - // Seeks the current packet to check for a coalesced packet at the end. // If the IETF length field only spans part of the outer packet, // then there is a coalesced packet after this one. @@ -1766,8 +1759,6 @@ size_t buffer_length) { DCHECK_NE(GOOGLE_QUIC_PACKET, header->form); DCHECK(!header->has_possible_stateless_reset_token); - header->retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; - header->retry_token = QuicStringPiece(); header->length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; header->remaining_packet_length = 0; if (header->form == IETF_QUIC_SHORT_HEADER_PACKET && @@ -1784,10 +1775,6 @@ } } - if (!MaybeProcessIetfInitialRetryToken(encrypted_reader, header)) { - return false; - } - if (!MaybeProcessIetfLength(encrypted_reader, header)) { return false; } @@ -2215,7 +2202,7 @@ // Append connection ID. if (!AppendIetfConnectionIds( - header.version_flag, + header.version_flag, version_.HasLengthPrefixedConnectionIds(), header.destination_connection_id_included != CONNECTION_ID_ABSENT ? header.destination_connection_id : EmptyQuicConnectionId(), @@ -2547,7 +2534,7 @@ QuicPacketHeader* header) { uint8_t type; if (!reader->ReadBytes(&type, 1)) { - set_detailed_error("Unable to read type."); + set_detailed_error("Unable to read first byte."); return false; } header->type_byte = type; @@ -2701,6 +2688,78 @@ bool QuicFramer::ProcessIetfPacketHeader(QuicDataReader* reader, QuicPacketHeader* header) { + if (version_.HasLengthPrefixedConnectionIds()) { + uint8_t expected_destination_connection_id_length = + perspective_ == Perspective::IS_CLIENT + ? expected_client_connection_id_length_ + : expected_server_connection_id_length_; + QuicVersionLabel version_label; + bool has_length_prefix; + std::string detailed_error; + QuicErrorCode parse_result = QuicFramer::ParsePublicHeader( + reader, expected_destination_connection_id_length, + VersionHasIetfInvariantHeader(version_.transport_version), + &header->type_byte, &header->form, &header->version_flag, + &has_length_prefix, &version_label, &header->version, + &header->destination_connection_id, &header->source_connection_id, + &header->long_packet_type, &header->retry_token_length_length, + &header->retry_token, &detailed_error); + if (parse_result != QUIC_NO_ERROR) { + set_detailed_error(detailed_error); + return false; + } + header->destination_connection_id_included = CONNECTION_ID_PRESENT; + header->source_connection_id_included = + header->version_flag ? CONNECTION_ID_PRESENT : CONNECTION_ID_ABSENT; + if (header->source_connection_id_included == CONNECTION_ID_ABSENT) { + DCHECK(header->source_connection_id.IsEmpty()); + if (perspective_ == Perspective::IS_CLIENT) { + header->source_connection_id = last_serialized_server_connection_id_; + } else { + header->source_connection_id = last_serialized_client_connection_id_; + } + } + if (header->version_flag && + header->version.transport_version > QUIC_VERSION_44 && + !(header->type_byte & FLAGS_FIXED_BIT)) { + set_detailed_error("Fixed bit is 0 in long header."); + return false; + } + if (!header->version_flag && version_.transport_version > QUIC_VERSION_44 && + !(header->type_byte & FLAGS_FIXED_BIT)) { + set_detailed_error("Fixed bit is 0 in short header."); + return false; + } + if (!header->version_flag) { + if (!version_.HasHeaderProtection() && + !GetShortHeaderPacketNumberLength( + transport_version(), header->type_byte, + infer_packet_header_type_from_version_, + &header->packet_number_length)) { + set_detailed_error("Failed to get short header packet number length."); + return false; + } + return true; + } + if (header->long_packet_type == RETRY) { + if (!version().SupportsRetry()) { + set_detailed_error("RETRY not supported in this version."); + return false; + } + if (perspective_ == Perspective::IS_SERVER) { + set_detailed_error("Client-initiated RETRY is invalid."); + return false; + } + return true; + } + if (!header->version.HasHeaderProtection()) { + header->packet_number_length = GetLongHeaderPacketNumberLength( + header->version.transport_version, header->type_byte); + } + + return true; + } + if (!ProcessIetfHeaderTypeByte(reader, header)) { return false; } @@ -2734,13 +2793,13 @@ // Read connection ID. if (!reader->ReadConnectionId(&header->destination_connection_id, destination_connection_id_length)) { - set_detailed_error("Unable to read Destination ConnectionId."); + set_detailed_error("Unable to read destination connection ID."); return false; } if (!reader->ReadConnectionId(&header->source_connection_id, source_connection_id_length)) { - set_detailed_error("Unable to read Source ConnectionId."); + set_detailed_error("Unable to read source connection ID."); return false; } @@ -6202,6 +6261,7 @@ QuicConnectionId* destination_connection_id, QuicConnectionId* source_connection_id, std::string* detailed_error) { + DCHECK(!GetQuicReloadableFlag(quic_use_parse_public_header)); QuicDataReader reader(packet.data(), packet.length()); *source_connection_id = EmptyQuicConnectionId(); @@ -6274,6 +6334,268 @@ } // static +QuicErrorCode QuicFramer::ParsePublicHeaderDispatcher( + const QuicEncryptedPacket& packet, + uint8_t expected_destination_connection_id_length, + PacketHeaderFormat* format, + bool* version_present, + bool* has_length_prefix, + QuicVersionLabel* version_label, + ParsedQuicVersion* parsed_version, + QuicConnectionId* destination_connection_id, + QuicConnectionId* source_connection_id, + bool* retry_token_present, + QuicStringPiece* retry_token, + std::string* detailed_error) { + QuicDataReader reader(packet.data(), packet.length()); + if (reader.IsDoneReading()) { + *detailed_error = "Unable to read first byte."; + return QUIC_INVALID_PACKET_HEADER; + } + const uint8_t first_byte = reader.PeekByte(); + const bool ietf_format = QuicUtils::IsIetfPacketHeader(first_byte); + uint8_t unused_first_byte; + QuicVariableLengthIntegerLength retry_token_length_length; + QuicLongHeaderType unused_log_packet_type; + const QuicErrorCode error_code = ParsePublicHeader( + &reader, expected_destination_connection_id_length, ietf_format, + &unused_first_byte, format, version_present, has_length_prefix, + version_label, parsed_version, destination_connection_id, + source_connection_id, &unused_log_packet_type, &retry_token_length_length, + retry_token, detailed_error); + *retry_token_present = + retry_token_length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0; + return error_code; +} + +// static +QuicErrorCode QuicFramer::ParsePublicHeaderGoogleQuic( + QuicDataReader* reader, + uint8_t* first_byte, + PacketHeaderFormat* format, + bool* version_present, + QuicVersionLabel* version_label, + QuicConnectionId* destination_connection_id, + std::string* detailed_error) { + *format = GOOGLE_QUIC_PACKET; + *version_present = (*first_byte & PACKET_PUBLIC_FLAGS_VERSION) != 0; + uint8_t destination_connection_id_length = 0; + if ((*first_byte & PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID) != 0) { + destination_connection_id_length = kQuicDefaultConnectionIdLength; + } + if (!reader->ReadConnectionId(destination_connection_id, + destination_connection_id_length)) { + *detailed_error = "Unable to read ConnectionId."; + return QUIC_INVALID_PACKET_HEADER; + } + if (*version_present && !ProcessVersionLabel(reader, version_label)) { + *detailed_error = "Unable to read protocol version."; + return QUIC_INVALID_PACKET_HEADER; + } + return QUIC_NO_ERROR; +} + +namespace { + +inline bool PacketHasLengthPrefixedConnectionIds( + const QuicDataReader& reader, + ParsedQuicVersion parsed_version, + QuicVersionLabel version_label, + uint8_t first_byte) { + if (parsed_version.transport_version != QUIC_VERSION_UNSUPPORTED) { + return parsed_version.HasLengthPrefixedConnectionIds(); + } + + // Received unsupported version, check known old unsupported versions. + if (QuicVersionLabelUses4BitConnectionIdLength(version_label)) { + return false; + } + + // Received unknown version, check connection ID length byte. + if (reader.IsDoneReading()) { + // This check is required to safely peek the connection ID length byte. + return true; + } + const uint8_t connection_id_length_byte = reader.PeekByte(); + + // Check for packets produced by older versions of + // QuicFramer::WriteClientVersionNegotiationProbePacket + if (first_byte == 0xc0 && (connection_id_length_byte & 0x0f) == 0 && + connection_id_length_byte >= 0x50 && version_label == 0xcabadaba) { + return false; + } + + // Check for munged packets with version tag PROX. + if ((connection_id_length_byte & 0x0f) == 0 && + connection_id_length_byte >= 0x20 && version_label == 0x50524F58) { + return false; + } + + return true; +} + +inline bool ParseLongHeaderConnectionIds( + QuicDataReader* reader, + bool has_length_prefix, + QuicConnectionId* destination_connection_id, + QuicConnectionId* source_connection_id, + std::string* detailed_error) { + if (has_length_prefix) { + if (!reader->ReadLengthPrefixedConnectionId(destination_connection_id)) { + *detailed_error = "Unable to read destination connection ID."; + return false; + } + if (!reader->ReadLengthPrefixedConnectionId(source_connection_id)) { + *detailed_error = "Unable to read source connection ID."; + return false; + } + } else { + // Parse connection ID lengths. + uint8_t connection_id_lengths_byte; + if (!reader->ReadUInt8(&connection_id_lengths_byte)) { + *detailed_error = "Unable to read connection ID lengths."; + return false; + } + uint8_t destination_connection_id_length = + (connection_id_lengths_byte & kDestinationConnectionIdLengthMask) >> 4; + if (destination_connection_id_length != 0) { + destination_connection_id_length += kConnectionIdLengthAdjustment; + } + uint8_t source_connection_id_length = + connection_id_lengths_byte & kSourceConnectionIdLengthMask; + if (source_connection_id_length != 0) { + source_connection_id_length += kConnectionIdLengthAdjustment; + } + + // Read destination connection ID. + if (!reader->ReadConnectionId(destination_connection_id, + destination_connection_id_length)) { + *detailed_error = "Unable to read destination connection ID."; + return false; + } + + // Read source connection ID. + if (!reader->ReadConnectionId(source_connection_id, + source_connection_id_length)) { + *detailed_error = "Unable to read source connection ID."; + return false; + } + } + return true; +} + +} // namespace + +// static +QuicErrorCode QuicFramer::ParsePublicHeader( + QuicDataReader* reader, + uint8_t expected_destination_connection_id_length, + bool ietf_format, + uint8_t* first_byte, + PacketHeaderFormat* format, + bool* version_present, + bool* has_length_prefix, + QuicVersionLabel* version_label, + ParsedQuicVersion* parsed_version, + QuicConnectionId* destination_connection_id, + QuicConnectionId* source_connection_id, + QuicLongHeaderType* long_packet_type, + QuicVariableLengthIntegerLength* retry_token_length_length, + QuicStringPiece* retry_token, + std::string* detailed_error) { + *version_present = false; + *has_length_prefix = false; + *version_label = 0; + *parsed_version = UnsupportedQuicVersion(); + *source_connection_id = EmptyQuicConnectionId(); + *long_packet_type = INVALID_PACKET_TYPE; + *retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + *retry_token = QuicStringPiece(); + *detailed_error = ""; + + if (!reader->ReadUInt8(first_byte)) { + *detailed_error = "Unable to read first byte."; + return QUIC_INVALID_PACKET_HEADER; + } + + if (!ietf_format) { + return ParsePublicHeaderGoogleQuic( + reader, first_byte, format, version_present, version_label, + destination_connection_id, detailed_error); + } + + *format = GetIetfPacketHeaderFormat(*first_byte); + + if (*format == IETF_QUIC_SHORT_HEADER_PACKET) { + // Read destination connection ID using + // expected_destination_connection_id_length to determine its length. + if (!reader->ReadConnectionId(destination_connection_id, + expected_destination_connection_id_length)) { + *detailed_error = "Unable to read destination connection ID."; + return QUIC_INVALID_PACKET_HEADER; + } + return QUIC_NO_ERROR; + } + + DCHECK_EQ(IETF_QUIC_LONG_HEADER_PACKET, *format); + *version_present = true; + if (!ProcessVersionLabel(reader, version_label)) { + *detailed_error = "Unable to read protocol version."; + return QUIC_INVALID_PACKET_HEADER; + } + + if (*version_label == 0) { + *long_packet_type = VERSION_NEGOTIATION; + } + + // Parse version. + *parsed_version = ParseQuicVersionLabel(*version_label); + + // Figure out which IETF QUIC invariants this packet follows. + *has_length_prefix = PacketHasLengthPrefixedConnectionIds( + *reader, *parsed_version, *version_label, *first_byte); + + // Parse connection IDs. + if (!ParseLongHeaderConnectionIds(reader, *has_length_prefix, + destination_connection_id, + source_connection_id, detailed_error)) { + return QUIC_INVALID_PACKET_HEADER; + } + + if (parsed_version->transport_version == QUIC_VERSION_UNSUPPORTED) { + // Skip parsing of long packet type and retry token for unknown versions. + return QUIC_NO_ERROR; + } + + // Parse long packet type. + if (!GetLongHeaderType(parsed_version->transport_version, *first_byte, + long_packet_type)) { + *detailed_error = "Unable to parse long packet type."; + return QUIC_INVALID_PACKET_HEADER; + } + + if (!parsed_version->SupportsRetry() || *long_packet_type != INITIAL) { + // Retry token is only present on initial packets for some versions. + return QUIC_NO_ERROR; + } + + *retry_token_length_length = reader->PeekVarInt62Length(); + uint64_t retry_token_length; + if (!reader->ReadVarInt62(&retry_token_length)) { + *retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + *detailed_error = "Unable to read retry token length."; + return QUIC_INVALID_PACKET_HEADER; + } + + if (!reader->ReadStringPiece(retry_token, retry_token_length)) { + *detailed_error = "Unable to read retry token."; + return QUIC_INVALID_PACKET_HEADER; + } + + return QUIC_NO_ERROR; +} + +// static bool QuicFramer::WriteClientVersionNegotiationProbePacket( char* packet_bytes, QuicByteCount packet_length, @@ -6294,14 +6616,17 @@ QUIC_BUG << "Invalid connection_id_length"; return false; } + const bool use_length_prefix = + GetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids); + const uint8_t last_version_byte = use_length_prefix ? 0xda : 0xba; // clang-format off - static const unsigned char packet_start_bytes[] = { + const unsigned char packet_start_bytes[] = { // IETF long header with fixed bit set, type initial, all-0 encrypted bits. 0xc0, // Version, part of the IETF space reserved for negotiation. // This intentionally differs from QuicVersionReservedForNegotiation() // to allow differentiating them over the wire. - 0xca, 0xba, 0xda, 0xba, + 0xca, 0xba, 0xda, last_version_byte, }; // clang-format on static_assert(sizeof(packet_start_bytes) == 5, "bad packet_start_bytes size"); @@ -6313,8 +6638,9 @@ QuicConnectionId destination_connection_id(destination_connection_id_bytes, destination_connection_id_length); - if (!AppendIetfConnectionIds(/*version_flag=*/true, destination_connection_id, - EmptyQuicConnectionId(), &writer)) { + if (!AppendIetfConnectionIds( + /*version_flag=*/true, use_length_prefix, destination_connection_id, + EmptyQuicConnectionId(), &writer)) { QUIC_BUG << "Failed to write connection IDs"; return false; } @@ -6398,35 +6724,50 @@ *detailed_error = "Packet is not a version negotiation packet"; return false; } - uint8_t expected_server_connection_id_length = 0, - destination_connection_id_length = 0, source_connection_id_length = 0; - if (!ProcessAndValidateIetfConnectionIdLength( - &reader, UnsupportedQuicVersion(), Perspective::IS_CLIENT, - /*should_update_expected_server_connection_id_length=*/true, - &expected_server_connection_id_length, - &destination_connection_id_length, &source_connection_id_length, - detailed_error)) { - return false; - } - if (destination_connection_id_length != 0) { - *detailed_error = "Received unexpected destination connection ID length"; - return false; - } + const bool use_length_prefix = + GetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids); QuicConnectionId destination_connection_id, source_connection_id; - if (!reader.ReadConnectionId(&destination_connection_id, - destination_connection_id_length)) { - *detailed_error = "Failed to read destination connection ID"; - return false; + if (use_length_prefix) { + if (!reader.ReadLengthPrefixedConnectionId(&destination_connection_id)) { + *detailed_error = "Failed to read destination connection ID"; + return false; + } + if (!reader.ReadLengthPrefixedConnectionId(&source_connection_id)) { + *detailed_error = "Failed to read source connection ID"; + return false; + } + } else { + uint8_t expected_server_connection_id_length = 0, + destination_connection_id_length = 0, + source_connection_id_length = 0; + if (!ProcessAndValidateIetfConnectionIdLength( + &reader, UnsupportedQuicVersion(), Perspective::IS_CLIENT, + /*should_update_expected_server_connection_id_length=*/true, + &expected_server_connection_id_length, + &destination_connection_id_length, &source_connection_id_length, + detailed_error)) { + return false; + } + if (!reader.ReadConnectionId(&destination_connection_id, + destination_connection_id_length)) { + *detailed_error = "Failed to read destination connection ID"; + return false; + } + if (!reader.ReadConnectionId(&source_connection_id, + source_connection_id_length)) { + *detailed_error = "Failed to read source connection ID"; + return false; + } } - if (!reader.ReadConnectionId(&source_connection_id, - source_connection_id_length)) { - *detailed_error = "Failed to read source connection ID"; + + if (destination_connection_id.length() != 0) { + *detailed_error = "Received unexpected destination connection ID length"; return false; } memcpy(source_connection_id_bytes, source_connection_id.data(), - source_connection_id_length); - *source_connection_id_length_out = source_connection_id_length; + source_connection_id.length()); + *source_connection_id_length_out = source_connection_id.length(); return true; }
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h index 0143abe..a05ad8f 100644 --- a/quic/core/quic_framer.h +++ b/quic/core/quic_framer.h
@@ -387,6 +387,43 @@ QuicConnectionId* source_connection_id, std::string* detailed_error); + // Parses the unencryoted fields in a QUIC header using |reader| as input, + // stores the result in the other parameters. + // |expected_destination_connection_id_length| is only used for short headers. + static QuicErrorCode ParsePublicHeader( + QuicDataReader* reader, + uint8_t expected_destination_connection_id_length, + bool ietf_format, + uint8_t* first_byte, + PacketHeaderFormat* format, + bool* version_present, + bool* has_length_prefix, + QuicVersionLabel* version_label, + ParsedQuicVersion* parsed_version, + QuicConnectionId* destination_connection_id, + QuicConnectionId* source_connection_id, + QuicLongHeaderType* long_packet_type, + QuicVariableLengthIntegerLength* retry_token_length_length, + QuicStringPiece* retry_token, + std::string* detailed_error); + + // Parses the unencryoted fields in |packet| and stores them in the other + // parameters. This can only be called on the server. + // |expected_destination_connection_id_length| is only used for short headers. + static QuicErrorCode ParsePublicHeaderDispatcher( + const QuicEncryptedPacket& packet, + uint8_t expected_destination_connection_id_length, + PacketHeaderFormat* format, + bool* version_present, + bool* has_length_prefix, + QuicVersionLabel* version_label, + ParsedQuicVersion* parsed_version, + QuicConnectionId* destination_connection_id, + QuicConnectionId* source_connection_id, + bool* retry_token_present, + QuicStringPiece* retry_token, + std::string* detailed_error); + // Serializes a packet containing |frames| into |buffer|. // Returns the length of the packet, which must not be longer than // |packet_length|. Returns 0 if it fails to serialize. @@ -437,10 +474,12 @@ QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& versions); // Returns a new IETF version negotiation packet. static std::unique_ptr<QuicEncryptedPacket> BuildIetfVersionNegotiationPacket( + bool use_length_prefix, QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, const ParsedQuicVersionVector& versions); @@ -690,9 +729,6 @@ bool ProcessRetryPacket(QuicDataReader* reader, const QuicPacketHeader& header); - bool MaybeProcessIetfInitialRetryToken(QuicDataReader* encrypted_reader, - QuicPacketHeader* header); - void MaybeProcessCoalescedPacket(const QuicDataReader& encrypted_reader, uint64_t remaining_bytes_length, const QuicPacketHeader& header); @@ -828,6 +864,15 @@ static AckFrameInfo GetAckFrameInfo(const QuicAckFrame& frame); + static QuicErrorCode ParsePublicHeaderGoogleQuic( + QuicDataReader* reader, + uint8_t* first_byte, + PacketHeaderFormat* format, + bool* version_present, + QuicVersionLabel* version_label, + QuicConnectionId* destination_connection_id, + std::string* detailed_error); + // The Append* methods attempt to write the provided header or frame using the // |writer|, and return true if successful. @@ -957,6 +1002,7 @@ void set_error(QuicErrorCode error) { error_ = error; } void set_detailed_error(const char* error) { detailed_error_ = error; } + void set_detailed_error(std::string error) { detailed_error_ = error; } std::string detailed_error_; QuicFramerVisitorInterface* visitor_;
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc index d73c412..e2c106a 100644 --- a/quic/core/quic_framer_test.cc +++ b/quic/core/quic_framer_test.cc
@@ -218,7 +218,7 @@ QUIC_DLOG(INFO) << "QuicFramer Version Mismatch, version: " << received_version; ++version_mismatch_; - return true; + return false; } bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override { @@ -917,11 +917,25 @@ QuicConnectionId destination_connection_id, source_connection_id; QuicVersionLabel version_label; std::string detailed_error; - EXPECT_EQ(QUIC_NO_ERROR, - QuicFramer::ProcessPacketDispatcher( - *encrypted, kQuicDefaultConnectionIdLength, &format, - &version_flag, &version_label, &destination_connection_id, - &source_connection_id, &detailed_error)); + QuicErrorCode error_code; + if (!GetQuicReloadableFlag(quic_use_parse_public_header)) { + error_code = QuicFramer::ProcessPacketDispatcher( + *encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag, + &version_label, &destination_connection_id, &source_connection_id, + &detailed_error); + } else { + bool retry_token_present, use_length_prefix; + QuicStringPiece retry_token; + ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); + error_code = QuicFramer::ParsePublicHeaderDispatcher( + *encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag, + &use_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + EXPECT_FALSE(retry_token_present); + EXPECT_FALSE(use_length_prefix); + } + EXPECT_EQ(QUIC_NO_ERROR, error_code); EXPECT_EQ(GOOGLE_QUIC_PACKET, format); EXPECT_FALSE(version_flag); EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id.length()); @@ -933,7 +947,7 @@ // clang-format off PacketFragments packet44 = { // type (long header with packet type INITIAL) - {"Unable to read type.", + {"Unable to read first byte.", {0xFF}}, // version tag {"Unable to read protocol version.", @@ -942,7 +956,7 @@ {"Unable to read ConnectionId length.", {0x50}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -950,7 +964,7 @@ }; PacketFragments packet46 = { // type (long header with packet type INITIAL) - {"Unable to read type.", + {"Unable to read first byte.", {0xC3}}, // version tag {"Unable to read protocol version.", @@ -959,7 +973,7 @@ {"Unable to read ConnectionId length.", {0x50}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -995,11 +1009,24 @@ QuicConnectionId destination_connection_id, source_connection_id; QuicVersionLabel version_label; std::string detailed_error; - EXPECT_EQ(QUIC_NO_ERROR, - QuicFramer::ProcessPacketDispatcher( - *encrypted, kQuicDefaultConnectionIdLength, &format, - &version_flag, &version_label, &destination_connection_id, - &source_connection_id, &detailed_error)); + QuicErrorCode error_code; + if (!GetQuicReloadableFlag(quic_use_parse_public_header)) { + error_code = QuicFramer::ProcessPacketDispatcher( + *encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag, + &version_label, &destination_connection_id, &source_connection_id, + &detailed_error); + } else { + bool retry_token_present, use_length_prefix; + QuicStringPiece retry_token; + ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); + error_code = QuicFramer::ParsePublicHeaderDispatcher( + *encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag, + &use_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + EXPECT_EQ(retry_token_present, framer_.version().SupportsRetry()); + EXPECT_FALSE(use_length_prefix); + } EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); EXPECT_TRUE(version_flag); EXPECT_EQ(kQuicDefaultConnectionIdLength, destination_connection_id.length()); @@ -1012,6 +1039,7 @@ // This test requires an IETF long header. return; } + SetQuicReloadableFlag(quic_use_parse_public_header, false); SetQuicRestartFlag(quic_do_not_override_connection_id, true); SetDecrypterLevel(ENCRYPTION_ZERO_RTT); const unsigned char type_byte = @@ -1044,11 +1072,24 @@ QuicConnectionId destination_connection_id, source_connection_id; QuicVersionLabel version_label = 0; std::string detailed_error = ""; - EXPECT_EQ(QUIC_NO_ERROR, - QuicFramer::ProcessPacketDispatcher( - encrypted, kQuicDefaultConnectionIdLength, &format, - &version_flag, &version_label, &destination_connection_id, - &source_connection_id, &detailed_error)); + QuicErrorCode error_code; + if (!GetQuicReloadableFlag(quic_use_parse_public_header)) { + error_code = QuicFramer::ProcessPacketDispatcher( + encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag, + &version_label, &destination_connection_id, &source_connection_id, + &detailed_error); + } else { + bool retry_token_present, use_length_prefix; + QuicStringPiece retry_token; + ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); + error_code = QuicFramer::ParsePublicHeaderDispatcher( + encrypted, kQuicDefaultConnectionIdLength, &format, &version_flag, + &use_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + EXPECT_FALSE(retry_token_present); + EXPECT_FALSE(use_length_prefix); + } EXPECT_EQ("", detailed_error); EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); EXPECT_TRUE(version_flag); @@ -1142,7 +1183,7 @@ PacketFragments packet44 = { // type (short header, 4 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x32}}, // connection_id // packet number @@ -1152,7 +1193,7 @@ PacketFragments packet46 = { // type (short header, 4 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x43}}, // connection_id // packet number @@ -1162,7 +1203,7 @@ PacketFragments packet_hp = { // type (short header, 4 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x43}}, // connection_id // packet number @@ -1216,7 +1257,7 @@ PacketFragments packet44 = { // type (long header with packet type ZERO_RTT_PROTECTED) - {"Unable to read type.", + {"Unable to read first byte.", {0xFC}}, // version tag {"Unable to read protocol version.", @@ -1225,7 +1266,7 @@ {"Unable to read ConnectionId length.", {0x50}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1235,7 +1276,7 @@ PacketFragments packet46 = { // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes // packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0xD3}}, // version tag {"Unable to read protocol version.", @@ -1244,7 +1285,7 @@ {"Unable to read ConnectionId length.", {0x50}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1254,17 +1295,20 @@ PacketFragments packet99 = { // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes // packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0xD3}}, // version tag {"Unable to read protocol version.", {QUIC_VERSION_BYTES}}, - // connection_id length - {"Unable to read ConnectionId length.", - {0x50}}, - // connection_id - {"Unable to read Destination ConnectionId.", + // destination connection ID length + {"Unable to read destination connection ID.", + {0x08}}, + // destination connection ID + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // source connection ID length + {"Unable to read source connection ID.", + {0x00}}, // long header packet length {"Unable to read long header payload length.", {0x04}}, @@ -1315,10 +1359,10 @@ PacketFragments packet44 = { // type (short header, 4 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x32}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1327,10 +1371,10 @@ PacketFragments packet46 = { // type (short header, 4 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x43}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1339,10 +1383,10 @@ PacketFragments packet_hp = { // type (short header, 4 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x43}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", @@ -1390,10 +1434,10 @@ PacketFragments packet44 = { // type (short header, 2 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x31}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1402,10 +1446,10 @@ PacketFragments packet46 = { // type (short header, 2 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x41}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1414,10 +1458,10 @@ PacketFragments packet_hp = { // type (short header, 2 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x41}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", @@ -1473,10 +1517,10 @@ PacketFragments packet44 = { // type (8 byte connection_id and 1 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x30}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1485,10 +1529,10 @@ PacketFragments packet46 = { // type (8 byte connection_id and 1 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x40}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", @@ -1497,10 +1541,10 @@ PacketFragments packet_hp = { // type (8 byte connection_id and 1 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x40}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", @@ -1677,9 +1721,11 @@ 0xD0, // version tag QUIC_VERSION_BYTES, - // connection_id length - 0x05, - // connection_id + // destination connection ID length + 0x00, + // source connection ID length + 0x08, + // source connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // long header packet length 0x26, @@ -1775,11 +1821,33 @@ 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char packet99[] = { + // type (long header, ZERO_RTT_PROTECTED, 4-byte packet number) + 0xD3, + // version tag + 'Q', '0', '0', '0', + // destination connection ID length + 0x08, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (padding frame) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; // clang-format on unsigned char* p = packet; size_t p_size = QUIC_ARRAYSIZE(packet); - if (framer_.transport_version() > QUIC_VERSION_44) { + if (framer_.transport_version() >= QUIC_VERSION_99) { + p = packet99; + p_size = QUIC_ARRAYSIZE(packet99); + } else if (framer_.transport_version() > QUIC_VERSION_44) { p = packet45; p_size = QUIC_ARRAYSIZE(packet45); } else if (framer_.transport_version() > QUIC_VERSION_43) { @@ -1792,8 +1860,6 @@ ASSERT_TRUE(visitor_.header_.get()); EXPECT_EQ(0, visitor_.frame_count_); EXPECT_EQ(1, visitor_.version_mismatch_); - ASSERT_EQ(1u, visitor_.padding_frames_.size()); - EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes); } TEST_P(QuicFramerTest, PaddingFrame) { @@ -2213,9 +2279,11 @@ 0xD3, // version tag QUIC_VERSION_BYTES, - // connection_id length - 0x05, - // connection_id + // destination connection ID length + 0x00, + // source connection ID length + 0x08, + // source connection ID 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, // IETF long header payload length 0x05, @@ -2738,12 +2806,15 @@ // version tag {"", {QUIC_VERSION_BYTES}}, - // connection_id length + // destination connection ID length {"", - {0x50}}, - // connection_id + {0x08}}, + // destination connection ID {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // source connection ID length + {"", + {0x00}}, // long header packet length {"", {0x1E}}, @@ -5682,12 +5753,34 @@ {QUIC_VERSION_BYTES, 'Q', '2', '.', '0'}}, }; + + PacketFragments packet99 = { + // type (long header) + {"", + {0x8F}}, + // version tag + {"", + {0x00, 0x00, 0x00, 0x00}}, + {"", + {0x08}}, + // connection_id + {"", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + {"", + {0x00}}, + // Supported versions + {"Unable to read supported version in negotiation.", + {QUIC_VERSION_BYTES, + 'Q', '2', '.', '0'}}, + }; // clang-format on QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet; + framer_.transport_version() >= QUIC_VERSION_99 + ? packet99 + : framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet; std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -5725,9 +5818,30 @@ QUIC_VERSION_BYTES, 'Q', '2', '.', '0', }; + unsigned char packet2[] = { + // public flags (long header with all ignored bits set) + 0xFF, + // version + 0x00, 0x00, 0x00, 0x00, + // destination connection ID length + 0x08, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // source connection ID length + 0x00, + // supported versions + QUIC_VERSION_BYTES, + 'Q', '2', '.', '0', + }; // clang-format on + unsigned char* p = packet; + size_t p_length = QUIC_ARRAYSIZE(packet); + if (framer_.version().HasLengthPrefixedConnectionIds()) { + p = packet2; + p_length = QUIC_ARRAYSIZE(packet2); + } - QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + QuicEncryptedPacket encrypted(AsChars(p), p_length, false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_INVALID_VERSION_NEGOTIATION_PACKET, framer_.error()); EXPECT_EQ("Server received version negotiation packet.", @@ -5796,9 +5910,34 @@ 'H', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'i', 's', ' ', 'i', 's', ' ', 'R', 'E', 'T', 'R', 'Y', '!', }; + unsigned char packet99[] = { + // public flags (long header with packet type RETRY) + 0xF0, + // version + QUIC_VERSION_BYTES, + // destination connection ID length + 0x00, + // source connection ID length + 0x08, + // source connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // original destination connection ID length + 0x08, + // original destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // retry token + 'H', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'i', 's', + ' ', 'i', 's', ' ', 'R', 'E', 'T', 'R', 'Y', '!', + }; // clang-format on - QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + unsigned char* p = packet; + size_t p_length = QUIC_ARRAYSIZE(packet); + if (framer_.transport_version() == QUIC_VERSION_99) { + p = packet99; + p_length = QUIC_ARRAYSIZE(packet99); + } + QuicEncryptedPacket encrypted(AsChars(p), p_length, false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -5828,7 +5967,7 @@ // version QUIC_VERSION_BYTES, // connection ID lengths - 0x05, + 0x00, 0x08, // source connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, // original destination connection ID @@ -6557,10 +6696,12 @@ 0xD3, // version tag QUIC_VERSION_BYTES, - // connection_id length - 0x50, - // connection_id + // destination connection ID length + 0x08, + // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // length 0x40, 0x1D, // packet number @@ -6786,10 +6927,28 @@ 0xDA, 0x5A, 0x3A, 0x3A, QUIC_VERSION_BYTES, }; + unsigned char packet99[] = { + // type (long header) + 0xC0, + // version tag + 0x00, 0x00, 0x00, 0x00, + // destination connection ID length + 0x00, + // source connection ID length + 0x08, + // source connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // supported versions + 0xDA, 0x5A, 0x3A, 0x3A, + QUIC_VERSION_BYTES, + }; // clang-format on unsigned char* p = packet; size_t p_size = QUIC_ARRAYSIZE(packet); - if (framer_.transport_version() > QUIC_VERSION_43) { + if (framer_.transport_version() >= QUIC_VERSION_99) { + p = packet99; + p_size = QUIC_ARRAYSIZE(packet99); + } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); } @@ -6799,14 +6958,14 @@ QuicFramer::BuildVersionNegotiationPacket( connection_id, EmptyQuicConnectionId(), framer_.transport_version() > QUIC_VERSION_43, + framer_.version().HasLengthPrefixedConnectionIds(), SupportedVersions(GetParam()))); test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(p), p_size); } TEST_P(QuicFramerTest, BuildVersionNegotiationPacketWithClientConnectionId) { - if (framer_.transport_version() <= QUIC_VERSION_43) { - // The GQUIC encoding does not support encoding client connection IDs. + if (!framer_.version().SupportsClientConnectionIds()) { return; } @@ -6821,11 +6980,11 @@ 0xC0, // version tag 0x00, 0x00, 0x00, 0x00, - // connection ID lengths - 0x55, // client/destination connection ID + 0x08, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, // server/source connection ID + 0x08, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // supported versions 0xDA, 0x5A, 0x3A, 0x3A, @@ -6836,9 +6995,9 @@ QuicConnectionId server_connection_id = FramerTestConnectionId(); QuicConnectionId client_connection_id = FramerTestConnectionIdPlusOne(); std::unique_ptr<QuicEncryptedPacket> data( - QuicFramer::BuildVersionNegotiationPacket(server_connection_id, - client_connection_id, true, - SupportedVersions(GetParam()))); + QuicFramer::BuildVersionNegotiationPacket( + server_connection_id, client_connection_id, true, true, + SupportedVersions(GetParam()))); test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(packet), QUIC_ARRAYSIZE(packet)); @@ -9873,10 +10032,12 @@ 0xD3, // version tag 'Q', '.', '1', '0', - // connection_id length - 0x50, - // connection_id + // destination connection ID length + 0x08, + // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // packet number 0x12, 0x34, 0x56, 0x78, @@ -13051,9 +13212,11 @@ // version QUIC_VERSION_BYTES, // destination connection ID length - 0x50, + 0x08, // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // long header packet length 0x1E, // packet number @@ -13078,9 +13241,11 @@ // version QUIC_VERSION_BYTES, // destination connection ID length - 0x50, + 0x08, // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // long header packet length 0x1E, // packet number @@ -13146,9 +13311,11 @@ // version QUIC_VERSION_BYTES, // destination connection ID length - 0x50, + 0x08, // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // long header packet length 0x1E, // packet number @@ -13173,9 +13340,11 @@ // version QUIC_VERSION_BYTES, // destination connection ID length - 0x50, + 0x08, // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // source connection ID length + 0x00, // long header packet length 0x1E, // packet number @@ -13229,9 +13398,11 @@ // version QUIC_VERSION_BYTES, // destination connection ID length - 0x50, + 0x08, // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // long header packet length 0x1E, // packet number @@ -13327,7 +13498,8 @@ // Make sure we discard the subsequent zeroes. EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)), - "Server: Received mismatched coalesced header.*"); + "Server: (Failed to parse received|Received mismatched) " + "coalesced header.*"); } TEST_P(QuicFramerTest, ClientReceivesInvalidVersion) { @@ -13376,10 +13548,10 @@ // clang-format off PacketFragments packet = { // type (8 byte connection_id and 1 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x40}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42}}, // packet number {"Unable to read packet number.", @@ -13388,10 +13560,10 @@ PacketFragments packet_with_padding = { // type (8 byte connection_id and 1 byte packet number) - {"Unable to read type.", + {"Unable to read first byte.", {0x40}}, // connection_id - {"Unable to read Destination ConnectionId.", + {"Unable to read destination connection ID.", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x42}}, // packet number {"", @@ -13451,9 +13623,11 @@ // version QUIC_VERSION_BYTES, // destination connection ID length - 0x50, + 0x08, // destination connection ID 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, // long header packet length 0x05, // packet number @@ -13535,7 +13709,7 @@ // clang-format off PacketFragments packet = { // public flags (IETF Retry packet, 0-length original destination CID) - {"Unable to read type.", + {"Unable to read first byte.", {0xf0}}, // version tag {"Unable to read protocol version.", @@ -13549,7 +13723,7 @@ // clang-format off PacketFragments packet45 = { // public flags (IETF Retry packet, 0-length original destination CID) - {"Unable to read type.", + {"Unable to read first byte.", {0xf0}}, // version tag {"Unable to read protocol version.", @@ -13580,7 +13754,7 @@ // clang-format off PacketFragments packet = { // public flags (IETF Retry packet, 0-length original destination CID) - {"Unable to read type.", + {"Unable to read first byte.", {0xf0}}, // version tag {"Unable to read protocol version.", @@ -13677,7 +13851,8 @@ CheckFramingBoundaries(packet, QUIC_INVALID_PACKET_HEADER); } -TEST_P(QuicFramerTest, WriteClientVersionNegotiationProbePacket) { +TEST_P(QuicFramerTest, WriteClientVersionNegotiationProbePacketOld) { + SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, false); // clang-format off static const char expected_packet[1200] = { // IETF long header with fixed bit set, type initial, all-0 encrypted bits. @@ -13726,17 +13901,18 @@ EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket( packet, sizeof(packet), destination_connection_id_bytes, sizeof(destination_connection_id_bytes))); - test::CompareCharArraysWithHexError("constructed packet", expected_packet, - sizeof(expected_packet), packet, - sizeof(packet)); + test::CompareCharArraysWithHexError("constructed packet", packet, + sizeof(packet), expected_packet, + sizeof(expected_packet)); QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet), sizeof(packet), false); // Make sure we fail to parse this packet for the version under test. - EXPECT_FALSE(framer_.ProcessPacket(encrypted)); if (framer_.transport_version() <= QUIC_VERSION_43) { // We can only parse the connection ID with an IETF parser. + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); return; } + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); ASSERT_TRUE(visitor_.header_.get()); QuicConnectionId probe_payload_connection_id( reinterpret_cast<const char*>(destination_connection_id_bytes), @@ -13745,7 +13921,232 @@ visitor_.header_.get()->destination_connection_id); } -TEST_P(QuicFramerTest, ParseServerVersionNegotiationProbeResponse) { +TEST_P(QuicFramerTest, WriteClientVersionNegotiationProbePacket) { + SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, true); + // clang-format off + static const char expected_packet[1200] = { + // IETF long header with fixed bit set, type initial, all-0 encrypted bits. + 0xc0, + // Version, part of the IETF space reserved for negotiation. + 0xca, 0xba, 0xda, 0xda, + // Destination connection ID length 8. + 0x08, + // 8-byte destination connection ID. + 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21, + // Source connection ID length 0. + 0x00, + // 8 bytes of zeroes followed by 8 bytes of ones to ensure that this does + // not parse with any known version. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + // zeroes to pad to 16 byte boundary. + 0x00, + // A polite greeting in case a human sees this in tcpdump. + 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x63, + 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, + 0x51, 0x55, 0x49, 0x43, 0x20, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x65, 0x67, + 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b, + 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x20, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x20, 0x54, 0x68, 0x61, 0x6e, 0x6b, 0x20, 0x79, + 0x6f, 0x75, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6e, 0x69, + 0x63, 0x65, 0x20, 0x64, 0x61, 0x79, 0x2e, 0x00, + }; + // clang-format on + char packet[1200]; + char destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70, + 0x6c, 0x7a, 0x20, 0x21}; + EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket( + packet, sizeof(packet), destination_connection_id_bytes, + sizeof(destination_connection_id_bytes))); + test::CompareCharArraysWithHexError("constructed packet", packet, + sizeof(packet), expected_packet, + sizeof(expected_packet)); + QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet), + sizeof(packet), false); + if (framer_.transport_version() < QUIC_VERSION_99) { + // We can only parse the connection ID with a v99 parser. + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + return; + } + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + ASSERT_TRUE(visitor_.header_.get()); + QuicConnectionId probe_payload_connection_id( + reinterpret_cast<const char*>(destination_connection_id_bytes), + sizeof(destination_connection_id_bytes)); + EXPECT_EQ(probe_payload_connection_id, + visitor_.header_.get()->destination_connection_id); +} + +TEST_P(QuicFramerTest, DispatcherParseOldClientVersionNegotiationProbePacket) { + // clang-format off + static const char packet[1200] = { + // IETF long header with fixed bit set, type initial, all-0 encrypted bits. + 0xc0, + // Version, part of the IETF space reserved for negotiation. + 0xca, 0xba, 0xda, 0xba, + // Destination connection ID length 8, source connection ID length 0. + 0x50, + // 8-byte destination connection ID. + 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21, + // 8 bytes of zeroes followed by 8 bytes of ones to ensure that this does + // not parse with any known version. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + // 2 bytes of zeroes to pad to 16 byte boundary. + 0x00, 0x00, + // A polite greeting in case a human sees this in tcpdump. + 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x63, + 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, + 0x51, 0x55, 0x49, 0x43, 0x20, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x65, 0x67, + 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b, + 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x20, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x20, 0x54, 0x68, 0x61, 0x6e, 0x6b, 0x20, 0x79, + 0x6f, 0x75, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6e, 0x69, + 0x63, 0x65, 0x20, 0x64, 0x61, 0x79, 0x2e, 0x00, + }; + // clang-format on + char expected_destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70, + 0x6c, 0x7a, 0x20, 0x21}; + QuicConnectionId expected_destination_connection_id( + reinterpret_cast<const char*>(expected_destination_connection_id_bytes), + sizeof(expected_destination_connection_id_bytes)); + + QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet), + sizeof(packet)); + PacketHeaderFormat format = GOOGLE_QUIC_PACKET; + bool version_present = false, has_length_prefix = true; + QuicVersionLabel version_label = 33; + ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); + QuicConnectionId destination_connection_id = TestConnectionId(1); + QuicConnectionId source_connection_id = TestConnectionId(2); + bool retry_token_present = true; + QuicStringPiece retry_token; + std::string detailed_error = "foobar"; + QuicErrorCode header_parse_result = QuicFramer::ParsePublicHeaderDispatcher( + encrypted, kQuicDefaultConnectionIdLength, &format, &version_present, + &has_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + EXPECT_EQ(QUIC_NO_ERROR, header_parse_result); + EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); + EXPECT_TRUE(version_present); + EXPECT_FALSE(has_length_prefix); + EXPECT_EQ(0xcabadaba, version_label); + EXPECT_EQ(expected_destination_connection_id, destination_connection_id); + EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id); + EXPECT_FALSE(retry_token_present); + EXPECT_EQ("", detailed_error); +} + +TEST_P(QuicFramerTest, DispatcherParseClientVersionNegotiationProbePacket) { + // clang-format off + static const char packet[1200] = { + // IETF long header with fixed bit set, type initial, all-0 encrypted bits. + 0xc0, + // Version, part of the IETF space reserved for negotiation. + 0xca, 0xba, 0xda, 0xba, + // Destination connection ID length 8. + 0x08, + // 8-byte destination connection ID. + 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21, + // Source connection ID length 0. + 0x00, + // 8 bytes of zeroes followed by 8 bytes of ones to ensure that this does + // not parse with any known version. + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + // 1 byte of zeroes to pad to 16 byte boundary. + 0x00, + // A polite greeting in case a human sees this in tcpdump. + 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x63, + 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x72, 0x69, 0x67, 0x67, + 0x65, 0x72, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, + 0x51, 0x55, 0x49, 0x43, 0x20, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x65, 0x67, + 0x6f, 0x74, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x20, 0x50, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x20, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, + 0x4e, 0x65, 0x67, 0x6f, 0x74, 0x69, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x61, 0x63, 0x6b, + 0x65, 0x74, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x77, 0x68, + 0x61, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x20, 0x79, 0x6f, 0x75, 0x20, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x20, 0x54, 0x68, 0x61, 0x6e, 0x6b, 0x20, 0x79, + 0x6f, 0x75, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x6e, 0x69, + 0x63, 0x65, 0x20, 0x64, 0x61, 0x79, 0x2e, 0x00, + }; + // clang-format on + char expected_destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70, + 0x6c, 0x7a, 0x20, 0x21}; + QuicConnectionId expected_destination_connection_id( + reinterpret_cast<const char*>(expected_destination_connection_id_bytes), + sizeof(expected_destination_connection_id_bytes)); + + QuicEncryptedPacket encrypted(reinterpret_cast<const char*>(packet), + sizeof(packet)); + PacketHeaderFormat format = GOOGLE_QUIC_PACKET; + bool version_present = false, has_length_prefix = false; + QuicVersionLabel version_label = 33; + ParsedQuicVersion parsed_version = UnsupportedQuicVersion(); + QuicConnectionId destination_connection_id = TestConnectionId(1); + QuicConnectionId source_connection_id = TestConnectionId(2); + bool retry_token_present = true; + QuicStringPiece retry_token; + std::string detailed_error = "foobar"; + QuicErrorCode header_parse_result = QuicFramer::ParsePublicHeaderDispatcher( + encrypted, kQuicDefaultConnectionIdLength, &format, &version_present, + &has_length_prefix, &version_label, &parsed_version, + &destination_connection_id, &source_connection_id, &retry_token_present, + &retry_token, &detailed_error); + EXPECT_EQ(QUIC_NO_ERROR, header_parse_result); + EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); + EXPECT_TRUE(version_present); + EXPECT_TRUE(has_length_prefix); + EXPECT_EQ(0xcabadaba, version_label); + EXPECT_EQ(expected_destination_connection_id, destination_connection_id); + EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id); + EXPECT_EQ("", detailed_error); +} + +TEST_P(QuicFramerTest, ParseServerVersionNegotiationProbeResponseOld) { + SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, false); // clang-format off const char packet[] = { // IETF long header with fixed bit set, type initial, all-0 encrypted bits. @@ -13771,8 +14172,39 @@ &parsed_probe_payload_length, &parse_detailed_error)); EXPECT_EQ("", parse_detailed_error); test::CompareCharArraysWithHexError( - "parsed probe", probe_payload_bytes, sizeof(probe_payload_bytes), - parsed_probe_payload_bytes, parsed_probe_payload_length); + "parsed probe", parsed_probe_payload_bytes, parsed_probe_payload_length, + probe_payload_bytes, sizeof(probe_payload_bytes)); +} + +TEST_P(QuicFramerTest, ParseServerVersionNegotiationProbeResponse) { + SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, true); + // clang-format off + const char packet[] = { + // IETF long header with fixed bit set, type initial, all-0 encrypted bits. + 0xc0, + // Version of 0, indicating version negotiation. + 0x00, 0x00, 0x00, 0x00, + // Destination connection ID length 0, source connection ID length 8. + 0x00, 0x08, + // 8-byte source connection ID. + 0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21, + // A few supported versions. + 0xaa, 0xaa, 0xaa, 0xaa, + QUIC_VERSION_BYTES, + }; + // clang-format on + char probe_payload_bytes[] = {0x56, 0x4e, 0x20, 0x70, 0x6c, 0x7a, 0x20, 0x21}; + char parsed_probe_payload_bytes[kQuicMaxConnectionIdLength] = {}; + uint8_t parsed_probe_payload_length = 0; + std::string parse_detailed_error = ""; + EXPECT_TRUE(QuicFramer::ParseServerVersionNegotiationProbeResponse( + reinterpret_cast<const char*>(packet), sizeof(packet), + reinterpret_cast<char*>(parsed_probe_payload_bytes), + &parsed_probe_payload_length, &parse_detailed_error)); + EXPECT_EQ("", parse_detailed_error); + test::CompareCharArraysWithHexError( + "parsed probe", parsed_probe_payload_bytes, parsed_probe_payload_length, + probe_payload_bytes, sizeof(probe_payload_bytes)); } TEST_P(QuicFramerTest, ClientConnectionIdFromLongHeaderToClient) { @@ -13802,9 +14234,34 @@ // padding frame 0x00, }; + unsigned char packet99[] = { + // public flags (long header with packet type HANDSHAKE and + // 4-byte packet number) + 0xE3, + // version + QUIC_VERSION_BYTES, + // destination connection ID length + 0x08, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // source connection ID length + 0x00, + // long header packet length + 0x05, + // packet number + 0x12, 0x34, 0x56, 0x00, + // padding frame + 0x00, + }; // clang-format on - const bool parse_success = framer_.ProcessPacket( - QuicEncryptedPacket(AsChars(packet), QUIC_ARRAYSIZE(packet), false)); + unsigned char* p = packet; + size_t p_length = QUIC_ARRAYSIZE(packet); + if (framer_.transport_version() == QUIC_VERSION_99) { + p = packet99; + p_length = QUIC_ARRAYSIZE(packet99); + } + const bool parse_success = + framer_.ProcessPacket(QuicEncryptedPacket(AsChars(p), p_length, false)); if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion( framer_.transport_version())) { EXPECT_FALSE(parse_success); @@ -13855,9 +14312,32 @@ // padding frame 0x00, }; + unsigned char packet99[] = { + // public flags (long header with packet type HANDSHAKE and + // 4-byte packet number) + 0xE3, + // version + QUIC_VERSION_BYTES, + // connection ID lengths + 0x00, 0x08, + // source connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // long header packet length + 0x05, + // packet number + 0x12, 0x34, 0x56, 0x00, + // padding frame + 0x00, + }; // clang-format on - const bool parse_success = framer_.ProcessPacket( - QuicEncryptedPacket(AsChars(packet), QUIC_ARRAYSIZE(packet), false)); + unsigned char* p = packet; + size_t p_length = QUIC_ARRAYSIZE(packet); + if (framer_.transport_version() == QUIC_VERSION_99) { + p = packet99; + p_length = QUIC_ARRAYSIZE(packet99); + } + const bool parse_success = + framer_.ProcessPacket(QuicEncryptedPacket(AsChars(p), p_length, false)); if (!QuicUtils::VariableLengthConnectionIdAllowedForVersion( framer_.transport_version())) { EXPECT_FALSE(parse_success);
diff --git a/quic/core/quic_ietf_framer_test.cc b/quic/core/quic_ietf_framer_test.cc index dbbacdd..f0872b6 100644 --- a/quic/core/quic_ietf_framer_test.cc +++ b/quic/core/quic_ietf_framer_test.cc
@@ -102,7 +102,7 @@ bool OnProtocolVersionMismatch( ParsedQuicVersion /*received_version*/) override { - return true; + return false; } bool OnUnauthenticatedPublicHeader(
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc index a8d3291..27c913e 100644 --- a/quic/core/quic_packet_creator.cc +++ b/quic/core/quic_packet_creator.cc
@@ -640,12 +640,13 @@ std::unique_ptr<QuicEncryptedPacket> QuicPacketCreator::SerializeVersionNegotiationPacket( bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& supported_versions) { DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective()); std::unique_ptr<QuicEncryptedPacket> encrypted = - QuicFramer::BuildVersionNegotiationPacket(server_connection_id_, - client_connection_id_, - ietf_quic, supported_versions); + QuicFramer::BuildVersionNegotiationPacket( + server_connection_id_, client_connection_id_, ietf_quic, + use_length_prefix, supported_versions); DCHECK(encrypted); DCHECK_GE(max_packet_length_, encrypted->length()); return encrypted;
diff --git a/quic/core/quic_packet_creator.h b/quic/core/quic_packet_creator.h index 2c2fffb..affc15c 100644 --- a/quic/core/quic_packet_creator.h +++ b/quic/core/quic_packet_creator.h
@@ -187,6 +187,7 @@ // Creates a version negotiation packet which supports |supported_versions|. std::unique_ptr<QuicEncryptedPacket> SerializeVersionNegotiationPacket( bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& supported_versions); // Creates a connectivity probing packet for versions prior to version 99.
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc index 802c07b..bd49182 100644 --- a/quic/core/quic_packet_creator_test.cc +++ b/quic/core/quic_packet_creator_test.cc
@@ -813,8 +813,11 @@ versions.push_back(test::QuicVersionMax()); const bool ietf_quic = VersionHasIetfInvariantHeader(GetParam().version.transport_version); + const bool has_length_prefix = + GetParam().version.HasLengthPrefixedConnectionIds(); std::unique_ptr<QuicEncryptedPacket> encrypted( - creator_.SerializeVersionNegotiationPacket(ietf_quic, versions)); + creator_.SerializeVersionNegotiationPacket(ietf_quic, has_length_prefix, + versions)); { InSequence s; @@ -1820,6 +1823,9 @@ if (QuicVersionHasLongHeaderLengths(version)) { expected_largest_payload -= 2; } + if (GetParam().version.HasLengthPrefixedConnectionIds()) { + expected_largest_payload -= 1; + } EXPECT_EQ(expected_largest_payload, creator_.GetGuaranteedLargestMessagePayload()); }
diff --git a/quic/core/quic_packet_generator.cc b/quic/core/quic_packet_generator.cc index fe17069..160222f 100644 --- a/quic/core/quic_packet_generator.cc +++ b/quic/core/quic_packet_generator.cc
@@ -297,9 +297,10 @@ std::unique_ptr<QuicEncryptedPacket> QuicPacketGenerator::SerializeVersionNegotiationPacket( bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& supported_versions) { - return packet_creator_.SerializeVersionNegotiationPacket(ietf_quic, - supported_versions); + return packet_creator_.SerializeVersionNegotiationPacket( + ietf_quic, use_length_prefix, supported_versions); } OwningSerializedPacketPointer
diff --git a/quic/core/quic_packet_generator.h b/quic/core/quic_packet_generator.h index ea7da5d..c6902e0 100644 --- a/quic/core/quic_packet_generator.h +++ b/quic/core/quic_packet_generator.h
@@ -141,6 +141,7 @@ // Creates a version negotiation packet which supports |supported_versions|. std::unique_ptr<QuicEncryptedPacket> SerializeVersionNegotiationPacket( bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& supported_versions); // Creates a connectivity probing packet.
diff --git a/quic/core/quic_packets.cc b/quic/core/quic_packets.cc index 4887e82..7d4769f 100644 --- a/quic/core/quic_packets.cc +++ b/quic/core/quic_packets.cc
@@ -134,6 +134,9 @@ if (include_diversification_nonce) { size += kDiversificationNonceSize; } + if (VersionHasLengthPrefixedConnectionIds(version)) { + size += kConnectionIdLengthSize; + } DCHECK(QuicVersionHasLongHeaderLengths(version) || !GetQuicReloadableFlag(quic_fix_get_packet_header_size) || retry_token_length_length + retry_token_length + length_length == @@ -508,6 +511,7 @@ packet(packet), form(GOOGLE_QUIC_PACKET), version_flag(false), + use_length_prefix(false), version_label(0), version(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED), destination_connection_id(EmptyQuicConnectionId()),
diff --git a/quic/core/quic_packets.h b/quic/core/quic_packets.h index cf6099e..3af15ea 100644 --- a/quic/core/quic_packets.h +++ b/quic/core/quic_packets.h
@@ -425,6 +425,7 @@ // Fields below are populated by QuicFramer::ProcessPacketDispatcher. PacketHeaderFormat form; bool version_flag; + bool use_length_prefix; QuicVersionLabel version_label; ParsedQuicVersion version; QuicConnectionId destination_connection_id;
diff --git a/quic/core/quic_time_wait_list_manager.cc b/quic/core/quic_time_wait_list_manager.cc index cb29a40..a0e7cfb 100644 --- a/quic/core/quic_time_wait_list_manager.cc +++ b/quic/core/quic_time_wait_list_manager.cc
@@ -206,17 +206,20 @@ QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& supported_versions, const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, std::unique_ptr<QuicPerPacketContext> packet_context) { std::unique_ptr<QuicEncryptedPacket> version_packet = - QuicFramer::BuildVersionNegotiationPacket(server_connection_id, - client_connection_id, ietf_quic, - supported_versions); + QuicFramer::BuildVersionNegotiationPacket( + server_connection_id, client_connection_id, ietf_quic, + use_length_prefix, supported_versions); QUIC_DVLOG(2) << "Dispatcher sending version negotiation packet: {" << ParsedQuicVersionVectorToString(supported_versions) << "}, " - << (ietf_quic ? "" : "!") << "ietf_quic:" << std::endl + << (ietf_quic ? "" : "!") + << "ietf_quic:" << (use_length_prefix ? "" : "!") + << "use_length_prefix:" << std::endl << QuicTextUtils::HexDump(QuicStringPiece( version_packet->data(), version_packet->length())); SendOrQueuePacket(QuicMakeUnique<QueuedPacket>(self_address, peer_address,
diff --git a/quic/core/quic_time_wait_list_manager.h b/quic/core/quic_time_wait_list_manager.h index c53632c..9a807c0 100644 --- a/quic/core/quic_time_wait_list_manager.h +++ b/quic/core/quic_time_wait_list_manager.h
@@ -125,6 +125,7 @@ QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, bool ietf_quic, + bool use_length_prefix, const ParsedQuicVersionVector& supported_versions, const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address,
diff --git a/quic/core/quic_time_wait_list_manager_test.cc b/quic/core/quic_time_wait_list_manager_test.cc index 0d9e32a..daa6431 100644 --- a/quic/core/quic_time_wait_list_manager_test.cc +++ b/quic/core/quic_time_wait_list_manager_test.cc
@@ -251,31 +251,50 @@ TEST_F(QuicTimeWaitListManagerTest, SendVersionNegotiationPacket) { std::unique_ptr<QuicEncryptedPacket> packet( - QuicFramer::BuildVersionNegotiationPacket(connection_id_, - EmptyQuicConnectionId(), false, - AllSupportedVersions())); + QuicFramer::BuildVersionNegotiationPacket( + connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/false, + /*use_length_prefix=*/false, AllSupportedVersions())); EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(), peer_address_, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); time_wait_list_manager_.SendVersionNegotiationPacket( - connection_id_, EmptyQuicConnectionId(), false, AllSupportedVersions(), - self_address_, peer_address_, QuicMakeUnique<QuicPerPacketContext>()); + connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/false, + /*use_length_prefix=*/false, AllSupportedVersions(), self_address_, + peer_address_, QuicMakeUnique<QuicPerPacketContext>()); + EXPECT_EQ(0u, time_wait_list_manager_.num_connections()); +} + +TEST_F(QuicTimeWaitListManagerTest, + SendIetfVersionNegotiationPacketWithoutLengthPrefix) { + std::unique_ptr<QuicEncryptedPacket> packet( + QuicFramer::BuildVersionNegotiationPacket( + connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/true, + /*use_length_prefix=*/false, AllSupportedVersions())); + EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(), + peer_address_, _)) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); + + time_wait_list_manager_.SendVersionNegotiationPacket( + connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/true, + /*use_length_prefix=*/false, AllSupportedVersions(), self_address_, + peer_address_, QuicMakeUnique<QuicPerPacketContext>()); EXPECT_EQ(0u, time_wait_list_manager_.num_connections()); } TEST_F(QuicTimeWaitListManagerTest, SendIetfVersionNegotiationPacket) { std::unique_ptr<QuicEncryptedPacket> packet( - QuicFramer::BuildVersionNegotiationPacket(connection_id_, - EmptyQuicConnectionId(), true, - AllSupportedVersions())); + QuicFramer::BuildVersionNegotiationPacket( + connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/true, + /*use_length_prefix=*/true, AllSupportedVersions())); EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(), peer_address_, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); time_wait_list_manager_.SendVersionNegotiationPacket( - connection_id_, EmptyQuicConnectionId(), true, AllSupportedVersions(), - self_address_, peer_address_, QuicMakeUnique<QuicPerPacketContext>()); + connection_id_, EmptyQuicConnectionId(), /*ietf_quic=*/true, + /*use_length_prefix=*/true, AllSupportedVersions(), self_address_, + peer_address_, QuicMakeUnique<QuicPerPacketContext>()); EXPECT_EQ(0u, time_wait_list_manager_.num_connections()); } @@ -285,16 +304,17 @@ SetQuicRestartFlag(quic_do_not_override_connection_id, true); std::unique_ptr<QuicEncryptedPacket> packet( - QuicFramer::BuildVersionNegotiationPacket(connection_id_, - TestConnectionId(0x33), true, - AllSupportedVersions())); + QuicFramer::BuildVersionNegotiationPacket( + connection_id_, TestConnectionId(0x33), /*ietf_quic=*/true, + /*use_length_prefix=*/true, AllSupportedVersions())); EXPECT_CALL(writer_, WritePacket(_, packet->length(), self_address_.host(), peer_address_, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 1))); time_wait_list_manager_.SendVersionNegotiationPacket( - connection_id_, TestConnectionId(0x33), true, AllSupportedVersions(), - self_address_, peer_address_, QuicMakeUnique<QuicPerPacketContext>()); + connection_id_, TestConnectionId(0x33), /*ietf_quic=*/true, + /*use_length_prefix=*/true, AllSupportedVersions(), self_address_, + peer_address_, QuicMakeUnique<QuicPerPacketContext>()); EXPECT_EQ(0u, time_wait_list_manager_.num_connections()); }
diff --git a/quic/core/quic_utils.h b/quic/core/quic_utils.h index 294f52f..db29740 100644 --- a/quic/core/quic_utils.h +++ b/quic/core/quic_utils.h
@@ -109,7 +109,7 @@ TransmissionType retransmission_type); // Returns true if header with |first_byte| is considered as an IETF QUIC - // packet header. + // packet header. This only works on the server. static bool IsIetfPacketHeader(uint8_t first_byte); // Returns true if header with |first_byte| is considered as an IETF QUIC
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc index adfec06..d08ab4d 100644 --- a/quic/core/quic_versions.cc +++ b/quic/core/quic_versions.cc
@@ -80,6 +80,15 @@ return transport_version >= QUIC_VERSION_99; } +bool ParsedQuicVersion::HasLengthPrefixedConnectionIds() const { + return VersionHasLengthPrefixedConnectionIds(transport_version); +} + +bool VersionHasLengthPrefixedConnectionIds( + QuicTransportVersion transport_version) { + return transport_version >= QUIC_VERSION_99; +} + std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) { os << ParsedQuicVersionToString(version); return os; @@ -407,6 +416,34 @@ return result; } +bool QuicVersionLabelUses4BitConnectionIdLength( + QuicVersionLabel version_label) { + // As we deprecate old versions, we still need the ability to send valid + // version negotiation packets for those versions. This function keeps track + // of the versions that ever supported the 4bit connection ID length encoding + // that we know about. Google QUIC 43 and earlier used a different encoding, + // and Google QUIC 49 will start using the new length prefixed encoding. + // Similarly, only IETF drafts 11 to 21 used this encoding. + + // Check Q044, Q045, Q046, Q047 and Q048. + for (uint8_t c = '4'; c <= '8'; ++c) { + if (version_label == MakeVersionLabel('Q', '0', '4', c)) { + return true; + } + } + // Check T048. + if (version_label == MakeVersionLabel('T', '0', '4', '8')) { + return true; + } + // Check IETF draft versions in [11,21]. + for (uint8_t draft_number = 11; draft_number <= 21; ++draft_number) { + if (version_label == MakeVersionLabel(0xff, 0x00, 0x00, draft_number)) { + return true; + } + } + return false; +} + ParsedQuicVersion UnsupportedQuicVersion() { return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED); } @@ -441,6 +478,7 @@ // Enable necessary flags. SetQuicFlag(FLAGS_quic_supports_tls_handshake, true); SetQuicReloadableFlag(quic_simplify_stop_waiting, true); + SetQuicReloadableFlag(quic_use_parse_public_header, true); SetQuicRestartFlag(quic_do_not_override_connection_id, true); SetQuicRestartFlag(quic_use_allocated_connection_ids, true); SetQuicRestartFlag(quic_dispatcher_hands_chlo_extractor_one_version, true);
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h index 1f35f7e..45caa03 100644 --- a/quic/core/quic_versions.h +++ b/quic/core/quic_versions.h
@@ -172,6 +172,11 @@ // Returns whether this version supports client connection ID. bool SupportsClientConnectionIds() const; + + // Returns whether this version supports long header 8-bit encoded + // connection ID lengths as described in draft-ietf-quic-invariants-06 and + // draft-ietf-quic-transport-22. + bool HasLengthPrefixedConnectionIds() const; }; QUIC_EXPORT_PRIVATE ParsedQuicVersion UnsupportedQuicVersion(); @@ -418,6 +423,18 @@ return transport_version >= QUIC_VERSION_99; } +// Returns whether this version supports long header 8-bit encoded +// connection ID lengths as described in draft-ietf-quic-invariants-06 and +// draft-ietf-quic-transport-22. +QUIC_EXPORT_PRIVATE bool VersionHasLengthPrefixedConnectionIds( + QuicTransportVersion transport_version); + +// Returns whether this version label supports long header 4-bit encoded +// connection ID lengths as described in draft-ietf-quic-invariants-05 and +// draft-ietf-quic-transport-21. +QUIC_EXPORT_PRIVATE bool QuicVersionLabelUses4BitConnectionIdLength( + QuicVersionLabel version_label); + // Returns the ALPN string to use in TLS for this version of QUIC. QUIC_EXPORT_PRIVATE std::string AlpnForVersion( ParsedQuicVersion parsed_version);
diff --git a/quic/test_tools/mock_quic_time_wait_list_manager.h b/quic/test_tools/mock_quic_time_wait_list_manager.h index b46e68b..6b2b6d0 100644 --- a/quic/test_tools/mock_quic_time_wait_list_manager.h +++ b/quic/test_tools/mock_quic_time_wait_list_manager.h
@@ -45,10 +45,11 @@ PacketHeaderFormat header_format, std::unique_ptr<QuicPerPacketContext> packet_context)); - MOCK_METHOD7(SendVersionNegotiationPacket, + MOCK_METHOD8(SendVersionNegotiationPacket, void(QuicConnectionId server_connection_id, QuicConnectionId client_connection_id, bool ietf_quic, + bool has_length_prefix, const ParsedQuicVersionVector& supported_versions, const QuicSocketAddress& server_address, const QuicSocketAddress& client_address,