In QUIC client, use normalized server address to determine whether a packet is from unknown server. The current code can fail if direct_peer_address_ is a dual stacked address and last_received_packet_info_.source_address is a normal v4 address. This has been observed in GFE custom prober test. Protected by FLAGS_quic_test_peer_addr_change_after_normalize. PiperOrigin-RevId: 608614629
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc index 99d8891..8f3437f 100644 --- a/quiche/quic/core/quic_connection.cc +++ b/quiche/quic/core/quic_connection.cc
@@ -2940,11 +2940,22 @@ packet_creator_.SetServerConnectionId(default_path_.server_connection_id); } +// TODO(wub): Inline this function when deprecating +// --quic_test_peer_addr_change_after_normalize. +bool QuicConnection::PeerAddressChanged() const { + if (quic_test_peer_addr_change_after_normalize_) { + return direct_peer_address_.Normalized() != + last_received_packet_info_.source_address.Normalized(); + } + + return direct_peer_address_ != last_received_packet_info_.source_address; +} + bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { if (perspective_ == Perspective::IS_CLIENT && version().HasIetfQuicFrames() && direct_peer_address_.IsInitialized() && last_received_packet_info_.source_address.IsInitialized() && - direct_peer_address_ != last_received_packet_info_.source_address && + PeerAddressChanged() && !IsKnownServerAddress(last_received_packet_info_.source_address)) { // Discard packets received from unseen server addresses. return false;
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h index 5a770be..0113dde 100644 --- a/quiche/quic/core/quic_connection.h +++ b/quiche/quic/core/quic_connection.h
@@ -2021,6 +2021,8 @@ QuicPacketWriter* writer, const QuicEcnCodepoint ecn_codepoint); + bool PeerAddressChanged() const; + QuicConnectionContext context_; QuicFramer framer_; @@ -2429,6 +2431,9 @@ const bool quic_limit_new_streams_per_loop_2_ = GetQuicReloadableFlag(quic_limit_new_streams_per_loop_2); + + const bool quic_test_peer_addr_change_after_normalize_ = + GetQuicReloadableFlag(quic_test_peer_addr_change_after_normalize); }; } // namespace quic
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc index 8cd373b..018d5ec 100644 --- a/quiche/quic/core/quic_connection_test.cc +++ b/quiche/quic/core/quic_connection_test.cc
@@ -3033,6 +3033,36 @@ } } +TEST_P(QuicConnectionTest, NoNormalizedPeerAddressChangeAtClient) { + if (!version().HasIetfQuicFrames()) { + return; + } + QuicIpAddress peer_ip; + peer_ip.FromString("1.1.1.1"); + + QuicSocketAddress peer_addr = QuicSocketAddress(peer_ip, /*port=*/443); + QuicSocketAddress dualstack_peer_addr = + QuicSocketAddress(peer_addr.host().DualStacked(), peer_addr.port()); + + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)).Times(AnyNumber()); + set_perspective(Perspective::IS_CLIENT); + EXPECT_EQ(Perspective::IS_CLIENT, connection_.perspective()); + + QuicConnectionPeer::SetDirectPeerAddress(&connection_, dualstack_peer_addr); + + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, peer_addr, + ENCRYPTION_INITIAL); + EXPECT_TRUE(connection_.connected()); + + if (GetQuicReloadableFlag(quic_test_peer_addr_change_after_normalize)) { + EXPECT_EQ(0u, connection_.GetStats().packets_dropped); + } else { + EXPECT_EQ(1u, connection_.GetStats().packets_dropped); + } +} + TEST_P(QuicConnectionTest, ServerAddressChangesToKnownAddress) { if (!connection_.version().HasIetfQuicFrames()) { return;
diff --git a/quiche/quic/core/quic_flags_list.h b/quiche/quic/core/quic_flags_list.h index 10790c5..9c116cb 100644 --- a/quiche/quic/core/quic_flags_list.h +++ b/quiche/quic/core/quic_flags_list.h
@@ -39,6 +39,8 @@ QUIC_FLAG(quic_reloadable_flag_quic_ignore_gquic_probing, true) // If true, QUIC will default enable MTU discovery at server, with a target of 1450 bytes. QUIC_FLAG(quic_reloadable_flag_quic_enable_mtu_discovery_at_server, false) +// If true, QuicConnection::ProcessValidatedPacket will use normalized address to test peer address changes. +QUIC_FLAG(quic_reloadable_flag_quic_test_peer_addr_change_after_normalize, false) // If true, QuicGsoBatchWriter will support release time if it is available and the process has the permission to do so. QUIC_FLAG(quic_restart_flag_quic_support_release_time_for_gso, false) // If true, QuicSession will block outgoing control frames when the connection is closed.