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/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;
}