Add check to enforce that IETF QUIC client (1) discards packet with an unknown server address and (2) does not start reverse path validation.

PiperOrigin-RevId: 363038408
Change-Id: I7caec059dabe33a2261ed4dd180ffd36ad5b11f5
diff --git a/quic/core/http/quic_spdy_client_session.cc b/quic/core/http/quic_spdy_client_session.cc
index 63dcc18..ada6d85 100644
--- a/quic/core/http/quic_spdy_client_session.cc
+++ b/quic/core/http/quic_spdy_client_session.cc
@@ -104,6 +104,18 @@
   return crypto_stream_.get();
 }
 
+bool QuicSpdyClientSession::IsKnownServerAddress(
+    const QuicSocketAddress& address) const {
+  return std::find(known_server_addresses_.cbegin(),
+                   known_server_addresses_.cend(),
+                   address) != known_server_addresses_.cend();
+}
+
+void QuicSpdyClientSession::AddKnownServerAddress(
+    const QuicSocketAddress& address) {
+  known_server_addresses_.push_back(address);
+}
+
 void QuicSpdyClientSession::CryptoConnect() {
   QUICHE_DCHECK(flow_controller());
   crypto_stream_->CryptoConnect();
diff --git a/quic/core/http/quic_spdy_client_session.h b/quic/core/http/quic_spdy_client_session.h
index c21eeea..345c014 100644
--- a/quic/core/http/quic_spdy_client_session.h
+++ b/quic/core/http/quic_spdy_client_session.h
@@ -41,6 +41,9 @@
   QuicSpdyClientStream* CreateOutgoingUnidirectionalStream() override;
   QuicCryptoClientStreamBase* GetMutableCryptoStream() override;
   const QuicCryptoClientStreamBase* GetCryptoStream() const override;
+  bool IsKnownServerAddress(const QuicSocketAddress& address) const override;
+
+  void AddKnownServerAddress(const QuicSocketAddress& address);
 
   bool IsAuthorized(const std::string& authority) override;
 
@@ -106,6 +109,8 @@
   std::unique_ptr<QuicCryptoClientStreamBase> crypto_stream_;
   QuicServerId server_id_;
   QuicCryptoClientConfig* crypto_config_;
+  // Server addresses that are known to the client.
+  std::vector<QuicSocketAddress> known_server_addresses_;
 
   // If this is set to false, the client will ignore server GOAWAYs and allow
   // the creation of streams regardless of the high chance they will fail.
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 30387ba..fd3955e 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -2861,6 +2861,17 @@
 }
 
 bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) {
+  if (perspective_ == Perspective::IS_CLIENT && version().HasIetfQuicFrames() &&
+      direct_peer_address_.IsInitialized() &&
+      last_packet_source_address_.IsInitialized() &&
+      direct_peer_address_ != last_packet_source_address_ &&
+      !visitor_->IsKnownServerAddress(last_packet_source_address_)) {
+    // TODO(haoyuewang) Revisit this when preferred_address transport parameter
+    // is used on the client side.
+    // Discard packets received from unseen server addresses.
+    return false;
+  }
+
   if (perspective_ == Perspective::IS_SERVER &&
       default_path_.self_address.IsInitialized() &&
       last_packet_destination_address_.IsInitialized() &&
@@ -5275,7 +5286,8 @@
       return connected_;
     }
     QUIC_CODE_COUNT_N(quic_count_bytes_on_alternative_path_seperately, 3, 5);
-    if (type == PATH_CHALLENGE_FRAME &&
+    if (perspective_ == Perspective::IS_SERVER &&
+        type == PATH_CHALLENGE_FRAME &&
         !IsAlternativePath(last_packet_destination_address_,
                            current_effective_peer_address)) {
       QUIC_DVLOG(1)
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index 65338d5..a6dc7f5 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -239,6 +239,9 @@
   // Called by the server to send another token.
   // Return false if the crypto stream fail to generate one.
   virtual void MaybeSendAddressToken() = 0;
+
+  // Whether the server address is known to the connection.
+  virtual bool IsKnownServerAddress(const QuicSocketAddress& address) const = 0;
 };
 
 // Interface which gets callbacks from the QuicConnection at interesting
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index b797da8..21e1f57 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -2573,8 +2573,14 @@
   EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0);
   ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress,
                                   kNewPeerAddress, ENCRYPTION_INITIAL);
-  EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
-  EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
+  if (connection_.version().HasIetfQuicFrames()) {
+    // IETF QUIC disallows server initiated address change.
+    EXPECT_EQ(kPeerAddress, connection_.peer_address());
+    EXPECT_EQ(kPeerAddress, connection_.effective_peer_address());
+  } else {
+    EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
+    EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address());
+  }
 }
 
 TEST_P(QuicConnectionTest, MaxPacketSize) {
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h
index f7eef2b..cd496cf 100644
--- a/quic/core/quic_session.h
+++ b/quic/core/quic_session.h
@@ -170,6 +170,10 @@
   void BeforeConnectionCloseSent() override {}
   bool ValidateToken(absl::string_view token) const override;
   void MaybeSendAddressToken() override;
+  bool IsKnownServerAddress(
+      const QuicSocketAddress& /*address*/) const override {
+    return false;
+  }
 
   // QuicStreamFrameDataProducer
   WriteStreamDataResult WriteStreamData(QuicStreamId id,
diff --git a/quic/test_tools/quic_test_client.cc b/quic/test_tools/quic_test_client.cc
index 8480b04..8c58cd7 100644
--- a/quic/test_tools/quic_test_client.cc
+++ b/quic/test_tools/quic_test_client.cc
@@ -311,6 +311,9 @@
 
 void MockableQuicClient::set_peer_address(const QuicSocketAddress& address) {
   mockable_network_helper()->set_peer_address(address);
+  if (client_session() != nullptr) {
+    client_session()->AddKnownServerAddress(address);
+  }
 }
 
 const QuicReceivedPacket* MockableQuicClient::last_incoming_packet() {
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
index d737ae9..032e38c 100644
--- a/quic/test_tools/quic_test_utils.h
+++ b/quic/test_tools/quic_test_utils.h
@@ -33,6 +33,7 @@
 #include "quic/core/quic_types.h"
 #include "quic/core/quic_utils.h"
 #include "quic/platform/api/quic_mem_slice_storage.h"
+#include "quic/platform/api/quic_socket_address.h"
 #include "quic/platform/api/quic_test.h"
 #include "quic/test_tools/mock_clock.h"
 #include "quic/test_tools/mock_quic_session_visitor.h"
@@ -622,6 +623,11 @@
   MOCK_METHOD(void, BeforeConnectionCloseSent, (), (override));
   MOCK_METHOD(bool, ValidateToken, (absl::string_view), (const, override));
   MOCK_METHOD(void, MaybeSendAddressToken, (), (override));
+
+  bool IsKnownServerAddress(
+      const QuicSocketAddress& /*address*/) const override {
+    return false;
+  }
 };
 
 class MockQuicConnectionHelper : public QuicConnectionHelperInterface {
diff --git a/quic/test_tools/simulator/quic_endpoint.h b/quic/test_tools/simulator/quic_endpoint.h
index 8dab235..01d35d3 100644
--- a/quic/test_tools/simulator/quic_endpoint.h
+++ b/quic/test_tools/simulator/quic_endpoint.h
@@ -114,6 +114,10 @@
     return true;
   }
   void MaybeSendAddressToken() override {}
+  bool IsKnownServerAddress(
+      const QuicSocketAddress& /*address*/) const override {
+    return false;
+  }
 
   // End QuicConnectionVisitorInterface implementation.