25772 Commits

Author SHA1 Message Date
Amaury Denoyelle
ef206d441c MINOR: check: ensure QUIC checks configuration coherency
QUIC is now supported on the backend side, thus it is possible to use it
with server checks. However, checks configuration can be quite
extensive, differing greatly from the server settings.

This patch ensures that QUIC checks are always performed under a
controlled context. Objectives are to avoid any crashes and ensure that
there is no suprise for users in respect to the configuration.

The first part of this patch ensures that QUIC checks can only be
activated on QUIC servers. Indeed, QUIC requires dedicated
initialization steps prior to its usage.

The other part of this patch disables QUIC usage when one or multiple
specific check connection settings are specified in the configuration,
diverging from the server settings. This is the simplest solution for
now and ensure that there is no hidden behavior to users. This means
that it's currently impossible to perform QUIC checks if other endpoints
that the server itself. However for now there is no real use-case for
this scenario.

Along with these changes, check-proto documentation is updated to
clarify QUIC checks behavior.
2025-11-14 13:42:08 +01:00
Amaury Denoyelle
ca5a5f37a1 MINOR: check: use auto SNI for QUIC checks
By default, check SNI is set to the Host header when an HTTPS check is
performed. This patch extends this mode so that it is also active when
QUIC checks are executed.

This patch should improve reuse rate with checks. Indeed, SNI is also
already automatically set for normal traffic. The same value must be
used during check so that a connection hash match can be found.
2025-11-14 13:42:08 +01:00
Olivier Houchard
333deef485 BUG/MEDIUM: h1: prevent a crash on HTTP/2 upgrade
Change h1_process() to return -2 when the mux is destroyed but the
connection is not, so that we can differentiate between "both mux and
connection were destroyed" and "only the mux was destroyed".
It can happen that only the mux gets destroyed, and the connection is
still alive, if we did upgrade it to HTTP/2.
In h1_wake(), if the connection is alive, then return 0, as the wake
methods should only return -1 if the connection is dead.
This fixes a bug where the ssl xprt would consider the connection
destroyed, and thus would consider its tasklet should die, and return
NULL, and its TASK_RUNNING flag would never be removed, leading to an
infinite loop later on. This would happen anytime an HTTP/2 upgrade was
successful.

This should be backported up to 2.8. While the bug by commit
00f43b7c8b136515653bcb2fc014b0832ec32d61, it was not triggered before
only by chance, and exists in previous releases too.
2025-11-14 12:49:35 +01:00
Olivier Houchard
2f8f09854f MINOR: h1: h1_release() should return if it destroyed the connection
h1_release() is called to destroy everything related to the mux h1,
usually even the connection. However, it handles upgrades to HTTP/2 too,
in which case the h1 mux will be destroyed, but the connection will
still be alive. So make it so it returns 0 if everything is destroyed,
and -1 if the connection is still alive.

This should be backported up to 2.8, as a future bugfix will depend on
it.
2025-11-14 12:49:35 +01:00
Christopher Faulet
14a333c4f4 CLEANUP: stick-tables: Don't needlessly compute shard number in stksess_free()
Since commit 0bda33a3e ("MINOR: stick-tables: remove the uneeded read lock
in stksess_free()"), the lock on the shard is no longer acquired. So it is
useless to still compture the shard number. The result is never used and can
be safely removed.
2025-11-14 11:56:14 +01:00
Christopher Faulet
346d6c3ac7 BUG/MINOR: stick-tables: Fix return value for __stksess_kill()
The commit 9938fb9c7 ("BUG/MEDIUM: stick-tables: Fix race with peers when
killing a sticky session") introduced a regression.

__stksess_kill() must always return 0 if the session cannot be released. But
when the ref_cnt is tested under the update lock, a success is reported if
the session is still in-used. 0 must be returned in that case.

This bug is harmless because callers never use the return value of
__stksess_kill() or stksess_kill().

This bug must be backported as far as 3.0.
2025-11-14 11:56:14 +01:00
Christopher Faulet
bd4fff9a76 BUG/MEDIUM: stick-tables: Always return the good stksess from stktable_set_entry
In stktable_set_entry(), the return value of __stktable_store() is not
tested while it is possible to get an existing session with the same key
instead of the one we want to insert. It happens when we fails to upgrade
the read lock on the bucket to an write lock. In that case, we release the
lock for a short time to get a write lock.

So, to fix the bug, we must check the session returned by __stktable_store()
and take care to return this one.

The bug was introduced by the commit e62885237c ("MEDIUM: stick-table: make
stktable_set_entry() look up under a read lock"). It must be backported as
far as 2.8.
2025-11-14 11:56:12 +01:00
William Lallemand
bf639e581d BUILD: ech: fix clang warnings
No impact as the state is either SHOW_ECH_SPECIFIC or SHOW_ECH_ALL but
never anything else.

src/ech.c:240:6: error: variable 'p' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized]
  240 |         if (ctx->state == SHOW_ECH_ALL) {
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~
src/ech.c:275:12: note: uninitialized use occurs here
  275 |         ctx->pp = p;
      |                   ^
src/ech.c:240:2: note: remove the 'if' if its condition is always true
  240 |         if (ctx->state == SHOW_ECH_ALL) {
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/ech.c:228:17: note: initialize the variable 'p' to silence this warning
  228 |         struct proxy *p;
      |                        ^
      |                         = NULL
src/ech.c:240:6: error: variable 'bind_conf' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized]
  240 |         if (ctx->state == SHOW_ECH_ALL) {
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~
src/ech.c:276:11: note: uninitialized use occurs here
  276 |         ctx->b = bind_conf;
      |                  ^~~~~~~~~
src/ech.c:240:2: note: remove the 'if' if its condition is always true
  240 |         if (ctx->state == SHOW_ECH_ALL) {
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/ech.c:229:29: note: initialize the variable 'bind_conf' to silence this warning
  229 |         struct bind_conf *bind_conf;
      |                                    ^
      |                                     = NULL
2 errors generated.
make: *** [Makefile:1062: src/ech.o] Error 1
2025-11-14 11:35:38 +01:00
William Lallemand
e17881128b REGTESTS: ssl: activate ssl_curve_name.vtc for AWS-LC
It was difficult to test ssl_curve_name.vtc with AWS-LC without a way to
check the AWS-LC API. Let's add awslc_api_atleast() in the start
conditions.
2025-11-14 11:01:45 +01:00
William Lallemand
3d15c07ed0 MINOR: cfgcond: add "awslc_api_atleast" and "awslc_api_before"
AWS-LC features are not easily tested with just the openssl version
constant. AWS-LC uses its own API versioning stored in the
AWSLC_API_VERSION constant.

This patch add the two awslc_api_atleast and awslc_api_before predicates
that help to check the AWS-LC API.
2025-11-14 11:01:45 +01:00
William Lallemand
35d21a8bc0 DOC: configuration: add missing openssl_version predicates
Add missing openssl_version_atleast() and  openssl_version_before()
predicates.

The predicates exist since 3aeb3f9347 ("MINOR: cfgcond: implements
openssl_version_atleast and openssl_version_before").

Must be backported in every stable versions.
2025-11-14 11:01:45 +01:00
William Lallemand
9ad018a3dd DOC: configuration: add missing ssllib_name_startswith()
Add the missing ssllib_name_startswith() predicate in the documentation.

The predicate was introduced with b01179aa9 ("MINOR: ssl: Add
ssllib_name_startswith precondition").

Must be backported as far as 2.6.
2025-11-14 11:01:45 +01:00
Amaury Denoyelle
8415254cea MINOR: check: clarify check-reuse-pool interaction with reuse policy
check-reuse-pool can only perform as expected if reuse policy on the
backend is set to aggressive or higher. Update the documentation to
reflect this and implement a server diag warning.
2025-11-14 10:44:05 +01:00
Amaury Denoyelle
52a7d4ec39 BUG/MINOR: check: fix reuse-pool if MUX inherited from server
Check reuse is only performed if no specific check connect options are
specified on the configuration. This ensures that reuse won't be
performed if intending to use different connection parameters from the
default traffic.

This relies on tcpcheck_use_nondefault_connect() which indicates if the
check has any specific connection parameters. One of them if check
<mux_proto> field. However, this field may be automatically set during
init_srv_check() in some specific conditions without any explicit
configuration, most notably when using http-check rulesets on an HTTP
backend. Thus, it prevents connection reuse for these checks.

This commit fixes this by adjuting tcpcheck_use_nondefault_connect().
Beside checking check <mux_proto> field, it also detects if it is
different from the server configuration. This is sufficient to know if
the value is derived from the configuration or automatically calculated
in init_srv_check().

Note that this patch introduces a small behavior change. Prior to it,
check reuse were never performed if "check-proto" is explicitely
configured. Now, check reuse will be performed if the configured value
is identical to the server MUX protocol. This is considered as
acceptable as connection reuse is safe when using a similar MUX
protocol.

This must be backported up to 3.2.
2025-11-14 10:44:05 +01:00
Amaury Denoyelle
5d021c028e BUG/MINOR: check: only try connection reuse for http-check rulesets
In 3.2, a new server keyword "check-reuse-pool" has been introduced. It
allows to reuse a connection for a new check, instead of always
initializing a new one. This is only performed if the check does not
rely on specific connection parameters differing from the server.

This patch further restricts reuse for checks only when an HTTP ruleset
is used at the backend level. Indeed, reusing a connection outside of
HTTP is an undefined behavior. The impact of this bug is unknown and
depends on the proxy/server configuration. In the case of an HTTP
backend with non-HTTP checks, check-reuse-pool would probably cause a
drop in reuse rate.

Along this change, implement a new diagnostic warning on servers to
report that check-reuse-pool cannot apply due to an incompatible check
type.

This must be backported up to 3.2.
2025-11-14 10:44:03 +01:00
Amaury Denoyelle
d92f8f84fb MINOR: cfgdiag: adjust diag on servers
Adjust code dealing with diagnostics performed on server. The objective
is to extract the check on duplicate cookies in a dedicated function
outside of the proxies/servers loop.

This does not have any noticeable impact. This patch is merely a code
improvment to implement easily new future diagnostics on servers.
2025-11-14 10:00:26 +01:00
Amaury Denoyelle
d12971dfea MINOR: check: delay MUX init when SSL ALPN is used
When instantiating a new connection for check, its MUX may be
initialized early. This was not performed though if SSL ALPN negotiation
will be used, except if check MUX is already fixed.

However, this method of initialization is problematic when QUIC MUX is
used. Indeed, this multiplexer must only be instantiated after the above
application protocol is known, which is derived from the ALPN
negotiation. If this is not the case a crash will occur in qmux_init().

In fact, a similar problem was already encountered for normal traffic.
Thus, a change was performed in connect_server() : MUX early
initialization is now always skipped if SSL ALPN negotiation is active,
even if MUX is already fixed. This patch introduces a similar change for
checks.

Without this patch, it is not possible to perform check on QUIC servers
as expected. Indeed, when http-check ruleset is active a crash would
occur prior to it.
2025-11-14 09:49:04 +01:00
Damien Claisse
1d46c08689 MINOR: ssl/sample: expose ssl_*c_curve for AWS-LC
The underlying SSL_get_negotiated_group function has been backported
into AWS-LC [1], so expose the feature for users of this TLS stack
as well. Note that even though it was actually added in AWS-LC 1.56.0,
we require AWSLC_API_VERSION >= 35 which was released in AWS-LC 1.57.0,
because API version wasn't incremented after this change. As the delta
is one minor version (less than two weeks), I consider this acceptable
to avoid relying on a proxy constant like TLSEXT_nid_unknown which
might be removed at some point.

[1] d6a37244ad
2025-11-13 17:36:43 +01:00
William Lallemand
b9b158ea4c BUG/MINOR: acme: can't override the default resolver
httpclient_acme_init() was called in cfg_parse_acme() which is at
section parsing. httpclient_acme_init() also calls
httpclient_create_proxy() which could create a "default" resolvers
section if it doesn't exists.

If one tries to override the default resolvers section after an ACME
section, the resolvers section parsing will fail because the section was
already created by httpclient_create_proxy().

This patch fixes the issue by moving the initialization of the ACME
proxy to a pre_check callback, which is called just before
check_config_validity().

Must be backported in 3.2.
2025-11-13 17:17:11 +01:00
William Lallemand
2bdf5a7937 BUG/MEDIUM: acme: move from mt_list to a rwlock + ebmbtree
The current ACME scheduler suffers from problems due to the way the
tasks are stored:

- MT_LIST are not scalables when having a lot of ACME tasks and having
  to look for a specific one.
- the acme_task pointer was stored in the ckch_store in order to not
  passing through the whole list. But a ckch_store can be updated and
  the pointer lost in the previous one.
- when a task fails, the ptr in the ckch_store was not removed because
  we only work with a copy of the original ckch_store, it would need to
  lock the ckchs_tree and remove this pointer.

This patch fixes the issues by removing the MT_LIST-based architecture,
and replacing it by a simple ebmbtree + rwlock design.

The pointer to the task is not stored anymore in the ckch_store, but
instead it is stored in the acme_tasks tree. Finding a task is done by
doing a lookup on this tree with a RDLOCK.
Instead of checking if store->acme_task is not NULL, a lookup is also
done.

This allow to remove the stuck "acme_task" pointer in the store, which
was preventing to restart an acme task when the previous failed for this
specific certificate.

Must be backported in 3.2.
2025-11-13 15:18:12 +01:00
Frederic Lecaille
c76e072e43 MINOR: quic-be: avoid a useless I/O callback wakeup for 0-RTT sessions
For backends and 0-RTT sessions, this patch modifies the ->start() callback to
wake up the I/O callback only if the connection (and the mux) is not ready. Note that
connect_server() has been modified to call this xprt callback just after having
created the mux and installed the mux. Contrary to 1-RTT session, for 0-RTT sessions,
the connections are always ready before calling this ->start xprt callback.
2025-11-13 14:04:31 +01:00
Frederic Lecaille
92d2ab76e0 MINOR: quic-be: do not create the mux after handshake completion (for 0-RTT)
This is required during connection with 0-RTT support, to prevent two mux creations.
Indeed, for 0-RTT sessions, the QUIC mux is already started very soon from
connect_server() (src/backend.c).
2025-11-13 14:04:31 +01:00
Frederic Lecaille
d84463f9f6 MINOR: quic-be: validate the 0-RTT transport parameters
During 0-RTT sessions, some server transport parameters are reused after having
been save from previous sessions. These parameters must not be reduced
when it resends them. The client must check this is the case when some early data
are accepted by the server. This is what is implemented by this patch.

Implement qc_early_tranport_params_validate() which checks the new server parameters
are not reduced.

Also implement qc_ssl_eary_data_accepted() which was not implemented for TLS
stack without 0-RTT support (for instance wolfssl). That said this function
was no more used. This is why the compilation against wolfssl could not fail.
2025-11-13 14:04:31 +01:00
Frederic Lecaille
6419b9f204 MEDIUM: quic-be: enable the use of 0-RTT
This patch allows the use of 0-RTT feature on QUIC server lines with "allow-0rtt"
option. In fact 0-RTT is really enabled only if ssl_sock_srv_try_reuse_sess()
successfully manages to reuse the SSL session and the chosen application protocol
from previous connections.

Note that, at this time, 0-RTT works only with quictls and aws-lc as TLS stack.

(0-RTT does not work at all (even for QUIC frontends) with libressl).
2025-11-13 14:04:31 +01:00
Frederic Lecaille
46d490f7c2 MINOR: quic-be: discard the 0-RTT keys
This patch allows the discarding of the 0-RTT keys as soon as 1-RTT keys
are available.
2025-11-13 14:04:31 +01:00
Frederic Lecaille
3f60891360 MEDIUM: quic-be: qc_send_mux() adaptation for 0-RTT
When entering this function, a selection is done about the encryption level
to be used to send data. For a client, the early data encryption level
is used to send 0-RTT if this encryption level is initialized.

The Initial encryption is also registered to the send list for clients if there
is Initial crypto data to send. This allow Initial and 0-RTT packets to
be coalesced by datagrams.
2025-11-13 14:04:31 +01:00
Frederic Lecaille
a4bbbc75db MINOR: quic-be: Send post handshake frames from list of frames (0-RTT)
This patch is required to make 0-RTT work. It modifies the prototype of
quic_build_post_handshake_frames() to send post handshake frames from a
list of frames in place of the application encryption level (used
as <qc->ael> local variable).

This patch does not modify at all the current QUIC stack behavior (even for
QUIC frontends). It must be considered as a preparation for the code
to come about 0-RTT support for QUIC backends.
2025-11-13 14:04:31 +01:00
Frederic Lecaille
ac1d3eba88 MINOR: quic-be: allow the preparation of 0-RTT packets
A QUIC server never sends 0-RTT packets contrary to the client.

This very simple modification allow the the preparation of 0-RTT packets
with early data as encryption level (->eel).
2025-11-13 14:04:31 +01:00
Frederic Lecaille
6e14365a5b MEDIUM: quic-be: modify ssl_sock_srv_try_reuse_sess() to reuse backend sessions (0-RTT)
This function is called for both TCP and QUIC connections to reuse SSL sessions
saved by ssl_sess_new_srv_cb() callback called upon new SSL session creation.

In addition to this, a QUIC SSL session must reuse the ALPN and some specific QUIC
transport parameters. This is what is added by this patch for QUIC 0-RTT sessions.

Note that for now on, ssl_sock_srv_try_reuse_sess() may fail for QUIC connections
if it did not managed to reuse the ALPN. The caller must be informed of such an
issue. It must not enable 0-RTT for the current session in this case. This is
impossible without ALPN which is required to start a mux.

ssl_sock_srv_try_reuse_sess() is modified to always succeeds for TCP connections.
2025-11-13 14:04:31 +01:00
Frederic Lecaille
5309dfb56b MINOR: quic-be: Save the backend 0-RTT parameters
For both TCP and QUIC connections, this is ssl_sess_new_srv_cb() callback which
is called when a new SSL session is created. Its role is to save the session to
be reused for the next sessions.

This patch modifies this callback to save the QUIC parameters to be reused
for the next 0-RTT sessions (or during SSL session resumption).

The already existing path_params->nego_alpn member is used to store the ALPN as
this is done for TCP alongside path_params->tps new quic_early_transport_params
struct used to save the QUIC transport parameters to be reused for 0-RTT sessions.
2025-11-13 14:04:31 +01:00
Frederic Lecaille
41e40eb431 MINOR: quic-be: helper quic_reuse_srv_params() function to reuse server params (0-RTT)
Implement quic_reuse_srv_params() whose role is to reuse the ALPN negotiated
during a first connection to a QUIC backend alongside its transport parameters.
2025-11-13 14:04:31 +01:00
Frederic Lecaille
33564ca54c MINOR: quic-be: helper functions to save/restore transport params (0-RTT)
Define quic_early_transport_params new struct for QUIC transport parameters
in relation with 0-RTT. This parameters must be saved during a first session to
be reused for 0-RTT next sessions.

qc_early_transport_params_cpy() copies the 0-RTT transport parameters to be
saved during a first connection to a backend. The copy is made from
a quic_transport_params struct to a quic_ealy_transport_params struct.

On the contrary, qc_early_transport_params_reuse() copies the transport parameters
to be reused for a 0-RTT session from a previous one. The copy is made
from a quic_early_transport_params strcut to a quic_transport_params struct.

Also add QUIC_EV_EARLY_TRANSP_PARAMS trace event to dump such 0-RTT
transport parameters from traces.
2025-11-13 14:04:31 +01:00
Frederic Lecaille
80070fe51c MEDIUM: quic-be: Parse, store and reuse tokens provided by NEW_TOKEN
Add a per thread ist struct to srv_per_thread struct to store the QUIC token to
be reused for subsequent sessions.

Parse at packet level (from qc_parse_ptk_frms()) these tokens and store
them calling qc_try_store_new_token() newly implemented function. This is
this new function which does its best (may fail) to update the tokens.

Modify qc_do_build_pkt() to resend these tokens calling quic_enc_token()
implemented by this patch.
2025-11-13 14:04:31 +01:00
Frederic Lecaille
8f23d4d287 MINOR: quic-be: Parse the NEW_TOKEN frame
Rename ->data qf_new_token struct field to ->w_data to distinguish it from
->r_data new field used to parse the NEW_TOKEN frame. Indeed to build the
NEW_TOKEN we need to write it to a static buffer into the frame struct. To
parse it we only need to store the address of the token field into the
RX buffer.
2025-11-13 14:04:31 +01:00
Frederic Lecaille
64e32a0767 BUG/MEDIUM: quic-be: do not launch the connection migration process
At this time the connection migration is not supported by QUIC backends.
This patch prevents this process to be launched for connections to QUIC backends.

Furthermore, the connection migration process could be started systematically
when connecting a backend to INADDR_ANY, leading to crashes into qc_handle_conn_migration()
(when referencing qc->li).

Thank you to @InputOutputZ for having reported this issue in GH #3178.

This patch simply checks the connection type (listener or not) before checking if
a connection migration must be started.

No need to backport because support for QUIC backends is available from 3.3.
2025-11-13 13:52:40 +01:00
William Lallemand
071e5063d8 BUG/MINOR: acme: more explicit error when BIO_new_file()
Replace the error message of BIO_new_file() when the account-key cannot
be created on disk by "acme: cannot create the file '%s'". It was
previously "acme: out of memory." Which is unclear.

Must be backported to 3.2.
2025-11-13 11:56:33 +01:00
Remi Tricot-Le Breton
1b19e4ef32 BUG/MEDIUM: init: 'devnullfd' not properly closed for master
Since commit "1ec59d3 MINOR: init: Make devnullfd global and create it
earlier in init" the devnullfd pointing towards /dev/null gets created
early in the init process but it was closed after the call to
"mworker_run_master". The master process never got to the FD closing
code and we had an FD leak.

This patch does not need to be backported.
2025-11-12 16:06:28 +01:00
Amaury Denoyelle
7927ee95f3 BUG/MINOR: do not account backend connections into maxconn
Remove QUIC backend connections from global actconn accounting. Indeed,
this counter is only used on the frontend side. This is required to
ensure maxconn coherence.
2025-11-12 14:45:00 +01:00
Aurelien DARRAGON
3262da84ea BUG/MEDIUM: stats-file: fix shm-stats-file preload not working anymore
Due to recent commit 5c299dee ("MEDIUM: stats: consider that shared stats
pointers may be NULL") shm-stats-file preloading suddenly stopped working

In fact preloading should be considered as an initializing step so the
counters may be assigned there without checking for NULL first.
Indeed there are supposed to be NULL because preloading occurs before
counters_{fe,be}_shared_prepare() which takes care of setting the pointers
for counters if they weren't set before.

Obviously this corner-case was overlooked during 5c299dee writing and
testing. Thanks to Nick Ramirez for having reported the issue.

No backport needed, this issue is specific to 3.3.
2025-11-11 22:36:17 +01:00
Aurelien DARRAGON
a287841578 MINOR: stats-proxy: ensure future-proof FN_AGE manipulation in me_generate_field()
Commit ad1bdc33 ("BUG/MAJOR: stats-file: fix crash on non-x86 platform
caused by unaligned cast") revealed an ambiguity in me_generate_field()
around FN_AGE manipulation. For now FN_AGE can only be stored as u32 or
s32, but in the future we could also support 64bit FN_AGES, and the
current code assumes 32bits types and performs and explicit unsigned int
cast. Instead we group current 32 bits operations for FF_U32 and FF_S32
formats, and let room for potential future formats for FN_AGE.

Commit ad1bdc33 also suggested that the fix was temporary and the approach
must change, but after a code review it turns out the current approach
(generic types manipulation under me_generate_field()) is legit. The
introduction of shm-stats-file feature didn't change the logic which
was initially implemented in 3.0. It only extended it and since shared
stats are now spread over thread-groups since 3.3, the use of atomic
operations made typecasting errors more visible, and structure mapping
change from d655ed5f14 ("BUG/MAJOR: stats-file: ensure
shm_stats_file_object struct mapping consistency (2nd attempt)") was in
fact the only change to blame for the crash on non-x86 platforms.

With ambiguities removed in me_generate_field(), let's hope we don't face
similar bugs in the future. Indeed, with generic counters, and more
specifically shared ones (which leverage atomic ops), great care must be
taken when changing their underlying types as me_generate_field() solely
relies on stat_col descriptor to know how to read the stat from a generic
pointer, so any breaking change must be reflected in that function as well

No backport needed.
2025-11-10 21:32:22 +01:00
Amaury Denoyelle
5a8728d03a MEDIUM/OPTIM: quic: alloc quic_conn after CID collision check
On Initial packet parsing, a new quic_conn instance is allocated via
qc_new_conn(). Then a CID is allocated with its value derivated from
client ODCID. On CID tree insert, a collision can occur if another
thread was already parsing an Initial packet from the same client. In
this case, the connection is released and the packet will be requeued to
the other thread.

Originally, CID collision check was performed prior to quic_conn
allocation. This was changed by the commit below, as this could cause
issue on quic_conn alloc failure.

  commit 4ae29be18c5b212dd2a1a8e9fa0ee2fcb9dbb4b3
  BUG/MINOR: quic: Possible endless loop in quic_lstnr_dghdlr()

However, this procedure is less optimal. Indeed, qc_new_conn() performs
many steps, thus it could be better to skip it on Initial CID collision,
which can happen frequently. This patch restores the older order of
operations, with CID collision check prior to quic_conn allocation.

To ensure this does not cause again the same bug, the CID is removed in
case of quic_conn alloc failure. This should prevent any loop as it
ensures that a CID found in the global tree does not point to a NULL
quic_conn, unless if CID is attach to a foreign thread. When this thread
will parse a re-enqueued packet, either the quic_conn is already
allocated or the CID has been removed, triggering a fresh CID and
quic_conn allocation procedure.
2025-11-10 12:10:14 +01:00
Amaury Denoyelle
a9d11ab7f3 MINOR: quic: extend traces on CID allocation
Add new traces to detect the CID generation method and also when an
Initial packet is requeued due to CID collision.
2025-11-10 12:10:14 +01:00
Amaury Denoyelle
2623e0a0b7 BUG/MEDIUM: quic: handle collision on CID generation
CIDs are provided by haproxy so that the peer can use them as DCID of
its packets. Their value is set via a random generator. It happens on
several occasions during connection lifetime:
* via ODCID derivation if haproxy is the server
* on quic_conn init if haproxy is the client
* during post-handshake if haproxy is the server
* on RETIRE_CONNECTION_ID frame parsing

CIDs are stored in a global tree. On ODCID derivation, a check is
performed to ensure the CID is not a duplicate value. This is mandatory
to properly handle multiple INITIAL packets from the same client on
different thread.

However, for the other cases, no check is performed for CID collision.
As _quic_cid_insert() is silent, the issue is not detected at all. This
results in a CID advertized to the peer but not stored in the global
one. In the end, this may cause two issues. The first one is that
packets from the client which use the new CID will be rejected by
haproxy, most probably with a STATELESS_RESET. The second issue is that
it can cause a crash during quic_conn release. Indeed, the CID is stored
in the quic_conn local tree and thus eb_delete() for the global tree
will be performed. As <leaf_p> member is uninit, this results in a
segfault.

Note that this issue is pretty rare. It can only be observed if running
with a high number of concurrent connections in parallel, so that the
random generator will provide duplicate values. Patch is still labelled
as MEDIUM as this modifies code paths used frequently.

To fix this, _quic_cid_insert() unsafe function is completely removed.
Instead, quic_cid_insert() can be used, which reports an error code if a
collision happens. CID are then stored in the quic_conn tree only after
global tree insert success. Here is the solution for each steps if a
collision occurs :
* on init as client: the connection is completely released
* post-handshake: the CID is immediately released. The connection is
  kept, but it will miss an extra CID.
* on RETIRE_CONNECTION_ID parsing: a loop is implemented to retry random
  generation. It it fails several times, the connection is closed in
  error.

A small convenience change is made to quic_cid_insert(). Output
parameter <new_tid> can now be NULL, which is useful as most of the
times caller do not care about it.

This must be backported up to 2.6.
2025-11-10 12:10:14 +01:00
Amaury Denoyelle
419e5509d8 MINOR: quic: split CID alloc/generation function
Split new_quic_cid() function into multiple ones. This patch should not
introduce any visible change. The objective is to render CID allocation
and generation more modular.

The first advantage of this patch is to bring code simplication. In
particular, conn CID sequence number increment and insertion into
connection tree is simpler than before. Another improvment is also that
errors could now be handled easier at each different steps of the CID
init.

This patch is a prerequisite for the fix on CID collision, thus it must
be backported prior to it to every affected version.
2025-11-10 12:10:14 +01:00
Amaury Denoyelle
0ef473ba6b MINOR: quic: adjust CID conn tree alloc in qc_new_conn()
Change qc_new_conn() so that the connection CID tree is allocated
earlier in the function. This patch does not introduce a behavior
change. Its objective is to facilitate future evolutions on CIDs
handling.

This patch is a prerequisite for the fix on CID collision, thus it must
be backported prior to it to every affected version.
2025-11-10 12:10:14 +01:00
Amaury Denoyelle
73621adb23 BUG/MINOR: quic: close connection on CID alloc failure
During RETIRE_CONNECTION_ID frame parsing, a new connection ID is
immediately reallocated after the release of the previous one. This is
done to ensure that the peer will never run out of DCID.

Prior to this patch, a CID allocation failure was be silently ignored.
This prevent the emission of a new CID, which could prevent the peer to
emit packets if it had no other CIDs available for use. Now, such error
is considered fatal to the connection. This is the safest solution as
it's better to close connections when memory is running low.

It must be backported up to 2.8.
2025-11-10 12:10:14 +01:00
Willy Tarreau
137d5ba93f BUG/MEDIUM: config: for word expansion, empty or non-existing are the same
Amaury reported a case where "${FOO[*]}" still produces an empty field.
It happens if the variable is defined but does not contain any non-space
characters. The reason is that we special-case word expansion only on
non-existing vars. Let's change the ordering of operations so that word-
expanded vars always pretend the current arg is not an empty quote, so
that we don't make any difference between a non-existing var and an
empty one.

No backport is needed unless commit 1968731765 ("BUG/MEDIUM: config:
solve the empty argument problem again") is.
2025-11-10 11:59:35 +01:00
Willy Tarreau
b26a6d50c6 [RELEASE] Released version 3.3-dev12
Released version 3.3-dev12 with the following main changes :
    - MINOR: quic: enable SSL on QUIC servers automatically
    - MINOR: quic: reject conf with QUIC servers if not compiled
    - OPTIM: quic: adjust automatic ALPN setting for QUIC servers
    - MINOR: sample: optional AAD parameter support to aes_gcm_enc/dec
    - REGTESTS: converters: check USE_OPENSSL in aes_gcm.vtc
    - BUG/MINOR: resolvers: ensure fair round robin iteration
    - BUG/MAJOR: stats-file: fix crash on non-x86 platform caused by unaligned cast
    - OPTIM: backend: skip conn reuse for incompatible proxies
    - SCRIPTS: build-ssl: allow to build a FIPS version without FIPS
    - OPTIM: proxy: move atomically access fields out of the read-only ones
    - SCRIPTS: build-ssl: fix rpath in AWS-LC install for openssl and bssl bin
    - CI: github: update to macos-26
    - BUG/MINOR: quic: fix crash on client handshake abort
    - MINOR: quic: do not set conn member if ssl_sock_ctx
    - MINOR: quic: remove connection arg from qc_new_conn()
    - BUG/MEDIUM: server: Add a rwlock to path parameter
    - BUG/MEDIUM: server: Also call srv_reset_path_parameters() on srv up
    - BUG/MEDIUM: mux-h1: fix 414 / 431 status code reporting
    - BUG/MEDIUM: mux-h2: make sure not to move a dead connection to idle
    - BUG/MEDIUM: connections: permit to permanently remove an idle conn
    - MEDIUM: cfgparse: deprecate 'master-worker' keyword alone
    - MEDIUM: cfgparse: 'daemon' not compatible with -Ws
    - DOC: configuration: deprecate the master-worker keyword
    - MINOR: quic: remove <mux_state> field
    - BUG/MEDIUM: stick-tables: Make sure we handle expiration on all tables
    - MEDIUM: stick-tables: Optimize the expiration process a bit.
    - MEDIUM: ssl/ckch: use ckch_store instead of ckch_data for ckch_conf_kws
    - MINOR: acme: generate a temporary key pair
    - MEDIUM: acme: generate a key pair when no file are available
    - BUILD: ssl/ckch: wrong function name in ckch_conf_kws
    - BUILD: acme: acme_gen_tmp_x509() signedness and unused variables
    - BUG/MINOR: acme: fix initialization issue in acme_gen_tmp_x509()
    - BUILD: ssl/ckch: fix ckch_conf_kws parsing without ACME
    - MINOR: server: move the lock inside srv_add_idle()
    - DOC: acme: crt-store allows you to start without a certificate
    - BUG/MINOR: acme: allow 'key' when generating cert
    - MINOR: stconn: Add counters to SC to know number of bytes received and sent
    - MINOR: stream: Add samples to get number of bytes received or sent on each side
    - MINOR: counters: Add req_in/req_out/res_in/res_out counters for fe/be/srv/li
    - MINOR: stream: Remove bytes_in and bytes_out counters from stream
    - MINOR: counters: Remove bytes_in and bytes_out counter from fe/be/srv/li
    - MINOR: stats: Add stats about request and response bytes received and sent
    - MINOR: applet: Add function to get amount of data in the output buffer
    - MINOR: channel: Remove total field from channels
    - DEBUG: stream: Add bytes_in/bytes_out value for both SC in session dump
    - MEDIUM: stktables: Limit the number of stick counters to 100
    - BUG/MINOR: config: Limit "tune.maxpollevents" parameter to 1000000
    - BUG/MEDIUM: server: close a race around ready_srv when deleting a server
    - BUG/MINOR: config: emit warning for empty args when *not* in discovery mode
    - BUG/MEDIUM: config: solve the empty argument problem again
    - MEDIUM: config: now reject configs with empty arguments
    - MINOR: tools: add support for ist to the word fingerprinting functions
    - MINOR: tools: add env_suggest() to suggest alternate variable names
    - MINOR: tools: have parse_line's error pointer point to unknown variable names
    - MINOR: cfgparse: try to suggest correct variable names on errors
    - IMPORT: cebtree: Replace offset calculation with offsetof to avoid UB
    - BUG/MINOR: acme: wrong dns-01 challenge in the log
    - MEDIUM: backend: Defer conn_xprt_start() after mux creation
    - MINOR: peers: Improve traces for peers
    - MEDIUM: peers: No longer ack updates during a full resync
    - MEDIUM: peers: Remove commitupdate field on stick-tables
    - BUG/MEDIUM: peers: Fix update message parsing during a full resync
    - MINOR: sample/stats: Add "bytes" in req_{in,out} and res_{in,out} names
    - BUG/MEDIUM: stick-tables: Make sure updates are seen as local
    - BUG/MEDIUM: proxy: use aligned allocations for struct proxy
    - BUG/MEDIUM: proxy: use aligned allocations for struct proxy_per_tgroup
    - BUG/MINOR: acme: avoid a possible crash on error paths
v3.3-dev12
2025-11-08 12:12:00 +01:00
Willy Tarreau
5574163073 BUG/MINOR: acme: avoid a possible crash on error paths
In acme_EVP_PKEY_gen(), an error message is printed if *errmsg is set,
however, since commit 546c67d13 ("MINOR: acme: generate a temporary key
pair"), errmsg is passed as NULL in at least one occurrence, leading
the compiler to issue a NULL deref warning at -O3. And indeed, if the
errors are encountered, a crash will occur. No backport is needed.
2025-11-07 22:27:25 +01:00
Willy Tarreau
fb8edd0ce6 BUG/MEDIUM: proxy: use aligned allocations for struct proxy_per_tgroup
In 3.2, commit f879b9a18 ("MINOR: proxies: Add a per-thread group field
to struct proxy") introduced struct proxy_per_tgroup that is declared as
thread_aligned, but is allocated using calloc(). Thus it is at risk of
crashing on machines using instructions requiring 64-byte alignment such
as AVX512. Let's use ha_aligned_zalloc_typed() instead of malloc().

For 3.2, we don't have aligned allocations, so instead the THREAD_ALIGNED()
will have to be removed from the struct definition. Alternately, we could
manually align it as is done for fdtab.
2025-11-07 22:22:55 +01:00