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,