Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

h2: Rapid reset mitigations (7.3) #4011

Merged
merged 29 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b9074c6
Bump cli_limit to fit param.show -j with more parameters coming
nigoroll Oct 16, 2023
5cdffa1
h2: Add a rate limit facility for h/2 RST handling
daghf Oct 12, 2023
54146bc
Introduce RAPID_RESET as a sess_close reason
daghf Oct 17, 2023
74bbb48
Add param h2_rapid_reset
daghf Oct 17, 2023
de3a875
Polish h2_rapid_reset docs
nigoroll Oct 17, 2023
d241f13
Flexelinting
bsdphk Oct 17, 2023
874a7cc
slinkified dridi-polish
nigoroll Oct 17, 2023
2eac591
vtc: Avoid cycling the barrier in t02014
dridi Oct 12, 2023
467a4db
transport: New poll method
dridi Oct 11, 2023
fa83fee
vcl_vrt: Skip VCL execution if the client is gone
dridi Oct 11, 2023
a1501a6
http2_session: Implement transport polling
dridi Oct 11, 2023
84b67dc
vtc: Stabilize r3996 and increase coverage
dridi Oct 18, 2023
ae7b0b5
vtc: Missing synchronization in t02025
dridi Oct 18, 2023
f5f8f27
Copy rapid reset parameters to the h2 session
nigoroll Oct 17, 2023
c21f9b2
Add vmod_h2 to control rapid_reset parameters per session
nigoroll Oct 16, 2023
53a1cd5
Start with a reasonable default for h2_rapid_reset_limit
nigoroll Oct 18, 2023
f064f64
Adjust test case to previous commit
nigoroll Oct 18, 2023
f28e5da
Flexelinting
nigoroll Oct 18, 2023
941d3fd
vmod_h2: VRT_fail if called outside of client context
daghf Oct 18, 2023
2e361de
Redo H2 field validation
bsdphk Aug 22, 2023
fec46c8
Slightly more coverage & consistency
bsdphk Aug 22, 2023
5e5a8cc
hpack: Turn header validation state into an enum
walid-git Sep 8, 2023
34dde81
hpack: Check illegal header blanks with vct_issp()
walid-git Sep 8, 2023
5db4965
hpack: Validate header values with vct_ishdrval()
walid-git Sep 8, 2023
01059ea
hpack: Remove redundant/incorrect header validation
walid-git Sep 8, 2023
2478263
vtc: More HPACK header validation coverage
walid-git Sep 8, 2023
05123d4
vtc: Coverage for h2 empty header in t02023
dridi Sep 14, 2023
2df7705
vmod_h2: Polish manual
dridi Oct 24, 2023
990bf81
build: Generate and install man/vmod_h2.3
dridi Oct 24, 2023
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
4 changes: 3 additions & 1 deletion include/tbl/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -1244,7 +1244,9 @@ PARAM_SIMPLE(
)

#define H2_RR_INFO \
"Changes to this parameter affect the default for new HTTP2 sessions"
"Changes to this parameter affect the default for new HTTP2 " \
"sessions. vmod_h2(3) can be used to adjust it from VCL."

PARAM_SIMPLE(
/* name */ h2_rapid_reset,
/* typ */ timeout,
Expand Down
1 change: 1 addition & 0 deletions vmod/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ AM_CPPFLAGS = \
vmod_LTLIBRARIES =

include $(srcdir)/automake_boilerplate_blob.am
include $(srcdir)/automake_boilerplate_h2.am
include $(srcdir)/automake_boilerplate_cookie.am
include $(srcdir)/automake_boilerplate_debug.am
include $(srcdir)/automake_boilerplate_directors.am
Expand Down
35 changes: 35 additions & 0 deletions vmod/automake_boilerplate_h2.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Generated by vmodtool.py --boilerplate.

vmod_LTLIBRARIES += libvmod_h2.la

libvmod_h2_la_SOURCES = \
vmod_h2.c

libvmod_h2_la_CFLAGS =

vmodtoolargs_h2 ?= --strict --boilerplate -o vcc_h2_if
vmod_h2_symbols_regex ?= Vmod_h2_Data

libvmod_h2_la_LDFLAGS = \
-export-symbols-regex $(vmod_h2_symbols_regex) \
$(AM_LDFLAGS) \
$(VMOD_LDFLAGS)

nodist_libvmod_h2_la_SOURCES = vcc_h2_if.c vcc_h2_if.h

EXTRA_libvmod_h2_la_DEPENDENCIES = $(nodist_libvmod_h2_la_SOURCES)

EXTRA_DIST += $(srcdir)/vmod_h2.vcc automake_boilerplate_h2.am

$(libvmod_h2_la_OBJECTS): vcc_h2_if.h

vcc_h2_if.h vmod_h2.rst vmod_h2.man.rst: vcc_h2_if.c

vcc_h2_if.c: $(vmodtool) $(srcdir)/vmod_h2.vcc
@PYTHON@ $(vmodtool) $(vmodtoolargs_h2) $(srcdir)/vmod_h2.vcc

clean-local: clean-vmod-h2

clean-vmod-h2:
rm -f $(nodist_libvmod_h2_la_SOURCES)
rm -f vmod_h2.rst vmod_h2.man.rst
90 changes: 90 additions & 0 deletions vmod/tests/h2_b00000.vtc
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
varnishtest "VMOD h2 basics"

varnish v1 -arg "-p feature=+http2" -vcl {
import h2;

backend proforma none;

sub vcl_recv {
return(synth(200));
}

sub vcl_synth {
set resp.http.http2-is = h2.is();
set resp.body = "";
return (deliver);
}
} -start

client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.http2-is == false
} -start

client c2 {
stream 7 {
txreq
rxresp
expect resp.status == 200
expect resp.http.http2-is == true
} -run
} -start

client c1 -wait
client c2 -wait

# coverage
varnish v1 -vcl {
import h2;

backend proforma none;

sub vcl_recv {
return(synth(200));
}

sub vcl_synth {
set resp.http.rapid-reset-o = h2.rapid_reset(10ms);
set resp.http.rapid-reset-n = h2.rapid_reset();
set resp.http.rapid-reset-limit-o = h2.rapid_reset_limit(100);
set resp.http.rapid-reset-limit-n = h2.rapid_reset_limit();
set resp.http.rapid-reset-period-o = h2.rapid_reset_period(10s);
set resp.http.rapid-reset-period-n = h2.rapid_reset_period();
set resp.http.rapid-reset-budget = h2.rapid_reset_budget();
set resp.body = "";
return (deliver);
}
}

client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.http.rapid-reset-o == -1.000
expect resp.http.rapid-reset-n == -1.000
expect resp.http.rapid-reset-limit-o == -1
expect resp.http.rapid-reset-limit-n == -1
expect resp.http.rapid-reset-period-o == -1.000
expect resp.http.rapid-reset-period-n == -1.000
expect resp.http.rapid-reset-budget == -1.000
} -start

client c2 {
stream 7 {
txreq
rxresp
expect resp.status == 200
expect resp.http.rapid-reset-o == 1.000
expect resp.http.rapid-reset-n == 0.010
expect resp.http.rapid-reset-limit-o == 0
expect resp.http.rapid-reset-limit-n == 100
expect resp.http.rapid-reset-period-o == 60.000
expect resp.http.rapid-reset-period-n == 10.000
expect resp.http.rapid-reset-budget == 100.000
} -run
} -start

client c1 -wait
client c2 -wait
100 changes: 100 additions & 0 deletions vmod/vmod_h2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*-
* Copyright 2023 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Author: Nils Goroll <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

#include "config.h"

#include "cache/cache_varnishd.h"

#include "vcc_h2_if.h"

#include "cache/cache_transport.h"
#include "http2/cache_http2.h"

static struct h2_sess *
h2get(VRT_CTX)
{
struct h2_sess *h2;
uintptr_t *up;

CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC); // $Restrict client
if (ctx->req->transport != &HTTP2_transport)
return (NULL);
AZ(SES_Get_proto_priv(ctx->req->sp, &up));
CAST_OBJ_NOTNULL(h2, (void *)*up, H2_SESS_MAGIC);
return (h2);
}
VCL_BOOL
vmod_is(VRT_CTX)
{
struct h2_sess *h2 = h2get(ctx);

return (h2 != NULL);
}

#define GETSET(type, name, argname) \
type \
vmod_ ## name(VRT_CTX, struct VARGS(name) *args) \
{ \
struct h2_sess *h2 = h2get(ctx); \
type r; \
\
if (h2 == NULL) \
return (-1); \
\
if (! args->valid_ ## argname) \
return (h2->name); \
if (h2->name == args->argname) \
return (h2->name); \
\
Lck_Lock(&h2->sess->mtx); \
r = h2->name; \
if (h2->name != args->argname) { \
h2->name = args->argname; \
h2->rst_budget = h2->rapid_reset_limit; \
h2->last_rst = ctx->now; \
} \
Lck_Unlock(&h2->sess->mtx); \
return (r); \
}

GETSET(VCL_DURATION, rapid_reset, threshold)
GETSET(VCL_INT, rapid_reset_limit, number)
GETSET(VCL_DURATION, rapid_reset_period, duration)

VCL_REAL
vmod_rapid_reset_budget(VRT_CTX)
{
struct h2_sess *h2 = h2get(ctx);

if (h2 == NULL)
return (-1);

return (h2->rst_budget);
}
88 changes: 88 additions & 0 deletions vmod/vmod_h2.vcc
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#-
# Copyright 2023 UPLEX - Nils Goroll Systemoptimierung
# All rights reserved.
#
# Author: Nils Goroll <[email protected]>
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

$ABI strict
$Module h2 3 "Module to control the built-in HTTP2 transport"

DESCRIPTION
===========

This VMOD contains functions to control the HTTP2 transport built into
Varnish-Cache.

$Function BOOL is()

Returns true when called on a session handled by the built-in HTTP2 transport.

$Function DURATION rapid_reset([DURATION threshold])

Get and optionally set the ``h2_rapid_reset`` parameter (See
:ref:`varnishd(1)`) for this HTTP2 session only.

Returns -1 when used outside the HTTP2 transport. Otherwise returns
dridi marked this conversation as resolved.
Show resolved Hide resolved
the previous value.

If the call leads to a change in the rate limit parameters, the
current budget as retuned by
`h2.rapid_reset_budget()`_ is reset.

$Function INT rapid_reset_limit([INT number])

Get and optionally set the ``h2_rapid_reset_limit`` parameter (See
:ref:`varnishd(1)`) for this HTTP2 session only.

Returns -1 when used outside the HTTP2 transport. Otherwise returns
the previous value.

If the call leads to a change in the rate limit parameters, the
current budget as retuned by
`h2.rapid_reset_budget()`_ is reset.

$Function DURATION rapid_reset_period([DURATION duration])

Get and optionally set the ``h2_rapid_reset_period`` parameter (See
:ref:`varnishd(1)`) for this HTTP2 session only.

Returns -1 when used outside the HTTP2 transport. Otherwise returns
the previous value.

If the call leads to a change in the rate limit parameters, the
current budget as retuned by
`h2.rapid_reset_budget()`_ is reset.

$Function REAL rapid_reset_budget()

Return how many RST frames classified as "rapid" the client is still
allowed to send before the session is going to be closed.

SEE ALSO
========

* :ref:`varnishd(1)`
* :ref:`vsl(7)`