]> git.kaiwu.me - haproxy.git/log
haproxy.git
2 weeks agoMINOR: xprt_qstrm: remove unused subs
Amaury Denoyelle [Thu, 23 Apr 2026 12:15:32 +0000 (14:15 +0200)]
MINOR: xprt_qstrm: remove unused subs

Currently, xprt_qstrm does not implement subscribe mechanism. As such,
it is better for now to remove unused member <subs> for clarity.

2 weeks agoBUG/MINOR: mux_quic: do not release conn on qcc_recv() for QMux
Amaury Denoyelle [Thu, 23 Apr 2026 13:32:58 +0000 (15:32 +0200)]
BUG/MINOR: mux_quic: do not release conn on qcc_recv() for QMux

Recently, an extra check has been added so that a dead connection is
immediately release on at the end of qcc_recv() operation. This is
useful when a GOAWAY frame is received from a server, so that the
backend connection is released if idle.

This step is in fact only necessary for QUIC, as qcc_recv() is called
directly from the lower transport layer. It causes issues with QMux as
in this case qcc_recv() is called via qcc_io_recv(). A crash in this
context will occur as qcc_recv() does not indicate that a release has
been performed.

To fix this, simply disable the extra check at the end of qcc_recv() for
QMux. This is fine as in this case receive operation is always followed
by qcc_io_process() which is able to release the connection in a safe
way.

No need to backport.

2 weeks agoBUG/MINOR: xprt_qstrm: prevent crash if conn release on MUX wake
Amaury Denoyelle [Thu, 23 Apr 2026 15:32:44 +0000 (17:32 +0200)]
BUG/MINOR: xprt_qstrm: prevent crash if conn release on MUX wake

When QMux XPRT has successfully been able to process to transport
parameters exchange, the MUX is initialized and immediately woken up to
start transfers. However, if the connection is in an unusable state, the
latter operation will instead release the connection and all of its
network stack.

A crash would occur in case of release when finalizing the XPRT tasklet
completion. To fix this, first free every XPRT resources. MUX wake is
now conducted in a safe way as the last operation before the tasklet is
completely released.

No need to backport.

2 weeks agoBUG/MINOR: xprt_qstrm: ensure all local TPs are allocated
Amaury Denoyelle [Thu, 23 Apr 2026 15:51:03 +0000 (17:51 +0200)]
BUG/MINOR: xprt_qstrm: ensure all local TPs are allocated

Complete initialization of xprt_qstrm layer by setting local parameters
to zero. This should prevent to emit random values to the peer.

No backport needed.

2 weeks agoBUG/MINOR: mux_quic: prevent crash on qc_frm_free() with QMux
Amaury Denoyelle [Fri, 24 Apr 2026 07:30:28 +0000 (09:30 +0200)]
BUG/MINOR: mux_quic: prevent crash on qc_frm_free() with QMux

qc_frm_free() is a helper used to clean up a QUIC frame object. It is
used by MUX layer both for QUIC and QMux protocols.

This function takes a pointer to the underlying quic_conn, used only for
trace purpose. This patch fixes its usage for QMux to ensure that in
this case a NULL value is used.

No need to backport.

2 weeks agoBUG/MEDIUM: mux-h1: Force close mode for bodyless message announcing a C-L
Christopher Faulet [Wed, 22 Apr 2026 14:55:00 +0000 (16:55 +0200)]
BUG/MEDIUM: mux-h1: Force close mode for bodyless message announcing a C-L

When dealing with EOH block, we must be sure to force the close mode for
message with no payload but annoncing a non-null content-length.

It is mainly an issue on the server side but it could be encountered on
client side too. Without this fix, a request can be switched to the DONE
state while the server is still expecting the payload. In an ideal world,
this case should not happen. But in conjunction with other bugs, it may lead
to a desynchro between haproxy and the server.

Now, when a non-null content-length is announced but we know we reached the
end of the message, we force the close mode. The only exception is for
bodyless responses (204s, 304s and responses to head requests).

Thanks to Martino Spagnuolo (r3verii) for his detailed report on this issue.

This patch must be backported to all stable version.

2 weeks agoBUG/MAJOR: mux-h2: detect incomplete transfers on HEADERS frames as well
Willy Tarreau [Wed, 22 Apr 2026 12:54:20 +0000 (14:54 +0200)]
BUG/MAJOR: mux-h2: detect incomplete transfers on HEADERS frames as well

Checks are already made on H2 to detect inconsistencies between
advertised content-length and transferred data (excess of data or
premature END_STREAM flag on DATA frame). However, as found by
Martino Spagnuolo (r3verii), a subtle case remains: if the END_STREAM
appears on the HEADERS frame (i.e. a regular request for example),
then the check is not made. In this case it is possible to advertise
more contents than will really be transferred. If the other side uses
HTTP/1.1, and the server responds before the end of the transfer,
this means that the number of advertised bytes that will never be
transferred and that the server will drain will be taken from the
next request, effectively hiding a part of the header.

In practice this can be used to force subsequent requests to fail, or
when running with "http-reuse never" or when running with a totally
idle server, to perform a request smuggling by constructing specially
crafted request pairs where the first one is used to trigger an early
response and hide parts of or all headers of the second one, to
instead use a second embedded one that was not subject to analysis.

The risk remains moderate given the low prevalence of "http-reuse never"
in production environments, and of idle servers.

The fix consists in detecting if advertised content-length remains when
processing an END_STREAM flag on a HEADERS frame. It also does it for
trailers, which turn out to be another way to abuse the bug. However it
takes great care not to break bodyless responses (204, 304 and responses
to HEAD requests) that may present a content-length that doesn't reflect
the presence of a body in the response.

A temporary alternative to the fix is to disable HTTP/2 by specifying
"alpn http/1.1" on "bind" lines, and adding "option disable-h2-upgrade"
in HTTP frontends.

This must be backported to all stable versions.

2 weeks agoBUG/MINOR: server: fix a possible leak of an error message in dynamic servers
Willy Tarreau [Thu, 23 Apr 2026 13:10:01 +0000 (15:10 +0200)]
BUG/MINOR: server: fix a possible leak of an error message in dynamic servers

In 3.4-dev6, commit de5fc2f515 ("BUG/MINOR: server: set auto SNI for
dynamic servers") allowed to properly set the SNI, and return an error
message. However the error message is leaked after being printed on the
CLI.

This should be backported to 3.3.

2 weeks agoRevert "BUG/MINOR: stream: add the newly added SF_TXN_* flags to strm_show_flags()"
Willy Tarreau [Thu, 23 Apr 2026 12:37:33 +0000 (14:37 +0200)]
Revert "BUG/MINOR: stream: add the newly added SF_TXN_* flags to strm_show_flags()"

This reverts commit 3c63298acdb298ed2cf18cde0b47c361ed7fdd8c.

Christopher and I had the same idea at the same moment, no need for
two fixes!

2 weeks agoBUG/MINOR: debug: properly mark the entire libs archive read-only
Willy Tarreau [Thu, 23 Apr 2026 11:52:33 +0000 (13:52 +0200)]
BUG/MINOR: debug: properly mark the entire libs archive read-only

In 3.4-dev7, commit e1738b665d ("MINOR: debug: read all libs in memory
when set-dumpable=libs") reads dependencies into memory to store them as
a tar archive for later debugging. There was an attempt to mark the whole
archive read-only, except that the size passed in argument to mprotect()
is wrong: lib_size is only assigned after the operation and is still zero
at the moment this is done. new_size ought to be used instead.

This needs to be backported wherever the commit above is backported, at
least 3.2.

2 weeks agoBUG/MINOR: stream: add the newly added SF_TXN_* flags to strm_show_flags()
Willy Tarreau [Thu, 23 Apr 2026 09:40:03 +0000 (11:40 +0200)]
BUG/MINOR: stream: add the newly added SF_TXN_* flags to strm_show_flags()

3 new enum values and a mask were added in latest -dev with commit
24e05fe33a ("MINOR: stream: Use a pcli transaction to replace pcli_*
members"), unfortunately the entries needed by the "flags" command were
forgotten.

No backport is needed.

2 weeks agoDOC: config: fix typo introduce in max-threads-per-group documentation
Willy Tarreau [Thu, 23 Apr 2026 09:32:52 +0000 (11:32 +0200)]
DOC: config: fix typo introduce in max-threads-per-group documentation

Since commit 0af603f46f ("MEDIUM: threads: change the default
max-threads-per-group value to 16"), it was written "Tha minimum" instead
of "The minimum". No backport needed, this is only in latest -dev.

2 weeks agoBUG/MINOR: servers: fix last_sess date calculation
Willy Tarreau [Thu, 23 Apr 2026 09:24:22 +0000 (11:24 +0200)]
BUG/MINOR: servers: fix last_sess date calculation

In 3.4-dev8, commit e264523112 ("MINOR: servers: Don't update last_sess
if it did not change") adjusted the last_sess date to avoid writing to
the same cache line all the time, however a typo makes it pick the wrong
second because it uses now_ms instead of now_ns (so the date would roughly
change every 12 days).

No backport needed.

2 weeks agoBUG/MINOR: compression: properly disable request when setting response
Willy Tarreau [Thu, 23 Apr 2026 09:00:11 +0000 (11:00 +0200)]
BUG/MINOR: compression: properly disable request when setting response

In 2.8, commit ead43fe4f2 ("MEDIUM: compression: Make it so we can
compress requests as well.") added the ability to independently enable
compression on request and/or response. However there's a bug in the
"compression direction response" case, which preserves only the request
flag and adds the response direction instead of clearing the request
flag, so this directive would clear offload and make it impossible to
disable request if it was already previously enabled.

This can be backported to stable releases as far as 2.8.

2 weeks agoREGTESTS: Never reuse server connection in server/cli_delete_dynamic_server.vtc
Christopher Faulet [Thu, 23 Apr 2026 08:55:00 +0000 (10:55 +0200)]
REGTESTS: Never reuse server connection in server/cli_delete_dynamic_server.vtc

A "Connection: close" header is added to responses to avoid any connection
reuse. This should avoid errors on the client side.

2 weeks agoREGTESTS: Never reuse server connection in jwt/jws_verify.vtc
Christopher Faulet [Thu, 23 Apr 2026 08:52:53 +0000 (10:52 +0200)]
REGTESTS: Never reuse server connection in jwt/jws_verify.vtc

A "Connection: close" header is added to responses to avoid any connection
reuse. This should avoid errors on the client side.

2 weeks agoBUG/MINOR: stream: Add SF_TXN_HTTP/SF_TXN_PCLI flags in strm_show_flags()
Christopher Faulet [Thu, 23 Apr 2026 08:43:36 +0000 (10:43 +0200)]
BUG/MINOR: stream: Add SF_TXN_HTTP/SF_TXN_PCLI flags in strm_show_flags()

These flags were missing in strm_show_flags(). So let's add them.

No backport needed.

2 weeks agoCLEANUP: cli: Fix typos in comments
Christopher Faulet [Thu, 23 Apr 2026 08:42:31 +0000 (10:42 +0200)]
CLEANUP: cli: Fix typos in comments

Some minor typos in comments were fixed.

2 weeks agoDOC: config: Fix a typo for "external-check" directive
Christopher Faulet [Thu, 23 Apr 2026 08:06:10 +0000 (10:06 +0200)]
DOC: config: Fix a typo for "external-check" directive

Fix duplicated "to the" in the "external-check" directive description.

2 weeks agoCLEANUP: proxy: Fix typos in comments
Christopher Faulet [Thu, 23 Apr 2026 08:05:19 +0000 (10:05 +0200)]
CLEANUP: proxy: Fix typos in comments

Some minor typos in comments were fixed.

2 weeks agoBUG/MEDIUM: tcpcheck: Release temporary small chunk when retrying on http-check
Christopher Faulet [Thu, 23 Apr 2026 07:56:06 +0000 (09:56 +0200)]
BUG/MEDIUM: tcpcheck: Release temporary small chunk when retrying on http-check

When a http request is sent during an http healthcheck, if an error is
triggered while the output buffer is a small buffer, another attempt is made
with a larger one. When this happens, the temporary chunk used to format
headers must be released.

No backport needed.

2 weeks agoCLEANUP: http-client: Fix typos in comments
Christopher Faulet [Thu, 23 Apr 2026 07:49:29 +0000 (09:49 +0200)]
CLEANUP: http-client: Fix typos in comments

Some minor typos in comments were fixed.

2 weeks agoCLEANUP: chunk: Fix a typo in a comment
Christopher Faulet [Thu, 23 Apr 2026 07:46:39 +0000 (09:46 +0200)]
CLEANUP: chunk: Fix a typo in a comment

A minor typo in a comment was fixed.

2 weeks agoCLEANUP: htx: Fix typos in comments
Christopher Faulet [Thu, 23 Apr 2026 07:42:17 +0000 (09:42 +0200)]
CLEANUP: htx: Fix typos in comments

Some minor typos in comments were fixed.

2 weeks agoCLEANUP: config: Fix warning about invalid small buffer size
Christopher Faulet [Thu, 23 Apr 2026 07:38:24 +0000 (09:38 +0200)]
CLEANUP: config: Fix warning about invalid small buffer size

"than" must be used instead of "to".

2 weeks agoCLEANUP: haterm: Fix typos in comments
Christopher Faulet [Thu, 23 Apr 2026 07:30:45 +0000 (09:30 +0200)]
CLEANUP: haterm: Fix typos in comments

Some minor typos in comments were fixed.

2 weeks agoBUG/MINOR: tcpcheck: Fix a leak on deinit by releasing ruleset's conf.file
Christopher Faulet [Thu, 23 Apr 2026 07:20:43 +0000 (09:20 +0200)]
BUG/MINOR: tcpcheck: Fix a leak on deinit by releasing ruleset's conf.file

Now healthcheck sections are supported, a ruleset can reference a
configuration file that must be freed on deinit. So let's do so.

No backport needed.

2 weeks agoBUG/MINOR: tcpcheck: Don't release ruleset when parsing 'spop-check' ruleset
Christopher Faulet [Thu, 23 Apr 2026 07:03:55 +0000 (09:03 +0200)]
BUG/MINOR: tcpcheck: Don't release ruleset when parsing 'spop-check' ruleset

Ruleset are stored in a global tree, released on deinit staged. All errors
are fatal and abort the configuration parsing. So the current ruleset must
not be released here.

2 weeks agoMINOR: tcpcheck: Rely on free_tcpcheck_ruleset() to deinit tcpchecks
Christopher Faulet [Thu, 23 Apr 2026 06:49:28 +0000 (08:49 +0200)]
MINOR: tcpcheck: Rely on free_tcpcheck_ruleset() to deinit tcpchecks

There is already a function to release a tcpcheck ruleset. So let's use it
on deinit stage.

2 weeks agoCLEANUP: tcpcheck: Fix some typos in comments
Christopher Faulet [Thu, 23 Apr 2026 06:39:45 +0000 (08:39 +0200)]
CLEANUP: tcpcheck: Fix some typos in comments

Some minor typos in comments were fixed.

2 weeks agoBUG/MINOR: http-act: fix a typo in a "del-heeaders-bin" error message
Christopher Faulet [Thu, 23 Apr 2026 06:28:44 +0000 (08:28 +0200)]
BUG/MINOR: http-act: fix a typo in a "del-heeaders-bin" error message

"with is" was replaced by "with" and the action name was not properly
reported (a 's' was missing).

No backport nedded.

2 weeks agoBUG/MINOR: mux-h1: Fix test to skip trailers from chunked messages
Christopher Faulet [Wed, 22 Apr 2026 15:24:56 +0000 (17:24 +0200)]
BUG/MINOR: mux-h1: Fix test to skip trailers from chunked messages

The test to remove trailers from chunked messages was inverted and is thus
ineffective. The flag for the requests was tested on client side and the flag
for the response was tested on server side. It should be the opposite.

This patch must be backported as far as 3.2.

2 weeks agoBUG/MINOR: mux-h1: Fix condition to send null-chunk for bodyless message
Christopher Faulet [Wed, 22 Apr 2026 14:40:55 +0000 (16:40 +0200)]
BUG/MINOR: mux-h1: Fix condition to send null-chunk for bodyless message

When the EOH block is processed, before sending message headers, there is a
test to know if there is no payload. In case of a chunked message, a
null-chunk is emitted, except for bodyless response. For instance, a
response to a HEAD request has no payload at all and no null-chunk.

However, the test for bodyless responses is not correct. Only
H1S_F_BODYLESS_RESP flag is tested. But this flag can be set on server side
when we are processing the request. To fix the issue, the test was
adapted. The null-chunk is added if a message with no payload is chunked and
it is a request or a non-bodyless responses.

This patch must be backported to all stable version.

2 weeks agoBUG/MINOR: log: also wait for the response when logging response headers
Willy Tarreau [Thu, 23 Apr 2026 06:22:58 +0000 (08:22 +0200)]
BUG/MINOR: log: also wait for the response when logging response headers

A typo in commit e51be30f78 ("BUG/MINOR: log: consider format expression
dependencies to decide when to log") made HRSHP appear twice (persistent
response) while the second one ought to be HRSHV (volatile response, e.g.
header values). This is harmless in practice since logs always wait for
at least headers.

This should be backported wherever the patch above was backported.

2 weeks agoBUG/MINOR: H2: Don't forget to free shared_rx_bufs on failure
Olivier Houchard [Wed, 22 Apr 2026 16:57:39 +0000 (18:57 +0200)]
BUG/MINOR: H2: Don't forget to free shared_rx_bufs on failure

In h2_init(), if we have a failure while creating the h2c, and we
allocated shared_tx_bufs, don't forget to free it, otherwise we'll have
a memory leak.

This was introduced in 3.1 by commit a891534bfd ("MINOR: mux-h2: allocate
the array of shared rx bufs in the h2c"), so the fix should be backported
as far as 3.2.

2 weeks agoBUG/MINOR: h2: Don't look at the exclusive bit for PRIORITY frame
Olivier Houchard [Wed, 22 Apr 2026 16:52:35 +0000 (18:52 +0200)]
BUG/MINOR: h2: Don't look at the exclusive bit for PRIORITY frame

When receiving a PRIORITY frame, when checking if the stream id provided
is ours, ignore bit 31, as it is the exclusive bit, and not part of the
stream id, whoever sends a PRIORITY frame with its own id and the
exclusive bit set will not be considered an error, as it should per the
RFC.

The impact is basically non-existent since we don't use PRIORITY frames,
it's only that we would ignore such an invalid frame instead of breaking
the connection.

The bug was introduced in 1.9 with commit 92153fccd3 ("BUG/MINOR: h2:
properly check PRIORITY frames") so the fix must be backported to all
versions.

2 weeks agoBUG/MINOR: h2: make tune.h2.log-errors actually work
Olivier Houchard [Wed, 22 Apr 2026 16:21:05 +0000 (18:21 +0200)]
BUG/MINOR: h2: make tune.h2.log-errors actually work

Commit e67e36c9eb35eb1477ae0e425a660ee0c631cecd introduced
tune.h2.log-errors, that would let you pick if you wanted to know about
stream errors, connection errors, or no error.
However, a logic error made it so no error will be picked for any value
except for "none", in which case connection would be picked. Fix that by
just checking the strcmp() return value correctly.

This should be backported wherever e67e36c9eb35eb1477ae0e425a660ee0c631cecd
has been backported.

2 weeks agoBUG/MAJOR: net_helper: ip.fp infinite loop on malformed tcp options
Emeric Brun [Wed, 22 Apr 2026 12:45:09 +0000 (14:45 +0200)]
BUG/MAJOR: net_helper: ip.fp infinite loop on malformed tcp options

A malformed tcp option with an option length set to 0 can cause
an infinite loop on ip.fp converter.

The patch also forces the computation to use an unsigned char to
avoid a shift back during the parsing.

This fix should be backported on all versions including the ip.fp
converter.

2 weeks agoBUG/MEDIUM: tasks: Make sure we don't schedule a task already running
Olivier Houchard [Thu, 9 Apr 2026 13:33:39 +0000 (15:33 +0200)]
BUG/MEDIUM: tasks: Make sure we don't schedule a task already running

In task_schedule(), before attempting to set the new task expiration
date, make sure it is not running by trying to set the TASK_RUNNING
flag, and waiting if it is already there. Having the flag set will
ensure that the task won't be running while we're modifying it.
There is a very rare race condition, where the expire would be set by
task_schedule(), then the running task might set it to something else,
and if it sets it to TICK_ETERNITY before task_schedule() calls
__task_queue(), then we will hit a BUG_ON() there.
This is very hard to reproduce, but has been reported a few times,
included in Github issue #3327, which should now be fixed.

This should be backported as far back as 2.8.

WIP: Make sure the task is not running before changing expire

2 weeks agoBUG/MINOR: mux-h2: count a proto error when rejecting a stream on parsing error
Willy Tarreau [Wed, 22 Apr 2026 11:51:10 +0000 (13:51 +0200)]
BUG/MINOR: mux-h2: count a proto error when rejecting a stream on parsing error

The proxy error counter was not updated in h2c_frt_handle_headers() in
case of failure to decode a HEADERS frame. Make sure to keep it updated.
This can be backported to all stable versions.

2 weeks agoBUG/MINOR: mux-h2: count a protocol error when failing to parse a trailer
Willy Tarreau [Wed, 22 Apr 2026 09:58:15 +0000 (11:58 +0200)]
BUG/MINOR: mux-h2: count a protocol error when failing to parse a trailer

Commit aab1a60977 ("BUG/MEDIUM: h2/htx: always fail on too large trailers")
explicitly returned an RST_STREAM on failure to decode some trailers, and
used the code H2_ERR_INTERNAL_ERROR. However there are multiple possible
causes for this failure to happen, and it turns out that it's much more
likely to be related to a protocol error than a decompression error. So
let's change this to PROTOCOL_ERROR, and count a protocol error on the
proxy and in the session.

This can be backported to all stable versions (with adjustments related
to these versions, maybe focusing on 3.2 max is reasonable).

2 weeks agoREGTESTS: ssl: mark ssl_dh.vtc as broken
William Lallemand [Wed, 22 Apr 2026 13:29:26 +0000 (15:29 +0200)]
REGTESTS: ssl: mark ssl_dh.vtc as broken

Test is broken since the feature was fixed in 3610a767 ("BUG/MINOR:
reg-tests: make shell syntax errors fatal")

2 weeks agoCLEANUP: applet: Remove useless shadow pointer from appctx
Christopher Faulet [Tue, 21 Apr 2026 05:52:57 +0000 (07:52 +0200)]
CLEANUP: applet: Remove useless shadow pointer from appctx

This pointer was used during the appctx refactoring performed in 2.6. The
ctx union was still there and this pointer was used as the "shadow" of the
svcctx pointer used by most commands. In 2.7, the union was removed, making
the shadow pointer useless. Let's remove it now.

2 weeks agoMINOR: stream: Use a pcli transaction to replace pcli_* members
Christopher Faulet [Tue, 14 Apr 2026 17:03:39 +0000 (19:03 +0200)]
MINOR: stream: Use a pcli transaction to replace pcli_* members

A new type of transaction was introduced for master-cli streams. So
SF_TXN_PCLI flag and functions to allocate and destroy PCLI transactions
were added.

In the stream structure, all pcli_* members were moved in the pcli
transaction and the txn union was updated accordingly.

When it was ambiguous, a test on the transaction type was performed. For
instance to destroy the transaciton.

2 weeks agoMINOR: stream: Add flags to identify the stream tansaction when allocated
Christopher Faulet [Mon, 20 Apr 2026 16:33:36 +0000 (18:33 +0200)]
MINOR: stream: Add flags to identify the stream tansaction when allocated

To be able to deal with different types of transaction for a stream, new
stream flags was added to know the transaction type when allocated. For now
only HTTP transactions can be allocated, so only SF_TXN_HTTP was
introduced. The mask SF_TXN_MASK must be used to get the transaction type.

The transaction type is set when it is allocated and removed when it is
destroyed.

2 weeks agoMINOR: stream: Move the HTTP txn in an union
Christopher Faulet [Tue, 14 Apr 2026 16:37:49 +0000 (18:37 +0200)]
MINOR: stream: Move the HTTP txn in an union

The HTTP transaction is moved in an union. For now, it is the only possible
transaction that can be allocated. But that will change. Thanks to this
commit and the next one, it will be possible to deal with different kind of
transactions for a stream.

This patch looks quite huge, but it is more or less a renaming of all
accesses to "txn" field by "txn.http".

2 weeks agoMEDIUM: cli: increase the payload pattern up to 64 bytes
Christopher Faulet [Tue, 14 Apr 2026 14:08:29 +0000 (16:08 +0200)]
MEDIUM: cli: increase the payload pattern up to 64 bytes

The maximum size allowed for the payload pattern was increase up to 64 bytes
(65 bytes because of the trailing \0), to be able to use a sha256 of random
data for instance. It could be useful to prevent any data smuggling on the
payload.

Note that on the CLI, it could be possible to have only the buffer size as a
limit, because the command line is only consumed once all commands are
executed. The payload pattern is only a pointer in the buffer where the
command line was copied. However, for the master CLI, the data are streamed
to the worker, so we must keep a copy of he payload pattern. This is why we
must limit its size.

2 weeks agoMEDIUM: cli: Add support for dynamically allocated payloads
Christopher Faulet [Tue, 14 Apr 2026 05:55:23 +0000 (07:55 +0200)]
MEDIUM: cli: Add support for dynamically allocated payloads

It is now possible to deal with too big payload to fit in a buffer, without
changing the buffer size. By default, a payload up to 128 KB can be
dynamically allocated. "tune.cli.max-payload-size" global parameter can be
used to change this value, with some caution for huge values.

For CLI command handler functions, there is no change at all. A pointer on
the payload is still passed as parameter. Internally, an area is allocated
for the payload only if it is too big.

The payload pattern used to detect the end of the payload is part from the
allocated area.

2 weeks agoMEDIUM: cli: Make a buffer for the command payload
Christopher Faulet [Wed, 8 Apr 2026 15:02:36 +0000 (17:02 +0200)]
MEDIUM: cli: Make a buffer for the command payload

The payload is now saved as a buffer in the CLI context instead of a simple
pointer. It is mandatory to be able to reallocate the payload if it is too
big.

2 weeks agoMINOR: cli: Handle the paylod pattern as a pointer in the cmdline buffer
Christopher Faulet [Wed, 8 Apr 2026 10:14:42 +0000 (12:14 +0200)]
MINOR: cli: Handle the paylod pattern as a pointer in the cmdline buffer

Instead of copying the payload pattern in the CLI context, we now only save
a pointer on this pattern. It is possible because the command line is copied
in the CLI context. Arguments are already handled this way when the command
is processed.

2 weeks agoBUG/MINOR: reg-tests: make shell syntax errors fatal
Ilia Shipitsin [Wed, 22 Apr 2026 06:38:08 +0000 (08:38 +0200)]
BUG/MINOR: reg-tests: make shell syntax errors fatal

Detect shell parser errors in test LOG files right after vtest execution
and mark the run as failed when such errors are found.

This turns malformed feature cmd expressions from warning-like diagnostics
into hard failures, so broken test conditions are caught reliably.

2 weeks agoci: modernize actions/upload-artifact@v4
Ilia Shipitsin [Wed, 22 Apr 2026 06:38:10 +0000 (08:38 +0200)]
ci: modernize actions/upload-artifact@v4

Node.js 20 actions are deprecated. The following actions are running on Node.js 20 and may not work as expected: actions/upload-artifact@v4.

2 weeks agoreg-tests/ssl/ssl_dh.vtc: fix syntax error
Ilia Shipitsin [Wed, 22 Apr 2026 06:38:09 +0000 (08:38 +0200)]
reg-tests/ssl/ssl_dh.vtc: fix syntax error

diag  0.0 sh: -c: line 0: syntax error near unexpected token `wolfSSL'

2 weeks agoBUILD: config: also set DEF_MAX_THREADS_PER_GROUP when not using threads
Willy Tarreau [Tue, 21 Apr 2026 12:49:26 +0000 (14:49 +0200)]
BUILD: config: also set DEF_MAX_THREADS_PER_GROUP when not using threads

The single-threaded build is currently broken in development since commit
0af603f46f ("MEDIUM: threads: change the default max-threads-per-group
value to 16") because it doesn't set the default for the non-threaded
build. Let's set it to 1.

No backport is needed.

2 weeks agoCI: github: add an i686 job to the push job 20260422-i686-push-vtest
William Lallemand [Mon, 20 Apr 2026 12:51:48 +0000 (14:51 +0200)]
CI: github: add an i686 job to the push job

Add an i686 job in order to run reg-tests on 32-bit architecture.

Use the i386 SSL and PCRE2 library provided by ubuntu.

VTest is still compiled in x86_64.

2 weeks agoBUG/MAJOR: sched: protect task->expire on 32-bit platforms
Willy Tarreau [Tue, 21 Apr 2026 21:21:21 +0000 (23:21 +0200)]
BUG/MAJOR: sched: protect task->expire on 32-bit platforms

Commit 7d40b3134 ("MEDIUM: sched: do not run a same task multiple times
in series") required to slightly reorder a few fields in struct tasklet
and task in order to reuse an existing hole and keep tree nodes aligned.

The problem is that nice+expire were placed in struct task just before
rq, and that a 48-bit hole replaces them in struct tasklet on 64-bit
platforms, just before the struct list. However, on 32-bit platforms,
the hole is only 16-bit and preserves nice, but expire is overwritten
by the first pointer of the list element. This is not a problem for
real tasklets which do not use these fields, but it definitely is a
problem for tasks that are cast to tasklets in the run queues, because
the expire field can be overwritten when the task is woken up, and if
requeued as-is, it will expire at a completely random date.

This is what caused certain regtests to fail on i386 and 32-bit arm
machines.

This fix needs to be backported wherever the patch above was backported.
The bug has no effect on 64-bit platforms. The fix doesn't inflate
structs on 64-bit, but will raise struct tasklet from 40 to 44 bytes on
32-bit platforms.

Thanks to William for spotting the problem, bisecting it and providing
a working reproducer.

3 weeks agoCLEANUP: mux-h1: remove the unneeded test on conn->owner in h1s_finish_detach()
Willy Tarreau [Mon, 20 Apr 2026 14:15:27 +0000 (16:15 +0200)]
CLEANUP: mux-h1: remove the unneeded test on conn->owner in h1s_finish_detach()

There was a test below the "release" label on conn->owner to decide
whether to kill the connection or not. But this test is not needed,
because:
  - for frontends, it's always set so the test never matches
  - for backends, it was NULL on the second stream once a request
    was being reused from an idle pool, so it couldn't be used to
    discriminate between connections. In practice, the goal was to
    try to detect certain dead connections but all cases leading to
    such connections are either already handled in the tests before
    (which don't reach this label), or are handled by the other
    conditions.

Thus, let's remove this confusing test.

3 weeks agoCLEANUP: mux-h1: avoid using conn->owner in uncertain areas
Willy Tarreau [Mon, 20 Apr 2026 13:36:38 +0000 (15:36 +0200)]
CLEANUP: mux-h1: avoid using conn->owner in uncertain areas

Some places use conn->owner to retrieve the session. It's valid because
each time it is done, it's on the frontend, though it's not always 100%
obvious and sometimes requires deep code analysis. Let's clarify these
points and even rely on an intermediary variable to make it clearer. One
case where the owner couldn't differ from the session without being NULL
was also eliminated.

3 weeks agoMEDIUM: session: always reset the conn->owner on backend when installing mux
Willy Tarreau [Mon, 20 Apr 2026 12:05:09 +0000 (14:05 +0200)]
MEDIUM: session: always reset the conn->owner on backend when installing mux

When installing a mux on the backend, unless we have a good reason for
keeping the session set in conn->owner, we must reset it. Having the
session there just hides potential bugs and prevents certain tests from
being properly done.

Now it is much clearer: conn->owner remains set to the session on
frontend connections, is set to the session when the connection is
private or assimilated private and belongs to the session list, or
is NULL.

3 weeks agoMEDIUM: muxes: always set conn->owner to the session that owns the connection
Willy Tarreau [Mon, 20 Apr 2026 09:40:08 +0000 (11:40 +0200)]
MEDIUM: muxes: always set conn->owner to the session that owns the connection

When an idle connection is private or considered private, session_add_conn()
is called to add it to the list of connections owned by the session. But
in case of allocation failure, the session is not set, which results in
a long list of possible situations that are all corner cases which are
difficult to test (and debug).

This commit relies on the fact that it is already permitted to have
conn->owner pointing to a session even if the connection couldn't be
added to the session's list, as this was already the case in
conn_backend_get() when dealing with HOL_RISK. Also as seen in commit
3aab17bd566 added in 2.4, it is already possible to have conn->owner
set with the connection not being in a list, and only the list element
is checked for this.

This commit modifies session_add_conn() to always set conn->onwer, even
if the list element couldn't be allocated. This way it's possible to
always refer to conn->owner to find the session owning a private conn
even in case of failure to allocate an entry. This requires to change
the checks on conn->owner to a check of the list element to see if the
connection belongs to a session, the pre-assignment of sess to
conn->owner in conn_backend_get() is no longer needed, same for the
pre-assignment in http_wait_for_response(), and that's all.

The H1 mux remained unchanged because since it cannot multiplex, in
case it fails to allocate a pconn, it instantly kills the connection.

3 weeks agoBUG/MINOR: sample: adjust dependencies for channel output bytes counters
Willy Tarreau [Mon, 20 Apr 2026 15:40:25 +0000 (17:40 +0200)]
BUG/MINOR: sample: adjust dependencies for channel output bytes counters

The bytes_in, bytes_out, {req,res}.bytes_{in,out} sample fetch functions
are marked as internal dependencies only. But that's not exact, they are
statistics. Request traffic (bytes_in, req.bytes*) is usable starting
from the request, while response traffic (bytes_out, res.bytes*) is usable
as soon as a response begins to be received, and all are valid till the
end of the transaction.

The impact is that the log-format below:

  log-format "req.bytes_in=%[req.bytes_in] req.bytes_out=%[req.bytes_out] res.bytes_in=%[res.bytes_in] res.bytes_out=%[res.bytes_out]"

is emitted too early and only logs zeroes when uploading 1MB and
downloading 1MB:

  req.bytes_in=0 req.bytes_out=0 res.bytes_in=15288 res.bytes_out=0

This patch marks the request stats RQFIN and the response stats RSFIN,
so that they're valid at any moment and the logs backend knows it must
wait for the latest moment to emit such a line. With this change, the
line above now correctly produces:

  req.bytes_in=1000157 req.bytes_out=1000157 res.bytes_in=1048629 res.bytes_out=1048629

This should be backported as far as the latest LTS probably, along with
these 2 previous patches:

  BUG/MINOR: log: consider format expression dependencies to decide when to log
  MINOR: sample: make RQ/RS stats available everywhere

3 weeks agoMINOR: sample: make RQ/RS stats available everywhere
Willy Tarreau [Mon, 20 Apr 2026 16:34:35 +0000 (18:34 +0200)]
MINOR: sample: make RQ/RS stats available everywhere

Sample fetch functions working on the request/response stats were marked
as being only compatible with the log phase. This is a mistake because
by definitions, stats can be consulted anywhere from the moment they
start to appear. It's only that they are valid as far as the logs. At the
moment, no sample fetch function depends on RQFIN, and only res.timer.data
depends on RSFIN. But this will be needed to relax certain sample fetch
functions (and will need to be backported along with a few other patches).

3 weeks agoBUG/MINOR: log: consider format expression dependencies to decide when to log
Willy Tarreau [Mon, 20 Apr 2026 15:59:53 +0000 (17:59 +0200)]
BUG/MINOR: log: consider format expression dependencies to decide when to log

Log-format properly takes into account the LW_* flags set by the log
aliases, however its consideration for the sample fetch expressions is
very minimalistic (HTTP y/n). It poses a problem because logging some
statistics doesn't work unless some log aliases are involved to force
the log to wait till the end.

Before this change, the following log-format:

    log-format "res.timer.data=%[res.timer.data]"

would log "res.timer.data=0" regardless of the time taken to transfer
data, and the log would be emitted instantly. However, this line:

    log-format "res.timer.data=%[res.timer.data] %B"

would properly log the time taken to transfer the data because %B which
carries the log flag LW_BYTES forces the log to wait till the end.

This patch makes sure that anything requiring response (headers or body)
waits for at least the response, and that anything requiring response body
or end of transfer (req/res) waits till the end (LW_BYTES). Thanks to
this, the log above is now correct even without the "%B" hack.

This should be backported at least till the latest LTS.

3 weeks agoMINOR: acme: allow IP SAN in certificate request
William Lallemand [Mon, 20 Apr 2026 16:06:43 +0000 (18:06 +0200)]
MINOR: acme: allow IP SAN in certificate request

Implement IP in both requestOrder and CSR so a certificate with SAN IPs
can be generated.

3 weeks agoMINOR: acme: implement draft-ietf-acme-profiles
William Lallemand [Mon, 20 Apr 2026 15:33:41 +0000 (17:33 +0200)]
MINOR: acme: implement draft-ietf-acme-profiles

The ACME Profiles extension (draft-ietf-acme-profiles) allows a client
to request a specific certificate profile by including a "profile" field
in the newOrder request. This lets the CA select the appropriate
certificate issuance policy (e.g. "classic", "shortlived") for a given
order.

A new "profile" keyword is added to the acme section. When set, its
value is included in the newOrder JSON payload sent to the CA.

3 weeks agoCI: github: switch to USE_PCRE2 in Fedora Rawhide build
William Lallemand [Mon, 20 Apr 2026 12:24:51 +0000 (14:24 +0200)]
CI: github: switch to USE_PCRE2 in Fedora Rawhide build

pcre-devel (PCRE1) was removed in bded31dd3b but the make flags
were not updated to match; switch to USE_PCRE2/USE_PCRE2_JIT.

32bits job was also lacking pcre2-devel.

3 weeks agoCI: github: fix sysctl in fedora-rawhide
William Lallemand [Mon, 20 Apr 2026 11:57:40 +0000 (13:57 +0200)]
CI: github: fix sysctl in fedora-rawhide

In Fedora containers, procps-ng seems to be lacking, install it
manually. Also set the --privileged option to be able to set the sysctl
for coredumps.

3 weeks agoCI: github: do not install pcre-devel on Fedora Rawhide build
Ilia Shipitsin [Mon, 20 Apr 2026 10:17:40 +0000 (12:17 +0200)]
CI: github: do not install pcre-devel on Fedora Rawhide build

it was actually not needed, now it was removed from Fedora

3 weeks agoBUG/MEDIUM: checks: Don't forget to set the "alt_proto" field
Olivier Houchard [Mon, 20 Apr 2026 09:58:57 +0000 (11:58 +0200)]
BUG/MEDIUM: checks: Don't forget to set the "alt_proto" field

The target address type has been added to checks in commit
d759e60a3292f425aee66384e87ae227ce191c08, but as part of that address
type is the "alt_proto" field, that was not properly set for dynamic
servers, That could lead to checks not working for any protocol that use
a non-zero alt_proto, such as QUIC. So set it properly.

3 weeks agoCI: github: add cross-zoo.yml in README.md
William Lallemand [Mon, 20 Apr 2026 09:47:20 +0000 (11:47 +0200)]
CI: github: add cross-zoo.yml in README.md

Add the status badge for cross-zoo.yml in the README.

3 weeks agoCI: github: run cross-zoo.yml weekly
William Lallemand [Mon, 20 Apr 2026 09:40:45 +0000 (11:40 +0200)]
CI: github: run cross-zoo.yml weekly

run cross-zoo.yml every monday at 2am

3 weeks agoCI: github: add an i686 job in cross-zoo.yml
William Lallemand [Mon, 20 Apr 2026 09:27:21 +0000 (11:27 +0200)]
CI: github: add an i686 job in cross-zoo.yml

Add an i686 job in the cross-compilation test job.

3 weeks agoBUILD: ssl/sample: potential null pointer dereference in sample_conv_aes
William Lallemand [Mon, 20 Apr 2026 08:58:08 +0000 (10:58 +0200)]
BUILD: ssl/sample: potential null pointer dereference in sample_conv_aes

gcc flags aead_tag_trash as potentially NULL at the chunk_memcpy call
inside the (!dec && gcm) block, because it cannot correlate the
condition with the allocation that only happens in that same branch. Add
an explicit NULL check to silence the warning.

This was caught by cross-zoo.yml:

In file included from include/haproxy/connection.h:28,
                 from src/ssl_sample.c:27:
In function â€˜b_orig’,
    inlined from â€˜sample_conv_aes’ at src/ssl_sample.c:540:23:
include/haproxy/buf.h:80:17: error: potential null pointer dereference [-Werror=null-dereference]
   80 |         return b->area;
      |                ~^~~~~~
In function â€˜b_data’,
    inlined from â€˜sample_conv_aes’ at src/ssl_sample.c:540:3:
include/haproxy/buf.h:100:17: error: potential null pointer dereference [-Werror=null-dereference]
  100 |         return b->data;
      |                ~^~~~~~

3 weeks agoCI: github: use quictls-3.1.7 for cross-zoo.yml
William Lallemand [Mon, 20 Apr 2026 08:10:53 +0000 (10:10 +0200)]
CI: github: use quictls-3.1.7 for cross-zoo.yml

Last version of quictls (3.3.0) does not seem to cross-compile correctly.

3 weeks agoBUG/MINOR: xprt_qstrm: reduce max record length check
Amaury Denoyelle [Mon, 20 Apr 2026 07:21:08 +0000 (09:21 +0200)]
BUG/MINOR: xprt_qstrm: reduce max record length check

When trying to read QMux transport parameters frame, the record length
is checked to ensure it is not bigger than the buffer size. The
objective is to detect as soon as possible when receiving data that
cannot be handled and to close the connection.

In fact, this check is not accurate, as it did not take into account the
size of the Record length field itself. This patch fixes the comparison
by substracting with the size of the decoded varint.

No need to backport.

3 weeks agoCI: github: revert quictls version on cross-zoo.yml
William Lallemand [Mon, 20 Apr 2026 07:56:07 +0000 (09:56 +0200)]
CI: github: revert quictls version on cross-zoo.yml

Use the last branch of quictls available instead of 1.1.1, even if it is
not maintained anymore that at least fix the build.

3 weeks agoBUG/MINOR: mux_quic: convert QCC rx.rlen to 64bits
Amaury Denoyelle [Mon, 20 Apr 2026 07:24:42 +0000 (09:24 +0200)]
BUG/MINOR: mux_quic: convert QCC rx.rlen to 64bits

This patch is related to the issue reported on the previous issue
related to QMux record length parsing.

QCC rx.rlen is used to store the decoded record length. Convert it into
a plain 64bits integer instead of a size_t. This ensures it is
sufficient to decode record length, even with an increase of
max_record_length value (not currently implemented).

This should fix github build issue #3334 for 32bits architecture.

No need to backport.

3 weeks agoBUG/MINOR: xprt_qstrm: read record length in 64bits
Amaury Denoyelle [Mon, 20 Apr 2026 06:36:51 +0000 (08:36 +0200)]
BUG/MINOR: xprt_qstrm: read record length in 64bits

QMux record lengths are encoded as a QUIC varint. Thus in theory, it
requires a 64bits integer to be able to read the whole value. In
practice, if the record is bigger than bufsize, read operation cannot be
completed and an error must be reported.

This patch fixes record length decoding both in xprt_qstrm layer, which
is now performed in two steps. The value is first read in a 64bits
integer instead of a size_t whose size is dependent on the architecture.
Result is then checked against bufsize and if inferior stored in the
previously used variable (xprt ctx rxrlen member).

This should partially fix build issue reported on github #3334.

No need to backport.

3 weeks agoCI: Build halog as part of contrib.yml
Tim Duesterhus [Mon, 13 Apr 2026 19:23:47 +0000 (21:23 +0200)]
CI: Build halog as part of contrib.yml

halog does not make use of any of the "fancy" build flags that HAProxy does and
except for itself only includes ebtree. There is no need to build it as part of
the VTest workflows.

3 weeks agoCI: github: merge Test and Test-musl in VTest.yml
William Lallemand [Sat, 18 Apr 2026 11:25:12 +0000 (13:25 +0200)]
CI: github: merge Test and Test-musl in VTest.yml

In commit 7640d794 ("CI: Integrate Musl build into vtest.yml"), the
alpine job was integrated into VTest.yml. However, most of the task are
still duplicated and changes in the workflow need edits of copy/paste
code in two places because of that.

This commit deduplicates the code by making the alpine job part of the
matrix, like it was done for macOS.

3 weeks agoBUILD: haterm: don't pass size_t to %lu in error messages
Willy Tarreau [Sat, 18 Apr 2026 09:25:30 +0000 (11:25 +0200)]
BUILD: haterm: don't pass size_t to %lu in error messages

It fails on 32-bit systems, let's cast it to ulong like in other places.
No backport needed.

3 weeks agoMINOR: otel: test: unified run scripts into a single symlinked script
Miroslav Zagorac [Thu, 16 Apr 2026 01:09:09 +0000 (03:09 +0200)]
MINOR: otel: test: unified run scripts into a single symlinked script

Replaced SH_ARGS variables with 'set --' and "${@}" to ensure proper
quoting of haproxy command-line arguments.  Then replaced individual
per-config run scripts with a single generic run-test-config.sh that
derives the configuration directory from its own filename.  The former
scripts became symlinks, and a new run-empty.sh symlink was added.

3 weeks agoCLEANUP: otel: removed insecure-fork-wanted requirement
Miroslav Zagorac [Thu, 16 Apr 2026 00:03:08 +0000 (02:03 +0200)]
CLEANUP: otel: removed insecure-fork-wanted requirement

Removed the insecure-fork-wanted runtime check from the OTel filter parser
and all related mentions from documentation and test configuration.

The OpenTelemetry C wrapper library can now explicitly start all necessary
OTel threads immediately after configuration parsing, so it is no longer
affected by the HAProxy thread/process creation restriction and the
insecure-fork-wanted option is no longer needed.

3 weeks agoMINOR: otel: test: replaced argument variables with positional parameters in run...
Miroslav Zagorac [Wed, 15 Apr 2026 02:37:38 +0000 (04:37 +0200)]
MINOR: otel: test: replaced argument variables with positional parameters in run scripts

Replaced SH_ARGS variables with 'set --' and "${@}" to ensure proper
quoting of haproxy command-line arguments.

3 weeks agoMINOR: otel: test: added option parsing to the speed test script
Miroslav Zagorac [Wed, 15 Apr 2026 01:48:45 +0000 (03:48 +0200)]
MINOR: otel: test: added option parsing to the speed test script

Added getopts argument parsing with -h, -r and -d options, making sample
rate limits and wrk runtime configurable.  Introduced a dry-run variable
for debugging, httpd cleanup in sh_exit, and removal of the log directory
on exit if empty.

3 weeks agoMINOR: otel: added debug thread ID support for the OTel C wrapper library
Miroslav Zagorac [Mon, 13 Apr 2026 22:11:38 +0000 (00:11 +0200)]
MINOR: otel: added debug thread ID support for the OTel C wrapper library

Added per-thread ID tracking for the OpenTelemetry C wrapper debug system.
Registered HAProxy worker threads are identified by their tid;
unregistered threads (such as those created internally by the OTel SDK)
receive unique IDs from an atomic offset counter.

3 weeks agoMINOR: mux-quic: release BE idle conn after GOAWAY reception
Amaury Denoyelle [Fri, 17 Apr 2026 10:02:41 +0000 (12:02 +0200)]
MINOR: mux-quic: release BE idle conn after GOAWAY reception

An idle backend connection is useless if a HTTP/3 GOAWAY frame has been
received. Indeed, it is forbid to open new stream on such connection.

Thus, this patch ensures such connections are removed as soon as
possible. This is performed via a new check in qcc_is_dead() on
QC_CF_CONN_SHUT flag for backend connections. This ensures that a shut
connection is released instead of being inserted in idle list on detach
operation.

This commits also completes qcc_recv() with a new call to qcc_is_dead()
on its ending. This is necessary if GOAWAY is received on an idle
connection. For now, this is only checked for backend connections as a
GOAWAY is without any real effect for frontend connections. Thus, this
extra protection ensures that we do not break by incident QUIC frontend
support.

qcc_io_recv() also performs qcc_decode_qcs(). However, an extra
qcc_is_dead() is not necessary in this case as the following
qcc_io_process() already performs it.

3 weeks agoMEDIUM: h3: prevent new streams on GOAWAY reception
Amaury Denoyelle [Wed, 15 Apr 2026 14:44:59 +0000 (16:44 +0200)]
MEDIUM: h3: prevent new streams on GOAWAY reception

Implement the reception of a HTTP/3 GOAWAY frame. This is performed via
the new function h3_parse_goaway_frm(). The advertised ID is stored in
new <id_shut_r> h3c member. It serves to ensure that a bigger ID is not
advertised when receiving multiple GOAWAY frames.

GOAWAY frame reception is only really useful on the backend side for
haproxy. When this occurs, h3c is now flagged with H3_CF_GOAWAY_RECV.
Also, QCC is also updated with new flag QC_CF_CONN_SHUT. This flag
indicates that no new stream may be opened on the connection. Callback
avail_streams() is thus edited to report 0 in this case.

3 weeks agoMINOR: h3: simplify GOAWAY local emission
Amaury Denoyelle [Thu, 16 Apr 2026 16:21:40 +0000 (18:21 +0200)]
MINOR: h3: simplify GOAWAY local emission

Rework GOAWAY emission handling at the HTTP/3 layer. Previously, h3c
member <id_goaway> were updated during the connection on each new
streams attach. This ID was finally reused when a GOAWAY was emitted.

However, this is unnecessary to keep an updated ID during the connection
lifetime. Indeed, <largest_bidi_r> QCC member can be used for the same
purpose. Note that this is only useful for the frontend side. For a
client connection, GOAWAY contains a PUSH ID, thus 0 can be used for
now.

Thus, <id_goaway> in h3c is renamed <id_shut_l>. Now it is only sent
when the GOAWAY is emitted. This allows to reject any streams with a
greater ID. This approach is considered simpler.

Note that <largest_bidi_r> is not strictly similar to the obsolete
<id_goaway>. Indeed, if an error occurs before the corresponding stream
layer allocation, the former would still be incremented. However,
this is not a real issue as GOAWAY specification is clear that lower IDs
are not guaranteed to being handled well, until either the stream is
closed or resetted, or the whole connection is teared down.

3 weeks agoBUG/MINOR: mux_quic: limit avail_streams() to 2^62
Amaury Denoyelle [Wed, 15 Apr 2026 14:32:48 +0000 (16:32 +0200)]
BUG/MINOR: mux_quic: limit avail_streams() to 2^62

QUIC streams ID are encoded as 62-bit integer and cannot reuse an ID
within a connection. This is necessary to take into account this
limitation for backend connections.

This patch implements this via qmux_avail_streams() callback. In the
case where the connection is approaching the encoding limit, reduce the
advertised value until the limit is reached. Note that this is very
unlikely to happen as the value is pretty high.

This should be backported up to 3.3.

3 weeks agoMINOR: compression: prefix compression oriented functions with "comp_"
Aurelien DARRAGON [Wed, 15 Apr 2026 10:21:14 +0000 (12:21 +0200)]
MINOR: compression: prefix compression oriented functions with "comp_"

add comp_ prefix to all compression related functions, in anticipation
of decompression functions that will be integrated in the same file, so
we don't get mixed up between the two.

No change of behavior expected.

3 weeks agoBUG/MINOR: task: fix uninitialised read in run_tasks_from_lists()
Aurelien DARRAGON [Fri, 17 Apr 2026 06:16:38 +0000 (08:16 +0200)]
BUG/MINOR: task: fix uninitialised read in run_tasks_from_lists()

Since commit 7d40b31 ("MEDIUM: sched: do not run a same task multiple
times in series") I noticed that any valid config, once haproxy was
started, would produce uninitialised reads on valgrind:

[NOTICE]   (243490) : haproxy version is 3.4-dev9-0af603-2
[NOTICE]   (243490) : path to executable is /tmp/haproxy/haproxy
[WARNING]  (243490) : missing timeouts for proxy 'test'.
   | While not properly invalid, you will certainly encounter various problems
   | with such a configuration. To fix this, please ensure that all following
   | timeouts are set to a non-zero value: 'client', 'connect', 'server'.
[NOTICE]   (243490) : Automatically setting global.maxconn to 491.
==243490== Thread 4:
==243490== Conditional jump or move depends on uninitialised value(s)
==243490==    at 0x44DBD7: run_tasks_from_lists (task.c:567)
==243490==    by 0x44E99E: process_runnable_tasks (task.c:913)
==243490==    by 0x395A41: run_poll_loop (haproxy.c:2981)
==243490==    by 0x396178: run_thread_poll_loop (haproxy.c:3211)
==243490==    by 0x4E2DAA3: start_thread (pthread_create.c:447)
==243490==    by 0x4EBAA63: clone (clone.S:100)
==243490==

Looking at it, it is caused by the fact that task->last_run member which
was introduced and used by commit above is never assigned a default value
so the first time it is used, reading from it causes uninitialised read.

To fix the issue, we simply ensure last_run task member gets a default
value when the task or tasklet is created. We use '0' as default value,
as the value itself is from minor importance because the member is used
to detect if the task has already been executed for the current loop cycle
so it will self-correct in any case.

No backport needed, unless 7d40b31 is

3 weeks agoBUG/MEDIUM: mux-h2: ignore conn->owner when deciding if a connection is dead
Willy Tarreau [Thu, 16 Apr 2026 15:59:44 +0000 (17:59 +0200)]
BUG/MEDIUM: mux-h2: ignore conn->owner when deciding if a connection is dead

Originally, valid backend connections always used to have conn->owner
pointing to the owner session. In 1.9, commit 93c885 enforced this when
implementing backend H2 support by making sure that no orphaned connection
was left on its own with no remaining stream able to handle it.
Later, idle connections were reworked so that they were no longer
necessarily attached to a stream, but could be directly in the server,
accessed via a hash, so it started to become possible to have conn->owner
left to NULL when picking such a connection. It in fact happens for
http-reuse always, when the second stream picks the connection because
its owner is NULL and it's not changed.

More recently, a case was identified where it could be theoretically
possible to reinsert a dead connection into an idle list, and commit
59c599f3f0 ("BUG/MEDIUM: mux-h2: make sure not to move a dead
connection to idle") addressed that possibility in 3.3 by adding the
h2c_is_dead() test in h2_detach() before deciding to reinsert a
connection into the idle list.

Unfortunately, the combination of changes above results in the following
sequence being possible:
  - a stream requires a connection, connect_server() creates one, sets
    conn->owner to the session, then when the session is being set up,
    the SSL stack calls conn_create_mux() which gets the session from
    conn->owner, passes it to mux->init() (h2_init), which in turn
    creates the backend stream and assigns it this session.

  - when the stream ends, it detaches (h2_detach), and the call to
    h2c_is_dead() returns false because h2c->conn->owner is set. The
    connection is thus added into the server's idle list.

  - a new stream comes, it finds the connection in the server's list,
    which doesn't require to set conn->owner, the stream is added via
    h2_attach() which passes the stream's session, and that one is
    properly set on h2s again, but never on conn->owner.

  - the stream finishes, detaches, and this time the call to h2c_is_dead()
    sees the owner is NULL, thus indicates that the connection seems dead
    so it's not added again to the idle list, and it's destroyed.

Note that this most only happens at low loads (at most one active stream
per connection, so typically at most than one active stream per thread),
where the H2 reuse ratio on a server configured with http-reuse always
or http-reuse aggressive is close to 50%. At high loads, this is much more
rare, though looking at the reuse stats for a server, it's visible that a
sustained load still shows around 1% of the connections being periodically
renewed.

Interestingly, for RHTTP the impact is more important because there
was already a work around for this test in h2c_is_dead() but it uses
conn_is_reverse(), which is never correct in this case (it should be
called conn_to_reverse() because it says the conn must be reversed
and has not yet been), so this extra test doesn't protect against the
NULL check, and connections are closed after each stream is terminated
(if there is no other stream left).

After a long analysis with Amaury and Olivier, it was concluded that:
  - the h2c_is_dead() addition is finally not the best solution and
    could be refined, however in the current state it's a bit tricky.
  - the conn->owner test in h2c_is_dead() is no longer relevant,
    probably since 2.4 when connections were stored using hash_nodes
    in the servers and would no longer depend on a session, so that
    test should be removed.
  - the test conn_is_reverse() on the same line, that was added to
    ignore the former for RHTTP, and which doesn't properly work either
    should be removed as well.

Some further cleanups should be performed to clarify this situation.

This patch implements the points above, and it should be backported
wherever commit 59c599f3f0 was backported.

3 weeks agoMEDIUM: threads: change the default max-threads-per-group value to 16
Willy Tarreau [Thu, 16 Apr 2026 08:48:43 +0000 (10:48 +0200)]
MEDIUM: threads: change the default max-threads-per-group value to 16

A lot of our subsystems start to be shared by thread groups now
(listeners, queues, stick-tables, stats, idle connections, LB algos).
This has allowed to recover the performance that used to be out of
reach on losely shared platforms (typically AMD EPYC systems), but in
parallel other large unified systems (Xeon and large Arm in general)
still suffer from the remaining contention when placing too many
threads in a group.

A first test running on a 64-core Neoverse-N1 processor with a single
backend with one server and no LB algo specifiied shows 1.58 Mrps with
64 threads per group, and 1.71 Mrps with 16 threads per group. The
difference is essentially spent updating stats counters everywhere.

Another test is the connection:close mode, delivering 85 kcps with
64 threads per group, and 172 kcps (202%) with 16 threads per group.
In this case it's mostly the more numerous listeners which improve
the situation as the change is mostly in the kernel:

max-threads-per-group 64:
  # perf top
  Samples: 244K of event 'cycles', 4000 Hz, Event count (approx.): 61065854708 los
  Overhead  Shared Object     Symbol
    10.41%  [kernel]          [k] queued_spin_lock_slowpath
    10.36%  [kernel]          [k] _raw_spin_unlock_irqrestore
     2.54%  [kernel]          [k] _raw_spin_lock
     2.24%  [kernel]          [k] handle_softirqs
     1.49%  haproxy           [.] process_stream
     1.22%  [kernel]          [k] _raw_spin_lock_bh

  # h1load
  time conns tot_conn  tot_req      tot_bytes    err  cps  rps  bps   ttfb
     1  1024    84560    83536        4761666      0 84k5 83k5 38M0 11.91m
     2  1024   168736   167713        9559698      0 84k0 84k0 38M3 11.98m
     3  1024   253865   252841       14412165      0 85k0 85k0 38M7 11.84m
     4  1024   339143   338119       19272783      0 85k1 85k1 38M8 11.80m
     5  1024   424204   423180       24121374      0 84k9 84k9 38M7 11.86m

max-threads-per-group 16:
  # perf top
  Samples: 1M of event 'cycles', 4000 Hz, Event count (approx.): 375998622679 lost
  Overhead  Shared Object     Symbol
    15.20%  [kernel]          [k] queued_spin_lock_slowpath
     4.31%  [kernel]          [k] _raw_spin_unlock_irqrestore
     3.33%  [kernel]          [k] handle_softirqs
     2.54%  [kernel]          [k] _raw_spin_lock
     1.46%  haproxy           [.] process_stream
     1.12%  [kernel]          [k] _raw_spin_lock_bh

  # h1load
      time conns tot_conn  tot_req      tot_bytes    err  cps  rps  bps   ttfb
         1  1020   172230   171211        9759255      0 172k 171k 78M0 5.817m
         2  1024   343482   342460       19520277      0 171k 171k 78M0 5.875m
         3  1021   515947   514926       29350953      0 172k 172k 78M5 5.841m
         4  1024   689972   688949       39270207      0 173k 173k 79M2 5.783m
         5  1024   863904   862881       49184274      0 173k 173k 79M2 5.795m

So let's change the default value to 16. It also happens to match what's
used by default on EPYC systems these days.

This change was marked MEDIUM as it will increase the number of listening
sockets on some systems, to match their counter parts from other vendors,
which is easier for capacity planning.

3 weeks agoDOC: config: fix spelling of "max-threads-per-group" in the index
Willy Tarreau [Thu, 16 Apr 2026 08:35:31 +0000 (10:35 +0200)]
DOC: config: fix spelling of "max-threads-per-group" in the index

It was spelled "max-thread-per-group" (without 's'). No backport is
needed unless commit 7e22d9c484 ("MEDIUM: cpu-topo: Add a new
"max-threads-per-group" global keyword") and its possible successors
are backported.

3 weeks ago[RELEASE] Released version 3.4-dev9 v3.4-dev9
Willy Tarreau [Wed, 15 Apr 2026 15:59:00 +0000 (17:59 +0200)]
[RELEASE] Released version 3.4-dev9

Released version 3.4-dev9 with the following main changes :
    - DOC: config: fix ambiguous info in log-steps directive description
    - MINOR: filters: add filter name to flt_conf struct
    - MEDIUM: filters: add "filter-sequence" directive
    - REGTESTS: add a test for "filter-sequence" directive
    - Revert "CLEANUP: tcpcheck: Don't needlessly expose proxy_parse_tcpcheck()"
    - MINOR: tcpcheck: reintroduce proxy_parse_tcpcheck() symbol
    - BUG/MEDIUM: haterm: Move all init functions of haterm in haterm_init.c
    - BUG/MEDIUM: mux-h1: Disable 0-copy forwarding when draining the request
    - MINOR: servers: The right parameter for idle-pool.shared is "full"
    - DOC: config: Fix two typos in the server param "healthcheck" description
    - BUG/MINOR: http-act: fix a typo in the "pause" action error message
    - MINOR: tcpcheck: Reject unknown keyword during parsing of healthcheck section
    - BUG/MEDIUM: tcpcheck/server: Fix parsing of healthcheck param for dynamic servers
    - BUG/MINOR: counters: fix unexpected 127 char GUID truncation for shm-stats-file objects
    - BUG/MEDIUM: tcpcheck: Properly retrieve tcpcheck type to install the best mux
    - BUG/MEDIUM: payload: validate SNI name_len in req.ssl_sni
    - BUG/MEDIUM: jwe: fix NULL deref crash with empty CEK and non-dir alg
    - BUG/MEDIUM: jwt: fix heap overflow in ECDSA signature DER conversion
    - BUG/MEDIUM: jwe: fix memory leak in jwt_decrypt_secret with var argument
    - BUG: hlua: fix stack overflow in httpclient headers conversion
    - BUG/MINOR: hlua: fix stack overflow in httpclient headers conversion
    - BUG/MINOR: hlua: fix format-string vulnerability in Patref error path
    - BUG/MEDIUM: chunk: fix typo allocating small trash with bufsize_large
    - BUG/MEDIUM: chunk: fix infinite loop in get_larger_trash_chunk()
    - BUG/MINOR: peers: fix OOB heap write in dictionary cache update
    - CI: VTest build with git clone + cache
    - BUG/MEDIUM: connection: Wake the stconn on error when failing to create mux
    - CI: github: update to cache@v5
    - Revert "BUG: hlua: fix stack overflow in httpclient headers conversion"
    - CI: github: fix vtest path to allow correct caching
    - CI: github: add the architecture to the cache key for vtest2
    - MEDIUM: connections: Really enforce mux protocol requirements
    - MINOR: tools: Implement net_addr_type_is_quic()
    - MEDIUM: check: Revamp the way the protocol and xprt are determined
    - BUG/MAJOR: slz: always make sure to limit fixed output to less than worst case literals
    - MINOR: lua: add tune.lua.openlibs to restrict loaded Lua standard libraries
    - REGTESTS: lua: add tune.lua.openlibs to all Lua reg-tests
    - BUG/MINOR: resolvers: fix memory leak on AAAA additional records
    - BUG/MINOR: spoe: fix pointer arithmetic overflow in spoe_decode_buffer()
    - BUG/MINOR: http-act: validate decoded lengths in *-headers-bin
    - BUG/MINOR: haterm: Return the good start-line for 100-continue interim message
    - BUG/MEDIUM: samples: Fix handling of SMP_T_METH samples
    - BUG/MINOR: sample: fix info leak in regsub when exp_replace fails
    - BUG/MEDIUM: mux-fcgi: prevent record-length truncation with large bufsize
    - BUG/MINOR: hlua: fix use-after-free of HTTP reason string
    - BUG/MINOR: mux-quic: fix potential NULL deref on qcc_release()
    - BUG/MINOR: quic: increment pos pointer on QMux transport params parsing
    - MINOR: xprt_qstrm: implement Rx buffering
    - MINOR: xprt_qstrm/mux-quic: handle extra QMux frames after params
    - MINOR: xprt_qstrm: implement Tx buffering
    - MINOR: xprt_qstrm: handle connection errors
    - MEDIUM: mux-quic: implement QMux record parsing
    - MEDIUM: xprt_qstrm: implement QMux record parsing
    - MEDIUM: mux-quic/xprt_qstrm: implement QMux record emission
    - DOC: update draft link for QMux protocol
    - BUG/MINOR: do not crash on QMux reception of BLOCKED frames
    - Revert "BUG/MEDIUM: haterm: Move all init functions of haterm in haterm_init.c"
    - BUG/MEDIUM: haterm: Properly initialize the splicing support for haterm
    - BUG/MINOR: mux_quic: prevent QMux crash on qcc_io_send() error path
    - BUG/MINOR: xprt_qstrm: do not parse record length on read again
    - MEDIUM: otel: added OpenTelemetry filter skeleton
    - MEDIUM: otel: added configuration and utility layer
    - MEDIUM: otel: added configuration parser and event model
    - MEDIUM: otel: added post-parse configuration check
    - MEDIUM: otel: added memory pool and runtime scope layer
    - MEDIUM: otel: implemented filter callbacks and event dispatcher
    - MEDIUM: otel: wired OTel C wrapper library integration
    - MEDIUM: otel: implemented scope execution and span management
    - MEDIUM: otel: added context propagation via carrier interfaces
    - MEDIUM: otel: added HTTP header operations for context propagation
    - MEDIUM: otel: added HAProxy variable storage for context propagation
    - MINOR: otel: added prefix-based variable scanning
    - MEDIUM: otel: added CLI commands for runtime filter management
    - MEDIUM: otel: added group action for rule-based scope execution
    - MINOR: otel: added log-format support to the sample parser and runtime
    - MINOR: otel: test: added test and benchmark suite for the OTel filter
    - MINOR: otel: added span link support
    - MINOR: otel: added metrics instrument support
    - MINOR: otel: added log-record signal support
    - MINOR: otel: test: added full-event test config
    - DOC: otel: added documentation
    - DOC: otel: test: added test README-* files
    - DOC: otel: test: added speed test guide and benchmark results
    - DOC: otel: added cross-cutting design patterns document
    - MINOR: otel: added flt_otel_sample_eval and exposed flt_otel_sample_add_kv
    - MINOR: otel: changed log-record attr to use sample expressions
    - MINOR: otel: changed instrument attr to use sample expressions
    - DOC: otel: added README.md overview document
    - CLEANUP: ot: use the item API for the variables trees
    - BUG/MINOR: ot: removed dead code in flt_ot_parse_cfg_str()
    - BUG/MINOR: ot: fixed wrong NULL check in flt_ot_parse_cfg_group()
    - BUILD: ot: removed explicit include path when building opentracing filter
    - MINOR: ot: renamed the variable dbg_indent_level to flt_ot_dbg_indent_level
    - CI: Drop obsolete `packages: write` permission from `quic-interop-*.yml`
    - CI: Consistently add a top-level `permissions` definition to GHA workflows
    - CI: Wrap all `if:` conditions in `${{ }}`
    - CI: Fix regular expression escaping in matrix.py
    - CI: Update to actions/checkout@v6
    - CI: Simplify version extraction with `haproxy -vq`
    - CI: Merge `aws-lc.yml` and `aws-lc-fips.yml` into `aws-lc.yml`
    - CI: Merge `aws-lc-template.yml` into `aws-lc.yml`
    - CI: Consistently set up VTest with `./.github/actions/setup-vtest`
    - MINOR: mux_quic: remove duplicate QMux local transport params
    - CI: github: add bash to the musl job
    - BUG/MINOR: quic: do not use hardcoded values in QMux TP frame builder
    - BUG/MINOR: log: Fix error message when using unavailable fetch in logfmt
    - CLEANUP: log: Return `size_t` from `sess_build_logline_orig()`
    - CLEANUP: stream: Explain the two-step initialization in `stream_generate_unique_id()`
    - CLEANUP: stream: Reduce duplication in `stream_generate_unique_id()`
    - CLEANUP: http_fetch: Use local `unique_id` variable in `smp_fetch_uniqueid()`
    - CI: build WolfSSL job with asan enabled
    - MINOR: tools: memvprintf(): remove <out> check that always true
    - BUG/MEDIUM: cli: Properly handle too big payload on a command line
    - REGTESTS: Never reuse server connection in reg-tests/jwt/jwt_decrypt.vtc
    - MINOR: errors: remove excessive errmsg checks
    - BUG/MINOR: haterm: preserve the pipe size margin for splicing
    - MEDIUM: acme: implement dns-persist-01 challenge
    - MINOR: acme: extend resolver-based DNS pre-check to dns-persist-01
    - DOC: configuration: document dns-persist-01 challenge type and options
    - BUG/MINOR: acme: read the wildcard flag from the authorization response
    - BUG/MINOR: acme: don't pass NULL into format string
    - BUG/MINOR: haterm: don't apply the default pipe size margin twice
    - CLEANUP: Make `lf_expr` parameter of `sess_build_logline_orig()` const
    - MINOR: Add `generate_unique_id()` helper
    - MINOR: Allow inlining of `stream_generate_unique_id()`
    - CLEANUP: log: Stop touching `struct stream` internals for `%ID`
    - MINOR: check: Support generating a `unique_id` for checks
    - MINOR: http_fetch: Add support for checks to `unique-id` fetch
    - MINOR: acme: display the type of challenge in ACME_INITIAL_DELAY
    - MINOR: mjson: reintroduce mjson_next()
    - CI: Remove obsolete steps from musl.yml
    - CI: Use `sh` in `actions/setup-vtest/action.yml`
    - CI: Sync musl.yml with vtest.yml
    - CI: Integrate Musl build into vtest.yml
    - CI: Use `case()` function
    - CI: Generate vtest.yml matrix on `ubuntu-slim`
    - CI: Run contrib.yml on `ubuntu-slim`
    - CI: Use `matrix:` in contrib.yml
    - CI: Build `dev/haring/` as part of contrib.yml
    - MINOR: htx: Add helper function to get type and size from the block info field
    - BUG/MEDIUM: htx: Properly handle block modification during defragmentation
    - BUG/MEDIUM: htx: Don't count delta twice when block value is replaced
    - MINOR: ssl: add TLS 1.2 values in HAPROXY_KEYLOG_XX_LOG_FMT
    - EXAMPLES: ssl: keylog entries are greater than 1024
    - BUILD: Makefile: don't forget to also delete haterm on make clean
    - MINOR: stats: report the number of thread groups in "show info"
    - CLEANUP: sample: fix the comment regarding the range of the thread sample fetch
    - MINOR: sample: return the number of the current thread group
    - MINOR: sample: add new sample fetch functions reporting current CPU usage
    - BUG/MEDIUM: peers: trash of expired entries delayed after fullresync
    - DOC: remove the alpine/musl status job image
    - MINOR: mux-quic: improve documentation for qcs_attach_sc()
    - MINOR: mux-quic: reorganize code for app init/shutdown
    - MINOR: mux-quic: perform app init in case of early shutdown
    - MEDIUM: quic: implement fe.stream.max-total
    - MINOR: mux-quic: close connection when reaching max-total streams
    - REGTESTS: add QUIC test for max-total streams setting
    - MEDIUM: threads: start threads by groups
    - MINOR: acme: opportunistic DNS check for dns-persist-01 to skip challenge-ready steps
    - BUG/MINOR: acme: fix fallback state after failed initial DNS check
    - CLEANUP: acme: no need to reset ctx state and http_state before nextreq
    - BUG/MINOR: threads: properly set the number of tgroups when non using policy

3 weeks agoBUG/MINOR: threads: properly set the number of tgroups when non using policy
Willy Tarreau [Wed, 15 Apr 2026 15:33:04 +0000 (17:33 +0200)]
BUG/MINOR: threads: properly set the number of tgroups when non using policy

When nbthread is set, the CPU policies are not used and do not set
nbthread nor nbtgroups. When back into thread_detect_count(), these
are set respectively to thr_max and 1. The problem which becomes very
visible with max-threads-per-group, is that setting this one in
combination with nbthreads results in only one group with the calculated
number of threads per group. And there's not even a warning. So basically
a configuration having:

   global
       nbthread 64
       max-threads-per-group 8

would only start 8 threads.

In this case, grp_min remains valid and should be used, so let's just
change the assignment so that the number of groups is always correct.

A few ifdefs had to move because the calculations were only made for
the USE_CPU_AFFINITY case. Now these parts have been refined so that
all the logic continues to apply even without USE_CPU_AFFINITY.

One visible side effect is that setting nbthread above 64 will
automatically create the associated number of groups even when
USE_CPU_AFFINITY is not set. Previously it was silently changed
to match the per-group limit.

Ideally this should be backported to 3.2 where the issue was
introduced, though it may change the behavior of configs that were
silently being ignored (e.g. "nbthread 128"), so the backport should
be considered with care. At least 3.3 should have it because it uses
cpu-policy by default so it's only for failing cases that it would be
involved.

3 weeks agoCLEANUP: acme: no need to reset ctx state and http_state before nextreq
William Lallemand [Wed, 15 Apr 2026 14:17:39 +0000 (16:17 +0200)]
CLEANUP: acme: no need to reset ctx state and http_state before nextreq

The nextreq label already implement setting http_state to ACME_HTTP_REQ
and setting ctx->state to st. It is only needed to set the st variable
before jumping to nextreq.

3 weeks agoBUG/MINOR: acme: fix fallback state after failed initial DNS check
William Lallemand [Wed, 15 Apr 2026 14:06:53 +0000 (16:06 +0200)]
BUG/MINOR: acme: fix fallback state after failed initial DNS check

When the opportunistic initial DNS check (ACME_INITIAL_RSLV_READY) fails,
the state machine was incorrectly transitioning to ACME_RSLV_RETRY_DELAY
instead of ACME_CLI_WAIT. This caused the challenge to enter the DNS retry
loop rather than falling back to the normal cond_ready flow that waits for
the CLI signal.

Also reorder ACME_CLI_WAIT in the state enum and trace switch to reflect
the actual execution order introduced in the previous commit: it comes after
ACME_INITIAL_RSLV_READY, not before ACME_INITIAL_RSLV_TRIGGER.

No backport needed.

3 weeks agoMINOR: acme: opportunistic DNS check for dns-persist-01 to skip challenge-ready steps
William Lallemand [Wed, 15 Apr 2026 13:46:26 +0000 (15:46 +0200)]
MINOR: acme: opportunistic DNS check for dns-persist-01 to skip challenge-ready steps

For dns-persist-01, the "_validation-persist.<domain>" TXT record is set once
and never changes between renewals. Add an initial opportunistic DNS check
(ACME_INITIAL_RSLV_TRIGGER / ACME_INITIAL_RSLV_READY states) that runs before
the challenge-ready conditions are evaluated. If all domains already have the
TXT record, the challenge is submitted immediately without going through the
cli/delay/dns challenge-ready steps, making renewals faster once the record is
in place.

The new ACME_RDY_INITIAL_DNS flag is automatically set for
dns-persist-01 in cond_ready.