Handle stateless reset that's received from path validation. Protected by quic_reloadable_flag_quic_pass_path_response_to_validator. PiperOrigin-RevId: 351648856 Change-Id: Ia503a2c78e8b6ec44e7fdb2cc4fc64e20b0c1045
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index b53e90d..d4a884e 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -1957,8 +1957,25 @@ // debug_visitor_. DCHECK(version().HasIetfInvariantHeader()); DCHECK_EQ(perspective_, Perspective::IS_CLIENT); - if (!visitor_->ValidateStatelessReset(last_packet_destination_address_, - last_packet_source_address_)) { + + if (use_path_validator_) { + if (!IsDefaultPath(last_packet_destination_address_, + last_packet_source_address_)) { + // This packet is received on a probing path. Do not close connection. + if (IsMostRecentAlternativePath( + last_packet_destination_address_, + GetEffectivePeerAddressFromCurrentPacket())) { + QUIC_BUG_IF(most_recent_alternative_path_.validated) + << "STATELESS_RESET received on alternate path after it's " + "validated."; + path_validator_.CancelPathValidation(); + } else { + QUIC_BUG << "Received Stateless Reset on unknown socket."; + } + return; + } + } else if (!visitor_->ValidateStatelessReset(last_packet_destination_address_, + last_packet_source_address_)) { // This packet is received on a probing path. Do not close connection. return; }
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index 14716ce..32cbf8d 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -6583,7 +6583,9 @@ kTestStatelessResetToken)); std::unique_ptr<QuicReceivedPacket> received( ConstructReceivedPacket(*packet, QuicTime::Zero())); - EXPECT_CALL(visitor_, ValidateStatelessReset(_, _)).WillOnce(Return(true)); + if (!connection_.use_path_validator()) { + EXPECT_CALL(visitor_, ValidateStatelessReset(_, _)).WillOnce(Return(true)); + } EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_PEER)) .WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame)); connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received); @@ -11314,6 +11316,50 @@ EXPECT_TRUE(success); } +TEST_P(QuicConnectionTest, PathValidationReceivesStatelessReset) { + if (!VersionHasIetfQuicFrames(connection_.version().transport_version) || + !connection_.use_path_validator()) { + return; + } + PathProbeTestInit(Perspective::IS_CLIENT); + const QuicUint128 kTestStatelessResetToken = 1010101; + QuicConfig config; + QuicConfigPeer::SetReceivedStatelessResetToken(&config, + kTestStatelessResetToken); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + const QuicSocketAddress kNewSelfAddress(QuicIpAddress::Any4(), 12345); + EXPECT_NE(kNewSelfAddress, connection_.self_address()); + TestPacketWriter new_writer(version(), &clock_, Perspective::IS_CLIENT); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .Times(AtLeast(1u)) + .WillOnce(Invoke([&]() { + EXPECT_EQ(1u, new_writer.packets_write_attempts()); + EXPECT_EQ(1u, new_writer.path_challenge_frames().size()); + EXPECT_EQ(1u, new_writer.padding_frames().size()); + EXPECT_EQ(kNewSelfAddress.host(), + new_writer.last_write_source_address()); + })); + bool success = true; + connection_.ValidatePath( + std::make_unique<TestQuicPathValidationContext>( + kNewSelfAddress, connection_.peer_address(), &new_writer), + std::make_unique<TestValidationResultDelegate>( + kNewSelfAddress, connection_.peer_address(), &success)); + EXPECT_EQ(0u, writer_->packets_write_attempts()); + EXPECT_TRUE(connection_.HasPendingPathValidation()); + + 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); + connection_.ProcessUdpPacket(kNewSelfAddress, kPeerAddress, *received); + EXPECT_FALSE(connection_.HasPendingPathValidation()); + EXPECT_FALSE(success); +} + // Tests that PATH_CHALLENGE is dropped if it is sent via a blocked alternative // writer. TEST_P(QuicConnectionTest, SendPathChallengeUsingBlockedNewSocket) {