Ignore stateless reset packet received on a probing path. Client side change only. not protected. PiperOrigin-RevId: 312125302 Change-Id: I113d78c8c0a1443815a9b50cee9240b79c0a90f7
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index 0747d4f..d692913 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -605,6 +605,7 @@ // here. (Check for a bug regression.) DCHECK_EQ(server_connection_id_, packet.connection_id); DCHECK_EQ(perspective_, Perspective::IS_CLIENT); + DCHECK(!VersionHasIetfInvariantHeader(transport_version())); if (debug_visitor_ != nullptr) { debug_visitor_->OnPublicResetPacket(packet); } @@ -1579,6 +1580,14 @@ const QuicIetfStatelessResetPacket& /*packet*/) { // TODO(fayang): Add OnAuthenticatedIetfStatelessResetPacket to // debug_visitor_. + DCHECK(VersionHasIetfInvariantHeader(transport_version())); + DCHECK_EQ(perspective_, Perspective::IS_CLIENT); + if (last_packet_destination_address_ != self_address()) { + // This packet is received on a probing path. Do not close connection. + visitor_->OnStatelessResetForProbing(); + return; + } + const std::string error_details = "Received stateless reset."; QUIC_CODE_COUNT(quic_tear_down_local_connection_on_stateless_reset); TearDownLocalConnectionState(QUIC_PUBLIC_RESET, error_details,
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h index 6586fb2..f931567e 100644 --- a/quic/core/quic_connection.h +++ b/quic/core/quic_connection.h
@@ -130,6 +130,9 @@ // bandwidth. Returns true if data was sent, false otherwise. virtual bool SendProbingData() = 0; + // Called when stateless reset packet is received but is on a different path. + virtual void OnStatelessResetForProbing() = 0; + // Called when the connection experiences a change in congestion window. virtual void OnCongestionWindowChange(QuicTime now) = 0;
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index 7fb8453..2e48f49 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -28,6 +28,7 @@ #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_reference_counted.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" #include "net/third_party/quiche/src/quic/test_tools/mock_random.h" @@ -7368,6 +7369,33 @@ IsError(QUIC_PUBLIC_RESET)); } +TEST_P(QuicConnectionTest, IetfStatelessResetOnProbingPath) { + if (!VersionHasIetfInvariantHeader(GetParam().version.transport_version)) { + return; + } + const QuicUint128 kTestStatelessResetToken = 1010101; + QuicConfig config; + QuicConfigPeer::SetReceivedStatelessResetToken(&config, + kTestStatelessResetToken); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + + // Process a normal packet first to set the self address. + QuicReceivedPacket encrypted(nullptr, 0, QuicTime::Zero()); + connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, encrypted); + + std::unique_ptr<QuicEncryptedPacket> packet( + QuicFramer::BuildIetfStatelessResetPacket(connection_id_, + kTestStatelessResetToken)); + std::unique_ptr<QuicReceivedPacket> received( + ConstructReceivedPacket(*packet, QuicTime::Zero())); + EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(0); + EXPECT_CALL(visitor_, OnStatelessResetForProbing()); + auto host = kSelfAddress.host(); + QuicSocketAddress alternate_address(host, 80); + connection_.ProcessUdpPacket(alternate_address, kPeerAddress, *received); +} + TEST_P(QuicConnectionTest, GoAway) { if (VersionHasIetfQuicFrames(GetParam().version.transport_version)) { // GoAway is not available in version 99.
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h index 5a1ebbc..626349c 100644 --- a/quic/core/quic_session.h +++ b/quic/core/quic_session.h
@@ -110,6 +110,7 @@ bool is_connectivity_probe) override; void OnCanWrite() override; bool SendProbingData() override; + void OnStatelessResetForProbing() override {} void OnCongestionWindowChange(QuicTime /*now*/) override {} void OnConnectionMigration(AddressChangeType /*type*/) override {} // Adds a connection level WINDOW_UPDATE frame.
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h index 7d1d9db..df91aab 100644 --- a/quic/test_tools/quic_test_utils.h +++ b/quic/test_tools/quic_test_utils.h
@@ -498,6 +498,7 @@ MOCK_METHOD(void, OnWriteBlocked, (), (override)); MOCK_METHOD(void, OnCanWrite, (), (override)); MOCK_METHOD(bool, SendProbingData, (), (override)); + MOCK_METHOD(void, OnStatelessResetForProbing, (), (override)); MOCK_METHOD(void, OnCongestionWindowChange, (QuicTime now), (override)); MOCK_METHOD(void, OnConnectionMigration,
diff --git a/quic/test_tools/simulator/quic_endpoint.h b/quic/test_tools/simulator/quic_endpoint.h index 8b9fd1f..b5be76f 100644 --- a/quic/test_tools/simulator/quic_endpoint.h +++ b/quic/test_tools/simulator/quic_endpoint.h
@@ -51,6 +51,7 @@ void OnCryptoFrame(const QuicCryptoFrame& frame) override; void OnCanWrite() override; bool SendProbingData() override; + void OnStatelessResetForProbing() override {} bool WillingAndAbleToWrite() const override; bool HasPendingHandshake() const override; bool ShouldKeepConnectionAlive() const override;