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) {