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