Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions doc/admin-guide/files/records.config.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4272,6 +4272,13 @@ HTTP/2 Configuration
This limit only will be enforced if :ts:cv:`proxy.config.http2.stream_priority_enabled`
is set to 1.

.. ts:cv:: CONFIG proxy.config.http2.max_rst_stream_frames_per_minute INT 14
:reloadable:

Specifies how many RST_STREAM frames |TS| receives for a minute at maximum.
Clients exceeded this limit will be immediately disconnected with an error
code of ENHANCE_YOUR_CALM.

.. ts:cv:: CONFIG proxy.config.http2.min_avg_window_update FLOAT 2560.0
:reloadable:

Expand Down
190 changes: 103 additions & 87 deletions doc/admin-guide/files/sni.yaml.en.rst

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,13 @@ HTTP/2
maximum allowed number of priority frames per minute limit which is configured by
:ts:cv:`proxy.config.http2.max_priority_frames_per_minute`.

.. ts:stat:: global proxy.process.http2.max_rst_stream_frames_per_minute_exceeded integer
:type: counter

Represents the total number of closed HTTP/2 connections for exceeding the
maximum allowed number of rst_stream frames per minute limit which is configured by
:ts:cv:`proxy.config.http2.max_rst_stream_frames_per_minute`.

.. ts:stat:: global proxy.process.http2.insufficient_avg_window_update integer
:type: counter

Expand Down
68 changes: 68 additions & 0 deletions iocore/net/P_SNIActionPerformer.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,74 @@ class HTTP2BufferWaterMark : public ActionItem
int value = -1;
};

class HTTP2MaxSettingsFramesPerMinute : public ActionItem
{
public:
HTTP2MaxSettingsFramesPerMinute(int value) : value(value) {}
~HTTP2MaxSettingsFramesPerMinute() override {}

int
SNIAction(TLSSNISupport *snis, const Context &ctx) const override
{
snis->hints_from_sni.http2_max_settings_frames_per_minute = value;
return SSL_TLSEXT_ERR_OK;
}

private:
int value = -1;
};

class HTTP2MaxPingFramesPerMinute : public ActionItem
{
public:
HTTP2MaxPingFramesPerMinute(int value) : value(value) {}
~HTTP2MaxPingFramesPerMinute() override {}

int
SNIAction(TLSSNISupport *snis, const Context &ctx) const override
{
snis->hints_from_sni.http2_max_ping_frames_per_minute = value;
return SSL_TLSEXT_ERR_OK;
}

private:
int value = -1;
};

class HTTP2MaxPriorityFramesPerMinute : public ActionItem
{
public:
HTTP2MaxPriorityFramesPerMinute(int value) : value(value) {}
~HTTP2MaxPriorityFramesPerMinute() override {}

int
SNIAction(TLSSNISupport *snis, const Context &ctx) const override
{
snis->hints_from_sni.http2_max_priority_frames_per_minute = value;
return SSL_TLSEXT_ERR_OK;
}

private:
int value = -1;
};

class HTTP2MaxRstStreamFramesPerMinute : public ActionItem
{
public:
HTTP2MaxRstStreamFramesPerMinute(int value) : value(value) {}
~HTTP2MaxRstStreamFramesPerMinute() override {}

int
SNIAction(TLSSNISupport *snis, const Context &ctx) const override
{
snis->hints_from_sni.http2_max_rst_stream_frames_per_minute = value;
return SSL_TLSEXT_ERR_OK;
}

private:
int value = -1;
};

class TunnelDestination : public ActionItem
{
public:
Expand Down
13 changes: 13 additions & 0 deletions iocore/net/SSLSNIConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,19 @@ SNIConfigParams::load_sni_config()
if (item.http2_buffer_water_mark.has_value()) {
ai->actions.push_back(std::make_unique<HTTP2BufferWaterMark>(item.http2_buffer_water_mark.value()));
}
if (item.http2_max_settings_frames_per_minute.has_value()) {
ai->actions.push_back(std::make_unique<HTTP2MaxSettingsFramesPerMinute>(item.http2_max_settings_frames_per_minute.value()));
}
if (item.http2_max_ping_frames_per_minute.has_value()) {
ai->actions.push_back(std::make_unique<HTTP2MaxPingFramesPerMinute>(item.http2_max_ping_frames_per_minute.value()));
}
if (item.http2_max_priority_frames_per_minute.has_value()) {
ai->actions.push_back(std::make_unique<HTTP2MaxPriorityFramesPerMinute>(item.http2_max_priority_frames_per_minute.value()));
}
if (item.http2_max_rst_stream_frames_per_minute.has_value()) {
ai->actions.push_back(
std::make_unique<HTTP2MaxRstStreamFramesPerMinute>(item.http2_max_rst_stream_frames_per_minute.value()));
}

ai->actions.push_back(std::make_unique<SNI_IpAllow>(item.ip_allow, item.fqdn));

Expand Down
4 changes: 4 additions & 0 deletions iocore/net/TLSSNISupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class TLSSNISupport

struct HintsFromSNI {
std::optional<uint32_t> http2_buffer_water_mark;
std::optional<uint32_t> http2_max_settings_frames_per_minute;
std::optional<uint32_t> http2_max_ping_frames_per_minute;
std::optional<uint32_t> http2_max_priority_frames_per_minute;
std::optional<uint32_t> http2_max_rst_stream_frames_per_minute;
} hints_from_sni;

protected:
Expand Down
16 changes: 16 additions & 0 deletions iocore/net/YamlSNIConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ std::set<std::string> valid_sni_config_keys = {TS_fqdn,
TS_client_sni_policy,
TS_http2,
TS_http2_buffer_water_mark,
TS_http2_max_settings_frames_per_minute,
TS_http2_max_ping_frames_per_minute,
TS_http2_max_priority_frames_per_minute,
TS_http2_max_rst_stream_frames_per_minute,
TS_ip_allow,
#if TS_USE_HELLO_CB || defined(OPENSSL_IS_BORINGSSL)
TS_valid_tls_versions_in,
Expand Down Expand Up @@ -177,6 +181,18 @@ template <> struct convert<YamlSNIConfig::Item> {
if (node[TS_http2_buffer_water_mark]) {
item.http2_buffer_water_mark = node[TS_http2_buffer_water_mark].as<int>();
}
if (node[TS_http2_max_settings_frames_per_minute]) {
item.http2_max_settings_frames_per_minute = node[TS_http2_max_settings_frames_per_minute].as<int>();
}
if (node[TS_http2_max_ping_frames_per_minute]) {
item.http2_max_ping_frames_per_minute = node[TS_http2_max_ping_frames_per_minute].as<int>();
}
if (node[TS_http2_max_priority_frames_per_minute]) {
item.http2_max_priority_frames_per_minute = node[TS_http2_max_priority_frames_per_minute].as<int>();
}
if (node[TS_http2_max_rst_stream_frames_per_minute]) {
item.http2_max_rst_stream_frames_per_minute = node[TS_http2_max_rst_stream_frames_per_minute].as<int>();
}

// enum
if (node[TS_verify_client]) {
Expand Down
8 changes: 8 additions & 0 deletions iocore/net/YamlSNIConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ TSDECL(ip_allow);
TSDECL(valid_tls_versions_in);
TSDECL(http2);
TSDECL(http2_buffer_water_mark);
TSDECL(http2_max_settings_frames_per_minute);
TSDECL(http2_max_ping_frames_per_minute);
TSDECL(http2_max_priority_frames_per_minute);
TSDECL(http2_max_rst_stream_frames_per_minute);
TSDECL(host_sni_policy);
#undef TSDECL

Expand Down Expand Up @@ -86,6 +90,10 @@ struct YamlSNIConfig {
unsigned long protocol_mask;
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;

bool tunnel_prewarm_srv = false;
uint32_t tunnel_prewarm_min = 0;
Expand Down
2 changes: 2 additions & 0 deletions mgmt/RecordsConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1391,6 +1391,8 @@ static const RecordElement RecordsConfig[] =
,
{RECT_CONFIG, "proxy.config.http2.max_priority_frames_per_minute", RECD_INT, "120", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL}
,
{RECT_CONFIG, "proxy.config.http2.max_rst_stream_frames_per_minute", RECD_INT, "200", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL}
,
{RECT_CONFIG, "proxy.config.http2.min_avg_window_update", RECD_FLOAT, "2560.0", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
,
{RECT_CONFIG, "proxy.config.http2.header_table_size_limit", RECD_INT, "65536", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL}
Expand Down
64 changes: 35 additions & 29 deletions proxy/http2/HTTP2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ static const char *const HTTP2_STAT_MAX_PING_FRAMES_PER_MINUTE_EXCEEDED_NAME =
"proxy.process.http2.max_ping_frames_per_minute_exceeded";
static const char *const HTTP2_STAT_MAX_PRIORITY_FRAMES_PER_MINUTE_EXCEEDED_NAME =
"proxy.process.http2.max_priority_frames_per_minute_exceeded";
static const char *const HTTP2_STAT_MAX_RST_STREAM_FRAMES_PER_MINUTE_EXCEEDED_NAME =
"proxy.process.http2.max_rst_stream_frames_per_minute_exceeded";
static const char *const HTTP2_STAT_INSUFFICIENT_AVG_WINDOW_UPDATE_NAME = "proxy.process.http2.insufficient_avg_window_update";
static const char *const HTTP2_STAT_MAX_CONCURRENT_STREAMS_EXCEEDED_IN_NAME =
"proxy.process.http2.max_concurrent_streams_exceeded_in";
Expand Down Expand Up @@ -796,35 +798,36 @@ http2_decode_header_blocks(HTTPHdr *hdr, const uint8_t *buf_start, const uint32_
}

// Initialize this subsystem with librecords configs (for now)
uint32_t Http2::max_concurrent_streams_in = 100;
uint32_t Http2::min_concurrent_streams_in = 10;
uint32_t Http2::max_active_streams_in = 0;
bool Http2::throttling = false;
uint32_t Http2::stream_priority_enabled = 0;
uint32_t Http2::initial_window_size = 65535;
uint32_t Http2::max_frame_size = 16384;
uint32_t Http2::header_table_size = 4096;
uint32_t Http2::max_header_list_size = 4294967295;
uint32_t Http2::accept_no_activity_timeout = 120;
uint32_t Http2::no_activity_timeout_in = 120;
uint32_t Http2::active_timeout_in = 0;
uint32_t Http2::push_diary_size = 256;
uint32_t Http2::zombie_timeout_in = 0;
float Http2::stream_error_rate_threshold = 0.1;
uint32_t Http2::stream_error_sampling_threshold = 10;
uint32_t Http2::max_settings_per_frame = 7;
uint32_t Http2::max_settings_per_minute = 14;
uint32_t Http2::max_settings_frames_per_minute = 14;
uint32_t Http2::max_ping_frames_per_minute = 60;
uint32_t Http2::max_priority_frames_per_minute = 120;
float Http2::min_avg_window_update = 2560.0;
uint32_t Http2::con_slow_log_threshold = 0;
uint32_t Http2::stream_slow_log_threshold = 0;
uint32_t Http2::header_table_size_limit = 65536;
uint32_t Http2::write_buffer_block_size = 262144;
float Http2::write_size_threshold = 0.5;
uint32_t Http2::write_time_threshold = 100;
uint32_t Http2::buffer_water_mark = 0;
uint32_t Http2::max_concurrent_streams_in = 100;
uint32_t Http2::min_concurrent_streams_in = 10;
uint32_t Http2::max_active_streams_in = 0;
bool Http2::throttling = false;
uint32_t Http2::stream_priority_enabled = 0;
uint32_t Http2::initial_window_size = 65535;
uint32_t Http2::max_frame_size = 16384;
uint32_t Http2::header_table_size = 4096;
uint32_t Http2::max_header_list_size = 4294967295;
uint32_t Http2::accept_no_activity_timeout = 120;
uint32_t Http2::no_activity_timeout_in = 120;
uint32_t Http2::active_timeout_in = 0;
uint32_t Http2::push_diary_size = 256;
uint32_t Http2::zombie_timeout_in = 0;
float Http2::stream_error_rate_threshold = 0.1;
uint32_t Http2::stream_error_sampling_threshold = 10;
uint32_t Http2::max_settings_per_frame = 7;
uint32_t Http2::max_settings_per_minute = 14;
uint32_t Http2::max_settings_frames_per_minute = 14;
uint32_t Http2::max_ping_frames_per_minute = 60;
uint32_t Http2::max_priority_frames_per_minute = 120;
uint32_t Http2::max_rst_stream_frames_per_minute = 200;
float Http2::min_avg_window_update = 2560.0;
uint32_t Http2::con_slow_log_threshold = 0;
uint32_t Http2::stream_slow_log_threshold = 0;
uint32_t Http2::header_table_size_limit = 65536;
uint32_t Http2::write_buffer_block_size = 262144;
float Http2::write_size_threshold = 0.5;
uint32_t Http2::write_time_threshold = 100;
uint32_t Http2::buffer_water_mark = 0;

void
Http2::init()
Expand All @@ -849,6 +852,7 @@ Http2::init()
REC_EstablishStaticConfigInt32U(max_settings_frames_per_minute, "proxy.config.http2.max_settings_frames_per_minute");
REC_EstablishStaticConfigInt32U(max_ping_frames_per_minute, "proxy.config.http2.max_ping_frames_per_minute");
REC_EstablishStaticConfigInt32U(max_priority_frames_per_minute, "proxy.config.http2.max_priority_frames_per_minute");
REC_EstablishStaticConfigInt32U(max_rst_stream_frames_per_minute, "proxy.config.http2.max_rst_stream_frames_per_minute");
REC_EstablishStaticConfigFloat(min_avg_window_update, "proxy.config.http2.min_avg_window_update");
REC_EstablishStaticConfigInt32U(con_slow_log_threshold, "proxy.config.http2.connection.slow.log.threshold");
REC_EstablishStaticConfigInt32U(stream_slow_log_threshold, "proxy.config.http2.stream.slow.log.threshold");
Expand Down Expand Up @@ -917,6 +921,8 @@ Http2::init()
static_cast<int>(HTTP2_STAT_MAX_PING_FRAMES_PER_MINUTE_EXCEEDED), RecRawStatSyncSum);
RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_MAX_PRIORITY_FRAMES_PER_MINUTE_EXCEEDED_NAME, RECD_INT, RECP_PERSISTENT,
static_cast<int>(HTTP2_STAT_MAX_PRIORITY_FRAMES_PER_MINUTE_EXCEEDED), RecRawStatSyncSum);
RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_MAX_RST_STREAM_FRAMES_PER_MINUTE_EXCEEDED_NAME, RECD_INT, RECP_PERSISTENT,
static_cast<int>(HTTP2_STAT_MAX_RST_STREAM_FRAMES_PER_MINUTE_EXCEEDED), RecRawStatSyncSum);
RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_INSUFFICIENT_AVG_WINDOW_UPDATE_NAME, RECD_INT, RECP_PERSISTENT,
static_cast<int>(HTTP2_STAT_INSUFFICIENT_AVG_WINDOW_UPDATE), RecRawStatSyncSum);
RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_MAX_CONCURRENT_STREAMS_EXCEEDED_IN_NAME, RECD_INT, RECP_PERSISTENT,
Expand Down
2 changes: 2 additions & 0 deletions proxy/http2/HTTP2.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ enum {
HTTP2_STAT_MAX_SETTINGS_FRAMES_PER_MINUTE_EXCEEDED,
HTTP2_STAT_MAX_PING_FRAMES_PER_MINUTE_EXCEEDED,
HTTP2_STAT_MAX_PRIORITY_FRAMES_PER_MINUTE_EXCEEDED,
HTTP2_STAT_MAX_RST_STREAM_FRAMES_PER_MINUTE_EXCEEDED,
HTTP2_STAT_INSUFFICIENT_AVG_WINDOW_UPDATE,
HTTP2_STAT_MAX_CONCURRENT_STREAMS_EXCEEDED_IN,
HTTP2_STAT_MAX_CONCURRENT_STREAMS_EXCEEDED_OUT,
Expand Down Expand Up @@ -402,6 +403,7 @@ class Http2
static uint32_t max_settings_frames_per_minute;
static uint32_t max_ping_frames_per_minute;
static uint32_t max_priority_frames_per_minute;
static uint32_t max_rst_stream_frames_per_minute;
static float min_avg_window_update;
static uint32_t con_slow_log_threshold;
static uint32_t stream_slow_log_threshold;
Expand Down
Loading