Send connection close packet for QUIC_INVALID_VERSION, behind client_connection_option INVC. PiperOrigin-RevId: 437343247
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h index 32fd192..ea05d35 100644 --- a/quic/core/crypto/crypto_protocol.h +++ b/quic/core/crypto/crypto_protocol.h
@@ -430,6 +430,9 @@ // server side. const QuicTag kGSR0 = TAG('G', 'S', 'R', '0'); // Selective Resumption +const QuicTag kINVC = TAG('I', 'N', 'V', 'C'); // Send connection close for + // INVALID_VERSION + // Client Hints triggers. const QuicTag kGWCH = TAG('G', 'W', 'C', 'H'); const QuicTag kYTCH = TAG('Y', 'T', 'C', 'H');
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index 6edaa8f..0cc3296 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -619,6 +619,10 @@ if (config.HasClientSentConnectionOption(kDFER, perspective_)) { defer_send_in_response_to_packets_ = false; } + + if (config.HasClientRequestedIndependentOption(kINVC, perspective_)) { + send_connection_close_for_invalid_version_ = true; + } const bool remove_connection_migration_connection_option = GetQuicReloadableFlag(quic_remove_connection_migration_connection_option); if (remove_connection_migration_connection_option) { @@ -882,7 +886,9 @@ ParsedQuicVersionVectorToString(framer_.supported_versions()), "}, peer supported versions: {", ParsedQuicVersionVectorToString(packet.versions), "}"), - ConnectionCloseBehavior::SILENT_CLOSE); + send_connection_close_for_invalid_version_ + ? ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET + : ConnectionCloseBehavior::SILENT_CLOSE); } // Handles retry for client connection.
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h index a38f2c0..17c0830 100644 --- a/quic/core/quic_connection.h +++ b/quic/core/quic_connection.h
@@ -2276,6 +2276,9 @@ // TODO(b/180103273): remove this after the bug gets fixed. absl::optional<QuicConnectionCloseFrame> connection_close_frame_sent_; + // If true, send connection close packet on INVALID_VERSION. + bool send_connection_close_for_invalid_version_ = false; + // TODO(b/205023946) Debug-only fields, to be deprecated after the bug is // fixed. absl::optional<QuicWallTime> quic_bug_10511_43_timestamp_;
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index 5effe44..fb16c11 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -7049,6 +7049,41 @@ IsError(QUIC_INVALID_VERSION)); } +TEST_P(QuicConnectionTest, ClientHandlesVersionNegotiationWithConnectionClose) { + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(kINVC); + config.SetClientConnectionOptions(connection_options); + connection_.SetFromConfig(config); + + // 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(), + connection_.version().HasIetfInvariantHeader(), + connection_.version().HasLengthPrefixedConnectionIds(), versions)); + std::unique_ptr<QuicReceivedPacket> received( + ConstructReceivedPacket(*encrypted, QuicTime::Zero())); + EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)) + .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame)); + // Verify connection close packet gets sent. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1u)); + connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); + EXPECT_FALSE(connection_.connected()); + EXPECT_EQ(1, connection_close_frame_count_); + EXPECT_THAT(saved_connection_close_frame_.quic_error_code, + IsError(QUIC_INVALID_VERSION)); +} + TEST_P(QuicConnectionTest, BadVersionNegotiation) { // Send a version negotiation packet with the version the client started with. // It should be rejected.