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;