gfe-relnote: Remove stateless reject from QUIC. This deprecates two flags in the false position: --gfe2_reloadable_flag_enable_quic_stateless_reject_support and --gfe2_reloadable_flag_quic_use_cheap_stateless_rejects.
PiperOrigin-RevId: 250347964
Change-Id: I50e150f91e76b672160eadc04a379b529a4f602d
diff --git a/quic/core/crypto/crypto_handshake_message.cc b/quic/core/crypto/crypto_handshake_message.cc
index 579bb37..457d0fb 100644
--- a/quic/core/crypto/crypto_handshake_message.cc
+++ b/quic/core/crypto/crypto_handshake_message.cc
@@ -286,16 +286,6 @@
done = true;
}
break;
- case kRCID:
- // uint64_t value
- if (it->second.size() == 8) {
- uint64_t value;
- memcpy(&value, it->second.data(), sizeof(value));
- value = QuicEndian::NetToHost64(value);
- ret += QuicTextUtils::Uint64ToString(value);
- done = true;
- }
- break;
case kTBKP:
case kKEXS:
case kAEAD:
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index e8c8d84..e63224a 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -27,14 +27,13 @@
typedef std::string ServerConfigID;
// The following tags have been deprecated and should not be reused:
-// "BBQ4"
+// "BBQ4", "RCID", "SREJ"
// clang-format off
const QuicTag kCHLO = TAG('C', 'H', 'L', 'O'); // Client hello
const QuicTag kSHLO = TAG('S', 'H', 'L', 'O'); // Server hello
const QuicTag kSCFG = TAG('S', 'C', 'F', 'G'); // Server config
const QuicTag kREJ = TAG('R', 'E', 'J', '\0'); // Reject
-const QuicTag kSREJ = TAG('S', 'R', 'E', 'J'); // Stateless reject
const QuicTag kCETV = TAG('C', 'E', 'T', 'V'); // Client encrypted tag-value
// pairs
const QuicTag kPRST = TAG('P', 'R', 'S', 'T'); // Public reset
@@ -245,9 +244,7 @@
// Rejection tags
const QuicTag kRREJ = TAG('R', 'R', 'E', 'J'); // Reasons for server sending
-// Stateless Reject tags
-const QuicTag kRCID = TAG('R', 'C', 'I', 'D'); // Server-designated
- // connection ID
+
// Server hello tags
const QuicTag kCADR = TAG('C', 'A', 'D', 'R'); // Client IP address and port
const QuicTag kASAD = TAG('A', 'S', 'A', 'D'); // Alternate Server IP address
diff --git a/quic/core/crypto/crypto_server_test.cc b/quic/core/crypto/crypto_server_test.cc
index 5d86dcb..306a28b 100644
--- a/quic/core/crypto/crypto_server_test.cc
+++ b/quic/core/crypto/crypto_server_test.cc
@@ -148,14 +148,6 @@
SERVER_CONFIG_INCHOATE_HELLO_FAILURE};
CheckRejectReasons(kRejectReasons, QUIC_ARRAYSIZE(kRejectReasons));
- // TODO(wub): Delete this block when deprecating RCID.
- {
- uint64_t server_designated_connection_id;
- EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND,
- out_.GetUint64(kRCID, &server_designated_connection_id));
- rand_for_id_generation_.ChangeValue();
- }
-
QuicStringPiece srct;
ASSERT_TRUE(out_.GetStringPiece(kSourceAddressTokenTag, &srct));
srct_hex_ = "#" + QuicTextUtils::HexEncode(srct);
diff --git a/quic/core/crypto/quic_crypto_client_config.cc b/quic/core/crypto/quic_crypto_client_config.cc
index d216f66..4fca4bb 100644
--- a/quic/core/crypto/quic_crypto_client_config.cc
+++ b/quic/core/crypto/quic_crypto_client_config.cc
@@ -761,8 +761,8 @@
std::string* error_details) {
DCHECK(error_details != nullptr);
- if ((rej.tag() != kREJ) && (rej.tag() != kSREJ)) {
- *error_details = "Message is not REJ or SREJ";
+ if (rej.tag() != kREJ) {
+ *error_details = "Message is not REJ";
return QUIC_CRYPTO_INTERNAL_ERROR;
}
@@ -778,30 +778,6 @@
out_params->server_nonce = std::string(nonce);
}
- if (rej.tag() == kSREJ) {
- QuicConnectionId connection_id;
-
- QuicStringPiece connection_id_bytes;
- if (!rej.GetStringPiece(kRCID, &connection_id_bytes)) {
- *error_details = "Missing kRCID";
- return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
- }
- connection_id = QuicConnectionId(connection_id_bytes.data(),
- connection_id_bytes.length());
- if (!QuicUtils::IsConnectionIdValidForVersion(connection_id, version)) {
- QUIC_PEER_BUG << "Received server-designated connection ID "
- << connection_id << " which is invalid with version "
- << QuicVersionToString(version);
- *error_details = "Bad kRCID length";
- return QUIC_CRYPTO_INTERNAL_ERROR;
- }
- cached->add_server_designated_connection_id(connection_id);
- if (!nonce.empty()) {
- cached->add_server_nonce(std::string(nonce));
- }
- return QUIC_NO_ERROR;
- }
-
return QUIC_NO_ERROR;
}
diff --git a/quic/core/crypto/quic_crypto_server_config.cc b/quic/core/crypto/quic_crypto_server_config.cc
index 404a29e..54d4bf4 100644
--- a/quic/core/crypto/quic_crypto_server_config.cc
+++ b/quic/core/crypto/quic_crypto_server_config.cc
@@ -1437,28 +1437,8 @@
const std::vector<uint32_t>& reject_reasons,
CryptoHandshakeMessage* out) const {
const QuicWallTime now = context.clock()->WallNow();
- if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) &&
- context.use_stateless_rejects()) {
- QUIC_DVLOG(1) << "QUIC Crypto server config returning stateless reject "
- << "with server-designated connection ID "
- << context.server_designated_connection_id();
- out->set_tag(kSREJ);
- if (!QuicUtils::IsConnectionIdValidForVersion(
- context.server_designated_connection_id(),
- context.transport_version())) {
- QUIC_BUG << "Tried to send server designated connection ID "
- << context.server_designated_connection_id()
- << " which is invalid with version "
- << QuicVersionToString(context.transport_version());
- return;
- }
- out->SetStringPiece(
- kRCID,
- QuicStringPiece(context.server_designated_connection_id().data(),
- context.server_designated_connection_id().length()));
- } else {
- out->set_tag(kREJ);
- }
+
+ out->set_tag(kREJ);
out->SetStringPiece(kSCFG, config.serialized);
out->SetStringPiece(
kSourceAddressTokenTag,
diff --git a/quic/core/crypto/quic_crypto_server_config.h b/quic/core/crypto/quic_crypto_server_config.h
index 9f3a7bc..039da84 100644
--- a/quic/core/crypto/quic_crypto_server_config.h
+++ b/quic/core/crypto/quic_crypto_server_config.h
@@ -338,6 +338,8 @@
const QuicSocketAddress& client_address,
ParsedQuicVersion version,
const ParsedQuicVersionVector& supported_versions,
+ // TODO(wub): Deprecate use_stateless_rejects and
+ // server_designated_connection_id.
bool use_stateless_rejects,
QuicConnectionId server_designated_connection_id,
const QuicClock* clock,
diff --git a/quic/core/quic_crypto_client_handshaker.cc b/quic/core/quic_crypto_client_handshaker.cc
index b0c26be..bf432ff 100644
--- a/quic/core/quic_crypto_client_handshaker.cc
+++ b/quic/core/quic_crypto_client_handshaker.cc
@@ -65,7 +65,6 @@
proof_verify_callback_(nullptr),
proof_handler_(proof_handler),
verify_ok_(false),
- stateless_reject_received_(false),
proof_verify_start_time_(QuicTime::Zero()),
num_scup_messages_received_(0),
encryption_established_(false),
@@ -232,20 +231,6 @@
void QuicCryptoClientHandshaker::DoSendCHLO(
QuicCryptoClientConfig::CachedState* cached) {
- if (stateless_reject_received_) {
- // If we've gotten to this point, we've sent at least one hello
- // and received a stateless reject in response. We cannot
- // continue to send hellos because the server has abandoned state
- // for this connection. Abandon further handshakes.
- next_state_ = STATE_NONE;
- if (session()->connection()->connected()) {
- session()->connection()->CloseConnection(
- QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject received",
- ConnectionCloseBehavior::SILENT_CLOSE);
- }
- return;
- }
-
// Send the client hello in plaintext.
session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL);
encryption_established_ = false;
@@ -295,15 +280,6 @@
return;
}
- // If the server nonce is empty, copy over the server nonce from a previous
- // SREJ, if there is one.
- if (GetQuicReloadableFlag(enable_quic_stateless_reject_support) &&
- crypto_negotiated_params_->server_nonce.empty() &&
- cached->has_server_nonce()) {
- crypto_negotiated_params_->server_nonce = cached->GetNextServerNonce();
- DCHECK(!crypto_negotiated_params_->server_nonce.empty());
- }
-
std::string error_details;
QuicErrorCode error = crypto_config_->FillClientHello(
server_id_, session()->connection()->connection_id(),
@@ -358,7 +334,7 @@
// perform a handshake, or we sent a full hello that the server
// rejected. Here we hope to have a REJ that contains the information
// that we need.
- if ((in->tag() != kREJ) && (in->tag() != kSREJ)) {
+ if (in->tag() != kREJ) {
next_state_ = STATE_NONE;
stream_->CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
"Expected REJ");
@@ -391,7 +367,6 @@
// so we can cancel and retransmissions.
session()->NeuterUnencryptedData();
- stateless_reject_received_ = in->tag() == kSREJ;
std::string error_details;
QuicErrorCode error = crypto_config_->ProcessRejection(
*in, session()->connection()->clock()->WallNow(),
@@ -500,7 +475,7 @@
// hoping for a SHLO from the server to confirm that. First check
// to see whether the response was a reject, and if so, move on to
// the reject-processing state.
- if ((in->tag() == kREJ) || (in->tag() == kSREJ)) {
+ if (in->tag() == kREJ) {
// A reject message must be sent in ENCRYPTION_INITIAL.
if (session()->connection()->last_decrypted_level() != ENCRYPTION_INITIAL) {
// The rejection was sent encrypted!
diff --git a/quic/core/quic_crypto_client_handshaker.h b/quic/core/quic_crypto_client_handshaker.h
index 023905b..5b7ce35 100644
--- a/quic/core/quic_crypto_client_handshaker.h
+++ b/quic/core/quic_crypto_client_handshaker.h
@@ -164,11 +164,6 @@
std::string verify_error_details_;
std::unique_ptr<ProofVerifyDetails> verify_details_;
- // True if the server responded to a previous CHLO with a stateless
- // reject. Used for book-keeping between the STATE_RECV_REJ,
- // STATE_VERIFY_PROOF*, and subsequent STATE_SEND_CHLO state.
- bool stateless_reject_received_;
-
QuicTime proof_verify_start_time_;
int num_scup_messages_received_;
diff --git a/quic/core/quic_crypto_server_handshaker.cc b/quic/core/quic_crypto_server_handshaker.cc
index 025e391..f345a14 100644
--- a/quic/core/quic_crypto_server_handshaker.cc
+++ b/quic/core/quic_crypto_server_handshaker.cc
@@ -169,27 +169,9 @@
}
if (reply->tag() != kSHLO) {
- if (reply->tag() == kSREJ) {
- DCHECK(false) << "Unexpected SREJ reply.";
- // Before sending the SREJ, cause the connection to save crypto packets
- // so that they can be added to the time wait list manager and
- // retransmitted.
- session()->connection()->EnableSavingCryptoPackets();
- }
session()->connection()->set_fully_pad_crypto_hadshake_packets(
crypto_config_->pad_rej());
SendHandshakeMessage(*reply);
-
- if (reply->tag() == kSREJ) {
- DCHECK(false) << "Unexpected SREJ reply.";
- DCHECK(!handshake_confirmed());
- QUIC_DLOG(INFO) << "Closing connection "
- << session()->connection()->connection_id()
- << " because of a stateless reject.";
- session()->connection()->CloseConnection(
- QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject",
- ConnectionCloseBehavior::SILENT_CLOSE);
- }
return;
}
diff --git a/quic/core/quic_crypto_server_stream.cc b/quic/core/quic_crypto_server_stream.cc
index e8937a0..a6486d8 100644
--- a/quic/core/quic_crypto_server_stream.cc
+++ b/quic/core/quic_crypto_server_stream.cc
@@ -28,24 +28,6 @@
QuicCryptoServerStreamBase::QuicCryptoServerStreamBase(QuicSession* session)
: QuicCryptoStream(session) {}
-// TODO(jokulik): Once stateless rejects support is inherent in the version
-// number, this function will likely go away entirely.
-// static
-bool QuicCryptoServerStreamBase::DoesPeerSupportStatelessRejects(
- const CryptoHandshakeMessage& message) {
- QuicTagVector received_tags;
- QuicErrorCode error = message.GetTaglist(kCOPT, &received_tags);
- if (error != QUIC_NO_ERROR) {
- return false;
- }
- for (const QuicTag tag : received_tags) {
- if (tag == kSREJ) {
- return true;
- }
- }
- return false;
-}
-
QuicCryptoServerStream::QuicCryptoServerStream(
const QuicCryptoServerConfig* crypto_config,
QuicCompressedCertsCache* compressed_certs_cache,
diff --git a/quic/core/quic_crypto_server_stream.h b/quic/core/quic_crypto_server_stream.h
index 9edd2ea..71ce297 100644
--- a/quic/core/quic_crypto_server_stream.h
+++ b/quic/core/quic_crypto_server_stream.h
@@ -56,11 +56,6 @@
const = 0;
virtual void SetPreviousCachedNetworkParams(
CachedNetworkParameters cached_network_params) = 0;
-
- // Checks the options on the handshake-message to see whether the
- // peer supports stateless-rejects.
- static bool DoesPeerSupportStatelessRejects(
- const CryptoHandshakeMessage& message);
};
class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc
index 609c6b6..796b2dc 100644
--- a/quic/core/quic_dispatcher.cc
+++ b/quic/core/quic_dispatcher.cc
@@ -14,7 +14,6 @@
#include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/stateless_rejector.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
@@ -229,55 +228,6 @@
std::string alpn_;
};
-// Class which sits between the ChloExtractor and the StatelessRejector
-// to give the QuicDispatcher a chance to apply policy checks to the CHLO.
-class ChloValidator : public ChloAlpnExtractor {
- public:
- ChloValidator(QuicCryptoServerStream::Helper* helper,
- const QuicSocketAddress& client_address,
- const QuicSocketAddress& peer_address,
- const QuicSocketAddress& self_address,
- StatelessRejector* rejector)
- : helper_(helper),
- client_address_(client_address),
- peer_address_(peer_address),
- self_address_(self_address),
- rejector_(rejector),
- can_accept_(false),
- error_details_("CHLO not processed") {}
-
- // ChloExtractor::Delegate implementation.
- void OnChlo(QuicTransportVersion version,
- QuicConnectionId server_connection_id,
- const CryptoHandshakeMessage& chlo) override {
- // Extract the ALPN
- ChloAlpnExtractor::OnChlo(version, server_connection_id, chlo);
- if (helper_->CanAcceptClientHello(chlo, client_address_, peer_address_,
- self_address_, &error_details_)) {
- can_accept_ = true;
- rejector_->OnChlo(
- version, server_connection_id,
- helper_->GenerateConnectionIdForReject(version, server_connection_id),
- chlo);
- }
- }
-
- bool can_accept() const { return can_accept_; }
-
- const std::string& error_details() const { return error_details_; }
-
- private:
- QuicCryptoServerStream::Helper* helper_; // Unowned.
- // client_address_ and peer_address_ could be different values for proxy
- // connections.
- QuicSocketAddress client_address_;
- QuicSocketAddress peer_address_;
- QuicSocketAddress self_address_;
- StatelessRejector* rejector_; // Unowned.
- bool can_accept_;
- std::string error_details_;
-};
-
} // namespace
QuicDispatcher::QuicDispatcher(
@@ -551,10 +501,8 @@
// Packet's connection ID is unknown. Apply the validity checks.
QuicPacketFate fate = ValidityChecks(header);
if (fate == kFateProcess) {
- // Execute stateless rejection logic to determine the packet fate, then
- // invoke ProcessUnauthenticatedHeaderFate.
- MaybeRejectStatelessly(server_connection_id, header.form,
- header.version_flag, header.version);
+ ProcessOrBufferPacket(server_connection_id, header.form,
+ header.version_flag, header.version);
} else {
// If the fate is already known, process it without executing stateless
// rejection logic.
@@ -575,21 +523,16 @@
break;
}
case kFateTimeWait:
- // MaybeRejectStatelessly or OnExpiredPackets might have already added the
- // connection to time wait, in which case it should not be added again.
- if (!GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) ||
- !time_wait_list_manager_->IsConnectionIdInTimeWait(
- server_connection_id)) {
- // Add this connection_id to the time-wait state, to safely reject
- // future packets.
- QUIC_DLOG(INFO) << "Adding connection ID " << server_connection_id
- << " to time-wait list.";
- QUIC_CODE_COUNT(quic_reject_fate_time_wait);
- StatelesslyTerminateConnection(
- server_connection_id, form, version_flag, version,
- QUIC_HANDSHAKE_FAILED, "Reject connection",
- quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
- }
+ // Add this connection_id to the time-wait state, to safely reject
+ // future packets.
+ QUIC_DLOG(INFO) << "Adding connection ID " << server_connection_id
+ << " to time-wait list.";
+ QUIC_CODE_COUNT(quic_reject_fate_time_wait);
+ StatelesslyTerminateConnection(
+ server_connection_id, form, version_flag, version,
+ QUIC_HANDSHAKE_FAILED, "Reject connection",
+ quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
+
DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
server_connection_id));
time_wait_list_manager_->ProcessPacket(
@@ -1167,10 +1110,6 @@
<< server_connection_id << " because of " << result;
}
-bool QuicDispatcher::ShouldAttemptCheapStatelessRejection() {
- return true;
-}
-
QuicTimeWaitListManager* QuicDispatcher::CreateQuicTimeWaitListManager() {
return new QuicTimeWaitListManager(writer_.get(), this, helper_->GetClock(),
alarm_factory_.get());
@@ -1274,49 +1213,7 @@
return true;
}
-class StatelessRejectorProcessDoneCallback
- : public StatelessRejector::ProcessDoneCallback {
- public:
- StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher,
- ParsedQuicVersion first_version,
- PacketHeaderFormat form,
- bool version_flag)
- : dispatcher_(dispatcher),
- current_client_address_(dispatcher->current_client_address_),
- current_peer_address_(dispatcher->current_peer_address_),
- current_self_address_(dispatcher->current_self_address_),
- additional_context_(dispatcher->GetPerPacketContext()),
- current_packet_(
- dispatcher->current_packet_->Clone()), // Note: copies the packet
- first_version_(first_version),
- current_packet_format_(form),
- current_version_flag_(version_flag) {}
-
- void Run(std::unique_ptr<StatelessRejector> rejector) override {
- if (additional_context_ != nullptr) {
- dispatcher_->RestorePerPacketContext(std::move(additional_context_));
- }
- dispatcher_->OnStatelessRejectorProcessDone(
- std::move(rejector), current_client_address_, current_peer_address_,
- current_self_address_, std::move(current_packet_), first_version_,
- current_packet_format_, current_version_flag_);
- }
-
- private:
- QuicDispatcher* dispatcher_;
- QuicSocketAddress current_client_address_;
- QuicSocketAddress current_peer_address_;
- QuicSocketAddress current_self_address_;
- // TODO(wub): Wrap all current_* variables into PerPacketContext. And rename
- // |additional_context_| to |context_|.
- std::unique_ptr<QuicPerPacketContext> additional_context_;
- std::unique_ptr<QuicReceivedPacket> current_packet_;
- ParsedQuicVersion first_version_;
- const PacketHeaderFormat current_packet_format_;
- bool current_version_flag_;
-};
-
-void QuicDispatcher::MaybeRejectStatelessly(
+void QuicDispatcher::ProcessOrBufferPacket(
QuicConnectionId server_connection_id,
PacketHeaderFormat form,
bool version_flag,
@@ -1327,179 +1224,20 @@
return;
// TODO(nharper): Support buffering non-ClientHello packets when using TLS.
}
- // TODO(rch): This logic should probably live completely inside the rejector.
- if (!FLAGS_quic_allow_chlo_buffering ||
- !GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) ||
- !GetQuicReloadableFlag(enable_quic_stateless_reject_support) ||
- !ShouldAttemptCheapStatelessRejection()) {
- // Not use cheap stateless reject.
- ChloAlpnExtractor alpn_extractor;
- if (FLAGS_quic_allow_chlo_buffering &&
- !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
- config_->create_session_tag_indicators(),
- &alpn_extractor,
- server_connection_id.length())) {
- // Buffer non-CHLO packets.
- ProcessUnauthenticatedHeaderFate(kFateBuffer, server_connection_id, form,
- version_flag, version);
- return;
- }
- current_alpn_ = alpn_extractor.ConsumeAlpn();
- ProcessUnauthenticatedHeaderFate(kFateProcess, server_connection_id, form,
- version_flag, version);
- return;
- }
- std::unique_ptr<StatelessRejector> rejector(new StatelessRejector(
- version, GetSupportedVersions(), crypto_config_, &compressed_certs_cache_,
- helper()->GetClock(), helper()->GetRandomGenerator(),
- current_packet_->length(), current_client_address_,
- current_self_address_));
- ChloValidator validator(session_helper_.get(), current_client_address_,
- current_peer_address_, current_self_address_,
- rejector.get());
- if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
+ ChloAlpnExtractor alpn_extractor;
+ if (FLAGS_quic_allow_chlo_buffering &&
+ !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
config_->create_session_tag_indicators(),
- &validator, server_connection_id.length())) {
+ &alpn_extractor, server_connection_id.length())) {
+ // Buffer non-CHLO packets.
ProcessUnauthenticatedHeaderFate(kFateBuffer, server_connection_id, form,
version_flag, version);
return;
}
- current_alpn_ = validator.ConsumeAlpn();
-
- if (!validator.can_accept()) {
- // This CHLO is prohibited by policy.
- QUIC_CODE_COUNT(quic_reject_cant_accept_chlo);
- StatelessConnectionTerminator terminator(
- server_connection_id, version, helper(), time_wait_list_manager_.get());
- terminator.CloseConnection(QUIC_HANDSHAKE_FAILED, validator.error_details(),
- form != GOOGLE_QUIC_PACKET);
- QuicSession::RecordConnectionCloseAtServer(
- QUIC_HANDSHAKE_FAILED, ConnectionCloseSource::FROM_SELF);
- ProcessUnauthenticatedHeaderFate(kFateTimeWait, server_connection_id, form,
- 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, form,
- version_flag);
- return;
- }
-
- // Insert into set of connection IDs to buffer
- const bool ok =
- temporarily_buffered_connections_.insert(server_connection_id).second;
- QUIC_BUG_IF(!ok)
- << "Processing multiple stateless rejections for connection ID "
- << server_connection_id;
-
- // Continue stateless rejector processing
- std::unique_ptr<StatelessRejectorProcessDoneCallback> cb(
- new StatelessRejectorProcessDoneCallback(this, version, form,
- version_flag));
- StatelessRejector::Process(std::move(rejector), std::move(cb));
-}
-
-void QuicDispatcher::OnStatelessRejectorProcessDone(
- std::unique_ptr<StatelessRejector> rejector,
- const QuicSocketAddress& current_client_address,
- const QuicSocketAddress& current_peer_address,
- const QuicSocketAddress& current_self_address,
- std::unique_ptr<QuicReceivedPacket> current_packet,
- ParsedQuicVersion first_version,
- 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;
- current_peer_address_ = current_peer_address;
- current_self_address_ = current_self_address;
- current_packet_ = current_packet.get();
- current_server_connection_id_ = rejector->connection_id();
- if (!no_framer_) {
- framer_.set_version(first_version);
- }
-
- // Stop buffering packets on this connection
- const auto num_erased =
- temporarily_buffered_connections_.erase(rejector->connection_id());
- QUIC_BUG_IF(num_erased != 1) << "Completing stateless rejection logic for "
- "non-buffered connection ID "
- << rejector->connection_id();
-
- // If this connection has gone into time-wait during the async processing,
- // don't proceed.
- if (time_wait_list_manager_->IsConnectionIdInTimeWait(
- rejector->connection_id())) {
- time_wait_list_manager_->ProcessPacket(
- current_self_address, current_peer_address, rejector->connection_id(),
- current_packet_format, GetPerPacketContext());
- return;
- }
-
- ProcessStatelessRejectorState(std::move(rejector), first_version,
- current_packet_format, current_version_flag);
-}
-
-void QuicDispatcher::ProcessStatelessRejectorState(
- std::unique_ptr<StatelessRejector> rejector,
- ParsedQuicVersion first_version,
- PacketHeaderFormat form,
- bool version_flag) {
- QuicPacketFate fate;
- switch (rejector->state()) {
- case StatelessRejector::FAILED: {
- // There was an error processing the client hello.
- QUIC_CODE_COUNT(quic_reject_error_processing_chlo);
- StatelessConnectionTerminator terminator(rejector->connection_id(),
- first_version, helper(),
- time_wait_list_manager_.get());
- terminator.CloseConnection(rejector->error(), rejector->error_details(),
- form != GOOGLE_QUIC_PACKET);
- fate = kFateTimeWait;
- break;
- }
-
- case StatelessRejector::UNSUPPORTED:
- // Cheap stateless rejects are not supported so process the packet.
- fate = kFateProcess;
- break;
-
- case StatelessRejector::ACCEPTED:
- // Contains a valid CHLO, so process the packet and create a connection.
- fate = kFateProcess;
- break;
-
- case StatelessRejector::REJECTED: {
- QUIC_BUG_IF(!no_framer_ && first_version != framer_.version())
- << "SREJ: Client's version: "
- << QuicVersionToString(first_version.transport_version)
- << " is different from current dispatcher framer's version: "
- << QuicVersionToString(framer_.transport_version());
- StatelessConnectionTerminator terminator(rejector->connection_id(),
- first_version, helper(),
- time_wait_list_manager_.get());
- terminator.RejectConnection(
- rejector->reply().GetSerialized().AsStringPiece(),
- form != GOOGLE_QUIC_PACKET);
- QuicSession::RecordConnectionCloseAtServer(
- QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT,
- ConnectionCloseSource::FROM_SELF);
- OnConnectionRejectedStatelessly();
- fate = kFateTimeWait;
- break;
- }
-
- default:
- QUIC_BUG << "Rejector has invalid state " << rejector->state();
- fate = kFateDrop;
- break;
- }
- ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id(), form,
- version_flag, rejector->version());
+ current_alpn_ = alpn_extractor.ConsumeAlpn();
+ ProcessUnauthenticatedHeaderFate(kFateProcess, server_connection_id, form,
+ version_flag, version);
}
const QuicTransportVersionVector&
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h
index 1798a0d..f22505a 100644
--- a/quic/core/quic_dispatcher.h
+++ b/quic/core/quic_dispatcher.h
@@ -23,7 +23,6 @@
#include "net/third_party/quiche/src/quic/core/quic_session.h"
#include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
#include "net/third_party/quiche/src/quic/core/quic_version_manager.h"
-#include "net/third_party/quiche/src/quic/core/stateless_rejector.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
@@ -208,12 +207,6 @@
QuicStringPiece alpn,
const ParsedQuicVersion& version) = 0;
- // Called when a connection is rejected statelessly.
- virtual void OnConnectionRejectedStatelessly() {}
-
- // Returns true if cheap stateless rejection should be attempted.
- virtual bool ShouldAttemptCheapStatelessRejection();
-
// Values to be returned by ValidityChecks() to indicate what should be done
// with a packet. Fates with greater values are considered to be higher
// priority, in that if one validity check indicates a lower-valued fate and
@@ -384,23 +377,21 @@
private:
friend class test::QuicDispatcherPeer;
- friend class StatelessRejectorProcessDoneCallback;
typedef QuicUnorderedSet<QuicConnectionId, QuicConnectionIdHash>
QuicConnectionIdSet;
// Based on an unauthenticated packet header |header|, calls ValidityChecks
- // and then either MaybeRejectStatelessly or ProcessUnauthenticatedHeaderFate.
+ // and then ProcessUnauthenticatedHeaderFate.
void ProcessHeader(const QuicPacketHeader& header);
- // Attempts to reject the connection statelessly, if stateless rejects are
- // possible and if the current packet contains a CHLO message. Determines a
- // fate which describes what subsequent processing should be performed on the
- // packets, like ValidityChecks, and invokes ProcessUnauthenticatedHeaderFate.
- void MaybeRejectStatelessly(QuicConnectionId server_connection_id,
- PacketHeaderFormat form,
- bool version_flag,
- ParsedQuicVersion version);
+ // TODO(wub): Move the body to ProcessHeader, then remove this function.
+ // Determine whether the current packet needs to be processed now or buffered
+ // for later processing, then invokes ProcessUnauthenticatedHeaderFate.
+ void ProcessOrBufferPacket(QuicConnectionId server_connection_id,
+ PacketHeaderFormat form,
+ bool version_flag,
+ ParsedQuicVersion version);
// Deliver |packets| to |session| for further processing.
void DeliverPacketsToSession(
@@ -415,30 +406,6 @@
bool version_flag,
ParsedQuicVersion version);
- // Invoked when StatelessRejector::Process completes. |first_version| is the
- // version of the packet which initiated the stateless reject.
- // WARNING: This function can be called when a async proof returns, i.e. not
- // from a stack traceable to ProcessPacket().
- // TODO(fayang): maybe consider not using callback when there is no crypto
- // involved.
- void OnStatelessRejectorProcessDone(
- std::unique_ptr<StatelessRejector> rejector,
- const QuicSocketAddress& current_client_address,
- const QuicSocketAddress& current_peer_address,
- const QuicSocketAddress& current_self_address,
- std::unique_ptr<QuicReceivedPacket> current_packet,
- ParsedQuicVersion first_version,
- 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,
- ParsedQuicVersion first_version,
- 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,
// and save it to make sure the mapping is persistent.
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc
index de06c52..6fdd130 100644
--- a/quic/core/quic_dispatcher_test.cc
+++ b/quic/core/quic_dispatcher_test.cc
@@ -19,7 +19,6 @@
#include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/stateless_rejector.h"
#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
@@ -1401,56 +1400,14 @@
MarkSession1Deleted();
}
-// Tests that bufferring packets works in stateful reject, expensive stateless
-// reject and cheap stateless reject.
-struct BufferedPacketStoreTestParams {
- BufferedPacketStoreTestParams(bool enable_stateless_rejects_via_flag,
- bool support_cheap_stateless_reject)
- : enable_stateless_rejects_via_flag(enable_stateless_rejects_via_flag),
- support_cheap_stateless_reject(support_cheap_stateless_reject) {}
-
- friend std::ostream& operator<<(std::ostream& os,
- const BufferedPacketStoreTestParams& p) {
- os << "{ enable_stateless_rejects_via_flag: "
- << p.enable_stateless_rejects_via_flag << std::endl;
- os << " support_cheap_stateless_reject: "
- << p.support_cheap_stateless_reject << " }";
- return os;
- }
-
- // This only enables the stateless reject feature via the feature-flag.
- // This should be a no-op if the peer does not support them.
- bool enable_stateless_rejects_via_flag;
- // Whether to do cheap stateless or not.
- bool support_cheap_stateless_reject;
-};
-
-std::vector<BufferedPacketStoreTestParams> GetBufferedPacketStoreTestParams() {
- std::vector<BufferedPacketStoreTestParams> params;
- for (bool enable_stateless_rejects_via_flag : {true, false}) {
- for (bool support_cheap_stateless_reject : {true, false}) {
- params.push_back(BufferedPacketStoreTestParams(
- enable_stateless_rejects_via_flag, support_cheap_stateless_reject));
- }
- }
- return params;
-}
-
// A dispatcher whose stateless rejector will always ACCEPTs CHLO.
-class BufferedPacketStoreTest
- : public QuicDispatcherTest,
- public testing::WithParamInterface<BufferedPacketStoreTestParams> {
+class BufferedPacketStoreTest : public QuicDispatcherTest {
public:
BufferedPacketStoreTest()
: QuicDispatcherTest(),
server_addr_(QuicSocketAddress(QuicIpAddress::Any4(), 5)),
client_addr_(QuicIpAddress::Loopback4(), 1234),
- signed_config_(new QuicSignedServerConfig) {
- SetQuicReloadableFlag(quic_use_cheap_stateless_rejects,
- GetParam().support_cheap_stateless_reject);
- SetQuicReloadableFlag(enable_quic_stateless_reject_support,
- GetParam().enable_stateless_rejects_via_flag);
- }
+ signed_config_(new QuicSignedServerConfig) {}
void SetUp() override {
QuicDispatcherTest::SetUp();
@@ -1460,7 +1417,6 @@
CryptoHandshakeMessage chlo =
crypto_test_utils::GenerateDefaultInchoateCHLO(clock_, version,
&crypto_config_);
- chlo.SetVector(kCOPT, QuicTagVector{kSREJ});
// Pass an inchoate CHLO.
crypto_test_utils::GenerateFullCHLO(
chlo, &crypto_config_, server_addr_, client_addr_, version, clock_,
@@ -1480,12 +1436,7 @@
CryptoHandshakeMessage full_chlo_;
};
-INSTANTIATE_TEST_SUITE_P(
- BufferedPacketStoreTests,
- BufferedPacketStoreTest,
- ::testing::ValuesIn(GetBufferedPacketStoreTestParams()));
-
-TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) {
+TEST_F(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) {
InSequence s;
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
QuicConnectionId conn_id = TestConnectionId(1);
@@ -1524,7 +1475,7 @@
ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
}
-TEST_P(BufferedPacketStoreTest,
+TEST_F(BufferedPacketStoreTest,
ProcessNonChloPacketsForDifferentConnectionsUptoLimit) {
InSequence s;
// A bunch of non-CHLO should be buffered upon arrival.
@@ -1578,7 +1529,7 @@
}
// Tests that store delivers empty packet list if CHLO arrives firstly.
-TEST_P(BufferedPacketStoreTest, DeliverEmptyPackets) {
+TEST_F(BufferedPacketStoreTest, DeliverEmptyPackets) {
QuicConnectionId conn_id = TestConnectionId(1);
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
EXPECT_CALL(*dispatcher_,
@@ -1596,7 +1547,7 @@
// Tests that a retransmitted CHLO arrives after a connection for the
// CHLO has been created.
-TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) {
+TEST_F(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) {
InSequence s;
QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
QuicConnectionId conn_id = TestConnectionId(1);
@@ -1626,7 +1577,7 @@
}
// Tests that expiration of a connection add connection id to time wait list.
-TEST_P(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) {
+TEST_F(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) {
InSequence s;
CreateTimeWaitListManager();
QuicBufferedPacketStore* store =
@@ -1652,7 +1603,7 @@
ProcessPacket(client_address, conn_id, true, SerializeFullCHLO());
}
-TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
+TEST_F(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
// Process more than (|kMaxNumSessionsToCreate| +
// |kDefaultMaxConnectionsInStore|) CHLOs,
// the first |kMaxNumSessionsToCreate| should create connections immediately,
@@ -1729,7 +1680,7 @@
}
// Duplicated CHLO shouldn't be buffered.
-TEST_P(BufferedPacketStoreTest, BufferDuplicatedCHLO) {
+TEST_F(BufferedPacketStoreTest, BufferDuplicatedCHLO) {
for (uint64_t conn_id = 1; conn_id <= kMaxNumSessionsToCreate + 1;
++conn_id) {
// Last CHLO will be buffered. Others will create connection right away.
@@ -1778,7 +1729,7 @@
dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
}
-TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) {
+TEST_F(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) {
uint64_t last_conn_id = kMaxNumSessionsToCreate + 1;
QuicConnectionId last_connection_id = TestConnectionId(last_conn_id);
for (uint64_t conn_id = 1; conn_id <= last_conn_id; ++conn_id) {
@@ -1832,7 +1783,7 @@
// Tests that when dispatcher's packet buffer is full, a CHLO on connection
// which doesn't have buffered CHLO should be buffered.
-TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) {
+TEST_F(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) {
QuicBufferedPacketStore* store =
QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
@@ -1877,7 +1828,7 @@
}
// Regression test for b/117874922.
-TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) {
+TEST_F(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) {
// Turn off version 99, such that the preferred version is not supported by
// the server.
SetQuicReloadableFlag(quic_enable_version_99, false);
diff --git a/quic/core/stateless_rejector.cc b/quic/core/stateless_rejector.cc
deleted file mode 100644
index e2ef51c..0000000
--- a/quic/core/stateless_rejector.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/core/stateless_rejector.h"
-
-#include <string>
-
-#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
-
-namespace quic {
-
-class StatelessRejector::ValidateCallback
- : public ValidateClientHelloResultCallback {
- public:
- explicit ValidateCallback(
- std::unique_ptr<StatelessRejector> rejector,
- std::unique_ptr<StatelessRejector::ProcessDoneCallback> cb)
- : rejector_(std::move(rejector)), cb_(std::move(cb)) {}
-
- ~ValidateCallback() override = default;
-
- void Run(QuicReferenceCountedPointer<Result> result,
- std::unique_ptr<ProofSource::Details> /* proof_source_details */)
- override {
- StatelessRejector* rejector_ptr = rejector_.get();
- rejector_ptr->ProcessClientHello(std::move(result), std::move(rejector_),
- std::move(cb_));
- }
-
- private:
- std::unique_ptr<StatelessRejector> rejector_;
- std::unique_ptr<StatelessRejector::ProcessDoneCallback> cb_;
-};
-
-StatelessRejector::StatelessRejector(
- ParsedQuicVersion version,
- const ParsedQuicVersionVector& versions,
- const QuicCryptoServerConfig* crypto_config,
- QuicCompressedCertsCache* compressed_certs_cache,
- const QuicClock* clock,
- QuicRandom* random,
- QuicByteCount chlo_packet_size,
- const QuicSocketAddress& client_address,
- const QuicSocketAddress& server_address)
- : state_(UNKNOWN),
- error_(QUIC_INTERNAL_ERROR),
- version_(version),
- versions_(versions),
- connection_id_(EmptyQuicConnectionId()),
- chlo_packet_size_(chlo_packet_size),
- client_address_(client_address),
- server_address_(server_address),
- clock_(clock),
- random_(random),
- crypto_config_(crypto_config),
- compressed_certs_cache_(compressed_certs_cache),
- signed_config_(new QuicSignedServerConfig),
- params_(new QuicCryptoNegotiatedParameters) {}
-
-StatelessRejector::~StatelessRejector() = default;
-
-void StatelessRejector::OnChlo(QuicTransportVersion version,
- QuicConnectionId connection_id,
- QuicConnectionId server_designated_connection_id,
- const CryptoHandshakeMessage& message) {
- DCHECK_EQ(kCHLO, message.tag());
- DCHECK_NE(connection_id, server_designated_connection_id);
- DCHECK_EQ(state_, UNKNOWN);
-
- if (!GetQuicReloadableFlag(enable_quic_stateless_reject_support) ||
- !GetQuicReloadableFlag(quic_use_cheap_stateless_rejects) ||
- !QuicCryptoServerStream::DoesPeerSupportStatelessRejects(message)) {
- state_ = UNSUPPORTED;
- return;
- }
-
- connection_id_ = connection_id;
- server_designated_connection_id_ = server_designated_connection_id;
- chlo_ = message; // Note: copies the message
-}
-
-void StatelessRejector::Process(std::unique_ptr<StatelessRejector> rejector,
- std::unique_ptr<ProcessDoneCallback> done_cb) {
- QUIC_BUG_IF(rejector->state() != UNKNOWN) << "StatelessRejector::Process "
- "called for a rejector which "
- "has already made a decision";
- StatelessRejector* rejector_ptr = rejector.get();
- rejector_ptr->crypto_config_->ValidateClientHello(
- rejector_ptr->chlo_, rejector_ptr->client_address_.host(),
- rejector_ptr->server_address_, rejector_ptr->version_.transport_version,
- rejector_ptr->clock_, rejector_ptr->signed_config_,
- std::unique_ptr<ValidateCallback>(
- new ValidateCallback(std::move(rejector), std::move(done_cb))));
-}
-
-class StatelessRejector::ProcessClientHelloCallback
- : public ProcessClientHelloResultCallback {
- public:
- ProcessClientHelloCallback(
- std::unique_ptr<StatelessRejector> rejector,
- std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb)
- : rejector_(std::move(rejector)), done_cb_(std::move(done_cb)) {}
-
- void Run(QuicErrorCode error,
- const std::string& error_details,
- std::unique_ptr<CryptoHandshakeMessage> message,
- std::unique_ptr<DiversificationNonce> diversification_nonce,
- std::unique_ptr<ProofSource::Details> /* proof_source_details */)
- override {
- StatelessRejector* rejector_ptr = rejector_.get();
- rejector_ptr->ProcessClientHelloDone(
- error, error_details, std::move(message), std::move(rejector_),
- std::move(done_cb_));
- }
-
- private:
- std::unique_ptr<StatelessRejector> rejector_;
- std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb_;
-};
-
-void StatelessRejector::ProcessClientHello(
- QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
- result,
- std::unique_ptr<StatelessRejector> rejector,
- std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) {
- std::unique_ptr<ProcessClientHelloCallback> cb(
- new ProcessClientHelloCallback(std::move(rejector), std::move(done_cb)));
- crypto_config_->ProcessClientHello(
- result,
- /*reject_only=*/true, connection_id_, server_address_, client_address_,
- version_, versions_,
- /*use_stateless_rejects=*/true, server_designated_connection_id_, clock_,
- random_, compressed_certs_cache_, params_, signed_config_,
- QuicCryptoStream::CryptoMessageFramingOverhead(version_.transport_version,
- connection_id_),
- chlo_packet_size_, std::move(cb));
-}
-
-void StatelessRejector::ProcessClientHelloDone(
- QuicErrorCode error,
- const std::string& error_details,
- std::unique_ptr<CryptoHandshakeMessage> message,
- std::unique_ptr<StatelessRejector> rejector,
- std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb) {
- reply_ = std::move(message);
-
- if (error != QUIC_NO_ERROR) {
- error_ = error;
- error_details_ = error_details;
- state_ = FAILED;
- } else if (reply_->tag() == kSREJ) {
- state_ = REJECTED;
- } else {
- state_ = ACCEPTED;
- }
- done_cb->Run(std::move(rejector));
-}
-
-} // namespace quic
diff --git a/quic/core/stateless_rejector.h b/quic/core/stateless_rejector.h
deleted file mode 100644
index 18dbdcb..0000000
--- a/quic/core/stateless_rejector.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef QUICHE_QUIC_CORE_STATELESS_REJECTOR_H_
-#define QUICHE_QUIC_CORE_STATELESS_REJECTOR_H_
-
-#include <string>
-
-#include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h"
-#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
-#include "net/third_party/quiche/src/quic/core/quic_packets.h"
-
-namespace quic {
-
-// The StatelessRejector receives CHLO messages and generates an SREJ
-// message in response, if the CHLO can be statelessly rejected.
-class StatelessRejector {
- public:
- enum State {
- UNKNOWN, // State has not yet been determined
- UNSUPPORTED, // Stateless rejects are not supported
- FAILED, // There was an error processing the CHLO.
- ACCEPTED, // The CHLO was accepted
- REJECTED, // The CHLO was rejected.
- };
-
- StatelessRejector(ParsedQuicVersion version,
- const ParsedQuicVersionVector& versions,
- const QuicCryptoServerConfig* crypto_config,
- QuicCompressedCertsCache* compressed_certs_cache,
- const QuicClock* clock,
- QuicRandom* random,
- QuicByteCount chlo_packet_size,
- const QuicSocketAddress& client_address,
- const QuicSocketAddress& server_address);
- StatelessRejector(const StatelessRejector&) = delete;
- StatelessRejector& operator=(const StatelessRejector&) = delete;
-
- ~StatelessRejector();
-
- // Called when |chlo| is received for |connection_id|.
- void OnChlo(QuicTransportVersion version,
- QuicConnectionId connection_id,
- QuicConnectionId server_designated_connection_id,
- const CryptoHandshakeMessage& chlo);
-
- class ProcessDoneCallback {
- public:
- virtual ~ProcessDoneCallback() = default;
- virtual void Run(std::unique_ptr<StatelessRejector> rejector) = 0;
- };
-
- // Perform processing to determine whether the CHLO received in OnChlo should
- // be statelessly rejected, and invoke the callback once a decision has been
- // made.
- static void Process(std::unique_ptr<StatelessRejector> rejector,
- std::unique_ptr<ProcessDoneCallback> done_cb);
-
- // Return the version of the CHLO.
- ParsedQuicVersion version() const { return version_; }
-
- // Returns the state of the rejector after OnChlo() has been called.
- State state() const { return state_; }
-
- // Returns the error code when state() returns FAILED.
- QuicErrorCode error() const { return error_; }
-
- // Returns the error details when state() returns FAILED.
- std::string error_details() const { return error_details_; }
-
- // Returns the connection ID.
- QuicConnectionId connection_id() const { return connection_id_; }
-
- // Returns the SREJ message when state() returns REJECTED.
- const CryptoHandshakeMessage& reply() const { return *reply_; }
-
- private:
- // Helper class which is passed in to
- // QuicCryptoServerConfig::ValidateClientHello.
- class ValidateCallback;
- friend class ValidateCallback;
-
- class ProcessClientHelloCallback;
- friend class ProcessClientHelloCallback;
-
- void ProcessClientHello(
- QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result>
- result,
- std::unique_ptr<StatelessRejector> rejector,
- std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb);
-
- void ProcessClientHelloDone(
- QuicErrorCode error,
- const std::string& error_details,
- std::unique_ptr<CryptoHandshakeMessage> message,
- std::unique_ptr<StatelessRejector> rejector,
- std::unique_ptr<StatelessRejector::ProcessDoneCallback> done_cb);
-
- State state_;
- QuicErrorCode error_;
- std::string error_details_;
- ParsedQuicVersion version_;
- ParsedQuicVersionVector versions_;
- QuicConnectionId connection_id_;
- QuicConnectionId server_designated_connection_id_;
- QuicByteCount chlo_packet_size_;
- QuicSocketAddress client_address_;
- QuicSocketAddress server_address_;
- const QuicClock* clock_;
- QuicRandom* random_;
- const QuicCryptoServerConfig* crypto_config_;
- QuicCompressedCertsCache* compressed_certs_cache_;
- CryptoHandshakeMessage chlo_;
- std::unique_ptr<CryptoHandshakeMessage> reply_;
- CryptoFramer crypto_framer_;
- QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_;
- QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params_;
-};
-
-} // namespace quic
-
-#endif // QUICHE_QUIC_CORE_STATELESS_REJECTOR_H_
diff --git a/quic/core/stateless_rejector_test.cc b/quic/core/stateless_rejector_test.cc
deleted file mode 100644
index f8757e1..0000000
--- a/quic/core/stateless_rejector_test.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/quiche/src/quic/core/stateless_rejector.h"
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
-#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h"
-#include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
-#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
-#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h"
-#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
-
-namespace quic {
-namespace test {
-namespace {
-
-QuicConnectionId TestServerDesignatedConnectionId() {
- return TestConnectionId(24);
-}
-
-// All four combinations of the two flags involved.
-enum FlagsMode { ENABLED, STATELESS_DISABLED, CHEAP_DISABLED, BOTH_DISABLED };
-
-const char* FlagsModeToString(FlagsMode mode) {
- switch (mode) {
- case ENABLED:
- return "ENABLED";
- case STATELESS_DISABLED:
- return "STATELESS_DISABLED";
- case CHEAP_DISABLED:
- return "CHEAP_DISABLED";
- case BOTH_DISABLED:
- return "BOTH_DISABLED";
- default:
- QUIC_DLOG(FATAL) << "Unexpected FlagsMode";
- return nullptr;
- }
-}
-
-// Test various combinations of QUIC version and flag state.
-struct TestParams {
- ParsedQuicVersion version = UnsupportedQuicVersion();
- FlagsMode flags;
-};
-
-std::string TestParamToString(
- const testing::TestParamInfo<TestParams>& params) {
- return QuicStrCat("v", ParsedQuicVersionToString(params.param.version), "_",
- FlagsModeToString(params.param.flags));
-}
-
-std::vector<TestParams> GetTestParams() {
- std::vector<TestParams> params;
- for (FlagsMode flags :
- {ENABLED, STATELESS_DISABLED, CHEAP_DISABLED, BOTH_DISABLED}) {
- for (ParsedQuicVersion version : AllSupportedVersions()) {
- TestParams param;
- param.version = version;
- param.flags = flags;
- params.push_back(param);
- }
- }
- return params;
-}
-
-class StatelessRejectorTest : public QuicTestWithParam<TestParams> {
- public:
- StatelessRejectorTest()
- : proof_source_(crypto_test_utils::ProofSourceForTesting()),
- config_(QuicCryptoServerConfig::TESTING,
- QuicRandom::GetInstance(),
- crypto_test_utils::ProofSourceForTesting(),
- KeyExchangeSource::Default(),
- TlsServerHandshaker::CreateSslCtx()),
- config_peer_(&config_),
- compressed_certs_cache_(
- QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
- rejector_(QuicMakeUnique<StatelessRejector>(
- GetParam().version,
- AllSupportedVersions(),
- &config_,
- &compressed_certs_cache_,
- &clock_,
- QuicRandom::GetInstance(),
- kDefaultMaxPacketSize,
- QuicSocketAddress(QuicIpAddress::Loopback4(), 12345),
- QuicSocketAddress(QuicIpAddress::Loopback4(), 443))) {
- SetQuicReloadableFlag(
- enable_quic_stateless_reject_support,
- GetParam().flags == ENABLED || GetParam().flags == CHEAP_DISABLED);
- SetQuicReloadableFlag(
- quic_use_cheap_stateless_rejects,
- GetParam().flags == ENABLED || GetParam().flags == STATELESS_DISABLED);
-
- // Add a new primary config.
- std::unique_ptr<CryptoHandshakeMessage> msg(config_.AddDefaultConfig(
- QuicRandom::GetInstance(), &clock_, config_options_));
-
- // Save the server config.
- scid_hex_ =
- "#" + QuicTextUtils::HexEncode(config_peer_.GetPrimaryConfig()->id);
-
- // Encode the QUIC version.
- ver_hex_ = ParsedQuicVersionToString(GetParam().version);
-
- // Generate a public value.
- char public_value[32];
- memset(public_value, 42, sizeof(public_value));
- pubs_hex_ =
- "#" + QuicTextUtils::HexEncode(public_value, sizeof(public_value));
-
- // Generate a client nonce.
- std::string nonce;
- CryptoUtils::GenerateNonce(
- clock_.WallNow(), QuicRandom::GetInstance(),
- QuicStringPiece(
- reinterpret_cast<char*>(config_peer_.GetPrimaryConfig()->orbit),
- kOrbitSize),
- &nonce);
- nonc_hex_ = "#" + QuicTextUtils::HexEncode(nonce);
-
- // Generate a source address token.
- SourceAddressTokens previous_tokens;
- QuicIpAddress ip = QuicIpAddress::Loopback4();
- MockRandom rand;
- std::string stk = config_peer_.NewSourceAddressToken(
- config_peer_.GetPrimaryConfig()->id, previous_tokens, ip, &rand,
- clock_.WallNow(), nullptr);
- stk_hex_ = "#" + QuicTextUtils::HexEncode(stk);
- }
-
- protected:
- class ProcessDoneCallback : public StatelessRejector::ProcessDoneCallback {
- public:
- explicit ProcessDoneCallback(StatelessRejectorTest* test) : test_(test) {}
- void Run(std::unique_ptr<StatelessRejector> rejector) override {
- test_->rejector_ = std::move(rejector);
- }
-
- private:
- StatelessRejectorTest* test_;
- };
-
- std::unique_ptr<ProofSource> proof_source_;
- MockClock clock_;
- QuicCryptoServerConfig config_;
- QuicCryptoServerConfigPeer config_peer_;
- QuicCompressedCertsCache compressed_certs_cache_;
- QuicCryptoServerConfig::ConfigOptions config_options_;
- std::unique_ptr<StatelessRejector> rejector_;
-
- // Values used in CHLO messages
- std::string scid_hex_;
- std::string nonc_hex_;
- std::string pubs_hex_;
- std::string ver_hex_;
- std::string stk_hex_;
-};
-
-INSTANTIATE_TEST_SUITE_P(Flags,
- StatelessRejectorTest,
- ::testing::ValuesIn(GetTestParams()),
- TestParamToString);
-
-TEST_P(StatelessRejectorTest, InvalidChlo) {
- // clang-format off
- const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO(
- {{"PDMD", "X509"},
- {"COPT", "SREJ"}});
- // clang-format on
- rejector_->OnChlo(GetParam().version.transport_version, TestConnectionId(),
- TestServerDesignatedConnectionId(), client_hello);
-
- if (GetParam().flags != ENABLED) {
- EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
- return;
- }
-
- // The StatelessRejector is undecided - proceed with async processing
- ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state());
- StatelessRejector::Process(std::move(rejector_),
- QuicMakeUnique<ProcessDoneCallback>(this));
-
- EXPECT_EQ(StatelessRejector::FAILED, rejector_->state());
- EXPECT_EQ(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, rejector_->error());
-}
-
-TEST_P(StatelessRejectorTest, ValidChloWithoutSrejSupport) {
- // clang-format off
- const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO(
- {{"PDMD", "X509"},
- {"AEAD", "AESG"},
- {"KEXS", "C255"},
- {"PUBS", pubs_hex_},
- {"NONC", nonc_hex_},
- {"VER\0", ver_hex_}},
- kClientHelloMinimumSize);
- // clang-format on
-
- rejector_->OnChlo(GetParam().version.transport_version, TestConnectionId(),
- TestServerDesignatedConnectionId(), client_hello);
- EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
-}
-
-TEST_P(StatelessRejectorTest, RejectChlo) {
- // clang-format off
- const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO(
- {{"PDMD", "X509"},
- {"AEAD", "AESG"},
- {"KEXS", "C255"},
- {"COPT", "SREJ"},
- {"SCID", scid_hex_},
- {"PUBS", pubs_hex_},
- {"NONC", nonc_hex_},
- {"#004b5453", stk_hex_},
- {"VER\0", ver_hex_}},
- kClientHelloMinimumSize);
- // clang-format on
-
- rejector_->OnChlo(GetParam().version.transport_version, TestConnectionId(),
- TestServerDesignatedConnectionId(), client_hello);
- if (GetParam().flags != ENABLED) {
- EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
- return;
- }
-
- // The StatelessRejector is undecided - proceed with async processing
- ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state());
- StatelessRejector::Process(std::move(rejector_),
- QuicMakeUnique<ProcessDoneCallback>(this));
-
- ASSERT_EQ(StatelessRejector::REJECTED, rejector_->state());
- const CryptoHandshakeMessage& reply = rejector_->reply();
- EXPECT_EQ(kSREJ, reply.tag());
- QuicTagVector reject_reasons;
- EXPECT_EQ(QUIC_NO_ERROR, reply.GetTaglist(kRREJ, &reject_reasons));
- EXPECT_EQ(1u, reject_reasons.size());
- EXPECT_EQ(INVALID_EXPECTED_LEAF_CERTIFICATE,
- static_cast<HandshakeFailureReason>(reject_reasons[0]));
-}
-
-TEST_P(StatelessRejectorTest, AcceptChlo) {
- const uint64_t xlct = crypto_test_utils::LeafCertHashForTesting();
- const std::string xlct_hex =
- "#" + QuicTextUtils::HexEncode(reinterpret_cast<const char*>(&xlct),
- sizeof(xlct));
- // clang-format off
- const CryptoHandshakeMessage client_hello = crypto_test_utils::CreateCHLO(
- {{"PDMD", "X509"},
- {"AEAD", "AESG"},
- {"KEXS", "C255"},
- {"COPT", "SREJ"},
- {"SCID", scid_hex_},
- {"PUBS", pubs_hex_},
- {"NONC", nonc_hex_},
- {"#004b5453", stk_hex_},
- {"VER\0", ver_hex_},
- {"XLCT", xlct_hex}},
- kClientHelloMinimumSize);
- // clang-format on
-
- rejector_->OnChlo(GetParam().version.transport_version, TestConnectionId(),
- TestServerDesignatedConnectionId(), client_hello);
- if (GetParam().flags != ENABLED) {
- EXPECT_EQ(StatelessRejector::UNSUPPORTED, rejector_->state());
- return;
- }
-
- // The StatelessRejector is undecided - proceed with async processing
- ASSERT_EQ(StatelessRejector::UNKNOWN, rejector_->state());
- StatelessRejector::Process(std::move(rejector_),
- QuicMakeUnique<ProcessDoneCallback>(this));
-
- EXPECT_EQ(StatelessRejector::ACCEPTED, rejector_->state());
-}
-
-} // namespace
-} // namespace test
-} // namespace quic