Use deterministic replacement connection IDs

This CL removes a DoS attack vector where an attacker could grow QuicDispatcher::connection_id_map_ unboundedly. It does so by no longer using random connection IDs that are saved in connection_id_map_; instead we now generate deterministic replacement connection IDs, removing the need for a map. It should not impact the GFE because the GFE overrides QuicDispatcher::GenerateNewServerConnectionId with an already deterministic method, but is still flag protected just in case.

gfe-relnote: use deterministic replacement connection IDs, protected by new disabled flag gfe2_restart_flag_quic_deterministic_replacement_connection_ids
PiperOrigin-RevId: 264192278
Change-Id: I843bf0d846830d4b13e0bb1b470a71b2428ad7c8
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index b659bda..553fcd4 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -305,18 +305,29 @@
   }
   DCHECK(QuicUtils::VariableLengthConnectionIdAllowedForVersion(
       version.transport_version));
-  auto it = connection_id_map_.find(server_connection_id);
-  if (it != connection_id_map_.end()) {
-    return it->second;
+
+  if (!GetQuicRestartFlag(quic_deterministic_replacement_connection_ids)) {
+    auto it = connection_id_map_.find(server_connection_id);
+    if (it != connection_id_map_.end()) {
+      return it->second;
+    }
+  } else {
+    // TODO(dschinazi) Remove QuicDispatcher::connection_id_map_ entirely
+    // when quic_deterministic_replacement_connection_ids is deprecated.
+    QUIC_RESTART_FLAG_COUNT_N(quic_deterministic_replacement_connection_ids, 1,
+                              2);
   }
   QuicConnectionId new_connection_id =
       GenerateNewServerConnectionId(version, server_connection_id);
   DCHECK_EQ(expected_server_connection_id_length_, new_connection_id.length());
-  // TODO(dschinazi) Prevent connection_id_map_ from growing indefinitely
-  // before we ship a version that supports variable length connection IDs
-  // to production.
-  connection_id_map_.insert(
-      std::make_pair(server_connection_id, new_connection_id));
+  if (!GetQuicRestartFlag(quic_deterministic_replacement_connection_ids)) {
+    connection_id_map_.insert(
+        std::make_pair(server_connection_id, new_connection_id));
+  } else {
+    // Verify that GenerateNewServerConnectionId is deterministic.
+    DCHECK_EQ(new_connection_id,
+              GenerateNewServerConnectionId(version, server_connection_id));
+  }
   QUIC_DLOG(INFO) << "Replacing incoming connection ID " << server_connection_id
                   << " with " << new_connection_id;
   return new_connection_id;
@@ -324,8 +335,15 @@
 
 QuicConnectionId QuicDispatcher::GenerateNewServerConnectionId(
     ParsedQuicVersion /*version*/,
-    QuicConnectionId /*connection_id*/) const {
-  return QuicUtils::CreateRandomConnectionId();
+    QuicConnectionId connection_id) const {
+  if (!GetQuicRestartFlag(quic_deterministic_replacement_connection_ids)) {
+    return QuicUtils::CreateRandomConnectionId();
+  }
+
+  QUIC_RESTART_FLAG_COUNT_N(quic_deterministic_replacement_connection_ids, 2,
+                            2);
+
+  return QuicUtils::CreateReplacementConnectionId(connection_id);
 }
 
 bool QuicDispatcher::MaybeDispatchPacket(