]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
2 months agoBUG/MINOR: tools: only fill first empty arg when not out of range
Willy Tarreau [Wed, 7 May 2025 05:22:24 +0000 (07:22 +0200)] 
BUG/MINOR: tools: only fill first empty arg when not out of range

In commit 3f2c8af313 ("MINOR: tools: make parse_line() provide hints
about empty args") we've added the ability to record the position of
the first empty arg in parse_line(), but that check requires to
access the args[] array for the current arg, which is not valid in
case we stopped on too large an argument count. Let's just check the
arg's validity before doing so.

This was reported by OSS Fuzz:
  https://issues.oss-fuzz.com/issues/415850462

No backport is needed since this was in the latest dev branch.

2 months agoBUG/MINOR: ssl: can't use crt-store some certificates in ssl-f-use
William Lallemand [Tue, 6 May 2025 19:16:20 +0000 (21:16 +0200)] 
BUG/MINOR: ssl: can't use crt-store some certificates in ssl-f-use

When declaring a certificate via the crt-store section, this certificate
can then be used 2 ways in a crt-list:
- only by using its name, without any crt-store options
- or by using the exact set of crt-list option that was defined in the
  crt-store

Since ssl-f-use is generating a crt-list, this is suppose to behave the
same. To achieve this, ckch_conf_parse() will parse the keywords related
to the ckch_conf on the ssl-f-use line and use ckch_conf_cmp() to
compare it to the previous declaration from the crt-store. This
comparaison is only done when any ckch_conf keyword are present.

However, ckch_conf_parse() was done for the crt-list, and the crt-list
does not use the "crt" parameter to declare the name of the certificate,
since it's the first element of the line. So when used with ssl-f-use,
ckch_conf_parse() will always see a "crt" keyword which is a ckch_conf
one, and consider that it will always need to have the exact same set of
paremeters when using the same crt in a crt-store and an ssl-f-use line.

So a simple configuration like this:

   crt-store web
     load crt "foo.com.crt" key "foo.com.key" alias "foo"

   frontend mysite
     bind :443 ssl
     ssl-f-use crt "@web/foo" ssl-min-ver TLSv1.2

Would lead to an error like this:

    config : '@web/foo' in crt-list '(null)' line 0, is already defined with incompatible parameters:
    - different parameter 'key' : previously 'foo.com.key' vs '(null)'

In order to fix the issue, this patch parses the "crt" parameter itself
for ssl-f-use instead of using ckch_conf_parse(), so the keyword would
never be considered as a ckch_conf keyword to compare.

This patch also take care of setting the CKCH_CONF_SET_CRTLIST flag only
if a ckch_conf keyword was found. This flag is used by ckch_conf_cmp()
to know if it has to compare or not.

No backport needed.

2 months agoMINOR: ssl: add filename and linenum for ssl-f-use errors
William Lallemand [Tue, 6 May 2025 18:13:15 +0000 (20:13 +0200)] 
MINOR: ssl: add filename and linenum for ssl-f-use errors

Fill cfg_crt_node with a filename and linenum so the post_section
callback can use it to emit errors.

This way the errors are emitted with the right filename and linenum
where ssl-f-use is used instead of (null):0

2 months agoBUG/MAJOR: queue: lock around the call to pendconn_process_next_strm()
Willy Tarreau [Tue, 6 May 2025 16:55:04 +0000 (18:55 +0200)] 
BUG/MAJOR: queue: lock around the call to pendconn_process_next_strm()

The extra call to pendconn_process_next_strm() made in commit cda7275ef5
("MEDIUM: queue: Handle the race condition between queue and dequeue
differently") was performed after releasing the server queue's lock,
which is incompatible with the calling convention for this function.
The result is random corruption of the server's streams list likely
due to picking old or incorrect pendconns from the queue, and in the
end infinitely looping on apparently already locked mt_list objects.
Just adding the lock fixes the problem.

It's very difficult to reproduce, it requires low maxconn values on
servers, stickiness on the servers (cookie), a long enough slowstart
(e.g. 10s), and regularly flipping servers up/down to re-trigger the
slowstart.

No backport is needed as this was only in 3.2.

2 months agoDOC: configuration: add the "crt-store" keyword
William Lallemand [Tue, 6 May 2025 14:07:29 +0000 (16:07 +0200)] 
DOC: configuration: add the "crt-store" keyword

Add the "crt-store" keyword with its argument in the "3.12" section, so
this could be detected by haproxy-dconv has a keyword and put in the
keywords list.

Must be backported as far as 3.0

2 months agoDOC: configuration: add "acme" section to the keywords list
William Lallemand [Tue, 6 May 2025 13:34:39 +0000 (15:34 +0200)] 
DOC: configuration: add "acme" section to the keywords list

Add the "acme" keyword with its argument in the "3.13" section, so this
could be detected by haproxy-dconv has a keyword and put in the keywords
list.

2 months agoMEDIUM: acme/ssl: remove 'acme ps' in favor of 'acme status'
William Lallemand [Tue, 6 May 2025 13:20:05 +0000 (15:20 +0200)] 
MEDIUM: acme/ssl: remove 'acme ps' in favor of 'acme status'

Remove the 'acme ps' command which does not seem useful anymore with the
'acme status' command.

The big difference with the 'acme status' command is that it was only
displaying the running tasks instead of the status of all certificate.

2 months agoMINOR: acme/cli: 'acme status' show the status acme-configured certificates
William Lallemand [Tue, 6 May 2025 12:56:38 +0000 (14:56 +0200)] 
MINOR: acme/cli: 'acme status' show the status acme-configured certificates

The "acme status" command, shows the status of every certificates
configured with ACME, not only the running task like "acme ps".

The IO handler loops on the ckch_store tree and outputs a line for each
ckch_store which has an acme section set. This is still done under the
ckch_store lock and doesn't support resuming when the buffer is full,
but we need to change that in the future.

2 months agoRevert "BUG/MEDIUM: mux-spop: Handle CLOSING state and wait for AGENT DISCONNECT...
Christopher Faulet [Tue, 6 May 2025 11:43:59 +0000 (13:43 +0200)] 
Revert "BUG/MEDIUM: mux-spop: Handle CLOSING state and wait for AGENT DISCONNECT frame"

This reverts commit 53c3046898633e56f74f7f05fb38cabeea1c87a1.

This patch introduced a regression leading to a loop on the frames
demultiplexing because a frame may be ignore but not consumed.

But outside this regression that can be fixed, there is a design issue that
was not totally fixed by the patch above. The SPOP connection state is mixed
with the status of the frames demultiplexer and this needlessly complexify
the connection management. Instead of fixing the fix, a better solution is
to revert it to work a a proper solution.

For the record, the idea is to deal with the spop connection state onlu
using 'state' field and to introduce a new field to handle the frames
demultiplexer state. This should ease the closing state management.

Another issue that must be fixed. We must take care to not abort a SPOP
stream when an error is detected on a SPOP connection or when the connection
is closed, if the ACK frame was already received for this stream. It is not
a common case, but it can be solved by saving the last known stream ID that
recieved a ACK.

This patch must be backported if the commit above is backported.

2 months agoBUG/MINOR: proxy: only use proxy_inc_fe_cum_sess_ver_ctr() with frontends
Aurelien DARRAGON [Fri, 2 May 2025 17:06:44 +0000 (19:06 +0200)] 
BUG/MINOR: proxy: only use proxy_inc_fe_cum_sess_ver_ctr() with frontends

proxy_inc_fe_cum_sess_ver_ctr() was implemented in 9969adbc
("MINOR: stats: add by HTTP version cumulated number of sessions and
requests")

As its name suggests, it is meant to be called for frontends, not backends

Also, in 9969adbc, when used under h1_init(), a precaution is taken to
ensure that the function is only called with frontends.

However, this precaution was not applied in h2_init() and qc_init().

Due to this, it remains possible to have proxy_inc_fe_cum_sess_ver_ctr()
being called with a backend proxy as parameter. While it did not cause
known issues so far, it is not expected and could result in bugs in the
future. Better fix this by ensuring the function is only called with
frontends.

It may be backported up to 2.8

2 months agoDEBUG: threads: display held locks in threads dumps
Willy Tarreau [Tue, 6 May 2025 03:11:56 +0000 (05:11 +0200)] 
DEBUG: threads: display held locks in threads dumps

Based on the lock history, we can spot some locks that are still held
by checking the last operation that happened on them: if it's not an
unlock, then we know the lock is held. In this case we append the list
after "locked:" with their label and state like below:

  U:QUEUE S:IDLE_CONNS U:IDLE_CONNS R:TASK_WQ U:TASK_WQ S:QUEUE S:QUEUE S:QUEUE locked: QUEUE(S)
  S:IDLE_CONNS U:IDLE_CONNS S:TASK_RQ U:TASK_RQ S:QUEUE U:QUEUE S:IDLE_CONNS locked: IDLE_CONNS(S)
  R:TASK_WQ S:TASK_WQ R:TASK_WQ S:TASK_WQ R:TASK_WQ S:TASK_WQ R:TASK_WQ locked: TASK_WQ(R)
  W:STK_TABLE W:STK_TABLE_UPDT U:STK_TABLE_UPDT W:STK_TABLE W:STK_TABLE_UPDT U:STK_TABLE_UPDT W:STK_TABLE W:STK_TABLE_UPDT locked: STK_TABLE(W) STK_TABLE_UPDT(W)

The format is slightly different (label(status)) so as to easily
differentiate them visually from the history.

2 months agoDEBUG: threads: merge successive idempotent lock operations in history
Willy Tarreau [Mon, 5 May 2025 16:24:40 +0000 (18:24 +0200)] 
DEBUG: threads: merge successive idempotent lock operations in history

In order to make the lock history a bit more useful, let's try to merge
adjacent lock/unlock sequences that don't change anything for other
threads. For this we can replace the last unlock with the new operation
on the same label, and even just not store it if it was the same as the
one before the unlock, since in the end it's the same as if the unlock
had not been done.

Now loops that used to be filled with "R:LISTENER U:LISTENER" show more
useful info such as:

  S:IDLE_CONNS U:IDLE_CONNS S:PEER U:PEER S:IDLE_CONNS U:IDLE_CONNS R:LISTENER U:LISTENER
  U:STK_TABLE W:STK_SESS U:STK_SESS R:STK_TABLE U:STK_TABLE W:STK_SESS U:STK_SESS R:STK_TABLE
  R:STK_TABLE U:STK_TABLE W:STK_SESS U:STK_SESS W:STK_TABLE_UPDT U:STK_TABLE_UPDT S:PEER

It's worth noting that it can sometimes induce confusion when recursive
locks of the same label are used (a few exist on peers or stick-tables),
as in such a case the two operations would be needed. However these ones
are already undebuggable, so instead they will just have to be renamed
to make sure they use a distinct label.

2 months agoDEBUG: threads: don't keep lock label "OTHER" in the per-thread history
Willy Tarreau [Mon, 5 May 2025 16:10:57 +0000 (18:10 +0200)] 
DEBUG: threads: don't keep lock label "OTHER" in the per-thread history

Most threads are filled with "R:OTHER U:OTHER" in their history. Since
anything non-important can use other it's not observable but it pollutes
the history. Let's just drop OTHER entirely during the recording.

2 months agoBUG/MINOR: tools: make parseline report the required space for the trailing 0
Willy Tarreau [Mon, 5 May 2025 15:58:04 +0000 (17:58 +0200)] 
BUG/MINOR: tools: make parseline report the required space for the trailing 0

The fix in commit 09a325a4de ("BUG/MINOR: tools: always terminate empty
lines") is insufficient. While it properly addresses the lack of trailing
zero, it doesn't account for it in the returned outlen that is used to
allocate a larger line. This happens at boot if the very first line of
the test file is exactly a sharp with nothing else. In this case it will
return a length 0 and the caller (parse_cfg()) will try to re-allocate an
entry of size zero and will fail, bailing out a lack of memory. This time
it should really be OK.

It doesn't need to be backported, unless the patch above would be.

2 months agoBUG/MINOR: tools: always terminate empty lines
Willy Tarreau [Mon, 5 May 2025 15:33:22 +0000 (17:33 +0200)] 
BUG/MINOR: tools: always terminate empty lines

Since latest commit 7e4a2f39ef ("BUG/MINOR: tools: do not create an empty
arg from trailing spaces"), an empty line will no longer produce an arg
and no longer append a trailing zero to them. This was not visible because
one is already present in the input string, however all the trailing args
are set to out+outpos-1, which now points one char before the buffer since
nothing was emitted, and was noticed by ASAN, and/or when parsing garbage.
Let's make sure to always emit the zero for empty lines as well to address
this issue. No backport is needed unless the patch above gets backported.

2 months agoMINOR: cfgparse: visually show the input line on empty args
Willy Tarreau [Mon, 5 May 2025 14:13:33 +0000 (16:13 +0200)] 
MINOR: cfgparse: visually show the input line on empty args

Now when an empty arg is found on a line, we emit the sanitized
input line and the position of the first empty arg so as to help
the user figure the cause (likely an empty environment variable).

Co-authored-by: Valentine Krasnobaeva <vkrasnobaeva@haproxy.com>
2 months agoMINOR: tools: make parse_line() provide hints about empty args
Willy Tarreau [Mon, 5 May 2025 14:11:42 +0000 (16:11 +0200)] 
MINOR: tools: make parse_line() provide hints about empty args

In order to help parse_line() callers report the position of empty
args to the user, let's decide that if no error is emitted, then
we'll stuff the errptr with the position of the first empty arg
without affecting the return value.

Co-authored-by: Valentine Krasnobaeva <vkrasnobaeva@haproxy.com>
2 months agoMEDIUM: config: warn about the consequences of empty arguments on a config line
Willy Tarreau [Fri, 2 May 2025 13:47:41 +0000 (15:47 +0200)] 
MEDIUM: config: warn about the consequences of empty arguments on a config line

For historical reasons, the config parser relies on the trailing '\0'
to detect the end of the line being parsed. When the lines started to be
tokenized into arguments, this principle has been preserved, and now all
the parsers rely on *args[arg]='\0' to detect the end of a line. But as
reported in issue #2944, while most of the time it breaks the parsing
like below:

     http-request deny if { path_dir '' }

it can also cause some elements to be silently ignored like below:

     acl bad_path path_sub '%2E' '' '%2F'

This may also subtly happen with environment variables that don't exist
or which are empty:

     acl bad_path path_sub '%2E' "$BAD_PATTERN" '%2F'

Fortunately, parse_line() returns the number of arguments found, so it's
easy from the callers to verify if any was empty. The goal of this commit
is not to perform sensitive changes, it's only to mention when parsing a
line that an empty argument was found and alert about its consequences
using a warning. Most of the time when this happens, the config does not
parse. But for examples as the ACLs above, there could be consequences
that are better detected early.

This patch depends on this previous fix:
   BUG/MINOR: tools: do not create an empty arg from trailing spaces

Co-authored-by: Valentine Krasnobaeva <vkrasnobaeva@haproxy.com>
2 months agoBUG/MINOR: tools: do not create an empty arg from trailing spaces
Willy Tarreau [Fri, 2 May 2025 13:46:18 +0000 (15:46 +0200)] 
BUG/MINOR: tools: do not create an empty arg from trailing spaces

Trailing spaces on the lines of the config file create an empty arg
which makes it complicated to detect really empty args. Let's first
address this. Note that it is not user-visible but prevents from
fixing user-visible issues. No backport is needed.

The initial issue was introduced with this fix that already tried to
address it:

    8a6767d266 ("BUG/MINOR: config: don't count trailing spaces as empty arg (v2)")

The current patch properly addresses leading and trailing spaces by
only counting arguments if non-lws chars were found on the line. LWS
do not cause a transition to a new arg anymore but they complete the
current one. The whole new code relies on a state machine to detect
when to create an arg (!in_arg->in_arg), and when to close the current
arg. A special care was taken for word expansion in the form of
"${ARGS[*]}" which still continue to emit individual arguments past
the first LWS. This example works fine:

    ARGS="100 check inter 1000"
    server name 192.168.1."${ARGS[*]}"

It properly results in 6 args:

    "server", "name", "192.168.1.100", "check", "inter", "1000"

This fix should not have any visible user impact and is a bit tricky,
so it's best not to backport it, at least for a while.

Co-authored-by: Valentine Krasnobaeva <vkrasnobaeva@haproxy.com>
2 months agoBUG/MINOR: acme/cli: don't output error on success
William Lallemand [Fri, 2 May 2025 19:15:45 +0000 (21:15 +0200)] 
BUG/MINOR: acme/cli: don't output error on success

Previous patch 7251c13c7 ("MINOR: acme: move the acme task init in a dedicated
function") mistakenly returned the wrong error code when "acme renew" parsing
was successful, and tried to emit an error message.

This patch fixes the issue by returning 0 when the acme task was correctly
scheduled to start.

No backport needed.

2 months agoBUG/MEDIUM: stktable: fix sc_*(<ctr>) BUG_ON() regression with ctx > 9
Aurelien DARRAGON [Fri, 2 May 2025 14:25:57 +0000 (16:25 +0200)] 
BUG/MEDIUM: stktable: fix sc_*(<ctr>) BUG_ON() regression with ctx > 9

As reported in GH #2958, commit 6c9b315 caused a regression with sc_*
fetches and tracked counter id > 9.

As such, the below configuration would cause a BUG_ON() to be triggered:

  global
    log stdout format raw local0
    tune.stick-counters 11

  defaults
    log global
    mode http

  frontend www
    bind *:8080

    acl track_me bool(true)
    http-request set-var(txn.track_var) str("a")
    http-request track-sc10 var(txn.track_var) table rate_table if track_me
    http-request set-var(txn.track_var_rate) sc_gpc_rate(0,10,rate_table)
    http-request return status 200

  backend rate_table
      stick-table type string size 1k expire 5m store gpc_rate(1,1m)

While in 6c9b315 the src_fetch logic was removed from
smp_fetch_sc_stkctr(), num > 9 is indeed not expected anymore as
original num value. But what we didn't consider is that num is effectively
re-assigned for generic sc_* variant.

Thus the BUG_ON() is misplaced as it should only be evaluated for
non-generic fetches. It explains why it triggers with valid configurations

Thanks to GH user @tkjaer for his detailed report and bug analysis

No backport needed, this bug is specific to 3.2.

2 months ago[RELEASE] Released version 3.2-dev14 v3.2-dev14
Willy Tarreau [Fri, 2 May 2025 14:23:28 +0000 (16:23 +0200)] 
[RELEASE] Released version 3.2-dev14

Released version 3.2-dev14 with the following main changes :
    - MINOR: acme: retry label always do a request
    - MINOR: acme: does not leave task for next request
    - BUG/MINOR: acme: reinit the retries only at next request
    - MINOR: acme: change the default max retries to 5
    - MINOR: acme: allow a delay after a valid response
    - MINOR: acme: wait 5s before checking the challenges results
    - MINOR: acme: emit a log when starting
    - MINOR: acme: delay of 5s after the finalize
    - BUG/MEDIUM: quic: Let it be known if the tasklet has been released.
    - BUG/MAJOR: tasks: fix task accounting when killed
    - CLEANUP: tasks: use the local state, not t->state, to check for tasklets
    - DOC: acme: external account binding is not supported
    - MINOR: hlua: ignore "tune.lua.bool-sample-conversion" if set after "lua-load"
    - MEDIUM: peers: Give up if we fail to take locks in hot path
    - MEDIUM: stick-tables: defer adding updates to a tasklet
    - MEDIUM: stick-tables: Limit the number of old entries we remove
    - MEDIUM: stick-tables: Limit the number of entries we expire
    - MINOR: cfgparse-global: add explicit error messages in cfg_parse_global_env_opts
    - MINOR: ssl: add function to extract X509 notBefore date in time_t
    - BUILD: acme: need HAVE_ASN1_TIME_TO_TM
    - MINOR: acme: move the acme task init in a dedicated function
    - MEDIUM: acme: add a basic scheduler
    - MINOR: acme: emit a log when the scheduler can't start the task

2 months agoMINOR: acme: emit a log when the scheduler can't start the task
William Lallemand [Fri, 2 May 2025 14:12:41 +0000 (16:12 +0200)] 
MINOR: acme: emit a log when the scheduler can't start the task

Emit an error log when the renewal scheduler can't start the task.

2 months agoMEDIUM: acme: add a basic scheduler
William Lallemand [Fri, 2 May 2025 12:55:08 +0000 (14:55 +0200)] 
MEDIUM: acme: add a basic scheduler

This patch implements a very basic scheduler for the ACME tasks.

The scheduler is a task which is started from the postparser function
when at least one acme section was configured.

The scheduler will loop over the certificates in the ckchs_tree, and for
each certificate will start an ACME task if the notAfter date is past
curtime + (notAfter - notBefore) / 12, or 7 days if notBefore is not
available.

Once the lookup over all certificates is terminated, the task will sleep
and will wakeup after 12 hours.

2 months agoMINOR: acme: move the acme task init in a dedicated function
William Lallemand [Fri, 2 May 2025 12:47:03 +0000 (14:47 +0200)] 
MINOR: acme: move the acme task init in a dedicated function

acme_start_task() is a dedicated function which starts an acme task
for a specified <store> certificate.

The initialization code was move from the "acme renew" command parser to
this function, in order to be called from a scheduler.

2 months agoBUILD: acme: need HAVE_ASN1_TIME_TO_TM
William Lallemand [Fri, 2 May 2025 13:57:31 +0000 (15:57 +0200)] 
BUILD: acme: need HAVE_ASN1_TIME_TO_TM

Restrict the build of the ACME feature to libraries which provide
ASN1_TIME_to_tm() function.

2 months agoMINOR: ssl: add function to extract X509 notBefore date in time_t
William Lallemand [Fri, 2 May 2025 12:42:28 +0000 (14:42 +0200)] 
MINOR: ssl: add function to extract X509 notBefore date in time_t

Add x509_get_notbefore_time_t() which returns the notBefore date in
time_t format.

2 months agoMINOR: cfgparse-global: add explicit error messages in cfg_parse_global_env_opts
Valentine Krasnobaeva [Mon, 28 Apr 2025 21:00:17 +0000 (23:00 +0200)] 
MINOR: cfgparse-global: add explicit error messages in cfg_parse_global_env_opts

When env variable name or value are not provided for setenv/presetenv it's not
clear from the old error message shown at stderr, what exactly is missed. User
needs to search in it's configuration.

Let's add more explicit error messages about these inconsistencies.

No need to be backported.

2 months agoMEDIUM: stick-tables: Limit the number of entries we expire
Olivier Houchard [Fri, 2 May 2025 12:07:53 +0000 (12:07 +0000)] 
MEDIUM: stick-tables: Limit the number of entries we expire

In process_table_expire(), limit the number of entries we remove in one
call, and just reschedule the task if there's more to do. Removing
entries require to use the heavily contended update write lock, and we
don't want to hold it for too long.
This helps getting stick tables perform better under heavy load.

2 months agoMEDIUM: stick-tables: Limit the number of old entries we remove
Olivier Houchard [Fri, 2 May 2025 12:05:37 +0000 (12:05 +0000)] 
MEDIUM: stick-tables: Limit the number of old entries we remove

Limit the number of old entries we remove in one call of
stktable_trash_oldest(), as we do so while holding the heavily contended
update write lock, so we'd rather not hold it for too long.
This helps getting stick tables perform better under heavy load.

2 months agoMEDIUM: stick-tables: defer adding updates to a tasklet
Olivier Houchard [Fri, 2 May 2025 11:46:54 +0000 (11:46 +0000)] 
MEDIUM: stick-tables: defer adding updates to a tasklet

There is a lot of contention trying to add updates to the tree. So
instead of trying to add the updates to the tree right away, just add
them to a mt-list (with one mt-list per thread group, so that the
mt-list does not become the new point of contention that much), and
create a tasklet dedicated to adding updates to the tree, in batchs, to
avoid keeping the update lock for too long.
This helps getting stick tables perform better under heavy load.

2 months agoMEDIUM: peers: Give up if we fail to take locks in hot path
Olivier Houchard [Fri, 2 May 2025 11:29:05 +0000 (11:29 +0000)] 
MEDIUM: peers: Give up if we fail to take locks in hot path

In peer_send_msgs(), give up in order to retry later if we failed at
getting the update read lock.
Similarly, in __process_running_peer_sync(), give up and just reschedule
the task if we failed to get the peer lock. There is an heavy contention
on both those locks, so we could spend a lot of time trying to get them.
This helps getting peers perform better under heavy load.

2 months agoMINOR: hlua: ignore "tune.lua.bool-sample-conversion" if set after "lua-load"
Aurelien DARRAGON [Fri, 2 May 2025 11:56:08 +0000 (13:56 +0200)] 
MINOR: hlua: ignore "tune.lua.bool-sample-conversion" if set after "lua-load"

tune.lua.bool-sample-conversion must be set before any lua-load or
lua-load-per-thread is used for it to be considered. Indeed, lua-load
directives are parsed on the fly and will cause some parts of the scripts
to be executed during init already (script body/init contexts).

As such, we cannot afford to have "tune.lua.bool-sample-conversion" set
after some Lua code was loaded, because it would mean that the setting
would be handled differently for Lua's code executed during or after
config parsing.

To avoid ambiguities, the documentation now states that the setting must
be set before any lua-load(-per-thread) directive, and if the setting
is met after some Lua was already loaded, the directive is ignored and
a warning informs about that.

It should fix GH #2957

It may be backported with 29b6d8af16 ("MINOR: hlua: rename
"tune.lua.preserve-smp-bool" to "tune.lua.bool-sample-conversion"")

2 months agoDOC: acme: external account binding is not supported
William Lallemand [Fri, 2 May 2025 10:03:21 +0000 (12:03 +0200)] 
DOC: acme: external account binding is not supported

Add a note on external account binding in the ACME section.

2 months agoCLEANUP: tasks: use the local state, not t->state, to check for tasklets
Willy Tarreau [Fri, 2 May 2025 08:55:43 +0000 (10:55 +0200)] 
CLEANUP: tasks: use the local state, not t->state, to check for tasklets

There's no point reading t->state to check for a tasklet after we've
atomically read the state into the local "state" variable. Not only it's
more expensive, it's also less clear whether that state is supposed to
be atomic or not. And in any case, tasks and tasklets have their type
forever and the one reflected in state is correct and stable.

2 months agoBUG/MAJOR: tasks: fix task accounting when killed
Willy Tarreau [Fri, 2 May 2025 08:34:16 +0000 (10:34 +0200)] 
BUG/MAJOR: tasks: fix task accounting when killed

After recent commit b81c9390f ("MEDIUM: tasks: Mutualize the TASK_KILLED
code between tasks and tasklets"), the task accounting was no longer
correct for killed tasks due to the decrement of tasks in list that was
no longer done, resulting in infinite loops in process_runnable_tasks().
This just illustrates that this code remains complex and should be further
cleaned up. No backport is needed, as this was in 3.2.

2 months agoBUG/MEDIUM: quic: Let it be known if the tasklet has been released.
Olivier Houchard [Thu, 1 May 2025 12:39:39 +0000 (14:39 +0200)] 
BUG/MEDIUM: quic: Let it be known if the tasklet has been released.

quic_conn_release() may, or may not, free the tasklet associated with
the connection. So make it return 1 if it was, and 0 otherwise, so that
if it was called from the tasklet handler itself, the said handler can
act accordingly and return NULL if the tasklet was destroyed.
This should be backported if 9240cd4a2771245fae4d0d69ef025104b14bfc23
is backported.

2 months agoMINOR: acme: delay of 5s after the finalize
William Lallemand [Fri, 2 May 2025 08:34:48 +0000 (10:34 +0200)] 
MINOR: acme: delay of 5s after the finalize

Let 5 seconds by default to the server after the finalize to generate
the certificate. Some servers would not send a Retry-After during
processing.

2 months agoMINOR: acme: emit a log when starting
William Lallemand [Fri, 2 May 2025 08:23:42 +0000 (10:23 +0200)] 
MINOR: acme: emit a log when starting

Emit a administrative log when starting the ACME client for a
certificate.

2 months agoMINOR: acme: wait 5s before checking the challenges results
William Lallemand [Fri, 2 May 2025 08:18:24 +0000 (10:18 +0200)] 
MINOR: acme: wait 5s before checking the challenges results

Wait 5 seconds before trying to check if the challenges are ready, so it
let time to server to execute the challenges.

2 months agoMINOR: acme: allow a delay after a valid response
William Lallemand [Fri, 2 May 2025 08:16:12 +0000 (10:16 +0200)] 
MINOR: acme: allow a delay after a valid response

Use the retryafter value to set a delay before doing the next request
when the previous response was valid.

2 months agoMINOR: acme: change the default max retries to 5
William Lallemand [Fri, 2 May 2025 07:40:12 +0000 (09:40 +0200)] 
MINOR: acme: change the default max retries to 5

Change the default max retries constant to 5 instead of 3.
Some servers can be be a bit long to execute the challenge.

2 months agoBUG/MINOR: acme: reinit the retries only at next request
William Lallemand [Fri, 2 May 2025 07:27:15 +0000 (09:27 +0200)] 
BUG/MINOR: acme: reinit the retries only at next request

The retries were reinitialized incorrectly, it must be reinit only
when we didn't retry. So any valid response would reinit the retries
number.

2 months agoMINOR: acme: does not leave task for next request
William Lallemand [Fri, 2 May 2025 07:22:23 +0000 (09:22 +0200)] 
MINOR: acme: does not leave task for next request

The next request was always leaving the task befor initializing the
httpclient. This patch optimize it by jumping to the next step at the
end of the current one. This way, only the httpclient is doing a
task_wakeup() to handle the response. But transiting from response to
the next request does not leave the task.

2 months agoMINOR: acme: retry label always do a request
William Lallemand [Fri, 2 May 2025 07:15:07 +0000 (09:15 +0200)] 
MINOR: acme: retry label always do a request

Doing a retry always result in initializing a request again, set
ACME_HTTP_REQ directly in the label instead of doing it for each step.

2 months ago[RELEASE] Released version 3.2-dev13 v3.2-dev13
Willy Tarreau [Wed, 30 Apr 2025 16:25:28 +0000 (18:25 +0200)] 
[RELEASE] Released version 3.2-dev13

Released version 3.2-dev13 with the following main changes :
    - MEDIUM: checks: Make sure we return the tasklet from srv_chk_io_cb
    - MEDIUM: listener: Make sure w ereturn the tasklet from accept_queue_process
    - MEDIUM: mux_fcgi: Make sure we return the tasklet from fcgi_deferred_shut
    - MEDIUM: quic: Make sure we return the tasklet from qcc_io_cb
    - MEDIUM: quic: Make sure we return NULL in quic_conn_app_io_cb if needed
    - MEDIUM: quic: Make sure we return the tasklet from quic_accept_run
    - BUG/MAJOR: tasklets: Make sure he tasklet can't run twice
    - BUG/MAJOR: listeners: transfer connection accounting when switching listeners
    - MINOR: ssl/cli: add a '-t' option to 'show ssl sni'
    - DOC: config: fix ACME paragraph rendering issue
    - DOC: config: clarify log-forward "host" option
    - MINOR: promex: expose ST_I_PX_RATE (current_session_rate)
    - BUILD: acme: use my_strndup() instead of strndup()
    - BUILD: leastconn: fix build warning when building without threads on old machines
    - MINOR: threads: prepare DEBUG_THREAD to receive more values
    - MINOR: threads: turn the full lock debugging to DEBUG_THREAD=2
    - MEDIUM: threads: keep history of taken locks with DEBUG_THREAD > 0
    - MINOR: threads/cli: display the lock history on "show threads"
    - MEDIUM: thread: set DEBUG_THREAD to 1 by default
    - BUG/MINOR: ssl/acme: free EVP_PKEY upon error
    - MINOR: acme: separate the code generating private keys
    - MINOR: acme: failure when no directory is specified
    - MEDIUM: acme: generate the account file when not found
    - MEDIUM: acme: use 'crt-base' to load the account key
    - MINOR: compiler: add more macros to detect macro definitions
    - MINOR: cli: split APPCTX_CLI_ST1_PROMPT into two distinct flags
    - MEDIUM: cli: make the prompt mode configurable between n/i/p
    - MEDIUM: mcli: make the prompt mode configurable between i/p
    - MEDIUM: mcli: replicate the current mode when enterin the worker process
    - DOC: configuration: acme account key are auto generated
    - CLEANUP: acme: remove old TODO for account key
    - DOC: configuration: add quic4 to the ssl-f-use example
    - BUG/MINOR: acme: does not try to unlock after a failed trylock
    - BUG/MINOR: mux-h2: fix the offset of the pattern for the ping frame
    - MINOR: tcp: add support for setting TCP_NOTSENT_LOWAT on both sides
    - BUG/MINOR: acme: creating an account should not end the task
    - MINOR: quic: rename min/max fields for congestion window algo
    - MINOR: quic: refactor BBR API
    - BUG/MINOR: quic: ensure cwnd limits are always enforced
    - MINOR: thread: define cshared type
    - MINOR: quic: account for global congestion window
    - MEDIUM: quic: limit global Tx memory
    - MEDIUM: acme: use a map to store tokens and thumbprints
    - BUG/MINOR: acme: remove references to virt@acme
    - MINOR: applet: add appctx_schedule() macro
    - BUG/MINOR: dns: add tempo between 2 connection attempts for dns servers
    - CLEANUP: dns: remove unused dns_stream_server struct member
    - BUG/MINOR: dns: prevent ds accumulation within dss
    - CLEANUP: proxy: mention that px->conn_retries isn't relevant in some cases
    - DOC: ring: refer to newer RFC5424
    - MINOR: tools: make my_strndup() take a size_t len instead of and int
    - MINOR: Add "sigalg" to "sigalg name" helper function
    - MINOR: ssl: Add traces to ssl init/close functions
    - MINOR: ssl: Add traces to recv/send functions
    - MINOR: ssl: Add traces to ssl_sock_io_cb function
    - MINOR: ssl: Add traces around SSL_do_handshake call
    - MINOR: ssl: Add traces to verify callback
    - MINOR: ssl: Add ocsp stapling callback traces
    - MINOR: ssl: Add traces to the switchctx callback
    - MINOR: ssl: Add traces about sigalg extension parsing in clientHello callback
    - MINOR: Add 'conn' param to ssl_sock_chose_sni_ctx
    - BUG/MEDIUM: mux-spop: Wait end of handshake to declare a spop connection ready
    - BUG/MEDIUM: mux-spop: Handle CLOSING state and wait for AGENT DISCONNECT frame
    - BUG/MINOR: mux-h1: Don't pretend connection was released for TCP>H1>H2 upgrade
    - BUG/MINOR: mux-h1: Fix trace message in h1_detroy() to not relay on connection
    - BUILD: ssl: Fix wolfssl build
    - BUG/MINOR: mux-spop: Use the right bitwise operator in spop_ctl()
    - MEDIUM: mux-quic: increase flow-control on each bufsize
    - MINOR: mux-quic: limit emitted MSD frames count per qcs
    - MINOR: add hlua_yield_asap() helper
    - MINOR: hlua_fcn: enforce yield after *_get_stats() methods
    - DOC: config: restore default values for resolvers hold directive
    - MINOR: ssl/cli: "acme ps" shows the acme tasks
    - MINOR: acme: acme_ctx_destroy() returns upon NULL
    - MINOR: acme: use acme_ctx_destroy() upon error
    - MEDIUM: tasks: Mutualize code between tasks and tasklets.
    - MEDIUM: tasks: More code factorization
    - MEDIUM: tasks: Remove TASK_IN_LIST and use TASK_QUEUED instead.
    - MINOR: tasks: Remove unused tasklet_remove_from_tasklet_list
    - MEDIUM: tasks: Mutualize the TASK_KILLED code between tasks and tasklets
    - BUG/MEDIUM: connections: Report connection closing in conn_create_mux()
    - BUILD/MEDIUM: quic: Make sure we build with recent changes

2 months agoBUILD/MEDIUM: quic: Make sure we build with recent changes
Olivier Houchard [Wed, 30 Apr 2025 16:22:46 +0000 (18:22 +0200)] 
BUILD/MEDIUM: quic: Make sure we build with recent changes

TASK_IN_LIST has been changed to TASK_QUEUED, but one was missed in
quic_conn.c, so fix that.

2 months agoBUG/MEDIUM: connections: Report connection closing in conn_create_mux()
Olivier Houchard [Wed, 30 Apr 2025 11:19:38 +0000 (13:19 +0200)] 
BUG/MEDIUM: connections: Report connection closing in conn_create_mux()

Add an extra parametre to conn_create_mux(), "closed_connection".
If a pointer is provided, then let it know if the connection was closed.
Callers have no way to determine that otherwise, and we need to know
that, at least in ssl_sock_io_cb(), as if the connection was closed we
need to return NULL, as the tasklet was free'd, otherwise that can lead
to memory corruption and crashes.
This should be backported if 9240cd4a2771245fae4d0d69ef025104b14bfc23
is backported too.

2 months agoMEDIUM: tasks: Mutualize the TASK_KILLED code between tasks and tasklets
Olivier Houchard [Tue, 29 Apr 2025 13:46:20 +0000 (15:46 +0200)] 
MEDIUM: tasks: Mutualize the TASK_KILLED code between tasks and tasklets

The code to handle a task/tasklet when it's been killed before it were
to run is mostly identical, so move it outside of task and tasklet
specific code, and inside the common code.

This commit is just cosmetic, and should have no impact.

2 months agoMINOR: tasks: Remove unused tasklet_remove_from_tasklet_list
Olivier Houchard [Tue, 29 Apr 2025 13:25:53 +0000 (15:25 +0200)] 
MINOR: tasks: Remove unused tasklet_remove_from_tasklet_list

Remove tasklet_remove_from_tasklet_list, as the function hasn't been
used for a long time, and there is little reason to keep it.

2 months agoMEDIUM: tasks: Remove TASK_IN_LIST and use TASK_QUEUED instead.
Olivier Houchard [Tue, 29 Apr 2025 13:24:54 +0000 (15:24 +0200)] 
MEDIUM: tasks: Remove TASK_IN_LIST and use TASK_QUEUED instead.

TASK_QUEUED was used to mean "the task has been scheduled to run",
TASK_IN_LIST was used to mean "the tasklet has been scheduled to run",
remove TASK_IN_LIST and just use TASK_QUEUED for tasklets instead.

This commit is just cosmetic, and should not have any impact.

2 months agoMEDIUM: tasks: More code factorization
Olivier Houchard [Tue, 29 Apr 2025 13:15:27 +0000 (15:15 +0200)] 
MEDIUM: tasks: More code factorization

There is some code that should run no matter if the task was killed or
not, and was needlessly duplicated, so only use one instance.
This also fixes a small bug when a tasklet that got killed before it
could run would still count as a tasklet that ran, when it should not,
which just means that we'd run one less useful task before going back to
the poller.
This commit is mostly cosmetic, and should not have any impact.

2 months agoMEDIUM: tasks: Mutualize code between tasks and tasklets.
Olivier Houchard [Tue, 29 Apr 2025 13:15:01 +0000 (15:15 +0200)] 
MEDIUM: tasks: Mutualize code between tasks and tasklets.

The code that checks if we're currently running, and waits if so, was
identical between tasks and tasklets, so move it in code common to tasks
and tasklets.
This commit is just cosmetic, and should not have any impact.

2 months agoMINOR: acme: use acme_ctx_destroy() upon error
William Lallemand [Wed, 30 Apr 2025 15:18:46 +0000 (17:18 +0200)] 
MINOR: acme: use acme_ctx_destroy() upon error

Use acme_ctx_destroy() instead of a simple free() upon error in the
"acme renew" error handling.

It's better to use this function to be sure than everything has been
been freed.

2 months agoMINOR: acme: acme_ctx_destroy() returns upon NULL
William Lallemand [Wed, 30 Apr 2025 15:17:58 +0000 (17:17 +0200)] 
MINOR: acme: acme_ctx_destroy() returns upon NULL

acme_ctx_destroy() returns when its argument is NULL.

2 months agoMINOR: ssl/cli: "acme ps" shows the acme tasks
William Lallemand [Wed, 30 Apr 2025 13:49:53 +0000 (15:49 +0200)] 
MINOR: ssl/cli: "acme ps" shows the acme tasks

Implement a way to display the running acme tasks over the CLI.

It currently only displays a "Running" status with the certificate name
and the acme section from the configuration.

The displayed running tasks are limited to the size of a buffer for now,
it will require a backref list later to be called multiple times to
resume the list.

2 months agoDOC: config: restore default values for resolvers hold directive
Aurelien DARRAGON [Wed, 30 Apr 2025 14:56:00 +0000 (16:56 +0200)] 
DOC: config: restore default values for resolvers hold directive

Default values for hold directive (resolver context) used to be documented
but this was lost when the keyword description was reworked in 24b319b
("Default value is 10s for "valid", 0s for "obsolete" and 30s for
others.")

Restoring the part that describes the default value.

It may be backported to all stable versions with 24b319b

2 months agoMINOR: hlua_fcn: enforce yield after *_get_stats() methods
Aurelien DARRAGON [Wed, 30 Apr 2025 14:41:16 +0000 (16:41 +0200)] 
MINOR: hlua_fcn: enforce yield after *_get_stats() methods

{listener,proxy,server}_get_stats() methods are know to be expensive,
expecially if used under an iteration. Indeed, while automatic yield
is performed every X lua instructions (defaults to 10k), computing an
object's stats 10K times in a single cpu loop is not desirable and
could create contention.

In this patch we leverage hlua_yield_asap() at the end of *_get_stats()
methods in order to force the automatic yield to occur ASAP after the
method returns. Hopefully this should help in similar scenarios as the
one described in GH #2903

2 months agoMINOR: add hlua_yield_asap() helper
Aurelien DARRAGON [Wed, 30 Apr 2025 14:37:56 +0000 (16:37 +0200)] 
MINOR: add hlua_yield_asap() helper

When called, this function will try to enforce a yield (if available) as
soon as possible. Indeed, automatic yield is already enforced every X
Lua instructions. However, there may be some cases where we know after
running heavy operation that we should yield already to avoid taking too
much CPU at once.

This is what this function offers, instead of asking the user to manually
yield using "core.yield()" from Lua itself after using an expensive
Lua method offered by haproxy, we can directly enforce the yield without
the need to do it in the Lua script.

2 months agoMINOR: mux-quic: limit emitted MSD frames count per qcs
Amaury Denoyelle [Mon, 28 Apr 2025 13:36:44 +0000 (15:36 +0200)] 
MINOR: mux-quic: limit emitted MSD frames count per qcs

The previous commit has implemented a new calcul method for
MAX_STREAM_DATA frame emission. Now, a frame may be emitted as soon as a
buffer was consumed by a QCS instance.

This will probably increase the number of MAX_STREAM_DATA frame
emission. It may even cause a series of frame emitted for the same
stream with increasing values under high load, which is completely
unnecessary.

To improve this, limit the number of MAX_STREAM_DATA frames built to one
per QCS instance. This is implemented by storing a reference to this
frame in QCS structure via a new member <tx.msd_frm>.

Note that to properly reset QCS msd_frm member, emission of flow-control
frames have been changed. Now, each frame is emitted individually. On
one side, it is better as it prevent to emit frames related to different
streams in a single datagram, which is not desirable in case of packet
loss. However, this can also increase sendto() syscall invocation.

2 months agoMEDIUM: mux-quic: increase flow-control on each bufsize
Amaury Denoyelle [Wed, 19 Mar 2025 15:09:08 +0000 (16:09 +0100)] 
MEDIUM: mux-quic: increase flow-control on each bufsize

Recently, QCS Rx allocation buffer method has been improved. It is now
possible to allocate multiple buffers per QCS instances, which was
necessary to improve HTTP/3 POST throughput.

However, a limitation remained related to the emission of
MAX_STREAM_DATA. These frames are only emitted once at least half of the
receive capacity has been consumed by its QCS instance. This may be too
restrictive when a client need to upload a large payload.

Improve this by adjusting MAX_STREAM_DATA allocation. If QCS capacity is
still limited to 1 or 2 buffers max, the old calcul is still used. This
is necessary when user has limited upload throughput via their
configuration. If QCS capacity is more than 2 buffers, a new frame is
emitted if at least a buffer was consumed.

This patch has reduced number of STREAM_DATA_BLOCKED frames received in
POST tests with some specific clients.

2 months agoBUG/MINOR: mux-spop: Use the right bitwise operator in spop_ctl()
Christopher Faulet [Wed, 30 Apr 2025 13:58:53 +0000 (15:58 +0200)] 
BUG/MINOR: mux-spop: Use the right bitwise operator in spop_ctl()

Becaues of a typo, '||' was used instead of '|' to test the SPOP conneciton
flags and decide if the mux is ready or not. The regression was introduced
in the commit fd7ebf117 ("BUG/MEDIUM: mux-spop: Wait end of handshake to
declare a spop connection ready").

This patch must be backported to 3.1 with the commit above.

2 months agoBUILD: ssl: Fix wolfssl build
Remi Tricot-Le Breton [Wed, 30 Apr 2025 13:26:30 +0000 (15:26 +0200)] 
BUILD: ssl: Fix wolfssl build

The newly added SSL traces require an extra 'conn' parameter to
ssl_sock_chose_sni_ctx which was added in the "regular" code but not in
the wolfssl specific one.
Wolfssl also has a different prototype for some getter functions
(SSL_get_servername for instance), which do not expect a const SSL while
openssl version does.

2 months agoBUG/MINOR: mux-h1: Fix trace message in h1_detroy() to not relay on connection
Christopher Faulet [Wed, 30 Apr 2025 12:32:16 +0000 (14:32 +0200)] 
BUG/MINOR: mux-h1: Fix trace message in h1_detroy() to not relay on connection

h1_destroy() may be called to release a H1C after a multiplexer upgrade. In
that case, the connection is no longer attached to the H1C. It must not be
used in the h1 trace message because the connection context is no longer a H1C.

Because of this bug, when a H1>H2 upgrade is performed, a crash may be
experienced if the H1 traces are enabled.

This patch must be backport to all stable versions.

2 months agoBUG/MINOR: mux-h1: Don't pretend connection was released for TCP>H1>H2 upgrade
Christopher Faulet [Wed, 30 Apr 2025 12:16:42 +0000 (14:16 +0200)] 
BUG/MINOR: mux-h1: Don't pretend connection was released for TCP>H1>H2 upgrade

When an applicative upgrade of the H1 multiplexer is performed, we must not
pretend the connection was released.  Indeed, in that case, a H1 stream is
still their with a stream connector attached on it. It must be detached
first before releasing the H1 connection and the underlying connection. So
it is important to not pretend the connection was already released.

Concretely, in that case h1_process() must return 0 instead of -1. It is
minor error because, AFAIK, it is harmless. But it is not correct. So let's
fix it to avoid futur bugs.

To be clear, this happens when a TCP connection is upgraded to H1 connection
and a H2 preface is detected, leading to a second upgrade from H1 to H2.

This patch may be backport to all stable versions.

2 months agoBUG/MEDIUM: mux-spop: Handle CLOSING state and wait for AGENT DISCONNECT frame
Christopher Faulet [Mon, 28 Apr 2025 06:08:06 +0000 (08:08 +0200)] 
BUG/MEDIUM: mux-spop: Handle CLOSING state and wait for AGENT DISCONNECT frame

In the SPOE specification, when an error occurred on the SPOP connection,
HAProxy must send a DISCONNECT frame and wait for the agent DISCONNECT frame
in return before trully closing the connection.

However, this part was not properly handled by the SPOP multiplexer. In this
case, the SPOP connection should be in the CLOSING state. But this state was
not used at all. Depending on when the error was encountered, the connection
could be closed immediately, without sending any DISCONNECT frame. It was
the case when an early error was detected during the AGENT-HELLO frame
parsing. Or it could be moved from ERROR to FRAME_H state, as if no error
were detected. This case was less dramatic than it seemed because some flags
were also set to prevent any problem. But it was not obvious.

So now, the SPOP connection is properly switch to CLOSING state when an
DISCONNECT is sent to the agent to be able to wait for its DISCONNECT in
reply. spop_process_demux() was updated to parse frames in that state and
some validity checks was added.

This patch must be backport to 3.1.

2 months agoBUG/MEDIUM: mux-spop: Wait end of handshake to declare a spop connection ready
Christopher Faulet [Mon, 28 Apr 2025 06:01:40 +0000 (08:01 +0200)] 
BUG/MEDIUM: mux-spop: Wait end of handshake to declare a spop connection ready

A SPOP connection must not be considered as ready while the hello handshake
is not finished with success. In addition, no error or shutdown must have
been reported for the underlying connection. Otherwise a freshly openned
spop connexion may be reused while it is in fact dead, leading to a
connection retry.

This patch must be backported to 3.1.

2 months agoMINOR: Add 'conn' param to ssl_sock_chose_sni_ctx
Remi Tricot-Le Breton [Fri, 18 Apr 2025 15:26:58 +0000 (17:26 +0200)] 
MINOR: Add 'conn' param to ssl_sock_chose_sni_ctx

This is only useful in the traces, the conn parameter won't be used
otherwise.

2 months agoMINOR: ssl: Add traces about sigalg extension parsing in clientHello callback
Remi Tricot-Le Breton [Fri, 18 Apr 2025 15:26:57 +0000 (17:26 +0200)] 
MINOR: ssl: Add traces about sigalg extension parsing in clientHello callback

We had to parse the sigAlg extension by hand in order to properly select
the certificate used by the SSL frontends. These traces allow to dump
the allowed sigAlg list sent by the client in its clientHello.

2 months agoMINOR: ssl: Add traces to the switchctx callback
Remi Tricot-Le Breton [Fri, 18 Apr 2025 15:26:56 +0000 (17:26 +0200)] 
MINOR: ssl: Add traces to the switchctx callback

This callback allows to pick the used certificate on an SSL frontend.
The certificate selection is made according to the information sent by
the client in the clientHello. The traces that were added will allow to
better understand what certificate was chosen and why. It will also warn
us if the chosen certificate was the default one.
The actual certificate parsing happens in ssl_sock_chose_sni_ctx. It's
in this function that we actually get the filename of the certificate
used.

2 months agoMINOR: ssl: Add ocsp stapling callback traces
Remi Tricot-Le Breton [Fri, 18 Apr 2025 15:26:55 +0000 (17:26 +0200)] 
MINOR: ssl: Add ocsp stapling callback traces

If OCSP stapling fails because of a missing or invalid OCSP response we
used to silently disable stapling for the given session. We can now know
a bit more what happened regarding OCSP stapling.

2 months agoMINOR: ssl: Add traces to verify callback
Remi Tricot-Le Breton [Fri, 18 Apr 2025 15:26:54 +0000 (17:26 +0200)] 
MINOR: ssl: Add traces to verify callback

Those traces allow to know which errors were met during certificate
chain validation as well as which ones were ignored.

2 months agoMINOR: ssl: Add traces around SSL_do_handshake call
Remi Tricot-Le Breton [Fri, 18 Apr 2025 15:26:53 +0000 (17:26 +0200)] 
MINOR: ssl: Add traces around SSL_do_handshake call

Those traces dump information about the multiple SSL_do_handshake calls
(renegotiation and regular call). Some errors coud also be dumped in
case of rejected early data.
Depending on the chosen verbosity, some information about the current
handshake can be dumped as well (servername, tls version, chosen cipher
for instance).
In case of failed handshake, the error codes and messages will also be
dumped in the log to ease debugging.

2 months agoMINOR: ssl: Add traces to ssl_sock_io_cb function
Remi Tricot-Le Breton [Fri, 18 Apr 2025 15:26:52 +0000 (17:26 +0200)] 
MINOR: ssl: Add traces to ssl_sock_io_cb function

Add new SSL traces.

2 months agoMINOR: ssl: Add traces to recv/send functions
Remi Tricot-Le Breton [Fri, 18 Apr 2025 15:26:51 +0000 (17:26 +0200)] 
MINOR: ssl: Add traces to recv/send functions

Those traces will allow to identify sessions on which early data is used
as well as some forcefully closed connections.

2 months agoMINOR: ssl: Add traces to ssl init/close functions
Remi Tricot-Le Breton [Fri, 18 Apr 2025 15:26:50 +0000 (17:26 +0200)] 
MINOR: ssl: Add traces to ssl init/close functions

Add a dedicated trace for some unlikely allocation failures and async
errors. Those traces will ostly be used to identify the start and end of
a given SSL connection.

2 months agoMINOR: Add "sigalg" to "sigalg name" helper function
Remi Tricot-Le Breton [Fri, 18 Apr 2025 15:26:49 +0000 (17:26 +0200)] 
MINOR: Add "sigalg" to "sigalg name" helper function

This function can be used to convert a TLSv1.3 sigAlg entry (2bytes)
from the signature_agorithms client hello extension into a string.

In order to ease debugging, some TLSv1.2 combinations can also be
dumped. In TLSv1.2 those signature algorithms pairs were built out of a
one byte signature identifier combined to a one byte hash identifier.
In TLSv1.3 those identifiers are two bytes blocs that must be treated as
such.

2 months agoMINOR: tools: make my_strndup() take a size_t len instead of and int
Willy Tarreau [Wed, 30 Apr 2025 03:15:22 +0000 (05:15 +0200)] 
MINOR: tools: make my_strndup() take a size_t len instead of and int

In relation to issue #2954, it appears that turning some size_t length
calculations to the int that uses my_strndup() upsets coverity a bit.
Instead of dealing with such warnings each time, better address it at
the root. An inspection of all call places show that the size passed
there is always positive so we can safely use an unsigned type, and
size_t will always suit it like for strndup() where it's available.

2 months agoDOC: ring: refer to newer RFC5424
Lukas Tribus [Mon, 28 Apr 2025 12:07:31 +0000 (12:07 +0000)] 
DOC: ring: refer to newer RFC5424

In the ring configuration example we refer to RFC3164 - the original BSD
syslog protocol without support for structured data (SDATA).

Let's refer to RFC5424 instead so SDATA is by default forwarded if
someone copy & pastes from the documentation:

https://discourse.haproxy.org/t/structured-data-lost-when-forwarding-logs-voa-syslog-forwarding-feature/11741/5

Should be backported to 2.6.

2 months agoCLEANUP: proxy: mention that px->conn_retries isn't relevant in some cases
Aurelien DARRAGON [Mon, 28 Apr 2025 14:52:33 +0000 (16:52 +0200)] 
CLEANUP: proxy: mention that px->conn_retries isn't relevant in some cases

Since 91e785edc ("MINOR: stream: Rely on a per-stream max connection
retries value"), px->conn_retries may be ignored in the following cases:

 * proxy not part of a list which gets properly post-init (ie: main proxy
   list, log-forward list, sink list)
 * proxy lacking the CAP_FE capability

Documenting such cases where the px->conn_retries is set but effectively
ignored, so that we either remove ignored statements or fix them in
the future if they are really needed. In fact all cases affected here are
automomous applets that already handle the retries themselves so the fact
that 91e785edc made ->conn_retries ineffective should not be a big deal
anyway.

2 months agoBUG/MINOR: dns: prevent ds accumulation within dss
Aurelien DARRAGON [Tue, 29 Apr 2025 08:22:38 +0000 (10:22 +0200)] 
BUG/MINOR: dns: prevent ds accumulation within dss

when dns session callback (dns_session_release()) is called upon error
(ie: when some pending queries were not sent), we try our best to
re-create the applet in order to preserve the pending queries and give
them a chance to be retried. This is done at the end of
dns_session_release().

However, doing so exposes to an issue: if the error preventing queries
from being sent is still encountered over and over the dns session could
stay there indefinitely. Meanwhile, other dns sessions may be created on
the same dns_stream_server periodically. If previous failing dns sessions
don't terminate but we also keep creating new ones, we end up accumulating
failing sessions on a given dns_stream_server, which can eventually cause
ressource shortage.

This issue was found when trying to address ("BUG/MINOR: dns: add tempo
between 2 connection attempts for dns servers")

To fix it, we track the number of failed consecutive sessions for a given
dns server. When we reach the threshold (set to 100), we consider that the
link to the dns server is broken (at least temporarily) and we force
dns_session_new() to fail, so that we stop creating new sessions until one
of the existing one eventually succeeds.

A workaround for this fix consists in setting the "maxconn" parameter on
nameserver directive (under resolvers section) to a reasonnable value so
that no more than "maxconn" sessions may co-exist on the same server at
a given time.

This may be backported to all stable versions.
("CLEANUP: dns: remove unused dns_stream_server struct member") may be
backported to ease the backport.

2 months agoCLEANUP: dns: remove unused dns_stream_server struct member
Aurelien DARRAGON [Tue, 29 Apr 2025 14:48:28 +0000 (16:48 +0200)] 
CLEANUP: dns: remove unused dns_stream_server struct member

dns_stream_server "max_slots" is unused, let's get rid of it

2 months agoBUG/MINOR: dns: add tempo between 2 connection attempts for dns servers
Aurelien DARRAGON [Tue, 29 Apr 2025 18:13:00 +0000 (20:13 +0200)] 
BUG/MINOR: dns: add tempo between 2 connection attempts for dns servers

As reported by Lukas Tribus on the mailing list [1], trying to connect to
a nameserver with invalid network settings causes haproxy to retry a new
connection attempt immediately which eventually causes unexpected CPU usage
on the thread responsible for the applet (namely 100% on one CPU will be
observed).

This can be reproduced with the test config below:

 resolvers default
  nameserver ns1 tcp4@8.8.8.8:53 source 192.168.99.99
 listen listen
  mode http
  bind :8080
  server s1 www.google.com resolvers default init-addr none

To fix this the issue, we add a temporisation of one second between a new
connection attempt is retried. We do this in dns_session_create() when we
know that the applet was created in the release callback (when previous
query attempt was unsuccessful), which means initial connection is not
affected.

[1]: https://www.mail-archive.com/haproxy@formilux.org/msg45665.html

This should fix GH #2909 and may be backported to all stable versions.
This patch depends on ("MINOR: applet: add appctx_schedule() macro")

2 months agoMINOR: applet: add appctx_schedule() macro
Aurelien DARRAGON [Mon, 28 Apr 2025 16:03:36 +0000 (18:03 +0200)] 
MINOR: applet: add appctx_schedule() macro

Just like task_schedule() but for applets to wakeup an applet at a
specific time, leverages _task_schedule() internally

2 months agoBUG/MINOR: acme: remove references to virt@acme
William Lallemand [Tue, 29 Apr 2025 14:35:35 +0000 (16:35 +0200)] 
BUG/MINOR: acme: remove references to virt@acme

"virt@acme" was the default map used during development, now this must
be configured in the acme section or it won't try to use any map.

This patch removes the references to virt@acme in the comments and the
code.

2 months agoMEDIUM: acme: use a map to store tokens and thumbprints
William Lallemand [Tue, 29 Apr 2025 14:08:31 +0000 (16:08 +0200)] 
MEDIUM: acme: use a map to store tokens and thumbprints

The stateless mode which was documented previously in the ACME example
is not convenient for all use cases.

First, when HAProxy generates the account key itself, you wouldn't be
able to put the thumbprint in the configuration, so you will have to get
the thumbprint and then reload.
Second, in the case you are using multiple account key, there are
multiple thumbprint, and it's not easy to know which one you want to use
when responding to the challenger.

This patch allows to configure a map in the acme section, which will be
filled by the acme task with the token corresponding to the challenge,
as the key, and the thumbprint as the value. This way it's easy to reply
the right thumbprint.

Example:
    http-request return status 200 content-type text/plain lf-string "%[path,field(-1,/)].%[path,field(-1,/),map(virt@acme)]\n" if { path_beg '/.well-known/acme-challenge/' }

2 months agoMEDIUM: quic: limit global Tx memory
Amaury Denoyelle [Tue, 29 Apr 2025 09:39:42 +0000 (11:39 +0200)] 
MEDIUM: quic: limit global Tx memory

Define a new settings tune.quic.frontend.max-tot-window. It contains a
size argument which can be used to set a limit on the sum of all QUIC
connections congestion window. This is applied both on
quic_cc_path_set() and quic_cc_path_inc().

Note that this limitation cannot reduce a congestion window more than
the minimal limit which is set to 2 datagrams.

2 months agoMINOR: quic: account for global congestion window
Amaury Denoyelle [Mon, 28 Apr 2025 06:52:43 +0000 (08:52 +0200)] 
MINOR: quic: account for global congestion window

Use the newly defined cshared type to account for the sum of congestion
window of every QUIC connection. This value is stored in global counter
quic_mem_global defined in proto_quic module.

2 months agoMINOR: thread: define cshared type
Amaury Denoyelle [Fri, 25 Apr 2025 09:37:07 +0000 (11:37 +0200)] 
MINOR: thread: define cshared type

Define a new type "struct cshared". This can be used as a tool to
manipulate a global counter with thread-safety ensured. Each thread
would declare its thread-local cshared type, which would point to a
global counter.

Each thread can then add/substract value to their owned thread-local
cshared instance via cshared_add(). If the difference exceed a
configured limit, either positively or negatively, the global counter is
updated and thread-local instance is reset to 0. Each thread can safely
read the global counter value using cshared_read().

2 months agoBUG/MINOR: quic: ensure cwnd limits are always enforced
Amaury Denoyelle [Mon, 20 Jan 2025 15:24:21 +0000 (16:24 +0100)] 
BUG/MINOR: quic: ensure cwnd limits are always enforced

Congestion window is limit by a minimal and maximum values which can
never be exceeded. Min value is hardcoded to 2 datagrams as recommended
by the specification. Max value is specified via haproxy configuration.

These values must be respected each time the congestion window size is
adjusted. However, in some rare occasions, limit were not always
enforced. Fix this by implementing wrappers to set or increment the
congestion window. These functions ensure limits are always applied
after the operation.

Additionnally, wrappers also ensure that if window reached a new maximum
value, it is saved in <cwnd_last_max> field.

This should be backported up to 2.6, after a brief period of
observation.

2 months agoMINOR: quic: refactor BBR API
Amaury Denoyelle [Mon, 28 Apr 2025 07:22:37 +0000 (09:22 +0200)] 
MINOR: quic: refactor BBR API

Write minor adjustments to QUIC BBR functions. The objective is to
centralize every modification of path cwnd field.

No functional change. This patch will be useful to simplify
implementation of global QUIC Tx memory usage limitation.

2 months agoMINOR: quic: rename min/max fields for congestion window algo
Amaury Denoyelle [Thu, 23 Jan 2025 09:47:57 +0000 (10:47 +0100)] 
MINOR: quic: rename min/max fields for congestion window algo

There was some possible confusion between fields related to congestion
window size min and max limit which cannot be exceeded, and the maximum
value previously reached by the window.

Fix this by adopting a new naming scheme. Enforced limit are now renamed
<limit_max>/<limit_min>, while the previously reached max value is
renamed <cwnd_last_max>.

This should be backported up to 3.1.

2 months agoBUG/MINOR: acme: creating an account should not end the task
William Lallemand [Tue, 29 Apr 2025 12:09:46 +0000 (14:09 +0200)] 
BUG/MINOR: acme: creating an account should not end the task

The account creation was mistakenly ending the task instead of being
wakeup for the NewOrder state, it was preventing the creation of the
certificate, however the account was correctly created.

To fix this, only the jump to the end label need to be remove, the
standard leaving codepath of the function will allow to be wakeup.

No backport needed.

2 months agoMINOR: tcp: add support for setting TCP_NOTSENT_LOWAT on both sides
Willy Tarreau [Tue, 29 Apr 2025 09:43:46 +0000 (11:43 +0200)] 
MINOR: tcp: add support for setting TCP_NOTSENT_LOWAT on both sides

TCP_NOTSENT_LOWAT is very convenient as it indicates when to report
EAGAIN on the sending side. It takes a margin on top of the estimated
window, meaning that it's no longer needed to store too many data in
socket buffers. Instead there's just enough to fill the send window
and a little bit of margin to cover the scheduling time to restart
sending. Experiments on a 100ms network have shown a 10-fold reduction
in the memory used by socket buffers by just setting this value to
tune.bufsize, without noticing any performance degradation. Theoretically
the responsiveness on multiplexed protocols such as H2 should also be
improved.

2 months agoBUG/MINOR: mux-h2: fix the offset of the pattern for the ping frame
Willy Tarreau [Tue, 29 Apr 2025 10:05:08 +0000 (12:05 +0200)] 
BUG/MINOR: mux-h2: fix the offset of the pattern for the ping frame

The ping frame's pattern must be written at offset 9 (frame header
length), not 8. This was added in 3.2 with commit 4dcfe098a6 ("MINOR:
mux-h2: prepare to support PING emission"), so no backport is needed.

2 months agoBUG/MINOR: acme: does not try to unlock after a failed trylock
William Lallemand [Tue, 29 Apr 2025 09:29:52 +0000 (11:29 +0200)] 
BUG/MINOR: acme: does not try to unlock after a failed trylock

Return after a failed trylock in acme_update_certificate() instead of
jumping to the error label which does an unlock.

2 months agoDOC: configuration: add quic4 to the ssl-f-use example
William Lallemand [Tue, 29 Apr 2025 08:50:39 +0000 (10:50 +0200)] 
DOC: configuration: add quic4 to the ssl-f-use example

The ssl-f-use keyword is very useful in the case of multiple SSL bind
lines. Add a quic4 bind line in the example to show that.

2 months agoCLEANUP: acme: remove old TODO for account key
William Lallemand [Tue, 29 Apr 2025 07:59:32 +0000 (09:59 +0200)] 
CLEANUP: acme: remove old TODO for account key

Remove old TODO comments about the account key.

2 months agoDOC: configuration: acme account key are auto generated
William Lallemand [Tue, 29 Apr 2025 07:27:45 +0000 (09:27 +0200)] 
DOC: configuration: acme account key are auto generated

Explain that account key are auto generated when they do not exist.

2 months agoMEDIUM: mcli: replicate the current mode when enterin the worker process
Willy Tarreau [Mon, 28 Apr 2025 17:09:02 +0000 (19:09 +0200)] 
MEDIUM: mcli: replicate the current mode when enterin the worker process

While humans can find it convenient to enter the worker process in prompt
mode, for external tools it will not be convenient to have to systematically
disable it. A better approach is to replicate the master socket's mode
there, since it has already been configured to suit the user: interactive,
prompt and timed modes are automatically passed to the worker process.
This makes the using the worker commands more natural from the master
process, without having to systematically adapt it for each new connection.