Add connection option kRVCM to enable reverse path validation upon new client address on server side.

Replace gfe2_reloadable_flag_quic_server_reverse_validate_new_path2 with gfe2_reloadable_flag_quic_server_reverse_validate_new_path3.

IETF QUIC server will validate new client address if kRVCM is present AND all path validation flags are true.

Protected by FLAGS_quic_reloadable_flag_quic_server_reverse_validate_new_path3.

PiperOrigin-RevId: 365133871
Change-Id: I86f40688c2e34995a5738b3f174f5f3014f54337
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index 99f5372..e08d90b 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -267,6 +267,9 @@
 
 const QuicTag kELDT = TAG('E', 'L', 'D', 'T');   // Enable Loss Detection Tuning
 
+const QuicTag kRVCM = TAG('R', 'V', 'C', 'M');   // Validate the new address
+                                                 // upon client address change.
+
 // Optional support of truncated Connection IDs.  If sent by a peer, the value
 // is the minimum number of bytes allowed for the connection ID sent to the
 // peer.
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc
index 585aab7..48ed82d 100644
--- a/quic/core/http/end_to_end_test.cc
+++ b/quic/core/http/end_to_end_test.cc
@@ -376,6 +376,7 @@
       copt.push_back(kILD0);
     }
     copt.push_back(kPLE1);
+    copt.push_back(kRVCM);
     client_config_.SetConnectionOptionsToSend(copt);
 
     // Start the server first, because CreateQuicClient() attempts
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 8510737..c53ceea 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -371,11 +371,7 @@
           GetQuicReloadableFlag(quic_use_encryption_level_context)),
       path_validator_(alarm_factory_, &arena_, this, random_generator_),
       alternative_path_(QuicSocketAddress(), QuicSocketAddress()),
-      most_recent_frame_type_(NUM_FRAME_TYPES),
-      validate_client_addresses_(
-          framer_.version().HasIetfQuicFrames() && use_path_validator_ &&
-          count_bytes_on_alternative_path_separately_ &&
-          GetQuicReloadableFlag(quic_server_reverse_validate_new_path2)) {
+      most_recent_frame_type_(NUM_FRAME_TYPES) {
   QUIC_BUG_IF(quic_bug_12714_1,
               !start_peer_migration_earlier_ && send_path_response_);
 
@@ -701,6 +697,13 @@
   if (config.HasClientSentConnectionOption(kDFER, perspective_)) {
     defer_send_in_response_to_packets_ = false;
   }
+  if (framer_.version().HasIetfQuicFrames() && use_path_validator_ &&
+      count_bytes_on_alternative_path_separately_ &&
+      GetQuicReloadableFlag(quic_server_reverse_validate_new_path3) &&
+      config.HasClientSentConnectionOption(kRVCM, perspective_)) {
+    QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 6, 6);
+    validate_client_addresses_ = true;
+  }
   if (config.HasReceivedMaxPacketSize()) {
     peer_max_packet_size_ = config.ReceivedMaxPacketSize();
     MaybeUpdatePacketCreatorMaxPacketLengthAndPadding();
@@ -1674,7 +1677,7 @@
   if (!validate_client_addresses_) {
     return OnPathChallengeFrameInternal(frame);
   }
-  QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path2, 1, 5);
+  QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 1, 6);
   {
     // UpdatePacketStateAndReplyPathChallenge() may start reverse path
     // validation, if so bundle the PATH_CHALLENGE together with the
@@ -4968,7 +4971,7 @@
   if (!validate_client_addresses_) {
     return;
   }
-  QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path2, 2, 5);
+  QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 2, 6);
   if (debug_visitor_ != nullptr) {
     const QuicTime now = clock_->ApproximateNow();
     if (now >= stats_.handshake_completion_time) {
@@ -4998,11 +5001,12 @@
           << "EffectivePeerMigration started without address change.";
       return;
     }
-    QUIC_DLOG(INFO) << ENDPOINT << "Effective peer's ip:port changed from "
-                    << default_path_.peer_address.ToString() << " to "
-                    << GetEffectivePeerAddressFromCurrentPacket().ToString()
-                    << ", address change type is " << type
-                    << ", migrating connection.";
+    QUIC_DLOG(INFO)
+        << ENDPOINT << "Effective peer's ip:port changed from "
+        << default_path_.peer_address.ToString() << " to "
+        << GetEffectivePeerAddressFromCurrentPacket().ToString()
+        << ", address change type is " << type
+        << ", migrating connection without validating new client address.";
 
     highest_packet_sent_before_effective_peer_migration_ =
         sent_packet_manager_.GetLargestSentPacket();
@@ -5013,7 +5017,7 @@
     return;
   }
 
-  QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path2, 3, 5);
+  QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 3, 6);
   if (type == NO_CHANGE) {
     UpdatePeerAddress(last_packet_source_address_);
     QUIC_BUG(quic_bug_10511_36)
@@ -5293,7 +5297,7 @@
         alternative_path_ = PathState(last_packet_destination_address_,
                                       current_effective_peer_address);
       } else if (!default_path_.validated) {
-        QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path2, 4, 5);
+        QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 4, 6);
         // Skip reverse path validation because either handshake hasn't
         // completed or the connection is validating the default path. Using
         // PATH_CHALLENGE to validate alternative client address before
@@ -5307,7 +5311,7 @@
                     IsHandshakeConfirmed() && !alternative_path_.validated)
             << "No validated peer address to send after handshake comfirmed.";
       } else if (!IsReceivedPeerAddressValidated()) {
-        QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path2, 5, 5);
+        QUIC_CODE_COUNT_N(quic_server_reverse_validate_new_path3, 5, 6);
         // Only override alternative path state upon receiving a PATH_CHALLENGE
         // from an unvalidated peer address, and the connection isn't validating
         // a recent peer migration.
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index a6dc7f5..2c70c04 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -2157,7 +2157,7 @@
       GetQuicReloadableFlag(quic_count_bytes_on_alternative_path_seperately);
 
   // If true, upon seeing a new client address, validate the client address.
-  const bool validate_client_addresses_;
+  bool validate_client_addresses_ = false;
 
   bool support_multiple_connection_ids_ = false;
 };
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 6b34ece..efeb53b 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -1322,6 +1322,13 @@
   void set_perspective(Perspective perspective) {
     connection_.set_perspective(perspective);
     if (perspective == Perspective::IS_SERVER) {
+      QuicConfig config;
+      QuicTagVector connection_options;
+      connection_options.push_back(kRVCM);
+      config.SetInitialReceivedConnectionOptions(connection_options);
+      EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+      connection_.SetFromConfig(config);
+
       connection_.set_can_truncate_connection_ids(true);
       QuicConnectionPeer::SetNegotiatedVersion(&connection_);
       connection_.OnSuccessfulVersionNegotiation();
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h
index 1ba0aa9..44e3e56 100644
--- a/quic/core/quic_flags_list.h
+++ b/quic/core/quic_flags_list.h
@@ -56,7 +56,7 @@
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_path_response2, true)
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_timestamps, false)
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_send_tls_crypto_error_code, true)
-QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_server_reverse_validate_new_path2, false)
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_server_reverse_validate_new_path3, false)
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_single_ack_in_packet2, false)
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_start_peer_migration_earlier, true)
 QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_stateless_reset_faster_random, true)