6135 Commits

Author SHA1 Message Date
Amaury Denoyelle
1c25b18e17 MINOR: mux-quic: delay cs_endpoint allocation
Do not allocate cs_endpoint for every QCS instances in qcs_new().
Instead, this is delayed to qc_attach_cs() function.

In effect, with H3 as app protocol, cs_endpoint will be allocated on
HEADERS parsing. Thus, no cs_endpoint is allocated for H3 unidirectional
streams which do not convey any HTTP data.
2022-05-25 15:41:25 +02:00
Christopher Faulet
d9404b464f BUG/MINOR: task: Don't defer tasks release when HAProxy is stopping
A running or queued task is not released when task_destroy() is called,
except if it is the current task. Its process function is set to NULL and we
let the scheduler to release the task. However, when HAProxy is stopping, it
never happens and some tasks may leak. To fix the issue, we now also rely on
the global MODE_STOPPING flag. When this flag is set, the task is always
immediately released.

This patch should fix the issue #1714. It could be backported as far as 2.4
but it's not a real problem in practice because it only happens on
deinit. The leak exists on previous versions but not MODE_STOPPING flag.
2022-05-25 15:31:21 +02:00
David CARLIER
842e4a6617 BUILD/MINOR: cpuset fix build for FreeBSD 13.1
the cpuset api changes done fir the future 14 release had been
backported to the 13.1 release so changing the cpuset api of choice
condition change accordingly.
2022-05-20 23:06:03 +02:00
Willy Tarreau
b5821e12ce MINOR: connection: add flag MX_FL_FRAMED to mark muxes relying on framed xprt
In order to be able to check compatibility between muxes and transport
layers, we'll need a new flag to tag muxes that work on framed transport
layers like QUIC. Only QUIC has this flag now.
2022-05-20 18:41:55 +02:00
Willy Tarreau
91b780a455 CLEANUP: listener: store stream vs dgram at the bind_conf level
Let's collect the set of xprt-level and sock-level dgram/stream protocols
seen on a bind line and store that in the bind_conf itself while they're
being parsed. This will make it much easier to detect incompatibilities
later than the current approch which consists in scanning all listeners
in post-parsing.
2022-05-20 18:41:55 +02:00
Willy Tarreau
787e92a4fb CLEANUP: listener: replace bind_conf->quic_force_retry with BC_O_QUIC_FORCE_RETRY
It was only set and used once, let's replace it now and take it out of
the ifdef.
2022-05-20 18:41:51 +02:00
Willy Tarreau
1ea6e6a17f CLEANUP: listener: replace bind_conf->generate_cers with BC_O_GENERATE_CERTS
The new flag will now replace this boolean variable.
2022-05-20 18:39:43 +02:00
Willy Tarreau
11ba404c6b CLEANUP: listener: replace all uses of bind_conf->is_ssl with BC_O_USE_SSL
The new flag will now replace this boolean variable that was only set and
tested.
2022-05-20 18:39:43 +02:00
Willy Tarreau
c694471b21 MINOR: listener: add a new "options" entry in bind_conf
There is no way to store useful info there, yet there's about one entry
per boolean. Let's add an "options" attribute which will collect various
options.

In practice, even the BC_O_SSL_* flags and a few info such as strict_sni
could move there.
2022-05-20 18:39:43 +02:00
Willy Tarreau
fca044bda5 CLEANUP: listener: add a comment about what the BC_SSL_O_* flags are for
They're for ->ssl_options but it wasn't obvious.
2022-05-20 18:39:43 +02:00
Willy Tarreau
3882d2a96c MINOR: listener: provide a function to process all of a bind_conf's arguments
The "bind" parsing code was duplicated for the peers section and as a
result it wasn't kept updated, resulting in slightly different error
behavior (e.g. errors were not freed, warnings were emitted as alerts)
Let's first unify it into a new dedicated function that properly reports
and frees the error.
2022-05-20 18:39:43 +02:00
Willy Tarreau
91b47263f7 MINOR: protocol: replace ctrl_type with xprt_type and clarify it
There's been some great confusion between proto_type, ctrl_type and
sock_type. It turns out that ctrl_type was improperly chosen because
it's not the control layer that is of this or that type, but the
transport layer, and it turns out that the transport layer doesn't
(normally) denaturate the underlying control layer, except for QUIC
which turns dgrams to streams. The fact that the SOCK_{DGRAM|STREAM}
set of values was used added to the confusion.

Let's replace it with xprt_type which reuses the later introduced
PROTO_TYPE_* values, and update the comments to explain which one
works at what level.
2022-05-20 18:39:43 +02:00
Amaury Denoyelle
d46b0f52ae MINOR: mux-quic: emit FLOW_CONTROL_ERROR
Send a CONNECTION_CLOSE if the peer emits more data than authorized by
our flow-control. This is implemented for both stream and connection
level.

Fields have been added in qcc/qcs structures to differentiate received
offsets for limit enforcing with consumed offsets for sending of
MAX_DATA/MAX_STREAM_DATA frames.
2022-05-20 17:47:09 +02:00
Amaury Denoyelle
9fab9fd7e5 MINOR: quic/mux-quic: define CONNECTION_CLOSE send API
Define an API to easily set a CONNECTION_CLOSE. This will mainly be
useful for the MUX when an error is detected which require to close the
whole connection.

On the MUX side, a new flag is added when a CONNECTION_CLOSE has been
prepared. This will disable add future send operations.
2022-05-20 17:26:56 +02:00
Frédéric Lécaille
9286210aa8 MINOR: quic: Add tune.quic.retry-threshold keyword
This QUIC specific keyword may be used to set the theshold, in number of
connection openings, beyond which QUIC Retry feature will be automatically
enabled. Its default value is 100.
2022-05-20 17:11:13 +02:00
Frédéric Lécaille
cbd59c7ab6 MINOR: quic: QUIC stats counters handling
First commit to handle the QUIC stats counters. There is nothing special to say
except perhaps for ->conn_openings which is a gauge to count the number of
connection openings. It is incremented after having instantiated a quic_conn
struct, then decremented when the handshake was successful (handshake completed
state) or failed or when the connection timed out without reaching the handshake
completed state.
2022-05-20 17:11:13 +02:00
Frédéric Lécaille
a89659a752 MINOR: quic: Attach proxy QUIC stats counters to the QUIC connection
Make usage of EXTRA_COUNTERS_GET() do to so from qc_new_conn().
2022-05-20 17:11:13 +02:00
Frédéric Lécaille
a58cafeb89 MINOR: quic_stats: Add a new stats module for QUIC
This is a very minimalist frontend only stats module with only one gauge for the
QUIC establishing connections count.
2022-05-20 17:11:13 +02:00
Frédéric Lécaille
2822593a12 BUILD: stats: Missing headers inclusions from stats.h
If we add a new stats module to C source files including only
stats.h we get these errors:

    include/haproxy/stats.h:39:31: error: array type has incomplete element type
    ‘struct name_desc’
       39 | extern const struct name_desc stat_fields[];

    include/haproxy/stats.h:55:50: warning: ‘struct listener’ declared inside
    parameter list will not be visible outside of this definition or declaration
       55 | int stats_fill_li_stats(struct proxy *px, struct listener *l, int flags,

name_desc struct is defined in tools-t.h and listener struct in listner-t.h.
2022-05-20 16:57:12 +02:00
Frédéric Lécaille
6492e66e41 MINOR: quic: Move quic_lstnr_dgram_dispatch() out of xprt_quic.c
Remove this function from xprt_quic.c which for now implements only
"by thread attached to a connection" code.
2022-05-20 16:57:12 +02:00
Frédéric Lécaille
3f3ff47998 MINOR: quic: Retry implementation
Here is the format of a token:
        - format (1 byte)
        - ODCID (from 9 up 21 bytes)
        - creation timestamp (4 bytes)
        - salt (16 bytes)

A format byte is required to distinguish the Retry token from others sent in
NEW_TOKEN frames.

The Retry token is ciphered after having derived a strong secret from the cluster secret
and generated the AEAD AAD, as well as a 16 bytes long salt. This salt is
added to the token. Obviously it is not ciphered. The format byte is not
ciphered too.

The AAD are built by quic_generate_retry_token_aad() which concatenates the version,
the client SCID and the IP address and port. We had to implement quic_saddr_cpy()
to copy the IP address and port to the AAD buffer. Only the Retry SCID is generated
on our side to build a Retry packet, the others fields come from the first packet
received by the client. It must reuse this Retry SCID in response to our Retry packet.
So, we have not to store it on our side. Everything is offloaded to the client (stateless).
quic_generate_retry_token() must be used to generate a Retry packet. It calls
quic_pkt_encrypt() to cipher the token.

quic_generate_retry_check() must be used to check the validity of a Retry token.
It is able to decipher a token which arrives into an Initial packet in response
to a Retry packet. It calls parse_retry_token() after having deciphered the token
to store the ODCID into a local quic_cid struct variable. Finally this ODCID may
be stored into the transport parameter thanks to qc_lstnr_params_init().
The Retry token lifetime is 10 seconds. This lifetime is also checked by
quic_generate_retry_check(). If quic_generate_retry_check() fails, the received
packet is dropped without anymore packet processing at this time.
2022-05-20 16:57:12 +02:00
Frédéric Lécaille
55367c8679 MINOR: quic_tls: Add quic_tls_decrypt2() implementation
This function does exactly the same thing as quic_tls_decrypt(), except that
it does reuse its input buffer as output buffer. This is needed
to decrypt the Retry token without modifying the packet buffer which
contains this token. Indeed, this would prevent us from decryption
the packet itself as the token belong to the AEAD AAD for the packet.
2022-05-20 16:57:12 +02:00
Frédéric Lécaille
a9c5d8da58 MINOR: quic_tls: Add quic_tls_derive_retry_token_secret()
This function must be used to derive strong secrets from a non pseudo-random
secret (cluster-secret setting in our case) and an IV. First it call
quic_hkdf_extract_and_expand() to do that for a temporary strong secret (tmpkey)
then two calls to quic_hkdf_expand() reusing this strong temporary secret
to derive the final strong secret and IV.
2022-05-20 16:57:12 +02:00
Frédéric Lécaille
359d877f73 MINOR: quic: Dump initial derived secrets
It seems <qc> parameters was removed for an unknown reason preventing
these secrets to dumped by the traces.
2022-05-20 16:57:12 +02:00
Amaury Denoyelle
fe1c785bcc CLEANUP: quic: adjust comment/coding style for TPs init
Fix typo in comment and adjust code alignment for better readability.
2022-05-19 17:40:09 +02:00
Amaury Denoyelle
0daef007e4 BUG/MEDIUM: quic: fix initialization for local/remote TPs
The local and remote TPs were both processed through the same function
quic_transport_params_init(). This caused the remote TPs to be
overwritten with values configured for our local usage.

Change this by reserving quic_transport_params_init() only for our local
TPs. Remote TPs are simply initialized via
quic_dflt_transport_params_cpy().

This bug could result in a connection closed in error by the client due
to a violation of its TPs. For example, curl client closed the
connection after receiving too many CONNECTION_ID due to an invalid
active_connection_id value used.
2022-05-19 17:40:09 +02:00
Christopher Faulet
c95eaefbfd MEDIUM: check: Use the CS to handle subscriptions for read/write events
Instead of using the health-check to subscribe to read/write events, we now
rely on the conn-stream. Indeed, on the server side, the conn-stream's
endpoint is a multiplexer. Thus it seems appropriate to handle subscriptions
for read/write events the same way than for the streams. Of course, the I/O
callback function is not the same. We use srv_chk_io_cb() instead of
cs_conn_io_cb().
2022-05-19 10:12:38 +02:00
Christopher Faulet
361417f9b4 REORG: check: Rename and export I/O callback function
event_srv_chk_io() function is renamed srv_chk_io_cb() to be consistant with
the I/O callback function of connections. In addition, this function is
exported. It will be required to use the conn-stream's subscriptions.
2022-05-19 10:12:38 +02:00
Amaury Denoyelle
c830e1e904 MINOR: mux-quic: implement MAX_DATA emission
This commit is similar to the previous one but deals with MAX_DATA for
connection-level data flow control. It uses the same function
qcc_consume_qcs() to update flow control level and generate a MAX_DATA
frame if needed.
2022-05-18 16:25:07 +02:00
Amaury Denoyelle
a977355aa1 MINOR: mux-quic: implement MAX_STREAM_DATA emission
Send MAX_STREAM_DATA frames when at least half of the allocated
flow-control has been demuxed, frame and cleared. This is necessary to
support QUIC STREAM with received data greater than a buffer.

Transcoders must use the new function qcc_consume_qcs() to empty the QCS
buffer. This will allow to monitor current flow-control level and
generate a MAX_STREAM_DATA frame if required. This frame will be emitted
via qc_io_cb().
2022-05-18 16:25:07 +02:00
Amaury Denoyelle
c985cb167d MINOR: mux-quic: reorganize flow-control frames emission
Adjust the mechanism for MAX_STREAMS_BIDI emission. When a bidirectional
stream is removed, current flow-control level is checked. If needed, a
MAX_STREAMS_BIDI frame is generated and inserted in a new list in the
QCS instance. The new frames will be emitted at the start of qc_send().

This has no impact on the current MAX_STREAMS_BIDI behavior. However,
this mechanism is more flexible and will allow to implement quickly
MAX_STREAM_DATA/MAX_DATA emission.
2022-05-18 15:52:44 +02:00
Amaury Denoyelle
3a0864067a MINOR: mux-quic: remove qcc_decode_qcs() call in XPRT
Slightly change the interface for qcc_recv() between MUX and XPRT. The
MUX is now responsible to call qcc_decode_qcs(). This is cleaner as now
the XPRT does not have to deal with an extra QCS parameter and the MUX
will call qcc_decode_qcs() only if really needed.

This change is possible since there is no extra buffering for
out-of-order STREAM frames and the XPRT does not have to handle buffered
frames.
2022-05-18 15:50:57 +02:00
Amaury Denoyelle
03dcf560ae BUG/MINOR: mux-quic: update session's idle delay before stream creation
This commit is an adaptation from the following patch :
  commit d0de6776826ee18da74e6949752e2f44cba8fdf2
  Author: Willy Tarreau <w@1wt.eu>
  Date:   Fri Feb 4 09:05:37 2022 +0100
  BUG/MINOR: mux-h2: update the session's idle delay before creating the stream

This should fix the incorrect timeouts present in httplog format for
QUIC requests.
2022-05-18 15:30:13 +02:00
Amaury Denoyelle
ca21c768b9 MINOR: ncbuf: refactor ncb_advance()
First adjusted some typos in comments inside the function. Second,
change the naming of some variable to reduce confusion.

A special case has been inserted when advance is done inside a GAP block
and this block is the last of the buffer. In this case, the whole buffer
will be emptied, equivalent to a ncb_init() operation.
2022-05-18 15:30:13 +02:00
Amaury Denoyelle
82c51b561e OPTIM: quic: realign empty Rx buffer
quic_rx_pkts_del() function removes packets from QUIC RX buffer. In most
cases, the buffer will be emptied after it. In this case, it's useful to
realign it. This will avoid future data wrapping and use of an
unnecessary junk to fill a too small contiguous space.
2022-05-18 15:16:26 +02:00
Maciej Zdeb
d01be2ab13 MINOR: peers: Track number of applets run by thread
Maintain number of peers applets run on all threads. It will be used
in next patch for least loaded thread selection.
2022-05-17 16:13:22 +02:00
Christopher Faulet
d9c1d33fa1 MEDIUM: applet: Add support for async appctx startup on a thread subset
It is now possible to start an appctx on a thread subset. Some controls were
added here and there. It is forbidden to start a backend appctx on another
thread than the local one. If a frontend appctx is started on another thread
or a thread subset, the applet .init callback function must be defined. This
callback function is responsible to finalize the appctx startup. It can be
performed synchornously. In this case, the appctx is started on the local
thread. It is not really useful but it is valid. Or it can be performed
asynchronously. In this case, .init callback function is called when the
appctx is woken up for the first time. When this happens, the appctx
affinity is set to the current thread to be able to start the session and
the stream.
2022-05-17 16:13:22 +02:00
Christopher Faulet
6095d57701 MINOR: applet: Add API to start applet on a thread subset
In the same way than for the tasks, the applets api was changed to be able
to start a new appctx on a thread subset. For now the feature is
disabled. Only appctx_new_here() is working. But it will be possible to
start an appctx on a specific thread or a subset via a mask.
2022-05-17 16:13:22 +02:00
Christopher Faulet
387e79727c MINOR: peers: Add a ref to peers section in the peer structure
This change is required to handle asynchrone init of the appctx. It is now
possible to directly get the peers section associated to a peer.
2022-05-17 16:13:22 +02:00
Christopher Faulet
2ae25ea24b MINOR: sink: Add a ref to sink in the sink_forward_target structure
This change is required to be able to refactor the init stage of appctx. It
is now possible to directly get the sink from a forward target.
2022-05-17 16:13:22 +02:00
Christopher Faulet
d0c4ec04b8 MINOR: applet: Add function to release appctx on error during init stage
appctx_free_on_early_error() must be used to release a freshly created
frontend appctx if an error occurred during the init stage. It takes care to
release the stream instead of the appctx if it exists. For a backend appctx,
it just calls appctx_free().
2022-05-17 16:13:21 +02:00
Christopher Faulet
8718c95c0a MINOR: applet: Add a function to finalize frontend appctx startup
appctx_finalize_startup() may be used to finalize the frontend appctx
startup. It is responsible to create the appctx's session and the frontend
conn-stream. On error, it is the caller responsibility to release the
appctx. However, the session is released if it was created. On success, if
an error is encountered in the caller function, the stream must be released
instead of the appctx.

This function should ease the init stage when new appctx is created.
2022-05-17 16:13:21 +02:00
Christopher Faulet
16c0d9cda0 MINOR: applet: Add appctx_init() helper fnuction
It is just a helper function that call the .init applet callback function,
if it exists. This will simplify a bit the init stage when a new applet is
started. For now, this callback function is only used when a new service is
started.
2022-05-17 16:13:21 +02:00
Christopher Faulet
ab5d1dceed MINOR: stream: Export stream_free()
The stream_free() function is now public. It is mandatory to properly handle
errors when a new applet is started.
2022-05-17 16:13:21 +02:00
Christopher Faulet
c9929380a4 MINOR: applet: Change return value for .init callback function
0 is now returned on success and -1 on error.
2022-05-17 16:13:21 +02:00
Christopher Faulet
ac57bb527a MINOR: applet: Prepare appctx to own the session on frontend side
Applets were moved at the same level than multiplexers. Thus, gradually,
applets code is changed to be less dependent from the stream. With this
commit, the frontend appctx are ready to own the session. It means a
frontend appctx will be responsible to release the session.
2022-05-17 16:13:21 +02:00
Christopher Faulet
ef5e1bb4cf CLEANUP: conn-stream: Remove cs_applet_shut declaration from header file
This function was renamed and moved in applet code. cs_applet_shut() does
not exist anymore. Its declaration must be removed.
2022-05-17 16:13:21 +02:00
David Carlier
135c1ec139 BUILD: fix build warning on solaris based systems with __maybe_unused.
__maybe_unused is already defined there.
2022-05-17 11:42:20 +02:00
Remi Tricot-Le Breton
1746a388c5 MINOR: ssl: Add 'ssl-provider' global option
When HAProxy is linked to an OpenSSLv3 library, this option can be used
to load a provider during init. You can specify multiple ssl-provider
options, which will be loaded in the order they appear. This does not
prevent OpenSSL from parsing its own configuration file in which some
other providers might be specified.
A linked list of the providers loaded from the configuration file is
kept so that all those providers can be unloaded during cleanup. The
providers loaded directly by OpenSSL will be freed by OpenSSL.
2022-05-17 10:56:05 +02:00
Christopher Faulet
18c13d3bd8 MEDIUM: http-ana: Add a proxy option to restrict chars in request header names
The "http-restrict-req-hdr-names" option can now be set to restrict allowed
characters in the request header names to the "[a-zA-Z0-9-]" charset.

Idea of this option is to not send header names with non-alphanumeric or
hyphen character. It is especially important for FastCGI application because
all those characters are converted to underscore. For instance,
"X-Forwarded-For" and "X_Forwarded_For" are both converted to
"HTTP_X_FORWARDED_FOR". So, header names can be mixed up by FastCGI
applications. And some HAProxy rules may be bypassed by mangling header
names. In addition, some non-HTTP compliant servers may incorrectly handle
requests when header names contain characters ouside the "[a-zA-Z0-9-]"
charset.

When this option is set, the policy must be specify:

  * preserve: It disables the filtering. It is the default mode for HTTP
              proxies with no FastCGI application configured.

  * delete: It removes request headers with a name containing a character
            outside the "[a-zA-Z0-9-]" charset. It is the default mode for
            HTTP backends with a configured FastCGI application.

  * reject: It rejects the request with a 403-Forbidden response if it
            contains a header name with a character outside the
            "[a-zA-Z0-9-]" charset.

The option is evaluated per-proxy and after http-request rules evaluation.

This patch may be backported to avoid any secuirty issue with FastCGI
application (so as far as 2.2).
2022-05-16 16:00:26 +02:00