]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
16 hours agoBUG/MEDIUM: ssl: Don't free the early data buffer too early master
Olivier Houchard [Mon, 15 Jun 2026 18:29:23 +0000 (20:29 +0200)] 
BUG/MEDIUM: ssl: Don't free the early data buffer too early

When 0RTT is enabled, a temporary buffer for early data is used. We read
from it first when the mux asks for data, and then we free it when it is
empty, but that is not right, because maybe we have more early data to
receive, and then we no longer have any buffer to store them, and that
will eventually end up with the connection closed in error.
To fix that, as long as we haven't received all the early data yet, just
reset the buffer, instead of freeing it.
This should fix github issue #3416
This should be backported up to 2.8.

22 hours agoEXAMPLES: lua/acme: fix acme-gandi-livedns.lua configuration example flx04/master
William Lallemand [Mon, 15 Jun 2026 11:47:52 +0000 (13:47 +0200)] 
EXAMPLES: lua/acme: fix acme-gandi-livedns.lua configuration example

Fix the configuration example in acme-gandi-livedns.lua.

26 hours agoBUG/MINOR: quic: fix rxbuf settings on backend side
Amaury Denoyelle [Fri, 12 Jun 2026 13:40:46 +0000 (15:40 +0200)] 
BUG/MINOR: quic: fix rxbuf settings on backend side

QUIC flow control on bidirectional streams ensure that the peer cannot
emit more than what haproxy has allowed, which guarantees that buffering
is under controlled on the receiver side.

This limit is first announced on the transport parameter via
initial_max_stream_data_bidi_remote which is derived from configuration
value. QUIC MUX calculation for its streams is then directly based on
the transport parameter.

This mechanism works as expected on the frontend side, as in this case
all exchanges occur on remote streams opened by the opposite side.
However, this is not working as expected on the backend side, as in this
case transfers occur on streams opened locally by haproxy as the client.
Thus, configuration has no impact on backend side rxbuf which remains
set to a single buffer, causing important latency when retrieving large
objects.

This patch removes this limitation on the backend side by adjusting
quic_transport_params_init(). If <server> parameter is false, limitation
is set for initial_max_stream_data_bidi_local TP.

This must be backported up to 3.3.

27 hours agoBUG/MINOR: mux-h1: Properly resolve file path for 'h1-case-adjust-file'
Christopher Faulet [Mon, 15 Jun 2026 05:29:23 +0000 (07:29 +0200)] 
BUG/MINOR: mux-h1: Properly resolve file path for 'h1-case-adjust-file'

The file specified by 'h1-case-adjust-file' directive is only loaded during
post-parsing. However when a relative path is used, the corresponding
absoulte path was not resolve during parsing. So the file could be loaded
relatively from the wrong location leading to a configuration error. It may
happen if several configuration files are used or if several
"default-config" are used. The last "default" location was always used.

To fix the issue, the absolute path of the file is now resolved when the
directive is parsed.

This patch should fix the issue #3415. It must be backported to all
versions.

27 hours agoBUG/MEDIUM: http-ana: Don't ignore L7 retry errors
Christopher Faulet [Fri, 12 Jun 2026 13:57:50 +0000 (15:57 +0200)] 
BUG/MEDIUM: http-ana: Don't ignore L7 retry errors

with L7 retries are configured, when the max number of retries is reached
the error must be reported to the client. However, when it was an abort on a
reused connections, the client connection is silently closed. While it is
expected without L7 retries, to let the client retries on its own, it is
unexepcted with L7 retries.

So let's fix it by ignoring the SF_SRV_REUSED flag on the stream when a L7
retry fails. This way, a 502/425 will be reported to the client.

This patch should help to fix the issue #3414. It must be backported to all
supported versions.

27 hours agoBUG/MINOR: http-ana: Remove a debugging memset on redirect
Christopher Faulet [Fri, 12 Jun 2026 09:20:28 +0000 (11:20 +0200)] 
BUG/MINOR: http-ana: Remove a debugging memset on redirect

A memset used for debug was left when "keep-query" option was added. Let's
remove it. This bug should be harmless but it consumes extra CPU for
nothing.

This patch should be backported as far as 3.2.

27 hours agoDEBUG: stconn: Add a BUG_ON on shut flags when the endpoint is shut
Christopher Faulet [Tue, 9 Jun 2026 08:44:59 +0000 (10:44 +0200)] 
DEBUG: stconn: Add a BUG_ON on shut flags when the endpoint is shut

Whne the endpoint is shut (an applet or a mux), at least one of the SHW
flags must be set (SE_SHW_SILENT or SE_SHW_NORMAL). It is mandatory for
muxes to perform the shutdown. Otherwise, the shutdown could be ignored.

So let's add a BUG_ON() on it to be sure this never happen.

46 hours agoDOC: httpclient: document status 0 on internal error
William Lallemand [Sun, 14 Jun 2026 11:12:02 +0000 (11:12 +0000)] 
DOC: httpclient: document status 0 on internal error

This patch documents the behavior where the internal HTTP client sets
the response status to 0 when an error is encountered by the stream
(SF_ERR_MASK).

This allows users to distinguish between an HTTP status code returned
by a remote server and an internal error generated by HAProxy (e.g.
connection timeout, connection refused, etc.).

2 days agoMEDIUM: httpclient: set res.status to 0 upon SF_ERR_MASK
William Lallemand [Sun, 14 Jun 2026 08:46:38 +0000 (10:46 +0200)] 
MEDIUM: httpclient: set res.status to 0 upon SF_ERR_MASK

With the httpclient it's difficult to get if the HTTP status code was
returned by the actual server or if it's the internal proxy that
generate the error.

This patch changes the behavior by setting the status to 0 when an error
is get by the stream.

There were already valid cases when the status was 0 on some error, so
that should not really change the error path in the scripts.

2 days agoMEDIUM: httpclient/lua: allow multiple requests from a single core.httpclient() instance
William Lallemand [Sat, 13 Jun 2026 23:04:05 +0000 (01:04 +0200)] 
MEDIUM: httpclient/lua: allow multiple requests from a single core.httpclient() instance

Refactor the Lua HTTP client to defer initialization. core.httpclient()
no longer initializes the internal HTTP client immediately. Instead,
initialization now occurs within hlua_httpclient_send() when a request
method (e.g., get, put, head) is invoked.

The HTTPClient class now serves as a factory for accessing methods, while
a new class, HTTPClientRequest, has been introduced to represent individual
requests and manage the HTTP client lifecycle.

This change allows multiple requests to be executed using a single
HTTP client instance:

  local hc = core.httpclient()
  local res1 = hc:get({url = "...", headers = ...})
  local res2 = hc:post({url = "...", headers = ...})
  local res3 = hc:put({url = "...", headers = ...})

This refactor maintains backward compatibility, as existing scripts that
instantiate a new core.httpclient() for every request will continue to
work as expected.

2 days agoREORG: httpclient/lua: move the lua httpclient code to http_client.c
William Lallemand [Sat, 13 Jun 2026 18:55:34 +0000 (20:55 +0200)] 
REORG: httpclient/lua: move the lua httpclient code to http_client.c

Move the lua httpclient code from hlua.c to http_client.c

The code is almost the same but the registering of the class which is
done in hlua_http_client_init_state(), from REGISTER_HLUA_STATE_INIT()

check_args() calls have been replaced by hlua_check_args().

hlua_httpclient_destroy_all() is exported so it can be called in hlua.c.
hlua_httpclient_table_to_hdrs() is made static.

2 days agoMINOR: lua: export hlua_pusherror() and check_args()
William Lallemand [Sat, 13 Jun 2026 18:49:43 +0000 (20:49 +0200)] 
MINOR: lua: export hlua_pusherror() and check_args()

hlua_pusherror() and check_args() are being exported.

check_args() is now a macro to hlua_check_args() so it's not confusing
when called outside hlua.c.

3 days agoBUG/MINOR: server: fix add server with consistent hash balancing quic-interop flx04/quic-interop
Amaury Denoyelle [Fri, 12 Jun 2026 08:54:42 +0000 (10:54 +0200)] 
BUG/MINOR: server: fix add server with consistent hash balancing

When a dynamic server is added with consistent hash balancing on the
backend, its lb_nodes elements are allocated and associated with a
calculated server key. This operation is performed in add server handler
via srv_alloc_lb(). By default, the server key is based on its ID.
However, automatic server ID is calculated later in add server handler,
which means the initial lb_nodes are not valid.

This could cause load balacing issue but in fact this is not directly
visible as the server key is recalculated when the dynamic server is
enabled via chash_queue_dequeue_srv() : all server lb_nodes are dequeued
and requeued with the now proper key.

Thus, "add server" handler must be corrected as it is buggy when
considering it alone. The simplest solution of the current patch is to
initialize server ID before srv_alloc_lb() is invoked. There is no issue
as handler runs under thread isolation so there is no risk of multiple
servers manipulating the same ID. Server insertion in proxy ID tree is
still performed at the end of the handler when all fallible operation
are completed.

The fact that server key is recalculated when the server is set to ready
state is a side effect of the following patch which was introduced in
3.0. What this means though is that users of older releases are facing a
bigger issue, with load-balancing not working as expected. Thus,
this patch is even more crucial for 2.8 and older releases.

  faa8c3e024b1e4e5833a8deaa6545675036544c6
  MEDIUM: lb-chash: Deterministic node hashes based on server address

This should fix github issue #3413. Thanks to Joao Morais for is
analysis on the problem.

This must be backported to all stable releases.

3 days agoBUG/MEDIUM: h3: Properly handle PUSH_PROMISE on backend connections
Olivier Houchard [Fri, 12 Jun 2026 11:39:07 +0000 (13:39 +0200)] 
BUG/MEDIUM: h3: Properly handle PUSH_PROMISE on backend connections

When we receive a PUSH_PROMISE frame while we don't expect it, flag it
as a connection error, do not just set ret to H3_ERR_ID_ERROR, as it
would just be considered the number of bytes we read, and could lead to
random corruption. This should only happen with backend connections.
This should be backported whenever commit 4a8bb2fe5 is backported.

4 days agoMEDIUM: tasks: Redispatch shared tasks when the thread is loaded
Olivier Houchard [Tue, 9 Jun 2026 11:01:09 +0000 (13:01 +0200)] 
MEDIUM: tasks: Redispatch shared tasks when the thread is loaded

Now that there is no longer a shared wake queue, chances are if a shared task
is scheduled, it will always end up on the same thread. In
wake_expired_tasks(), when a task has to be waken up, randomly look to
three other threads, and if the runqueue of the current thread is at least
two time bigger than the runqueue of one of the other threads, then give
that task to that thread, so that our load gets reduced.
If we're giving the task to another thread, then we have to add the
TASK_RUNNING flag until we waked it up, otherwise the other thread could
just run it, if it gets waken up from another path, and free it while
we're still not done with it.
2 times has been chosen somewhat arbitrarily, and may be tweaked at a
later date if deemed not optimal.

4 days agoMINOR: tasks: Remove wq_lock and the per-thread group wait queues
Olivier Houchard [Wed, 13 May 2026 11:54:42 +0000 (13:54 +0200)] 
MINOR: tasks: Remove wq_lock and the per-thread group wait queues

Now that they are no longer used, remove wq_lock and the per-thread
group wait queues.

4 days agoMINOR: tasks: Use __task_set_state_and_tid() in task_instant_wakeup()
Olivier Houchard [Thu, 11 Jun 2026 14:34:19 +0000 (16:34 +0200)] 
MINOR: tasks: Use __task_set_state_and_tid() in task_instant_wakeup()

Modify task_instant_wakeup() to use __task_set_state_and_tid().
It uses the new ownership behavior, but that's okay because
task_instant_wakeup() was not used anywhere.

4 days agoMEDIUM: tasks: Remove the per-thread group wait queue
Olivier Houchard [Tue, 28 Apr 2026 16:46:54 +0000 (18:46 +0200)] 
MEDIUM: tasks: Remove the per-thread group wait queue

Totally remove the per-thread group wait queue. This was potentially a
source of contention, because there were only a global lock for all
those wait queues.
Instead, for shared tasks, there is now the concept of ownership for the
task. When a task is in the wait queue, run queue, or is running on that
particular thread, the task's tid is set to -2 - thread_tid, and only
that thread will be responsible for it until it is no longer running,
and in none of its queue.
When a shared task is scheduled to be run at a later time, if its
current tid is -1, then the current thread will take ownership, and put
it in its own wait queue. If it is already owned, then TASK_WOKEN_WQ is
added to the task's state, and a task_wakeup() is done, so that the
owner thread will add it in its wait queue.
If there is any owner, then a task_wakeup() will just add the task to
the owner's runqueue, otherwise the current thread will become the
owner.

4 days agoMINOR: tasks: Start using __task_set_state_and_tid()
Olivier Houchard [Thu, 11 Jun 2026 14:29:03 +0000 (16:29 +0200)] 
MINOR: tasks: Start using __task_set_state_and_tid()

Start using __task_set_state_and_tid() when we're changing the state of
the task while queueing it, in preparation to the future ownership
changes.

4 days agoMINOR: tasks: Use __task_get_current_owner() in task_kill.
Olivier Houchard [Thu, 11 Jun 2026 14:20:29 +0000 (16:20 +0200)] 
MINOR: tasks: Use __task_get_current_owner() in task_kill.

In task_kill(), to know which thread to send the task to, use
__task_get_current_owner(), in preparation for future changes.

4 days agoMINOR: tasks: Introduce __task_get_current_owner
Olivier Houchard [Tue, 28 Apr 2026 16:09:19 +0000 (18:09 +0200)] 
MINOR: tasks: Introduce __task_get_current_owner

Introduce a new function, __task_get_current_owner, that returns the
owner of a task based on its current tid.
-1 means there is no current owner, otherwise either the tid is >= 0, in
which case it will just return it, or it's < -1, in which case it will
return -2 - tid, the tid of the thread with the current ownership.

4 days agoMINOR: tasks: Add __task_get_new_tid_field()
Olivier Houchard [Tue, 28 Apr 2026 16:09:32 +0000 (18:09 +0200)] 
MINOR: tasks: Add __task_get_new_tid_field()

Introduce __task_get_new_tid_field(), that provides the tid to be used
for a task.
For shared task, to mark temporary ownership of a task, instead of -1,
the tid will be set to -2-tid, tid being the tid of the current thread.

4 days agoMINOR: tasks: Introduce __task_set_state_and_tid
Olivier Houchard [Thu, 16 Apr 2026 16:01:52 +0000 (18:01 +0200)] 
MINOR: tasks: Introduce __task_set_state_and_tid

Introduce a new function, __task_set_state_and_tid, that atomically can
set a task's state and its tid. This will be used later, as the tid will
be used to indicate task ownership even for shared tasks.

4 days agoDOC: acme: add mentions of lua features
William Lallemand [Thu, 11 Jun 2026 21:51:45 +0000 (23:51 +0200)] 
DOC: acme: add mentions of lua features

Mention ACME.challenge_ready() and event_hdl which are useful in lua to
implement dns-01.

4 days agoEXAMPLES: lua/acme: add a dns-01 handler for Gandi LiveDNS API
William Lallemand [Thu, 11 Jun 2026 17:34:15 +0000 (19:34 +0200)] 
EXAMPLES: lua/acme: add a dns-01 handler for Gandi LiveDNS API

This Lua script automates dns-01 ACME challenges using the Gandi LiveDNS
API v5. It subscribes to the ACME_DEPLOY event to set the required
_acme-challenge TXT record via the Gandi REST API, signals HAProxy that
the challenge is ready using ACME.challenge_ready(), then cleans up the
TXT record once the certificate is issued on ACME_NEWCERT.

The API key is read from the GANDI_API_KEY environment variable at
startup. Zone discovery is automatic: the script probes parent zones
from longest to shortest until Gandi accepts the record, which handles
both apex and wildcard certificates transparently.

4 days agoMINOR: acme: publish ACME_DEPLOY event via event_hdl
William Lallemand [Thu, 11 Jun 2026 16:39:51 +0000 (18:39 +0200)] 
MINOR: acme: publish ACME_DEPLOY event via event_hdl

Add EVENT_HDL_SUB_ACME_DEPLOY to the ACME family. It is published in
the dns-01 challenge path after the TXT record information has been
prepared, carrying the certificate store name, domain, account
thumbprint, dns_record value, and optionally the provider and vars
strings.

Lua subscribers using core.event_sub() receive the event data as an
AcmeEvent object, which is the same class used for ACME_NEWCERT and
carries the fields relevant to the event type.

4 days agoMINOR: acme: publish ACME_NEWCERT event via event_hdl
William Lallemand [Thu, 11 Jun 2026 13:47:42 +0000 (15:47 +0200)] 
MINOR: acme: publish ACME_NEWCERT event via event_hdl

Add a new EVENT_HDL_SUB_ACME_NEWCERT event type in the ACME family.
It is published after a new certificate has been successfully fetched
and installed. The event carries the certificate store name, allowing
subscribers to act on newly available certificates.

Lua subscribers using core.event_sub() receive the event data as an
AcmeEvent object with a crtname field containing the certificate store
name.

4 days agoBUG/MINOR: cpu-topo: use ha_diag_notice() to report thread creations
Willy Tarreau [Thu, 11 Jun 2026 16:40:08 +0000 (18:40 +0200)] 
BUG/MINOR: cpu-topo: use ha_diag_notice() to report thread creations

Using ha_diag_warning() to report the number of threads created resulted
in warnings being counted and possibly an error being fired when combined
with -dW:

  $ printf "global\nstats socket /tmp/sock1\n" | ./haproxy -dD -dW -c -f /dev/stdin; echo $?
  [NOTICE]   (10406) : haproxy version is 3.5-dev0-5091ac-35
  [NOTICE]   (10406) : path to executable is ./haproxy
  [DIAG]     (10406) : Created 20 threads split into 2 groups
  [ALERT]    (10406) : Some warnings were found and 'zero-warning' is set. Aborting.
  1

Now that we have ha_diag_notice(), let's use it:

  $ printf "global\nstats socket /tmp/sock1\n" | ./haproxy -dD -dW -c -f /dev/stdin; echo $?
  [DIAG]     (10513) : Created 20 threads split into 2 groups
  0

It would make sense to backport this to 3.2 because it helps validate configs
against diag warnings without triggering a false positive. It depends on
this previous patch:

  MINOR: errors: add ha_diag_notice() to report diag-level notifications

4 days agoMINOR: errors: add ha_diag_notice() to report diag-level notifications
Willy Tarreau [Thu, 11 Jun 2026 16:36:17 +0000 (18:36 +0200)] 
MINOR: errors: add ha_diag_notice() to report diag-level notifications

Right now the only way to report info that is only displayed in diag
mode with -dD is to use ha_diag_warning(). The problem is that this is
then counted as a warning and may result in errors when combined with
-dW, as happens for the CPU topology info:

  $ printf "global\nstats socket /tmp/sock1\n" | ./haproxy -dD -dW -c -f /dev/stdin; echo $?
  [NOTICE]   (10406) : haproxy version is 3.5-dev0-5091ac-35
  [NOTICE]   (10406) : path to executable is ./haproxy
  [DIAG]     (10406) : Created 20 threads split into 2 groups
  [ALERT]    (10406) : Some warnings were found and 'zero-warning' is set. Aborting.
  1

We need another level. This commit introduces ha_diag_notice() which only
emits a notification that doesn't count as a warning. Note that we could
even introduce an info level and revisit various messages so that notice
only reports certain events while info is for anything (like versions
above). That could be a future improvement.

4 days agoBUG/MEDIUM: ktls: defer enabling TLS ULP on a socket until connected
Karol Kucharski [Thu, 11 Jun 2026 12:48:38 +0000 (14:48 +0200)] 
BUG/MEDIUM: ktls: defer enabling TLS ULP on a socket until connected

The Linux tls module requires a socket to be in TCP_ESTABLISHED state
before we can enable the TLS ULP on the socket, if the socket is in any
other state, then the setsockopt() call will fail, and we won't use
kTLS on that socket.
To make sure we're not doing it too early, defer it until the TLS
handshake is done, which means the TCP connection is established.

This should be backported up to 3.3.

Signed-off-by: Karol Kucharski <kkucharski@fastlogic.pl>
4 days agoMINOR: acme/lua: implement ACME.challenge_ready() Lua function
William Lallemand [Wed, 10 Jun 2026 13:12:51 +0000 (15:12 +0200)] 
MINOR: acme/lua: implement ACME.challenge_ready() Lua function

Add a new ACME global Lua table with a challenge_ready(crt, dns) method
that wraps acme_challenge_ready(). It marks the ACME challenge for domain
<dns> in certificate <crt> as ready and returns the number of remaining
challenges, or 0 when all challenges are ready and validation has been
triggered. A Lua error is raised if the certificate or domain is not found.

The ACME table is registered for each lua_State via the new
REGISTER_HLUA_STATE_INIT() mechanism.

4 days agoMEDIUM: lua: move longjmp annotation macros to hlua.h
William Lallemand [Wed, 10 Jun 2026 12:17:22 +0000 (14:17 +0200)] 
MEDIUM: lua: move longjmp annotation macros to hlua.h

__LJMP, WILL_LJMP() and MAY_LJMP() were defined locally in hlua.c,
making them unavailable to other modules that implement Lua bindings.
Move them to include/haproxy/hlua.h so they can be used outside of
hlua.c.

4 days agoMINOR: lua: add REGISTER_HLUA_STATE_INIT() to register state init callbacks
William Lallemand [Wed, 10 Jun 2026 13:03:05 +0000 (15:03 +0200)] 
MINOR: lua: add REGISTER_HLUA_STATE_INIT() to register state init callbacks

Add a registration mechanism so that modules outside of hlua.c can hook
into each lua_State creation. Modules call hap_register_hlua_state_init()
(or the REGISTER_HLUA_STATE_INIT() macro) with a callback of the form:

  int my_init(lua_State *L, char **errmsg);

The callback returns an ERR_* code. ERR_ALERT and ERR_WARN trigger
ha_alert()/ha_warning() respectively; any other non-zero errmsg is
emitted via ha_notice(). ERR_FATAL or ERR_ABORT cause exit(1).
Registered entries are freed in hlua_deinit().

5 days agoBUILD: h3: fix compilation with USE_TRACE=0
Amaury Denoyelle [Thu, 11 Jun 2026 09:47:57 +0000 (11:47 +0200)] 
BUILD: h3: fix compilation with USE_TRACE=0

Mark argument in h3_trace_header as unused if USE_TRACE is not set.

No need to backport unless HTTP/3 header traces are picked.

5 days agoMINOR: h3: trace HTTP headers on BE side
Amaury Denoyelle [Thu, 11 Jun 2026 09:20:54 +0000 (11:20 +0200)] 
MINOR: h3: trace HTTP headers on BE side

Output HTTP/3 header traces on the backend side. As previous commit,
this relies on h3_trace_header() function.

Extra calls are added for fields extracted from the request start-line
which produce an HTTP/3 pseudo-header.

5 days agoMINOR: h3: trace HTTP headers on FE side
Amaury Denoyelle [Thu, 11 Jun 2026 09:09:31 +0000 (11:09 +0200)] 
MINOR: h3: trace HTTP headers on FE side

Output trace for HTTP/3 headers manipulated on the frontend side. This
is implement via a new utility function h3_trace_header(), largely
inspired from existing h2_trace_header().

An extra call is added for HTTP/3 response :status which is extracted
from the HTX start line.

5 days agoMINOR: h3: extend trace verbosity
Amaury Denoyelle [Thu, 11 Jun 2026 08:57:56 +0000 (10:57 +0200)] 
MINOR: h3: extend trace verbosity

Define two new values for HTTP/3 trace verbosity : simple and advanced.
For now, these values are unused. However advanced level will become
useful to implement HTTP/3 header traces.

5 days agoMINOR: acme: introduce acme_challenge_ready() for reuse outside the CLI
William Lallemand [Wed, 10 Jun 2026 09:29:18 +0000 (11:29 +0200)] 
MINOR: acme: introduce acme_challenge_ready() for reuse outside the CLI

Extract the challenge-readiness logic from cli_acme_chall_ready_parse()
into a new acme_challenge_ready(crt, dns) function so it can be called
from other contexts such as Lua event handlers.

It slightly changes the messages on the CLI.

5 days agoBUG/MEDIUM: acme: stuck ACME task when authz is already "valid"
William Lallemand [Wed, 10 Jun 2026 16:06:57 +0000 (18:06 +0200)] 
BUG/MEDIUM: acme: stuck ACME task when authz is already "valid"

When an ACME order is re-used or when a domain was recently validated,
the CA may return status "valid" for an authorization without requiring
any challenge to be solved.  In acme_res_auth(), this is handled by
setting auth->validated = 1 and jumping to out â€” but auth->ready is
never initialized and stays 0.

This became a bug in 3.4 when the "challenge-ready" option and the
ACME_CLI_WAIT state were introduced (commit 2b0c510aff).  ACME_CLI_WAIT
computes:

    all_cond_ready &= auth->ready;

across all authorizations.  A single auth->ready == 0 drives the AND
to zero and the task waits indefinitely for a readiness signal that
will never arrive, since no challenge was published and no external
agent will ever call challenge_ready() for that domain.

Fix it by setting auth->ready = ctx->cfg->cond_ready for already-valid
authorizations, marking them as satisfying all required readiness
conditions so ACME_CLI_WAIT can proceed normally.

This should be backported to 3.4.

6 days agoBUILD: servers: Fix build with -std=gnu89
Olivier Houchard [Wed, 10 Jun 2026 08:23:18 +0000 (10:23 +0200)] 
BUILD: servers: Fix build with -std=gnu89

Commit 3c923d075 introduced a C99ism by declaring a variable in a for loop,
don't do that, especially since there already is a variable named "i"
declared.
This should fix the build when -std=c89 is used.
This should be backported if commit 3c923d075 is backported.

6 days agoBUG/MINOR: quic: fix Initial length value in sent packets
Amaury Denoyelle [Tue, 9 Jun 2026 13:15:47 +0000 (15:15 +0200)] 
BUG/MINOR: quic: fix Initial length value in sent packets

QUIC packets using a long header contains a Length field. Its value is
the length of the content following it, i.e. the packet number field and
the remaining payload (QUIC frames and TLS AEAD tag).

Computation to determine the packet length is performed in
qc_do_build_pkt(). However this calculation is incorrect when Initial
padding is added on a small enough Initial packet. As length field is
encoded as a varint, it changes the field size which grow from one to
two bytes, reducing in effect the total required padding length from one
byte. However, length value is not updated and thus is one byte bigger
than the final packet payload with padding.

Fix this calculation by reducing the length value after padding size has
been adjusted.

This bug caused the peer to reject such faulty packets. However, its
impact is minor as it only happened only for Initial with small enough
payload. Packets used for ClientHello/ServerHello exchanges should be
large enough and typically not concerned by this bug, except maybe in
case of fragmentation.

This bug was detected by testing QUIC backend with a quiche server. The
server endpoint reported the faulty packets with the following trace :
  [2026-06-09T13:42:13.694179158Z ERROR quiche_server] 1b1b961c9c4ae1f470f3687510b120da1f5d5f5a recv failed: InvalidPacket

This must be backported up to 3.0.

7 days agoREGTESTS: Fix log matching in healthcheck-section.vtc
Christopher Faulet [Tue, 9 Jun 2026 06:36:29 +0000 (08:36 +0200)] 
REGTESTS: Fix log matching in healthcheck-section.vtc

One of the regex matching syslog messages for S2 was not correct, making the
script fail depending on the order of the healthchecks. It is now fixed.

7 days agoMEDIUM: servers: Move to a per-thread idle connection cleanup task
Olivier Houchard [Thu, 28 May 2026 15:24:08 +0000 (17:24 +0200)] 
MEDIUM: servers: Move to a per-thread idle connection cleanup task

Having a single task to take care of idle connection cleanup across all
servers leads to high contention. It uses a lock to maintain its tree of
servers to track, and then can acquire the idle_conns lock for each thread.
Instead, have one task per thread. Each thread will maintain its own
tree, so there will be no need for any lock, and it will just acquire
its own idle_conns lock, so it will lead to less contention.
This is a performance improvement, so backporting is optional, but may be
considered if it is worth it. That would require backporting commit
6f8dab258379dd53e327433ffd890c6d3d6f89ed too.

7 days agoMINOR: servers: Add a back-pointer to the server in srv_per_thread
Olivier Houchard [Thu, 28 May 2026 13:21:13 +0000 (15:21 +0200)] 
MINOR: servers: Add a back-pointer to the server in srv_per_thread

In struct srv_per_thread, add a pointer to the server, as with just a
pointer to srv_per_thread, we can't figure out the related server.

7 days agoBUG/MEDIUM: checks: Dequeue checks on purge
Olivier Houchard [Mon, 8 Jun 2026 13:48:42 +0000 (15:48 +0200)] 
BUG/MEDIUM: checks: Dequeue checks on purge

When tune.max-checks-per-thread is used, checks that should run are
queued, to avoid having too many checks running at the same time.
But if the check is about to be purged, because the server is being
deleted, we have to explicitly remove it from the queue as that memory is
about to be freed, otherwise it will cause a use-after-free.
Also, queued checks have not yet incremented th_ctx->running_checks, so
don't decrement it if we're queued.

This should be backported up to 3.0.

7 days agoMINOR: memprof: be careful to account allocations only once
Willy Tarreau [Mon, 8 Jun 2026 07:52:45 +0000 (09:52 +0200)] 
MINOR: memprof: be careful to account allocations only once

For certain calls like strdup(), certain libc call the malloc() symbol
themselves, resulting in both strdup() and malloc() accounting for the
allocation while a single free() call is accounted for. Usually it's
not very hard to spot as these allocations are done inside libc, but
yet they complicate the tracing of allocations.

Let's note when we enter a handler and refrain from doing the accounting
again in this case. This way, the strdup() call place will be accountable
for the allocation and the libc's internal malloc() will not be seen.

7 days agoMINOR: memprof: make in_memprof a bitfield instead of a counter
Willy Tarreau [Mon, 8 Jun 2026 07:39:43 +0000 (09:39 +0200)] 
MINOR: memprof: make in_memprof a bitfield instead of a counter

It's not convenient to use it as it is now because it may only be
used to count passes via the memprof init code. Let's turn it to
a bitfield instead so that we can also check what we're doing there.
This is safe because all callers of memprof_init() check for the
bit being zero first so it's not reentrant.

7 days agoBUG/MINOR: acl: report "ACL" not "map" in ACL ID lookup failures
Willy Tarreau [Mon, 8 Jun 2026 11:43:25 +0000 (13:43 +0200)] 
BUG/MINOR: acl: report "ACL" not "map" in ACL ID lookup failures

As reported by @broxio in issue #3411, when trying to delete an ACL by
its name, in case of error the message says "unknown map identifier".
We need to check the type to decide between map and ACL as in other
messages.

This can be backported to all stable branches. Thanks to @broxio for
reporting the issue with a reproducer and providing this tested fix.

8 days agoMINOR: pools: reject creation of pools containing invalid chars in their name
Willy Tarreau [Mon, 8 Jun 2026 06:54:37 +0000 (08:54 +0200)] 
MINOR: pools: reject creation of pools containing invalid chars in their name

In order to preventively avoid issues that complicate debugging, let's
report to developers early if a pool name is not acceptable. This patch
does it in create_pool_from_reg() which catches both direct and declared
registrations. Aside the previous case, this didn't catch any other
occurrence.

8 days agoCLEANUP: sessions: simplify the sess_priv_conns pool name
Willy Tarreau [Mon, 8 Jun 2026 06:44:25 +0000 (08:44 +0200)] 
CLEANUP: sessions: simplify the sess_priv_conns pool name

Using "show pools detailed" on the CLI breaks the column alignment on
"sess_priv_conns" because the pool name contains spaces: "session priv
conns list", which is not welcome as pool names are truncated after the
12th chars anyway. Let's shorten it to the pool's name as done for many
other ones: sess_priv_conns.

This can be backported as far as 3.0 where this name was introduced,
because it helps when trying to sum or graph certain metrics during
debugging.

8 days agoBUG/MEDIUM: xprt_qmux: implement ->get_ssl_sock_ctx() to get the SSL laye
Willy Tarreau [Sat, 6 Jun 2026 08:32:36 +0000 (08:32 +0000)] 
BUG/MEDIUM: xprt_qmux: implement ->get_ssl_sock_ctx() to get the SSL laye

conn_get_ssl_sock_ctx() retrieves the ssl_sock_ctx of a connection by
calling conn->xprt->get_ssl_sock_ctx(). Only ssl_sock implements this
method, and it returns conn->xprt_ctx. This works because for every
existing XPRT combination the SSL layer is the topmost one: even
xprt_handshake (SOCKS4, PROXY, NetScaler CIP) is installed *below*
ssl_sock, so conn->xprt keeps pointing to ssl_sock.

Qmux changes this assumption: xprt_qmux is stacked *on top of* ssl_sock
and keeps the SSL layer as its lower layer to exchange the QUIC transport
parameters over the established TLS stream. During the qmux handshake,
conn->xprt therefore points to xprt_qmux, which does not implement
get_ssl_sock_ctx(), making conn_get_ssl_sock_ctx() return NULL for the
whole connection, affecting every caller that inspects the SSL layer
(sample fetches, logging, ssl_sock_infocbk(), ...).

The visible consequence was a crash: when the peer sends a TLS alert
during the qmux handshake, the SSL library calls ssl_sock_infocbk(),
which recovers a valid connection but a NULL ctx, rightfully triggering
the "BUG_ON(!ctx)" early in the function.

This patch implements xprt_qmux_get_ssl_sock_ctx() so that it returns
the ssl_sock_ctx of the lower layer when it is the SSL layer, just like
ssl_sock_get_ctx() does. conn_get_ssl_sock_ctx() then works again for
all callers while the qmux handshake is in progress. After the handshake,
conn->xprt is restored to the SSL layer so nothing else changes.

This should be backported to 3.4.

8 days agoBUG/MEDIUM: threads: Fiw build when using no thread
Olivier Houchard [Mon, 8 Jun 2026 00:07:03 +0000 (02:07 +0200)] 
BUG/MEDIUM: threads: Fiw build when using no thread

In thread_detect_count(), avoid any usage of thread_cpu_enable_at_boot
if we're building without thread support. That variable is only defined
when building with threads, and those tests make little sense when
building with no thread, anyway.
This was submitted by: ririnto <ririnto@kakao.com>
This should fix github issue #3408.
This should be backported to 3.4.

9 days agoBUG/MEDIUM: regex: initialize the match array earlier during boot
Willy Tarreau [Sun, 7 Jun 2026 05:03:06 +0000 (07:03 +0200)] 
BUG/MEDIUM: regex: initialize the match array earlier during boot

As reported by @zhanhb in github issue #3410, since 3.3 with commit
fda6dc959 ("MINOR: regex: use a thread-local match pointer for pcre2"),
the local_pcre2_match array is initialized too late for use by Lua. If
a lua-load makes use of regex, it may segfault (actually using PCRE2
is fine but PCRE2_JIT will crash):

Let's change the init sequence so that the first thread's context is
initialized early at boot and other threads are initialized when they
are created. For lua-load-per-thread, all extra threads will run on
the first thread's temporary storage during init but that's not a
problem since the sole purpose is to avoid concurrent accesses.

Thanks to @zhanbb for the detailed report and quick tests. This needs
to be backported to 3.3.

10 days agoREGTESTS: checks: Add script for external healthchecks
Christopher Faulet [Fri, 5 Jun 2026 09:10:18 +0000 (11:10 +0200)] 
REGTESTS: checks: Add script for external healthchecks

This script is quite basic but it should validate the external healthchecks
are working well.

10 days agoBUG/MINOR: tcpcheck: Override external check if healthcheck section is set
Christopher Faulet [Fri, 5 Jun 2026 08:50:32 +0000 (10:50 +0200)] 
BUG/MINOR: tcpcheck: Override external check if healthcheck section is set

When an external check was configured at the proxy level, the healthcheck
section set on a server was not considered. The main reason was that the
check type of the server was always inherited for the proxy one.

To fix the issue, when a healthcheck section is set on a server line, the
check type for the server is forced to TCPCHK.

This patch must be backported to 3.4.

10 days agoBUG/MINOR: mux_quic: do not interrupt recv on error/incomplete data
Amaury Denoyelle [Fri, 5 Jun 2026 08:22:50 +0000 (10:22 +0200)] 
BUG/MINOR: mux_quic: do not interrupt recv on error/incomplete data

Prior to this patch, qcc_io_recv() stream decoding loop was interrupted
on the first decoding error or if incomplete data could not be parsed.

This patch adjusts this part so that loop is stopped only on a
connection level error. In case of a stream level error or on incomplete
data, decoding continues on the next QCS entry.

Without this patch, there is a risk that a QCS decode is not performed
as expected, with a possible client timeout firing. This is pretty
unlikely though. However this patch is still necessary to remove
completely this possibility.

This should be backported up to 3.2.

10 days agoOPTIM: mux_quic: remove QCS from recv_list on reset
Amaury Denoyelle [Fri, 5 Jun 2026 08:02:31 +0000 (10:02 +0200)] 
OPTIM: mux_quic: remove QCS from recv_list on reset

When a RESET_STREAM is received, QCS Rx channel is closed and pending Rx
data and buf are cleared without being transmitted to upper stream
layer.

This patch complements this by removing the QCS from recv_list if
present in it. This is a small optimization nothing would be performed
for such QCS on qcc_io_recv().

10 days agoBUG/MEDIUM: mux_quic: prevent risk of infinite loop on recv
Amaury Denoyelle [Fri, 5 Jun 2026 08:03:08 +0000 (10:03 +0200)] 
BUG/MEDIUM: mux_quic: prevent risk of infinite loop on recv

When a RESET_STREAM is received, QCS Rx channel is closed and pending Rx
data and buf are cleared without being transmitted to upper stream
layer.

This can cause an issue if this QCS instance is present in the QCC
recv_list. When qcc_io_recv() is executed after reset handling, an
infinite loop is triggered for the QCS instance as qcs_rx_avail_data()
always return 0.

This issue happened due to the poor writing of the while loop in
qcc_io_recv() which is not correctly protected against infinite
execution.

To prevent this issue, this patch rewrites the loop. Crucially,
LIST_DEL_INIT() is now performed unconditionally outside of the inner
loop. This guarantees that even if the inner loop is not executed, the
stream will be removed from QCC recv_list and iteration will progress.

This is functionally correct as a QCS should not be present in recv_list
if there is no avail data or demux is currently blocked. For the first
condition, qcc_decode_qcs() will be called again when new data is read
unless demux is blocked. In this case, QCS will be reinserted in the
list on unblocking, with a rescheduling to invoke qcc_decode_qcs().

In the context of the currently found reproducer linked to stream reset,
the QCS instance can be safely removed from the recv_list without
implication.

This must be backported up to 3.2.

11 days agoBUG/MEDIUM: server/checks: Support healtcheck keyword on default-server lines
Christopher Faulet [Thu, 4 Jun 2026 19:53:31 +0000 (21:53 +0200)] 
BUG/MEDIUM: server/checks: Support healtcheck keyword on default-server lines

The healthcheck keyword could be parsed on default-server lines but not
copied during server initialization, making it ineffective. But there is
also a true issue by setting it on a default-server. The pseudo server used
to parse the default-server line is not initialized via the new_server()
function, as regular servers. So there is no tcpcheck information inherited
from the proxy. We must take care of that when the "healthcheck" keyword is
parsed to avoid crashes.

This patch must be backported to 3.4.

11 days agoMINOR: check: Don't dump buffers state in check traces for external checks
Christopher Faulet [Thu, 4 Jun 2026 19:50:11 +0000 (21:50 +0200)] 
MINOR: check: Don't dump buffers state in check traces for external checks

In healthcheck trace messages, there is no reason to dump the in/out buffers
state for external checks. So let's skip this part in that case.

11 days agoBUG/MEDIUM: check: Ignore small-buffer option when starting an external check
Christopher Faulet [Thu, 4 Jun 2026 16:55:23 +0000 (18:55 +0200)] 
BUG/MEDIUM: check: Ignore small-buffer option when starting an external check

When an external check is started for a server, there is no tcpcheck
ruleset. The pointer is NULL. It was an issue leading to a crash if the
small-buffer option was enabled on the healthchecks. However, it is
irrelevant for external checks because it is only usefull to tcp checks.

So, the option must be ignored if there is no tcpcheck ruleset.

This patch must be backported to 3.4.

11 days agoBUG/MEDIUM: check: Skip tcpcheck post-config for external checks
Christopher Faulet [Thu, 4 Jun 2026 16:43:12 +0000 (18:43 +0200)] 
BUG/MEDIUM: check: Skip tcpcheck post-config for external checks

When an external check was configured on a backend, the tcpcheck post config
for backend's servers was still performed instead to be skipped. The led to
a NULL-deref on the tcpcheck ruleset pointer and so to a segfault.

It seems to be only an issue for the 3.4 and higher. However, for older
versions, the tcpcheck post-config is still performed for external checks
and it is not really clean. This can hide some bugs.

For the 3.4, a workaround consists in configuring the backend to use a
tcp-check before configuring the external check:

  backend be
    option tcp-check
    option external-check
    ...

This patch should fix the issue #3407. It could be good to backport it to
all supported versions.

12 days ago[RELEASE] Released version 3.5-dev0 v3.5-dev0
Willy Tarreau [Wed, 3 Jun 2026 13:26:45 +0000 (15:26 +0200)] 
[RELEASE] Released version 3.5-dev0

Released version 3.5-dev0 with the following main changes :
    - MINOR: version: mention that it's development again

12 days agoMINOR: version: mention that it's development again
Willy Tarreau [Wed, 3 Jun 2026 13:25:53 +0000 (15:25 +0200)] 
MINOR: version: mention that it's development again

This essentially reverts 1cf7dc07e9.

12 days ago[RELEASE] Released version 3.4.0 v3.4.0
Willy Tarreau [Wed, 3 Jun 2026 13:01:51 +0000 (15:01 +0200)] 
[RELEASE] Released version 3.4.0

Released version 3.4.0 with the following main changes :
    - BUG/MINOR: tcpcheck: Check LDAP response to not read more data than available
    - BUG/MINOR: ssl-gencert: validate SNI characters to prevent SAN certificate injection
    - BUG/MINOR: mux-h1: H2 preface rejection doesn't update stick-table glitches
    - BUG/MEDIUM: cpu-topo: Enforce thread-hard-limit on policy
    - BUG/MEDIUM: qmux: do not crash on too large record
    - BUG/MEDIUM: qmux: do not crash on receiving an invalid first frame
    - BUG/MINOR: qmux: reject too large initial record
    - Revert "BUG/MEDIUM: dns: fix long loops in additional records parse on name failure"
    - BUG/MINOR: qpack: Fix index calculation in debug functions
    - BUG/MINOR: qpack: fix potential null-pointer dereference in qpack_dht_insert()
    - CLEANUP: qpack: fix copy-paste typo in value Huffman debug string
    - BUG/MINOR: qpack: fix sign bit mask in qpack_decode_fs_pfx()
    - CLEANUP: qpack: fix copy-paste typo in value Huffman debug string for WLN
    - BUG/MINOR: qpack: fix huff_dec() error handling in qpack_decode_fs()
    - CLEANUP: qpack: move encoded macros to qpack-t.h to avoid duplication
    - BUG/MEDIUM: quic: handle ECONNREFUSED on RX side
    - BUG/MINOR: quic: Fix memory leak in quic_deallocate_dghdlrs()
    - BUG/MEDIUM: lua: defer Lua VM initialisation to the first Lua config keyword
    - REGTESTS: lua: fix tune.lua.openlibs in Lua reg-tests
    - BUG/MINOR: mux-h2: Count padding for connection flow control on error path
    - BUILD: addons: convert 51d addon to EXTRA_MAKE
    - BUILD: addons: convert deviceatlas addon to EXTRA_MAKE
    - BUILD: addons: convert WURFL addon to EXTRA_MAKE
    - MINOR: mux_quic/flags: add missing flags
    - BUG/MINOR: mux_quic: open an idle QCS on reset on BE side
    - BUG/MINOR: mux_quic: fix BE conn removal on app shutdown
    - BUG/MINOR: mux_quic: prevent BE reuse with an errored conn
    - BUG/MINOR: quic: fix ack range node pool_free call passing wrong pointer type
    - MEDIUM: quic: optimize HKDF operations by reusing per-thread contexts
    - BUG/MEDIUM: quic: reset cwnd in slow_start on persistent congestion (cubic)
    - BUG/MEDIUM: quic: reset consecutive_losses on exit from recovery period (cubic)
    - BUG/MINOR: quic: update drs->lost before calling on_ack_recv
    - Revert "MEDIUM: quic: optimize HKDF operations by reusing per-thread contexts"
    - BUG/MEDIUM: lua: register hlua_init() as a pre-check to fix crash without Lua config
    - REGTESTS: quic: disable quic/ocsp_auto_update for now
    - BUG/MINOR: threads: set at least grp_max when mtpg is too small
    - BUG/MEDIUM: threads: ignore max-threads-per-group when thread-groups is set
    - CLEANUP: thread: indicate when max-threads-per-group is ignored
    - MINOR: cpu-topo: notify when cpu-policy is ignored due to other settings
    - MINOR: thread: report when thread-groups or nbthread results in less threads
    - BUILD: makefile: include EXTRA_MAKE in the .build_opts construction
    - BUG/MINOR: quic: Fix another buffer overflow with sockaddr_in46
    - MINOR: quic: Copy sin6_flowinfo and sin6_scope_id too
    - BUILD: Makefile: put EXTRA_MAKE help at the right place
    - BUG/MINOR: cache: fix cache tree iteration
    - BUG/MEDIUM: resolvers: Wait a bit before calling the xprt prepare_srv
    - CLEANUP: addons/51degrees: initialize variables
    - MINOR: addons/51degrees: handle memory allocation failures
    - CLEANUP: ncbmbuf: improve handling of memory allocation errors in unit tests
    - CLEANUP: admin/halog: improve handling of memory allocation errors
    - DOC: internals: clarify ambiguous wording in core-principles
    - DOC: internals: add a threat model definition
    - DOC: add security.txt describing how to report security issues
    - DOC: security: also add a note to exclude dev/ and admin/
    - BUG/MEDIUM: qmux: Close connection on invalid frame
    - CLEANUP: fix comment typo
    - BUG/MEDIUM: h3: fix MAX_PUSH_ID handling
    - BUG/MINOR: cache: Fix copy of value when parsing maxage
    - BUG/MEDIUM: mux-h1: Dup connection/upgrade value to parse it when making headers
    - BUG/MEDIUM: htx: Fix headers rollback on partial copy in htx_xfer()
    - MINOR: deinit: release the in-memory copy of shared libs
    - MINOR: debug: add -dA to dump an archive of all dependencies
    - BUG/MEDIUM: ssl: Make sure the alpn length is small enough
    - BUG/MINOR: applet: Commit changes into input buffer after sending HTX data
    - BUG/MINOR: mux-spop: Fix possible off-by-one OOB read in spop_get_varint()
    - BUG/MEDIUM: leastconn: Unlock the write lock on allocation failure
    - BUG/MINOR: tasks: Increase the right niced_task counter
    - BUILD: makefile: search for Lua 5.5 as well
    - DEV: dev/gdb: improve ebtree pointer handling
    - DEV: dev/gdb: add simple task dump
    - DEV: dev/gdb: add simple thread dump
    - DEV: dev/gdb: add fdtab dump
    - DOC: config: add a few more explanation in http-reusee regarding sni-auto
    - REGTESTS: add basic QMux tests
    - BUG/MINOR: http-act: Properly handle final evaluation in pause action
    - BUILD: makefile/lua: use the system's default library before all other variants
    - BUG/MINOR: startup: unbreak chroot with CAP_SYS_CHROOT
    - BUG/MINOR: haterm: do not try to bind QUIC when not supported
    - BUG/MINOR: haterm: also apply the tcp-bind-opts to clear TCP "bind" lines
    - CLEANUP: haterm: do not try to bind to SSL when not built in
    - MINOR: haterm: enable ktls on the SSL bind line when supported
    - CI: github: replace cirrus by a vmactions/freebsd-vm job
    - BUILD: makefile: fix build error with GNU make 4.2.1 and /bin/dash
    - BUG/MEDIUM: channel: Fix condition to know if a channel may send
    - BUG/MEDIUM: vars: Properly eval set-var-fmt action for emtpy log-format string
    - CI: github: run illumos job weekly on Mondays at 03:00 instead of monthly
    - BUG/MEDIUM: stream: Don't use small buffer on queuing with a request data filter
    - BUG/MINOR: jwe: don't write randoms past MAX_DECRYPTED_CEK_LEN in RSA_PKCS1_PADDING
    - BUG/MEDIUM: chunk: do not rely on small trash by default for expressions
    - CLEANUP: map: always test pat->ref in sample_conv_map_key()
    - DEV: patchbot: prepare for new version 3.5-dev
    - MINOR: version: mention that it's 3.4 LTS now.

12 days agoMINOR: version: mention that it's 3.4 LTS now.
Willy Tarreau [Wed, 3 Jun 2026 13:00:25 +0000 (15:00 +0200)] 
MINOR: version: mention that it's 3.4 LTS now.

The version will be maintained up to around Q2 2031. Let's
also update the INSTALL file to mention this.

12 days agoDEV: patchbot: prepare for new version 3.5-dev
Willy Tarreau [Wed, 3 Jun 2026 12:56:22 +0000 (14:56 +0200)] 
DEV: patchbot: prepare for new version 3.5-dev

The bot will now load the prompt for the upcoming 3.5 version so we have
to rename the files and update their contents to match the current version.

12 days agoCLEANUP: map: always test pat->ref in sample_conv_map_key()
Willy Tarreau [Wed, 3 Jun 2026 12:36:37 +0000 (14:36 +0200)] 
CLEANUP: map: always test pat->ref in sample_conv_map_key()

sample_conf_map_key() calls pattern_exec_match() which may return a
static pattern with ref=NULL when passed with fill=1 (which is the
case) and pat->match == NULL (which doesn't seem to be the case). It
doesn't seem it could happen with standard maps, as only "-m found"
drops has a NULL ->match function and there's no keyword associated
with it) but maybe this could happen with maps implemented in Lua,
though this remains unlikely.

Anyway better clarify the situation by always checking that the ref
is non-null before dereferencing it, it will at least avoid warnings
from code coverage tools.

12 days agoBUG/MEDIUM: chunk: do not rely on small trash by default for expressions
Willy Tarreau [Wed, 3 Jun 2026 12:00:31 +0000 (14:00 +0200)] 
BUG/MEDIUM: chunk: do not rely on small trash by default for expressions

There's a corner case with get_trash_chunk_sz() combined with the use
of small bufs: if some incoming data is going to be inflated by a
converter in a non-predictable way (say url_enc etc) then there are
two possibilities:
  - either we try to allocate a size that corresponds to the data, but
    we risk to allocate a small buf to convert a 900B chunk, that will
    now fail if it contains too many non-printable chars;
  - or we try to allocate 3x the size to be conservative, but without
    large bufs we'd fail to transcode any chunk larger than 5.3kB, even
    if it contains only printable chars.

The approach should definitely be refined and it is not 100% reliable
for now. Better temporarily ignore the small buffers for these particular
cases where the savings are not relevant, and see how to pass the knowledge
of the expected size ranges deeper down the API in 3.5. We may possibly rely
on the current trash size (instead of contents) or other mechanisms that
are yet to be specified. alloc_small_trash_chunk() gets the same change
BTW for the same reasons.

The comment for get_trash_chunk_sz() was updated to restate the importance
of being conservative when requesting a size.

No backport is needed.

12 days agoBUG/MINOR: jwe: don't write randoms past MAX_DECRYPTED_CEK_LEN in RSA_PKCS1_PADDING
Willy Tarreau [Wed, 3 Jun 2026 11:23:32 +0000 (13:23 +0200)] 
BUG/MINOR: jwe: don't write randoms past MAX_DECRYPTED_CEK_LEN in RSA_PKCS1_PADDING

The recent fix in commit 1a5a33396d ("BUG/MEDIUM: jwe: substitute random
CEK on RSA1_5 decryption failure per RFC 7516 #11.5") writes 8 bytes at
once but stops at the last one, so it can overflow the sample by 7 bytes.
This is totally harmless since the max size is 64 bytes, but better stop
at the boundary. A final loop completes one byte at a time by construction
so that we can adapt to any value of MAX_DECRYPTED_CEK_LEN, but the compiler
will not emit it since we stop at 64.

No backport is needed, it's only for 3.4.

12 days agoBUG/MEDIUM: stream: Don't use small buffer on queuing with a request data filter
Christopher Faulet [Wed, 3 Jun 2026 12:28:27 +0000 (14:28 +0200)] 
BUG/MEDIUM: stream: Don't use small buffer on queuing with a request data filter

When there is a filter registered on the request data forwarding, we must
disable usage of the small buffers. For now it is safer to do so because we
don't know if the filter will properly handle the small buffers. In
addition, there is a true issue because it is possible to never re-arm the
receives in that case because the buffer reserve must be respected. This
leads to think a small buffer is always full, even empty one.

No backport needed.

12 days agoCI: github: run illumos job weekly on Mondays at 03:00 instead of monthly
William Lallemand [Wed, 3 Jun 2026 11:18:47 +0000 (13:18 +0200)] 
CI: github: run illumos job weekly on Mondays at 03:00 instead of monthly

The previous schedule (25th of each month) provided too little coverage
frequency. Switch to a weekly run every Monday at 03:00 UTC to catch
regressions sooner.

13 days agoBUG/MEDIUM: vars: Properly eval set-var-fmt action for emtpy log-format string
Christopher Faulet [Wed, 3 Jun 2026 09:48:16 +0000 (11:48 +0200)] 
BUG/MEDIUM: vars: Properly eval set-var-fmt action for emtpy log-format string

When the log-format string was empty, in action_store() function, a fallback was
performed on the expression evaluation, thinking a set-var() was performed.
However, it is possible to have an empty log-format string. At least, on 3.2 and
3.0, it is allowed to parse an empty log-format string, quoted empty string are
not rejected.

So, on 3.2 and 3.0, it was possible to have a "set-var-fmt" action in the config
leading to parse an empty log-format string. Doing so, a crash could be
experienced when the action was executed because the fallback on the expression
evaluation led to dereference a NULL pointer.

To fix the issue, during parsing the action type is now set to a different value
for a "set-var" or a "set-var-fmt" action. And this action type is tested during
execution to perform the right action.

This patch should fix issue #3406. It must be backported as far as 3.0. Only 3.2
and 3.0 are affected by the issue.

13 days agoBUG/MEDIUM: channel: Fix condition to know if a channel may send
Christopher Faulet [Wed, 3 Jun 2026 09:27:30 +0000 (11:27 +0200)] 
BUG/MEDIUM: channel: Fix condition to know if a channel may send

Historically, we considered a channel cannot send before the connection was
established. This was useful to know if the reserve should still be
respected for the receives. This was because it was possible to rewrite the
request on connection retry (because of http-send-name-header option).

However noadays, it is a useless limitation. Once data forwarding is
started, there is no longer rewrites on the request at the stream layer
(http-send-name-header option is handled by the muxes). And, since it is
possible to use small buffers to queue requests, it could be an issue,
because the reserve and the small buffer size are the same by default. Once
a small request was finally dequeued, the receives on client side were not
re-armed because we should still respect the reserve on receives
(channel_recv_limit() was returning 0 in that case).

To fix the issue, we must consider a channel may send since the underlying
stconn has reached the SC_ST_REQ state, instead of SC_ST_EST. Doing so, we
are able to ignore the reserve earlier and the receives can be re-armed even
with small buffers.

There is no reason to backport this patch, except if an issue is reported,
because only the 3.4 is concerned. But it could theorically be backported to
all stable versions.

13 days agoBUILD: makefile: fix build error with GNU make 4.2.1 and /bin/dash
Willy Tarreau [Wed, 3 Jun 2026 10:01:47 +0000 (12:01 +0200)] 
BUILD: makefile: fix build error with GNU make 4.2.1 and /bin/dash

The latest fix in the Makefile in commit 9993688954 ("BUILD: makefile/lua:
use the system's default library before all other variants") broke the
build on a machine with GNU make 4.2.1 and /bin/dash:

  Makefile:690: *** unterminated call to function 'shell': missing ')'.  Stop.

It's caused by the '#' in '#include'. Protecting it with a backslash
fixes the make issue but moves it to the shell where it's echoed in the
output. Printf '\043' works but not sure if it's everywhere yet. At this
point better just revert that tiny part which was made to refine the
presence check for lua.h by checking that it contains valid C code. If
the commit above is backported, this one will have to be as well.

13 days agoCI: github: replace cirrus by a vmactions/freebsd-vm job
William Lallemand [Sat, 18 Apr 2026 13:13:18 +0000 (15:13 +0200)] 
CI: github: replace cirrus by a vmactions/freebsd-vm job

Cirrus FreeBSD jobs is not available anymore since June 1st , this job
uses github qemu-based images to run a FreeBSD job.

Remove Cirrus job.

13 days agoMINOR: haterm: enable ktls on the SSL bind line when supported
Willy Tarreau [Tue, 2 Jun 2026 17:19:25 +0000 (19:19 +0200)] 
MINOR: haterm: enable ktls on the SSL bind line when supported

When both USE_LINUX_SPLICE and USE_KTLS are enabled, it's worth
enabling kTLS on the bind line as it significantly increases the
local bit rate as well as through TLS accelerators (up to x2/x3).
The -dT option remains available to disable it. It was verified to
gracefully downgrade when not supported (e.g. OpenSSL 3.0.1 does
this).

13 days agoCLEANUP: haterm: do not try to bind to SSL when not built in
Willy Tarreau [Tue, 2 Jun 2026 16:57:05 +0000 (18:57 +0200)] 
CLEANUP: haterm: do not try to bind to SSL when not built in

When built without USE_OPENSSL, the binding errors are dirty, speaking
about crt-store and stuff like this. Better just indicate that SSL
support was not built in and explain how to enable it.

13 days agoBUG/MINOR: haterm: also apply the tcp-bind-opts to clear TCP "bind" lines
Willy Tarreau [Tue, 2 Jun 2026 16:52:56 +0000 (18:52 +0200)] 
BUG/MINOR: haterm: also apply the tcp-bind-opts to clear TCP "bind" lines

Commit 92581043fb ("MINOR: haterm: add long options for QUIC and TCP
"bind" settings") added --tcp-bind-opts. The doc (and commit) says that
it applies to TCP bind lines but it only applied to the TCP/SSL ones,
not the clear ones. Let's fix it. No backport needed, this is only 3.4.

13 days agoBUG/MINOR: haterm: do not try to bind QUIC when not supported
Willy Tarreau [Tue, 2 Jun 2026 16:46:01 +0000 (18:46 +0200)] 
BUG/MINOR: haterm: do not try to bind QUIC when not supported

When building without QUIC support (e.g. an SSL library not supporting
it), we'll get errors when trying to bind to the SSL port that QUIC is
not supported because the quic binding was unconditional. Let's only
place it when QUIC is supported. No backport needed, this is only 3.4.

13 days agoBUG/MINOR: startup: unbreak chroot with CAP_SYS_CHROOT
Maxime Henrion [Mon, 1 Jun 2026 14:49:02 +0000 (10:49 -0400)] 
BUG/MINOR: startup: unbreak chroot with CAP_SYS_CHROOT

The use of the unshare() mechanism to get the ability to chroot as an
unprivileged user produced a warning on some configurations where the
haproxy process has the CAP_SYS_CHROOT capability. We now only attempt
to use it when a previous chroot() call failed because of insufficient
privileges.

This should fix GitHub issue #3395. No backport needed.

13 days agoBUILD: makefile/lua: use the system's default library before all other variants
Willy Tarreau [Tue, 2 Jun 2026 14:34:37 +0000 (16:34 +0200)] 
BUILD: makefile/lua: use the system's default library before all other variants

The recent update to the makefile in commit bfbca23dc2 ("BUILD: makefile:
search for Lua 5.5 as well") to enable searching for Lua 5.5 revealed a
problem by which we were using the fallback versions before the main one
(e.g. /usr/include/lua-5.4/lua.h before /usr/include/lua.h). However, the
libs often contain the version in their name so that we can end up linking
with 5.5 while 5.4 was used in the include.

This was detected only when enabling lua 5.5 because in Lua 5.4
"luaL_openlibs()" was a symbol and became an inline in 5.5, preventing
from using a mix of the two versions.

The current change is minimal in that it skips all fallbacks when lua.h
is present in /usr/include, and includes it in the test to make sure that
the directory found contains valid C. LUA_LIB checks for lua before the
variants so as to remain consistent with the system provided version.

Thanks to @gene-git for reporting this problem in GH issue #3404.

This may have to be backported after a period of observation if users
face build issues for older releases on newer distros. In this case,
backporting 1c0f781994 ("MINOR: hlua: Add support for lua 5.5") would
equally be needed. However this will result in the system's version
being used first, which may or may not be desired.

13 days agoBUG/MINOR: http-act: Properly handle final evaluation in pause action
Christopher Faulet [Tue, 2 Jun 2026 11:38:14 +0000 (13:38 +0200)] 
BUG/MINOR: http-act: Properly handle final evaluation in pause action

The ACT_OPT_FINAL flag was not properly handled in the pause action. When
this flag is set, because of an abort or an unexpected error, an action must
no longer yield. However, in the pause action, this flag was never tested.
In case of client abort for instance, this could trigger an internal error
instead of a client error.

This patch should fix the issue #3403. It must be backported as far as 3.2.

13 days agoREGTESTS: add basic QMux tests
Amaury Denoyelle [Mon, 1 Jun 2026 16:27:26 +0000 (18:27 +0200)] 
REGTESTS: add basic QMux tests

Write two simple QMux tests, for http/3 in SSL and clear.

2 weeks agoDOC: config: add a few more explanation in http-reusee regarding sni-auto
Willy Tarreau [Tue, 2 Jun 2026 07:10:27 +0000 (09:10 +0200)] 
DOC: config: add a few more explanation in http-reusee regarding sni-auto

The default sni-auto that aims at not upsetting certain servers doing
excessive checks of SNI vs host has some drawbacks (lower reuse ratio)
that are particularly hard to diagnose, so let's explain how connections
are reused/purged when dealing with many hosts, and how to cheat as well.

Let's also mention the expression used by "sni-auto" since it was only
mentioned in the code.

2 weeks agoDEV: dev/gdb: add fdtab dump
Willy Tarreau [Wed, 27 May 2026 16:51:28 +0000 (18:51 +0200)] 
DEV: dev/gdb: add fdtab dump

Three functions are provided here:
  fd_dump: lists all FDs
  fd_dump_conn: lists all FDs holding a connection
  fd_dump_listener: lists all FDs holding a listener

They take no argument, and dump some of the known info. E.g. for
a connection, ctrl, xprt, flags, mux, sessions, frontend's name
and session's age are reported. Example:

  (gdb) fd_dump_conn
  fd    31: rm=0 tm=0x2 um=0 st=0x21 refc=0x1 tkov=0 gen=0 conn=0x7fffe803b600: flg=0x300 err=0 ctrl=0xdf51c0 xprt=0xdf5c80 mux=0xbaeee0 sess=0x7ffff003b570: fe=0x1e45b00 id=foo age=0ms

They are particularly slow because they iterate over all possible FDs,
so better limit them to the desired types.

2 weeks agoDEV: dev/gdb: add simple thread dump
Willy Tarreau [Wed, 27 May 2026 16:50:11 +0000 (18:50 +0200)] 
DEV: dev/gdb: add simple thread dump

The thread_dump function dumps the list of known threads and a few info
on them (pointer, current run queue, flags etc). This should help more
easily spot a particular one and find stuck ones.

E.g:

  (gdb) thread_dump
  Tid    0: pth=0x7ffff7e797c0 mono=2222322327950732 now_ms=4294947291 fl=0x38 rq=-1 cq=0 current=(nil)
  Tid    1: pth=0x7ffff78d8640 mono=2222322327928085 now_ms=4294947291 fl=0x38 rq=-1 cq=0 current=(nil)
  Tid    2: pth=0x7ffff6b7e640 mono=2222322327927150 now_ms=4294947291 fl=0x38 rq=-1 cq=0 current=(nil)
  Tid    3: pth=0x7ffff637d640 mono=2222322327924878 now_ms=4294947291 fl=0x38 rq=-1 cq=0 current=(nil)
  Tid    4: pth=0x7ffff5b7c640 mono=2222322327925676 now_ms=4294947291 fl=0x38 rq=-1 cq=0 current=(nil)
  Tid    5: pth=0x7ffff537b640 mono=2222322327929524 now_ms=4294947291 fl=0x38 rq=-1 cq=0 current=(nil)
  Tid    6: pth=0x7ffff4b7a640 mono=2222322327926817 now_ms=4294947291 fl=0x38 rq=-1 cq=0 current=(nil)
  Tid    7: pth=0x7fffdffff640 mono=2222322327947960 now_ms=4294947291 fl=0x38 rq=-1 cq=0 current=(nil)

2 weeks agoDEV: dev/gdb: add simple task dump
Willy Tarreau [Wed, 27 May 2026 16:49:51 +0000 (18:49 +0200)] 
DEV: dev/gdb: add simple task dump

New functions task_dump_wq and task_dump_rq can be used to dump tasks
in a wait queue or in a run queue respectively. For the wait queue (the
most common usage), one needs to pass either the thread-local's timers,
or the thread group ones for shared tasks:

  task_dump_wq &ha_tgroup_ctx[0].timers
  task_dump_wq &ha_thread_ctx[0].timers

For the run queue, task_dump_rq will take the thread's rqueue:

  task_dump_rq &ha_thread_ctx[0].rqueue

The output is  the task pointer and a dump of the task* struct per line,
then a total count at the end.

2 weeks agoDEV: dev/gdb: improve ebtree pointer handling
Willy Tarreau [Wed, 27 May 2026 16:49:27 +0000 (18:49 +0200)] 
DEV: dev/gdb: improve ebtree pointer handling

The ebtree descent functions currently use $arg0 as is and it's up to
the user to manually type the required casts that are never obvious
(particularly when coming from a pointer). Let's put the eb_root* cast
in the function to be more user-friendly.

2 weeks agoBUILD: makefile: search for Lua 5.5 as well
Willy Tarreau [Mon, 1 Jun 2026 16:44:04 +0000 (18:44 +0200)] 
BUILD: makefile: search for Lua 5.5 as well

Support for Lua 5.5 was brought in 3.4-dev2 with commit 1c0f781994
("MINOR: hlua: Add support for lua 5.5") but the Makefile doesn't look
for it, which can be quite confusing on recent distros which start to
ship with it. Let's add it to the looked up names.

2 weeks agoBUG/MINOR: tasks: Increase the right niced_task counter
Olivier Houchard [Mon, 1 Jun 2026 16:17:50 +0000 (18:17 +0200)] 
BUG/MINOR: tasks: Increase the right niced_task counter

In __task_wakeup(), for a niced task, we don't always want to increase
the niced_task counter of the running thread's thread group, if we are
waking up the task of another thread, who belongs to a different thread
group, then we want to increment that thread group's counter instead, as
that's the one that will get decremented later.
So just increase the counter for the target thread'd thread group,
instead of using tg_ctx.
The impact is probably pretty minor, niced task shared amongst thread
are not very common, and the impact would mostly mean we'd run more/less
tasks in one run of process_runnable_tasks() than expected.
This should be backported as far as 2.8.

2 weeks agoBUG/MEDIUM: leastconn: Unlock the write lock on allocation failure
Olivier Houchard [Mon, 1 Jun 2026 13:52:21 +0000 (15:52 +0200)] 
BUG/MEDIUM: leastconn: Unlock the write lock on allocation failure

When we fail to allocate a new tree element, we're still holding the
write lock, so we should do an write unlock, not a read unlock, or the
lock will get corrupted and most likely this will end in a deadlock.

This should be backported up to 3.2.

2 weeks agoBUG/MINOR: mux-spop: Fix possible off-by-one OOB read in spop_get_varint()
Christopher Faulet [Mon, 1 Jun 2026 13:25:32 +0000 (15:25 +0200)] 
BUG/MINOR: mux-spop: Fix possible off-by-one OOB read in spop_get_varint()

In spop_get_varint(), -1 is returned if there is not enough data in the
buffer to decode the variable integer. However a strict comparison agasint
b_data() was performed, which is wrong. A failure must be reported if the
index is greater or equal to b_data().

This patch must be backported as far as 3.2.

2 weeks agoBUG/MINOR: applet: Commit changes into input buffer after sending HTX data
Christopher Faulet [Mon, 1 Jun 2026 13:16:35 +0000 (15:16 +0200)] 
BUG/MINOR: applet: Commit changes into input buffer after sending HTX data

After sending HTX data to an applet, htx_to_buf() must be called on the
applet buffer to commit changes (and possibly to reset the buffer if it is
empty). This was performed on the output buffer while it should in fact be
performed on the input buffer. So let's fix it.

This patch must be backported as far as 3.0.

2 weeks agoBUG/MEDIUM: ssl: Make sure the alpn length is small enough
Olivier Houchard [Mon, 1 Jun 2026 13:04:09 +0000 (15:04 +0200)] 
BUG/MEDIUM: ssl: Make sure the alpn length is small enough

When the check for server hash was introduced to make sure we're using
the right alpn, the logic to store the new alpn was flawed. We should
always check that the new alpn length is small enough to fit in the
buffer, no matter if the server hash is not the same or not. So always
check the length first, and only check if the alpn or the server changed
after.
This should be backported whenever commit
de3f245df032073dec134f5d0f597d73a7b2575d has been backported.

2 weeks agoMINOR: debug: add -dA to dump an archive of all dependencies
Willy Tarreau [Fri, 29 May 2026 09:39:05 +0000 (11:39 +0200)] 
MINOR: debug: add -dA to dump an archive of all dependencies

This adds "-dA[file]" on the command line, which dumps an archive of all
dependencies detected at runtime into the designated file in tar format.
This is equivalent to "set-dumpable libs", but instead of keeping the libs
in memory, it dumps them into a file. This may be used after a core dump,
in order to provide all necessary libraries to developers to permit them
to exploit the core. This may not be available on all operating systems.

2 weeks agoMINOR: deinit: release the in-memory copy of shared libs
Willy Tarreau [Fri, 29 May 2026 09:20:12 +0000 (11:20 +0200)] 
MINOR: deinit: release the in-memory copy of shared libs

When shared libs were loaded via "set-dumpable libs", better release
them upon deinit, it will make valgrind happier. For this we now have
a new function free_collected_libs() in tools.c and call it in deinit().

2 weeks agoBUG/MEDIUM: htx: Fix headers rollback on partial copy in htx_xfer()
Christopher Faulet [Mon, 1 Jun 2026 07:45:32 +0000 (09:45 +0200)] 
BUG/MEDIUM: htx: Fix headers rollback on partial copy in htx_xfer()

In htx_xfer() function, when headers are partially copied, depending on the
flags, a rollback may be performed to remove all copied headers from the
destination message. However, there was an issue in the loop performing the
rollback. Instead of decrementing the returned value using the size of the
HTX block from the destination message, the one from the source message was
used. So the wrong value was be returned and in worst case, it could
overflow.

In addition, the BUG_ON() in the loop was removed because test condition was
wrong.

It is a 3.4-specific issue. No backport needed.

2 weeks agoBUG/MEDIUM: mux-h1: Dup connection/upgrade value to parse it when making headers
Christopher Faulet [Fri, 29 May 2026 14:26:29 +0000 (16:26 +0200)] 
BUG/MEDIUM: mux-h1: Dup connection/upgrade value to parse it when making headers

When message headers are formatted, the connection and upgrade header values
are parsed to be sanitized and to fill H1M flags. The values are modified in
place without changing the HTX message information accordingly (the block
info and the HTX info). It could be an issue if the output buffer is full
and the header cannot be formatted. Because the formatting can be stopped
with a HTX message in hazardous state.

It should be quite difficult to trigger this issue. But now, a copy of the
value is performed before parsing it. So only the copy will be altered,
leaving the HTX message in a safe state.

This patch must be backported to all stable versions.

2 weeks agoBUG/MINOR: cache: Fix copy of value when parsing maxage
Christopher Faulet [Fri, 29 May 2026 14:20:34 +0000 (16:20 +0200)] 
BUG/MINOR: cache: Fix copy of value when parsing maxage

During maxage parsing, the size of the value was not properly computed when
it was copied into the trash chunk. The name (max-age or s-maxage) must be
skipped with the '=' character. But instead of doing a subtraction, and
addition was performed, adding 2 extra bytes to the value used for the
convertion to integer.

In addition, the "chunk_memcat(chk, "", 1)" operation to add a trailing
NULL-byte was replaced by "*(b_tail(chk)) = '\0'". It a bit easier to
understand.

This patch should be backported to all stable versions.