This is an automated email from the ASF dual-hosted git repository.
maskit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new e0620eb941 proxy.config.http2.max_continuation_frames_per_minute
(#11205)
e0620eb941 is described below
commit e0620eb941eab2603b2c230366e0fae5eeb6b57d
Author: Masakazu Kitajo <[email protected]>
AuthorDate: Wed Apr 3 09:40:14 2024 -0600
proxy.config.http2.max_continuation_frames_per_minute (#11205)
This adds the ability to rate limite HTTP/2 CONTINUATION frames per
stream per minute.
Co-authored-by: Brian Neradt <[email protected]>
---
doc/admin-guide/files/records.yaml.en.rst | 11 +-
doc/admin-guide/files/sni.yaml.en.rst | 382 +++++++++++----------
.../statistics/core/http-connection.en.rst | 11 +-
include/iocore/net/TLSSNISupport.h | 1 +
include/iocore/net/YamlSNIConfig.h | 2 +
include/proxy/http2/HTTP2.h | 2 +
include/proxy/http2/Http2ConnectionState.h | 12 +-
src/iocore/net/SNIActionPerformer.cc | 9 +
src/iocore/net/SNIActionPerformer.h | 12 +
src/iocore/net/YamlSNIConfig.cc | 7 +
src/proxy/http2/HTTP2.cc | 36 +-
src/proxy/http2/Http2ConnectionState.cc | 36 +-
src/records/RecordsConfig.cc | 2 +
13 files changed, 306 insertions(+), 217 deletions(-)
diff --git a/doc/admin-guide/files/records.yaml.en.rst
b/doc/admin-guide/files/records.yaml.en.rst
index 34c6b91448..6045e3d7f1 100644
--- a/doc/admin-guide/files/records.yaml.en.rst
+++ b/doc/admin-guide/files/records.yaml.en.rst
@@ -4559,8 +4559,15 @@ HTTP/2 Configuration
.. ts:cv:: CONFIG proxy.config.http2.max_rst_stream_frames_per_minute INT 200
: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
+ 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.
+
+.. ts:cv:: CONFIG proxy.config.http2.max_continuation_frames_per_minute INT 120
+ :reloadable:
+
+ 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.
.. ts:cv:: CONFIG proxy.config.http2.min_avg_window_update FLOAT 2560.0
diff --git a/doc/admin-guide/files/sni.yaml.en.rst
b/doc/admin-guide/files/sni.yaml.en.rst
index b514752063..7be40de811 100644
--- a/doc/admin-guide/files/sni.yaml.en.rst
+++ b/doc/admin-guide/files/sni.yaml.en.rst
@@ -83,203 +83,207 @@ inbound_port_ranges Inbound The port ranges for
the inbound connection i
The following fields are the directives that determine the behavior of
connections matching the key.
-====================================== =========
========================================================================================
-Key Direction Meaning
-====================================== =========
========================================================================================
-ip_allow Inbound Specify a list of client IP
address, subnets, or ranges what are allowed to complete
- the connection. This list is
comma separated. IPv4 and IPv6 addresses can be specified.
- Here is an example list ::
-
-
192.168.1.0/24,192.168.10.1-192.168.10.4
-
- This would allow connections
- from clients in the
19.168.1.0 network or in the range from 192.168.10.1 to 192.168.1.4.
-
- Alternatively, the path to a
file containing
- the list of IP addresses can
be specified in
- the form of
``"@path_to_file"``. The IP
- addresses in the file can be
either
- comma-separated or
line-separated. If a
- given file path does not
begin with ``/``,
- it must be relative to the
Traffic Server
- configuration directory. Here
is an example
- showing this form of the
configuration:
-
- ``ip_allow:
"@ip_dir/example.com.ip.txt"``
-
-verify_server_policy Outbound One of the values
:code:`DISABLED`, :code:`PERMISSIVE`, or :code:`ENFORCED`.
-
- By default this is
:ts:cv:`proxy.config.ssl.client.verify.server.policy`.
- This controls how |TS|
evaluated the origin certificate.
-
-verify_server_properties Outbound One of the values
:code:`NONE`, :code:`SIGNATURE`, :code:`NAME`, and :code:`ALL`
-
- By default this is
:ts:cv:`proxy.config.ssl.client.verify.server.properties`.
- This controls what |TS|
checks when evaluating the origin certificate.
-
-verify_client Outbound One of the values
:code:`NONE`, :code:`MODERATE`, or :code:`STRICT`.
- If ``NONE`` is specified,
|TS| requests no certificate. If ``MODERATE`` is specified
- |TS| will verify a
certificate that is presented by the client, but it will not
- fail the TLS handshake if no
certificate is presented. If ``STRICT`` is specified
- the client must present a
certificate during the TLS handshake.
-
- By default this is
:ts:cv:`proxy.config.ssl.client.certification_level`.
-
-verify_client_ca_certs Both Specifies an alternate set of
certificate authority certs to use to verify the
- client cert. The value must
be either a file path, or a nested set of key /
- value pairs. If the value is
a file path, it must specify a file containing the
- CA certs. Otherwise, there
should be up to two nested pairs. The possible keys
- are ``file`` and ``dir``.
The value for ``file`` must be a file path for a file
- containing CA certs. The
value for ``dir`` must be a file path for an OpenSSL
- X509 hashed directory
containing CA certs. If a given file path does not begin
- with ``/`` , it must be
relative to the |TS| configuration directory.
- ``verify_client_ca_certs``
can only be used with capabilities provided by
- OpenSSL 1.0.2 or later.
-
-host_sni_policy Inbound One of the values
:code:`DISABLED`, :code:`PERMISSIVE`, or :code:`ENFORCED`.
-
- If not specified, the value
of :ts:cv:`proxy.config.http.host_sni_policy` is used.
- This controls how policy
impacting mismatches between host header and SNI values are
- dealt with. For details
about how this configuration behaves, see the corresponding
-
:ts:cv:`proxy.config.http.host_sni_policy` :file:`records.yaml` documentation.
-
- Note that this particular
configuration will be inspected at the time the HTTP Host
- header field is processed.
Further, this policy check will be keyed off of the Host header
- field value rather than the
SNI in this :file:`sni.yaml` file. This is done because
- the Host header field is
ultimately the resource that will be retrieved from the
- origin and the administrator
will intend to guard this resource rather than the SNI,
- which a malicious user may
alter to some other server value whose policies are more
- lenient than the host he is
trying to access.
-
-valid_tls_version_min_in Inbound This specifies the minimum
TLS version that will be offered to user agents during
- the TLS negotiation. This
replaces the global settings in
-
:ts:cv:`proxy.config.ssl.server.version.min`,
-
:ts:cv:`proxy.config.ssl.TLSv1`, :ts:cv:`proxy.config.ssl.TLSv1_1`,
-
:ts:cv:`proxy.config.ssl.TLSv1_2`, and :ts:cv:`proxy.config.ssl.TLSv1_3`. The
potential
- values are TLSv1, TLSv1_1,
TLSv1_2, and TLSv1_3. This key is only valid for OpenSSL
- 1.1.0 and later and
BoringSSL. Older versions of OpenSSL do not provide a hook early enough to
update
- the SSL object. It is a
syntax error for |TS| built against earlier versions.
-
-valid_tls_version_max_in Inbound This specifies the minimum
TLS version that will be offered to user agents during
- the TLS negotiation. This
replaces the global settings in
-
:ts:cv:`proxy.config.ssl.server.version.max`,
-
:ts:cv:`proxy.config.ssl.TLSv1`, :ts:cv:`proxy.config.ssl.TLSv1_1`,
-
:ts:cv:`proxy.config.ssl.TLSv1_2`, and :ts:cv:`proxy.config.ssl.TLSv1_3`. The
potential
- values are TLSv1, TLSv1_1,
TLSv1_2, and TLSv1_3. This key is only valid for OpenSSL
- 1.1.0 and later and
BoringSSL. Older versions of OpenSSL do not provide a hook early enough to
update
- the SSL object. It is a
syntax error for |TS| built against earlier versions.
-
-valid_tls_versions_in Inbound Deprecated. This specifies
the list of TLS protocols that will be offered to user agents during
- the TLS negotiation. This
replaces the global settings in
-
:ts:cv:`proxy.config.ssl.TLSv1`, :ts:cv:`proxy.config.ssl.TLSv1_1`,
-
:ts:cv:`proxy.config.ssl.TLSv1_2`, and :ts:cv:`proxy.config.ssl.TLSv1_3`. The
potential
- values are TLSv1, TLSv1_1,
TLSv1_2, and TLSv1_3. You must list all protocols that |TS|
- should offer to the client
when using this key. This key is only valid for OpenSSL
- 1.1.0 and later and
BoringSSL. Older versions of OpenSSL do not provide a hook early enough to
update
- the SSL object. It is a
syntax error for |TS| built against earlier versions.
-
-client_cert Outbound The file containing the
client certificate to use for the outbound connection.
-
- If this is relative, it is
relative to the path in
-
:ts:cv:`proxy.config.ssl.client.cert.path`. If not set
-
:ts:cv:`proxy.config.ssl.client.cert.filename` is used.
-
-client_key Outbound The file containing the
client private key that corresponds to the certificate
- for the outbound connection.
-
- If this is relative, it is
relative to the path in
-
:ts:cv:`proxy.config.ssl.client.private_key.path`. If not set,
- |TS| tries to use a private
key in client_cert. Otherwise,
-
:ts:cv:`proxy.config.ssl.client.private_key.filename` is used.
-
-client_sni_policy Outbound Policy of SNI on outbound
connection.
-
- If not specified, the value
of :ts:cv:`proxy.config.ssl.client.sni_policy` is used.
-
-http2 Inbound Indicates whether the H2
protocol should be added to or removed from the
- protocol negotiation list.
The valid values are :code:`on` or :code:`off`.
-
-http2_buffer_water_mark Inbound Specifies the high water mark
for all HTTP/2 frames on an outgoing connection.
- By default this is
:ts:cv:`proxy.config.http2.default_buffer_water_mark`.
- NOTE: Connection coalescing
may prevent this from taking effect.
-
-http2_initial_window_size_in Inbound Specifies the initial HTTP/2
stream window size for inbound connections that
- |TS| as a receiver advertises
to the peer.
- By default this is
:ts:cv:`proxy.config.http2.initial_window_size_in`.
- NOTE: Connection coalescing
may prevent this from taking effect.
-
-http2_max_settings_frames_per_minute Inbound Specifies how many SETTINGS
frames |TS| receives per minute at maximum.
- By default this is
:ts:cv:`proxy.config.http2.max_settings_frames_per_minute`.
- NOTE: Connection coalescing
may prevent this from taking effect.
-
-http2_max_ping_frames_per_minute Inbound Specifies how many PING
frames |TS| receives per minute at maximum.
- By default this is
:ts:cv:`proxy.config.http2.max_ping_frames_per_minute`.
- NOTE: Connection coalescing
may prevent this from taking effect.
-
-http2_max_priority_frames_per_minute Inbound Specifies how many PRIORITY
frames |TS| receives per minute at maximum.
- By default this is
:ts:cv:`proxy.config.http2.max_priority_frames_per_minute`.
- NOTE: Connection coalescing
may prevent this from taking effect.
-
-http2_max_rst_stream_frames_per_minute Inbound Specifies how many RST_STREAM
frames |TS| receives per minute at maximum.
- By default this is
:ts:cv:`proxy.config.http2.max_rst_stream_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
- open ports for QUIC.
-
-tunnel_route Inbound Destination as an FQDN and
port, separated by a colon ``:``.
- Match group number can be
specified by ``$N`` where N should refer to a specified group
- in the FQDN, ``tunnel_route:
$1.domain``.
-
- This will forward all traffic
to the specified destination without first terminating
- the incoming TLS connection.
-
- The destination port can be
designated with the literal string
- ``{inbound_local_port}`` to
specify that |TS| should connect to the tunnel route's
- port on the same destination
port that the incoming connection had. For
- example, if a client
connected to |TS| on port ``4443`` and the associated
- ``tunnel_route`` had
``{inbound_local_port}`` for the port designation, then |TS|
- will connect to the specified
host using port ``4443``.
-
- The destination port can also
be designated with the literal string
- ``{proxy_protocol_port}``, in
which case |TS| will connect to the specified host on
- the port that was specified
by the incoming Proxy Protocol payload. See :ref:`Proxy
- Protocol <proxy-protocol>`
for more information on Proxy Protocol and how it is
- configured for |TS|.
-
- Note that only one of the
``{inbound_local_port}`` and ``{proxy_protocol_port}`` literal
- strings can be specified. The
match group number can be used in combination with either
- one of those.
-
- For each of these tunnel
targets, unless the port is explicitly specified in the target
- (e.g., if the port is derived
from the Proxy Protocol header), the port must be
- specified in the
:ts:cv:`proxy.config.http.connect_ports` configuration in order for
- the tunnel to succeed.
+======================================== =========
========================================================================================
+Key Direction Meaning
+======================================== =========
========================================================================================
+ip_allow Inbound Specify a list of client IP
address, subnets, or ranges what are allowed to complete
+ the connection. This list
is comma separated. IPv4 and IPv6 addresses can be specified.
+ Here is an example list ::
+
+
192.168.1.0/24,192.168.10.1-192.168.10.4
+
+ This would allow connections
+ from clients in the
19.168.1.0 network or in the range from 192.168.10.1 to 192.168.1.4.
+
+ Alternatively, the path to
a file containing
+ the list of IP addresses
can be specified in
+ the form of
``"@path_to_file"``. The IP
+ addresses in the file can
be either
+ comma-separated or
line-separated. If a
+ given file path does not
begin with ``/``,
+ it must be relative to the
Traffic Server
+ configuration directory.
Here is an example
+ showing this form of the
configuration:
+
+ ``ip_allow:
"@ip_dir/example.com.ip.txt"``
+
+verify_server_policy Outbound One of the values
:code:`DISABLED`, :code:`PERMISSIVE`, or :code:`ENFORCED`.
+
+ By default this is
:ts:cv:`proxy.config.ssl.client.verify.server.policy`.
+ This controls how |TS|
evaluated the origin certificate.
+
+verify_server_properties Outbound One of the values
:code:`NONE`, :code:`SIGNATURE`, :code:`NAME`, and :code:`ALL`
+
+ By default this is
:ts:cv:`proxy.config.ssl.client.verify.server.properties`.
+ This controls what |TS|
checks when evaluating the origin certificate.
+
+verify_client Outbound One of the values
:code:`NONE`, :code:`MODERATE`, or :code:`STRICT`.
+ If ``NONE`` is specified,
|TS| requests no certificate. If ``MODERATE`` is specified
+ |TS| will verify a
certificate that is presented by the client, but it will not
+ fail the TLS handshake if
no certificate is presented. If ``STRICT`` is specified
+ the client must present a
certificate during the TLS handshake.
+
+ By default this is
:ts:cv:`proxy.config.ssl.client.certification_level`.
+
+verify_client_ca_certs Both Specifies an alternate set
of certificate authority certs to use to verify the
+ client cert. The value
must be either a file path, or a nested set of key /
+ value pairs. If the value
is a file path, it must specify a file containing the
+ CA certs. Otherwise, there
should be up to two nested pairs. The possible keys
+ are ``file`` and ``dir``.
The value for ``file`` must be a file path for a file
+ containing CA certs. The
value for ``dir`` must be a file path for an OpenSSL
+ X509 hashed directory
containing CA certs. If a given file path does not begin
+ with ``/`` , it must be
relative to the |TS| configuration directory.
+ ``verify_client_ca_certs``
can only be used with capabilities provided by
+ OpenSSL 1.0.2 or later.
+
+host_sni_policy Inbound One of the values
:code:`DISABLED`, :code:`PERMISSIVE`, or :code:`ENFORCED`.
+
+ If not specified, the value
of :ts:cv:`proxy.config.http.host_sni_policy` is used.
+ This controls how policy
impacting mismatches between host header and SNI values are
+ dealt with. For details
about how this configuration behaves, see the corresponding
+
:ts:cv:`proxy.config.http.host_sni_policy` :file:`records.yaml` documentation.
+
+ Note that this particular
configuration will be inspected at the time the HTTP Host
+ header field is processed.
Further, this policy check will be keyed off of the Host header
+ field value rather than the
SNI in this :file:`sni.yaml` file. This is done because
+ the Host header field is
ultimately the resource that will be retrieved from the
+ origin and the
administrator will intend to guard this resource rather than the SNI,
+ which a malicious user may
alter to some other server value whose policies are more
+ lenient than the host he is
trying to access.
+
+valid_tls_version_min_in Inbound This specifies the minimum
TLS version that will be offered to user agents during
+ the TLS negotiation. This
replaces the global settings in
+
:ts:cv:`proxy.config.ssl.server.version.min`,
+
:ts:cv:`proxy.config.ssl.TLSv1`, :ts:cv:`proxy.config.ssl.TLSv1_1`,
+
:ts:cv:`proxy.config.ssl.TLSv1_2`, and :ts:cv:`proxy.config.ssl.TLSv1_3`. The
potential
+ values are TLSv1, TLSv1_1,
TLSv1_2, and TLSv1_3. This key is only valid for OpenSSL
+ 1.1.0 and later and
BoringSSL. Older versions of OpenSSL do not provide a hook early enough to
update
+ the SSL object. It is a
syntax error for |TS| built against earlier versions.
+
+valid_tls_version_max_in Inbound This specifies the minimum
TLS version that will be offered to user agents during
+ the TLS negotiation. This
replaces the global settings in
+
:ts:cv:`proxy.config.ssl.server.version.max`,
+
:ts:cv:`proxy.config.ssl.TLSv1`, :ts:cv:`proxy.config.ssl.TLSv1_1`,
+
:ts:cv:`proxy.config.ssl.TLSv1_2`, and :ts:cv:`proxy.config.ssl.TLSv1_3`. The
potential
+ values are TLSv1, TLSv1_1,
TLSv1_2, and TLSv1_3. This key is only valid for OpenSSL
+ 1.1.0 and later and
BoringSSL. Older versions of OpenSSL do not provide a hook early enough to
update
+ the SSL object. It is a
syntax error for |TS| built against earlier versions.
+
+valid_tls_versions_in Inbound Deprecated. This specifies
the list of TLS protocols that will be offered to user agents during
+ the TLS negotiation. This
replaces the global settings in
+
:ts:cv:`proxy.config.ssl.TLSv1`, :ts:cv:`proxy.config.ssl.TLSv1_1`,
+
:ts:cv:`proxy.config.ssl.TLSv1_2`, and :ts:cv:`proxy.config.ssl.TLSv1_3`. The
potential
+ values are TLSv1, TLSv1_1,
TLSv1_2, and TLSv1_3. You must list all protocols that |TS|
+ should offer to the client
when using this key. This key is only valid for OpenSSL
+ 1.1.0 and later and
BoringSSL. Older versions of OpenSSL do not provide a hook early enough to
update
+ the SSL object. It is a
syntax error for |TS| built against earlier versions.
+
+client_cert Outbound The file containing the
client certificate to use for the outbound connection.
+
+ If this is relative, it is
relative to the path in
+
:ts:cv:`proxy.config.ssl.client.cert.path`. If not set
+
:ts:cv:`proxy.config.ssl.client.cert.filename` is used.
+
+client_key Outbound The file containing the
client private key that corresponds to the certificate
+ for the outbound connection.
+
+ If this is relative, it is
relative to the path in
+
:ts:cv:`proxy.config.ssl.client.private_key.path`. If not set,
+ |TS| tries to use a private
key in client_cert. Otherwise,
+
:ts:cv:`proxy.config.ssl.client.private_key.filename` is used.
+
+client_sni_policy Outbound Policy of SNI on outbound
connection.
+
+ If not specified, the value
of :ts:cv:`proxy.config.ssl.client.sni_policy` is used.
+
+http2 Inbound Indicates whether the H2
protocol should be added to or removed from the
+ protocol negotiation list.
The valid values are :code:`on` or :code:`off`.
+
+http2_buffer_water_mark Inbound Specifies the high water
mark for all HTTP/2 frames on an outgoing connection.
+ By default this is
:ts:cv:`proxy.config.http2.default_buffer_water_mark`.
+ NOTE: Connection coalescing
may prevent this from taking effect.
+
+http2_initial_window_size_in Inbound Specifies the initial
HTTP/2 stream window size for inbound connections that
+ |TS| as a receiver
advertises to the peer.
+ By default this is
:ts:cv:`proxy.config.http2.initial_window_size_in`.
+ NOTE: Connection coalescing
may prevent this from taking effect.
+
+http2_max_settings_frames_per_minute Inbound Specifies how many SETTINGS
frames |TS| receives per minute at maximum.
+ By default this is
:ts:cv:`proxy.config.http2.max_settings_frames_per_minute`.
+ NOTE: Connection coalescing
may prevent this from taking effect.
+
+http2_max_ping_frames_per_minute Inbound Specifies how many PING
frames |TS| receives per minute at maximum.
+ By default this is
:ts:cv:`proxy.config.http2.max_ping_frames_per_minute`.
+ NOTE: Connection coalescing
may prevent this from taking effect.
+
+http2_max_priority_frames_per_minute Inbound Specifies how many PRIORITY
frames |TS| receives per minute at maximum.
+ By default this is
:ts:cv:`proxy.config.http2.max_priority_frames_per_minute`.
+ NOTE: Connection coalescing
may prevent this from taking effect.
+
+http2_max_rst_stream_frames_per_minute Inbound Specifies how many
RST_STREAM frames |TS| receives per minute at maximum.
+ By default this is
:ts:cv:`proxy.config.http2.max_rst_stream_frames_per_minute`.
+ NOTE: Connection coalescing
may prevent this from taking effect.
+
+http2_max_continuation_frames_per_minute Inbound Specifies how many
CONTINUATION frames |TS| receives per minute at maximum.
+ By default this is
:ts:cv:`proxy.config.http2.max_continuation_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
+ open ports for QUIC.
+
+tunnel_route Inbound Destination as an FQDN and
port, separated by a colon ``:``.
+ Match group number can be
specified by ``$N`` where N should refer to a specified group
+ in the FQDN,
``tunnel_route: $1.domain``.
+
+ This will forward all
traffic to the specified destination without first terminating
+ the incoming TLS connection.
+
+ The destination port can be
designated with the literal string
+ ``{inbound_local_port}`` to
specify that |TS| should connect to the tunnel route's
+ port on the same
destination port that the incoming connection had. For
+ example, if a client
connected to |TS| on port ``4443`` and the associated
+ ``tunnel_route`` had
``{inbound_local_port}`` for the port designation, then |TS|
+ will connect to the
specified host using port ``4443``.
+
+ The destination port can
also be designated with the literal string
+ ``{proxy_protocol_port}``,
in which case |TS| will connect to the specified host on
+ the port that was specified
by the incoming Proxy Protocol payload. See :ref:`Proxy
+ Protocol <proxy-protocol>`
for more information on Proxy Protocol and how it is
+ configured for |TS|.
+
+ Note that only one of the
``{inbound_local_port}`` and ``{proxy_protocol_port}`` literal
+ strings can be specified.
The match group number can be used in combination with either
+ one of those.
+
+ For each of these tunnel
targets, unless the port is explicitly specified in the target
+ (e.g., if the port is
derived from the Proxy Protocol header), the port must be
+ specified in the
:ts:cv:`proxy.config.http.connect_ports` configuration in order for
+ the tunnel to succeed.
-forward_route Inbound Destination as an FQDN and
port, separated by a colon ``:``.
+forward_route Inbound Destination as an FQDN and
port, separated by a colon ``:``.
- This is similar to
tunnel_route, but it terminates the TLS connection and forwards the
- decrypted traffic. |TS| will
not interpret the decrypted data, so the contents do not
- need to be HTTP.
+ This is similar to
tunnel_route, but it terminates the TLS connection and forwards the
+ decrypted traffic. |TS|
will not interpret the decrypted data, so the contents do not
+ need to be HTTP.
-partial_blind_route Inbound Destination as an FQDN and
port, separated by a colon ``:``.
+partial_blind_route Inbound Destination as an FQDN and
port, separated by a colon ``:``.
- This is similar to
forward_route in that |TS| terminates the incoming TLS connection.
- In addition
partial_blind_route creates a new TLS connection to the specified origin.
- It does not interpret the
decrypted data before passing it to the origin TLS
- connection, so the contents
do not need to be HTTP.
+ This is similar to
forward_route in that |TS| terminates the incoming TLS connection.
+ In addition
partial_blind_route creates a new TLS connection to the specified origin.
+ It does not interpret the
decrypted data before passing it to the origin TLS
+ connection, so the contents
do not need to be HTTP.
-tunnel_alpn Inbound List of ALPN Protocol Ids for
Partial Blind Tunnel.
+tunnel_alpn Inbound List of ALPN Protocol Ids
for Partial Blind Tunnel.
- ATS negotiates application
protocol with the client on behalf of the origin server.
- This only works with
``partial_blind_route``.
+ ATS negotiates application
protocol with the client on behalf of the origin server.
+ This only works with
``partial_blind_route``.
-server_max_early_data Inbound Specifies the maximum amount
of early data in bytes that is permitted to be sent on a single connection.
+server_max_early_data Inbound Specifies the maximum
amount of early data in bytes that is permitted to be sent on a single
connection.
- If not specified, the value
of :ts:cv:`proxy.config.ssl.server.max_early_data` is used.
-====================================== =========
========================================================================================
+ If not specified, the value
of :ts:cv:`proxy.config.ssl.server.max_early_data` is used.
+======================================== =========
========================================================================================
Pre-warming TLS Tunnel
----------------------
diff --git a/doc/admin-guide/monitoring/statistics/core/http-connection.en.rst
b/doc/admin-guide/monitoring/statistics/core/http-connection.en.rst
index cd9a554e0b..80df47cf5b 100644
--- a/doc/admin-guide/monitoring/statistics/core/http-connection.en.rst
+++ b/doc/admin-guide/monitoring/statistics/core/http-connection.en.rst
@@ -306,10 +306,17 @@ HTTP/2
.. 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
+ Represents the total number of HTTP/2 connections closed 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.max_continuation_frames_per_minute_exceeded integer
+ :type: counter
+
+ Represents the total number of HTTP/2 connections closed for exceeding the
+ maximum allowed number of ``CONTINUATION`` frames per minute limit which is
+ configured by
:ts:cv:`proxy.config.http2.max_continuation_frames_per_minute`.
+
.. ts:stat:: global proxy.process.http2.insufficient_avg_window_update integer
:type: counter
diff --git a/include/iocore/net/TLSSNISupport.h
b/include/iocore/net/TLSSNISupport.h
index a4a3de350c..8fcff07fa2 100644
--- a/include/iocore/net/TLSSNISupport.h
+++ b/include/iocore/net/TLSSNISupport.h
@@ -65,6 +65,7 @@ public:
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<std::string_view> outbound_sni_policy;
} hints_from_sni;
diff --git a/include/iocore/net/YamlSNIConfig.h
b/include/iocore/net/YamlSNIConfig.h
index aa5ec2008d..40978f9a82 100644
--- a/include/iocore/net/YamlSNIConfig.h
+++ b/include/iocore/net/YamlSNIConfig.h
@@ -66,6 +66,7 @@ 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(http2_max_continuation_frames_per_minute);
TSDECL(quic);
TSDECL(host_sni_policy);
TSDECL(http2_initial_window_size_in);
@@ -111,6 +112,7 @@ struct YamlSNIConfig {
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;
diff --git a/include/proxy/http2/HTTP2.h b/include/proxy/http2/HTTP2.h
index fbaa579e7c..8001c9787d 100644
--- a/include/proxy/http2/HTTP2.h
+++ b/include/proxy/http2/HTTP2.h
@@ -103,6 +103,7 @@ struct Http2StatsBlock {
Metrics::Counter::AtomicType *max_ping_frames_per_minute_exceeded;
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 *insufficient_avg_window_update;
Metrics::Counter::AtomicType *max_concurrent_streams_exceeded_in;
Metrics::Counter::AtomicType *max_concurrent_streams_exceeded_out;
@@ -427,6 +428,7 @@ public:
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 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 83ff405649..00f0089425 100644
--- a/include/proxy/http2/Http2ConnectionState.h
+++ b/include/proxy/http2/Http2ConnectionState.h
@@ -197,6 +197,8 @@ public:
uint32_t get_received_priority_frame_count();
void increment_received_rst_stream_frame_count();
uint32_t get_received_rst_stream_frame_count();
+ void increment_received_continuation_frame_count();
+ uint32_t get_received_continuation_frame_count();
ssize_t get_peer_rwnd() const;
Http2ErrorCode increment_peer_rwnd(size_t amount);
@@ -331,6 +333,7 @@ private:
FrequencyCounter _received_ping_frame_counter;
FrequencyCounter _received_priority_frame_counter;
FrequencyCounter _received_rst_stream_frame_counter;
+ FrequencyCounter _received_continuation_frame_counter;
/** Records the various settings for each SETTINGS frame that we've sent.
*
@@ -399,10 +402,11 @@ private:
Event *fini_event = nullptr;
Event *zombie_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_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;
};
///////////////////////////////////////////////
diff --git a/src/iocore/net/SNIActionPerformer.cc
b/src/iocore/net/SNIActionPerformer.cc
index 34f35e533b..a9130b8673 100644
--- a/src/iocore/net/SNIActionPerformer.cc
+++ b/src/iocore/net/SNIActionPerformer.cc
@@ -134,6 +134,15 @@ HTTP2MaxRstStreamFramesPerMinute::SNIAction(SSL &ssl,
const Context &ctx) const
return SSL_TLSEXT_ERR_OK;
}
+int
+HTTP2MaxContinuationFramesPerMinute::SNIAction(SSL &ssl, const Context &ctx)
const
+{
+ if (auto snis = TLSSNISupport::getInstance(&ssl)) {
+ snis->hints_from_sni.http2_max_continuation_frames_per_minute = value;
+ }
+ return SSL_TLSEXT_ERR_OK;
+}
+
TunnelDestination::TunnelDestination(const std::string_view &dest,
SNIRoutingType type, YamlSNIConfig::TunnelPreWarm prewarm,
const std::vector<int> &alpn)
: destination(dest), type(type), tunnel_prewarm(prewarm), alpn_ids(alpn)
diff --git a/src/iocore/net/SNIActionPerformer.h
b/src/iocore/net/SNIActionPerformer.h
index a6654f3117..5b7604318a 100644
--- a/src/iocore/net/SNIActionPerformer.h
+++ b/src/iocore/net/SNIActionPerformer.h
@@ -139,6 +139,18 @@ private:
int value = -1;
};
+class HTTP2MaxContinuationFramesPerMinute : public ActionItem
+{
+public:
+ HTTP2MaxContinuationFramesPerMinute(int value) : value(value) {}
+ ~HTTP2MaxContinuationFramesPerMinute() override {}
+
+ int SNIAction(SSL &ssl, const Context &ctx) const override;
+
+private:
+ int value = -1;
+};
+
class TunnelDestination : public ActionItem
{
// ID of the configured variable. This will be used to know which function
diff --git a/src/iocore/net/YamlSNIConfig.cc b/src/iocore/net/YamlSNIConfig.cc
index 26d12b6e3a..a742abdde2 100644
--- a/src/iocore/net/YamlSNIConfig.cc
+++ b/src/iocore/net/YamlSNIConfig.cc
@@ -175,6 +175,9 @@ YamlSNIConfig::Item::populate_sni_actions(action_vector_t
&actions)
if (http2_max_rst_stream_frames_per_minute.has_value()) {
actions.push_back(std::make_unique<HTTP2MaxRstStreamFramesPerMinute>(http2_max_rst_stream_frames_per_minute.value()));
}
+ if (http2_max_continuation_frames_per_minute.has_value()) {
+
actions.push_back(std::make_unique<HTTP2MaxContinuationFramesPerMinute>(http2_max_continuation_frames_per_minute.value()));
+ }
actions.push_back(std::make_unique<ServerMaxEarlyData>(server_max_early_data));
actions.push_back(std::make_unique<SNI_IpAllow>(ip_allow, fqdn));
@@ -222,6 +225,7 @@ std::set<std::string> valid_sni_config_keys = {TS_fqdn,
TS_http2_max_ping_frames_per_minute,
TS_http2_max_priority_frames_per_minute,
TS_http2_max_rst_stream_frames_per_minute,
+
TS_http2_max_continuation_frames_per_minute,
TS_quic,
TS_ip_allow,
#if TS_USE_HELLO_CB || defined(OPENSSL_IS_BORINGSSL)
@@ -277,6 +281,9 @@ template <> struct convert<YamlSNIConfig::Item> {
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>();
}
+ if (node[TS_http2_max_continuation_frames_per_minute]) {
+ item.http2_max_continuation_frames_per_minute =
node[TS_http2_max_continuation_frames_per_minute].as<int>();
+ }
if (node[TS_quic]) {
item.offer_quic = node[TS_quic].as<bool>();
}
diff --git a/src/proxy/http2/HTTP2.cc b/src/proxy/http2/HTTP2.cc
index 3bd504ee62..abfd85f345 100644
--- a/src/proxy/http2/HTTP2.cc
+++ b/src/proxy/http2/HTTP2.cc
@@ -482,22 +482,23 @@ uint32_t Http2::initial_window_size_out =
65535;
Http2FlowControlPolicy Http2::flow_control_policy_out =
Http2FlowControlPolicy::STATIC_SESSION_AND_STATIC_STREAM;
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;
-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;
+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;
+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()
@@ -545,6 +546,7 @@ Http2::init()
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_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");
@@ -597,6 +599,8 @@ Http2::init()
Metrics::Counter::createPtr("proxy.process.http2.max_priority_frames_per_minute_exceeded");
http2_rsb.max_rst_stream_frames_per_minute_exceeded =
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.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 703586c383..759e1042cc 100644
--- a/src/proxy/http2/Http2ConnectionState.cc
+++ b/src/proxy/http2/Http2ConnectionState.cc
@@ -1013,6 +1013,18 @@ Http2ConnectionState::rcv_continuation_frame(const
Http2Frame &frame)
}
}
+ // Update CONTINUATION frame count per minute.
+ 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) {
+
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());
+ return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION,
Http2ErrorCode::HTTP2_ERROR_ENHANCE_YOUR_CALM,
+ "reset too frequent CONTINUATION frames");
+ }
+
uint32_t header_blocks_offset = stream->header_blocks_length;
stream->header_blocks_length += payload_length;
@@ -1254,10 +1266,11 @@ Http2ConnectionState::init(Http2CommonSession *ssn)
acknowledged_local_settings.set(HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
configured_settings.get(HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE));
- configured_max_settings_frames_per_minute =
Http2::max_settings_frames_per_minute;
- configured_max_ping_frames_per_minute =
Http2::max_ping_frames_per_minute;
- 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_settings_frames_per_minute =
Http2::max_settings_frames_per_minute;
+ configured_max_ping_frames_per_minute =
Http2::max_ping_frames_per_minute;
+ 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;
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();
@@ -1271,6 +1284,9 @@ Http2ConnectionState::init(Http2CommonSession *ssn)
if
(snis->hints_from_sni.http2_max_rst_stream_frames_per_minute.has_value()) {
configured_max_rst_stream_frames_per_minute =
snis->hints_from_sni.http2_max_rst_stream_frames_per_minute.value();
}
+ if
(snis->hints_from_sni.http2_max_continuation_frames_per_minute.has_value()) {
+ configured_max_continuation_frames_per_minute =
snis->hints_from_sni.http2_max_continuation_frames_per_minute.value();
+ }
}
_cop = ActivityCop<Http2Stream>(this->mutex, &stream_list, 1);
@@ -2670,6 +2686,18 @@
Http2ConnectionState::get_received_rst_stream_frame_count()
return this->_received_rst_stream_frame_counter.get_count();
}
+void
+Http2ConnectionState::increment_received_continuation_frame_count()
+{
+ this->_received_continuation_frame_counter.increment();
+}
+
+uint32_t
+Http2ConnectionState::get_received_continuation_frame_count()
+{
+ return this->_received_continuation_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 607abe23e0..9e3df88167 100644
--- a/src/records/RecordsConfig.cc
+++ b/src/records/RecordsConfig.cc
@@ -1312,6 +1312,8 @@ static const RecordElement RecordsConfig[] =
,
{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_continuation_frames_per_minute",
RECD_INT, "120", 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}