Skip to content

Commit

Permalink
quic: Add a DataSource option for server preferred address config
Browse files Browse the repository at this point in the history
Signed-off-by: Greg Greenway <ggreenway@apple.com>
  • Loading branch information
ggreenway committed Jun 26, 2024
1 parent f0201e5 commit e146fa2
Show file tree
Hide file tree
Showing 14 changed files with 478 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
syntax = "proto3";

package envoy.extensions.quic.server_preferred_address.v3;

import "envoy/config/core/v3/base.proto";

import "xds/annotations/v3/status.proto";

import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.quic.server_preferred_address.v3";
option java_outer_classname = "DataSourceServerPreferredAddressConfig";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/quic/server_preferred_address/v3;server_preferred_addressv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: QUIC DataSource server preferred address config]
// [#extension: envoy.quic.server_preferred_address.datasource]

// Configuration for DataSourceServerPreferredAddressConfig.
message DataSourceServerPreferredAddressConfig {
// [#comment:TODO(danzh2010): discuss with API shepherds before removing WiP status.]

option (xds.annotations.v3.message_status).work_in_progress = true;

// Addresses for server preferred address for a single address family (IPv4 or IPv6).
message AddressFamilyConfig {
// The server preferred address sent to clients. The data must contain an IP address string.
envoy.config.core.v3.DataSource address = 1 [(validate.rules).message = {required: true}];

// The server preferred address port sent to clients. The data must contain a integer port value.
//
// If this is not specified, the listener's port is used.
//
// Note: Envoy currently must receive all packets for a QUIC connection on the same port, so unless
// :ref:`dnat_address <envoy_v3_api_field_extensions.quic.server_preferred_address.v3.DataSourceServerPreferredAddressConfig.AddressFamilyConfig.dnat_address>`
// is configured, this must be left unset.
envoy.config.core.v3.DataSource port = 2;

// If there is a DNAT between the client and Envoy, the address that Envoy will observe
// server preferred address packets being sent to. If this is not specified, it is assumed
// there is no DNAT and the server preferred address packets will be sent to the address advertised
// to clients for server preferred address.
envoy.config.core.v3.DataSource dnat_address = 3;
}

// The IPv4 address to advertise to clients for Server Preferred Address.
AddressFamilyConfig ipv4_config = 1;

// The IPv6 address to advertise to clients for Server Preferred Address.
AddressFamilyConfig ipv6_config = 2;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/quic/server_preferred_address/v3;server_preferred_addressv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: QUIC server preferred address config]
// [#protodoc-title: QUIC fixed server preferred address config]
// [#extension: envoy.quic.server_preferred_address.fixed]

// Configuration for FixedServerPreferredAddressConfig.
Expand Down
1 change: 1 addition & 0 deletions source/common/quic/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,7 @@ envoy_cc_library(
deps = [
"//envoy/config:typed_config_interface",
"//envoy/network:address_interface",
"//envoy/server:factory_context_interface",
"@com_github_google_quiche//:quic_platform_socket_address",
],
)
Expand Down
1 change: 1 addition & 0 deletions source/extensions/extensions_build_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ EXTENSIONS = {
"envoy.quic.crypto_stream.server.quiche": "//source/extensions/quic/crypto_stream:envoy_quic_default_crypto_server_stream",
"envoy.quic.proof_source.filter_chain": "//source/extensions/quic/proof_source:envoy_quic_default_proof_source",
"envoy.quic.server_preferred_address.fixed": "//source/extensions/quic/server_preferred_address:fixed_server_preferred_address_config_factory_config",
"envoy.quic.server_preferred_address.datasource": "//source/extensions/quic/server_preferred_address:datasource_server_preferred_address_config_factory_config",
"envoy.quic.connection_debug_visitor.basic": "//source/extensions/quic/connection_debug_visitor:envoy_quic_connection_debug_visitor_basic",

#
Expand Down
7 changes: 7 additions & 0 deletions source/extensions/extensions_metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,13 @@ envoy.quic.server_preferred_address.fixed:
status: alpha
type_urls:
- envoy.extensions.quic.server_preferred_address.v3.FixedServerPreferredAddressConfig
envoy.quic.server_preferred_address.datasource:
categories:
- envoy.quic.server_preferred_address
security_posture: robust_to_untrusted_downstream
status: alpha
type_urls:
- envoy.extensions.quic.server_preferred_address.v3.DataSourceServerPreferredAddressConfig
envoy.udp_packet_writer.default:
categories:
- envoy.udp_packet_writer
Expand Down
44 changes: 44 additions & 0 deletions source/extensions/quic/server_preferred_address/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,23 @@ licenses(["notice"]) # Apache 2

envoy_extension_package()

envoy_cc_library(
name = "server_preferred_address_lib",
srcs = ["server_preferred_address.cc"],
hdrs = ["server_preferred_address.h"],
tags = ["nofips"],
deps = [
"//source/common/quic:envoy_quic_server_preferred_address_config_factory_interface",
],
)

envoy_cc_library(
name = "fixed_server_preferred_address_config_lib",
srcs = ["fixed_server_preferred_address_config.cc"],
hdrs = ["fixed_server_preferred_address_config.h"],
tags = ["nofips"],
deps = [
":server_preferred_address_lib",
"//envoy/registry",
"//source/common/quic:envoy_quic_server_preferred_address_config_factory_interface",
"//source/common/quic:envoy_quic_utils_lib",
Expand All @@ -45,3 +56,36 @@ envoy_cc_extension(
},
),
)

envoy_cc_library(
name = "datasource_server_preferred_address_config_lib",
srcs = ["datasource_server_preferred_address_config.cc"],
hdrs = ["datasource_server_preferred_address_config.h"],
tags = ["nofips"],
deps = [
":server_preferred_address_lib",
"//envoy/registry",
"//source/common/config:datasource_lib",
"//source/common/quic:envoy_quic_server_preferred_address_config_factory_interface",
"//source/common/quic:envoy_quic_utils_lib",
"@envoy_api//envoy/extensions/quic/server_preferred_address/v3:pkg_cc_proto",
],
alwayslink = LEGACY_ALWAYSLINK,
)

envoy_cc_extension(
name = "datasource_server_preferred_address_config_factory_config",
extra_visibility = [
"//test:__subpackages__",
],
tags = ["nofips"],
deps = select(
{
"//bazel:boringssl_fips": [],
"//bazel:boringssl_disabled": [],
"//conditions:default": [
":datasource_server_preferred_address_config_lib",
],
},
),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include "source/extensions/quic/server_preferred_address/datasource_server_preferred_address_config.h"

#include "envoy/common/exception.h"

#include "source/common/common/utility.h"
#include "source/common/config/datasource.h"
#include "source/common/network/utility.h"
#include "source/common/quic/envoy_quic_utils.h"
#include "source/extensions/quic/server_preferred_address/server_preferred_address.h"

namespace Envoy {
namespace Quic {

namespace {

quic::QuicIpAddress parseIp(const envoy::config::core::v3::DataSource& source,
quiche::IpAddressFamily address_family,
absl::string_view address_family_str, const Protobuf::Message& message,
Server::Configuration::ServerFactoryContext& context) {
std::string data =
THROW_OR_RETURN_VALUE(Config::DataSource::read(source, false, context.api()), std::string);

quic::QuicIpAddress ip;
if (!ip.FromString(std::string(StringUtil::trim(data)))) {
ProtoExceptionUtil::throwProtoValidationException(
absl::StrCat("bad ", address_family_str, " server preferred address: ", data), message);
}

if (ip.address_family() != address_family) {
ProtoExceptionUtil::throwProtoValidationException(
absl::StrCat("wrong address family for ", address_family_str,
" server preferred address: ", data),
message);
}
return ip;
}

ServerPreferredAddressConfig::FamilyAddresses
parseFamily(const envoy::extensions::quic::server_preferred_address::v3::
DataSourceServerPreferredAddressConfig::AddressFamilyConfig* addresses,
quiche::IpAddressFamily address_family, absl::string_view address_family_str,
const Protobuf::Message& message,
Server::Configuration::ServerFactoryContext& context) {
ServerPreferredAddressConfig::FamilyAddresses ret;
if (addresses != nullptr) {
const quic::QuicIpAddress spa_addr =
parseIp(addresses->address(), address_family, address_family_str, message, context);

if (!addresses->has_dnat_address() && addresses->has_port()) {
ProtoExceptionUtil::throwProtoValidationException(
fmt::format("port must be unset unless 'dnat_address' is set "
"for address family {}",
address_family_str),
message);
}

uint16_t spa_port = 0;
if (addresses->has_port()) {
std::string port_str = THROW_OR_RETURN_VALUE(
Config::DataSource::read(addresses->port(), false, context.api()), std::string);

// absl::SimpleAtoi doesn't work with uint16_t, so first convert to uint32_t.
uint32_t big_port = 0;
const bool success = absl::SimpleAtoi(port_str, &big_port);
if (!success || big_port > UINT16_MAX) {
ProtoExceptionUtil::throwProtoValidationException(
absl::StrCat("server preferred address ", address_family_str,
" port was not a valid port: ", port_str),
message);
}

spa_port = big_port;
}
ret.spa_ = quic::QuicSocketAddress(spa_addr, spa_port);

if (addresses->has_dnat_address()) {
ret.dnat_ =
parseIp(addresses->dnat_address(), address_family, address_family_str, message, context);
}
}

return ret;
}

} // namespace

Quic::EnvoyQuicServerPreferredAddressConfigPtr
DataSourceServerPreferredAddressConfigFactory::createServerPreferredAddressConfig(
const Protobuf::Message& message, ProtobufMessage::ValidationVisitor& validation_visitor,
Server::Configuration::ServerFactoryContext& context) {
auto& config =
MessageUtil::downcastAndValidate<const envoy::extensions::quic::server_preferred_address::v3::
DataSourceServerPreferredAddressConfig&>(
message, validation_visitor);

ServerPreferredAddressConfig::FamilyAddresses v4 =
parseFamily(config.has_ipv4_config() ? &config.ipv4_config() : nullptr,
quiche::IpAddressFamily::IP_V4, "v4", message, context);
ServerPreferredAddressConfig::FamilyAddresses v6 =
parseFamily(config.has_ipv6_config() ? &config.ipv6_config() : nullptr,
quiche::IpAddressFamily::IP_V6, "v6", message, context);

return std::make_unique<ServerPreferredAddressConfig>(v4, v6);
}

REGISTER_FACTORY(DataSourceServerPreferredAddressConfigFactory,
Quic::EnvoyQuicServerPreferredAddressConfigFactory);

} // namespace Quic
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include "envoy/extensions/quic/server_preferred_address/v3/datasource.pb.h"
#include "envoy/extensions/quic/server_preferred_address/v3/datasource.pb.validate.h"
#include "envoy/registry/registry.h"

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

namespace Envoy {
namespace Quic {

class DataSourceServerPreferredAddressConfigFactory
: public Envoy::Quic::EnvoyQuicServerPreferredAddressConfigFactory {
public:
std::string name() const override { return "quic.server_preferred_address.datasource"; }

Envoy::Quic::EnvoyQuicServerPreferredAddressConfigPtr
createServerPreferredAddressConfig(const Protobuf::Message& message,
ProtobufMessage::ValidationVisitor& validation_visitor,
Server::Configuration::ServerFactoryContext& context) override;

ProtobufTypes::MessagePtr createEmptyConfigProto() override {
return ProtobufTypes::MessagePtr{new envoy::extensions::quic::server_preferred_address::v3::
DataSourceServerPreferredAddressConfig()};
}
};

DECLARE_FACTORY(DataSourceServerPreferredAddressConfigFactory);

} // namespace Quic
} // namespace Envoy
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,13 @@

#include "source/common/network/utility.h"
#include "source/common/quic/envoy_quic_utils.h"
#include "source/extensions/quic/server_preferred_address/server_preferred_address.h"

namespace Envoy {
namespace Quic {

namespace {

quic::QuicSocketAddress ipOrAddressToAddress(const quic::QuicSocketAddress& address, int32_t port) {
if (address.port() == 0) {
return quic::QuicSocketAddress(address.host(), port);
}

return address;
}

quic::QuicIpAddress parseIp(const std::string& addr, absl::string_view address_family,
const Protobuf::Message& message) {
quic::QuicIpAddress ip;
Expand Down Expand Up @@ -65,13 +58,13 @@ parseIpAddressFromSocketAddress(const envoy::config::core::v3::SocketAddress& ad
return socket_addr.host();
}

FixedServerPreferredAddressConfig::FamilyAddresses
ServerPreferredAddressConfig::FamilyAddresses
parseFamily(const std::string& addr_string,
const envoy::extensions::quic::server_preferred_address::v3::
FixedServerPreferredAddressConfig::AddressFamilyConfig* addresses,
Network::Address::IpVersion version, absl::string_view address_family,
const Protobuf::Message& message) {
FixedServerPreferredAddressConfig::FamilyAddresses ret;
ServerPreferredAddressConfig::FamilyAddresses ret;
if (addresses != nullptr) {
if (addresses->has_dnat_address() && !addresses->has_address()) {
ProtoExceptionUtil::throwProtoValidationException(
Expand Down Expand Up @@ -107,18 +100,6 @@ parseFamily(const std::string& addr_string,

} // namespace

EnvoyQuicServerPreferredAddressConfig::Addresses
FixedServerPreferredAddressConfig::getServerPreferredAddresses(
const Network::Address::InstanceConstSharedPtr& local_address) {
int32_t port = local_address->ip()->port();
Addresses addresses;
addresses.ipv4_ = ipOrAddressToAddress(v4_.spa_, port);
addresses.ipv6_ = ipOrAddressToAddress(v6_.spa_, port);
addresses.dnat_ipv4_ = quic::QuicSocketAddress(v4_.dnat_, port);
addresses.dnat_ipv6_ = quic::QuicSocketAddress(v6_.dnat_, port);
return addresses;
}

Quic::EnvoyQuicServerPreferredAddressConfigPtr
FixedServerPreferredAddressConfigFactory::createServerPreferredAddressConfig(
const Protobuf::Message& message, ProtobufMessage::ValidationVisitor& validation_visitor,
Expand All @@ -128,14 +109,14 @@ FixedServerPreferredAddressConfigFactory::createServerPreferredAddressConfig(
FixedServerPreferredAddressConfig&>(message,
validation_visitor);

FixedServerPreferredAddressConfig::FamilyAddresses v4 =
ServerPreferredAddressConfig::FamilyAddresses v4 =
parseFamily(config.ipv4_address(), config.has_ipv4_config() ? &config.ipv4_config() : nullptr,
Network::Address::IpVersion::v4, "v4", message);
FixedServerPreferredAddressConfig::FamilyAddresses v6 =
ServerPreferredAddressConfig::FamilyAddresses v6 =
parseFamily(config.ipv6_address(), config.has_ipv6_config() ? &config.ipv6_config() : nullptr,
Network::Address::IpVersion::v6, "v6", message);

return std::make_unique<FixedServerPreferredAddressConfig>(v4, v6);
return std::make_unique<ServerPreferredAddressConfig>(v4, v6);
}

REGISTER_FACTORY(FixedServerPreferredAddressConfigFactory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,6 @@
namespace Envoy {
namespace Quic {

class FixedServerPreferredAddressConfig : public Quic::EnvoyQuicServerPreferredAddressConfig {
public:
struct FamilyAddresses {
quic::QuicSocketAddress spa_;
quic::QuicIpAddress dnat_;
};

FixedServerPreferredAddressConfig(const FamilyAddresses& v4, const FamilyAddresses& v6)
: v4_(v4), v6_(v6) {}

Addresses getServerPreferredAddresses(
const Network::Address::InstanceConstSharedPtr& local_address) override;

private:
const FamilyAddresses v4_;
const FamilyAddresses v6_;
};

class FixedServerPreferredAddressConfigFactory
: public Quic::EnvoyQuicServerPreferredAddressConfigFactory {
public:
Expand Down
Loading

0 comments on commit e146fa2

Please sign in to comment.