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