relnote: On server side, do not process the first initial QUIC packet received from a client if the UDP datagram is < 1200 bytes. Instead, send a connection close with PROTOCOL_VIOLATION if the version is supported. Protected by quic_reloadable_flag_quic_donot_process_small_initial_packets.
PiperOrigin-RevId: 270157435
Change-Id: Id0faa750300b2e75c7e87cc05dd8635c580f01ba
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index beb70ca..3187c78 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -32,6 +32,9 @@
namespace {
+// Minimal INITIAL packet length sent by clients is 1200.
+const QuicPacketLength kMinClientInitialPacketLength = 1200;
+
// An alarm that informs the QuicDispatcher to delete old sessions.
class DeleteSessionsAlarm : public QuicAlarm::Delegate {
public:
@@ -142,11 +145,35 @@
framer_.set_data_producer(nullptr);
}
+ // Serializes a packet containing CONNECTION_CLOSE frame and send it (without
+ // adding connection to the time wait).
+ void StatelesslyCloseConnection(const QuicSocketAddress& self_address,
+ const QuicSocketAddress& peer_address,
+ QuicErrorCode error_code,
+ const std::string& error_details) {
+ SerializeConnectionClosePacket(error_code, error_details);
+
+ for (const auto& packet : *collector_.packets()) {
+ time_wait_list_manager_->SendPacket(self_address, peer_address, *packet);
+ }
+ }
+
// Generates a packet containing a CONNECTION_CLOSE frame specifying
// |error_code| and |error_details| and add the connection to time wait.
void CloseConnection(QuicErrorCode error_code,
const std::string& error_details,
bool ietf_quic) {
+ SerializeConnectionClosePacket(error_code, error_details);
+
+ time_wait_list_manager_->AddConnectionIdToTimeWait(
+ server_connection_id_, ietf_quic,
+ QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
+ quic::ENCRYPTION_INITIAL, collector_.packets());
+ }
+
+ private:
+ void SerializeConnectionClosePacket(QuicErrorCode error_code,
+ const std::string& error_details) {
QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame(
framer_.transport_version(), error_code, error_details,
/*transport_close_frame_type=*/0);
@@ -158,13 +185,8 @@
}
creator_.FlushCurrentPacket();
DCHECK_EQ(1u, collector_.packets()->size());
- time_wait_list_manager_->AddConnectionIdToTimeWait(
- server_connection_id_, ietf_quic,
- QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
- quic::ENCRYPTION_INITIAL, collector_.packets());
}
- private:
QuicConnectionId server_connection_id_;
QuicFramer framer_;
// Set as the visitor of |creator_| to collect any generated packets.
@@ -256,9 +278,9 @@
QuicStringPiece retry_token;
error = QuicFramer::ParsePublicHeaderDispatcher(
packet, expected_server_connection_id_length_, &packet_info.form,
- &packet_info.version_flag, &packet_info.use_length_prefix,
- &packet_info.version_label, &packet_info.version,
- &packet_info.destination_connection_id,
+ &packet_info.long_packet_type, &packet_info.version_flag,
+ &packet_info.use_length_prefix, &packet_info.version_label,
+ &packet_info.version, &packet_info.destination_connection_id,
&packet_info.source_connection_id, &retry_token_present, &retry_token,
&detailed_error);
}
@@ -447,6 +469,24 @@
}
return true;
}
+
+ if (GetQuicReloadableFlag(quic_use_parse_public_header) &&
+ GetQuicReloadableFlag(quic_donot_process_small_initial_packets) &&
+ crypto_config()->validate_chlo_size() &&
+ packet_info.form == IETF_QUIC_LONG_HEADER_PACKET &&
+ packet_info.long_packet_type == INITIAL &&
+ packet_info.packet.length() < kMinClientInitialPacketLength) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_donot_process_small_initial_packets);
+ StatelessConnectionTerminator terminator(
+ packet_info.destination_connection_id, packet_info.version,
+ helper_.get(), time_wait_list_manager_.get());
+ QUIC_DVLOG(1) << "Initial packet too small: "
+ << packet_info.packet.length();
+ terminator.StatelesslyCloseConnection(
+ packet_info.self_address, packet_info.peer_address,
+ IETF_QUIC_PROTOCOL_VIOLATION, "Initial packet too small");
+ return true;
+ }
}
return false;