gfe-relnote: In QUIC, terminate Google QUIC connections (<= v43) similar as IETF QUIC connection. Protected by gfe2_reloadable_flag_quic_terminate_gquic_connection_as_ietf.

Use version_flag to indicate whether the connection is pre or post handshake.

PiperOrigin-RevId: 244349046
Change-Id: I3af6c5f14f12168351c8908bf03eab6c8d24740a
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index e537c73..7a49700 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -3348,7 +3348,8 @@
   EXPECT_EQ("", client_->SendSynchronousRequest("/foo"));
 
   if (client_->client()->client_session()->connection()->transport_version() >
-      QUIC_VERSION_43) {
+          QUIC_VERSION_43 ||
+      GetQuicReloadableFlag(quic_terminate_gquic_connection_as_ietf)) {
     EXPECT_EQ(QUIC_HANDSHAKE_FAILED, client_->connection_error());
   } else {
     EXPECT_EQ(QUIC_PUBLIC_RESET, client_->connection_error());
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index 75b3c30..2e81740 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -392,7 +392,7 @@
                     << static_cast<int>(
                            framer_.GetExpectedConnectionIdLength());
     ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id, header.form,
-                                     header.version);
+                                     header.version_flag, header.version);
     return false;
   }
 
@@ -480,12 +480,13 @@
   if (fate == kFateProcess) {
     // Execute stateless rejection logic to determine the packet fate, then
     // invoke ProcessUnauthenticatedHeaderFate.
-    MaybeRejectStatelessly(connection_id, header.form, header.version);
+    MaybeRejectStatelessly(connection_id, header.form, header.version_flag,
+                           header.version);
   } else {
     // If the fate is already known, process it without executing stateless
     // rejection logic.
     ProcessUnauthenticatedHeaderFate(fate, connection_id, header.form,
-                                     header.version);
+                                     header.version_flag, header.version);
   }
 
   return false;
@@ -495,6 +496,7 @@
     QuicPacketFate fate,
     QuicConnectionId connection_id,
     PacketHeaderFormat form,
+    bool version_flag,
     ParsedQuicVersion version) {
   switch (fate) {
     case kFateProcess: {
@@ -512,7 +514,7 @@
                         << " to time-wait list.";
         QUIC_CODE_COUNT(quic_reject_fate_time_wait);
         StatelesslyTerminateConnection(
-            connection_id, form, version, QUIC_HANDSHAKE_FAILED,
+            connection_id, form, version_flag, version, QUIC_HANDSHAKE_FAILED,
             "Reject connection",
             quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
       }
@@ -605,15 +607,23 @@
   if (connection->termination_packets() != nullptr &&
       !connection->termination_packets()->empty()) {
     action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS;
-  } else if (connection->transport_version() > QUIC_VERSION_43) {
+  } else if (connection->transport_version() > QUIC_VERSION_43 ||
+             GetQuicReloadableFlag(quic_terminate_gquic_connection_as_ietf)) {
     if (!connection->IsHandshakeConfirmed()) {
-      QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_handshake_failed);
+      if (connection->transport_version() <= QUIC_VERSION_43) {
+        QUIC_CODE_COUNT(gquic_add_to_time_wait_list_with_handshake_failed);
+      } else {
+        QUIC_CODE_COUNT(quic_v44_add_to_time_wait_list_with_handshake_failed);
+      }
       action = QuicTimeWaitListManager::SEND_TERMINATION_PACKETS;
       // This serializes a connection close termination packet with error code
       // QUIC_HANDSHAKE_FAILED and adds the connection to the time wait list.
       StatelesslyTerminateConnection(
-          connection->connection_id(), IETF_QUIC_LONG_HEADER_PACKET,
-          connection->version(), QUIC_HANDSHAKE_FAILED,
+          connection->connection_id(),
+          connection->transport_version() > QUIC_VERSION_43
+              ? IETF_QUIC_LONG_HEADER_PACKET
+              : GOOGLE_QUIC_PACKET,
+          /*version_flag=*/true, connection->version(), QUIC_HANDSHAKE_FAILED,
           "Connection is closed by server before handshake confirmed",
           // Although it is our intention to send termination packets, the
           // |action| argument is not used by this call to
@@ -756,11 +766,14 @@
 void QuicDispatcher::StatelesslyTerminateConnection(
     QuicConnectionId connection_id,
     PacketHeaderFormat format,
+    bool version_flag,
     ParsedQuicVersion version,
     QuicErrorCode error_code,
     const std::string& error_details,
     QuicTimeWaitListManager::TimeWaitAction action) {
-  if (format != IETF_QUIC_LONG_HEADER_PACKET) {
+  if (format != IETF_QUIC_LONG_HEADER_PACKET &&
+      (!GetQuicReloadableFlag(quic_terminate_gquic_connection_as_ietf) ||
+       !version_flag)) {
     QUIC_DVLOG(1) << "Statelessly terminating " << connection_id
                   << " based on a non-ietf-long packet, action:" << action
                   << ", error_code:" << error_code
@@ -786,7 +799,12 @@
     StatelessConnectionTerminator terminator(
         connection_id, &framer_, helper_.get(), time_wait_list_manager_.get());
     // This also adds the connection to time wait list.
-    terminator.CloseConnection(error_code, error_details, true);
+    if (format == GOOGLE_QUIC_PACKET) {
+      QUIC_RELOADABLE_FLAG_COUNT_N(quic_terminate_gquic_connection_as_ietf, 1,
+                                   2);
+    }
+    terminator.CloseConnection(error_code, error_details,
+                               format != GOOGLE_QUIC_PACKET);
 
     // Restore framer_ to the original version, as if nothing changed in it.
     framer_.set_version(original_version);
@@ -802,10 +820,13 @@
   // with an empty version list, which can be understood by the client.
   std::vector<std::unique_ptr<QuicEncryptedPacket>> termination_packets;
   termination_packets.push_back(QuicFramer::BuildVersionNegotiationPacket(
-      connection_id, /*ietf_quic=*/true,
+      connection_id, /*ietf_quic=*/format != GOOGLE_QUIC_PACKET,
       ParsedQuicVersionVector{UnsupportedQuicVersion()}));
+  if (format == GOOGLE_QUIC_PACKET) {
+    QUIC_RELOADABLE_FLAG_COUNT_N(quic_terminate_gquic_connection_as_ietf, 2, 2);
+  }
   time_wait_list_manager()->AddConnectionIdToTimeWait(
-      connection_id, /*ietf_quic=*/true,
+      connection_id, /*ietf_quic=*/format != GOOGLE_QUIC_PACKET,
       QuicTimeWaitListManager::SEND_TERMINATION_PACKETS, ENCRYPTION_INITIAL,
       &termination_packets);
 }
@@ -1006,8 +1027,8 @@
       connection_id,
       early_arrived_packets.ietf_quic ? IETF_QUIC_LONG_HEADER_PACKET
                                       : GOOGLE_QUIC_PACKET,
-      early_arrived_packets.version, QUIC_HANDSHAKE_FAILED,
-      "Packets buffered for too long",
+      /*version_flag=*/true, early_arrived_packets.version,
+      QUIC_HANDSHAKE_FAILED, "Packets buffered for too long",
       quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
 }
 
@@ -1093,8 +1114,8 @@
     // Don't any create new connection.
     QUIC_CODE_COUNT(quic_reject_stop_accepting_new_connections);
     StatelesslyTerminateConnection(
-        current_connection_id(), form, version, QUIC_HANDSHAKE_FAILED,
-        "Stop accepting new connections",
+        current_connection_id(), form, /*version_flag=*/true, version,
+        QUIC_HANDSHAKE_FAILED, "Stop accepting new connections",
         quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
     // Time wait list will reject the packet correspondingly.
     time_wait_list_manager()->ProcessPacket(
@@ -1168,7 +1189,8 @@
  public:
   StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher,
                                        ParsedQuicVersion first_version,
-                                       PacketHeaderFormat form)
+                                       PacketHeaderFormat form,
+                                       bool version_flag)
       : dispatcher_(dispatcher),
         current_client_address_(dispatcher->current_client_address_),
         current_peer_address_(dispatcher->current_peer_address_),
@@ -1177,7 +1199,8 @@
         current_packet_(
             dispatcher->current_packet_->Clone()),  // Note: copies the packet
         first_version_(first_version),
-        current_packet_format_(form) {}
+        current_packet_format_(form),
+        current_version_flag_(version_flag) {}
 
   void Run(std::unique_ptr<StatelessRejector> rejector) override {
     if (additional_context_ != nullptr) {
@@ -1186,7 +1209,7 @@
     dispatcher_->OnStatelessRejectorProcessDone(
         std::move(rejector), current_client_address_, current_peer_address_,
         current_self_address_, std::move(current_packet_), first_version_,
-        current_packet_format_);
+        current_packet_format_, current_version_flag_);
   }
 
  private:
@@ -1200,15 +1223,16 @@
   std::unique_ptr<QuicReceivedPacket> current_packet_;
   ParsedQuicVersion first_version_;
   const PacketHeaderFormat current_packet_format_;
+  bool current_version_flag_;
 };
 
 void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id,
-
                                             PacketHeaderFormat form,
+                                            bool version_flag,
                                             ParsedQuicVersion version) {
   if (version.handshake_protocol == PROTOCOL_TLS1_3) {
     ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id, form,
-                                     version);
+                                     version_flag, version);
     return;
     // TODO(nharper): Support buffering non-ClientHello packets when using TLS.
   }
@@ -1225,12 +1249,12 @@
                                 &alpn_extractor, connection_id.length())) {
       // Buffer non-CHLO packets.
       ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form,
-                                       version);
+                                       version_flag, version);
       return;
     }
     current_alpn_ = alpn_extractor.ConsumeAlpn();
     ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id, form,
-                                     version);
+                                     version_flag, version);
     return;
   }
 
@@ -1245,7 +1269,8 @@
   if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
                               config_->create_session_tag_indicators(),
                               &validator, connection_id.length())) {
-    ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form, version);
+    ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form,
+                                     version_flag, version);
     return;
   }
   current_alpn_ = validator.ConsumeAlpn();
@@ -1260,15 +1285,15 @@
     QuicSession::RecordConnectionCloseAtServer(
         QUIC_HANDSHAKE_FAILED, ConnectionCloseSource::FROM_SELF);
     ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id, form,
-                                     version);
+                                     version_flag, version);
     return;
   }
 
   // If we were able to make a decision about this CHLO based purely on the
   // information available in OnChlo, just invoke the done callback immediately.
   if (rejector->state() != StatelessRejector::UNKNOWN) {
-    ProcessStatelessRejectorState(std::move(rejector),
-                                  version.transport_version, form);
+    ProcessStatelessRejectorState(
+        std::move(rejector), version.transport_version, form, version_flag);
     return;
   }
 
@@ -1281,7 +1306,8 @@
 
   // Continue stateless rejector processing
   std::unique_ptr<StatelessRejectorProcessDoneCallback> cb(
-      new StatelessRejectorProcessDoneCallback(this, version, form));
+      new StatelessRejectorProcessDoneCallback(this, version, form,
+                                               version_flag));
   StatelessRejector::Process(std::move(rejector), std::move(cb));
 }
 
@@ -1292,7 +1318,8 @@
     const QuicSocketAddress& current_self_address,
     std::unique_ptr<QuicReceivedPacket> current_packet,
     ParsedQuicVersion first_version,
-    PacketHeaderFormat current_packet_format) {
+    PacketHeaderFormat current_packet_format,
+    bool current_version_flag) {
   // Reset current_* to correspond to the packet which initiated the stateless
   // reject logic.
   current_client_address_ = current_client_address;
@@ -1321,13 +1348,14 @@
 
   ProcessStatelessRejectorState(std::move(rejector),
                                 first_version.transport_version,
-                                current_packet_format);
+                                current_packet_format, current_version_flag);
 }
 
 void QuicDispatcher::ProcessStatelessRejectorState(
     std::unique_ptr<StatelessRejector> rejector,
     QuicTransportVersion first_version,
-    PacketHeaderFormat form) {
+    PacketHeaderFormat form,
+    bool version_flag) {
   QuicPacketFate fate;
   switch (rejector->state()) {
     case StatelessRejector::FAILED: {
@@ -1377,7 +1405,7 @@
       break;
   }
   ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id(), form,
-                                   rejector->version());
+                                   version_flag, rejector->version());
 }
 
 const QuicTransportVersionVector&
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h
index a6d7e37..af268f9 100644
--- a/quic/core/quic_dispatcher.h
+++ b/quic/core/quic_dispatcher.h
@@ -339,6 +339,7 @@
   void StatelesslyTerminateConnection(
       QuicConnectionId connection_id,
       PacketHeaderFormat format,
+      bool version_flag,
       ParsedQuicVersion version,
       QuicErrorCode error_code,
       const std::string& error_details,
@@ -380,6 +381,7 @@
   // packets, like ValidityChecks, and invokes ProcessUnauthenticatedHeaderFate.
   void MaybeRejectStatelessly(QuicConnectionId connection_id,
                               PacketHeaderFormat form,
+                              bool version_flag,
                               ParsedQuicVersion version);
 
   // Deliver |packets| to |session| for further processing.
@@ -392,6 +394,7 @@
   void ProcessUnauthenticatedHeaderFate(QuicPacketFate fate,
                                         QuicConnectionId connection_id,
                                         PacketHeaderFormat form,
+                                        bool version_flag,
                                         ParsedQuicVersion version);
 
   // Invoked when StatelessRejector::Process completes. |first_version| is the
@@ -407,14 +410,16 @@
       const QuicSocketAddress& current_self_address,
       std::unique_ptr<QuicReceivedPacket> current_packet,
       ParsedQuicVersion first_version,
-      PacketHeaderFormat current_packet_format);
+      PacketHeaderFormat current_packet_format,
+      bool current_version_flag);
 
   // Examine the state of the rejector and decide what to do with the current
   // packet.
   void ProcessStatelessRejectorState(
       std::unique_ptr<StatelessRejector> rejector,
       QuicTransportVersion first_version,
-      PacketHeaderFormat form);
+      PacketHeaderFormat form,
+      bool version_flag);
 
   // If the connection ID length is different from what the dispatcher expects,
   // replace the connection ID with a random one of the right length,