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.