| // 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/quic/core/stateless_rejector.h" |
| |
| #include "net/third_party/quic/core/quic_crypto_server_stream.h" |
| #include "net/third_party/quic/platform/api/quic_bug_tracker.h" |
| #include "net/third_party/quic/platform/api/quic_flags.h" |
| #include "net/third_party/quic/platform/api/quic_string.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 QuicString& 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 QuicString& 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 |