]> git.kaiwu.me - haproxy.git/log
haproxy.git
5 weeks agoCLEANUP: cfgparse-global: move the log keywords to a single parser
Willy Tarreau [Wed, 7 Oct 2026 14:48:59 +0000 (16:48 +0200)]
CLEANUP: cfgparse-global: move the log keywords to a single parser

"log", "log-send-hostname" and "log-tag" are all related to the logging
setup, so they were moved together to a new cfg_parse_global_log_opts()
function and registered in cfg_kws so as to become discoverable via
"-dKcfg". The "log" keyword uses cfg_curr_kwm to detect "no log".

Like for previous commits, the result of the strdup() of the hostname
is now checked, and the duplicate hostname only emits a warning.

5 weeks agoCLEANUP: cfgparse-global: move "unix-bind" to its own parser
Willy Tarreau [Wed, 7 Oct 2026 14:44:49 +0000 (16:44 +0200)]
CLEANUP: cfgparse-global: move "unix-bind" to its own parser

The "unix-bind" keyword even had its own args loop in cfg_parse_global().
It's now registered in cfg_kws and parsed by cfg_parse_global_unix_bind(),
making it discoverable via "-dKcfg". The code was slightly restructured,
particularly the long chain of "if (...) { ...; continue; }" was simplified
a bit.

Like in a few previous patches, the duplicate test for "prefix" now just
emits a warning, and the result of strdup() is tested.

5 weeks agoCLEANUP: cfgparse-global: move "node" and "description" to their own parser
Willy Tarreau [Wed, 7 Oct 2026 14:41:09 +0000 (16:41 +0200)]
CLEANUP: cfgparse-global: move "node" and "description" to their own parser

Both keywords give an name/desc to the current node, so they were moved
together to a new cfg_parse_global_node_desc() function and registered in
cfg_kws so as to become discoverable via "-dKcfg".

While doing this, a test on strdup(node) result was added so as to fail
cleanly on memory allocation failure (this remains i nthe scope of a
cleanup since in practice it never happens).

5 weeks agoCLEANUP: cfgparse-global: move "ssl-server-verify" to its own parser
Willy Tarreau [Wed, 7 Oct 2026 14:35:56 +0000 (16:35 +0200)]
CLEANUP: cfgparse-global: move "ssl-server-verify" to its own parser

The keyword is now registered in cfg_kws and parsed by
cfg_parse_global_ssl_server_verify(), making it discoverable via
"-dKcfg".

5 weeks agoCLEANUP: cfgparse-global: move the compression limits to a single parser
Willy Tarreau [Wed, 7 Oct 2026 14:35:35 +0000 (16:35 +0200)]
CLEANUP: cfgparse-global: move the compression limits to a single parser

"maxcomprate", "maxzlibmem" and "maxcompcpuusage" all limit the resources
which may be dedicated to the compression, so they were moved together to
a new cfg_parse_global_comp_limits() function and registered in cfg_kws
so as to become discoverable via "-dKcfg".

5 weeks agoCLEANUP: cfgparse-global: move the process-wide limits to a single parser
Willy Tarreau [Wed, 7 Oct 2026 14:35:28 +0000 (16:35 +0200)]
CLEANUP: cfgparse-global: move the process-wide limits to a single parser

"maxconn", "maxconnrate", "maxpipes", "maxsessrate", "maxsslrate",
"fd-hard-limit" and "ulimit-n" all take a single integer argument, may
only be specified once and simply assign a field in the global struct,
so they were moved together to a new cfg_parse_global_limits() function
and registered in cfg_kws so as to become discoverable via "-dKcfg".

The arguments are now checked before the value is assigned rather than
after. The two non-fatal alerts ("already specified" and "maxconn too high")
are emitted directly via ha_warning() / ha_alert(). (Same as for previous
patch, "already specified" turned to a warning) since more appropriate.

5 weeks agoCLEANUP: cfgparse-global: move "cluster-secret" to its own parser
Willy Tarreau [Wed, 7 Oct 2026 14:28:20 +0000 (16:28 +0200)]
CLEANUP: cfgparse-global: move "cluster-secret" to its own parser

The keyword is now registered in cfg_kws and parsed by
cfg_parse_global_cluster_secret(), making it discoverable via "-dKcfg".
Note that using ha_alert() to warn about a repetition did not make much
sense since it didn't declare a fatal error, and since it doesn't prevent
from starting, it's better turned to a warning so that's what was done
here.

5 weeks agoCLEANUP: cfgparse-global: move "external-check" to its own parser
Willy Tarreau [Wed, 7 Oct 2026 14:24:32 +0000 (16:24 +0200)]
CLEANUP: cfgparse-global: move "external-check" to its own parser

The keyword is now registered in cfg_kws and parsed by
cfg_parse_global_external_check(), making it discoverable via "-dKcfg".

5 weeks agoCLEANUP: cfgparse-global: move "uid", "gid", "user" and "group" to its own parser
Willy Tarreau [Wed, 7 Oct 2026 14:22:30 +0000 (16:22 +0200)]
CLEANUP: cfgparse-global: move "uid", "gid", "user" and "group" to its own parser

These 4 keywords all end up setting global.{uid,gid}, either from a
number or by resolving a system user or group name, so they were moved
together to a new cfg_parse_global_uid_gid() function and registered in
cfg_kws so as to become discoverable via "-dKcfg". The parser continues
to use ha_alert() / ha_warning() since keyword parsers can normally only
return a single message (e.g. "statically built libc" could be emitted
before the rest).

5 weeks agoCLEANUP: cfgparse-global: move "set-dumpable" to its own parser
Willy Tarreau [Wed, 7 Oct 2026 14:18:55 +0000 (16:18 +0200)]
CLEANUP: cfgparse-global: move "set-dumpable" to its own parser

The keyword is now registered in cfg_kws and parsed by
cfg_parse_global_set_dumpable(), so that it becomes discoverable via
"-dKcfg". It relies on cfg_curr_kwm to detect the "no" modifier.

5 weeks agoCLEANUP: cfgparse-global: move the argument-less boolean options to a parser
Willy Tarreau [Wed, 7 Oct 2026 14:15:59 +0000 (16:15 +0200)]
CLEANUP: cfgparse-global: move the argument-less boolean options to a parser

The following keywords were still parsed in cfg_parse_global() and were
not discoverable via "-dKcfg": "busy-polling", "nosplice", "nogetaddrinfo",
"noreuseport", "numa-cpu-mapping", "quick-exit", "strict-limits",
"limited-quic", "insecure-fork-wanted", "insecure-setuid-wanted" and
"h2-workaround-bogus-websocket-clients". They all take no argument and
just set or clear a boolean, so they were moved to a single new parser,
cfg_parse_global_bool_opts(), and registered in cfg_kws. The ones which
support the "no" modifier now consult cfg_curr_kwm for this.

The check for extra args is now factored and the "no" support is checked
at the upper level.

5 weeks agoMINOR: cfgparse: expose the keyword modifier to the keyword parsers
Willy Tarreau [Wed, 7 Oct 2026 14:06:44 +0000 (16:06 +0200)]
MINOR: cfgparse: expose the keyword modifier to the keyword parsers

Section parsers receive the keyword modifier ("no" or "default") found in
front of the keyword as their last argument, but the keyword parsers which
are registered in a cfg_kw_list only receive the arguments, the file name
and the line number. As a consequence, a keyword supporting negation such
as "busy-polling" cannot be moved out of a section parser.

Let's just expose the modifier of the line being parsed in a new global
variable, cfg_curr_kwm, which is set for each new line in readcfgfile()
and reset once the file is completely parsed. This way the few keyword
parsers which are interested in it may consult it, the same way they
already consult "file" and "line".

5 weeks agoCLEANUP: proxy: adapt the error message for removed "option transparent"
Willy Tarreau [Fri, 9 Oct 2026 07:26:46 +0000 (09:26 +0200)]
CLEANUP: proxy: adapt the error message for removed "option transparent"

The keyword was removed by commit be8159248f ("MAJOR: proxy: remove
support for "dispatch" and "transparent" proxy keywords"), but the
warning message for deprecated "option transparent" wasn't removed
now that the option may no longer be found.

5 weeks agoBUG/MINOR: cfgparse-listen: complete the list of options for the suggestions
Willy Tarreau [Tue, 15 Sep 2026 14:37:58 +0000 (16:37 +0200)]
BUG/MINOR: cfgparse-listen: complete the list of options for the suggestions

The options which need a dedicated parsing are not described in the
cfg_opts* arrays, so they are listed in common_options[] in order to be
proposed as a suggestion when one of them is mistyped. That list was
incomplete and was missing "accept-invalid-http-request",
"accept-invalid-http-response", "forceclose",
"http-restrict-req-hdr-names", "http-tunnel", "http_proxy", "httpslog"
and "use-small-buffers", and it spelled "originalto" as "original-to",
so none of these ever got suggested:

  $ printf 'backend b\noption originalt\n' | ./haproxy -c -f /dev/stdin
  [ALERT] : parsing [/dev/stdin:2] : unknown option 'originalt'.

In addition "spop-check" was listed unconditionally while the option
only exists when SPOE is enabled, so a build spoe would propose it
but fail to recognize it:

  [ALERT] : unknown option 'spop-chek'; did you mean 'spop-check' maybe ?
  ...
  [ALERT] : unknown option 'spop-check'; did you mean 'tcp-check' maybe ?

The list is now sorted, complete and conditional where needed, and it
received a comment saying that it must be kept in sync with the options.

Note that the existing cfg_opts* already handle a few special cases like
disabled or obsolete options. Maybe we could extend it to also support
special options that are just not parsed there and must appear somewhere
else. This could even further simplify the parser by preserving PR_CAP_*
to let the main parser handle incompatibilities.

This may be backported to all supported versions.

5 weeks agoBUG/MINOR: proxy: also look for the closest option among cfg_opts3
Willy Tarreau [Tue, 15 Sep 2026 14:37:58 +0000 (16:37 +0200)]
BUG/MINOR: proxy: also look for the closest option among cfg_opts3

proxy_find_best_option() scans cfg_opts[] and cfg_opts2[] for the option
which looks closest to a mistyped one. When cfg_opts3[] was introduced
in 3.2 with commit cc5a66212d ("MINOR: proxy: add proxy->options3"), it
was not added there, so such newly added options are not proposed as
candidates for mistakes (e.g. "assume-rfc6587-ntf" or "dont-parse-log").
Let's just fix this.

This may be backported to 3.2.

5 weeks agoBUG/MINOR: cfgparse-listen: properly reject extra args in a backend section
Willy Tarreau [Tue, 15 Sep 2026 14:37:58 +0000 (16:37 +0200)]
BUG/MINOR: cfgparse-listen: properly reject extra args in a backend section

A proxy section only accepts "<keyword> <name> [from <defaults>]", and
anything else was reported as an alert suggesting to use the "bind"
keyword, but only for sections with the frontend capability. For the
others the block was left silently, without any message and without
creating the proxy nor opening a bacend section! As such any keyword
so that either the next line was a section keyword and it would restart
from there, or any other proxy keyword was rejected with "'listen' or
'defaults' expected". The only really silent case was when the section
is the last one, as it's silently dropped:

  $ printf 'defaults\nmode http\nbackend b junk\n' | ./haproxy -c -f /dev/stdin
  $ echo 0
  0

This patch fixes the error report (both message and err_code) for
backends. It moves the too many args check after the fe/be distinction
so that we don't mix the two messages and we can always emit a relevant
message for both fronts and backs.

Since the only case where such a config would have been accepted was
when an empty and invalid backend definition was placed at the end
immediately after a defaults section, there's no risk to break any
working config so this can safely be backported.

5 weeks agoBUG/MINOR: cfgparse-listen: don't lose the errors reported while creating a proxy
Willy Tarreau [Tue, 15 Sep 2026 14:37:58 +0000 (16:37 +0200)]
BUG/MINOR: cfgparse-listen: don't lose the errors reported while creating a proxy

When a proxy inherits from its defaults section, the return value of
proxy_ref_defaults() was assigned to err_code instead of being ORed
into it, wiping all the errors collected earlier for that line. As a
result an invalid character in a proxy's name was reported but the
process started anyway:

  $ cat inv.cfg
  defaults
      mode http
  frontend inv@lid
      bind :8080
  $ ./haproxy -c -f inv.cfg
  [ALERT] : parsing [inv.cfg:3] : character '@' is not permitted in
    'frontend' name 'inv@lid'.
  $ echo 0
  0

The same applies to the duplicate name and ambiguous defaults reference
diagnostics emitted before the proxy is created.

Configurations which were mistakenly accepted until will now be rejected,
though they were already emitting an alert. The issue was only introduced
in 3.4 with commit 87ea407cce ("MINOR: proxy: refactor proxy inheritance
of a defaults section"), so it's fairly unlikely that a bogus configuration
was introduced only there, thus a backport would be preferable, or maybe
only the err_code should be turned to ERR_WARN to remain tolerant for
existing versions.

5 weeks agoBUG/MINOR: cfgparse-listen: always reject extra arguments to "persist"
Willy Tarreau [Tue, 15 Sep 2026 14:37:58 +0000 (16:37 +0200)]
BUG/MINOR: cfgparse-listen: always reject extra arguments to "persist"

The check for extra arguments was placed inside the "if" block which
parses "persist rdp-cookie(<name>)", so "persist rdp-cookie foo" was
silently accepted. Let's move it to the beginning of the keyword's
processing so that it covers all the cases.

This must NOT be backported since it makes the config parser stricter.

5 weeks agoBUG/MINOR: cfgparse-global: reject extra arguments to numa-cpu-mapping and anonkey
Willy Tarreau [Tue, 15 Sep 2026 14:37:58 +0000 (16:37 +0200)]
BUG/MINOR: cfgparse-global: reject extra arguments to numa-cpu-mapping and anonkey

Both keywords silently ignored anything passed after their expected
argument, contrary to all the other keywords of the section which
properly check for extra args. Let's just fix this.

This must NOT be backported since it makes the config parser stricter.

5 weeks agoBUG/MINOR: cfgparse-listen: fix quoting of the condition conflict warning
Willy Tarreau [Tue, 15 Sep 2026 14:37:58 +0000 (16:37 +0200)]
BUG/MINOR: cfgparse-listen: fix quoting of the condition conflict warning

The 10 places which report the message returned by warnif_cond_conflicts()
use "'%s.\n'" as a format, so the closing quote is emitted after the \n and
ends up alone at the beginning of the next line:

  [WARNING] : parsing [x.cfg:4] : 'acl 'a' will never match ...
  '

Let's just move the quote before the LF and even the trailing '.'.

This may be backported to all supported versions.

5 weeks agoBUG/MINOR: cfgparse-listen: fix the argument checked by "email-alert"
Willy Tarreau [Tue, 15 Sep 2026 14:37:58 +0000 (16:37 +0200)]
BUG/MINOR: cfgparse-listen: fix the argument checked by "email-alert"

The "from", "mailers", "myhostname" and "to" options of "email-alert"
each check that a value was passed, but they test args[1], which is the
option's own name instead fo args[2]. As a consequence an empty args[2]
was accepted. The same copy-paste mistake made the "level" option error
handling report the option name instead of the wrong value.

This may be backported to all supported versions.

5 weeks agoBUG/MINOR: cfgparse-listen: release the previous description of the proxy
Willy Tarreau [Tue, 15 Sep 2026 14:37:58 +0000 (16:37 +0200)]
BUG/MINOR: cfgparse-listen: release the previous description of the proxy

The proxy's "description" keyword did not release the previous value
before assigning the new one, so the first one was leaked when the
keyword was used twice, e.g. once in a defaults section and once in the
proxy. Note that the global section's "description" does it properly.

This may be backported to all supported versions.

5 weeks agoBUG/MINOR: cfgparse-global: add missing calloc() check for the global description
Willy Tarreau [Tue, 15 Sep 2026 14:37:58 +0000 (16:37 +0200)]
BUG/MINOR: cfgparse-global: add missing calloc() check for the global description

The global "description" keyword passes the result of calloc() directly to
snprintf() without checking it, resulting in a crash instead of an error
message if the allocation fails.

This may be backported to all supported versions.

5 weeks agoBUG/MINOR: cfgparse-global: add missing gotos to error label in max-spread-checks
Willy Tarreau [Tue, 15 Sep 2026 14:37:58 +0000 (16:37 +0200)]
BUG/MINOR: cfgparse-global: add missing gotos to error label in max-spread-checks

The three error paths of the parse_time_err() call in the
"max-spread-checks" keyword only set the error code without leaving the
block, so that global.max_spread_checks was assigned an uninitialized
value right after the error was reported. No impact but clearly what
could report a build warning or a report from a static analyser. Let's
just add the missing gotos like everywhere else.

This may be backported to all supported versions.

5 weeks agoBUG/MAJOR: cfgparse: properly check userlist section when scanning keywords
Willy Tarreau [Fri, 9 Oct 2026 06:52:44 +0000 (08:52 +0200)]
BUG/MAJOR: cfgparse: properly check userlist section when scanning keywords

In cfg_parse_users(), we scan all config keywords and only want to
evaluate those whose section is CFG_USERLIST. However, the section
is checked as a bit field instead of an equality, and CFG_USERLIST
is 3, which is CFG_GLOBAL|CFG_LISTEN, meaning that we can call a
wrong parser for keywords "user" or "group" when they are registered
in one of these sections. This is what randomly happens when the
global "group" keyword is refactored to have its own parser, depending
on build options the linker, it may randomly be found before or after
the userlist's and cause startup failures if the global section's
keyword parser is called from the userlist parser, such as in this
regtest that only fails with ASAN on the CI when the config only has
"group" set in a userlist section:

  config : parsing [cfg:18] : cannot find group id for 'admins' (0:Success)

This was introduced in 3.4 with commit c17ed69bf3 ("MINOR: cfgparse:
Refactor "userlist" parser to print it in -dKall operation") so it must
be backported there.

If a config works it's OK, but this was still marked major because
there's simply no workaround for a failing binary where it only
depends on build options. It could happen for example if other
keywords are added via Lua or patches.

5 weeks agoBUG/MEDIUM: h3: fix incorrect DATA size block on DEM FULL
Amaury Denoyelle [Thu, 8 Oct 2026 17:24:20 +0000 (19:24 +0200)]
BUG/MEDIUM: h3: fix incorrect DATA size block on DEM FULL

The following patch fixes h3_data_to_htx() to ensure the correct value
is returned in case of buffer wrapper.

  bcdbc399d34f82a21c49162f203f2ff16b0aed79
  BUG/MEDIUM: h3: fix end-of-input report on DATA wrapping

However, this introduces a regression when HTX buffer is smaller than
the copied block. In this case, QCS is flagged with QC_SF_DEM_FULL, but
early goto skip the increment on <htx_sent> total value.

This causes corrupted transfers with H3 POST larger than a bufsize
resulting in a larger payload. This is caused by duplicated data blocks
when copy resumes after hitting QC_SF_DEM_FULL condition.

Fix this by ensuring <htx_sent> is always updated before the early goto
path. Intent of the above fix is kept as well as <ret> still serves as a
comparison for QC_SF_DEM_FULL / EOM cases.

This must be backported along the above patch, planned up to 2.6 (after
a period of observation).

5 weeks agoMINOR: doc: elaborate on diagnostic mode behavior
Lukas Tribus [Thu, 8 Oct 2026 17:16:21 +0000 (17:16 +0000)]
MINOR: doc: elaborate on diagnostic mode behavior

Commit 7b01a8dbdd("MINOR: global: define diagnostic mode of execution")
in 2.4-dev15 introduced diagnostic mode for config warnings.

It was initially designed to be ignored by "zero-warning" mode
(-dW) and documented accordingly.

Since commit ced4148401 ("BUG/MINOR: diag: always show the version
before dumping a diag warning") in 3.0-dev3 this changed, and
zero-warning mode combined with diagnostic messages stop haproxy from
starting. This appears to be a unintended consequence in ced4148401.

Since commit 7d63efa5f5 ("MINOR: errors: add ha_diag_notice() to
report diag-level notifications") there is a distinction between
what should not interact with zero-warning mode (ha_diag_notice()),
and the previous behavior with ha_diag_warning().

Explain the that some diagnostic message interact with zero-warning
and that diagnostic message will be backported, as such diagnostic
mode must only be used interactively.

Should be backported to stable trees.

Co-Authored-By: Willy Tarreau <w@1wt.eu>
5 weeks agoMEDIUM: h3: do not close conn on unaligned non DATA frame
Amaury Denoyelle [Thu, 8 Oct 2026 07:34:34 +0000 (09:34 +0200)]
MEDIUM: h3: do not close conn on unaligned non DATA frame

Until now, H3 parser rejected a non aligned frame, except for DATA. The
whole connection was closed with error H3_EXCESSIVE_LOAD, which can be
seen as a medium defect given that the client did not produce anything
invalid or even suspect.

In fact, most frame parsers are already able to support wrapping
content, as they deal with a struct buffer representation. This is also
the case for QPACK uni streams. The real limitation is for HEADERS frame
which rely on qpack_decode_fs() which can only work on aligned content.

This patch removes the connection closure on unaligned content. For H3
HEADERS frames, the buffer content is realigned by performing two
memmove() calls into a temporarily allocated alternative area. The
current parsing iteration will continue in this new aligned storage.

A future optimisation would be to support wrapping content in
qpack_decode_fs() to remove realign operation.

This can be considered as a bug, as previous state prevents to handle
valid H3 content. As no user complains about it, it may be better to
refrain from backporting the patch, unless there is some explicit demand
about it.

Note that original Rx buffer is not realigned, as this would mangle the
underlying MUX ncbuf storage. An alternative approach was implemented
first, performing the realign at the MUX level, however it was probably
less efficient as it required to copy the whole ncbuf. For the record,
this patch is attached here with its original message.

---
Subject: [PATCH] MEDIUM: quic/h3: support parsing of unaligned non DATA H3
 frame

Until now, H3 parser was not able to parse a non DATA frame which wraps
in QCS Rx buffer. When this happened, the whole connection was closed
with error H3_EXCESSIVE_LOAD, which can be seen as a medium defect given
that the client did not produce anything invalid or even suspect.

This patch finally implements a method to deal with unaligned non DATA
H3 frames. When such frame is detected by H3 parser, rcv_buf callback is
interrupted. MUX will react to a null returned value and detect that the
buffer data is wrapping. In this case, the new function
qcs_realign_rx_data() is used to perform the realign operation using
b_slow_realign() helper. Callback rcv_buf is then reinvoked immediately.

This can be considered as a bug, as previous state prevents to handle
valid H3 content. As no user complains about it, it may be better to
refrain from backporting the patch, unless there is some explicit demand
about it.
---
 src/h3.c       |  8 ++------
 src/mux_quic.c | 35 ++++++++++++++++++++++++++++++++---
 2 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/src/h3.c b/src/h3.c
index 4750ff69f..1ed4a4d8b 100644
--- a/src/h3.c
+++ b/src/h3.c
@@ -2068,13 +2068,9 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
  goto err;
  }

- /* TODO extend parser to support the realignment of a frame. */
  if (b_head(b) + b_data(b) > b_wrap(b)) {
- TRACE_ERROR("cannot parse unaligned data frame", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
- qcc_set_error(qcs->qcc, H3_ERR_EXCESSIVE_LOAD, 1,
-               muxc_tevt_type_other_err);
- qcc_report_glitch(qcs->qcc, 1);
- goto err;
+ TRACE_PROTO("pause parsing on unaligned payload", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
+ break;
  }

  /* Only parse full HTTP/3 frames. */
diff --git a/src/mux_quic.c b/src/mux_quic.c
index de443a568..70a6cad2d 100644
--- a/src/mux_quic.c
+++ b/src/mux_quic.c
@@ -1255,6 +1255,24 @@ static inline struct buffer qcs_b_dup(const struct qc_stream_rxbuf *b)
  }
 }

+/* Realign buffer content in <rxbuf>. This should be called when parsing is
+ * blocked due to wrapping content.
+ */
+static void qcs_realign_rx_data(struct qc_stream_rxbuf *rxbuf)
+{
+ struct ncbuf *ncb = &rxbuf->ncb;
+ struct buffer old;
+
+ /* Convert ncbuf to a full buffer type. This forces b_slow_realign()
+  * will copy every non contiguous blocks plus first ncb block header.
+  */
+ old = b_make(ncb_orig(ncb), ncb->size, ncb->head, ncb->size);
+ b_slow_realign(&old, trash.area, 0);
+
+ /* ncb area now realigned - ensure head is resetted as well. */
+ ncb->head = 0;
+}
+
 /* Transfer data into <qcs> stream <rxbuf> current Rx buffer from its directly
  * following buffer. This is useful when parsing was interrupted due to partial
  * data. If following buffer does not exists, nothing is done.
@@ -1508,9 +1526,20 @@ static int qcc_decode_qcs(struct qcc *qcc, struct qcs *qcs)
   * at a Rx buffer boundary. Try to realign data if possible and
   * restart decoding.
   */
- if (!ret && rxbuf && !(qcs->flags & QC_SF_DEM_FULL) &&
-     qcs->rx.offset + ncb_data(&rxbuf->ncb, 0) == rxbuf->off_end) {
- if (!qcs_transfer_rx_data(qcs, rxbuf)) {
+ if (!ret && rxbuf && !(qcs->flags & QC_SF_DEM_FULL)) {
+ int need_restart = 0;
+
+ if (ncb_head(&rxbuf->ncb) + ncb_data(&rxbuf->ncb, 0) > ncb_wrap(&rxbuf->ncb)) {
+ qcs_realign_rx_data(rxbuf);
+ need_restart = 1;
+ }
+
+ if (qcs->rx.offset + ncb_data(&rxbuf->ncb, 0) == rxbuf->off_end) {
+ if (!qcs_transfer_rx_data(qcs, rxbuf))
+ need_restart = 1;
+ }
+
+ if (need_restart) {
  TRACE_DEVEL("restart parsing after data realignment", QMUX_EV_QCS_RECV, qcc->conn, qcs);
  goto restart;
  }
--
2.56.0

5 weeks agoBUG/MEDIUM: h3: fix end-of-input report on DATA wrapping
Amaury Denoyelle [Wed, 7 Oct 2026 13:31:40 +0000 (15:31 +0200)]
BUG/MEDIUM: h3: fix end-of-input report on DATA wrapping

A received H3 DATA frame may wrap in the buffer. Function
h3_data_to_htx() will parse it in two pass in this case, calling
htx_add_data() twice.

A double bug was present in case of such parsing as second call of
htx_add_data() return value was immediately added in <htx_sent>. This
could cause first check to activate QC_SF_DEM_FULL to be ignored. This
is a minor issue, as MUX would immediately reinvoke h3_rcv_buf(), with
the flag set this time.

The second bug is more important : comparison for HTX EOM reporting was
invalid in case of a two pass parsing. Most of the time, this result in
EOM not reported, causing the stream layer to report a stream
interruption with state CL--.

Fix this by using an intermediary return value for the second
htx_add_data() invokation. This value is only added to <htx_sent> once
necessary checks are performed. It is important to keep h3_data_to_htx()
to still return the total value of HTX added data to avoid parser desync
issue.

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

5 weeks agoBUG/MINOR: ssl: Fix potential NULL-deref in "dump ssl cert" with AWS-LC
Remi Tricot-Le Breton [Mon, 5 Oct 2026 13:37:36 +0000 (15:37 +0200)]
BUG/MINOR: ssl: Fix potential NULL-deref in "dump ssl cert" with AWS-LC

In some corner cases we could have a public certificate with no private
key stored in a crt-store. In such a case, when trying to dump the
contents of the store entry via the "dump ssl cert" CLI command, the
'PEM_write_bio_PrivateKey' was always called without checking for a NULL
pointer.
This poses no problems with OpenSSL libraries which already check the
pointer but on some other libs, AWS-LC for instance, the NULL pointer is
dereferenced without check.
The only other use of this function is in acme code where the function
can never be called with a NULL 'key' pointer.

This patch can be backported up to 3.2.

5 weeks agoBUG/MEDIUM: mux_quic: notify stream on RESET_STREAM reception
Amaury Denoyelle [Tue, 29 Sep 2026 09:27:41 +0000 (11:27 +0200)]
BUG/MEDIUM: mux_quic: notify stream on RESET_STREAM reception

Always notify upper stream layer when a RESET_STREAM is received. This
is necessary as reset will be reported during rcv_buf callback.

Without this patch, reset won't be reported if stream is already
subscribed. This may result in a stream freeze, until its close on
timeout.

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

5 weeks agoBUG/MINOR: h3: reject RS/SS for QPACK uni streams
Amaury Denoyelle [Tue, 29 Sep 2026 10:05:41 +0000 (12:05 +0200)]
BUG/MINOR: h3: reject RS/SS for QPACK uni streams

A H3 peer must not close its qpack encoder/decoder stream. This is
already detected when a stream frame with FIN is received.

This patch extends the detection to RESET_STREAM frames. A similar error
H3_CLOSED_CRITICAL_STREAM is emitted.

This must be backported up to 2.8.

5 weeks agoBUG/MINOR: h3: close connection on GOAWAY frame too long
Amaury Denoyelle [Tue, 29 Sep 2026 09:48:54 +0000 (11:48 +0200)]
BUG/MINOR: h3: close connection on GOAWAY frame too long

GOAWAY frame contains a single stream ID varint. When decoding it,
ensure its length match the announced value in frame header. If not the
case, the connection must be closed with code FRAME_ERROR.

This must be backported up to 3.4.

5 weeks agoBUG/MINOR: h3: reject frames with truncated header
Amaury Denoyelle [Thu, 24 Sep 2026 16:06:02 +0000 (18:06 +0200)]
BUG/MINOR: h3: reject frames with truncated header

The following patch ensures that H3 frames with a truncated payload are
now properly rejected with H3_FRAME_ERROR.

  86a4ebc761a278838e8cb06f3a292282ba704c65
  BUG/MAJOR: h3: reject H3 truncated frames

However, this fix is not complete as it did not detect H3 frame
truncated at the header boundary. This happens when one of the two
fields varint cannot be decoded and FIN is reported as well.

This patch corrects this by reporting a connection error H3_FRAME_ERROR
in this condition. This allows to quickly teardown the connection
instead of waiting for the stream timeout without any error.

This must be backported to all stable releases.

5 weeks agoBUG/MINOR: mux_quic: account data in conn fctl on early detach
Amaury Denoyelle [Tue, 29 Sep 2026 14:39:17 +0000 (16:39 +0200)]
BUG/MINOR: mux_quic: account data in conn fctl on early detach

The previous patch accounts unconsumed data when QCS is freed before
being remotely closed. The objective is to ensure to limit the
inconsistency in conn flow control between client and server.

In fact, this patch is incomplete as peer consumed level cannot be known
before receiving its final size. Thus, discrepancies in connection flow
control may still appear over time. The proper method is to delay QCS
release until remote close is performed. However, this is a significant
change which will be implemented in a future patch.

This must be backported up to 2.8, after a period of observation

5 weeks agoBUG/MEDIUM: mux_quic: account discarded data in connection flow control
Amaury Denoyelle [Wed, 23 Sep 2026 13:34:28 +0000 (15:34 +0200)]
BUG/MEDIUM: mux_quic: account discarded data in connection flow control

Read data not yet consumed by the upper stream layer are discarded when
a RESET_STREAM is received. This patch implements their accounting in
the connection flow control.

This feature is mandatory as it could result in discrepancies between
each peers for the measured connection flow control. If this grows too
big, the sender may be indefinitely blocked, forcing the opening of a
new connection.

This patch introduces a new function qcc_account_conn_fctl(), which is
used to factorize the code already present during STREAM frames
handling. This is now also called for RESET_STREAM frames.

This must be backported up to 2.8, after a period of observation.

5 weeks agoBUG/MINOR: mux_quic: report conn error on RESET_STREAM fctl violation
Amaury Denoyelle [Wed, 23 Sep 2026 13:28:29 +0000 (15:28 +0200)]
BUG/MINOR: mux_quic: report conn error on RESET_STREAM fctl violation

When a RESET_STREAM is received, its announced final size must be taken
into account in the connection flow control.

This patch is a prerequisite prior to implement this accounting. It adds
the mandatory check of the final size field to ensure it does not
violate either the stream or the connection flow control.

In case of invalid value, the connection is closed with
FLOW_CONTROL_ERROR.

This must be backported up to 2.8, after a period of observation.

5 weeks agoBUG/MINOR: mux_quic: extend FINAL_SIZE_ERROR detection on stream
Amaury Denoyelle [Tue, 29 Sep 2026 09:49:13 +0000 (11:49 +0200)]
BUG/MINOR: mux_quic: extend FINAL_SIZE_ERROR detection on stream

On STREAM reception, a frame is rejected if final size is known but a
frame which exceeds it is received. Connection is closed with
FINAL_SIZE_ERROR code. This is also the case for a frame with FIN set
but shorter than the already received maximum offset.

This patch rewrites the condition so that the second check on frame with
FIN is always performed. Indeed, it does not depend on the known final
size status. A similar test is already performed as expected in the
RESET_STREAM frame handler.

This must be backported up to 2.6.

5 weeks agoBUG/MINOR: mux_quic: prevent purgeable QCS lingering
Amaury Denoyelle [Wed, 23 Sep 2026 12:31:37 +0000 (14:31 +0200)]
BUG/MINOR: mux_quic: prevent purgeable QCS lingering

Ensure QCC tasklet is woken up when a QCS is inserted in the purge list.
The objective is to prevent keeping QCS for too long in it.

Changes are only necessary when running outside of QCC tasklet. Thus new
wakeup are only inserted in receive handlers to avoid unnecessary
tasklet execution.

Prior to this patch, a purgeable QCS could have been kept virtually
indefinitely. This probably did not really happen as QCC tasklet is
frequently woken after frames handling.

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

5 weeks agoBUG/MAJOR: mux-quic: prevent crash on QCS already set for purging
Amaury Denoyelle [Mon, 5 Oct 2026 08:57:22 +0000 (10:57 +0200)]
BUG/MAJOR: mux-quic: prevent crash on QCS already set for purging

QCC connection has a purge list member. It contains QCS instances
considered as completed, whiches will be freed during the next tasklet
run. Such QCS are reported via qcs_is_completed() helper function.

QCS member <el_send> is used for purge list storage. It is also used for
send list, however an inactive QCS should not be present in the latter.
To enforce this rule, a BUG_ON() is present before purge list insertion
in qcs_close_remote(). This would also be triggered if QCS was already
inserted in the purge list before remote closing.

This BUG_ON() may be triggered when a QCS is scheduled for purge while
it still contains stom data to read. When the final read is performed,
crash will occur in qcs_close_remote(). This happens with detached QCS
only, as they are considered as completed even if only closed locally.

To prevent this situation, add an early return in qcs_close_remote() :
if QCS is already considered completed, do not change its state to fully
closed. As stated above, this only occur for detached QCS instances. The
main objective is to prevent the BUG_ON() crash while still preventing
double insert. As an added value, it guarantees that QCS state remains
constant once scheduled for purge.

Thanks to Brendon C. <bren@bren.win> for his detailled report on the
issue.

This must be backported up to 3.2, after a period of observation.

5 weeks agoMINOR: ssl: accept integer group IDs in curve2name
William Lallemand [Tue, 6 Oct 2026 13:26:21 +0000 (15:26 +0200)]
MINOR: ssl: accept integer group IDs in curve2name

Allow curve2name to convert integer TLS Supported Group identifiers
in addition to curve names. Register the converter with SMP_T_ANY to
preserve the input type, and accept only integer and string samples.

Return unknown IDs, or IDs without a name in the requested convention,
as decimal strings. Preserve the existing fallback for string inputs.

Document binary group extraction and extend regression coverage for
integer IDs, missing names, unknown IDs and values outside the TLS
identifier range. The build and converter regression test pass.

5 weeks agoMINOR: ssl: add curve2name converter
William Lallemand [Tue, 6 Oct 2026 12:59:43 +0000 (14:59 +0200)]
MINOR: ssl: add curve2name converter

Add a string converter to normalize curve names to IANA, ANSI X9.62
or NIST notation. Match both the requested format and input names
case-insensitively, and resolve old ecdh_* aliases to canonical names.

Keep the original string unchanged when no curve matches or the
requested naming convention has no corresponding name. The converter
uses the curve table independently of the SSL library's available NIDs.

Document the supported formats and add regression coverage for curve
aliases, mixed-case formats and unchanged-string fallbacks. The build
and all three SSL curve regression tests pass.

5 weeks agoMINOR: ssl: complete registered group names and library NID mappings
William Lallemand [Tue, 6 Oct 2026 12:41:52 +0000 (14:41 +0200)]
MINOR: ssl: complete registered group names and library NID mappings

Add the missing IANA groups for SM2, ML-KEM and hybrid key exchanges.
Provide both AWS-LC and OpenSSL NID spellings for standalone ML-KEM
and use AWS-LC NIDs for the supported hybrid and Kyber draft groups.
Undefined NID macros remain unavailable through the existing V macro.

The mappings were checked with OpenSSL 3.5, OpenSSL 4 development
headers and AWS-LC 4.2.

5 weeks agoMINOR: ssl: skip unavailable NIDs in curves2nid lookup
William Lallemand [Tue, 6 Oct 2026 12:22:22 +0000 (14:22 +0200)]
MINOR: ssl: skip unavailable NIDs in curves2nid lookup

Curve table entries with NIDs undefined by the SSL library remain at -1
after initialization. Skip these entries during name lookup so an
unavailable mapping does not hide a later valid mapping for the same
name. This allows the table to contain both OpenSSL and AWS-LC NID
spellings without conditional compilation.

5 weeks agoMINOR: ssl: split curve names into ANSI, IANA and NIST columns
William Lallemand [Tue, 6 Oct 2026 11:59:03 +0000 (13:59 +0200)]
MINOR: ssl: split curve names into ANSI, IANA and NIST columns

Store ANSI X9.62 aliases separately from IANA and NIST names,
consolidating the duplicate P-192 and P-256 entries. Make curves2nid()
search all three columns and keep curveid2str() returning the existing
TLS group name.

5 weeks agoBUG/MINOR: ssl: use standard names for X25519 and X448 groups
William Lallemand [Tue, 6 Oct 2026 11:51:45 +0000 (13:51 +0200)]
BUG/MINOR: ssl: use standard names for X25519 and X448 groups

The curve table uses ecdh_x25519 and ecdh_x448, which are OpenSSL TLS1.3
draft11 name labels rather than the released group names registered at
IANA. As a result, SSL traces print those labels and curves2nid() cannot
resolve x25519 or x448 even when the corresponding NID is available.

Use x25519 and x448 as the primary names. Keep the old ecdh_* strings
as aliases at the end of the table so existing name-to-NID lookups
continue to work. The aliases must follow the standard names because
curveid2str() returns the first entry matching a group identifier.

curveid2str() is only used in the traces so there's no fonctionnal
changes.

This should be backported to 3.3 and 3.4, which contain the curve table
introduced by d799a1b3b (MINOR: ssl: Add curve id to curve name table
and mapping functions).

5 weeks agoDOC: ssl: clarify the NID-based curve fetch branch
William Lallemand [Mon, 5 Oct 2026 16:27:55 +0000 (16:27 +0000)]
DOC: ssl: clarify the NID-based curve fetch branch

Document that the SSL_get_negotiated_group() path is used for OpenSSL
before 3.2 and AWS-LC API 35 or later. This only adds a comment and
does not change the fetch behavior.

5 weeks agoBUG/MINOR: ssl: don't uppercase the native group name
William Lallemand [Mon, 5 Oct 2026 16:21:29 +0000 (16:21 +0000)]
BUG/MINOR: ssl: don't uppercase the native group name

The change to SSL_get0_group_name() assumed that its output differed
from SSL_get_negotiated_group() followed by OBJ_nid2sn() only in
case. This is true for x25519/X25519 and x448/X448, but cannot be
generalized to other groups.

For P-256, the APIs return secp256r1 and prime256v1 respectively:
these are aliases, not a case difference. For P-384 and P-521, both
APIs already return secp384r1 and secp521r1, so uppercasing actually
introduces a mismatch. It also changes native mixed-case hybrid names
such as SecP256r1MLKEM768.

Moreover, SSL_get0_group_name() returns a library-owned string shared
through the SSL_CTX. Uppercasing it in place modifies OpenSSL state
and risks concurrent access to that string.

Remove the uppercase conversion and return the native name unchanged.

This should not be backported as it would could break matching of the
curves.

5 weeks agoBUG/MEDIUM: listener: Consider maxconn before waking listeners
Olivier Houchard [Tue, 6 Oct 2026 12:42:47 +0000 (14:42 +0200)]
BUG/MEDIUM: listener: Consider maxconn before waking listeners

When dequeueing listeners in dequeue_all_listeners() and
dequeue_proxy_listeners(), consider if we reached maxconn before doing
so.
If we do not, with enough thread groups, we may enter a state in which we
dequeue listeners, try again to accept more connections, but that would
fail, as maxconn would have been reached again by a different thread
group, and we'd end up being stuck for long enough for the watchdog to
trigger.

This should be backported up to 2.8.

This was submitted by Bruno Henc in github issue #3525.

5 weeks agoCI: github: move wolfSSL 5.7.0 testing to a nightly workflow
William Lallemand [Tue, 6 Oct 2026 10:28:00 +0000 (12:28 +0200)]
CI: github: move wolfSSL 5.7.0 testing to a nightly workflow

Remove wolfSSL 5.7.0 from the push-triggered VTest matrix. Update the
standalone wolfSSL workflow to test that version nightly instead of
building git-master weekly.

The weekly git-master worflow was not working anymore for months.

5 weeks agoCI: github: cache QuicTLS builds
William Lallemand [Tue, 6 Oct 2026 09:22:26 +0000 (11:22 +0200)]
CI: github: cache QuicTLS builds

Resolve the QuicTLS ref to a commit SHA when generating the VTest
matrix and include it in the SSL build inputs and cache key. Keep job
labels readable by showing the ref and an eight-character SHA.

Fetch and check out the resolved commit in build-ssl.sh while retaining
QUICTLS_VERSION for the OpenSSL 1.1.1 build target selection. Preserve
the existing download behavior when QUICTLS_COMMIT is unset.

Enable SSL caching for QuicTLS.

5 weeks agoCI: github: test the latest AWS-LC release on development branches
William Lallemand [Tue, 6 Oct 2026 08:41:30 +0000 (10:41 +0200)]
CI: github: test the latest AWS-LC release on development branches

Replace the AWS-LC 1.39.0 pin with latest-release discovery using the
existing determine_latest_aws_lc() helper. Add it alongside the other
latest SSL libraries in the development-only matrix list.

Remove the separate AWS-LC workflow now that the VTest matrix covers
the latest release and both LTS branches.

5 weeks agoCI: github: test AWS-LC 3.x and 4.x LTS branches
William Lallemand [Tue, 6 Oct 2026 08:35:28 +0000 (10:35 +0200)]
CI: github: test AWS-LC 3.x and 4.x LTS branches

Add the fips-2024-09-27 (3.x) and fips-2025-09-12-lts (4.x) AWS-LC
branches to the VTest matrix for GCC and Clang, including QUIC support.

Resolve each branch head to a commit SHA when generating the matrix
and download the corresponding immutable archive in build-ssl.sh.
Read the AWS-LC version from that commit's header to display readable
job names such as ssl=aws_lc=4.2.0+37341efe.

Generate the SSL cache key from both the job name and SSL source,
retaining the full commit SHA even though the display uses only eight
characters. Builds are reused until the branch advances, and distinct
commits cannot share a cache entry because of a short SHA collision.

Validated branch resolution and version extraction against GitHub,
readable GCC and Clang jobs in development and stable matrices, commit
and tag archive URLs, cache reuse, shell syntax, and git diff --check.

5 weeks agoBUG/MEDIUM: ssl: crt-list curves ignored with AWS-LC
Frederic Lecaille [Tue, 6 Oct 2026 07:59:44 +0000 (09:59 +0200)]
BUG/MEDIUM: ssl: crt-list curves ignored with AWS-LC

SSL_new() copies the curves of the SSL_CTX into the SSL object, and
SSL_set_SSL_CTX() does not update this copy while the handshake uses it.
The "curves" and "ecdhe" options of a crt-list line were thus silently
ignored: a client could negotiate a curve excluded by the certificate as
long as the bind line allowed it.

The ClientHello callback used by AWS-LC now sets them again on the SSL
object after the context switch. The value is picked in the same order
as when the SSL_CTX is prepared, so the curves of the bind line still
win over the <ecdhe> of the crt-list line.

The curves setter is inefficient here: it parses the configuration
string for each connection.

This adds the ssl_crt-list_curves reg-tests for TCP and QUIC.

Tested with AWS-LC 3.6.0 (LTS) and 4.2.0. The curves regression tests
pass over TCP and QUIC with both versions.
The TLSv1.2, TLSv1.3 and QUIC cipher regression tests also pass.

Thank you to @ygkat for having reported this issue in GH #3500

This should be backported to all stable versions. Note the code is in
ssl_sock.c before 3.1.

Co-authored-by: William Lallemand <wlallemand@haproxy.com>
5 weeks agoBUG/MEDIUM: ssl: crt-list ciphers ignored with AWS-LC
Frederic Lecaille [Tue, 6 Oct 2026 07:46:11 +0000 (09:46 +0200)]
BUG/MEDIUM: ssl: crt-list ciphers ignored with AWS-LC

AWS-LC's SSL_new() copies the cipher lists of the SSL_CTX into the SSL
object, and SSL_set_SSL_CTX() does not update this copy while the server
handshake uses it. The "ciphers" and "ciphersuites" options of a
crt-list line were thus silently ignored: a client could negotiate a cipher
excluded by the certificate as long as the bind line allowed it. The same
configuration built against OpenSSL rejects such a connection.

The SNI callback now sets both lists again on the SSL object after the
context switch when built with AWS-LC API versions greater than 30.
API version 30 (AWS-LC 3.x) uses the selected SSL_CTX cipher lists
directly and does not need this workaround.

These setters are inefficient here: they parse the cipher configuration
strings for each connection.

This adds the ssl_crt-list_ciphers reg-test for TLSv1.2 and the
ssl_crt-list_ciphersuites ones for TLSv1.3, over TCP and QUIC.

Tested with AWS-LC LTS versions 3.6.0 and 4.2.0.

Thank you to @ygkat for having reported this issue in GH #3500

This should be backported as far as 3.0. Note the code is in ssl_sock.c
before 3.1.

Co-authored-by: William Lallemand <wlallemand@haproxy.com>
5 weeks agoBUG/MINOR: ssl: fix trace crash on BE conn release in io cb
Amaury Denoyelle [Tue, 6 Oct 2026 07:45:37 +0000 (09:45 +0200)]
BUG/MINOR: ssl: fix trace crash on BE conn release in io cb

Since 3.3, handling of idle connections in io handler for muxes/SSL has
been extended. On io completion, connection is not reinserted anymore in
the server list if it is in maintenance mode. Also, private connections
are need race protection as they may be purged : on completion, a
connection is reinserted in its parent session. This operation is
failible as it may require an allocation.

In SSL io tasklet, if a BE connection is not reinserted in its idle pool
for one of the two reasons described above, it is freed instead via MUX
destroy callback. This causes a crash if traces are activated as conn
pointer is not updated.

Fix this by ensuring conn pointer is set to NULL after destroy
invokation.

This must be backported up to 3.3.

5 weeks agoBUG/MINOR: ssl: fix trace crash on FE conn release in io cb
Amaury Denoyelle [Mon, 5 Oct 2026 15:42:18 +0000 (17:42 +0200)]
BUG/MINOR: ssl: fix trace crash on FE conn release in io cb

The following patch has added an output parameter in conn_create_mux()
to report if the connection has been destroyed. This can happen for
frontend connection only.

In case the connection is destroyed, tasklet is set to NULL as expected
to avoid returning an invalid pointer. However, conn pointer is left
unchanged. This leads to a crash if traces are activated. The proper fix
is to also set conn to NULL.

This must be backported up to 3.2.

5 weeks agoBUG/MINOR: hq-interop: prevent double EOM on request with standalone FIN
Amaury Denoyelle [Tue, 6 Oct 2026 08:37:06 +0000 (10:37 +0200)]
BUG/MINOR: hq-interop: prevent double EOM on request with standalone FIN

Previously, HTX EOM was unconditionnaly set during HTTP/0.9 to HTX
request conversion. This was valid as content was only parsed when all
STREAM were received.

However, this has changed in 3.2 with support for incomplete request and
standalone FIN in HTTP/0.9 parser. The objective is to better test a
mechanism close to HTTP/3 parser. But unconditionnal EOM was not
adjusted. Thus, EOM would be set two times per message if FIN is
transmitted via a dedicated empty STREAM frame.

Previously, this was silently ignored by stream layer. However, this is
not case anymore since conversion of HTX EOM from a message level to a
block level flag. A new BUG_ON() added in htx_add_blk() would report
incorrect blocks found after EOM : this may be triggered in case the
second EOM is reported through an EOT block.

Fix this only setting EOM if fin is set during HTTP/0.9 request parsing.
Handling of standalone FIN is already supported here so there is no need
for more changes. Now, HTTP/0.9 parser can now considered even more
closer to HTTP/3.

This should be backported up to 3.2.

5 weeks agoDEBUG: support reading set-dumpable from HAPROXY_FORCE_DUMPABLE
Willy Tarreau [Tue, 6 Oct 2026 08:10:02 +0000 (10:10 +0200)]
DEBUG: support reading set-dumpable from HAPROXY_FORCE_DUMPABLE

When debugging regtests, it is super complicated to get a core to be
dumped. It often requires to place a set-dumpable directive in the
config, but when it's generated it's really not convenient. A better
approach in this case is to read the value from an environment variable.

That's what this patch does, by accepting to preset the set-dumpable
options from the contents of HAPROXY_FORCE_DUMPABLE. It's a bit more
relaxed, though, as it accepts "off" to stay disabled, "libs" to just
load the libs, and anything else to enable.

The config and management docs were updated. This could be backported
to older versions if found helpful.

5 weeks agoBUILD: ssl: avoid mixed declarations in the AWS-LC curve fetch
William Lallemand [Mon, 5 Oct 2026 13:04:29 +0000 (13:04 +0000)]
BUILD: ssl: avoid mixed declarations in the AWS-LC curve fetch

The AWS-LC API 30-34 curve fetch declares the group variable after
statements, which fails builds using -Werror=declaration-after-statement.

Move the declaration to the beginning of smp_fetch_ssl_fc_ec() and keep
the assignment in the AWS-LC branch. Mark the variable __maybe_unused
for builds using other SSL libraries.

This fix must be backported wherever commit e671cb696d ("MINOR: ssl:
support curve fetches with AWS-LC API 30") was backported.

5 weeks agoMINOR: ssl: support curve fetches with AWS-LC API 30
William Lallemand [Mon, 5 Oct 2026 12:45:35 +0000 (14:45 +0200)]
MINOR: ssl: support curve fetches with AWS-LC API 30

Enable ssl_fc_curve and ssl_bc_curve with AWS-LC API 30-34, including
AWS-LC 3.0.0, using SSL_get_group_id() and SSL_get_group_name() instead
of SSL_get_negotiated_group(), which requires API 35.

Map NIST curve group IDs to OpenSSL short names to keep the output
consistent with newer AWS-LC versions. Preserve native names for other
groups, including post-quantum and hybrid groups.

Update the compatibility documentation and enable the curve regression
tests for AWS-LC API 30.

5 weeks agoDOC: config: document new "loggers" section and relevant uses
Aurelien DARRAGON [Fri, 2 Oct 2026 13:56:03 +0000 (15:56 +0200)]
DOC: config: document new "loggers" section and relevant uses

loggers (plural) section may be used to defined a group of log
directives within a single section that can be used later in the
config as a replacement of "log" directive to specify log target(s),
for instance in a proxy section to inherit from existing loggers or
directly on a do-log action to send generated log to specific endpoints
only.

5 weeks agoMINOR: log: support 'to' parameter fo do-log action
Aurelien DARRAGON [Fri, 2 Oct 2026 07:15:32 +0000 (09:15 +0200)]
MINOR: log: support 'to' parameter fo do-log action

Similar to the "to" argument for "log" directive, the optional "to"
parameter allows to specify a list of comma separater loggers section
names to be used as log destination for the logs produce by the do-log
action.

However, while the "to" argument from "log" directive adds up loggers
to existing loggers of the proxy, the do-log "to" argument actually
replaces the loggers configured on the proxy! Indeed, the ultimate
goal is to be able to filter which loggers sections should receive
do-log logs, which by default are sent to all loggers from the proxy.

5 weeks agoMINOR: log: support explicit <loggers> list for do_log_ctx()
Aurelien DARRAGON [Fri, 2 Oct 2026 09:10:03 +0000 (11:10 +0200)]
MINOR: log: support explicit <loggers> list for do_log_ctx()

This way we can provide our own list of loggers to override the default
one (defaults to sess->fe->loggers when <logger> is NULL).

5 weeks agoMINOR: log: support 'to' parameter for "log" directive
Aurelien DARRAGON [Thu, 1 Oct 2026 09:03:03 +0000 (11:03 +0200)]
MINOR: log: support 'to' parameter for "log" directive

"to" is like "global", this is a special (optional) argument to be used
alone without ordinary log's arguments. It expects a comma separated list
of "loggers" section names which indicates which loggers section to inherit
loggers from. (each loggers section defines a number of "log" directive,
called logger).

5 weeks agoMINOR: log: add "loggers" section
Aurelien DARRAGON [Wed, 30 Sep 2026 12:32:04 +0000 (14:32 +0200)]
MINOR: log: add "loggers" section

loggers section allows to define multiple loggers (ie: "log" directive)
within a single config block, and group them under a common "loggers"
group identified by a unique name.

The end goal is to be able to reference a loggers section from a proxy
and other places such as do-log action in order to inherit from the
loggers defined in the section.

5 weeks agoBUG/MINOR: log: fix erroneous error message in log-steps parser
Aurelien DARRAGON [Thu, 1 Oct 2026 09:03:18 +0000 (11:03 +0200)]
BUG/MINOR: log: fix erroneous error message in log-steps parser

When invalid arguments are provided to "log-steps" directive, the
following error is returned: "invalid arguments, expects 'all' or a
composition of logging steps separated by spaces."

While in fact the parser expects comma separated values, and even the
documentation states it.

Let's fix the error message to match with the actual behavior and doc.

It should be backported to 3.2.

6 weeks agoBUILD: sym: Define HA_HAVE_DL_ITERATE_PHDR on FreeBSD
Olivier Houchard [Fri, 2 Oct 2026 18:22:39 +0000 (20:22 +0200)]
BUILD: sym: Define HA_HAVE_DL_ITERATE_PHDR on FreeBSD

FreeBSD has been providing dl_iterate_phdr() since FreeBSD 7.0, so
define HA_HAVE_DL_ITERATE_PHDR and HA_HAVE_DUMP_LIBS there.

6 weeks agoBUILD: Hopefully fix build on FreeBSD
Olivier Houchard [Fri, 2 Oct 2026 15:24:20 +0000 (17:24 +0200)]
BUILD: Hopefully fix build on FreeBSD

Commit 005038b80d468cdca0a9fdcb4b3c993ec02f8367 introduced a new script,
to inject the gnu_debugdata section into the binary. However, the script
used %b to print binary values, and %b behaves differently on Linux and
FreeBSD shells, and on FreeBSD, it would end up corrupting the binary,
making it crash on start.
Fix that by avoid using %b at all.

6 weeks agoREGTESTS: cli: don't check the HAProxy string
William Lallemand [Fri, 2 Oct 2026 13:26:49 +0000 (15:26 +0200)]
REGTESTS: cli: don't check the HAProxy string

Don't check the HAProxy string on "show info" since it can be changed
with -DPRODUCT_NAME, but check the "Name:" string instead.

6 weeks agoMINOR: http-ana: automatically enable http-no-delay for streaming events (SSE)
Willy Tarreau [Fri, 2 Oct 2026 12:19:09 +0000 (14:19 +0200)]
MINOR: http-ana: automatically enable http-no-delay for streaming events (SSE)

Some people get trapped using plain HTTP in AI gateway environments which
rely on server-sent events (SSE, documented at
  https://html.spec.whatwg.org/multipage/server-sent-events.html).

This mechanism consists in pushing body updates and expecting intermediaries
not to buffer them. The way to detect this is to check the advertised
content-type in the response, which is "text/event-stream" in this case.

What happens by default is that the Nagle algorithm delays short messages
by up to ~200ms hoping to aggregate them. But when all messages are only
a few tens of bytes large, sent every 5-10ms, this shows a jerky traffic
that's not pleasant to use.

The current patch simply adds a check for the aforementioned content-type
on the response path, and automatically enables http-no-delay for sending
to the client when found. It's sufficient to address the case without
requiring the user to adjust the config, as measured with sse-latency:

Before:
  === gateway overhead (gateway minus loopback; negative = loopback noise) ===
  emit->recv (1st token)   mean +206.851ms  p50 +206.851ms  p95 +206.851ms  p99 +206.851ms
  emit->recv (tokens)      mean +104.002ms  p50 +103.851ms  p95 +197.599ms  p99 +205.709ms
  TTFT (client)            mean +207.122ms  p50 +207.122ms  p95 +207.122ms  p99 +207.122ms
  inter-token (client)     mean -0.205ms  p50 -5.128ms  p95 -5.331ms  p99 +202.624ms

After:
  === gateway overhead (gateway minus loopback; negative = loopback noise) ===
  emit->recv (1st token)   mean +0.026ms  p50 +0.026ms  p95 +0.026ms  p99 +0.026ms
  emit->recv (tokens)      mean +0.034ms  p50 +0.036ms  p95 +0.059ms  p99 +0.029ms
  TTFT (client)            mean +0.135ms  p50 +0.135ms  p95 +0.135ms  p99 +0.135ms
  inter-token (client)     mean -0.002ms  p50 +0.042ms  p95 +0.041ms  p99 +0.035ms

It would make sense to backport this to 3.4 to help users who forget to
adjust their config to handle the streamed events.

6 weeks agoDEV: sse-latency: add a latency measuring tool for SSE response streams
Willy Tarreau [Fri, 2 Oct 2026 12:08:59 +0000 (14:08 +0200)]
DEV: sse-latency: add a latency measuring tool for SSE response streams

Common HTTP load generation tools are not convenient to measure latency
through haproxy when it comes to server-sent events, because the
measurements do not apply to the partial contents that SSE are. These
are particularly important for AI environments where agents need to
minimize latency.

This commit introduces a new tool that is both a client and a server,
and that is meant to measure an intermediary's added latency. For this,
it connects to itself to measure its own inflicted latency (loopback
test) then does it again through the configured proxy, and reports both
as well as the traversal time. The principle is to note the timestamp
at which each SSE is sent, and measure the difference when received by
the client, since both sides are the same process and use the same clock
reference. The output shows the reference time (loopback), the gateway
time, and the gateway overhead as the difference between the two.

The tool supports adding more clients, doing more requests, delaying the
first token response, and setting the inter-token latency.

An example haproxy config is provided (gateway.cfg) that measures both
with and without option http-no-delay.

Without http-no-delay (+ ~100ms, max 200 due to Nagle):

  === loopback (direct to listen address): 1 requests, 1 ok, 0 failed, 200 tokens ===
  TTFT (client)            n=1  mean=0.04ms  min=0.04ms  p50=0.04ms  p95=0.04ms  p99=0.04ms  max=0.04ms
  TTFT emit->recv(1st)     n=1  mean=0.00ms  min=0.00ms  p50=0.00ms  p95=0.00ms  p99=0.00ms  max=0.00ms
  inter-token (client)     n=199  mean=5.00ms  min=4.07ms  p50=5.13ms  p95=5.33ms  p99=5.36ms  max=5.38ms
  emit->recv (tokens)      n=199  mean=0.04ms  min=0.01ms  p50=0.03ms  p95=0.07ms  p99=0.18ms  max=0.19ms

  === gateway: 1 requests, 1 ok, 0 failed, 1000 tokens ===
  TTFT (client)            n=1  mean=207.17ms  min=207.17ms  p50=207.17ms  p95=207.17ms  p99=207.17ms  max=207.17ms
  TTFT emit->recv(1st)     n=1  mean=206.86ms  min=206.86ms  p50=206.86ms  p95=206.86ms  p99=206.86ms  max=206.86ms
  inter-token (client)     n=999  mean=4.80ms  min=0.00ms  p50=0.00ms  p95=0.00ms  p99=207.98ms  max=208.97ms
  emit->recv (tokens)      n=999  mean=104.04ms  min=1.02ms  p50=103.88ms  p95=197.67ms  p99=205.89ms  max=208.07ms

  === gateway overhead (gateway minus loopback; negative = loopback noise) ===
  emit->recv (1st token)   mean +206.851ms  p50 +206.851ms  p95 +206.851ms  p99 +206.851ms
  emit->recv (tokens)      mean +104.002ms  p50 +103.851ms  p95 +197.599ms  p99 +205.709ms
  TTFT (client)            mean +207.122ms  p50 +207.122ms  p95 +207.122ms  p99 +207.122ms
  inter-token (client)     mean -0.205ms  p50 -5.128ms  p95 -5.331ms  p99 +202.624ms

With http-no-delay (+ ~40 microseconds max):

  === loopback (direct to listen address): 1 requests, 1 ok, 0 failed, 200 tokens ===
  TTFT (client)            n=1  mean=0.05ms  min=0.05ms  p50=0.05ms  p95=0.05ms  p99=0.05ms  max=0.05ms
  TTFT emit->recv(1st)     n=1  mean=0.01ms  min=0.01ms  p50=0.01ms  p95=0.01ms  p99=0.01ms  max=0.01ms
  inter-token (client)     n=199  mean=5.00ms  min=4.03ms  p50=5.06ms  p95=5.27ms  p99=5.34ms  max=5.59ms
  emit->recv (tokens)      n=199  mean=0.04ms  min=0.01ms  p50=0.03ms  p95=0.07ms  p99=0.18ms  max=0.49ms

  === gateway: 1 requests, 1 ok, 0 failed, 1000 tokens ===
  TTFT (client)            n=1  mean=0.18ms  min=0.18ms  p50=0.18ms  p95=0.18ms  p99=0.18ms  max=0.18ms
  TTFT emit->recv(1st)     n=1  mean=0.03ms  min=0.03ms  p50=0.03ms  p95=0.03ms  p99=0.03ms  max=0.03ms
  inter-token (client)     n=999  mean=5.00ms  min=4.04ms  p50=5.10ms  p95=5.31ms  p99=5.37ms  max=5.45ms
  emit->recv (tokens)      n=999  mean=0.07ms  min=0.03ms  p50=0.07ms  p95=0.13ms  p99=0.20ms  max=0.28ms

  === gateway overhead (gateway minus loopback; negative = loopback noise) ===
  emit->recv (1st token)   mean +0.026ms  p50 +0.026ms  p95 +0.026ms  p99 +0.026ms
  emit->recv (tokens)      mean +0.034ms  p50 +0.036ms  p95 +0.059ms  p99 +0.029ms
  TTFT (client)            mean +0.135ms  p50 +0.135ms  p95 +0.135ms  p99 +0.135ms
  inter-token (client)     mean -0.002ms  p50 +0.042ms  p95 +0.041ms  p99 +0.035ms

6 weeks agoBUILD: ssl: fix build without USE_OPENSSL + clear_ocsp_clt_check_ctx
William Lallemand [Fri, 2 Oct 2026 11:15:46 +0000 (13:15 +0200)]
BUILD: ssl: fix build without USE_OPENSSL + clear_ocsp_clt_check_ctx

src/stream.c: In function â€˜stream_free’:
src/stream.c:722:9: error: implicit declaration of function â€˜clear_ocsp_clt_check_ctx’ [-Werror=implicit-function-declaration]
  722 |         clear_ocsp_clt_check_ctx(&s->ocsp_clt_check_ctx);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~

Add HAVE_SSL_OCSP to ensure we have the feature.

6 weeks agoREGTESTS: ocsp: Add 'do-ocsp-request' tests
Remi Tricot-Le Breton [Thu, 1 Oct 2026 14:59:30 +0000 (16:59 +0200)]
REGTESTS: ocsp: Add 'do-ocsp-request' tests

Add a regtest that uses the 'do-ocsp-request' action with a client that
uses a good certificate, a revoked certificate or no certificate.

6 weeks agoDOC: ocsp: Add doc for the new 'do-ocsp-request' action
Remi Tricot-Le Breton [Thu, 1 Oct 2026 14:59:29 +0000 (16:59 +0200)]
DOC: ocsp: Add doc for the new 'do-ocsp-request' action

The new 'do-ocsp-request' action checks for a client certificate after
an SSL handshake and checks its validity by sending an OCSP request to
the right OCSP responder. The resulting status is stored in a variable
and the request is denied by default is the resulting status is not
good.

6 weeks agoMINOR: ocsl: Add 'inapplicable' return code to client certificate ocsp check
Remi Tricot-Le Breton [Thu, 1 Oct 2026 14:59:28 +0000 (16:59 +0200)]
MINOR: ocsl: Add 'inapplicable' return code to client certificate ocsp check

When no client certificate is provided or no ocsp uri is present in the
certificate, the "status-var" content of the "wait-for-ocsp" action will
be set to "inapplicable" instead of the "unknown" value (which is an
actual OCSP status that could be sent by the OCSP responder).

6 weeks agoMEDIUM: ocsp: Create new do-ocsp-request action
Remi Tricot-Le Breton [Thu, 1 Oct 2026 14:59:27 +0000 (16:59 +0200)]
MEDIUM: ocsp: Create new do-ocsp-request action

Create a new 'do-ocsp-request' http-request and "tcp-request content"
action. When an SSL handshake occurred and was successful, the action
checks for a client certificate. If any is provided and it contains an
OCSP URI, we build an OCSP request and send it to the responder. No
other action is performed until a response is processed or a timeout
occurs.
When the response is received, we check its signature thanks to an
issuer certificate that should be in the issuer tree (see
'issers-chain-path' option), check its expiration dates and the client
certificate's status, and put the status and error reason (if any) in
the user provided "status-var" and "reason-var".
By default the action denies the request is the received status is not
'good' but this can be tuned thanks to the 'no-deny' option.

6 weeks agoMINOR: ocsp: Dup OCSP_CERTID in ssl_ocsp_create_request_details
Remi Tricot-Le Breton [Thu, 1 Oct 2026 14:59:26 +0000 (16:59 +0200)]
MINOR: ocsp: Dup OCSP_CERTID in ssl_ocsp_create_request_details

Instead of giving our only reference to the OCSP_CERTID to the
OCSP_REQUEST in ssl_ocsp_create_request_details we will duplicate it and
let the caller free it.

6 weeks agoMINOR: ocsp: Raise specific ocsp error code in ocsp parsing/verifying functions
Remi Tricot-Le Breton [Thu, 1 Oct 2026 14:59:25 +0000 (16:59 +0200)]
MINOR: ocsp: Raise specific ocsp error code in ocsp parsing/verifying functions

Instead of relying purely on error messages, the ssl_ocsp_check_response
and ssl_sock_update_ocsp_response functions can now return custom error
codes.
They were loosely based on the new verify error codes introduced in
newer version of OpenSSL (3.6.2 for instance) but needed to be
duplicated rather than used directly because of compatibility issues
with various SSL libraries.

6 weeks agoMINOR: ocsp: Send OCSP response status back to caller
Remi Tricot-Le Breton [Thu, 1 Oct 2026 14:59:24 +0000 (16:59 +0200)]
MINOR: ocsp: Send OCSP response status back to caller

The 'ssl_sock_load_ocsp_response' function parses an OCSP response,
checks its status and it expiration times but it did not provide the
status anywhere, which will come to use in upcoming OCSP-related devs.
Now it returns the OCSP status to the caller.

6 weeks agoMINOR: ocsp: Remove free of main structure from ssl_sock_free_ocsp_data
Remi Tricot-Le Breton [Thu, 1 Oct 2026 14:59:23 +0000 (16:59 +0200)]
MINOR: ocsp: Remove free of main structure from ssl_sock_free_ocsp_data

The 'ssl_sock_free_ocsp_data' now only frees the contents of the
'certificate_ocsp' while leaving the actual structure unfreed.
This will allow to keep certificate_ocsp structures on the stack later.

6 weeks agoDOC: server: explicit refcount interaction in "del server"
Amaury Denoyelle [Mon, 21 Sep 2026 07:45:55 +0000 (09:45 +0200)]
DOC: server: explicit refcount interaction in "del server"

Add a paragraph in "del server" to highlight that a server instance may
still be kept for some time after command completion for internal
management. This does not prevent though to reuse its name or GUID for a
newly created instance.

6 weeks agoBUG/MEDIUM: server: remove immediately from GUID tree on delete server
Amaury Denoyelle [Mon, 21 Sep 2026 07:05:09 +0000 (09:05 +0200)]
BUG/MEDIUM: server: remove immediately from GUID tree on delete server

On "delete server", the target instance is removed from its various
attach points in the parent proxy and global collections. The server
will then be freed immediately or kept temporarily in the process until
its refcount is null.

In effect, this means that a server name can be reused immediately after
"delete server" success, even if the instance is not immediately freed.
This was not the case though with its GUID, as guid_remove() was
performed in srv_drop() on null refcount.

Changes this behavior so that guid_remove() is now called directly
during "delete server" handler. This is better as there is no difference
now for server names and GUIDs : both can be reused immediately after
the command completion.

This could be considered as a bug with a possible backport up to 3.0.
Currently it may be better to not pick it unless it becomes mandatory.

6 weeks agoBUG/MINOR: cli: update wait help usage
Amaury Denoyelle [Tue, 15 Sep 2026 08:48:13 +0000 (10:48 +0200)]
BUG/MINOR: cli: update wait help usage

CLI command wait has a built-in help message which notably list all
supported condition. This patch complete it to add "be-removable" as a
valid entry, available since the implementation of the removal of
backends at runtime.

This must be backported up to 3.4.

6 weeks agoBUG/MINOR: server: fix "del server" description
Amaury Denoyelle [Thu, 17 Sep 2026 12:33:43 +0000 (14:33 +0200)]
BUG/MINOR: server: fix "del server" description

Update help for "del server" by stating that any servers can be removed,
not just dynamically added ones. This is supported since version 2.5.

This must be backported up to 2.6.

6 weeks agoBUG/MINOR: proxy: add PR_CAP_LB for dynamically added backend
Amaury Denoyelle [Fri, 2 Oct 2026 07:25:13 +0000 (09:25 +0200)]
BUG/MINOR: proxy: add PR_CAP_LB for dynamically added backend

When a new backend is added at runtime via the CLI, ensures its cap
contains PR_CAP_LB along with already set PR_CAP_BE.

The purpose of this cap is to flag a proxy with "load-balancing
capabilities". In fact this is a loose meaning which could be understand
in several manners. Currently, this cap is reserved for frontend,
backend and listen instances from the configuration file explicitely
created by users, by contrast to internal proxies. Thus, dynamically
added backends also enter in this definition.

The impact of this bug is limited as PR_CAP_LB usage is only used for
checking the compatibility of a server with the proxy mode. However,
this may change in the future so this change is mandatory.

This must be backported up to 3.4.

6 weeks agoMINOR: makefile: add CROSS_TOOLCHAIN to prefix the target's tools 20261001-oho-debug-syms
Olivier Houchard [Thu, 17 Sep 2026 09:18:48 +0000 (11:18 +0200)]
MINOR: makefile: add CROSS_TOOLCHAIN to prefix the target's tools

Cross-building also needs the target's nm, objcopy and readelf, since the
host ones do not know a foreign object. Instead of setting each one,
CROSS_TOOLCHAIN=arm-linux-gnueabi- prefixes them all, giving arm-linux-
gnueabi-gcc, -nm and so on. Empty by default.

6 weeks agoOPTIM: sym: skip the embedded table when the file provided the symbols
Olivier Houchard [Tue, 15 Sep 2026 15:51:03 +0000 (17:51 +0200)]
OPTIM: sym: skip the embedded table when the file provided the symbols

The embedded compressed table and the file's .symtab describe the same
local functions, the latter being a superset, so decompressing it when the
file is readable is pure loss, which is the common case.

Only decompress it when the file gave us nothing, i.e. once stripped or
unreachable. This is what the table is for and saves inflating about 1.5 MB
per object at every start.

6 weeks agoMINOR: sym: also read the compressed symbol tables from the ELF files
Olivier Houchard [Tue, 15 Sep 2026 15:51:02 +0000 (17:51 +0200)]
MINOR: sym: also read the compressed symbol tables from the ELF files

Distributions ship libraries stripped, keeping local symbols in a
compressed .gnu_debugdata section. It is not loaded in memory, so it was
only reachable for objects mapping it in a segment of their own, i.e. the
ones we build, leaving system libraries unnamed.

Look for that section in the ELF files already mapped to read their
.symtab, and hand it to the same decompressor. A separate debug file still
wins as it is more complete, and the file mappings are released right away
since names point into the decompressed image. On Fedora this names
libcrypto, libssl, liblua, libm, libcrypt and libz, turning
"liblua-5:luaopen_package+0x41a0/0x205" into "liblua-5:luaV_execute+0x90f".

6 weeks agoMINOR: sym: read local symbols and debug info from ELF files
Olivier Houchard [Tue, 15 Sep 2026 15:50:37 +0000 (17:50 +0200)]
MINOR: sym: read local symbols and debug info from ELF files

The dynamic linker and the embedded table only cover exported symbols and
our own objects, so static functions of system libraries still show as the
nearest export plus a large offset.

When files are readable, parse their .symtab, which lists local functions
too. On Linux the executable is read from /proc/self/exe, so a moved or
replaced file, or a relative exec path after a chdir (-C), still designates
the running image; a file whose program headers, or build-id when present,
do not match the image is ignored. Stripped objects fall back to the
separate debug file, looked up by GNU build-id and .gnu_debuglink as gdb
does, in /usr/lib/debug and the "tune.debug-file-directory" directories,
skipping a stale one whose build-id or CRC32 does not match. Files are
mapped only for the build.

6 weeks agoMEDIUM: sym: store a compressed symbol table in a loadable section
Olivier Houchard [Wed, 16 Sep 2026 14:10:08 +0000 (16:10 +0200)]
MEDIUM: sym: store a compressed symbol table in a loadable section

Implement the MiniDebugInfo, and store the symtab, compressed with xz,
into the .gnu_debugdata section, provided the needed utilities are
available, and we're building an ELF binary.
Makes it a loadable section, so that it is always available, and teach
haproxy to parse it, so that we will always get all available symbols
for binaries built that way, even if we can't even read the binary
itself.

6 weeks agoIMPORT: xz: import the xz-embedded decoder
Olivier Houchard [Tue, 15 Sep 2026 14:04:29 +0000 (16:04 +0200)]
IMPORT: xz: import the xz-embedded decoder

Import the .xz decoder from xz-embedded v2024-12-30 (0BSD). Only what is
needed for a plain LZMA2 stream is taken: the stream and LZMA2 decoders and
the two check modules; BCJ filters, SHA-256 and the kernel glue are left
out. The Makefile enables CRC64, the integrity check "xz" uses by default,
and links the decoder only when the compiler produces ELF objects, since
its only user in sym.c is not compiled for another object format.

Files are imported verbatim for later resyncing: C files in src/, headers
in include/import/. As the C files include their private headers quoted,
src/ carries small wrappers including the real ones, as src/cebtree-prv.h
does. include/import/xz_config.h maps the few kernel calls onto malloc()
and string functions.

6 weeks agoMINOR: sym: add helpers to collect the symbols of an ELF image
Olivier Houchard [Tue, 15 Sep 2026 15:48:50 +0000 (17:48 +0200)]
MINOR: sym: add helpers to collect the symbols of an ELF image

The next commits read symbols from ELF images (an embedded compressed table
and the object's file), and both need the same primitives, so introduce
them here: validate an ELF header and its section header table, keep every
read inside the image, find .symtab and its string table, and collect its
function symbols into the builder, applying the object's load address.
Parsing an ELF image needs no help from the dynamic linker, so they are
gated on __ELF__ alone; only enumerating the loaded objects needs
dl_iterate_phdr().

They are tagged __maybe_unused because their users come in later commits,
which may be picked independently.

6 weeks agoMINOR: sym: collect the symbols known to the dynamic linker
Olivier Houchard [Tue, 15 Sep 2026 13:07:53 +0000 (15:07 +0200)]
MINOR: sym: collect the symbols known to the dynamic linker

The dynamic linker keeps .dynsym/.dynstr of every loaded object mapped for
relocation. Where dl_iterate_phdr() exists, walk each object's PT_DYNAMIC
to collect its exported function symbols from the memory image, plus its
address range from PT_LOAD. This works even when files are unreadable (e.g.
after chroot) and gives what dladdr() sees, but lock-free.

When an address falls past the nearest lower symbol, resolve_sym_name() now
prints "sym+off/size" instead of a bare offset, easier to feed to gdb. Add
"tune.disable-elf-symbols" to restore the previous output.

6 weeks agoMINOR: sym: add an in-process symbol table for backtraces
Olivier Houchard [Tue, 15 Sep 2026 13:03:31 +0000 (15:03 +0200)]
MINOR: sym: add an in-process symbol table for backtraces

Build an address-sorted table at boot and publish immutable snapshots for
lock-free, signal-safe lookups. Seed it with the existing known functions.
The table is built while the process is still starting and no thread is
 running yet, so the build needs no locking.
The table is sorted using a radix sort.

6 weeks agoCLEANUP: sym: move symbol resolution out of tools.c
Olivier Houchard [Thu, 24 Sep 2026 15:26:03 +0000 (17:26 +0200)]
CLEANUP: sym: move symbol resolution out of tools.c

Group symbol resolution and the shared dynamic-loader helpers in sym.c
before extending them with the in-process table: resolve_sym_name(),
the dladdr() and dlsym() wrappers, static-build detection, the executable
path, and the dlopen() interposer which verifies the loaded symbols
through the same helpers. Their declarations, and the backtrace helpers
that report the frames they resolve, move into a new sym.h which their
callers now include.
No functional change.

6 weeks ago[RELEASE] Released version 3.5-dev8 v3.5-dev8
Willy Tarreau [Thu, 1 Oct 2026 12:49:21 +0000 (14:49 +0200)]
[RELEASE] Released version 3.5-dev8

Released version 3.5-dev8 with the following main changes :
    - BUG/MEDIUM: task: Do not destroy a task that is not ours in task_destroy
    - BUG/MEDIUM: http-client: Don't use the httpclient context if it was released
    - MINOR: http-client: Add an option to not stop the reception of the response
    - BUG/MEDIUM: ssl/ocsp: Set HTTPCLIENT_O_RES_ACCUM option on the http-client
    - BUG/MEDIUM: acme: Set HTTPCLIENT_O_RES_ACCUM option on the http-client
    - MINOR: http-client: Add a function to notify some data were consumed
    - BUG/MEDIUM: http-client/cli: Notify the http-client when the response is consumed
    - MINOR: ssl/ocsp: Remove the useless res_payload callback of the http-client
    - BUG/MINOR: ssl/ocsp: Report an error when an empty OCSP response is received
    - BUG/MEDIUM: htx: Fix the position returned by htx_defrag()
    - BUG/MINOR: tools: Don't try to anonymize a NULL string
    - BUG/MAJOR: htx: Check the header/trailer length limits when one is updated
    - MINOR: htx: Add macros for the header/trailer name and value max lengths
    - BUG/MINOR: mux-h2: Reject trailers received on a tunneled stream
    - MEDIUM: htx: Skip UNUSED blocs when getting previous,next and first blocks
    - MEDIUM: htx/tree-wide: Remove tests on HTX_BLK_UNUSED when possible
    - MEDIUM: htx: Insert headers and trailers before corresponding end-of block
    - MINOR: htx: Add support for flags on HTX blocks
    - MAJOR: htx: Use htx_set_eom() instead of setting HTX_FL_EOM by hand
    - MAJOR: htx: Rename HTX_FL_EOM into HTX_FL_HAS_EOM
    - MEDIUM: htx: Add HTX_BLK_FL_EOM flag and set it on last block of the message
    - MINOR: compression: Rely on HTX block flags to detect the end of message
    - MINOR: fcgi-app: Stop on last HTX block when getting the payload size
    - MINOR: mux-h2: Use flags of HTX blocks to detect end of message during sending
    - MINOR: mux-h1: Use flags of HTX blocks to detect end of message during sending
    - MINOR: mux-fcgi: Use flags of HTX blocks to detect end of message during sending
    - MEDIUM: h3: Use flags of HTX blocks to detect end of message during sending
    - MINOR: stats-html: Detect a complete request by testing flags on the tail bloc
    - MINOR: hlua: Use flags of HTX blocks to detect EOM from an HTTP applet
    - MINOR: htx: Add function to know if the tail block carry EOM flag
    - MAJOR: tree-wide: No longer use HTX_FL_HAS_EOM to detect end of message
    - MAJOR: htx: Remove HTX_FL_HAS_EOM flag
    - MEDIUM: mux-h2: Don't mix HTTP and tunneled data in the same buffer
    - MEDIUM: htx: Harden HTX API to avoid invalid uses when EOM was reached
    - MEDIUM: htx: Remove usless htx_is_unique_blk() function
    - DOC: internals: Update the HTX API documentation
    - MINOR: htx: Rename htx_has_eom() into htx_msg_ended()
    - MINOR: htx: Add HTX_BLK_RAW_DATA block type
    - MINOR: htx: Add the block type as argument of the data insertion functions
    - MINOR: htx: Handle RAW_DATA blocks like DATA blocks in the HTX API
    - MEDIUM: htx: Allow tunneled data to be added in a message already ended
    - MINOR: mux-h1: Handle RAW_DATA blocks when sending data
    - MINOR: mux-h2: Handle RAW_DATA blocks when sending data
    - MEDIUM: mux-h1: Use RAW_DATA blocks to store tunneled data
    - MEDIUM: mux-h2: Use RAW_DATA blocks to store tunneled data
    - Revert "MEDIUM: mux-h2: Don't mix HTTP and tunneled data in the same buffer"
    - MINOR: http-htx: Really test the EOM flag presence in internal.htx.has_eom
    - MINOR: http-htx: Report the payload of RAW_DATA blocks in internal.htx_blk.data
    - MINOR: mux-h1: Only handle RAW_DATA blocks when emitting tunneled data
    - DOC: internals: Update the HTX API documentation for tunneled data
    - REGTESTS: http-messaging: Add a test for the CONNECT tunnels
    - BUG/MINOR: hlua: release private Lua rule data on teardown
    - BUG/MINOR: ssl: Fix possible null deref on the SSL context in ssl_sock_to_buf()
    - MEDIUM: ssl: add ocsp-update.timeout global option
    - BUG/MINOR: http-client: Convert server timeout ticks when setting it
    - BUG/MEDIUM: h1-htx: Don't report EOM for H1 interim responses during parsing
    - BUG/MINOR: mux-h2: Don't expect more HTX data on 1xx interim responses
    - REG-TESTS: http-messaging: Add a script to test interim responses for H1/H2
    - BUG/MEDIUM: log: reserve the trailing 0 in CBOR int and bool encoders
    - BUG/MEDIUM: http-htx: don't build the new authority in a rotating trash chunk
    - BUG/MEDIUM: http-act: ignore "capture len" rules evaluated from a backend
    - BUG/MEDIUM: tcp-rules: ignore "capture len" rules evaluated from a backend
    - BUG/MINOR: http-ana: count response body failures only once in http_fail_cnt
    - BUG/MINOR: http-fetch: http_auth_bearer() must not match a missing header
    - BUG/MINOR: http-fetch: fix the space check of http_auth_bearer(<hdr>)
    - BUG/MINOR: mux-h1: only mark C-L and T-E as sent once the header is emitted
    - BUG/MINOR: tcpcheck: refresh the start-line after updating the authority
    - CLEANUP: mux-h2: replace a non-UTF-8 character in a comment
    - BUG/MINOR: http-ana: restore the transaction status after early hints
    - REG-TESTS: http-messaging: Send one request per h2 client in h2_trailers.vtc
    - BUG/MEDIUM: h3: Set FIN when last DATA block is sent via zero-copy
    - BUG/MAJOR: mux_quic: fix leak on RESET_STREAM reception
    - BUG/MEDIUM: mux_quic: activate timeout on FE init
    - BUG/MINOR: h2: reject :protocol pseudo-header in H2 responses
    - MINOR: ssl: cleanse TLS ticket keys before freeing
    - MINOR: init: also set the worker-id in file-less mode
    - BUG/MINOR: acme: exact domain match in acme_challenge_ready()
    - BUG/MINOR: ssl: copy curves, sigalgs and client_sigalgs in srv_ssl_settings_cpy()
    - BUG/MINOR: ssl: free curves, sigalgs and client_sigalgs in ssl_sock_free_srv_ctx()
    - BUG/MINOR: ssl: free curves, sigalgs and client_sigalgs in srv_parse_*()
    - MINOR: log: pass the input end to the _lf_encode_bytes() byte encoders
    - MINOR: log: add the +utf8 encoding option to let valid UTF-8 pass
    - BUG/MAJOR: mux_quic: fix potential crash on RESET_STREAM receive
    - BUG/MEDIUM: sink: reconnect attempt not working after session lasted more than ~25 days
    - BUG/MEDIUM: server: skip log backend addr checks for internal proxies
    - REGTESTS: log: check that a ring's internal server may target a UNIX socket
    - Revert "CLEANUP: proxy: mention that px->conn_retries isn't relevant in some cases"
    - BUILD: haring: fix compile issue due to nop warning.
    - BUG/MINOR: chunk: Allow large chunks uses from large const buffers
    - MINOR: htx: Remove htx_move_blk_before() function
    - BUG/MAJOR: mux-h2: Preserve raw data on aborted frontend tunnels
    - BUG/MEDIUM: mux-h1: Don't subscribe for sends while output is blocked
    - BUG/MINOR: mux-h1: Discard pending raw data after a tunnel rejection
    - MINOR: stick-table: provide a function to estimate on-wire data size
    - MINOR: stick-table: calculate the on-wire size of each key
    - BUG/MEDIUM: stick-table: restrict key sizes to what fits in a buffer
    - REGTESTS: http-messaging: consume window update before txdata
    - BUG/MEDIUM: pattern: don't dereference static_pattern's data when not filling it
    - BUG/MINOR: jwe: Buffer overflow when filling fake cek in case of RSA1.5
    - BUG/MINOR: jwe: Avoid buffer overflow in fake cek (RSA1.5)
    - BUG/MINOR: startup: don't chroot by default when set-dumpable is set
    - BUG/MINOR: http: do not consume the delimiter of a truncated q-factor
    - BUG/MINOR: sample: apply the ms_/us_ time offsets in the input unit
    - BUG/MINOR: sample: zero-pad the fractional part emitted by http_date()
    - BUG/MINOR: sample: make quic_enabled() always succeed
    - BUG/MINOR: http-ana: return a 502 when checkcache blocks a response
    - BUG/MINOR: stick-table: do not count the lookup itself in table_trackers()
    - BUG/MINOR: payload: always report a boolean from req.ssl_ec_ext
    - BUG/MINOR: http-fetch: do not count Set-Cookie attributes as cookies
    - BUG/MEDIUM: tcpcheck: do not run a regex on an unallocated buffer
    - BUG/MINOR: sample: return the decoded JWT part when no path is given
    - DOC: config: mention other responses not blocked by option checkcache
    - DOC: config: fix doc for hex2i() converter on unparsable input
    - DOC: config: mention that url_ip and url_port fail when passed a name
    - REGTESTS: converter: add a test for the arithmetic and bitwise converters
    - REGTESTS: converter: add a test for the string trimming and parsing converters
    - REGTESTS: converter: add a test for the date formatting converters
    - REGTESTS: converter: cover all the map match methods and output types
    - REGTESTS: http-rules: test the run-time ACL and map update actions
    - REGTESTS: http-rules: test the ACL and map management commands of the CLI
    - REGTESTS: sample_fetches: add a test for the HTTP response fetches
    - REGTESTS: sample_fetches: add a test for the HTTP request fetches
    - REGTESTS: sample_fetches: add a test for the connection address fetches
    - REGTESTS: sample_fetches: add a test for the proxy and server state fetches
    - REGTESTS: stick-table: test the general purpose counters and tags
    - REGTESTS: stick-table: test the traffic counters of the stick counters
    - REGTESTS: http-rules: test the HTTP authentication action, fetches and ACL
    - REGTESTS: log: test the transaction state fetches and the logging actions
    - REGTESTS: http-rules: test the binary header manipulation actions
    - REGTESTS: http-rules: test replace-uri and the header replacement actions
    - REGTESTS: tcp-rules: test the set-src, set-dst and port rewriting actions
    - REGTESTS: sample_fetches: add a test for the constant and process fetches
    - REGTESTS: converter: add a test for the when() and debug() converters
    - REGTESTS: http-errorfiles: test the errorloc directives
    - REGTESTS: proxy: test the "option checkcache" response filter
    - REGTESTS: proxy: test the connection retries, retry-on and redispatch
    - REGTESTS: http-rules: test the tarpit, deny and silent-drop actions
    - REGTESTS: log: test the log filtering options of a frontend
    - REGTESTS: proxy: test monitor-uri and the monitor fail condition
    - REGTESTS: cli: add a smoke test for the read-only CLI commands
    - REGTESTS: cli: test the commands which change the run-time settings
    - REGTESTS: http-rules: test the declared capture slots
    - REGTESTS: tcp-rules: test the raw payload fetches
    - REGTESTS: sample_fetches: pin one thread in the connection address test
    - REGTESTS: sample_fetches: pin one thread in the proxy state test
    - REGTESTS: server: test the server settings reported by the runtime
    - REGTESTS: checks: test the health adjusting from observed traffic
    - REGTESTS: cli: test the privilege levels of the CLI
    - REGTESTS: connection: test the expect-proxy action
    - REGTESTS: sample_fetches: test the raw TLS hello fetches
    - REGTESTS: connection: do not race with the reset in the expect-proxy test
    - REGTESTS: ssl: test the ssl_fc_* and ssl_bc_* connection fetches
    - REGTESTS: protobuf: add a test for the ungrpc converter
    - REGTESTS: http-messaging: test the options dropping the HTTP trailers
    - REGTESTS: protobuf: cover all the field types of the ungrpc converter
    - REGTESTS: sample_fetches: test req.ssl_ver on an SSLv2 CLIENT-HELLO
    - REGTESTS: sample_fetches: test the req.ssl_alpn fetch
    - REGTESTS: ssl: test ssl_c_used, ssl_c_san and ssl_c_ca_err_depth
    - REGTESTS: stick-table: read the counters through sc1_ and sc2_ as well
    - REGTESTS: stick-table: cover the remaining gpc and gpt spellings
    - REGTESTS: http-rules: cover the rfc7239_nn and rfc7239_np converters
    - REGTESTS: proxy: test the disable-l7-retry action
    - REGTESTS: connection: test the NetScaler CIP protocol
    - REGTESTS: tcp-rules: test the RDP cookie fetches
    - REGTESTS: tcp-rules: read the payload through the deprecated spellings
    - REGTESTS: sample_fetches: test the TCP_INFO counters
    - REGTESTS: sample_fetches: check the rtt headers this test was filling
    - REGTESTS: sample_fetches: test the req.cook() fetch itself
    - REGTESTS: sample_fetches: test fe_tarpit_timeout
    - REGTESTS: sample_fetches: test res.body, res.body_len and server_status
    - REGTESTS: sample_fetches: test the request_date fetch
    - REGTESTS: sample_fetches: test the stream state fetches over HTTP/2
    - REGTESTS: ssl: test the wait-for-handshake action and fc.timer.handshake
    - REGTESTS: http-messaging: test the option httpclose
    - REGTESTS: http-messaging: test the option http-no-delay
    - REGTESTS: http-messaging: check that a truncated response loses no byte
    - REGTESTS: sample_fetches: do not race with the server close in proxy_state
    - REGTESTS: sample_fetches: make the raw hello test parallel-safe
    - REGTESTS: http-messaging: widen the abort window of the abortonclose test
    - REGTESTS: log: serve the transaction state test on a single connection
    - REGTESTS: http-messaging: give each frontend its own syslog server
    - REGTESTS: converter: serve the two sha2 requests on one connection
    - REGTESTS: http-messaging: make the /c5 abort land during the retries
    - REGTESTS: http-rules: one connection per request in the replace-uri test
    - MINOR: vars: Add a helper to parse a variable scope name
    - MINOR: vars: Add 'var_name_is_valid' helper function
    - MEDIUM: vars: Add the set-vars-from-map action
    - REGTESTS: vars: Add a test for the set-vars-from-map action

6 weeks agoREGTESTS: vars: Add a test for the set-vars-from-map action
Remi Tricot-Le Breton [Thu, 1 Oct 2026 12:33:28 +0000 (14:33 +0200)]
REGTESTS: vars: Add a test for the set-vars-from-map action

Test the new "set-vars-from-map" action with different input types and
with valid and invalid values.

6 weeks agoMEDIUM: vars: Add the set-vars-from-map action
Remi Tricot-Le Breton [Thu, 1 Oct 2026 12:33:27 +0000 (14:33 +0200)]
MEDIUM: vars: Add the set-vars-from-map action

Add a new action, set-vars-from-map(<scope>,<map-file>[,<type>]), that
loads a two-column (key/value) map file and sets one variable per entry,
named "<scope>.<key>", to the entry's value. The scope is one of sess,
txn, req, res or check and the variable name is relative to it.
The new "tune.vars.from-map.max" global option defines the maximum
number of entries taken into account in each map. It default to 100.

Values are read as strings and converted according to the optional
<type>, which may be "str" (default), "int" or "bool". Integer
conversion is strict, so an entry with trailing garbage is rejected
rather than silently truncated, and booleans accept 0/1 as well as
true/false in any case. An entry that cannot be parsed is skipped
without aborting the remaining entries.

The file is loaded as a pattern reference flagged PAT_REF_SMP, or reused
if it was already loaded, in which case it must also have been loaded as
a two-column file. The action is registered for all rule sets that
already support set-var.

This was GH issue #1619.

6 weeks agoMINOR: vars: Add 'var_name_is_valid' helper function
Remi Tricot-Le Breton [Thu, 1 Oct 2026 12:33:26 +0000 (14:33 +0200)]
MINOR: vars: Add 'var_name_is_valid' helper function

This function checks a variable name (scope excluded) and fails if any
invalid character is found. Variable names must contain alphanumeric
characters, '-', '_' or '.'.