Skip to content

Commit

Permalink
Quic refactor (envoyproxy#31097)
Browse files Browse the repository at this point in the history

Signed-off-by: Alyssa Wilk <[email protected]>
  • Loading branch information
alyssawilk authored Jan 2, 2024
1 parent b8d7aea commit 5a15b9f
Show file tree
Hide file tree
Showing 25 changed files with 314 additions and 225 deletions.
2 changes: 1 addition & 1 deletion mobile/envoy_build_config/extension_registry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
#include "source/extensions/quic/proof_source/envoy_quic_proof_source_factory_impl.h"
#include "source/extensions/udp_packet_writer/default/config.h"
#endif
#include "source/common/quic/quic_transport_socket_factory.h"
#include "source/common/quic/quic_client_transport_socket_factory.h"
#endif

#include "extension_registry_platform_additions.h"
Expand Down
1 change: 1 addition & 0 deletions mobile/test/common/integration/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ envoy_cc_test(
"@envoy//source/common/quic:active_quic_listener_lib",
"@envoy//source/common/quic:client_connection_factory_lib",
"@envoy//source/common/quic:quic_server_factory_lib",
"@envoy//source/common/quic:quic_server_transport_socket_factory_lib",
"@envoy//source/common/quic:quic_transport_socket_factory_lib",
"@envoy//source/common/quic:udp_gso_batch_writer_lib",
"@envoy//source/extensions/udp_packet_writer/gso:config",
Expand Down
2 changes: 1 addition & 1 deletion mobile/test/common/integration/client_integration_test.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "source/common/quic/quic_transport_socket_factory.h"
#include "source/common/quic/quic_server_transport_socket_factory.h"
#include "source/common/quic/server_codec_impl.h"
#include "source/extensions/http/header_formatters/preserve_case/preserve_case_formatter.h"
#include "source/extensions/quic/connection_id_generator/envoy_deterministic_connection_id_generator_config.h"
Expand Down
1 change: 1 addition & 0 deletions source/common/listener_manager/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ envoy_cc_library(
"//source/common/quic:active_quic_listener_lib",
"//source/common/quic:client_connection_factory_lib",
"//source/common/quic:quic_server_factory_lib",
"//source/common/quic:quic_server_transport_socket_factory_lib",
"//source/common/quic:quic_transport_socket_factory_lib",
"//source/common/quic:udp_gso_batch_writer_lib",
"//source/extensions/udp_packet_writer/gso:config",
Expand Down
2 changes: 1 addition & 1 deletion source/common/listener_manager/listener_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#include "absl/synchronization/blocking_counter.h"

#if defined(ENVOY_ENABLE_QUIC)
#include "source/common/quic/quic_transport_socket_factory.h"
#include "source/common/quic/quic_server_transport_socket_factory.h"
#endif

#include "source/server/api_listener_impl.h"
Expand Down
36 changes: 34 additions & 2 deletions source/common/quic/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ envoy_cc_library(
":quic_io_handle_wrapper_lib",
":quic_transport_socket_factory_lib",
"//envoy/ssl:tls_certificate_config_interface",
"//source/common/quic:quic_server_transport_socket_factory_lib",
"//source/common/stream_info:stream_info_lib",
"//source/server:listener_stats",
"@com_github_google_quiche//:quic_core_crypto_certificate_view_lib",
Expand Down Expand Up @@ -436,11 +437,42 @@ envoy_cc_library(

envoy_cc_library(
name = "quic_transport_socket_factory_lib",
srcs = ["quic_transport_socket_factory.cc"],
hdrs = ["quic_transport_socket_factory.h"],
srcs = [
"quic_client_transport_socket_factory.cc",
"quic_transport_socket_factory.cc",
],
hdrs = [
"quic_client_transport_socket_factory.h",
"quic_transport_socket_factory.h",
],
tags = ["nofips"],
deps = [
":envoy_quic_proof_verifier_lib",
"//envoy/network:transport_socket_interface",
"//envoy/server:transport_socket_config_interface",
"//envoy/ssl:context_config_interface",
"//source/common/common:assert_lib",
"//source/common/network:transport_socket_options_lib",
"//source/extensions/transport_sockets/tls:context_config_lib",
"//source/extensions/transport_sockets/tls:ssl_socket_lib",
"@com_github_google_quiche//:quic_core_crypto_crypto_handshake_lib",
"@envoy_api//envoy/extensions/transport_sockets/quic/v3:pkg_cc_proto",
],
alwayslink = LEGACY_ALWAYSLINK,
)

envoy_cc_library(
name = "quic_server_transport_socket_factory_lib",
srcs = [
"quic_server_transport_socket_factory.cc",
],
hdrs = [
"quic_server_transport_socket_factory.h",
],
tags = ["nofips"],
deps = [
":envoy_quic_proof_verifier_lib",
":quic_transport_socket_factory_lib",
"//envoy/network:transport_socket_interface",
"//envoy/server:transport_socket_config_interface",
"//envoy/ssl:context_config_interface",
Expand Down
2 changes: 1 addition & 1 deletion source/common/quic/envoy_quic_proof_source.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "source/common/quic/envoy_quic_proof_source_base.h"
#include "source/common/quic/quic_transport_socket_factory.h"
#include "source/common/quic/quic_server_transport_socket_factory.h"
#include "source/server/listener_stats.h"

namespace Envoy {
Expand Down
66 changes: 66 additions & 0 deletions source/common/quic/quic_client_transport_socket_factory.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "source/common/quic/quic_client_transport_socket_factory.h"

#include <memory>

#include "envoy/extensions/transport_sockets/quic/v3/quic_transport.pb.validate.h"

#include "source/common/quic/envoy_quic_proof_verifier.h"
#include "source/common/runtime/runtime_features.h"
#include "source/extensions/transport_sockets/tls/context_config_impl.h"

#include "quiche/quic/core/crypto/quic_client_session_cache.h"

namespace Envoy {
namespace Quic {

Network::UpstreamTransportSocketFactoryPtr
QuicClientTransportSocketConfigFactory::createTransportSocketFactory(
const Protobuf::Message& config,
Server::Configuration::TransportSocketFactoryContext& context) {
auto quic_transport = MessageUtil::downcastAndValidate<
const envoy::extensions::transport_sockets::quic::v3::QuicUpstreamTransport&>(
config, context.messageValidationVisitor());
auto client_config = std::make_unique<Extensions::TransportSockets::Tls::ClientContextConfigImpl>(
quic_transport.upstream_tls_context(), context);
auto factory =
std::make_unique<QuicClientTransportSocketFactory>(std::move(client_config), context);
factory->initialize();
return factory;
}

QuicClientTransportSocketFactory::QuicClientTransportSocketFactory(
Ssl::ClientContextConfigPtr config,
Server::Configuration::TransportSocketFactoryContext& factory_context)
: QuicTransportSocketFactoryBase(factory_context.statsScope(), "client"),
fallback_factory_(std::make_unique<Extensions::TransportSockets::Tls::ClientSslSocketFactory>(
std::move(config), factory_context.sslContextManager(), factory_context.statsScope())) {}

ProtobufTypes::MessagePtr QuicClientTransportSocketConfigFactory::createEmptyConfigProto() {
return std::make_unique<envoy::extensions::transport_sockets::quic::v3::QuicUpstreamTransport>();
}

std::shared_ptr<quic::QuicCryptoClientConfig> QuicClientTransportSocketFactory::getCryptoConfig() {
Envoy::Ssl::ClientContextSharedPtr context = sslCtx();
// If the secrets haven't been loaded, there is no crypto config.
if (context == nullptr) {
ENVOY_LOG(warn, "SDS hasn't finished updating Ssl context config yet.");
stats_.upstream_context_secrets_not_ready_.inc();
return nullptr;
}

if (client_context_ != context) {
// If the context has been updated, update the crypto config.
client_context_ = context;
crypto_config_ = std::make_shared<quic::QuicCryptoClientConfig>(
std::make_unique<Quic::EnvoyQuicProofVerifier>(std::move(context)),
std::make_unique<quic::QuicClientSessionCache>());
}
// Return the latest crypto config.
return crypto_config_;
}

REGISTER_FACTORY(QuicClientTransportSocketConfigFactory,
Server::Configuration::UpstreamTransportSocketConfigFactory);

} // namespace Quic
} // namespace Envoy
74 changes: 74 additions & 0 deletions source/common/quic/quic_client_transport_socket_factory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#pragma once

#include "source/common/quic/quic_transport_socket_factory.h"

namespace Envoy {
namespace Quic {

class QuicClientTransportSocketFactory : public Network::CommonUpstreamTransportSocketFactory,
public QuicTransportSocketFactoryBase {
public:
QuicClientTransportSocketFactory(
Ssl::ClientContextConfigPtr config,
Server::Configuration::TransportSocketFactoryContext& factory_context);

void initialize() override {}
bool implementsSecureTransport() const override { return true; }
bool supportsAlpn() const override { return true; }
absl::string_view defaultServerNameIndication() const override {
return clientContextConfig()->serverNameIndication();
}

// As documented above for QuicTransportSocketFactoryBase, the actual HTTP/3
// code does not create transport sockets.
// QuicClientTransportSocketFactory::createTransportSocket is called by the
// connection grid when upstream HTTP/3 fails over to TCP, and a raw SSL socket
// is needed. In this case the QuicClientTransportSocketFactory falls over to
// using the fallback factory.
Network::TransportSocketPtr
createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options,
Upstream::HostDescriptionConstSharedPtr host) const override {
return fallback_factory_->createTransportSocket(options, host);
}

Envoy::Ssl::ClientContextSharedPtr sslCtx() override { return fallback_factory_->sslCtx(); }

OptRef<const Ssl::ClientContextConfig> clientContextConfig() const override {
return fallback_factory_->clientContextConfig();
}

// Returns a crypto config generated from the up-to-date client context config. Once the passed in
// context config gets updated, a new crypto config object will be returned by this method.
std::shared_ptr<quic::QuicCryptoClientConfig> getCryptoConfig() override;

protected:
// fallback_factory_ will update the context.
void onSecretUpdated() override {}

private:
// The QUIC client transport socket can create TLS sockets for fallback to TCP.
std::unique_ptr<Extensions::TransportSockets::Tls::ClientSslSocketFactory> fallback_factory_;
// Latch the latest client context, to determine if it has updated since last
// checked.
Envoy::Ssl::ClientContextSharedPtr client_context_;
// If client_context_ changes, client config will be updated as well.
std::shared_ptr<quic::QuicCryptoClientConfig> crypto_config_;
};

class QuicClientTransportSocketConfigFactory
: public QuicTransportSocketConfigFactory,
public Server::Configuration::UpstreamTransportSocketConfigFactory {
public:
// Server::Configuration::UpstreamTransportSocketConfigFactory
Network::UpstreamTransportSocketFactoryPtr createTransportSocketFactory(
const Protobuf::Message& config,
Server::Configuration::TransportSocketFactoryContext& context) override;

// Server::Configuration::TransportSocketConfigFactory
ProtobufTypes::MessagePtr createEmptyConfigProto() override;
};

DECLARE_FACTORY(QuicClientTransportSocketConfigFactory);

} // namespace Quic
} // namespace Envoy
43 changes: 43 additions & 0 deletions source/common/quic/quic_server_transport_socket_factory.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "source/common/quic/quic_server_transport_socket_factory.h"

#include <memory>

#include "envoy/extensions/transport_sockets/quic/v3/quic_transport.pb.validate.h"

#include "source/common/runtime/runtime_features.h"
#include "source/extensions/transport_sockets/tls/context_config_impl.h"

namespace Envoy {
namespace Quic {

Network::DownstreamTransportSocketFactoryPtr
QuicServerTransportSocketConfigFactory::createTransportSocketFactory(
const Protobuf::Message& config, Server::Configuration::TransportSocketFactoryContext& context,
const std::vector<std::string>& /*server_names*/) {
auto quic_transport = MessageUtil::downcastAndValidate<
const envoy::extensions::transport_sockets::quic::v3::QuicDownstreamTransport&>(
config, context.messageValidationVisitor());
auto server_config = std::make_unique<Extensions::TransportSockets::Tls::ServerContextConfigImpl>(
quic_transport.downstream_tls_context(), context);
// TODO(RyanTheOptimist): support TLS client authentication.
if (server_config->requireClientCertificate()) {
throwEnvoyExceptionOrPanic("TLS Client Authentication is not supported over QUIC");
}

auto factory = std::make_unique<QuicServerTransportSocketFactory>(
PROTOBUF_GET_WRAPPED_OR_DEFAULT(quic_transport, enable_early_data, true),
context.statsScope(), std::move(server_config));
factory->initialize();
return factory;
}

ProtobufTypes::MessagePtr QuicServerTransportSocketConfigFactory::createEmptyConfigProto() {
return std::make_unique<
envoy::extensions::transport_sockets::quic::v3::QuicDownstreamTransport>();
}

REGISTER_FACTORY(QuicServerTransportSocketConfigFactory,
Server::Configuration::DownstreamTransportSocketConfigFactory);

} // namespace Quic
} // namespace Envoy
77 changes: 77 additions & 0 deletions source/common/quic/quic_server_transport_socket_factory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#pragma once

#include "envoy/extensions/transport_sockets/quic/v3/quic_transport.pb.h"
#include "envoy/network/transport_socket.h"
#include "envoy/server/transport_socket_config.h"
#include "envoy/ssl/context_config.h"

#include "source/common/common/assert.h"
#include "source/common/network/transport_socket_options_impl.h"
#include "source/common/quic/quic_transport_socket_factory.h"
#include "source/extensions/transport_sockets/tls/ssl_socket.h"

namespace Envoy {
namespace Quic {

// TODO(danzh): when implement ProofSource, examine of it's necessary to
// differentiate server and client side context config.
class QuicServerTransportSocketFactory : public Network::DownstreamTransportSocketFactory,
public QuicTransportSocketFactoryBase {
public:
QuicServerTransportSocketFactory(bool enable_early_data, Stats::Scope& store,
Ssl::ServerContextConfigPtr config)
: QuicTransportSocketFactoryBase(store, "server"), config_(std::move(config)),
enable_early_data_(enable_early_data) {}

// Network::DownstreamTransportSocketFactory
Network::TransportSocketPtr createDownstreamTransportSocket() const override {
PANIC("not implemented");
}
bool implementsSecureTransport() const override { return true; }

void initialize() override {
config_->setSecretUpdateCallback([this]() {
// The callback also updates config_ with the new secret.
onSecretUpdated();
});
}

// Return TLS certificates if the context config is ready.
std::vector<std::reference_wrapper<const Envoy::Ssl::TlsCertificateConfig>>
getTlsCertificates() const {
if (!config_->isReady()) {
ENVOY_LOG(warn, "SDS hasn't finished updating Ssl context config yet.");
stats_.downstream_context_secrets_not_ready_.inc();
return {};
}
return config_->tlsCertificates();
}

bool earlyDataEnabled() const { return enable_early_data_; }

protected:
void onSecretUpdated() override { stats_.context_config_update_by_sds_.inc(); }

private:
Ssl::ServerContextConfigPtr config_;
bool enable_early_data_;
};

class QuicServerTransportSocketConfigFactory
: public QuicTransportSocketConfigFactory,
public Server::Configuration::DownstreamTransportSocketConfigFactory {
public:
// Server::Configuration::DownstreamTransportSocketConfigFactory
Network::DownstreamTransportSocketFactoryPtr
createTransportSocketFactory(const Protobuf::Message& config,
Server::Configuration::TransportSocketFactoryContext& context,
const std::vector<std::string>& server_names) override;

// Server::Configuration::TransportSocketConfigFactory
ProtobufTypes::MessagePtr createEmptyConfigProto() override;
};

DECLARE_FACTORY(QuicServerTransportSocketConfigFactory);

} // namespace Quic
} // namespace Envoy
Loading

0 comments on commit 5a15b9f

Please sign in to comment.