Allow TLS-based versions in quic_client and quic_server Also adds functions for overriding the version label for T099, parsing version labels from strings, and easily enabling flags required by particular QUIC versions. gfe-relnote: protected by disabled flag quic_supports_tls_handshake, or test-only code PiperOrigin-RevId: 242047771 Change-Id: I00d8948fca5e91021c386944371dc3b92f1f3988
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc index 036fbd0..62f9ce9 100644 --- a/quic/core/quic_versions.cc +++ b/quic/core/quic_versions.cc
@@ -8,11 +8,13 @@ #include "net/third_party/quiche/src/quic/core/quic_tag.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" namespace quic { namespace { @@ -23,6 +25,10 @@ return MakeQuicTag(d, c, b, a); } +// Version label for ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99). +// Defaults to "T099". Can be overridden for IETF interop events. +QuicVersionLabel kQuicT099VersionLabel = 0; + } // namespace ParsedQuicVersion::ParsedQuicVersion(HandshakeProtocol handshake_protocol, @@ -66,6 +72,10 @@ case QUIC_VERSION_47: return MakeVersionLabel(proto, '0', '4', '7'); case QUIC_VERSION_99: + if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3 && + kQuicT099VersionLabel != 0) { + return kQuicT099VersionLabel; + } return MakeVersionLabel(proto, '0', '9', '9'); default: // This shold be an ERROR because we should never attempt to convert an @@ -105,6 +115,41 @@ return UnsupportedQuicVersion(); } +ParsedQuicVersion ParseQuicVersionString(std::string version_string) { + if (version_string.length() == 0) { + return UnsupportedQuicVersion(); + } + int quic_version_number = 0; + if (QuicTextUtils::StringToInt(version_string, &quic_version_number) && + quic_version_number > 0) { + return ParsedQuicVersion( + PROTOCOL_QUIC_CRYPTO, + static_cast<QuicTransportVersion>(quic_version_number)); + } + + std::vector<HandshakeProtocol> protocols = {PROTOCOL_QUIC_CRYPTO}; + if (FLAGS_quic_supports_tls_handshake) { + protocols.push_back(PROTOCOL_TLS1_3); + } + for (QuicTransportVersion version : kSupportedTransportVersions) { + for (HandshakeProtocol handshake : protocols) { + const ParsedQuicVersion parsed_version = + ParsedQuicVersion(handshake, version); + if (version_string == ParsedQuicVersionToString(parsed_version)) { + return parsed_version; + } + } + } + // Still recognize T099 even if kQuicT099VersionLabel has been changed. + if (FLAGS_quic_supports_tls_handshake && version_string == "T099") { + return ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99); + } + // Reading from the client so this should not be considered an ERROR. + QUIC_DLOG(INFO) << "Unsupported QUIC version string: \"" << version_string + << "\"."; + return UnsupportedQuicVersion(); +} + QuicTransportVersionVector AllSupportedTransportVersions() { QuicTransportVersionVector supported_versions; for (QuicTransportVersion version : kSupportedTransportVersions) { @@ -333,5 +378,49 @@ return ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED); } +void QuicVersionInitializeSupportForIetfDraft(int32_t draft_version) { + if (draft_version == 0) { + return; + } + if (draft_version < 0 || draft_version >= 256) { + LOG(FATAL) << "Invalid IETF draft version " << draft_version; + return; + } + + kQuicT099VersionLabel = 0xff000000 + draft_version; + + // Enable necessary flags. + SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); + SetQuicReloadableFlag(quic_deprecate_ack_bundling_mode, true); + SetQuicReloadableFlag(quic_rpm_decides_when_to_send_acks, true); + SetQuicReloadableFlag(quic_use_uber_loss_algorithm, true); + SetQuicReloadableFlag(quic_use_uber_received_packet_manager, true); + SetQuicReloadableFlag(quic_validate_packet_number_post_decryption, true); + SetQuicRestartFlag(quic_enable_accept_random_ipn, true); +} + +void QuicEnableVersion(ParsedQuicVersion parsed_version) { + if (parsed_version.handshake_protocol == PROTOCOL_TLS1_3) { + SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); + } + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, + "Supported versions out of sync"); + if (parsed_version.transport_version >= QUIC_VERSION_99) { + SetQuicReloadableFlag(quic_enable_version_99, true); + } + if (parsed_version.transport_version >= QUIC_VERSION_47) { + SetQuicReloadableFlag(quic_enable_version_47, true); + } + if (parsed_version.transport_version >= QUIC_VERSION_46) { + SetQuicReloadableFlag(quic_enable_version_46, true); + } + if (parsed_version.transport_version >= QUIC_VERSION_44) { + SetQuicReloadableFlag(quic_enable_version_44, true); + } + if (parsed_version.transport_version >= QUIC_VERSION_43) { + SetQuicReloadableFlag(quic_enable_version_43, true); + } +} + #undef RETURN_STRING_LITERAL // undef for jumbo builds } // namespace quic
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h index b23ae08..2c78760 100644 --- a/quic/core/quic_versions.h +++ b/quic/core/quic_versions.h
@@ -227,6 +227,11 @@ QUIC_EXPORT_PRIVATE ParsedQuicVersion ParseQuicVersionLabel(QuicVersionLabel version_label); +// Parses a QUIC version string such as "Q043" or "T099". +// Also supports parsing numbers such as "44". +QUIC_EXPORT_PRIVATE ParsedQuicVersion +ParseQuicVersionString(std::string version_string); + // Constructs a QuicVersionLabel from the provided ParsedQuicVersion. QUIC_EXPORT_PRIVATE QuicVersionLabel CreateQuicVersionLabel(ParsedQuicVersion parsed_version); @@ -348,6 +353,14 @@ return transport_version == QUIC_VERSION_99; } +// Initializes support for the provided IETF draft version by setting flags +// and the version label. +QUIC_EXPORT_PRIVATE void QuicVersionInitializeSupportForIetfDraft( + int32_t draft_version); + +// Enables the flags required to support this version of QUIC. +QUIC_EXPORT_PRIVATE void QuicEnableVersion(ParsedQuicVersion parsed_version); + } // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_VERSIONS_H_
diff --git a/quic/core/quic_versions_test.cc b/quic/core/quic_versions_test.cc index db7f53a..6139ca8 100644 --- a/quic/core/quic_versions_test.cc +++ b/quic/core/quic_versions_test.cc
@@ -171,6 +171,45 @@ ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '7'))); } +TEST_F(QuicVersionsTest, ParseQuicVersionString) { + EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39), + ParseQuicVersionString("Q039")); + EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43), + ParseQuicVersionString("Q043")); + EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44), + ParseQuicVersionString("Q044")); + EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46), + ParseQuicVersionString("Q046")); + EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47), + ParseQuicVersionString("Q047")); + + EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("")); + EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q 47")); + EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("Q047 ")); + + // Test a TLS version: + FLAGS_quic_supports_tls_handshake = true; + EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39), + ParseQuicVersionString("T039")); + EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_43), + ParseQuicVersionString("T043")); + EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_44), + ParseQuicVersionString("T044")); + EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46), + ParseQuicVersionString("T046")); + EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47), + ParseQuicVersionString("T047")); + + FLAGS_quic_supports_tls_handshake = false; + EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T035")); + EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T039")); + EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T043")); + EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T044")); + EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T045")); + EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T046")); + EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionString("T047")); +} + TEST_F(QuicVersionsTest, CreateQuicVersionLabel) { EXPECT_EQ(MakeVersionLabel('Q', '0', '3', '9'), CreateQuicVersionLabel( @@ -516,6 +555,58 @@ EXPECT_EQ(QUIC_VERSION_47, 47); EXPECT_EQ(QUIC_VERSION_99, 99); } + +TEST_F(QuicVersionsTest, InitializeSupportForIetfDraft) { + FLAGS_quic_supports_tls_handshake = true; + ParsedQuicVersion parsed_version_t099 = + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99); + FLAGS_quic_supports_tls_handshake = false; + EXPECT_EQ(MakeVersionLabel('T', '0', '9', '9'), + CreateQuicVersionLabel(parsed_version_t099)); + + QuicVersionInitializeSupportForIetfDraft(0); + EXPECT_EQ(MakeVersionLabel('T', '0', '9', '9'), + CreateQuicVersionLabel(parsed_version_t099)); + EXPECT_FALSE(FLAGS_quic_supports_tls_handshake); + + QuicVersionInitializeSupportForIetfDraft(18); + EXPECT_TRUE(FLAGS_quic_supports_tls_handshake); + EXPECT_EQ(MakeVersionLabel(0xff, 0, 0, 18), + CreateQuicVersionLabel(parsed_version_t099)); +} + +TEST_F(QuicVersionsTest, QuicEnableVersion) { + FLAGS_quic_supports_tls_handshake = true; + ParsedQuicVersion parsed_version_q047 = + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47); + ParsedQuicVersion parsed_version_t047 = + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47); + ParsedQuicVersion parsed_version_t099 = + ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_99); + FLAGS_quic_supports_tls_handshake = false; + SetQuicReloadableFlag(quic_disable_version_39, false); + SetQuicReloadableFlag(quic_enable_version_43, true); + SetQuicReloadableFlag(quic_enable_version_44, true); + SetQuicReloadableFlag(quic_enable_version_46, true); + SetQuicReloadableFlag(quic_enable_version_47, false); + SetQuicReloadableFlag(quic_enable_version_99, false); + + QuicEnableVersion(parsed_version_q047); + EXPECT_FALSE(FLAGS_quic_supports_tls_handshake); + EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47)); + EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99)); + + QuicEnableVersion(parsed_version_t047); + EXPECT_TRUE(FLAGS_quic_supports_tls_handshake); + EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47)); + EXPECT_FALSE(GetQuicReloadableFlag(quic_enable_version_99)); + + QuicEnableVersion(parsed_version_t099); + EXPECT_TRUE(FLAGS_quic_supports_tls_handshake); + EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_47)); + EXPECT_TRUE(GetQuicReloadableFlag(quic_enable_version_99)); +} + } // namespace } // namespace test } // namespace quic
diff --git a/quic/tools/quic_client_bin.cc b/quic/tools/quic_client_bin.cc index ff81125..ee8262f 100644 --- a/quic/tools/quic_client_bin.cc +++ b/quic/tools/quic_client_bin.cc
@@ -47,6 +47,7 @@ #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_server_id.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" @@ -151,11 +152,20 @@ "Set to true for a quieter output experience."); DEFINE_QUIC_COMMAND_LINE_FLAG( - int32_t, + std::string, quic_version, - -1, + "", "QUIC version to speak, e.g. 21. If not set, then all available " - "versions are offered in the handshake."); + "versions are offered in the handshake. Also supports wire versions " + "such as Q043 or T099."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + int32_t, + quic_ietf_draft, + 0, + "QUIC IETF draft number to use over the wire, e.g. 18. " + "By default this sets quic_version to T099. " + "This also enables required internal QUIC flags."); DEFINE_QUIC_COMMAND_LINE_FLAG( bool, @@ -228,12 +238,31 @@ quic::QuicEpollServer epoll_server; quic::QuicServerId server_id(url.host(), port, false); quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions(); - if (GetQuicFlag(FLAGS_quic_version) != -1) { - versions.clear(); - versions.push_back(quic::ParsedQuicVersion( - quic::PROTOCOL_QUIC_CRYPTO, static_cast<quic::QuicTransportVersion>( - GetQuicFlag(FLAGS_quic_version)))); + + std::string quic_version_string = GetQuicFlag(FLAGS_quic_version); + const int32_t quic_ietf_draft = GetQuicFlag(FLAGS_quic_ietf_draft); + if (quic_ietf_draft > 0) { + quic::QuicVersionInitializeSupportForIetfDraft(quic_ietf_draft); + if (quic_version_string.length() == 0) { + quic_version_string = "T099"; + } } + if (quic_version_string.length() > 0) { + if (quic_version_string[0] == 'T') { + // ParseQuicVersionString checks quic_supports_tls_handshake. + SetQuicFlag(&FLAGS_quic_supports_tls_handshake, true); + } + quic::ParsedQuicVersion parsed_quic_version = + quic::ParseQuicVersionString(quic_version_string); + if (parsed_quic_version.transport_version == + quic::QUIC_VERSION_UNSUPPORTED) { + return 1; + } + versions.clear(); + versions.push_back(parsed_quic_version); + quic::QuicEnableVersion(parsed_quic_version); + } + const int32_t num_requests(GetQuicFlag(FLAGS_num_requests)); std::unique_ptr<quic::ProofVerifier> proof_verifier; if (GetQuicFlag(FLAGS_disable_certificate_verification)) {
diff --git a/quic/tools/quic_server_bin.cc b/quic/tools/quic_server_bin.cc index 1029fbd..128c873 100644 --- a/quic/tools/quic_server_bin.cc +++ b/quic/tools/quic_server_bin.cc
@@ -7,6 +7,7 @@ #include <vector> +#include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" @@ -26,6 +27,13 @@ "construction to seed the cache. Cache directory can be " "generated using `wget -p --save-headers <url>`"); +DEFINE_QUIC_COMMAND_LINE_FLAG( + int32_t, + quic_ietf_draft, + 0, + "QUIC IETF draft number to use over the wire, e.g. 18. " + "This also enables required internal QUIC flags."); + int main(int argc, char* argv[]) { const char* usage = "Usage: quic_server [options]"; std::vector<std::string> non_option_args = @@ -35,6 +43,13 @@ exit(0); } + const int32_t quic_ietf_draft = GetQuicFlag(FLAGS_quic_ietf_draft); + if (quic_ietf_draft > 0) { + quic::QuicVersionInitializeSupportForIetfDraft(quic_ietf_draft); + quic::QuicEnableVersion( + quic::ParsedQuicVersion(quic::PROTOCOL_TLS1_3, quic::QUIC_VERSION_99)); + } + quic::QuicMemoryCacheBackend memory_cache_backend; if (!GetQuicFlag(FLAGS_quic_response_cache_dir).empty()) { memory_cache_backend.InitializeBackend(