Add DNAT support for QUIC Server Preferred Address.
When a server is behind a DNAT, the address it receives packets on
will be different from the address that the client sends to. So for
QUIC Server Preferred Address the server needs to advertise a different
address than the address it will expect to receive packets on.

This change adds an an optional "expected" server preferred address to
QuicConfig and changes QuicSession to pass the expected address to
QuicConnection. Renames the QuicConnection member and method from "sent"
to "expected".

PiperOrigin-RevId: 622937854
diff --git a/quiche/quic/core/quic_config.cc b/quiche/quic/core/quic_config.cc
index 2516c8c..04235cf 100644
--- a/quiche/quic/core/quic_config.cc
+++ b/quiche/quic/core/quic_config.cc
@@ -1419,6 +1419,34 @@
   return std::nullopt;
 }
 
+void QuicConfig::SetIPv4AlternateServerAddressForDNat(
+    const QuicSocketAddress& alternate_server_address_ipv4_to_send,
+    const QuicSocketAddress& mapped_alternate_server_address_ipv4) {
+  SetIPv4AlternateServerAddressToSend(alternate_server_address_ipv4_to_send);
+  mapped_alternate_server_address_ipv4_ = mapped_alternate_server_address_ipv4;
+}
+
+void QuicConfig::SetIPv6AlternateServerAddressForDNat(
+    const QuicSocketAddress& alternate_server_address_ipv6_to_send,
+    const QuicSocketAddress& mapped_alternate_server_address_ipv6) {
+  SetIPv6AlternateServerAddressToSend(alternate_server_address_ipv6_to_send);
+  mapped_alternate_server_address_ipv6_ = mapped_alternate_server_address_ipv6;
+}
+
+std::optional<QuicSocketAddress> QuicConfig::GetMappedAlternativeServerAddress(
+    quiche::IpAddressFamily address_family) const {
+  if (mapped_alternate_server_address_ipv6_.has_value() &&
+      address_family == quiche::IpAddressFamily::IP_V6) {
+    return *mapped_alternate_server_address_ipv6_;
+  }
+
+  if (mapped_alternate_server_address_ipv4_.has_value() &&
+      address_family == quiche::IpAddressFamily::IP_V4) {
+    return *mapped_alternate_server_address_ipv4_;
+  }
+  return GetPreferredAddressToSend(address_family);
+}
+
 void QuicConfig::ClearAlternateServerAddressToSend(
     quiche::IpAddressFamily address_family) {
   if (address_family == quiche::IpAddressFamily::IP_V4) {
diff --git a/quiche/quic/core/quic_config.h b/quiche/quic/core/quic_config.h
index c635689..bf2dae5 100644
--- a/quiche/quic/core/quic_config.h
+++ b/quiche/quic/core/quic_config.h
@@ -418,6 +418,22 @@
   void ClearAlternateServerAddressToSend(
       quiche::IpAddressFamily address_family);
 
+  // Sets the alternate server addresses to be used for a server behind a
+  // DNAT. The `to_send` address will be sent to the client, and the
+  // `mapped` address will be the corresponding internal address. Server-only.
+  void SetIPv4AlternateServerAddressForDNat(
+      const QuicSocketAddress& alternate_server_address_ipv4_to_send,
+      const QuicSocketAddress& mapped_alternate_server_address_ipv4);
+  void SetIPv6AlternateServerAddressForDNat(
+      const QuicSocketAddress& alternate_server_address_ipv6_to_send,
+      const QuicSocketAddress& mapped_alternate_server_address_ipv6);
+
+  // Returns the address the the server will receive packest from
+  // when the client is sending to the preferred address. Will be
+  // the mapped address, if present, or the alternate address otherwise.
+  std::optional<QuicSocketAddress> GetMappedAlternativeServerAddress(
+      quiche::IpAddressFamily address_family) const;
+
   // Returns true if this config supports server preferred address,
   // either via the kSPAD connection option or the QUIC protocol flag
   // quic_always_support_server_preferred_address.
@@ -610,6 +626,14 @@
   // Note that when QUIC_CRYPTO is in use, only one of the addresses is sent.
   QuicFixedSocketAddress alternate_server_address_ipv6_;
   QuicFixedSocketAddress alternate_server_address_ipv4_;
+
+  // When a server is behind DNAT, the addresses it sends to the client will
+  // not be the source address recevied in packets from the client. These
+  // two optional members capture the internal addresses which map to
+  // the addresses sent on the wire.
+  std::optional<QuicSocketAddress> mapped_alternate_server_address_ipv6_;
+  std::optional<QuicSocketAddress> mapped_alternate_server_address_ipv4_;
+
   // Connection Id data to send from the server or receive at the client as part
   // of the preferred address transport parameter.
   std::optional<std::pair<QuicConnectionId, StatelessResetToken>>
diff --git a/quiche/quic/core/quic_config_test.cc b/quiche/quic/core/quic_config_test.cc
index 625f645..9351118 100644
--- a/quiche/quic/core/quic_config_test.cc
+++ b/quiche/quic/core/quic_config_test.cc
@@ -537,6 +537,37 @@
   EXPECT_EQ(kFakeGoogleHandshakeMessage, params.google_handshake_message);
 }
 
+TEST_P(QuicConfigTest, DNATPreferredAddress) {
+  QuicIpAddress host_v4;
+  host_v4.FromString("127.0.3.1");
+  QuicSocketAddress server_address_v4 = QuicSocketAddress(host_v4, 1234);
+  QuicSocketAddress expected_server_address_v4 =
+      QuicSocketAddress(host_v4, 1235);
+
+  QuicIpAddress host_v6;
+  host_v6.FromString("2001:db8:0::1");
+  QuicSocketAddress server_address_v6 = QuicSocketAddress(host_v6, 1234);
+  QuicSocketAddress expected_server_address_v6 =
+      QuicSocketAddress(host_v6, 1235);
+
+  config_.SetIPv4AlternateServerAddressForDNat(server_address_v4,
+                                               expected_server_address_v4);
+  config_.SetIPv6AlternateServerAddressForDNat(server_address_v6,
+                                               expected_server_address_v6);
+
+  EXPECT_EQ(server_address_v4,
+            config_.GetPreferredAddressToSend(quiche::IpAddressFamily::IP_V4));
+  EXPECT_EQ(server_address_v6,
+            config_.GetPreferredAddressToSend(quiche::IpAddressFamily::IP_V6));
+
+  EXPECT_EQ(expected_server_address_v4,
+            config_.GetMappedAlternativeServerAddress(
+                quiche::IpAddressFamily::IP_V4));
+  EXPECT_EQ(expected_server_address_v6,
+            config_.GetMappedAlternativeServerAddress(
+                quiche::IpAddressFamily::IP_V6));
+}
+
 TEST_P(QuicConfigTest, FillTransportParamsNoV4PreferredAddress) {
   if (!version_.UsesTls()) {
     // TransportParameters are only used for QUIC+TLS.
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index e5fcc38..3b63ce0 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -2674,9 +2674,9 @@
   if (!default_path_.self_address.IsInitialized()) {
     default_path_.self_address = last_received_packet_info_.destination_address;
   } else if (default_path_.self_address != self_address &&
-             sent_server_preferred_address_.IsInitialized() &&
+             expected_server_preferred_address_.IsInitialized() &&
              self_address.Normalized() ==
-                 sent_server_preferred_address_.Normalized()) {
+                 expected_server_preferred_address_.Normalized()) {
     // If the packet is received at the preferred address, treat it as if it is
     // received on the original server address.
     last_received_packet_info_.destination_address = default_path_.self_address;
@@ -2972,8 +2972,8 @@
             "Self address migration is not supported at the server, current "
             "address: ",
             default_path_.self_address.ToString(),
-            ", server preferred address: ",
-            sent_server_preferred_address_.ToString(),
+            ", expected server preferred address: ",
+            expected_server_preferred_address_.ToString(),
             ", received packet address: ",
             last_received_packet_info_.destination_address.ToString(),
             ", size: ", last_received_packet_info_.length,
@@ -3009,7 +3009,7 @@
     // different sockets to the server's preferred address before handshake
     // gets confirmed. In this case, do not kick off client address migration
     // detection.
-    QUICHE_DCHECK(sent_server_preferred_address_.IsInitialized());
+    QUICHE_DCHECK(expected_server_preferred_address_.IsInitialized());
     last_received_packet_info_.source_address = direct_peer_address_;
   }
 
@@ -3408,16 +3408,16 @@
   QuicSocketAddress send_to_address = packet->peer_address;
   QuicSocketAddress send_from_address = self_address();
   if (perspective_ == Perspective::IS_SERVER &&
-      sent_server_preferred_address_.IsInitialized() &&
+      expected_server_preferred_address_.IsInitialized() &&
       received_client_addresses_cache_.Lookup(send_to_address) ==
           received_client_addresses_cache_.end()) {
     // Given server has not received packets from send_to_address to
     // self_address(), most NATs do not allow packets from self_address() to
     // send_to_address to go through. Override packet's self address to
-    // sent_server_preferred_address_.
+    // expected_server_preferred_address_.
     // TODO(b/262386897): server should validate reverse path before changing
     // self address of packets to send.
-    send_from_address = sent_server_preferred_address_;
+    send_from_address = expected_server_preferred_address_;
   }
   // Self address is always the default self address on this code path.
   const bool send_on_current_path = send_to_address == peer_address();
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h
index 36f0aca..6a4ddfe 100644
--- a/quiche/quic/core/quic_connection.h
+++ b/quiche/quic/core/quic_connection.h
@@ -1326,13 +1326,18 @@
   void OnServerPreferredAddressValidated(QuicPathValidationContext& context,
                                          bool owns_writer);
 
-  void set_sent_server_preferred_address(
-      const QuicSocketAddress& sent_server_preferred_address) {
-    sent_server_preferred_address_ = sent_server_preferred_address;
+  void set_expected_server_preferred_address(
+      const QuicSocketAddress& expected_server_preferred_address) {
+    expected_server_preferred_address_ = expected_server_preferred_address;
   }
 
+  // TODO(rch): Remove this method once Envoy is no longer using it.
   const QuicSocketAddress& sent_server_preferred_address() const {
-    return sent_server_preferred_address_;
+    return expected_server_preferred_address_;
+  }
+
+  const QuicSocketAddress& expected_server_preferred_address() const {
+    return expected_server_preferred_address_;
   }
 
   // True if received long packet header contains source connection ID.
@@ -2398,8 +2403,11 @@
   // only.
   QuicSocketAddress received_server_preferred_address_;
 
-  // Stores sent server preferred address in transport param. Server side only.
-  QuicSocketAddress sent_server_preferred_address_;
+  // Stores server preferred address which the server expects to receive
+  // packets from when the client is sending to the preferred address. May be
+  // different from the address sent to the client when the server is behind
+  // a DNAT.
+  QuicSocketAddress expected_server_preferred_address_;
 
   // If true, kicks off validation of server_preferred_address_ once it is
   // received. Also, send all coalesced packets on both paths until handshake is
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 11c98e6..883b6a3 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -1484,7 +1484,7 @@
     QuicConfig config;
     EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
     connection_.SetFromConfig(config);
-    connection_.set_sent_server_preferred_address(kServerPreferredAddress);
+    connection_.set_expected_server_preferred_address(kServerPreferredAddress);
   }
 
   // Receive server preferred address.
diff --git a/quiche/quic/core/quic_session.cc b/quiche/quic/core/quic_session.cc
index 5f3c68a..f8c763d 100644
--- a/quiche/quic/core/quic_session.cc
+++ b/quiche/quic/core/quic_session.cc
@@ -1390,9 +1390,9 @@
               .Normalized()
               .host()
               .address_family();
-      std::optional<QuicSocketAddress> preferred_address =
-          config_.GetPreferredAddressToSend(address_family);
-      if (preferred_address.has_value()) {
+      std::optional<QuicSocketAddress> expected_preferred_address =
+          config_.GetMappedAlternativeServerAddress(address_family);
+      if (expected_preferred_address.has_value()) {
         // Set connection ID and token if SPAD has received and a preferred
         // address of the same address family is configured.
         std::optional<QuicNewConnectionIdFrame> frame =
@@ -1401,7 +1401,8 @@
           config_.SetPreferredAddressConnectionIdAndTokenToSend(
               frame->connection_id, frame->stateless_reset_token);
         }
-        connection_->set_sent_server_preferred_address(*preferred_address);
+        connection_->set_expected_server_preferred_address(
+            *expected_preferred_address);
       }
       // Clear the alternative address of the other address family in the
       // config.
diff --git a/quiche/quic/core/quic_session_test.cc b/quiche/quic/core/quic_session_test.cc
index 897cc80..dc87ae5 100644
--- a/quiche/quic/core/quic_session_test.cc
+++ b/quiche/quic/core/quic_session_test.cc
@@ -3350,7 +3350,41 @@
                    ->GetPreferredAddressToSend(quiche::IpAddressFamily::IP_V6)
                    .has_value());
   EXPECT_EQ(preferred_address,
-            QuicConnectionPeer::GetSentServerPreferredAddress(connection_));
+            connection_->expected_server_preferred_address());
+}
+
+TEST_P(QuicSessionTestServer,
+       SetDNatServerPreferredAddressAccordingToAddressFamily) {
+  if (!session_.version().HasIetfQuicFrames()) {
+    return;
+  }
+  EXPECT_EQ(quiche::IpAddressFamily::IP_V4,
+            connection_->peer_address().host().address_family());
+  QuicConnectionPeer::SetEffectivePeerAddress(connection_,
+                                              connection_->peer_address());
+  QuicTagVector copt;
+  copt.push_back(kSPAD);
+  QuicConfigPeer::SetReceivedConnectionOptions(session_.config(), copt);
+  QuicSocketAddress sent_preferred_address(QuicIpAddress::Loopback4(), 12345);
+  QuicSocketAddress expected_preferred_address(QuicIpAddress::Loopback4(),
+                                               12346);
+  session_.config()->SetIPv4AlternateServerAddressForDNat(
+      sent_preferred_address, expected_preferred_address);
+  session_.config()->SetIPv6AlternateServerAddressForDNat(
+      QuicSocketAddress(QuicIpAddress::Loopback6(), 12345),
+      QuicSocketAddress(QuicIpAddress::Loopback6(), 12346));
+
+  connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+  session_.OnConfigNegotiated();
+  EXPECT_EQ(QuicSocketAddress(QuicIpAddress::Loopback4(), 12345),
+            session_.config()
+                ->GetPreferredAddressToSend(quiche::IpAddressFamily::IP_V4)
+                .value());
+  EXPECT_FALSE(session_.config()
+                   ->GetPreferredAddressToSend(quiche::IpAddressFamily::IP_V6)
+                   .has_value());
+  EXPECT_EQ(expected_preferred_address,
+            connection_->expected_server_preferred_address());
 }
 
 TEST_P(QuicSessionTestServer, NoServerPreferredAddressIfAddressFamilyMismatch) {
@@ -3375,8 +3409,8 @@
   EXPECT_FALSE(session_.config()
                    ->GetPreferredAddressToSend(quiche::IpAddressFamily::IP_V6)
                    .has_value());
-  EXPECT_FALSE(QuicConnectionPeer::GetSentServerPreferredAddress(connection_)
-                   .IsInitialized());
+  EXPECT_FALSE(
+      connection_->expected_server_preferred_address().IsInitialized());
 }
 
 TEST_P(QuicSessionTestServer, OpenStreamLimitPerEventLoop) {