This is an automated email from the ASF dual-hosted git repository. cmcfarlen pushed a commit to branch 10.0.x in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit 62355fb177d18ea566c5a30df775b41d9e4c14b5 Author: Masakazu Kitajo <[email protected]> AuthorDate: Wed Jul 17 14:04:34 2024 -0600 Add HTTP/2 Empty CONTINUATION & DATA frame counter (#11345) * HTTP/2 Empty CONTINUATION & DATA frame counter * Allow using 0 as a valid limit value and use negative numbers as unlimited * Don't return early if CONTINUATION frame is empty * Fix typos * Add documentation about proxy.config.http2.max_empty_frames_per_minute * Add documentation about http2_max_empty_frames_per_minute in sni.yaml * Fix errors from rebasing * Documentation * Improve wording --------- Co-authored-by: Masaori Koshiba <[email protected]> (cherry picked from commit 21581ecbf1cc441cfb6fab4f935b326107963ced) --- doc/admin-guide/files/records.yaml.en.rst | 19 +++++++++ doc/admin-guide/files/sni.yaml.en.rst | 4 ++ include/iocore/net/TLSSNISupport.h | 10 ++--- include/proxy/http2/HTTP2.h | 16 ++++---- include/proxy/http2/Http2ConnectionState.h | 14 ++++--- src/proxy/http2/HTTP2.cc | 32 ++++++++------- src/proxy/http2/Http2ConnectionState.cc | 66 +++++++++++++++++++++++------- src/records/RecordsConfig.cc | 14 ++++--- 8 files changed, 124 insertions(+), 51 deletions(-) diff --git a/doc/admin-guide/files/records.yaml.en.rst b/doc/admin-guide/files/records.yaml.en.rst index 198b014e4f..19d6dbd144 100644 --- a/doc/admin-guide/files/records.yaml.en.rst +++ b/doc/admin-guide/files/records.yaml.en.rst @@ -4546,6 +4546,7 @@ HTTP/2 Configuration Specifies how many settings in an HTTP/2 SETTINGS frame |TS| accepts. Clients exceeded this limit will be immediately disconnected with an error code of ENHANCE_YOUR_CALM. + Any negative value configures no limit to the number of settings received. .. ts:cv:: CONFIG proxy.config.http2.max_settings_per_minute INT 14 :reloadable: @@ -4553,6 +4554,7 @@ HTTP/2 Configuration Specifies how many settings in HTTP/2 SETTINGS frames |TS| accept for a minute. Clients exceeded this limit will be immediately disconnected with an error code of ENHANCE_YOUR_CALM. + Any negative value configures no limit to the number of settings received. .. ts:cv:: CONFIG proxy.config.http2.max_settings_frames_per_minute INT 14 :reloadable: @@ -4560,6 +4562,7 @@ HTTP/2 Configuration Specifies how many SETTINGS frames |TS| receives for a minute at maximum. Clients exceeded this limit will be immediately disconnected with an error code of ENHANCE_YOUR_CALM. + Any negative value configures no limit to the number of SETTINGS frames received. .. ts:cv:: CONFIG proxy.config.http2.max_ping_frames_per_minute INT 60 :reloadable: @@ -4567,6 +4570,7 @@ HTTP/2 Configuration Specifies how many number of PING frames |TS| receives for a minute at maximum. Clients exceeded this limit will be immediately disconnected with an error code of ENHANCE_YOUR_CALM. + Any negative value configures no limit to the number of PING frames received. .. ts:cv:: CONFIG proxy.config.http2.max_priority_frames_per_minute INT 120 :reloadable: @@ -4576,6 +4580,7 @@ HTTP/2 Configuration code of ENHANCE_YOUR_CALM. If this is set to 0, the limit logic is disabled. This limit only will be enforced if :ts:cv:`proxy.config.http2.stream_priority_enabled` is set to 1. + Any negative value configures no limit to the number of PRIORITY frames received. .. ts:cv:: CONFIG proxy.config.http2.max_rst_stream_frames_per_minute INT 200 :reloadable: @@ -4583,6 +4588,7 @@ HTTP/2 Configuration Specifies how many RST_STREAM frames |TS| receives per minute at maximum. Clients exceeding this limit will be immediately disconnected with an error code of ENHANCE_YOUR_CALM. + Any negative value configures no limit to the number of RST_STREAM frames received. .. ts:cv:: CONFIG proxy.config.http2.max_continuation_frames_per_minute INT 120 :reloadable: @@ -4590,6 +4596,19 @@ HTTP/2 Configuration Specifies how many CONTINUATION frames |TS| receives per minute at maximum. Clients exceeding this limit will be immediately disconnected with an error code of ENHANCE_YOUR_CALM. + Any negative value configures no limit to the number of CONTINUATION frames received. + +.. ts:cv:: CONFIG proxy.config.http2.max_empty_frames_per_minute INT 0 + :reloadable: + + Specifies the maximum number of empty frames |TS| will receive per minute before it will start closing connections. + In this context, an "empty frame" means either a DATA frame that does not carry a payload + nor an END_STREAM flag, or a CONTINUATION frame that does not carry payload + nor an END_HEADERS flag. + Clients exceeding this limit will be immediately disconnected with an error + code of ENHANCE_YOUR_CALM. + Any negative value configures no limit to the number of empty frames received. + ``0`` is the default configuration, meaning that no empty frames are allowed. .. ts:cv:: CONFIG proxy.config.http2.min_avg_window_update FLOAT 2560.0 :reloadable: diff --git a/doc/admin-guide/files/sni.yaml.en.rst b/doc/admin-guide/files/sni.yaml.en.rst index 7be40de811..191fefb010 100644 --- a/doc/admin-guide/files/sni.yaml.en.rst +++ b/doc/admin-guide/files/sni.yaml.en.rst @@ -228,6 +228,10 @@ http2_max_continuation_frames_per_minute Inbound Specifies how many CONTINUATI By default this is :ts:cv:`proxy.config.http2.max_continuation_frames_per_minute`. NOTE: Connection coalescing may prevent this from taking effect. +http2_max_empty_frames_per_minute Inbound Specifies how many empty frames |TS| receives per minute at maximum. + By default this is :ts:cv:`proxy.config.http2.max_empty_frames_per_minute`. + NOTE: Connection coalescing may prevent this from taking effect. + quic Inbound Indicates whether QUIC connections should be accepted. The valid values are :code:`on` or :code:`off`. Note that this is a more specific setting to configure QUIC availability per server name. More broadly, you will also need to configure :ts:cv:`proxy.config.http.server_ports` to diff --git a/include/iocore/net/TLSSNISupport.h b/include/iocore/net/TLSSNISupport.h index 060b60c826..1e6685276f 100644 --- a/include/iocore/net/TLSSNISupport.h +++ b/include/iocore/net/TLSSNISupport.h @@ -61,11 +61,11 @@ public: std::optional<uint32_t> http2_buffer_water_mark; std::optional<uint32_t> server_max_early_data; std::optional<uint32_t> http2_initial_window_size_in; - 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; - std::optional<uint32_t> http2_max_continuation_frames_per_minute; + std::optional<int32_t> http2_max_settings_frames_per_minute; + std::optional<int32_t> http2_max_ping_frames_per_minute; + std::optional<int32_t> http2_max_priority_frames_per_minute; + std::optional<int32_t> http2_max_rst_stream_frames_per_minute; + std::optional<int32_t> http2_max_continuation_frames_per_minute; std::optional<std::string_view> outbound_sni_policy; } hints_from_sni; diff --git a/include/proxy/http2/HTTP2.h b/include/proxy/http2/HTTP2.h index 11c60ec35f..9f3c62b97e 100644 --- a/include/proxy/http2/HTTP2.h +++ b/include/proxy/http2/HTTP2.h @@ -104,6 +104,7 @@ struct Http2StatsBlock { Metrics::Counter::AtomicType *max_priority_frames_per_minute_exceeded; Metrics::Counter::AtomicType *max_rst_stream_frames_per_minute_exceeded; Metrics::Counter::AtomicType *max_continuation_frames_per_minute_exceeded; + Metrics::Counter::AtomicType *max_empty_frames_per_minute_exceeded; Metrics::Counter::AtomicType *insufficient_avg_window_update; Metrics::Counter::AtomicType *max_concurrent_streams_exceeded_in; Metrics::Counter::AtomicType *max_concurrent_streams_exceeded_out; @@ -423,13 +424,14 @@ public: static float stream_error_rate_threshold; static uint32_t stream_error_sampling_threshold; - static uint32_t max_settings_per_frame; - static uint32_t max_settings_per_minute; - 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 uint32_t max_continuation_frames_per_minute; + static int32_t max_settings_per_frame; + static int32_t max_settings_per_minute; + static int32_t max_settings_frames_per_minute; + static int32_t max_ping_frames_per_minute; + static int32_t max_priority_frames_per_minute; + static int32_t max_rst_stream_frames_per_minute; + static int32_t max_continuation_frames_per_minute; + static int32_t max_empty_frames_per_minute; static float min_avg_window_update; static uint32_t con_slow_log_threshold; static uint32_t stream_slow_log_threshold; diff --git a/include/proxy/http2/Http2ConnectionState.h b/include/proxy/http2/Http2ConnectionState.h index 0681fddeed..289918754c 100644 --- a/include/proxy/http2/Http2ConnectionState.h +++ b/include/proxy/http2/Http2ConnectionState.h @@ -201,6 +201,8 @@ public: uint32_t get_received_rst_stream_frame_count(); void increment_received_continuation_frame_count(); uint32_t get_received_continuation_frame_count(); + void increment_received_empty_frame_count(); + uint32_t get_received_empty_frame_count(); ssize_t get_peer_rwnd() const; Http2ErrorCode increment_peer_rwnd(size_t amount); @@ -336,6 +338,7 @@ private: FrequencyCounter _received_priority_frame_counter; FrequencyCounter _received_rst_stream_frame_counter; FrequencyCounter _received_continuation_frame_counter; + FrequencyCounter _received_empty_frame_counter; /** Records the various settings for each SETTINGS frame that we've sent. * @@ -405,11 +408,12 @@ private: Event *_data_event = nullptr; Event *retransmit_event = nullptr; - uint32_t configured_max_settings_frames_per_minute = 0; - uint32_t configured_max_ping_frames_per_minute = 0; - uint32_t configured_max_priority_frames_per_minute = 0; - uint32_t configured_max_rst_stream_frames_per_minute = 0; - uint32_t configured_max_continuation_frames_per_minute = 0; + int32_t configured_max_settings_frames_per_minute = 0; + int32_t configured_max_ping_frames_per_minute = 0; + int32_t configured_max_priority_frames_per_minute = 0; + int32_t configured_max_rst_stream_frames_per_minute = 0; + int32_t configured_max_continuation_frames_per_minute = 0; + int32_t configured_max_empty_frames_per_minute = 0; }; /////////////////////////////////////////////// diff --git a/src/proxy/http2/HTTP2.cc b/src/proxy/http2/HTTP2.cc index a28284588d..8323b05352 100644 --- a/src/proxy/http2/HTTP2.cc +++ b/src/proxy/http2/HTTP2.cc @@ -486,13 +486,14 @@ uint32_t Http2::no_activity_timeout_out = 120; 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; -uint32_t Http2::max_continuation_frames_per_minute = 120; +int32_t Http2::max_settings_per_frame = 7; +int32_t Http2::max_settings_per_minute = 14; +int32_t Http2::max_settings_frames_per_minute = 14; +int32_t Http2::max_ping_frames_per_minute = 60; +int32_t Http2::max_priority_frames_per_minute = 120; +int32_t Http2::max_rst_stream_frames_per_minute = 200; +int32_t Http2::max_continuation_frames_per_minute = 120; +int32_t Http2::max_empty_frames_per_minute = 0; float Http2::min_avg_window_update = 2560.0; uint32_t Http2::con_slow_log_threshold = 0; uint32_t Http2::stream_slow_log_threshold = 0; @@ -544,13 +545,14 @@ Http2::init() REC_EstablishStaticConfigInt32U(zombie_timeout_in, "proxy.config.http2.zombie_debug_timeout_in"); REC_EstablishStaticConfigFloat(stream_error_rate_threshold, "proxy.config.http2.stream_error_rate_threshold"); REC_EstablishStaticConfigInt32U(stream_error_sampling_threshold, "proxy.config.http2.stream_error_sampling_threshold"); - REC_EstablishStaticConfigInt32U(max_settings_per_frame, "proxy.config.http2.max_settings_per_frame"); - REC_EstablishStaticConfigInt32U(max_settings_per_minute, "proxy.config.http2.max_settings_per_minute"); - 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_EstablishStaticConfigInt32U(max_continuation_frames_per_minute, "proxy.config.http2.max_continuation_frames_per_minute"); + REC_EstablishStaticConfigInt32(max_settings_per_frame, "proxy.config.http2.max_settings_per_frame"); + REC_EstablishStaticConfigInt32(max_settings_per_minute, "proxy.config.http2.max_settings_per_minute"); + REC_EstablishStaticConfigInt32(max_settings_frames_per_minute, "proxy.config.http2.max_settings_frames_per_minute"); + REC_EstablishStaticConfigInt32(max_ping_frames_per_minute, "proxy.config.http2.max_ping_frames_per_minute"); + REC_EstablishStaticConfigInt32(max_priority_frames_per_minute, "proxy.config.http2.max_priority_frames_per_minute"); + REC_EstablishStaticConfigInt32(max_rst_stream_frames_per_minute, "proxy.config.http2.max_rst_stream_frames_per_minute"); + REC_EstablishStaticConfigInt32(max_continuation_frames_per_minute, "proxy.config.http2.max_continuation_frames_per_minute"); + REC_EstablishStaticConfigInt32(max_empty_frames_per_minute, "proxy.config.http2.max_empty_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"); @@ -607,6 +609,8 @@ Http2::init() Metrics::Counter::createPtr("proxy.process.http2.max_rst_stream_frames_per_minute_exceeded"); http2_rsb.max_continuation_frames_per_minute_exceeded = Metrics::Counter::createPtr("proxy.process.http2.max_continuation_frames_per_minute_exceeded"); + http2_rsb.max_empty_frames_per_minute_exceeded = + Metrics::Counter::createPtr("proxy.process.http2.max_empty_frames_per_minute_exceeded"); http2_rsb.insufficient_avg_window_update = Metrics::Counter::createPtr("proxy.process.http2.insufficient_avg_window_update"); http2_rsb.max_concurrent_streams_exceeded_in = Metrics::Counter::createPtr("proxy.process.http2.max_concurrent_streams_exceeded_in"); diff --git a/src/proxy/http2/Http2ConnectionState.cc b/src/proxy/http2/Http2ConnectionState.cc index d4e1ac6f2d..affbf0b813 100644 --- a/src/proxy/http2/Http2ConnectionState.cc +++ b/src/proxy/http2/Http2ConnectionState.cc @@ -184,8 +184,19 @@ Http2ConnectionState::rcv_data_frame(const Http2Frame &frame) stream->set_trailing_header_is_possible(); } - // If payload length is 0 without END_STREAM flag, do nothing - if (payload_length == 0 && !stream->receive_end_stream) { + // If payload length is 0 without END_STREAM flag, just count it + const uint32_t unpadded_length = payload_length - pad_length; + if (unpadded_length == 0 && !stream->receive_end_stream) { + this->increment_received_empty_frame_count(); + if (configured_max_empty_frames_per_minute >= 0 && + this->get_received_empty_frame_count() > static_cast<uint32_t>(configured_max_empty_frames_per_minute)) { + Metrics::Counter::increment(http2_rsb.max_empty_frames_per_minute_exceeded); + Http2StreamDebug(this->session, id, "Observed too many empty DATA frames: %u within the last minute", + this->get_received_empty_frame_count()); + return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM, + "recv data too frequent empty frame"); + } + return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_NONE); } @@ -211,8 +222,7 @@ Http2ConnectionState::rcv_data_frame(const Http2Frame &frame) this->get_local_rwnd(), session_window, stream->get_local_rwnd(), stream_window); } - const uint32_t unpadded_length = payload_length - pad_length; - MIOBuffer *writer = stream->read_vio_writer(); + MIOBuffer *writer = stream->read_vio_writer(); if (writer == nullptr) { return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_INTERNAL_ERROR, "no writer"); } @@ -573,8 +583,8 @@ Http2ConnectionState::rcv_priority_frame(const Http2Frame &frame) // Update PRIORITY frame count per minute this->increment_received_priority_frame_count(); // Close this connection if its priority frame count received exceeds a limit - if (configured_max_priority_frames_per_minute != 0 && - this->get_received_priority_frame_count() > configured_max_priority_frames_per_minute) { + if (configured_max_priority_frames_per_minute >= 0 && + this->get_received_priority_frame_count() > static_cast<uint32_t>(configured_max_priority_frames_per_minute)) { Metrics::Counter::increment(http2_rsb.max_priority_frames_per_minute_exceeded); Http2StreamDebug(this->session, stream_id, "Observed too frequent priority changes: %u priority changes within a last minute", this->get_received_priority_frame_count()); @@ -648,8 +658,8 @@ Http2ConnectionState::rcv_rst_stream_frame(const Http2Frame &frame) // Update RST_STREAM frame count per minute this->increment_received_rst_stream_frame_count(); // Close this connection if its RST_STREAM frame count exceeds a limit - if (configured_max_rst_stream_frames_per_minute != 0 && - this->get_received_rst_stream_frame_count() > configured_max_rst_stream_frames_per_minute) { + if (configured_max_rst_stream_frames_per_minute >= 0 && + this->get_received_rst_stream_frame_count() > static_cast<uint32_t>(configured_max_rst_stream_frames_per_minute)) { Metrics::Counter::increment(http2_rsb.max_rst_stream_frames_per_minute_exceeded); Http2StreamDebug(this->session, stream_id, "Observed too frequent RST_STREAM frames: %u frames within a last minute", this->get_received_rst_stream_frame_count()); @@ -697,8 +707,8 @@ Http2ConnectionState::rcv_settings_frame(const Http2Frame &frame) // Update SETTINGS frame count per minute this->increment_received_settings_frame_count(); // Close this connection if its SETTINGS frame count exceeds a limit - if (configured_max_settings_frames_per_minute != 0 && - this->get_received_settings_frame_count() > configured_max_settings_frames_per_minute) { + if (configured_max_settings_frames_per_minute >= 0 && + this->get_received_settings_frame_count() > static_cast<uint32_t>(configured_max_settings_frames_per_minute)) { Metrics::Counter::increment(http2_rsb.max_settings_frames_per_minute_exceeded); Http2StreamDebug(this->session, stream_id, "Observed too frequent SETTINGS frames: %u frames within a last minute", this->get_received_settings_frame_count()); @@ -738,7 +748,7 @@ Http2ConnectionState::rcv_settings_frame(const Http2Frame &frame) uint32_t n_settings = 0; while (nbytes < frame.header().length) { - if (n_settings >= Http2::max_settings_per_frame) { + if (Http2::max_settings_per_frame >= 0 && n_settings >= static_cast<uint32_t>(Http2::max_settings_per_frame)) { Metrics::Counter::increment(http2_rsb.max_settings_per_frame_exceeded); Http2StreamDebug(this->session, stream_id, "Observed too many settings in a frame"); return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM, @@ -779,7 +789,8 @@ Http2ConnectionState::rcv_settings_frame(const Http2Frame &frame) // Update settings count per minute this->increment_received_settings_count(n_settings); // Close this connection if its settings count received exceeds a limit - if (this->get_received_settings_count() > Http2::max_settings_per_minute) { + if (Http2::max_settings_per_frame >= 0 && + this->get_received_settings_count() > static_cast<uint32_t>(Http2::max_settings_per_minute)) { Metrics::Counter::increment(http2_rsb.max_settings_per_minute_exceeded); Http2StreamDebug(this->session, stream_id, "Observed too frequent setting changes: %u settings within a last minute", this->get_received_settings_count()); @@ -833,7 +844,8 @@ Http2ConnectionState::rcv_ping_frame(const Http2Frame &frame) // Update PING frame count per minute this->increment_received_ping_frame_count(); // Close this connection if its ping count received exceeds a limit - if (configured_max_ping_frames_per_minute != 0 && this->get_received_ping_frame_count() > configured_max_ping_frames_per_minute) { + if (configured_max_ping_frames_per_minute >= 0 && + this->get_received_ping_frame_count() > static_cast<uint32_t>(configured_max_ping_frames_per_minute)) { Metrics::Counter::increment(http2_rsb.max_ping_frames_per_minute_exceeded); Http2StreamDebug(this->session, stream_id, "Observed too frequent PING frames: %u PING frames within a last minute", this->get_received_ping_frame_count()); @@ -1002,6 +1014,18 @@ Http2ConnectionState::rcv_continuation_frame(const Http2Frame &frame) "continuation bad client id"); } + if (payload_length == 0 && (frame.header().flags & HTTP2_FLAGS_HEADERS_END_HEADERS) == 0x0) { + this->increment_received_empty_frame_count(); + if (configured_max_empty_frames_per_minute >= 0 && + this->get_received_empty_frame_count() > static_cast<uint32_t>(configured_max_empty_frames_per_minute)) { + Metrics::Counter::increment(http2_rsb.max_empty_frames_per_minute_exceeded); + Http2StreamDebug(this->session, stream_id, "Observed too many empty CONTINUATION frames: %u within the last minute", + this->get_received_empty_frame_count()); + return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM, + "recv continuation too frequent empty frame"); + } + } + // Find opened stream // CONTINUATION frames MUST be associated with a stream. If a // CONTINUATION frame is received whose stream identifier field is 0x0, @@ -1033,7 +1057,7 @@ Http2ConnectionState::rcv_continuation_frame(const Http2Frame &frame) this->increment_received_continuation_frame_count(); // Close this connection if its CONTINUATION frame count exceeds a limit. if (configured_max_continuation_frames_per_minute != 0 && - this->get_received_continuation_frame_count() > configured_max_continuation_frames_per_minute) { + this->get_received_continuation_frame_count() > static_cast<uint32_t>(configured_max_continuation_frames_per_minute)) { Metrics::Counter::increment(http2_rsb.max_continuation_frames_per_minute_exceeded); Http2StreamDebug(this->session, stream_id, "Observed too frequent CONTINUATION frames: %u frames within a last minute", this->get_received_continuation_frame_count()); @@ -1287,6 +1311,8 @@ Http2ConnectionState::init(Http2CommonSession *ssn) configured_max_priority_frames_per_minute = Http2::max_priority_frames_per_minute; configured_max_rst_stream_frames_per_minute = Http2::max_rst_stream_frames_per_minute; configured_max_continuation_frames_per_minute = Http2::max_continuation_frames_per_minute; + configured_max_empty_frames_per_minute = Http2::max_empty_frames_per_minute; + if (auto snis = session->get_netvc()->get_service<TLSSNISupport>(); snis) { if (snis->hints_from_sni.http2_max_settings_frames_per_minute.has_value()) { configured_max_settings_frames_per_minute = snis->hints_from_sni.http2_max_settings_frames_per_minute.value(); @@ -2798,6 +2824,18 @@ Http2ConnectionState::get_received_continuation_frame_count() return this->_received_continuation_frame_counter.get_count(); } +void +Http2ConnectionState::increment_received_empty_frame_count() +{ + this->_received_empty_frame_counter.increment(); +} + +uint32_t +Http2ConnectionState::get_received_empty_frame_count() +{ + return this->_received_empty_frame_counter.get_count(); +} + // Return min_concurrent_streams_in when current client streams number is larger than max_active_streams_in. // Main purpose of this is preventing DDoS Attacks. unsigned diff --git a/src/records/RecordsConfig.cc b/src/records/RecordsConfig.cc index 4955ee7de3..899a6d3c76 100644 --- a/src/records/RecordsConfig.cc +++ b/src/records/RecordsConfig.cc @@ -1304,17 +1304,19 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.http2.stream_error_sampling_threshold", RECD_INT, "10", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.http2.max_settings_per_frame", RECD_INT, "7", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.http2.max_settings_per_frame", RECD_INT, "7", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.http2.max_settings_per_minute", RECD_INT, "14", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.http2.max_settings_per_minute", RECD_INT, "14", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.http2.max_settings_frames_per_minute", RECD_INT, "14", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.http2.max_settings_frames_per_minute", RECD_INT, "14", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {RECT_CONFIG, "proxy.config.http2.max_ping_frames_per_minute", RECD_INT, "60", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} + {RECT_CONFIG, "proxy.config.http2.max_ping_frames_per_minute", RECD_INT, "60", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , - {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_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.max_rst_stream_frames_per_minute", RECD_INT, "200", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} + , + {RECT_CONFIG, "proxy.config.http2.max_empty_frames_per_minute", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^-?[0-9]+$", RECA_NULL} , {RECT_CONFIG, "proxy.config.http2.max_continuation_frames_per_minute", RECD_INT, "120", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} ,
