Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "quiche/quic/core/quic_versions.h" |
| 6 | |
QUICHE team | 7baee70 | 2024-05-21 11:18:15 -0700 | [diff] [blame] | 7 | #include <algorithm> |
| 8 | #include <ostream> |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 9 | #include <string> |
QUICHE team | 7baee70 | 2024-05-21 11:18:15 -0700 | [diff] [blame] | 10 | #include <vector> |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 11 | |
| 12 | #include "absl/base/macros.h" |
| 13 | #include "absl/strings/numbers.h" |
| 14 | #include "absl/strings/str_cat.h" |
| 15 | #include "absl/strings/str_split.h" |
| 16 | #include "quiche/quic/core/crypto/quic_random.h" |
| 17 | #include "quiche/quic/core/quic_tag.h" |
| 18 | #include "quiche/quic/core/quic_types.h" |
| 19 | #include "quiche/quic/platform/api/quic_bug_tracker.h" |
| 20 | #include "quiche/quic/platform/api/quic_flag_utils.h" |
| 21 | #include "quiche/quic/platform/api/quic_flags.h" |
| 22 | #include "quiche/quic/platform/api/quic_logging.h" |
| 23 | #include "quiche/common/quiche_endian.h" |
| 24 | #include "quiche/common/quiche_text_utils.h" |
| 25 | |
| 26 | namespace quic { |
| 27 | namespace { |
| 28 | |
| 29 | QuicVersionLabel CreateRandomVersionLabelForNegotiation() { |
| 30 | QuicVersionLabel result; |
birenroy | ef68622 | 2022-09-12 11:34:34 -0700 | [diff] [blame] | 31 | if (!GetQuicFlag(quic_disable_version_negotiation_grease_randomness)) { |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 32 | QuicRandom::GetInstance()->RandBytes(&result, sizeof(result)); |
| 33 | } else { |
| 34 | result = MakeVersionLabel(0xd1, 0x57, 0x38, 0x3f); |
| 35 | } |
| 36 | result &= 0xf0f0f0f0; |
| 37 | result |= 0x0a0a0a0a; |
| 38 | return result; |
| 39 | } |
| 40 | |
| 41 | void SetVersionFlag(const ParsedQuicVersion& version, bool should_enable) { |
rch | 6767ab5 | 2024-03-20 22:20:34 -0700 | [diff] [blame] | 42 | static_assert(SupportedVersions().size() == 4u, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 43 | "Supported versions out of sync"); |
| 44 | const bool enable = should_enable; |
| 45 | const bool disable = !should_enable; |
martinduke | 88918ac | 2023-06-02 10:44:08 -0700 | [diff] [blame] | 46 | if (version == ParsedQuicVersion::RFCv2()) { |
| 47 | SetQuicReloadableFlag(quic_enable_version_rfcv2, enable); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 48 | } else if (version == ParsedQuicVersion::RFCv1()) { |
| 49 | SetQuicReloadableFlag(quic_disable_version_rfcv1, disable); |
| 50 | } else if (version == ParsedQuicVersion::Draft29()) { |
| 51 | SetQuicReloadableFlag(quic_disable_version_draft_29, disable); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 52 | } else if (version == ParsedQuicVersion::Q046()) { |
| 53 | SetQuicReloadableFlag(quic_disable_version_q046, disable); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 54 | } else { |
| 55 | QUIC_BUG(quic_bug_10589_1) |
| 56 | << "Cannot " << (enable ? "en" : "dis") << "able version " << version; |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | } // namespace |
| 61 | |
| 62 | bool ParsedQuicVersion::IsKnown() const { |
| 63 | QUICHE_DCHECK(ParsedQuicVersionIsValid(handshake_protocol, transport_version)) |
| 64 | << QuicVersionToString(transport_version) << " " |
| 65 | << HandshakeProtocolToString(handshake_protocol); |
| 66 | return transport_version != QUIC_VERSION_UNSUPPORTED; |
| 67 | } |
| 68 | |
| 69 | bool ParsedQuicVersion::KnowsWhichDecrypterToUse() const { |
| 70 | QUICHE_DCHECK(IsKnown()); |
| 71 | return transport_version > QUIC_VERSION_46; |
| 72 | } |
| 73 | |
| 74 | bool ParsedQuicVersion::UsesInitialObfuscators() const { |
| 75 | QUICHE_DCHECK(IsKnown()); |
| 76 | // Initial obfuscators were added in version 50. |
| 77 | return transport_version > QUIC_VERSION_46; |
| 78 | } |
| 79 | |
| 80 | bool ParsedQuicVersion::AllowsLowFlowControlLimits() const { |
| 81 | QUICHE_DCHECK(IsKnown()); |
| 82 | // Low flow-control limits are used for all IETF versions. |
| 83 | return UsesHttp3(); |
| 84 | } |
| 85 | |
| 86 | bool ParsedQuicVersion::HasHeaderProtection() const { |
| 87 | QUICHE_DCHECK(IsKnown()); |
| 88 | // Header protection was added in version 50. |
| 89 | return transport_version > QUIC_VERSION_46; |
| 90 | } |
| 91 | |
| 92 | bool ParsedQuicVersion::SupportsRetry() const { |
| 93 | QUICHE_DCHECK(IsKnown()); |
| 94 | // Retry was added in version 47. |
| 95 | return transport_version > QUIC_VERSION_46; |
| 96 | } |
| 97 | |
| 98 | bool ParsedQuicVersion::SendsVariableLengthPacketNumberInLongHeader() const { |
| 99 | QUICHE_DCHECK(IsKnown()); |
| 100 | return transport_version > QUIC_VERSION_46; |
| 101 | } |
| 102 | |
| 103 | bool ParsedQuicVersion::AllowsVariableLengthConnectionIds() const { |
| 104 | QUICHE_DCHECK(IsKnown()); |
| 105 | return VersionAllowsVariableLengthConnectionIds(transport_version); |
| 106 | } |
| 107 | |
| 108 | bool ParsedQuicVersion::SupportsClientConnectionIds() const { |
| 109 | QUICHE_DCHECK(IsKnown()); |
| 110 | // Client connection IDs were added in version 49. |
| 111 | return transport_version > QUIC_VERSION_46; |
| 112 | } |
| 113 | |
| 114 | bool ParsedQuicVersion::HasLengthPrefixedConnectionIds() const { |
| 115 | QUICHE_DCHECK(IsKnown()); |
| 116 | return VersionHasLengthPrefixedConnectionIds(transport_version); |
| 117 | } |
| 118 | |
| 119 | bool ParsedQuicVersion::SupportsAntiAmplificationLimit() const { |
| 120 | QUICHE_DCHECK(IsKnown()); |
| 121 | // The anti-amplification limit is used for all IETF versions. |
| 122 | return UsesHttp3(); |
| 123 | } |
| 124 | |
| 125 | bool ParsedQuicVersion::CanSendCoalescedPackets() const { |
| 126 | QUICHE_DCHECK(IsKnown()); |
| 127 | return HasLongHeaderLengths() && UsesTls(); |
| 128 | } |
| 129 | |
| 130 | bool ParsedQuicVersion::SupportsGoogleAltSvcFormat() const { |
| 131 | QUICHE_DCHECK(IsKnown()); |
| 132 | return VersionSupportsGoogleAltSvcFormat(transport_version); |
| 133 | } |
| 134 | |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 135 | bool ParsedQuicVersion::UsesHttp3() const { |
| 136 | QUICHE_DCHECK(IsKnown()); |
| 137 | return VersionUsesHttp3(transport_version); |
| 138 | } |
| 139 | |
| 140 | bool ParsedQuicVersion::HasLongHeaderLengths() const { |
| 141 | QUICHE_DCHECK(IsKnown()); |
| 142 | return QuicVersionHasLongHeaderLengths(transport_version); |
| 143 | } |
| 144 | |
| 145 | bool ParsedQuicVersion::UsesCryptoFrames() const { |
| 146 | QUICHE_DCHECK(IsKnown()); |
| 147 | return QuicVersionUsesCryptoFrames(transport_version); |
| 148 | } |
| 149 | |
| 150 | bool ParsedQuicVersion::HasIetfQuicFrames() const { |
| 151 | QUICHE_DCHECK(IsKnown()); |
| 152 | return VersionHasIetfQuicFrames(transport_version); |
| 153 | } |
| 154 | |
| 155 | bool ParsedQuicVersion::UsesLegacyTlsExtension() const { |
| 156 | QUICHE_DCHECK(IsKnown()); |
| 157 | return UsesTls() && transport_version <= QUIC_VERSION_IETF_DRAFT_29; |
| 158 | } |
| 159 | |
| 160 | bool ParsedQuicVersion::UsesTls() const { |
| 161 | QUICHE_DCHECK(IsKnown()); |
| 162 | return handshake_protocol == PROTOCOL_TLS1_3; |
| 163 | } |
| 164 | |
| 165 | bool ParsedQuicVersion::UsesQuicCrypto() const { |
| 166 | QUICHE_DCHECK(IsKnown()); |
| 167 | return handshake_protocol == PROTOCOL_QUIC_CRYPTO; |
| 168 | } |
| 169 | |
| 170 | bool ParsedQuicVersion::UsesV2PacketTypes() const { |
| 171 | QUICHE_DCHECK(IsKnown()); |
martinduke | 88918ac | 2023-06-02 10:44:08 -0700 | [diff] [blame] | 172 | return transport_version == QUIC_VERSION_IETF_RFC_V2; |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 173 | } |
| 174 | |
| 175 | bool ParsedQuicVersion::AlpnDeferToRFCv1() const { |
| 176 | QUICHE_DCHECK(IsKnown()); |
martinduke | 88918ac | 2023-06-02 10:44:08 -0700 | [diff] [blame] | 177 | return transport_version == QUIC_VERSION_IETF_RFC_V2; |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | bool VersionHasLengthPrefixedConnectionIds( |
| 181 | QuicTransportVersion transport_version) { |
| 182 | QUICHE_DCHECK(transport_version != QUIC_VERSION_UNSUPPORTED); |
| 183 | // Length-prefixed connection IDs were added in version 49. |
| 184 | return transport_version > QUIC_VERSION_46; |
| 185 | } |
| 186 | |
| 187 | std::ostream& operator<<(std::ostream& os, const ParsedQuicVersion& version) { |
| 188 | os << ParsedQuicVersionToString(version); |
| 189 | return os; |
| 190 | } |
| 191 | |
| 192 | std::ostream& operator<<(std::ostream& os, |
| 193 | const ParsedQuicVersionVector& versions) { |
| 194 | os << ParsedQuicVersionVectorToString(versions); |
| 195 | return os; |
| 196 | } |
| 197 | |
| 198 | QuicVersionLabel MakeVersionLabel(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { |
| 199 | return MakeQuicTag(d, c, b, a); |
| 200 | } |
| 201 | |
| 202 | std::ostream& operator<<(std::ostream& os, |
| 203 | const QuicVersionLabelVector& version_labels) { |
| 204 | os << QuicVersionLabelVectorToString(version_labels); |
| 205 | return os; |
| 206 | } |
| 207 | |
| 208 | std::ostream& operator<<(std::ostream& os, |
| 209 | const QuicTransportVersionVector& transport_versions) { |
| 210 | os << QuicTransportVersionVectorToString(transport_versions); |
| 211 | return os; |
| 212 | } |
| 213 | |
| 214 | QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version) { |
rch | 6767ab5 | 2024-03-20 22:20:34 -0700 | [diff] [blame] | 215 | static_assert(SupportedVersions().size() == 4u, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 216 | "Supported versions out of sync"); |
martinduke | 88918ac | 2023-06-02 10:44:08 -0700 | [diff] [blame] | 217 | if (parsed_version == ParsedQuicVersion::RFCv2()) { |
martinduke | a2cb68a | 2022-12-12 17:24:39 -0800 | [diff] [blame] | 218 | return MakeVersionLabel(0x6b, 0x33, 0x43, 0xcf); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 219 | } else if (parsed_version == ParsedQuicVersion::RFCv1()) { |
| 220 | return MakeVersionLabel(0x00, 0x00, 0x00, 0x01); |
| 221 | } else if (parsed_version == ParsedQuicVersion::Draft29()) { |
| 222 | return MakeVersionLabel(0xff, 0x00, 0x00, 29); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 223 | } else if (parsed_version == ParsedQuicVersion::Q046()) { |
| 224 | return MakeVersionLabel('Q', '0', '4', '6'); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 225 | } else if (parsed_version == ParsedQuicVersion::ReservedForNegotiation()) { |
| 226 | return CreateRandomVersionLabelForNegotiation(); |
| 227 | } |
| 228 | QUIC_BUG(quic_bug_10589_2) |
| 229 | << "Unsupported version " |
| 230 | << QuicVersionToString(parsed_version.transport_version) << " " |
| 231 | << HandshakeProtocolToString(parsed_version.handshake_protocol); |
| 232 | return 0; |
| 233 | } |
| 234 | |
| 235 | QuicVersionLabelVector CreateQuicVersionLabelVector( |
| 236 | const ParsedQuicVersionVector& versions) { |
| 237 | QuicVersionLabelVector out; |
| 238 | out.reserve(versions.size()); |
| 239 | for (const auto& version : versions) { |
| 240 | out.push_back(CreateQuicVersionLabel(version)); |
| 241 | } |
| 242 | return out; |
| 243 | } |
| 244 | |
| 245 | ParsedQuicVersionVector AllSupportedVersionsWithQuicCrypto() { |
| 246 | ParsedQuicVersionVector versions; |
| 247 | for (const ParsedQuicVersion& version : AllSupportedVersions()) { |
| 248 | if (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) { |
| 249 | versions.push_back(version); |
| 250 | } |
| 251 | } |
| 252 | QUIC_BUG_IF(quic_bug_10589_3, versions.empty()) |
| 253 | << "No version with QUIC crypto found."; |
| 254 | return versions; |
| 255 | } |
| 256 | |
| 257 | ParsedQuicVersionVector CurrentSupportedVersionsWithQuicCrypto() { |
| 258 | ParsedQuicVersionVector versions; |
| 259 | for (const ParsedQuicVersion& version : CurrentSupportedVersions()) { |
| 260 | if (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) { |
| 261 | versions.push_back(version); |
| 262 | } |
| 263 | } |
| 264 | QUIC_BUG_IF(quic_bug_10589_4, versions.empty()) |
| 265 | << "No version with QUIC crypto found."; |
| 266 | return versions; |
| 267 | } |
| 268 | |
| 269 | ParsedQuicVersionVector AllSupportedVersionsWithTls() { |
| 270 | ParsedQuicVersionVector versions; |
| 271 | for (const ParsedQuicVersion& version : AllSupportedVersions()) { |
| 272 | if (version.UsesTls()) { |
| 273 | versions.push_back(version); |
| 274 | } |
| 275 | } |
| 276 | QUIC_BUG_IF(quic_bug_10589_5, versions.empty()) |
| 277 | << "No version with TLS handshake found."; |
| 278 | return versions; |
| 279 | } |
| 280 | |
| 281 | ParsedQuicVersionVector CurrentSupportedVersionsWithTls() { |
| 282 | ParsedQuicVersionVector versions; |
| 283 | for (const ParsedQuicVersion& version : CurrentSupportedVersions()) { |
| 284 | if (version.UsesTls()) { |
| 285 | versions.push_back(version); |
| 286 | } |
| 287 | } |
| 288 | QUIC_BUG_IF(quic_bug_10589_6, versions.empty()) |
| 289 | << "No version with TLS handshake found."; |
| 290 | return versions; |
| 291 | } |
| 292 | |
rch | 2957702 | 2023-09-14 13:45:51 -0700 | [diff] [blame] | 293 | ParsedQuicVersionVector ObsoleteSupportedVersions() { |
| 294 | return ParsedQuicVersionVector{quic::ParsedQuicVersion::Q046(), |
rch | 2957702 | 2023-09-14 13:45:51 -0700 | [diff] [blame] | 295 | quic::ParsedQuicVersion::Draft29()}; |
| 296 | } |
| 297 | |
| 298 | bool IsObsoleteSupportedVersion(ParsedQuicVersion version) { |
| 299 | static const ParsedQuicVersionVector obsolete_versions = |
| 300 | ObsoleteSupportedVersions(); |
| 301 | for (const ParsedQuicVersion& obsolete_version : obsolete_versions) { |
| 302 | if (version == obsolete_version) { |
| 303 | return true; |
| 304 | } |
| 305 | } |
| 306 | return false; |
| 307 | } |
| 308 | |
| 309 | ParsedQuicVersionVector CurrentSupportedVersionsForClients() { |
| 310 | ParsedQuicVersionVector versions; |
| 311 | for (const ParsedQuicVersion& version : CurrentSupportedVersionsWithTls()) { |
| 312 | QUICHE_DCHECK_EQ(version.handshake_protocol, PROTOCOL_TLS1_3); |
| 313 | if (version.transport_version >= QUIC_VERSION_IETF_RFC_V1) { |
| 314 | versions.push_back(version); |
| 315 | } |
| 316 | } |
| 317 | QUIC_BUG_IF(quic_bug_10589_8, versions.empty()) |
| 318 | << "No supported client versions found."; |
| 319 | return versions; |
| 320 | } |
| 321 | |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 322 | ParsedQuicVersionVector CurrentSupportedHttp3Versions() { |
| 323 | ParsedQuicVersionVector versions; |
| 324 | for (const ParsedQuicVersion& version : CurrentSupportedVersions()) { |
| 325 | if (version.UsesHttp3()) { |
| 326 | versions.push_back(version); |
| 327 | } |
| 328 | } |
| 329 | QUIC_BUG_IF(no_version_uses_http3, versions.empty()) |
| 330 | << "No version speaking Http3 found."; |
| 331 | return versions; |
| 332 | } |
| 333 | |
| 334 | ParsedQuicVersion ParseQuicVersionLabel(QuicVersionLabel version_label) { |
| 335 | for (const ParsedQuicVersion& version : AllSupportedVersions()) { |
| 336 | if (version_label == CreateQuicVersionLabel(version)) { |
| 337 | return version; |
| 338 | } |
| 339 | } |
| 340 | // Reading from the client so this should not be considered an ERROR. |
| 341 | QUIC_DLOG(INFO) << "Unsupported QuicVersionLabel version: " |
| 342 | << QuicVersionLabelToString(version_label); |
| 343 | return UnsupportedQuicVersion(); |
| 344 | } |
| 345 | |
| 346 | ParsedQuicVersionVector ParseQuicVersionLabelVector( |
| 347 | const QuicVersionLabelVector& version_labels) { |
| 348 | ParsedQuicVersionVector parsed_versions; |
| 349 | for (const QuicVersionLabel& version_label : version_labels) { |
| 350 | ParsedQuicVersion parsed_version = ParseQuicVersionLabel(version_label); |
| 351 | if (parsed_version.IsKnown()) { |
| 352 | parsed_versions.push_back(parsed_version); |
| 353 | } |
| 354 | } |
| 355 | return parsed_versions; |
| 356 | } |
| 357 | |
| 358 | ParsedQuicVersion ParseQuicVersionString(absl::string_view version_string) { |
| 359 | if (version_string.empty()) { |
| 360 | return UnsupportedQuicVersion(); |
| 361 | } |
| 362 | const ParsedQuicVersionVector supported_versions = AllSupportedVersions(); |
| 363 | for (const ParsedQuicVersion& version : supported_versions) { |
| 364 | if (version_string == ParsedQuicVersionToString(version) || |
| 365 | (version_string == AlpnForVersion(version) && |
| 366 | !version.AlpnDeferToRFCv1()) || |
| 367 | (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO && |
| 368 | version_string == QuicVersionToString(version.transport_version))) { |
| 369 | return version; |
| 370 | } |
| 371 | } |
| 372 | for (const ParsedQuicVersion& version : supported_versions) { |
| 373 | if (version.UsesHttp3() && |
| 374 | version_string == |
| 375 | QuicVersionLabelToString(CreateQuicVersionLabel(version))) { |
| 376 | return version; |
| 377 | } |
| 378 | } |
| 379 | int quic_version_number = 0; |
| 380 | if (absl::SimpleAtoi(version_string, &quic_version_number) && |
| 381 | quic_version_number > 0) { |
| 382 | QuicTransportVersion transport_version = |
| 383 | static_cast<QuicTransportVersion>(quic_version_number); |
| 384 | if (!ParsedQuicVersionIsValid(PROTOCOL_QUIC_CRYPTO, transport_version)) { |
| 385 | return UnsupportedQuicVersion(); |
| 386 | } |
| 387 | ParsedQuicVersion version(PROTOCOL_QUIC_CRYPTO, transport_version); |
| 388 | if (std::find(supported_versions.begin(), supported_versions.end(), |
| 389 | version) != supported_versions.end()) { |
| 390 | return version; |
| 391 | } |
| 392 | return UnsupportedQuicVersion(); |
| 393 | } |
| 394 | // Reading from the client so this should not be considered an ERROR. |
| 395 | QUIC_DLOG(INFO) << "Unsupported QUIC version string: \"" << version_string |
| 396 | << "\"."; |
| 397 | return UnsupportedQuicVersion(); |
| 398 | } |
| 399 | |
| 400 | ParsedQuicVersionVector ParseQuicVersionVectorString( |
| 401 | absl::string_view versions_string) { |
| 402 | ParsedQuicVersionVector versions; |
| 403 | std::vector<absl::string_view> version_strings = |
| 404 | absl::StrSplit(versions_string, ','); |
| 405 | for (absl::string_view version_string : version_strings) { |
| 406 | quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace( |
| 407 | &version_string); |
| 408 | ParsedQuicVersion version = ParseQuicVersionString(version_string); |
| 409 | if (!version.IsKnown() || std::find(versions.begin(), versions.end(), |
| 410 | version) != versions.end()) { |
| 411 | continue; |
| 412 | } |
| 413 | versions.push_back(version); |
| 414 | } |
| 415 | return versions; |
| 416 | } |
| 417 | |
| 418 | QuicTransportVersionVector AllSupportedTransportVersions() { |
| 419 | QuicTransportVersionVector transport_versions; |
| 420 | for (const ParsedQuicVersion& version : AllSupportedVersions()) { |
| 421 | if (std::find(transport_versions.begin(), transport_versions.end(), |
| 422 | version.transport_version) == transport_versions.end()) { |
| 423 | transport_versions.push_back(version.transport_version); |
| 424 | } |
| 425 | } |
| 426 | return transport_versions; |
| 427 | } |
| 428 | |
| 429 | ParsedQuicVersionVector AllSupportedVersions() { |
| 430 | constexpr auto supported_versions = SupportedVersions(); |
| 431 | return ParsedQuicVersionVector(supported_versions.begin(), |
| 432 | supported_versions.end()); |
| 433 | } |
| 434 | |
| 435 | ParsedQuicVersionVector CurrentSupportedVersions() { |
| 436 | return FilterSupportedVersions(AllSupportedVersions()); |
| 437 | } |
| 438 | |
| 439 | ParsedQuicVersionVector FilterSupportedVersions( |
| 440 | ParsedQuicVersionVector versions) { |
rch | 6767ab5 | 2024-03-20 22:20:34 -0700 | [diff] [blame] | 441 | static_assert(SupportedVersions().size() == 4u, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 442 | "Supported versions out of sync"); |
| 443 | ParsedQuicVersionVector filtered_versions; |
| 444 | filtered_versions.reserve(versions.size()); |
| 445 | for (const ParsedQuicVersion& version : versions) { |
martinduke | 88918ac | 2023-06-02 10:44:08 -0700 | [diff] [blame] | 446 | if (version == ParsedQuicVersion::RFCv2()) { |
| 447 | if (GetQuicReloadableFlag(quic_enable_version_rfcv2)) { |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 448 | filtered_versions.push_back(version); |
| 449 | } |
| 450 | } else if (version == ParsedQuicVersion::RFCv1()) { |
| 451 | if (!GetQuicReloadableFlag(quic_disable_version_rfcv1)) { |
| 452 | filtered_versions.push_back(version); |
| 453 | } |
| 454 | } else if (version == ParsedQuicVersion::Draft29()) { |
| 455 | if (!GetQuicReloadableFlag(quic_disable_version_draft_29)) { |
| 456 | filtered_versions.push_back(version); |
| 457 | } |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 458 | } else if (version == ParsedQuicVersion::Q046()) { |
| 459 | if (!GetQuicReloadableFlag(quic_disable_version_q046)) { |
| 460 | filtered_versions.push_back(version); |
| 461 | } |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 462 | } else { |
| 463 | QUIC_BUG(quic_bug_10589_7) |
| 464 | << "QUIC version " << version << " has no flag protection"; |
| 465 | filtered_versions.push_back(version); |
| 466 | } |
| 467 | } |
| 468 | return filtered_versions; |
| 469 | } |
| 470 | |
| 471 | ParsedQuicVersionVector ParsedVersionOfIndex( |
| 472 | const ParsedQuicVersionVector& versions, int index) { |
| 473 | ParsedQuicVersionVector version; |
| 474 | int version_count = versions.size(); |
| 475 | if (index >= 0 && index < version_count) { |
| 476 | version.push_back(versions[index]); |
| 477 | } else { |
| 478 | version.push_back(UnsupportedQuicVersion()); |
| 479 | } |
| 480 | return version; |
| 481 | } |
| 482 | |
| 483 | std::string QuicVersionLabelToString(QuicVersionLabel version_label) { |
| 484 | return QuicTagToString(quiche::QuicheEndian::HostToNet32(version_label)); |
| 485 | } |
| 486 | |
| 487 | ParsedQuicVersion ParseQuicVersionLabelString( |
| 488 | absl::string_view version_label_string) { |
| 489 | const ParsedQuicVersionVector supported_versions = AllSupportedVersions(); |
| 490 | for (const ParsedQuicVersion& version : supported_versions) { |
| 491 | if (version_label_string == |
| 492 | QuicVersionLabelToString(CreateQuicVersionLabel(version))) { |
| 493 | return version; |
| 494 | } |
| 495 | } |
| 496 | return UnsupportedQuicVersion(); |
| 497 | } |
| 498 | |
| 499 | std::string QuicVersionLabelVectorToString( |
| 500 | const QuicVersionLabelVector& version_labels, const std::string& separator, |
| 501 | size_t skip_after_nth_version) { |
| 502 | std::string result; |
| 503 | for (size_t i = 0; i < version_labels.size(); ++i) { |
| 504 | if (i != 0) { |
| 505 | result.append(separator); |
| 506 | } |
| 507 | |
| 508 | if (i > skip_after_nth_version) { |
| 509 | result.append("..."); |
| 510 | break; |
| 511 | } |
| 512 | result.append(QuicVersionLabelToString(version_labels[i])); |
| 513 | } |
| 514 | return result; |
| 515 | } |
| 516 | |
| 517 | #define RETURN_STRING_LITERAL(x) \ |
| 518 | case x: \ |
| 519 | return #x |
| 520 | |
| 521 | std::string QuicVersionToString(QuicTransportVersion transport_version) { |
| 522 | switch (transport_version) { |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 523 | RETURN_STRING_LITERAL(QUIC_VERSION_46); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 524 | RETURN_STRING_LITERAL(QUIC_VERSION_IETF_DRAFT_29); |
| 525 | RETURN_STRING_LITERAL(QUIC_VERSION_IETF_RFC_V1); |
martinduke | 88918ac | 2023-06-02 10:44:08 -0700 | [diff] [blame] | 526 | RETURN_STRING_LITERAL(QUIC_VERSION_IETF_RFC_V2); |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 527 | RETURN_STRING_LITERAL(QUIC_VERSION_UNSUPPORTED); |
| 528 | RETURN_STRING_LITERAL(QUIC_VERSION_RESERVED_FOR_NEGOTIATION); |
| 529 | } |
| 530 | return absl::StrCat("QUIC_VERSION_UNKNOWN(", |
| 531 | static_cast<int>(transport_version), ")"); |
| 532 | } |
| 533 | |
| 534 | std::string HandshakeProtocolToString(HandshakeProtocol handshake_protocol) { |
| 535 | switch (handshake_protocol) { |
| 536 | RETURN_STRING_LITERAL(PROTOCOL_UNSUPPORTED); |
| 537 | RETURN_STRING_LITERAL(PROTOCOL_QUIC_CRYPTO); |
| 538 | RETURN_STRING_LITERAL(PROTOCOL_TLS1_3); |
| 539 | } |
| 540 | return absl::StrCat("PROTOCOL_UNKNOWN(", static_cast<int>(handshake_protocol), |
| 541 | ")"); |
| 542 | } |
| 543 | |
| 544 | std::string ParsedQuicVersionToString(ParsedQuicVersion version) { |
rch | 6767ab5 | 2024-03-20 22:20:34 -0700 | [diff] [blame] | 545 | static_assert(SupportedVersions().size() == 4u, |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 546 | "Supported versions out of sync"); |
| 547 | if (version == UnsupportedQuicVersion()) { |
| 548 | return "0"; |
martinduke | 88918ac | 2023-06-02 10:44:08 -0700 | [diff] [blame] | 549 | } else if (version == ParsedQuicVersion::RFCv2()) { |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 550 | QUICHE_DCHECK(version.UsesHttp3()); |
martinduke | 88918ac | 2023-06-02 10:44:08 -0700 | [diff] [blame] | 551 | return "RFCv2"; |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 552 | } else if (version == ParsedQuicVersion::RFCv1()) { |
| 553 | QUICHE_DCHECK(version.UsesHttp3()); |
| 554 | return "RFCv1"; |
| 555 | } else if (version == ParsedQuicVersion::Draft29()) { |
| 556 | QUICHE_DCHECK(version.UsesHttp3()); |
| 557 | return "draft29"; |
| 558 | } |
| 559 | |
| 560 | return QuicVersionLabelToString(CreateQuicVersionLabel(version)); |
| 561 | } |
| 562 | |
| 563 | std::string QuicTransportVersionVectorToString( |
| 564 | const QuicTransportVersionVector& versions) { |
| 565 | std::string result = ""; |
| 566 | for (size_t i = 0; i < versions.size(); ++i) { |
| 567 | if (i != 0) { |
| 568 | result.append(","); |
| 569 | } |
| 570 | result.append(QuicVersionToString(versions[i])); |
| 571 | } |
| 572 | return result; |
| 573 | } |
| 574 | |
| 575 | std::string ParsedQuicVersionVectorToString( |
| 576 | const ParsedQuicVersionVector& versions, const std::string& separator, |
| 577 | size_t skip_after_nth_version) { |
| 578 | std::string result; |
| 579 | for (size_t i = 0; i < versions.size(); ++i) { |
| 580 | if (i != 0) { |
| 581 | result.append(separator); |
| 582 | } |
| 583 | if (i > skip_after_nth_version) { |
| 584 | result.append("..."); |
| 585 | break; |
| 586 | } |
| 587 | result.append(ParsedQuicVersionToString(versions[i])); |
| 588 | } |
| 589 | return result; |
| 590 | } |
| 591 | |
| 592 | bool VersionSupportsGoogleAltSvcFormat(QuicTransportVersion transport_version) { |
| 593 | return transport_version <= QUIC_VERSION_46; |
| 594 | } |
| 595 | |
| 596 | bool VersionAllowsVariableLengthConnectionIds( |
| 597 | QuicTransportVersion transport_version) { |
| 598 | QUICHE_DCHECK_NE(transport_version, QUIC_VERSION_UNSUPPORTED); |
| 599 | return transport_version > QUIC_VERSION_46; |
| 600 | } |
| 601 | |
| 602 | bool QuicVersionLabelUses4BitConnectionIdLength( |
| 603 | QuicVersionLabel version_label) { |
| 604 | // As we deprecate old versions, we still need the ability to send valid |
| 605 | // version negotiation packets for those versions. This function keeps track |
| 606 | // of the versions that ever supported the 4bit connection ID length encoding |
| 607 | // that we know about. Google QUIC 43 and earlier used a different encoding, |
| 608 | // and Google QUIC 49 and later use the new length prefixed encoding. |
| 609 | // Similarly, only IETF drafts 11 to 21 used this encoding. |
| 610 | |
fayang | fc04b8a | 2023-05-18 09:26:25 -0700 | [diff] [blame] | 611 | // Check Q043, Q044, Q045, Q046, Q047 and Q048. |
| 612 | for (uint8_t c = '3'; c <= '8'; ++c) { |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 613 | if (version_label == MakeVersionLabel('Q', '0', '4', c)) { |
| 614 | return true; |
| 615 | } |
| 616 | } |
| 617 | // Check T048. |
| 618 | if (version_label == MakeVersionLabel('T', '0', '4', '8')) { |
| 619 | return true; |
| 620 | } |
| 621 | // Check IETF draft versions in [11,21]. |
| 622 | for (uint8_t draft_number = 11; draft_number <= 21; ++draft_number) { |
| 623 | if (version_label == MakeVersionLabel(0xff, 0x00, 0x00, draft_number)) { |
| 624 | return true; |
| 625 | } |
| 626 | } |
| 627 | return false; |
| 628 | } |
| 629 | |
| 630 | ParsedQuicVersion UnsupportedQuicVersion() { |
| 631 | return ParsedQuicVersion::Unsupported(); |
| 632 | } |
| 633 | |
| 634 | ParsedQuicVersion QuicVersionReservedForNegotiation() { |
| 635 | return ParsedQuicVersion::ReservedForNegotiation(); |
| 636 | } |
| 637 | |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 638 | std::string AlpnForVersion(ParsedQuicVersion parsed_version) { |
martinduke | 88918ac | 2023-06-02 10:44:08 -0700 | [diff] [blame] | 639 | if (parsed_version == ParsedQuicVersion::RFCv2()) { |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 640 | return "h3"; |
| 641 | } else if (parsed_version == ParsedQuicVersion::RFCv1()) { |
| 642 | return "h3"; |
| 643 | } else if (parsed_version == ParsedQuicVersion::Draft29()) { |
| 644 | return "h3-29"; |
| 645 | } |
| 646 | return "h3-" + ParsedQuicVersionToString(parsed_version); |
| 647 | } |
| 648 | |
Bence Béky | bac0405 | 2022-04-07 15:44:29 -0400 | [diff] [blame] | 649 | void QuicEnableVersion(const ParsedQuicVersion& version) { |
| 650 | SetVersionFlag(version, /*should_enable=*/true); |
| 651 | } |
| 652 | |
| 653 | void QuicDisableVersion(const ParsedQuicVersion& version) { |
| 654 | SetVersionFlag(version, /*should_enable=*/false); |
| 655 | } |
| 656 | |
| 657 | bool QuicVersionIsEnabled(const ParsedQuicVersion& version) { |
| 658 | ParsedQuicVersionVector current = CurrentSupportedVersions(); |
| 659 | return std::find(current.begin(), current.end(), version) != current.end(); |
| 660 | } |
| 661 | |
| 662 | #undef RETURN_STRING_LITERAL // undef for jumbo builds |
| 663 | } // namespace quic |