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