| Index: net/tools/quic/quic_dispatcher.cc
|
| diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
|
| index 486aea70a3eb36947b0af412b27756a54ab86fd7..0d558694418f84c74ddabd2696a2d179cfd53a7f 100644
|
| --- a/net/tools/quic/quic_dispatcher.cc
|
| +++ b/net/tools/quic/quic_dispatcher.cc
|
| @@ -14,9 +14,11 @@
|
| #include "net/quic/core/quic_bug_tracker.h"
|
| #include "net/quic/core/quic_flags.h"
|
| #include "net/quic/core/quic_utils.h"
|
| +
|
| #include "net/tools/quic/chlo_extractor.h"
|
| #include "net/tools/quic/quic_per_connection_packet_writer.h"
|
| #include "net/tools/quic/quic_simple_server_session.h"
|
| +#include "net/tools/quic/quic_simple_server_session.h"
|
| #include "net/tools/quic/quic_time_wait_list_manager.h"
|
| #include "net/tools/quic/stateless_rejector.h"
|
|
|
| @@ -155,7 +157,7 @@ class StatelessConnectionTerminator {
|
| // to give the QuicDispatcher a chance to apply policy checks to the CHLO.
|
| class ChloValidator : public ChloExtractor::Delegate {
|
| public:
|
| - ChloValidator(QuicServerSessionBase::Helper* helper,
|
| + ChloValidator(QuicCryptoServerStream::Helper* helper,
|
| IPEndPoint self_address,
|
| StatelessRejector* rejector)
|
| : helper_(helper),
|
| @@ -180,7 +182,7 @@ class ChloValidator : public ChloExtractor::Delegate {
|
| const string& error_details() const { return error_details_; }
|
|
|
| private:
|
| - QuicServerSessionBase::Helper* helper_; // Unowned.
|
| + QuicCryptoServerStream::Helper* helper_; // Unowned.
|
| IPEndPoint self_address_;
|
| StatelessRejector* rejector_; // Unowned.
|
| bool can_accept_;
|
| @@ -194,7 +196,7 @@ QuicDispatcher::QuicDispatcher(
|
| const QuicCryptoServerConfig* crypto_config,
|
| QuicVersionManager* version_manager,
|
| std::unique_ptr<QuicConnectionHelperInterface> helper,
|
| - std::unique_ptr<QuicServerSessionBase::Helper> session_helper,
|
| + std::unique_ptr<QuicCryptoServerStream::Helper> session_helper,
|
| std::unique_ptr<QuicAlarmFactory> alarm_factory)
|
| : config_(config),
|
| crypto_config_(crypto_config),
|
| @@ -325,12 +327,25 @@ bool QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
|
| return false;
|
| }
|
|
|
| - // Packet's connection ID is unknown.
|
| - // Apply the validity checks.
|
| + // Packet's connection ID is unknown. Apply the validity checks.
|
| QuicPacketFate fate = ValidityChecks(header);
|
| if (fate == kFateProcess) {
|
| - fate = MaybeRejectStatelessly(connection_id, header);
|
| + // Execute stateless rejection logic to determine the packet fate, then
|
| + // invoke ProcessUnauthenticatedHeaderFate.
|
| + MaybeRejectStatelessly(connection_id, header);
|
| + } else {
|
| + // If the fate is already known, process it without executing stateless
|
| + // rejection logic.
|
| + ProcessUnauthenticatedHeaderFate(fate, connection_id, header.packet_number);
|
| }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +void QuicDispatcher::ProcessUnauthenticatedHeaderFate(
|
| + QuicPacketFate fate,
|
| + QuicConnectionId connection_id,
|
| + QuicPacketNumber packet_number) {
|
| switch (fate) {
|
| case kFateProcess: {
|
| ProcessChlo();
|
| @@ -340,8 +355,7 @@ bool QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
|
| // MaybeRejectStatelessly might have already added the connection to
|
| // time wait, in which case it should not be added again.
|
| if (!FLAGS_quic_use_cheap_stateless_rejects ||
|
| - !time_wait_list_manager_->IsConnectionIdInTimeWait(
|
| - header.public_header.connection_id)) {
|
| + !time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)) {
|
| // Add this connection_id to the time-wait state, to safely reject
|
| // future packets.
|
| DVLOG(1) << "Adding connection ID " << connection_id
|
| @@ -350,12 +364,10 @@ bool QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
|
| connection_id, framer_.version(),
|
| /*connection_rejected_statelessly=*/false, nullptr);
|
| }
|
| - DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(
|
| - header.public_header.connection_id));
|
| + DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
|
| time_wait_list_manager_->ProcessPacket(
|
| - current_server_address_, current_client_address_,
|
| - header.public_header.connection_id, header.packet_number,
|
| - *current_packet_);
|
| + current_server_address_, current_client_address_, connection_id,
|
| + packet_number, *current_packet_);
|
| break;
|
| case kFateBuffer:
|
| // This packet is a non-CHLO packet which has arrived out of order.
|
| @@ -366,8 +378,6 @@ bool QuicDispatcher::OnUnauthenticatedHeader(const QuicPacketHeader& header) {
|
| // Do nothing with the packet.
|
| break;
|
| }
|
| -
|
| - return false;
|
| }
|
|
|
| QuicDispatcher::QuicPacketFate QuicDispatcher::ValidityChecks(
|
| @@ -757,9 +767,29 @@ bool QuicDispatcher::OnUnauthenticatedUnknownPublicHeader(
|
| return true;
|
| }
|
|
|
| -QuicDispatcher::QuicPacketFate QuicDispatcher::MaybeRejectStatelessly(
|
| - QuicConnectionId connection_id,
|
| - const QuicPacketHeader& header) {
|
| +class StatelessRejectorProcessDoneCallback
|
| + : public StatelessRejector::ProcessDoneCallback {
|
| + public:
|
| + StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher,
|
| + QuicPacketNumber packet_number,
|
| + QuicVersion first_version)
|
| + : dispatcher_(dispatcher),
|
| + packet_number_(packet_number),
|
| + first_version_(first_version) {}
|
| +
|
| + void Run(std::unique_ptr<StatelessRejector> rejector) override {
|
| + dispatcher_->OnStatelessRejectorProcessDone(std::move(rejector),
|
| + packet_number_, first_version_);
|
| + }
|
| +
|
| + private:
|
| + QuicDispatcher* dispatcher_;
|
| + QuicPacketNumber packet_number_;
|
| + QuicVersion first_version_;
|
| +};
|
| +
|
| +void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id,
|
| + const QuicPacketHeader& header) {
|
| // TODO(rch): This logic should probably live completely inside the rejector.
|
| if (!FLAGS_quic_use_cheap_stateless_rejects ||
|
| !FLAGS_enable_quic_stateless_reject_support ||
|
| @@ -770,18 +800,22 @@ QuicDispatcher::QuicPacketFate QuicDispatcher::MaybeRejectStatelessly(
|
| !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
|
| nullptr)) {
|
| // Buffer non-CHLO packets.
|
| - return kFateBuffer;
|
| + ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id,
|
| + header.packet_number);
|
| + return;
|
| }
|
| - return kFateProcess;
|
| + ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id,
|
| + header.packet_number);
|
| + return;
|
| }
|
|
|
| - StatelessRejector rejector(
|
| + std::unique_ptr<StatelessRejector> rejector(new StatelessRejector(
|
| header.public_header.versions.front(), GetSupportedVersions(),
|
| crypto_config_, &compressed_certs_cache_, helper()->GetClock(),
|
| helper()->GetRandomGenerator(), current_packet_->length(),
|
| - current_client_address_, current_server_address_);
|
| + current_client_address_, current_server_address_));
|
| ChloValidator validator(session_helper_.get(), current_server_address_,
|
| - &rejector);
|
| + rejector.get());
|
| if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
|
| &validator)) {
|
| if (!FLAGS_quic_buffer_packet_till_chlo) {
|
| @@ -790,9 +824,13 @@ QuicDispatcher::QuicPacketFate QuicDispatcher::MaybeRejectStatelessly(
|
| "not supported while trying to do stateless reject. "
|
| "--gfe2_reloadable_flag_quic_buffer_packet_till_chlo false"
|
| " --gfe2_reloadable_flag_quic_use_cheap_stateless_rejects true";
|
| - return kFateDrop;
|
| + ProcessUnauthenticatedHeaderFate(kFateDrop, connection_id,
|
| + header.packet_number);
|
| + return;
|
| }
|
| - return kFateBuffer;
|
| + ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id,
|
| + header.packet_number);
|
| + return;
|
| }
|
|
|
| if (!validator.can_accept()) {
|
| @@ -802,40 +840,63 @@ QuicDispatcher::QuicPacketFate QuicDispatcher::MaybeRejectStatelessly(
|
| terminator.CloseConnection(QUIC_HANDSHAKE_FAILED,
|
| validator.error_details());
|
| OnConnectionClosedStatelessly(QUIC_HANDSHAKE_FAILED);
|
| - return kFateTimeWait;
|
| + ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id,
|
| + header.packet_number);
|
| + return;
|
| }
|
|
|
| - // This packet included a CHLO. See if it can be rejected statelessly.
|
| - switch (rejector.state()) {
|
| + // Continue stateless rejector processing
|
| + std::unique_ptr<StatelessRejectorProcessDoneCallback> cb(
|
| + new StatelessRejectorProcessDoneCallback(
|
| + this, header.packet_number, header.public_header.versions.front()));
|
| + StatelessRejector::Process(std::move(rejector), std::move(cb));
|
| +}
|
| +
|
| +void QuicDispatcher::OnStatelessRejectorProcessDone(
|
| + std::unique_ptr<StatelessRejector> rejector,
|
| + QuicPacketNumber packet_number,
|
| + QuicVersion first_version) {
|
| + QuicPacketFate fate;
|
| + switch (rejector->state()) {
|
| case StatelessRejector::FAILED: {
|
| // There was an error processing the client hello.
|
| - StatelessConnectionTerminator terminator(
|
| - connection_id, &framer_, helper(), time_wait_list_manager_.get());
|
| - terminator.CloseConnection(rejector.error(), rejector.error_details());
|
| - return kFateTimeWait;
|
| + StatelessConnectionTerminator terminator(rejector->connection_id(),
|
| + &framer_, helper(),
|
| + time_wait_list_manager_.get());
|
| + terminator.CloseConnection(rejector->error(), rejector->error_details());
|
| + fate = kFateTimeWait;
|
| + break;
|
| }
|
|
|
| case StatelessRejector::UNSUPPORTED:
|
| // Cheap stateless rejects are not supported so process the packet.
|
| - return kFateProcess;
|
| + fate = kFateProcess;
|
| + break;
|
|
|
| case StatelessRejector::ACCEPTED:
|
| // Contains a valid CHLO, so process the packet and create a connection.
|
| - return kFateProcess;
|
| + fate = kFateProcess;
|
| + break;
|
|
|
| case StatelessRejector::REJECTED: {
|
| - DCHECK_EQ(framer_.version(), header.public_header.versions.front());
|
| - StatelessConnectionTerminator terminator(
|
| - connection_id, &framer_, helper(), time_wait_list_manager_.get());
|
| + DCHECK_EQ(framer_.version(), first_version);
|
| + StatelessConnectionTerminator terminator(rejector->connection_id(),
|
| + &framer_, helper(),
|
| + time_wait_list_manager_.get());
|
| terminator.RejectConnection(
|
| - rejector.reply().GetSerialized().AsStringPiece());
|
| + rejector->reply().GetSerialized().AsStringPiece());
|
| OnConnectionRejectedStatelessly();
|
| - return kFateTimeWait;
|
| + fate = kFateTimeWait;
|
| + break;
|
| }
|
| - }
|
|
|
| - QUIC_BUG << "Rejector has unknown invalid state.";
|
| - return kFateDrop;
|
| + default:
|
| + QUIC_BUG << "Rejector has invalid state " << rejector->state();
|
| + fate = kFateDrop;
|
| + break;
|
| + }
|
| + ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id(),
|
| + packet_number);
|
| }
|
|
|
| const QuicVersionVector& QuicDispatcher::GetSupportedVersions() {
|
|
|