Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions doc/admin-guide/files/sni.yaml.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,37 @@ server_groups_list Inbound Specifies an override to the
:file:`records.yaml` configuration. See the
`OpenSSL SSL_CTX_set_groups_list <https://docs.openssl.org/3.5/man3/SSL_CTX_set1_curves/>`_
documentation.

Each item contains a group key identifying the server group name and optionally,
a percentage key that determines how frequently that group is selected when multiple
entries are present.

Percentages are relative; they do not need to sum to 100. Any omitted percentage defaults to 100.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's a ratio then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe a weight as you say on the subject.


For example:

.. code-block:: yaml

sni:
- fqdn: example1.com
server_groups_list:
- group: "group_1"
percentage: 20
- group: "group_2"
percentage: 80
- fqdn: example2.com
server_groups_list:
- group: "group_1"
- fqdn: example3.com
server_groups_list: "group_1"


In this configuration:
- connections with SNI example1.com will be directed to group_1 about 20%
of the time and to group_2 about 80% of the time
- Connections for example2.com and example3.com will always use group_1.



host_sni_policy Inbound One of the values :code:`DISABLED`, :code:`PERMISSIVE`, or :code:`ENFORCED`.

Expand Down
65 changes: 35 additions & 30 deletions include/iocore/net/YamlSNIConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ TSDECL(server_max_early_data);

class ActionItem;

struct SNIServerGroupsList {
std::string group;
int percentage = 100;
};

struct YamlSNIConfig {
enum class Policy : uint8_t { DISABLED = 0, PERMISSIVE, ENFORCED, UNSET };
enum class Property : uint8_t { NONE = 0, SIGNATURE_MASK = 0x1, NAME_MASK = 0x2, ALL_MASK = 0x3, UNSET };
Expand All @@ -91,36 +96,36 @@ struct YamlSNIConfig {

std::vector<ts::port_range_t> inbound_port_ranges;

std::optional<bool> offer_h2; // Has no value by default, so do not initialize!
std::optional<bool> offer_quic; // Has no value by default, so do not initialize!
uint8_t verify_client_level = 255;
std::string verify_client_ca_file;
std::string verify_client_ca_dir;
uint8_t host_sni_policy = 255;
SNIRoutingType tunnel_type = SNIRoutingType::NONE;
std::string tunnel_destination;
Policy verify_server_policy = Policy::UNSET;
Property verify_server_properties = Property::UNSET;
std::string client_cert;
std::string client_key;
std::string client_sni_policy;
std::string server_cipher_suite;
std::string server_TLSv1_3_cipher_suites;
std::string server_groups_list;
std::string ip_allow;
bool protocol_unset = true;
unsigned long protocol_mask;
int valid_tls_version_min_in = -1;
int valid_tls_version_max_in = -1;
std::vector<int> tunnel_alpn{};
std::optional<int> http2_buffer_water_mark;
std::optional<int> http2_max_settings_frames_per_minute;
std::optional<int> http2_max_ping_frames_per_minute;
std::optional<int> http2_max_priority_frames_per_minute;
std::optional<int> http2_max_rst_stream_frames_per_minute;
std::optional<int> http2_max_continuation_frames_per_minute;
uint32_t server_max_early_data = 0;
std::optional<int> http2_initial_window_size_in;
std::optional<bool> offer_h2; // Has no value by default, so do not initialize!
std::optional<bool> offer_quic; // Has no value by default, so do not initialize!
uint8_t verify_client_level = 255;
std::string verify_client_ca_file;
std::string verify_client_ca_dir;
uint8_t host_sni_policy = 255;
SNIRoutingType tunnel_type = SNIRoutingType::NONE;
std::string tunnel_destination;
Policy verify_server_policy = Policy::UNSET;
Property verify_server_properties = Property::UNSET;
std::string client_cert;
std::string client_key;
std::string client_sni_policy;
std::string server_cipher_suite;
std::string server_TLSv1_3_cipher_suites;
std::vector<SNIServerGroupsList> server_groups_list;
std::string ip_allow;
bool protocol_unset = true;
unsigned long protocol_mask;
int valid_tls_version_min_in = -1;
int valid_tls_version_max_in = -1;
std::vector<int> tunnel_alpn{};
std::optional<int> http2_buffer_water_mark;
std::optional<int> http2_max_settings_frames_per_minute;
std::optional<int> http2_max_ping_frames_per_minute;
std::optional<int> http2_max_priority_frames_per_minute;
std::optional<int> http2_max_rst_stream_frames_per_minute;
std::optional<int> http2_max_continuation_frames_per_minute;
uint32_t server_max_early_data = 0;
std::optional<int> http2_initial_window_size_in;

bool tunnel_prewarm_srv = false;
uint32_t tunnel_prewarm_min = 0;
Expand Down
24 changes: 21 additions & 3 deletions src/iocore/net/SNIActionPerformer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -516,10 +516,28 @@ ServerGroupsList::SNIAction(SSL &ssl, const Context & /* ctx ATS_UNUSED */) cons
if (tbs == nullptr) {
return SSL_TLSEXT_ERR_OK;
}
Dbg(dbg_ctl_ssl_sni, "Setting groups list from server_groups_list to %s", server_groups_list.c_str());

if (!tbs->set_groups_list(server_groups_list)) {
Error("Invalid server_groups_list: %s", server_groups_list.c_str());
int total = 0;
for (auto const &g : server_groups_list) {
total += g.percentage;
}

int r = random() % total;
int culmative = 0;
std::string group;
for (auto const &g : server_groups_list) {
int start = culmative;
culmative += g.percentage;
if (r >= start && r < culmative) {
group = g.group;
break;
}
}

Dbg(dbg_ctl_ssl_sni, "selecting server group '%s' (rand=%i, total_sum=%i)", group.c_str(), r, total);

if (!tbs->set_groups_list(group)) {
Warning("Invalid server group '%s' in SNI configuration", group.c_str());
return SSL_TLSEXT_ERR_ALERT_WARNING;
}
return SSL_TLSEXT_ERR_OK;
Expand Down
4 changes: 2 additions & 2 deletions src/iocore/net/SNIActionPerformer.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,11 @@ class ServerTLSv1_3CipherSuites : public ActionItem
class ServerGroupsList : public ActionItem
{
public:
ServerGroupsList(std::string const &p) : server_groups_list(p) {}
ServerGroupsList(std::vector<SNIServerGroupsList> const &p) : server_groups_list(p) {}
~ServerGroupsList() override {}

int SNIAction(SSL &ssl, const Context &ctx) const override;

private:
std::string const server_groups_list{};
std::vector<SNIServerGroupsList> const server_groups_list{};
};
16 changes: 15 additions & 1 deletion src/iocore/net/YamlSNIConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,21 @@ template <> struct convert<YamlSNIConfig::Item> {
item.server_TLSv1_3_cipher_suites = node[TS_server_TLSv1_3_cipher_suites].as<std::string>();
}
if (node[TS_server_groups_list]) {
item.server_groups_list = node[TS_server_groups_list].as<std::string>();
SNIServerGroupsList input;
if (node[TS_server_groups_list].IsScalar()) {
input.group = node[TS_server_groups_list].as<std::string>();
item.server_groups_list.emplace_back(input);
} else {
for (auto const &it : node[TS_server_groups_list]) {
if (it["group"]) {
input.group = it["group"].as<std::string>();
}
if (it["percentage"]) {
input.percentage = it["percentage"].as<int>();
}
item.server_groups_list.emplace_back(std::move(input));
}
}
}
if (node[TS_ip_allow]) {
item.ip_allow = node[TS_ip_allow].as<std::string>();
Expand Down