Defer the creation of control streams in QBONE client & server until encryption is established. Default enabled by --qbone_client_defer_control_stream_creation & --qbone_server_defer_control_stream_creation. This should be a no-op as a sane client/server should only be able to write/read(decrypt) control stream related frames only after encryption is established. And receiving any frame related to the control stream earlier than that should result in connection close. PiperOrigin-RevId: 413473872
diff --git a/quic/qbone/qbone_client_session.cc b/quic/qbone/qbone_client_session.cc index 1f8ca0a..fce08d2 100644 --- a/quic/qbone/qbone_client_session.cc +++ b/quic/qbone/qbone_client_session.cc
@@ -10,6 +10,11 @@ #include "quic/core/quic_types.h" #include "quic/qbone/qbone_constants.h" +DEFINE_QUIC_COMMAND_LINE_FLAG( + bool, qbone_client_defer_control_stream_creation, true, + "If true, control stream in QBONE client session is created after " + "encryption established."); + namespace quic { QboneClientSession::QboneClientSession( @@ -34,12 +39,10 @@ /*has_application_state = */ true); } -void QboneClientSession::Initialize() { - // Initialize must be called first, as that's what generates the crypto - // stream. - QboneSessionBase::Initialize(); - static_cast<QuicCryptoClientStreamBase*>(GetMutableCryptoStream()) - ->CryptoConnect(); +void QboneClientSession::CreateControlStream() { + if (control_stream_ != nullptr) { + return; + } // Register the reserved control stream. QuicStreamId next_id = GetNextOutgoingBidirectionalStreamId(); QUICHE_DCHECK_EQ(next_id, @@ -50,6 +53,26 @@ ActivateStream(std::move(control_stream)); } +void QboneClientSession::Initialize() { + // Initialize must be called first, as that's what generates the crypto + // stream. + QboneSessionBase::Initialize(); + static_cast<QuicCryptoClientStreamBase*>(GetMutableCryptoStream()) + ->CryptoConnect(); + if (!GetQuicFlag(FLAGS_qbone_client_defer_control_stream_creation)) { + CreateControlStream(); + } +} + +void QboneClientSession::SetDefaultEncryptionLevel( + quic::EncryptionLevel level) { + QboneSessionBase::SetDefaultEncryptionLevel(level); + if (GetQuicFlag(FLAGS_qbone_client_defer_control_stream_creation) && + level == quic::ENCRYPTION_FORWARD_SECURE) { + CreateControlStream(); + } +} + int QboneClientSession::GetNumSentClientHellos() const { return static_cast<const QuicCryptoClientStreamBase*>(GetCryptoStream()) ->num_sent_client_hellos();
diff --git a/quic/qbone/qbone_client_session.h b/quic/qbone/qbone_client_session.h index 442b859..8f1b3a9 100644 --- a/quic/qbone/qbone_client_session.h +++ b/quic/qbone/qbone_client_session.h
@@ -33,6 +33,8 @@ // QuicSession overrides. This will initiate the crypto stream. void Initialize() override; + // Override to create control stream at FORWARD_SECURE encryption level. + void SetDefaultEncryptionLevel(quic::EncryptionLevel level) override; // Returns the number of client hello messages that have been sent on the // crypto stream. If the handshake has completed then this is one greater @@ -65,6 +67,9 @@ // QboneSessionBase interface implementation. std::unique_ptr<QuicCryptoStream> CreateCryptoStream() override; + // Instantiate QboneClientControlStream. + void CreateControlStream(); + // ProofHandler interface implementation. void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override; void OnProofVerifyDetailsAvailable( @@ -82,7 +87,7 @@ // Passed to the control stream. QboneClientControlStream::Handler* handler_; // The unowned control stream. - QboneClientControlStream* control_stream_; + QboneClientControlStream* control_stream_ = nullptr; }; } // namespace quic
diff --git a/quic/qbone/qbone_server_session.cc b/quic/qbone/qbone_server_session.cc index 3b80dab..2ddb8e4 100644 --- a/quic/qbone/qbone_server_session.cc +++ b/quic/qbone/qbone_server_session.cc
@@ -4,6 +4,7 @@ #include "quic/qbone/qbone_server_session.h" +#include <string> #include <utility> #include "absl/strings/string_view.h" @@ -12,6 +13,11 @@ #include "quic/core/quic_utils.h" #include "quic/qbone/qbone_constants.h" +DEFINE_QUIC_COMMAND_LINE_FLAG( + bool, qbone_server_defer_control_stream_creation, true, + "If true, control stream in QBONE server session is created after " + "encryption established."); + namespace quic { bool QboneCryptoServerStreamHelper::CanAcceptClientHello( @@ -55,8 +61,10 @@ &stream_helper_); } -void QboneServerSession::Initialize() { - QboneSessionBase::Initialize(); +void QboneServerSession::CreateControlStream() { + if (control_stream_ != nullptr) { + return; + } // Register the reserved control stream. auto control_stream = std::make_unique<QboneServerControlStream>(this, handler_); @@ -64,6 +72,22 @@ ActivateStream(std::move(control_stream)); } +void QboneServerSession::Initialize() { + QboneSessionBase::Initialize(); + if (!GetQuicFlag(FLAGS_qbone_server_defer_control_stream_creation)) { + CreateControlStream(); + } +} + +void QboneServerSession::SetDefaultEncryptionLevel( + quic::EncryptionLevel level) { + QboneSessionBase::SetDefaultEncryptionLevel(level); + if (GetQuicFlag(FLAGS_qbone_server_defer_control_stream_creation) && + level == quic::ENCRYPTION_FORWARD_SECURE) { + CreateControlStream(); + } +} + bool QboneServerSession::SendClientRequest(const QboneClientRequest& request) { if (!control_stream_) { QUIC_BUG(quic_bug_11026_1)
diff --git a/quic/qbone/qbone_server_session.h b/quic/qbone/qbone_server_session.h index 76b7333..f5af8b4 100644 --- a/quic/qbone/qbone_server_session.h +++ b/quic/qbone/qbone_server_session.h
@@ -50,6 +50,8 @@ ~QboneServerSession() override; void Initialize() override; + // Override to create control stream at FORWARD_SECURE encryption level. + void SetDefaultEncryptionLevel(quic::EncryptionLevel level) override; virtual bool SendClientRequest(const QboneClientRequest& request); @@ -73,6 +75,10 @@ protected: // QboneSessionBase interface implementation. std::unique_ptr<QuicCryptoStream> CreateCryptoStream() override; + + // Instantiate QboneServerControlStream. + void CreateControlStream(); + // The packet processor. QbonePacketProcessor processor_; @@ -86,7 +92,7 @@ // Passed to the control stream. QboneServerControlStream::Handler* handler_; // The unowned control stream. - QboneServerControlStream* control_stream_; + QboneServerControlStream* control_stream_ = nullptr; }; } // namespace quic