Enforce strict amplification limit:
1) throttle sending if next created packet + bytes_sent >= factor * bytes_received,
2) buffer coalesced packet if size + bytes_sent >= factor * bytes_received.

Protected by FLAGS_quic_strict_amplification_factor.

PiperOrigin-RevId: 458577060
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 0fea5c6..13cf40f 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -1709,7 +1709,8 @@
 
 TEST_P(QuicConnectionTest, PeerIpAddressChangeAtServer) {
   set_perspective(Perspective::IS_SERVER);
-  if (!connection_.validate_client_address()) {
+  if (!connection_.validate_client_address() ||
+      GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
     return;
   }
   QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
@@ -1905,6 +1906,9 @@
 
   QuicFrames frames2;
   frames2.push_back(QuicFrame(frame2_));
+  if (GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
+    frames2.push_back(QuicFrame(QuicPaddingFrame(-1)));
+  }
   ProcessFramesPacketWithAddresses(frames2, kSelfAddress, kNewPeerAddress,
                                    ENCRYPTION_FORWARD_SECURE);
   EXPECT_EQ(kNewPeerAddress, connection_.peer_address());
@@ -1926,6 +1930,9 @@
 }
 
 TEST_P(QuicConnectionTest, EffectivePeerAddressChangeAtServer) {
+  if (GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
+    return;
+  }
   set_perspective(Perspective::IS_SERVER);
   QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
   EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective());
@@ -2102,7 +2109,8 @@
 TEST_P(QuicConnectionTest,
        ReversePathValidationResponseReceivedFromUnexpectedPeerAddress) {
   set_perspective(Perspective::IS_SERVER);
-  if (!connection_.connection_migration_use_new_cid()) {
+  if (!connection_.connection_migration_use_new_cid() ||
+      GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
     return;
   }
   QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
@@ -7612,6 +7620,7 @@
 TEST_P(QuicConnectionTest, ServerReceivesChloOnNonCryptoStream) {
   set_perspective(Perspective::IS_SERVER);
   QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+  QuicConnectionPeer::SetAddressValidated(&connection_);
 
   CryptoHandshakeMessage message;
   CryptoFramer framer;
@@ -7838,6 +7847,9 @@
     return;
   }
   set_perspective(Perspective::IS_SERVER);
+  // Receives packet 1000 in initial data.
+  EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1);
+  ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL);
 
   if (version().handshake_protocol == PROTOCOL_TLS1_3) {
     EXPECT_CALL(visitor_, BeforeConnectionCloseSent());
@@ -9544,7 +9556,8 @@
 }
 
 TEST_P(QuicConnectionTest, AntiAmplificationLimit) {
-  if (!connection_.version().SupportsAntiAmplificationLimit()) {
+  if (!connection_.version().SupportsAntiAmplificationLimit() ||
+      GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
     return;
   }
   EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
@@ -9600,7 +9613,8 @@
 }
 
 TEST_P(QuicConnectionTest, 3AntiAmplificationLimit) {
-  if (!connection_.version().SupportsAntiAmplificationLimit()) {
+  if (!connection_.version().SupportsAntiAmplificationLimit() ||
+      GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
     return;
   }
   EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
@@ -9668,7 +9682,8 @@
 }
 
 TEST_P(QuicConnectionTest, 10AntiAmplificationLimit) {
-  if (!connection_.version().SupportsAntiAmplificationLimit()) {
+  if (!connection_.version().SupportsAntiAmplificationLimit() ||
+      GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
     return;
   }
   EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
@@ -9873,7 +9888,8 @@
 TEST_P(QuicConnectionTest, FailToCoalescePacket) {
   // EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
   if (!IsDefaultTestConfiguration() ||
-      !connection_.version().CanSendCoalescedPackets()) {
+      !connection_.version().CanSendCoalescedPackets() ||
+      GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
     return;
   }
 
@@ -11919,6 +11935,7 @@
   frames.push_back(QuicFrame(frame1_));
   QuicPathFrameBuffer path_frame_buffer{0, 1, 2, 3, 4, 5, 6, 7};
   frames.push_back(QuicFrame(QuicPathChallengeFrame(0, path_frame_buffer)));
+  frames.push_back(QuicFrame(QuicPaddingFrame(-1)));
   const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback4(),
                                           /*port=*/23456);
 
@@ -14500,7 +14517,8 @@
 // Regression test for b/182571515
 TEST_P(QuicConnectionTest, LostDataThenGetAcknowledged) {
   set_perspective(Perspective::IS_SERVER);
-  if (!connection_.validate_client_address()) {
+  if (!connection_.validate_client_address() ||
+      GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
     return;
   }
 
@@ -14923,7 +14941,8 @@
 
 // Regression test for b/201643321.
 TEST_P(QuicConnectionTest, FailedToRetransmitShlo) {
-  if (!version().HasIetfQuicFrames()) {
+  if (!version().HasIetfQuicFrames() ||
+      GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
     return;
   }
   set_perspective(Perspective::IS_SERVER);
@@ -15485,7 +15504,8 @@
   QuicConnectionPeer::SendPing(&connection_);
   const QuicConnectionStats& stats = connection_.GetStats();
   if (GetQuicReloadableFlag(
-          quic_fix_bytes_accounting_for_buffered_coalesced_packets)) {
+          quic_fix_bytes_accounting_for_buffered_coalesced_packets) ||
+      GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
     // Verify padding is accounted.
     EXPECT_EQ(stats.bytes_sent, connection_.max_packet_length());
   } else {
@@ -15493,6 +15513,80 @@
   }
 }
 
+TEST_P(QuicConnectionTest, StrictAntiAmplificationLimit) {
+  if (!connection_.version().SupportsAntiAmplificationLimit()) {
+    return;
+  }
+  EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(AnyNumber());
+  set_perspective(Perspective::IS_SERVER);
+  use_tagging_decrypter();
+  connection_.SetEncrypter(ENCRYPTION_INITIAL,
+                           std::make_unique<TaggingEncrypter>(0x01));
+  connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
+  // Verify no data can be sent at the beginning because bytes received is 0.
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+  connection_.SendCryptoDataWithString("foo", 0);
+  EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA));
+  EXPECT_FALSE(connection_.CanWrite(NO_RETRANSMITTABLE_DATA));
+  EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+  const size_t anti_amplification_factor =
+      GetQuicFlag(FLAGS_quic_anti_amplification_factor);
+  // Receives packet 1.
+  EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+      .Times(anti_amplification_factor);
+  ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL);
+  connection_.SetEncrypter(ENCRYPTION_HANDSHAKE,
+                           std::make_unique<TaggingEncrypter>(0x02));
+  connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE,
+                           std::make_unique<TaggingEncrypter>(0x03));
+
+  for (size_t i = 1; i < anti_amplification_factor - 1; ++i) {
+    connection_.SendCryptoDataWithString("foo", i * 3);
+  }
+  // Send an addtion packet with max_packet_size - 1.
+  connection_.SetMaxPacketLength(connection_.max_packet_length() - 1);
+  connection_.SendCryptoDataWithString("bar",
+                                       (anti_amplification_factor - 1) * 3);
+  EXPECT_LT(writer_->total_bytes_written(),
+            anti_amplification_factor *
+                QuicConnectionPeer::BytesReceivedOnDefaultPath(&connection_));
+  if (GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
+    // 3 connection closes which will be buffered.
+    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(3);
+    // Verify retransmission alarm is not set.
+    EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+  } else {
+    // Crypto + 3 connection closes.
+    EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(4);
+    EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+  }
+  // Try to send another packet with max_packet_size.
+  connection_.SetMaxPacketLength(connection_.max_packet_length() + 1);
+  connection_.SendCryptoDataWithString("bar", anti_amplification_factor * 3);
+  EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+  // Close connection.
+  EXPECT_CALL(visitor_, BeforeConnectionCloseSent());
+  EXPECT_CALL(visitor_, OnConnectionClosed(_, _));
+  connection_.CloseConnection(
+      QUIC_INTERNAL_ERROR, "error",
+      ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+  EXPECT_EQ(0u, connection_.NumQueuedPackets());
+  if (GetQuicFlag(FLAGS_quic_enforce_strict_amplification_factor)) {
+    EXPECT_LT(writer_->total_bytes_written(),
+              anti_amplification_factor *
+                  QuicConnectionPeer::BytesReceivedOnDefaultPath(&connection_));
+  } else {
+    EXPECT_LT(writer_->total_bytes_written(),
+              (anti_amplification_factor + 2) *
+                  QuicConnectionPeer::BytesReceivedOnDefaultPath(&connection_));
+    EXPECT_GT(writer_->total_bytes_written(),
+              (anti_amplification_factor + 1) *
+                  QuicConnectionPeer::BytesReceivedOnDefaultPath(&connection_));
+  }
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic