Add a QUIC protocol flag to not require the the kSPAD connection option in order to use QUIC server preferred address support. quic_always_support_server_preferred_address defaults to false to match existing behavior but may be set to true. This will make it easier for QUICHE servers to support non-QUICHE clients using server preferred address. For context: https://github.com/envoyproxy/envoy/pull/32130 PiperOrigin-RevId: 603488744
diff --git a/quiche/quic/core/http/end_to_end_test.cc b/quiche/quic/core/http/end_to_end_test.cc index 6024569..3eaddf2 100644 --- a/quiche/quic/core/http/end_to_end_test.cc +++ b/quiche/quic/core/http/end_to_end_test.cc
@@ -467,7 +467,9 @@ server_writer_ = new PacketDroppingTestWriter(); StartServer(); - client_config_.SetConnectionOptionsToSend(QuicTagVector{kSPAD}); + if (!GetQuicFlag(quic_always_support_server_preferred_address)) { + client_config_.SetConnectionOptionsToSend(QuicTagVector{kSPAD}); + } } if (!connect_to_server_on_initialize_) { @@ -5467,6 +5469,35 @@ EXPECT_FALSE(client_stats.failed_to_validate_server_preferred_address); } +TEST_P(EndToEndTest, SimpleServerPreferredAddressTestNoSPAD) { + SetQuicFlag(quic_always_support_server_preferred_address, true); + use_preferred_address_ = true; + ASSERT_TRUE(Initialize()); + if (!version_.HasIetfQuicFrames()) { + return; + } + client_.reset(CreateQuicClient(nullptr)); + QuicConnection* client_connection = GetClientConnection(); + EXPECT_TRUE(client_->client()->WaitForHandshakeConfirmed()); + EXPECT_EQ(server_address_, client_connection->effective_peer_address()); + EXPECT_EQ(server_address_, client_connection->peer_address()); + EXPECT_TRUE(client_->client()->HasPendingPathValidation()); + QuicConnectionId server_cid1 = client_connection->connection_id(); + + SendSynchronousFooRequestAndCheckResponse(); + while (client_->client()->HasPendingPathValidation()) { + client_->client()->WaitForEvents(); + } + EXPECT_EQ(server_preferred_address_, + client_connection->effective_peer_address()); + EXPECT_EQ(server_preferred_address_, client_connection->peer_address()); + EXPECT_NE(server_cid1, client_connection->connection_id()); + + const auto client_stats = GetClientConnection()->GetStats(); + EXPECT_TRUE(client_stats.server_preferred_address_validated); + EXPECT_FALSE(client_stats.failed_to_validate_server_preferred_address); +} + TEST_P(EndToEndTest, OptimizedServerPreferredAddress) { use_preferred_address_ = true; ASSERT_TRUE(Initialize());
diff --git a/quiche/quic/core/quic_config.cc b/quiche/quic/core/quic_config.cc index 75d29f3..2516c8c 100644 --- a/quiche/quic/core/quic_config.cc +++ b/quiche/quic/core/quic_config.cc
@@ -1428,4 +1428,9 @@ } } +bool QuicConfig::SupportsServerPreferredAddress(Perspective perspective) const { + return HasClientSentConnectionOption(kSPAD, perspective) || + GetQuicFlag(quic_always_support_server_preferred_address); +} + } // namespace quic
diff --git a/quiche/quic/core/quic_config.h b/quiche/quic/core/quic_config.h index bf1cc6c..c635689 100644 --- a/quiche/quic/core/quic_config.h +++ b/quiche/quic/core/quic_config.h
@@ -418,6 +418,11 @@ void ClearAlternateServerAddressToSend( quiche::IpAddressFamily address_family); + // 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. + bool SupportsServerPreferredAddress(Perspective perspective) const; + // Original destination connection ID. void SetOriginalConnectionIdToSend( const QuicConnectionId& original_destination_connection_id);
diff --git a/quiche/quic/core/quic_config_test.cc b/quiche/quic/core/quic_config_test.cc index 86e5a99..625f645 100644 --- a/quiche/quic/core/quic_config_test.cc +++ b/quiche/quic/core/quic_config_test.cc
@@ -568,6 +568,26 @@ kTestServerAddressV6); } +TEST_P(QuicConfigTest, SupportsServerPreferredAddress) { + SetQuicFlag(quic_always_support_server_preferred_address, true); + EXPECT_TRUE(config_.SupportsServerPreferredAddress(Perspective::IS_CLIENT)); + EXPECT_TRUE(config_.SupportsServerPreferredAddress(Perspective::IS_SERVER)); + + SetQuicFlag(quic_always_support_server_preferred_address, false); + EXPECT_FALSE(config_.SupportsServerPreferredAddress(Perspective::IS_CLIENT)); + EXPECT_FALSE(config_.SupportsServerPreferredAddress(Perspective::IS_SERVER)); + + QuicTagVector copt; + copt.push_back(kSPAD); + config_.SetConnectionOptionsToSend(copt); + EXPECT_TRUE(config_.SupportsServerPreferredAddress(Perspective::IS_CLIENT)); + EXPECT_FALSE(config_.SupportsServerPreferredAddress(Perspective::IS_SERVER)); + + config_.SetInitialReceivedConnectionOptions(copt); + EXPECT_TRUE(config_.SupportsServerPreferredAddress(Perspective::IS_CLIENT)); + EXPECT_TRUE(config_.SupportsServerPreferredAddress(Perspective::IS_SERVER)); +} + TEST_P(QuicConfigTest, ProcessTransportParametersServer) { 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 3a3b356..88f52d8 100644 --- a/quiche/quic/core/quic_connection.cc +++ b/quiche/quic/core/quic_connection.cc
@@ -648,7 +648,7 @@ if (version().HasIetfQuicFrames() && config.HasReceivedPreferredAddressConnectionIdAndToken() && - config.HasClientSentConnectionOption(kSPAD, perspective_)) { + config.SupportsServerPreferredAddress(perspective_)) { if (self_address().host().IsIPv4() && config.HasReceivedIPv4AlternateServerAddress()) { received_server_preferred_address_ =
diff --git a/quiche/quic/core/quic_protocol_flags_list.h b/quiche/quic/core/quic_protocol_flags_list.h index bd337e9..417c1a6 100644 --- a/quiche/quic/core/quic_protocol_flags_list.h +++ b/quiche/quic/core/quic_protocol_flags_list.h
@@ -231,4 +231,8 @@ bool, quic_enable_chaos_protection, true, "If true, use chaos protection to randomize client initials.") +QUIC_PROTOCOL_FLAG(bool, quic_always_support_server_preferred_address, false, + "If false, the kSPAD connection option is required to use " + "QUIC server preferred address support.") + #endif
diff --git a/quiche/quic/core/quic_session.cc b/quiche/quic/core/quic_session.cc index 6e655c5..359841a 100644 --- a/quiche/quic/core/quic_session.cc +++ b/quiche/quic/core/quic_session.cc
@@ -1384,7 +1384,7 @@ if (perspective_ == Perspective::IS_SERVER && version().HasIetfQuicFrames() && connection_->effective_peer_address().IsInitialized()) { - if (config_.HasClientSentConnectionOption(kSPAD, perspective_)) { + if (config_.SupportsServerPreferredAddress(perspective_)) { quiche::IpAddressFamily address_family = connection_->effective_peer_address() .Normalized()