Commit graph

20432 commits

Author SHA1 Message Date
Christopher Faulet
54e58103e5 BUG/MEDIUM: stconn: Don't report abort from SC if read0 was already received
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
SC_FL_ABRT_DONE flag should never be set when SC_FL_EOS was already
set. These both flags were introduced to replace the old CF_SHUTR and to
have a flag for shuts driven by the stream and a flag for the read0 received
by the mux. So both flags must not be seen at same time on a SC. It is
espeically important because some processing are performed when these flags
are set. And wrong decisions may be made.

This patch must be backproted as far as 2.8.
2025-12-12 08:41:08 +01:00
Christopher Faulet
a483450fa2 BUG/MEDIUM: http-ana: Properly detect client abort when forwarding response (v2)
The first attempt to fix this issue (c672b2a29 "BUG/MINOR: http-ana:
Properly detect client abort when forwarding the response") was not fully
correct and could be responsible to false report of client abort during the
response forwarding. I guess it is possible to truncate the response.

Instead, we must also take care that the client closed on its side, by
checking SC_FL_EOS flag on the front SC. Indeed, if the client has aborted,
this flag should be set.

This patch should be backported as far as 2.8.
2025-12-12 08:41:08 +01:00
William Lallemand
5b19d95850 BUG/MEDIUM: mworker/listener: ambiguous use of RX_F_INHERITED with shards
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
The RX_F_INHERITED flag was ambiguous, as it was used to mark both
listeners inherited from the parent process and listeners duplicated
from another local receiver. This could lead to incorrect behavior
concerning socket unbinding and suspension.

This commit refactors the handling of inherited listeners by splitting
the RX_F_INHERITED flag into two more specific flags:

- RX_F_INHERITED_FD: Indicates a listener inherited from the parent
  process via its file descriptor. These listeners should not be unbound
  by the master.

- RX_F_INHERITED_SOCK: Indicates a listener that shares a socket with
  another one, either by being inherited from the parent or by being
  duplicated from another local listener. These listeners should not be
  suspended or resumed individually.

Previously, the sharding code was unconditionally using RX_F_INHERITED
when duplicating a file descriptor. In HAProxy versions prior to 3.1,
this led to a file descriptor leak for duplicated unix stats sockets in
the master process. This would eventually cause the master to crash with
a BUG_ON in fd_insert() once the file descriptor limit was reached.

This must be backported as far as 3.0. Branches earlier than 3.0 are
affected but would need a different patch as the logic is different.
2025-12-11 18:09:47 +01:00
Willy Tarreau
3ec5818807 MINOR: h2/trace: emit a trace of the received RST_STREAM type
Right now we don't get any state trace when receiving an RST_STREAM, and
this is not convenient because RST_STREAM(0) is not visible at all, except
in developer level because the function is entered and left.

Let's extract the RST code first and always log it using TRACE_PRINTF()
(along with h2c/h2s) so that it's possible to detect certain codes being
used.
2025-12-10 15:58:56 +01:00
Amaury Denoyelle
5b8e6d6811 BUG/MEDIUM: h3: fix access to QCS <sd> definitely
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
The previous patch tried to fix access to QCS <sd> member, as the latter
is not always allocated anymore on the frontend side.

  a15f0461a0
  BUG/MEDIUM: h3: do not access QCS <sd> if not allocated

In particular, access was prevented after HEADERS parsing in case
h3_req_headers_to_htx() returned an error, which indicates that the
stream-endpoint allocation was not performed. However, this still is not
enough when QCS instance is already closed at this step. Indeed, in this
case, h3_req_headers_to_htx() returns OK but stream-endpoint allocation
is skipped as an optimization as no data exchange will be performed.

To definitely fix this kind of problems, add checks on qcs <sd> member
before accessing it in H3 layer. This method is the safest one to ensure
there is no NULL dereferencement.

This should fix github issue #3211.

This must be backported along the above mentionned patch.
2025-12-10 12:04:37 +01:00
Maxime Henrion
6eedd0d485 CLEANUP: more conversions and cleanups for alignment
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
- Convert additional cases to use the automatic alignment feature for
  the THREAD_ALIGN(ED) macros. This includes some cases that are less
  obviously correct where it seems we wanted to align only in the
  USE_THREAD case but were not using the thread specific macros.
- Also move some alignment requirements to the structure definition
  instead of having it on variable declaration.
2025-12-09 17:40:58 +01:00
Maxime Henrion
bc8e14ec23 CLEANUP: use the automatic alignment feature
- Use the automatic alignment feature instead of hardcoding 64 all over
  the code.
- This also converts a few bare __attribute__((aligned(X))) to using the
  ALIGNED macro.
2025-12-09 17:14:58 +01:00
Olivier Houchard
420b42df1c BUG/MEDIUM: ssl: Don't resume session for check connections
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
Don't attempt to use stored sessions when creating new check
connections, as the check SSL parameters might be different from the
server's ones.
This has not been proven to be a problem yet, but it doesn't mean it
can't be, and this should be backported up to 2.8 along with
dcce936912 if it is.
2025-12-09 16:45:54 +01:00
Olivier Houchard
be4e1220c2 BUG/MEDIUM: ssl: Don't store the ALPN for check connections
When establishing check connections, do not store the negociated ALPN
into the server's path_param if the connection is a check connection, as
it may use different SSL parameters than the regular connections. To do
so, only store them if the CO_FL_SSL_NO_CACHED_INFO is not set.
Otherwise, the check ALPN may be stored, and the wrong mux can be used
for regular connections, which will end up generating 502s.

This should fix Github issue #3207

This should be backported to 3.3.
2025-12-09 16:43:31 +01:00
Olivier Houchard
dcce936912 MINOR: connections: Add a new CO_FL_SSL_NO_CACHED_INFO flag
Add a new flag to connections, CO_FL_SSL_NO_CACHED_INFO, and set it for
checks.
It lets the ssl layer know that he should not use cached informations,
such as the ALPN as stored in the server, or cached sessions.
This wlil be used for checks, as checks may target different servers, or
used a different SSL configuration, so we can't assume the stored
informations are correct.

This should be backported to 3.3, and may be backported up to 2.8 if the
attempts to do session resume by checks is proven to be a problem.
2025-12-09 16:43:31 +01:00
Olivier Houchard
260d64d787 BUG/MEDIUM: ssl: Always check the ALPN after handshake
Move the code that is responsible for checking the ALPN, and updating
the one stored in the server's path_param, from after we created the
mux, to after we did an handshake. Once we did it once, the mux will not
be created by the ssl code anymore, as when we know which mux to use
thanks to the ALPN, it will be done earlier in connect_server(), so in
the unlikely event it changes, we would not detect it anymore, and we'd
keep on creating the wrong mux.
This can be reproduced by doing a first request, and then changing the
ALPN of the server without haproxy noticing (ie without haproxy noticing
that the server went down).

This should be backported to 3.3.
2025-12-09 16:43:31 +01:00
William Lallemand
594408cd61 BUG/MINOR: mworker/cli: 'show proc' is limited by buffer size
In ticket #3204, it was reported that "show proc" is not able to display
more than 202 processes. Indeed the bufsize is 16k by default in the
master, and can't be changed anymore since 3.1.

This patch allows the 'show proc' to start again to dump when the buffer
is full, based on the timestamp of the last PID it attempted to dump.
Using pointers or count the number of processes might not be a good idea
since the list can change between calls.

Could be backported in all stable branche.
2025-12-09 16:09:10 +01:00
William Lallemand
dabe8856ad CLEANUP: mworker/cli: remove useless variable
The msg variable is declared and free but never used, this patch removes it.
2025-12-09 16:09:10 +01:00
Amaury Denoyelle
a15f0461a0 BUG/MEDIUM: h3: do not access QCS <sd> if not allocated
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
Since the following commit, allocation of QCS stream-endpoint on FE side
has been delayed. The objective is to allocate it only for QCS attached
to an upper stream object. Stream-endpoint allocation is now performed
on qcs_attach_sc() called during HEADERS parsing.

  commit e6064c5616
  OPTIM: mux-quic: delay FE sedesc alloc to stream creation

Also, stream-endpoint is accessed through the QCS instance after HEADERS
or DATA frames parsing, to update the known input payload length. The
above patch triggered regressions as in some code paths, <sd> field is
dereferenced while still being NULL.

This patch fixes this by restricting access to <sd> field after newer
conditions.

First, after HEADERS parsing, known input length is only updated if
h3_req_headers_to_htx() previously returned a success value, which
guarantee that qcs_attach_sc() has been executed.

After DATA parsing, <sd> is only accessed after the frame validity
check. This ensures that HEADERS were already parsed, thus guaranteing
that stream-endpoint is allocated.

This should fix github issue #3211.

This must be backported up to 3.3. This is sufficient, unless above
patch is backported to previous releases, in which case the current one
must be picked with it.
2025-12-09 15:00:23 +01:00
Christopher Faulet
3cf4e7afb9 BUG/MEDIUM: http-ana: Don't close server connection on read0 in TUNNEL mode
It is a very old bug (2012), dating from the introduction of the keep-alive
support to HAProxy. When a request is fully received, the SC on backend side
is switched to NOHALF mode. It means that when the read0 is received from
the server, the server connection is immediately closed. It is expected to
do so at the end of a classical request. However, it must not be performed
if the session is switched to the TUNNEL mode (after an HTTP/1 upgrade or a
CONNECT). The client may still have data to send to the server. And closing
brutally the server connection this way will be handled as an error on
client side.

This bug is especially visible when a H2 connection on client side because a
RST_STREAM is emitted and a "SD--" is reported in logs.

Thanks to @chrisstaite

This patch should fix the issue #3205. It must be backported to all stable
versions.
2025-12-08 15:22:01 +01:00
Christopher Faulet
5d74980277 BUG/MINOR: log: Dump good %B and %U values in logs
When per-stream "bytes_in" and "bytes_out" counters where replaced in 3.3,
the wrong counters were used for %B and %U values in logs. In the
configuration manual and the commit message, it was specificed that
"bytes_in" was replaced by "req_in" and "bytes_out" by "res_in", but in the
code, wrong counters were used. It is now fixed.

This patch should fix the issue #3208. It must be backported to 3.3.
2025-12-08 15:22:01 +01:00
Christopher Faulet
be998b590e MEDIUM: ssl/server: No longer store the SNI of cached TLS sessions
Thanks to the previous patch, "BUG/MEDIUM: ssl: Don't reuse TLS session
if the connection's SNI differs", it is no useless to store the SNI of
cached TLS sessions. This SNI is no longer tested and new connections
reusing a session must have the same SNI.

The main change here is for the ssl_sock_set_servername() function. It is no
longer possible to compare the SNI of the reused session with the one of the
new connection. So, the SNI is always set, with no other processing. Mainly,
the session is not destroyed when SNIs don't match. It means the commit
119a4084bf ("BUG/MEDIUM: ssl: for a handshake when server-side SNI changes")
is implicitly reverted.

It is good to note that it is unclear for me when and why the reused session
should be destroyed. Because I'm unable to reproduce any issue fixed by the
commit above.

This patch could be backported as far as 3.0 with the commit above.
2025-12-08 15:22:01 +01:00
Christopher Faulet
5702009c8c BUG/MEDIUM: ssl: Don't reuse TLS session if the connection's SNI differs
When a new SSL server connection is created, if no SNI is set, it is
possible to inherit from the one of the reused TLS session. The bug was
introduced by the commit 95ac5fe4a ("MEDIUM: ssl_sock: always use the SSL's
server name, not the one from the tid"). The mixup is possible between
regular connections but also with health-checks connections.

But it is only the visible part of the bug. If the SNI of the cached TLS
session does not match the one of the new connection, no reuse must be
performed at all.

To fix the bug, hash of the SNI of the reused session is compared with the
one of the new connection. The TLS session is reused only if the hashes are
the same.

This patch should fix the issue #3195. It must be slowly backported as far
as 3.0. it relies on the following series:

  * MEDIUM: tcpcheck/backend: Get the connection SNI before initializing SSL ctx
  * MINOR: connection/ssl: Store the SNI hash value in the connection itself
  * MEDIUM: ssl: Store hash of the SNI for cached TLS sessions
  * MINOR: ssl: Add a function to hash SNIs
  * MEDIUM: quic: Add connection as argument when qc_new_conn() is called
  * BUG/MINOR: ssl: Don't allow to set NULL sni
2025-12-08 15:22:01 +01:00
Christopher Faulet
7e9d921141 MEDIUM: tcpcheck/backend: Get the connection SNI before initializing SSL ctx
The SNI of a new connection is now retrieved earlier, before the
initialization of the SSL context. So, concretely, it is now performed
before calling conn_prepare(). The SNI is then set just after.
2025-12-08 15:22:01 +01:00
Christopher Faulet
28654f3c9b MINOR: connection/ssl: Store the SNI hash value in the connection itself
When a SNI is set on a new connection, its hash is now saved in the
connection itself. To do so, a dedicated field was added into the connection
strucutre, called sni_hash. For now, this value is only used when the TLS
session is cached.
2025-12-08 15:22:01 +01:00
Christopher Faulet
92f77cb3e6 MINOR: ssl: Compare hashes instead of SNIs when a session is cached
This patch relies on the commit "MINOR: ssl: Store hash of the SNI for
cached TLS sessions". We now use the hash of the SNIs instead of the SNIs
themselves to know if we must update the cached SNI or not.
2025-12-08 15:22:01 +01:00
Christopher Faulet
9794585204 MINOR: ssl: Store hash of the SNI for cached TLS sessions
For cached TLS sessions, in addition to the SNI itself, its hash is now also
saved. No changes are expected here because this hash is not used for now.

This commit relies on:

  * MINOR: ssl: Add a function to hash SNIs
2025-12-08 15:22:00 +01:00
Christopher Faulet
d993e1eeae MINOR: ssl: Add a function to hash SNIs
This patch only adds the function ssl_sock_sni_hash() that can be used to
get the hash value corresponding to an SNI. A global seed, sni_hash_seed, is
used.
2025-12-08 15:22:00 +01:00
Christopher Faulet
a83ed86b78 MEDIUM: quic: Add connection as argument when qc_new_conn() is called
This patch reverts the commit efe60745b ("MINOR: quic: remove connection arg
from qc_new_conn()"). The connection will be mandatory when the QUIC
connection is created on backend side to fix an issue when we try to reuse a
TLS session.

So, the connection is again an argument of qc_new_conn(), the 4th
argument. It is NULL for frontend QUIC connections but there is no special
check on it.
2025-12-08 15:22:00 +01:00
Christopher Faulet
3534efe798 BUG/MINOR: ssl: Don't allow to set NULL sni
ssl_sock_set_servername() function was documented to support NULL sni to
unset it. However, the man page of SSL_get_servername() does not mentionned
it is supported or not. And it is in fact not supported by WolfSSL and leads
to a crash if we do so.

For now, this function is never called with a NULL sni, so it better and
safer to forbid this case. Now, if the sni is NULL, the function does
nothing.

This patch could be backported to all stable versions.
2025-12-08 15:22:00 +01:00
Frederic Lecaille
90064ac88b BUG/MINOR: quic: do not set first the default QUIC curves
This patch impacts both the QUIC frontends and listeners.

Note that "ssl-default-bind-ciphersuites", "ssl-default-bind-curves",
are not ignored by QUIC by the frontend. This is also the case for the
backends with "ssl-default-server-ciphersuites" and "ssl-default-server-curves".

These settings are set by ssl_sock_prepare_ctx() for the frontends and
by ssl_sock_prepare_srv_ssl_ctx() for the backends. But ssl_quic_initial_ctx()
first sets the default QUIC frontends (see <quic_ciphers> and <quic_groups>)
before these ssl_sock.c function are called, leading some TLS stack to
refuse them if they do not support them. This is the case for some OpenSSL 3.5
stack with FIPS support. They do not support X25519.

To fix this, set the default QUIC ciphersuites and curves only if not already
set by the settings mentioned above.

Rename <quic_ciphers> global variable to <default_quic_ciphersuites>
and <quic_groups> to <default_quic_curves> to reflect the OpenSSL API naming.

These options are taken into an account by ssl_quic_initial_ctx()
which inspects these four variable before calling SSL_CTX_set_ciphersuites()
with <default_quic_ciphersuites> as parameter and SSL_CTX_set_curves() with
<default_quic_curves> as parameter if needed, that is to say, if no ciphersuites
and curves were set by "ssl-default-bind-ciphersuites", "ssl-default-bind-curves"
as global options  or "ciphersuites", "curves" as "bind" line options.
Note that the bind_conf struct is not modified when no "ciphersuites" or
"curves" option are used on "bind" lines.

On backend side, rely on ssl_sock_init_srv() to set the server ciphersuites
and curves. This function is modified to use respectively <default_quic_ciphersuites>
and <default_quic_curves> if no ciphersuites  and curves were set by
"ssl-default-server-ciphersuites", "ssl-default-server-curves" as global options
or "ciphersuites", "curves" as "server" line options.

Thank to @rwagoner for having reported this issue in GH #3194 when using
an OpenSSL 3.5.4 stack with FIPS support.

Must be backported as far as 2.6
2025-12-08 10:40:59 +01:00
Frederic Lecaille
3f5e73e83f BUG/MINOR: quic-be: missing connection stream closure upon TLS alert to send
This is the same issue as the one fixed by this commit:
   BUG/MINOR: quic-be: handshake errors without connection stream closure
But this time this is when the client has to send an alert to the server.
The fix consists in creating the mux after having set the handshake connection
error flag and error_code.

This bug was revealed by ssl/set_ssl_cafile.vtc reg test.

Depends on this commit:
     MINOR: quic: avoid code duplication in TLS alert callback

Must be backported to 3.3
2025-12-08 10:40:59 +01:00
Frederic Lecaille
e7b06f5e7a MINOR: quic: avoid code duplication in TLS alert callback
Both the OpenSSL QUIC API TLS alert callback ha_quic_ossl_alert() does exactly
the same thing than the one for quictls API, even if the parameter have different
types.

Call ha_quic_send_alert() quictls callback from ha_quic_ossl_alert OpenSSL
QUIC API callback to avoid such code duplication.
2025-12-08 10:40:59 +01:00
Frederic Lecaille
21293dd6c3 MINOR: quic: Add useful debugging traces in qc_idle_timer_do_rearm()
Traces were missing in this function.
Also add information about the connection struct from qc->conn when
initialized for all the traces.

Should be easily backported as far as 2.6.
2025-12-08 10:40:59 +01:00
Frederic Lecaille
c36e27d10e BUG/MINOR: quic-be: handshake errors without connection stream closure
This bug was revealed on backend side by reg-tests/ssl/del_ssl_crt-list.vtc when
run wich QUIC connections. As expected by the test, a TLS alert is generated on
servsr side. This latter sands a CONNECTION_CLOSE frame with a CRYPTO error
(>= 0x100). In this case the client closes its QUIC connection. But
the stream connection was not informed. This leads the connection to
be closed after the server timeout expiration. It shouls be closed asap.
This is the reason why reg-tests/ssl/del_ssl_crt-list.vtc could succeeds
or failed, but only after a 5 seconds delay.

To fix this, mimic the ssl_sock_io_cb() for TCP/SSL connections. Call
the same code this patch implements with ssl_sock_handle_hs_error()
to correctly handle the handshake errors. Note that some SSL counters
were not incremented for both the backends and frontends. After such
errors, ssl_sock_io_cb() start the mux after the connection has been
flagged in error. This has as side effect to close the stream
in conn_create_mux().

Must be backported to 3.3 only for backends. This is not sure at this time
if this bug may impact the frontends.
2025-12-08 10:40:59 +01:00
Frederic Lecaille
63273c795f BUG/MINOR: quic/ssl: crash in ClientHello callback ssl traces
Such crashes may occur for QUIC frontends only when the SSL traces are enabled.

ssl_sock_switchctx_cbk() ClientHello callback may be called without any connection
initialize (<conn>) for QUIC connections leading to crashes when passing
conn->err_code to TRACE_ERROR().

Modify the TRACE_ERROR() statement to pass this parameter only when <conn> is
initialized.

Must be backported as far as 3.2.
2025-12-08 10:40:59 +01:00
Willy Tarreau
cd959f1321 BUG/MEDIUM: config: ignore empty args in skipped blocks
As returned by Christian Ruppert in GH issue #3203, we're having an
issue with checks for empty args in skipped blocks: the check is
performed after the line is tokenized, without considering the case
where it's disabled due to outer false .if/.else conditions. Because
of this, a test like this one:

    .if defined(SRV1_ADDR)
        server srv1 "$SRV1_ADDR"
    .endif

will fail when SRV1_ADDR is empty or not set, saying that this will
result in an empty arg on the line.

The solution consists in postponing this check after the conditions
evaluation so that disabled lines are already skipped. And for this
to be possible, we need to move "errptr" one level above so that it
remains accessible there.

This will need to be backported to 3.3 and wherever commit 1968731765
("BUG/MEDIUM: config: solve the empty argument problem again") is
backported. As such it is also related to GH issue #2367.
2025-12-04 15:33:43 +01:00
Willy Tarreau
b29560f610 BUG/MEDIUM: connection: fix "bc_settings_streams_limit" typo
The keyword was correct in the doc but in the code it was spelled
with a missing 's' after 'settings', making it unavailable. Since
there was no other way to find this but reading the code, it's safe
to simply fix it and assume nobody relied on the wrong spelling.

In the worst case for older backports it can also be duplicated.

This must be backported to 3.0.
2025-12-04 15:26:54 +01:00
Frederic Lecaille
cdca48b88c BUG/MINOR: quic-be: Missing keywords array NULL termination
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
This bug arrived with this commit:
     MINOR: quic: implement cc-algo server keyword
where <srv> keywords list with a missing array NULL termination inside was
introduced to parse the QUIC backend CC algorithms.

Detected by ASAN during ssl/add_ssl_crt-list.vtc execution as follows:

***  h1    debug|==4066081==ERROR: AddressSanitizer: global-buffer-overflow on address 0x5562e31dedb8 at pc 0x5562e298951f bp 0x7ffe9f9f2b40 sp 0x7ffe9f9f2b38
***  h1    debug|READ of size 8 at 0x5562e31dedb8 thread T0
**** dT    0.173
***  h1    debug|    #0 0x5562e298951e in srv_find_kw src/server.c:789
***  h1    debug|    #1 0x5562e2989630 in _srv_parse_kw src/server.c:3847
***  h1    debug|    #2 0x5562e299db1f in parse_server src/server.c:4024
***  h1    debug|    #3 0x5562e2c86ea4 in cfg_parse_listen src/cfgparse-listen.c:593
***  h1    debug|    #4 0x5562e2b0ede9 in parse_cfg src/cfgparse.c:2708
***  h1    debug|    #5 0x5562e2c47d48 in read_cfg src/haproxy.c:1077
***  h1    debug|    #6 0x5562e2682055 in main src/haproxy.c:3366
***  h1    debug|    #7 0x7ff3ff867249 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
***  h1    debug|    #8 0x7ff3ff867304 in __libc_start_main_impl ../csu/libc-start.c:360
***  h1    debug|    #9 0x5562e26858d0 in _start (/home/flecaille/src/haproxy/haproxy+0x2638d0)
***  h1    debug|
***  h1    debug|0x5562e31dedb8 is located 40 bytes to the left of global variable 'bind_kws' defined in 'src/cfgparse-quic.c:255:28' (0x5562e31dede0) of size 120
***  h1    debug|0x5562e31dedb8 is located 0 bytes to the right of global variable 'srv_kws' defined in 'src/cfgparse-quic.c:264:27' (0x5562e31ded80) of size 56
***  h1    debug|SUMMARY: AddressSanitizer: global-buffer-overflow src/server.c:789 in srv_find_kw
***  h1    debug|Shadow bytes around the buggy address:
***  h1    debug|  0x0aacdc633d60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
***  h1    debug|  0x0aacdc633d70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
***  h1    debug|  0x0aacdc633d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
***  h1    debug|  0x0aacdc633d90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
***  h1    debug|  0x0aacdc633da0: 00 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9
***  h1    debug|=>0x0aacdc633db0: 00 00 00 00 00 00 00[f9]f9 f9 f9 f9 00 00 00 00
***  h1    debug|  0x0aacdc633dc0: 00 00 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9 f9
***  h1    debug|  0x0aacdc633dd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
***  h1    debug|  0x0aacdc633de0: 00 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9 f9 f9
***  h1    debug|  0x0aacdc633df0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
***  h1    debug|  0x0aacdc633e00: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
***  h1    debug|Shadow byte legend (one shadow byte represents 8 application bytes):

This should be backported where the commit above is supposed to be backported.
2025-12-03 11:07:47 +01:00
Amaury Denoyelle
47dff5be52 MINOR: quic: implement cc-algo server keyword
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
Extend QUIC server configuration so that congestion algorithm and
maximum window size can be set on the server line. This can be achieved
using quic-cc-algo keyword with a syntax similar to a bind line.

This should be backported up to 3.3 as this feature is considered as
necessary for full QUIC backend support. Note that this relies on the
serie of previous commits which should be picked first.
2025-12-01 15:53:58 +01:00
Amaury Denoyelle
4f43abd731 MINOR: quic: extract cc-algo parsing in a dedicated function
Extract code from bind_parse_quic_cc_algo() related to pure parsing of
quic-cc-algo keyword. The objective is to be able to quickly duplicate
this option on the server line.

This may need to be backported to support QUIC congestion control
algorithm support on the server line in version 3.3.
2025-12-01 15:06:01 +01:00
Amaury Denoyelle
979588227f MINOR: quic: define quic_cc_algo as const
Each QUIC congestion algorithm is defined as a structure with callbacks
in it. Every quic_conn has a member pointing to the configured
algorithm, inherited from the bind-conf keyword or to the default CUBIC
value.

Convert all these definitions to const. This ensures that there never
will be an accidental modification of a globally shared structure. This
also requires to mark quic_cc_algo field in bind_conf and quic_cc as
const.
2025-12-01 15:05:41 +01:00
Amaury Denoyelle
acbb378136 Revert "MINOR: quic: use dynamic cc_algo on bind_conf"
This reverts commit a6504c9cfb.

Each supported QUIC algo are associated with a set of callbacks defined
in a structure quic_cc_algo. Originally, bind_conf would use a constant
pointer to one of these definitions.

During pacing implementation, this field was transformed into a
dynamically allocated value copied from the original definition. The
idea was to be able to tweak settings at the listener level. However,
this was never used in practice. As such, revert to the original model.

This may need to be backported to support QUIC congestion control
algorithm support on the server line in version 3.3.
2025-12-01 14:18:58 +01:00
Remi Tricot-Le Breton
2b3d13a740 BUG/MINOR: jwt: Missing "case" in switch statement
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
Because of missing "case" keyword in front of the values in a switch
case statement, the values were interpreted as goto tags and the switch
statement became useless.

This patch should fix GitHub issue #3200.
The fix should be backported up to 2.8.
2025-11-28 16:36:46 +01:00
Willy Tarreau
e5658c52d0 BUG/MINOR: sock-inet: ignore conntrack for transparent sockets on Linux
As reported in github issue #3192, in certain situations with transparent
listeners, it is possible to get the incoming connection's destination
wrong via SO_ORIGINAL_DST. Two cases were identified thus far:
  - incorrect conntrack configuration where NOTRACK is used only on
    incoming packets, resulting in reverse connections being created
    from response packets. It's then mostly a matter of timing, i.e.
    whether or not the connection is confirmed before the source is
    retrieved, but in this case the connection's destination address
    as retrieved by SO_ORIGINAL_DST is the client's address.

  - late outgoing retransmit that recreates a just expired conntrack
    entry, in reverse direction as well. It's possible that combinations
    of RST or FIN might play a role here in speeding up conntrack eviction,
    as well as the rollover of source ports on the client whose new
    connection matches an older one and simply refreshes it due to
    nf_conntrack_tcp_loose being set by default.

TPROXY doesn't require conntrack, only REDIRECT, DNAT etc do. However
the system doesn't offer any option to know how a conntrack entry was
created (i.e. normally or via a response packet) to let us know that
it's pointless to check the original destination, nor does it permit
to access the local vs peer addresses in opposition to src/dst which
can be wrong in this case.

One alternate approach could consist in only checking SO_ORIGINAL_DST
for listening sockets not configured with the "transparent" option,
but the problem here is that our low-level API only works with FDs
without knowing their purpose, so it's unknown there that the fd
corresponds to a listener, let alone in transparent mode.

A (slightly more expensive) variant of this approach here consists in
checking on the socket itself that it was accepted in transparent mode
using IP_TRANSPARENT, and skip SO_ORIGINAL_DST if this is the case.
This does the job well enough (no more client addresses appearing in
the dst field) and remains a good compromise. A future improvement of
the API could permit to pass the transparent flag down the stack to
that function.

This should be backported to stable versions after some observation
in latest -dev.

For reference, here are some links to older conversations on that topic
that Lukas found during this analysis:

  https://lists.openwall.net/netdev/2019/01/12/34
  https://discourse.haproxy.org/t/send-proxy-not-modifying-some-traffic-with-proxy-ip-port-details/3336/9
  https://www.mail-archive.com/haproxy@formilux.org/msg32199.html
  https://lists.openwall.net/netdev/2019/01/23/114
2025-11-26 13:43:58 +01:00
Christopher Faulet
7d9cc28f92 Revert "BUG/MEDIUM: server/ssl: Unset the SNI for new server connections if none is set"
This reverts commit de29000e60.

The fix was in fact invalid. First it is not supprted by WolfSSL to call
SSL_set_tlsext_host_name with a hostname to NULL. Then, it is not specified
as supported by other SSL libraries.

But, by reviewing the root cause of this bug, it appears there is an issue
with the reuse of TLS sesisons. It must not be performed if the SNI does not
match. A TLS session created with a SNI must not be reused with another
SNI. The side effects are not clear but functionnaly speaking, it is
invalid.

So, for now, the commit above was reverted because it is invalid and it
crashes with WolfSSL. Then the init of the SSL connection must be reworked
to get the SNI earlier, to be able to reuse or not an existing TLS
session.
2025-11-26 12:05:43 +01:00
Maxime Henrion
d506c03aa0 BUG/MINOR: acme: fix ha_alert() call
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
A NULL pointer was passed as the format string, so this alert message
was never written.

Must be backported to 3.2.
2025-11-25 20:20:25 +01:00
Christopher Faulet
de29000e60 BUG/MEDIUM: server/ssl: Unset the SNI for new server connections if none is set
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
When a new SSL server connection is created, if no SNI is set, it is
possible to inherit from the one of the reused TLS session. The bug was
introduced by the commit 95ac5fe4a ("MEDIUM: ssl_sock: always use the SSL's
server name, not the one from the tid"). The mixup is possible between
regular connections but also with health-checks connections.

To fix the issue, when no SNI is set, for regular server connections and for
health-check connections, the SNI must explicitly be disabled by calling
ssl_sock_set_servername() with the hostname set to NULL.

Many thanks to Lukas for his detailed bug report.

This patch should fix the issue #3195. It must be backported as far as 3.0.
2025-11-25 16:32:46 +01:00
Amaury Denoyelle
a70816da82 BUG/MINOR: h3: handle properly buf alloc failure on response forwarding
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
Replace BUG_ON() for buffer alloc failure on h3_resp_headers_to_htx() by
proper error handling. An error status is reported which should be
sufficient to initiate connection closure.

No need to backport.
2025-11-25 15:55:08 +01:00
Amaury Denoyelle
ae96defaca BUG/MINOR: h3: do no crash on forwarding multiple chained response
h3_resp_headers_to_htx() is the function used to convert an HTTP/3
response into a HTX message. It was introduced on this release for QUIC
backend support.

A BUG_ON() would occur if multiple responses are forwarded
simultaneously on a stream without rcv_buf in between. Fix this by
removing it. Instead, if QCS HTX buffer is not empty when handling with
a new response, prefer to pause demux operation. This is restarted when
the buffer has been read and emptied by the upper stream layer.

No need to backport.
2025-11-25 15:52:37 +01:00
Amaury Denoyelle
a363b536a9 BUG/MINOR: server: fix srv_drop() crash on partially init srv
A recent patch has introduced free operation for QUIC tokens stored in a
server. These values are located in <per_thr> server array.

However, a server instance may be released prior to its full
initialization in case of a failure during "add server" CLI command. The
mentionned patch would cause a srv_drop() crash due to an invalid usage
of NULL <per_thr> member.

Fix this by adding a check on <per_thr> prior to dereference it in
srv_drop().

No need to backport.
2025-11-25 15:16:13 +01:00
Amaury Denoyelle
6c08eb7173 BUG/MINOR: quic: release BE quic_conn on connect failure
If quic_connect_server() fails, quic_conn FD will remain unopened as set
to -1. Backend connections do not have a fallback socket for future
exchange, contrary to frontend one which can use the listener FD. As
such, it is better to release these connections early.

This patch adjusts such failure by extending quic_close(). This function
is called by the upper layer immediately after a connect issue. In this
case, release immediately a quic_conn backend instance if the FD is
unset, which means that connect has previously failed.

Also, quic_conn_release() is extended to ensure that such faulty
connections are immediately freed and not converted into a
quic_conn_closed instance.

Prior to this patch, a backend quic_conn without any FD would remain
allocated and possibly active. If its tasklet is executed, this resulted
in a crash due to access to an invalid FD.

No need to backport.
2025-11-25 14:50:23 +01:00
Amaury Denoyelle
346631700d BUG/MINOR: quic: fix uninit list on show quic handler
A recent patch has extended "show quic" capability. It is now possible
to list a specific list of connections, either active frontend, closing
frontend or backend connections.

An issue was introduced as the list is local storage. As this command is
reentrant, show quic context must be extended so that the currently
inspected list is also saved.

This issue was reported via GCC which mentions an uninitilized value
depending on branching conditions.
2025-11-25 14:50:19 +01:00
Amaury Denoyelle
a3f76875f4 MINOR: quic: mark backend conns on show quic
Add an extra "(B)" marker when displaying a backend connection during a
"show quic". This is useful to differentiate them with the frontend side
when displaying all connections.
2025-11-25 14:31:27 +01:00
Amaury Denoyelle
e56fdf6320 MINOR: quic: dump backend connections on show quic
Add a new "be" filter to "show quic". Its purpose is to be able to
display backend connections. These connections can also be listed using
"all" filter.
2025-11-25 14:30:18 +01:00
Amaury Denoyelle
3685681373 MINOR: quic: add "clo" filter on show quic
Add a new filter "clo" for "show quic" command. Its purpose is to filter
output to only list closing frontend connections.
2025-11-25 14:30:18 +01:00
Amaury Denoyelle
49e6fca51b MINOR: quic: use separate global quic_conns FE/BE lists
Each quic_conn instance is stored in a global list. Its purpose is to be
able to loop over all known connections during "show quic".

Split this into two separate lists for frontend and backend usage.
Another change is that closing backend connections do not move into
quic_conns_clo list. They remain instead in their original list. The
objective of this patch is to reduce the contention between the two
sides.

Note that this prevents backend connections to be listed in "show quic"
now. This will be adjusted in a future patch.
2025-11-25 14:30:18 +01:00
Amaury Denoyelle
a5801e542d MINOR: quic: split global CID tree between FE and BE sides
QUIC CIDs are stored in a global tree. Prior to this patch, CIDs used on
both frontend and backend sides were mixed together.

This patch implement CID storage separation between FE and BE sides. The
original tre quic_cid_trees is splitted as
quic_fe_cid_trees/quic_be_cid_trees.

This patch should reduce contention between frontend and backend usages.
Also, it should reduce the risk of random CID collision.
2025-11-25 14:30:18 +01:00
Amaury Denoyelle
4b596c1ea8 BUG/MINOR: quic/server: free quic_retry_token on srv drop
A recent patch has implemented caching of QUIC token received from a
NEW_TOKEN frame into the server cache. This value is stored per thread
into a <quic_retry_token> field.

This field is an ist, first set to an empty string. Via
qc_try_store_new_token(), it is reallocated to fit the size of the newly
stored token. Prior to this patch, the field was never freed so this
causes a memory leak.

Fix this by using istfree() on <quic_retry_token> field during
srv_drop().

No need to backport.
2025-11-25 14:30:18 +01:00
Amaury Denoyelle
cbfe574d8a BUG/MEDIUM: quic: do not prevent sending if no BE token
For QUIC client support, a token may be emitted along with INITIAL
packets during the handshake. The token is encoded during emission via
qc_enc_token() called by qc_build_pkt().

The token may be provided from different sources. First, it can be
retrieved via <retry_token> quic_conn member when a Retry packet was
received. If not present, a token may be reused from the server cache,
populated from NEW_TOKEN received from previous a connection.

Prior to this patch, the last method may cause an issue. If the upper
connection instance is released prior to the handshake completion, this
prevents access to a possible server token. This is considered an error
by qc_enc_token(). The error is reported up to calling functions,
preventing any emission to be performed. In the end, this prevented the
either the full quic_conn release or subsizing into quic_conn_closed
until the idle timeout completion (30s by default). With abortonclose
set now by default on HTTP frontends, early client shutdowns can easily
cause excessive memory consumption.

To fix this, change qc_enc_token() so that if connection is closed, no
token is encoded but also no error is reported. This allows to continue
emission and permit early connection release.

No need to backport.
2025-11-25 14:30:18 +01:00
Jacques Heunis
91eb9b082b BUG/MINOR: freq_ctr: Prevent possible signed overflow in freq_ctr_overshoot_period
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
All of the other bandwidth-limiting code stores limits and intermediate
(byte) counters as unsigned integers. The exception here is
freq_ctr_overshoot_period which takes in unsigned values but returns a
signed value. While this has the benefit of letting the caller know how
far away from overshooting they are, this is not currently leveraged
anywhere in the codebase, and it has the downside of halving the positive
range of the result.

More concretely though, returning a signed integer when all intermediate
values are unsigned (and boundaries are not checked) could result in an
overflow, producing values that are at best unexpected. In the case of
flt_bwlim (the only usage of freq_ctr_overshoot_period in the codebase at
the time of writing), an overflow could cause the filter to wait for a
large number of milliseconds when in fact it shouldn't wait at all.

This is a niche possibility, because it requires that a bandwidth limit is
defined in the range [2^31, 2^32). In this case, the raw limit value would
not fit into a signed integer, and close to the end of the period, the
`(elapsed * freq)/period` calculation could produce a value which also
doesn't fit into a signed integer.

If at the same time `curr` (the number of events counted so far in the
current period) is small, then we could get a very large negative value
which overflows. This is undefined behaviour and could produce surprising
results. The most obvious outcome is flt_bwlim sometimes waiting for a
large amount of time in a case where it shouldn't wait at all, thereby
incorrectly slowing down the flow of data.

Converting just the return type from signed to unsigned (and checking for
the overflow) prevents this undefined behaviour. It also makes the range
of valid values consistent between the input and output of
freq_ctr_overshoot_period and with the input and output of other freq_ctr
functions, thereby reducing the potential for surprise in intermediate
calculations: now everything supports the full 0 - 2^32 range.
2025-11-24 14:10:13 +01:00
Amaury Denoyelle
2829165f61 BUG/MEDIUM: server: do not use default SNI if manually set
A new server feature "sni-auto" has been introduced recently. The
objective is to automatically set the SNI value to the host header if no
SNI is explicitely set.

  668916c1a2
  MEDIUM: server/ssl: Base the SNI value to the HTTP host header by default

There is an issue with it : server SNI is currently always overwritten,
even if explicitely set in the configuration file. Adjust
check_config_validity() to ensure the default value is only used if
<sni_expr> is NULL.

This issue was detected as a memory leak on <sni_expr> was reported when
SNI is explicitely set on a server line.

This patch is related to github feature request #3081.

No need to backport, unless the above patch is.
2025-11-24 11:45:18 +01:00
William Lallemand
5dbf06e205 MINOR: httpclient: complete the https log
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
The httpsclient_log_format variable lacks a few values in the TLS fields
that are now available as fetches.

On the backend side we have:

"%[fc_err]/%[ssl_fc_err,hex]/%[ssl_c_err]/%[ssl_c_ca_err]/%[ssl_fc_is_resumed] %[ssl_fc_sni]/%sslv/%sslc"

We now have enough sample fetches to have this equivalent in the
httpclient:

"%[bc_err]/%[ssl_bc_err,hex]/%[ssl_c_err]/%[ssl_c_ca_err]/%[ssl_bc_is_resumed] %[ssl_bc_sni]/%[ssl_bc_protocol]/%[ssl_bc_cipher]"

Instead of the current:

"%[bc_err]/%[ssl_bc_err,hex]/-/-/%[ssl_bc_is_resumed] -/-/-"
2025-11-22 12:29:33 +01:00
William Lallemand
0cae2f0515 BUG/MINOR: acme: warning ‘ctx’ may be used uninitialized
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
Please compiler with maybe-uninitialized warning

src/acme.c: In function ‘cli_acme_chall_ready_parse’:
include/haproxy/task.h:215:9: error: ‘ctx’ may be used uninitialized [-Werror=maybe-uninitialized]
  215 |         _task_wakeup(t, f, MK_CALLER(WAKEUP_TYPE_TASK_WAKEUP, 0, 0))
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/acme.c:2903:17: note: in expansion of macro ‘task_wakeup’
 2903 |                 task_wakeup(ctx->task, TASK_WOKEN_MSG);
      |                 ^~~~~~~~~~~
src/acme.c:2862:26: note: ‘ctx’ was declared here
 2862 |         struct acme_ctx *ctx;
      |                          ^~~

Backport to 3.2.
2025-11-21 23:04:16 +01:00
William Lallemand
d77d3479ed BUG/MINOR: acme: better challenge_ready processing
Improve the challenge_ready processing:

- do a lookup directly instead looping in the task tree
- only do a task_wakeup when every challenges are ready to avoid starting
  the task and stopping it just after
- Compute the number of remaining challenge to setup
- Output a message giving the number of remaining challenges to setup
  and if the task started again.

Backport to 3.2.
2025-11-21 22:47:52 +01:00
William Lallemand
548e7079cd BUG/MINOR: acme: prevent creating map entries with dns-01
We don't need map entries with dns-01.

The patch must be backported to 3.2.
2025-11-21 12:28:41 +01:00
William Lallemand
26093121a3 BUG/MINOR: acme: handle multiple auth with the same name
In case of the dns-01 challenge, it is possible to have a domain
"example.com" and "*.example.com" in the same request. This will create
2 different auth objects, which need 2 different challenges.

However the associated domain is "example.com" for both auth objects.

When doing a "challenge_ready", the algorithm will break at the first
domain found. But since you can have multiple time the same domain in
this case, breaking at the first one prevent to have all auth objects in
a ready state.

This patch just remove the break so we can loop on every auth objects.

Must be backported to 3.2.
2025-11-21 12:28:41 +01:00
Amaury Denoyelle
bbd83e3de9 BUG/MINOR: mux-quic: check access on qcs stream-endpoint
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
Since the following commit, allocation of stream-endpoint has been
delayed. The objective is to allocate it only for QCS attached to an
upper stream object.

  commit e6064c5616
  OPTIM: mux-quic: delay FE sedesc alloc to stream creation

However, some MUX functions are unsafe as qcs->sd is dereferenced
without any check on it which will result in a crash. Fix this by
testing that qcs->sd is allocated before using it.

This does not need to be backported, unless the above patch is.
2025-11-21 11:16:07 +01:00
Frederic Lecaille
91f479604e BUG/MEDIUM: quic-be: quic_conn_closed buffer overflow
This bug impacts only the backends.

Recent commits have modified quic_rx_pkt_parse() for the QUIC backend to handle the
retry token, and version negotiation. This function is called for the quic_conn
even when is closing state (so for the quic_conn_closed struct). The quic_conn
struct and quic_conn_closed struct share some members thank to the leading
QUIC_CONN_COMMON struct. The recent modification impacts some members which do not
exist for the quic_connn_closed struct, leading to buffer overflows if modified.

For the backends only this patch:
  1- silently drops the Retry packet (received/parsed only by backends)
  2- silently drops the Initial packets received in closing state

This is safe for the Initial packets because in closing state the datagrams
are entirely skipped thanks to qc_rx_check_closing() in quic_dgram_parse().

No backport needed because the backend support arrived with the current dev.
2025-11-21 10:49:44 +01:00
Amaury Denoyelle
e6064c5616 OPTIM: mux-quic: delay FE sedesc alloc to stream creation
On frontend side, a stream-endpoint is allocated on every qcs_new()
invokation. However, this is only used for bidirectional request
streams.

This patch delays stream-endpoint allocation to qcs_attach_sc(), just
prior the instantiation of the upper stream object. This does not bring
any behavior change but is a nice optimization.
2025-11-21 10:34:08 +01:00
Amaury Denoyelle
4fb8908605 BUG/MINOR: mux-quic: fix sedesc leak on BE side
On backend side, streams are instantiated prior to their QCS MUX
counterpart. Thus, QCS can reuse the stream-endpoint already allocated
with the streams, either on qmux_init() or attach operation.

However, a stream-endpoint is also always allocated in every qcs_new()
invokation. For backend QCS, it is thus overwritten on
qmux_init()/attach operation. This causes a memleak.

Fix this by restricting allocation of stream-endpoint only for frontend
connection.

This does not need to be backported.
2025-11-21 10:34:08 +01:00
Amaury Denoyelle
9f16c64a8c MINOR: h3: adjust sedesc update for known input payload len 2025-11-21 10:34:08 +01:00
Christopher Faulet
0629ce8f4b BUG/MEDIUM: cli: State the cli have no more data to deliver if it yields
A regression was introduced in the commit 2d7e3ddd4 ("BUG/MEDIUM: cli: do
not return ACKs one char at a time"). When the CLI is processing a command
line, we no longer send response immediately. It is especially useful for
clients sending a bunch of commands with very short response.

However, in that state, the CLI applet must state it has no more data to
deliver. Otherwise it will be woken up again and again because data are
found in its output buffer with no blocking conditions. In worst cases, if
the command rate is really high, this can trigger the watchdog.

This patch must be backported where the patch above is, so probably as far
as 3.0.
2025-11-21 10:00:15 +01:00
Christopher Faulet
dfdccbd2af BUG/MEDIUM: applet: Fix conditions to detect spinning loop with the new API
There was a mixup between read/send events and ability for an applet to
receive and send. The fix seems obvious by reading it. The call-rate must be
incremented when nothing was received from the applet while it was allowed
and nothing was sent to the applet while it was allowed.

This patch must be backported as far as 3.0.
2025-11-21 09:41:05 +01:00
Willy Tarreau
4cbff2cad9 MINOR: limits: display the computed maxconn using ha_notice()
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
The computed maxconn was only displayed in verbose or debug modes. This
is too bad because lots of users just don't know what they're starting
with and can be trapped when an environment changes. Let's use ha_notice()
instead of a conditional fprintf() so that it gets displayed right after
the other startup messages, hoping that users will get used to seeing it
and more easily spot anomalies. See github issue #3191 for more context.
2025-11-20 18:38:09 +01:00
Willy Tarreau
05c409f1be BUG/MEDIUM: connection/ssl: also fix the ssl_sock_io_cb() regarding idle list
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
The fix in commit 9481cef948 ("BUG/MEDIUM: connection: do not reinsert a
purgeable conn in idle list") is also needed for ssl_sock_io_cb() which
can also release an idle connection and must perform the same checks.
This fix must be backported to all stable versions containing the fix
above.
2025-11-20 17:19:50 +01:00
Amaury Denoyelle
b2664d4450 BUG/MINOR: quic: flag conn with CO_FL_FDLESS on backend side
Connection struct defines an handle which can point to either a FD or a
quic_conn. On the latter case, CO_FL_FDLESS must be set. This is already
the case on frontend side.

This patch fixes QUIC backend support. Before setting connection handle
member to a quic_conn instance, ensure that CO_FL_FDLESS flag is set on
the connection.

Prior to this patch, crash can occur in "show sess all".

No need to backport.
2025-11-20 16:44:03 +01:00
Amaury Denoyelle
cd2962ee64 MINOR: quic: store source address for backend conns
quic_conn has a local_addr member which is used to store the connection
source address. On backend side, this member is initialized to NULL as
the address is not yet known prior to connect. With this patch,
quic_connect_server() is extended so that local_addr is updated after
connect() success.

Also, quic_sock_get_src() is completed for the backend side which now
returns local_addr member. This step is necessary to properly support
fetches bc_src/bc_src_port.
2025-11-20 16:44:03 +01:00
Christopher Faulet
0a7f3954b5 BUG/MEDIUM: config: Use the mux protocol ALPN by default for listeners if forced
Since the commit 5003ac7fe ("MEDIUM: config: set useful ALPN defaults for
HTTPS and QUIC"), the ALPN is set by default to "h2,http/1.1" for HTTPS
listeners. However, it is in conflict with the forced mux protocol, if
any. Indeed, with "proto" keyword, the mux can be forced. In that case, some
combinations with the default ALPN will triggers connections errors.

For instance, by setting "proto h2", it will not be possible to use the H1
multiplexer. So we must take care to not advertise it in the ALPN. Worse,
since the commit above, most modern HTTP clients will try to use the H2
because it is advertised in the ALPN. By setting "proto h1" on the bind line
will make all the traffic rejected in error.

To fix the issue, and thanks to previous commits, if it is defined, we are
now relying on the ALPN defined by the mux protocol by default. The H1
multiplexer (only the one that can be forced) defines it to "http/1.1" while
the H2 multiplexer defines it to "h2". So by default, if one or another of
these muxes is forced, and if no ALPN is set, the mux ALPN is used.

Other multiplexers are not defining any default ALPN for now, because it is
useless. In addition, only the listeners are concerned because there is no
default ALPN on the server side.Finally, there is no tests performed if the
ALPN is forced on the bind line. It is the user responsibility to properly
configure his listeners (at least for now).

This patch depends on:
  * MINOR: config: Do proto detection for listeners before checks about ALPN
  * MINOR: muxes: Support an optional ALPN string when defining mux protocols

The series must be backported as far as 2.8.
2025-11-20 16:14:52 +01:00
Christopher Faulet
2ef8b91a00 MINOR: config: Do proto detection for listeners before checks about ALPN
The verification of any forced mux protocol, via the "proto" keyword, for
listeners is now performed before any tests on the ALPN. It will be
mandatory to be able to force the default ALPN, if not forced on the bind
line.

This patch will be mandatory for the next fix.
2025-11-20 16:14:52 +01:00
Christopher Faulet
8e08a635eb MINOR: muxes: Support an optional ALPN string when defining mux protocols
When a multiplexer protocol is defined, it is now possible to specify the
ALPN it supports, in binary format. This info is optionnal. For now only the
h2 and the h1 multiplexers define an ALPN because this will be mandatory for
a fix. But this could be used in future for different purpose.

This patch will be mandatory for the next fix.
2025-11-20 16:14:52 +01:00
Olivier Houchard
e9d34f991e BUG/MEDIUM: queues: Don't forget to unlock the queue before exiting
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
In assign_server_and_queue(), there's a rare case when the server was
full, so we created a pendconn, another server was considered but in the
meanwhile the pendconn was unqueued already, so we just left the
function. We did so, however, while still holding the queue lock, which
will ultimately lead to a deadlock, and ultimately the watchdog would
kill the process.
To fix that, just unlock the queue before leaving.

This should be backported to 3.2.
2025-11-20 13:57:06 +01:00
William Lallemand
e0665d4ffe BUG/MINOR: acme: alert when the map doesn't exist at startup
When configuring an acme section with the 'map' keyword, the user must
use an existing map. If the map doesn't exist, a log will be emitted
when trying to add the challenge to the map.

This patch change the behavior by checking at startup if the map exists,
so haproxy would warn and won't start with a non-existing map.

This must be backported in 3.2.
2025-11-20 12:22:19 +01:00
Frederic Lecaille
fab7da0fd0 BUG/MEDIUM: quic-be/ssl_sock: TLS callback called without connection
Contrary to TCP, QUIC does not SSL_free() its SSL *  object when its ->close()
XPRT callback is called. This has as side effect to trigger some BUG_ON(!conn)
with <conn> the connection from TLS callbacks registered at configuration
parsing time, so after this <conn> have been released.

This is the case for instance with ssl_sock_srv_verifycbk() whose role is to
add some checks to the built-in server certificate verification process.

This patch prevents the pointer to <conn> dereferencing inside several callbacks
shared between TCP and QUIC.

Thank you to @InputOutputZ for its report in GH #3188.

As the QUIC backend feature arrived with the current 3.3 dev, no need to backport.
2025-11-20 11:36:57 +01:00
Willy Tarreau
8438ca273f MINOR: limits: explain a bit better what to do when fd limits are exceeded
As shown in github issue #3191, the error message shown when FD limits
are exceeded is not very useful as-is, since the current hard limit is
not displayed, and no suggestion is made about what to change in the
config. Let's explain about maxconn/ulimit-n/fd-hard-limit, suggest
dropping them or setting them to a context-based value at roughly 49%
of the current limit minus the known used FDs for listeners and checks.
This allows common "large" hard limits to report mostly round maxconns.
Example:

  [ALERT]    (25330) : [haproxy.main()] Cannot raise FD limit to 4001020,
  current limit is 1024 and hard limit is 4096. You may prefer to let
  HAProxy adjust the limit by itself; for this, please just drop any
  'maxconn' and 'ulimit-n' from the global section, and possibly add
  'fd-hard-limit' lower than this hard limit. You may also force a new
  'maxconn' value that is a bit lower than half of the hard limit minus
  listeners and checks. This results in roughly 1500 here.
2025-11-20 08:44:52 +01:00
Willy Tarreau
91d4f4f618 MINOR: limits: keep a copy of the rough estimate of needed FDs in global struct
It's always a pain to guess the number of FDs that can be needed by
listeners, checks, threads, pollers etc. We have this estimate in
global.maxsock before calling set_global_maxconn(), but we lose it
the line after. Let's copy it into global.est_fd_usage and keep it.
This will be helpful to try to provide more accurate suggestions for
maxconn.
2025-11-20 08:44:52 +01:00
Frederic Lecaille
2c6720a163 MINOR: quic: uneeded xprt context variable passed as parameter
This quic_conn ->xrpt_ctx is passed to qc_send_ppkts(), the quic_conn is retrieved
from this context to be used inside this function and it is not used at all
by this function.

This patch simply directly passes the quic_conn to qc_send_ppkts(). This is only
what this function needs.
2025-11-20 08:17:44 +01:00
Amaury Denoyelle
d54d78fe9a BUG/MINOR: quic: fix FD usage for quic_conn_closed on backend side
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
On the frontend side, QUIC transfer can be performed either via a
connection owned FD or multiplex on the listener one. When a quic_conn
is freed and converted to quic_conn_closed instance, its FD if open is
closed and all exchanges are now multiplex via the listener FD.

This is different for the backend as connections only has the choice to
use their owned FD. Thus, special care care must be taken when freeing a
connection and converting it to a quic_conn_closed instance. In this
case, qc_release_fd() is delayed to the quic_conn_closed release.

Furthermore, when the FD is transferred, its iocb and owner fields are
updated to the new quic_conn_closed instance. Without it, a crash will
occur when accessing the freed quic_conn tasklet. A newly dedicated
handler quic_conn_closed_sock_fd_iocb is used to ensure access to
quic_conn_closed members only.
2025-11-19 16:02:22 +01:00
Amaury Denoyelle
46c5c232d7 BUG/MINOR: quic: do not decrement jobs for backend conns
jobs is a global counter which serves to account activity through the
whole process. Soft-stop procedure will wait until this counter is
resetted to the nul value.

jobs is not used for backend connections. Thus, it is not incremented
when a QUIC backend connection is instantiated as expected. However,
decrement is performed on all sides during quic_conn_release(). This
causes the counter wrapping.

Fix this by decrementing jobs only for frontend connections. Without
this patch, soft stop procedure will hang indefinitely if QUIC backend
connections were in use.
2025-11-19 16:02:22 +01:00
Amaury Denoyelle
1a22caa6ed MINOR: quic: fix trace on quic_conn_closed release
Adjust leaving trace of quic_release_cc_conn() so that the end of the
function is properly reported.
2025-11-19 16:02:22 +01:00
Amaury Denoyelle
e55bcf5746 BUG/MINOR: mux-quic: implement max-reuse server parameter
Properly implement support for max-reuse server keyword. This is done by
adding a total count of streams seen for the whole connection. This
value is used in avail_streams callback.
2025-11-19 16:02:22 +01:00
William Lallemand
c8540f7437 BUG/MINOR: ssl: remove dead code in ssl_sock_from_buf()
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
When haproxy is compiled in -O0, the SSL_get_max_early_data() symbol is
used in the generated assembly, however -O2 seems to remove this symbol
when optimizing the code.

It happens because `if conn_is_back(conn)` and `if
(objt_listener(conn->target))` are opposed conditions, which mean we
never use the branch when objt_listener(conn->target) is true.

This patch removes the dead code. Bonus: SSL_get_max_early_data() is not
implemented in rustls, and that's the only thing preventing to start
with it.

This can be backported in every stable branches.
2025-11-19 11:00:05 +01:00
William Lallemand
177816d2b8 BUG/MINOR: acme: P-256 doesn't work with openssl >= 3.0
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
When trying to use the P-256 curve in the acme configuration with
OpenSSL 3.x, the generation of the account was failing because OpenSSL
doesn't return a NIST or SECG curve name, but a ANSI X9.62 one.

Since the ANSI X9.62 curve names were not in the list, it couldn't match
anything supported.

This patch fixes the issue by adding both prime192v1 and prime256v1 name
in the struct curve array which is used during curve parsing.

Must be backported to 3.2.
2025-11-18 11:34:28 +01:00
William Lallemand
9bf01a0d29 BUG/MINOR: mworker: wrong signals during startup
Since the new master-worker model in 3.1, signals are registered in
step_init_3(). However, those signals were supposed to be registered
only for the worker or the standalone mode. It would call the wrong
callback in the master even during configuration parsing.

The patch set the signals handler to NULL for the master so it does
nothing until they really are registered.

Must be backported as far as 3.1.
2025-11-18 10:27:34 +01:00
William Lallemand
709cde6d08 BUG/MEDIUM: mworker: signals inconsistencies during startup and reload
Since haproxy 3.1, the master-worker mode changed to let the worker
parse the configuration instead of the master.

Previously, signals were blocked during configuration parsing and
unblocked before entering the polling loop of the master. This way it
was impossible to start a reload during the configuration parsing.

But with the new model, the polling loop is started in the master before
the configuration parsing is finished, and the signals are still
unblocked at this step. Meaning that it is possible to start a reload
while the configuration is parsing.

This patch reintroduce the behavior of blocking the signals during
configuration parsing adapted to the new model:

- Before the exec() of the reload, signals are blocked.
- When entering the polling loop, the SIGCHLD is unblocked because it is
  required to get a failure during configuration parsing in the worker
- Once the configuration is parsed, upon success in _send_status() or
  upon failure in run_master_in_recovery_mode() every signals are unblocked.

This patch must be backported as far as 3.1.
2025-11-18 10:05:42 +01:00
William Lallemand
b38405d156 CLEANUP: startup: move confusing msg variable
Move the char *msg variable declared in main() in a sub-block since
there's already multiple msg variable in other sub-blocks in this
function.

Also make it const.
2025-11-18 09:43:25 +01:00
Frederic Lecaille
37d01eea37 BUG/MEDIUM: quic-be: prevent use of MUX for 0-RTT sessions without secrets
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
The QUIC backend crashes when its peer does not support 0-RTT. In this case,
when the sessions are reused, no early-data level secrets are derived by
the TLS stack. This leads to crashes from qc_send_mux() which does not suppose
that both early-data level (qc->eel) and application level (qc->ael) cipher levels
could be non initialized.

To fix this:
  - prevent qc_send_mux() to send data if these two encryption level are not
    intialized. In this case it returns QUIC_TX_ERR_NONE;
  - avoid waking up the MUX from XPRT ->start() callback if the MUX is ready
    but without early-data level secrets to send them;
  - ensure the MUX is woken up by qc_ssl_do_handshake() after handshake completion
    if it is ready calling qc_notify_send()

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

No need to backport because QUIC backends is a current 3.3 development feature.
2025-11-17 15:40:24 +01:00
William Lallemand
0367227375 MEDIUM: mworker: set the mworker-max-reloads to 50
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
There was no mworker-max-reload value by default, it was set to INT_MAX
so this was impossible to reach.

The default value is now 50, which is still high, but no workers should
undergo that much reloads. Meaning that a worker will be killed with
SIGTERM if it reach this much reloads.
2025-11-17 11:54:30 +01:00
Amaury Denoyelle
c67a614e45 MINOR: quic: remove <ipv4> arg from qc_new_conn()
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
Remove <ipv4> argument from qc_new_conn(). This parameter is unnecessary
as it can be derived from the family type of the addresses also passed
as argument.
2025-11-17 10:20:54 +01:00
Amaury Denoyelle
133f100467 MINOR: quic: refactor qc_new_conn() prototype
The objective of this patch is to streamline qc_new_conn() usage so that
it is similar for frontend and backend sides.

Previously, several parameters were set only for frontend connections.
These arguments are replaced by a single quic_rx_packet argument, which
represents the INITIAL packet triggering the connection allocation on
the server side. For a QUIC client endpoint, it remains NULL. This usage
is consider more explicit.

As a minor change, <target> is moved as the first argument of the
function. This is considered useful as this argument determines whether
the connection is a frontend or backend entry.

Along with these changes, qc_new_conn() documentation has been reworded
so that it is now up-to-date with the newest usage.
2025-11-17 10:13:40 +01:00
Amaury Denoyelle
035c026220 MINOR: quic: support multiple random CID generation for BE side
When a new backend connection is instantiated, a CID is first randomly
generated. It will serve as the first DCID for incoming packets from the
server. Prior to this patch, if the generated CID caused a collision
with an other entries from another connection, an error is reported and
the connection cannot be allocated.

This patch improves this procedure by implementing retries when a
collision occurs. Now, at most three attemps will be performed before
giving up. This is the same procedure already performed for CIDs
instantiated after RETIRE_CONNECTION_ID frame parsing.

Along with this functional change, qc_new_conn() is refactored for
backend instantiation. The CID generation is extracted from it and the
value is passed as an argument. This is considered cleaner as the code
is more similar between frontend and backend sides.
2025-11-17 10:11:04 +01:00
Amaury Denoyelle
8720130cc7 MINOR: quic: do not use quic_newcid_from_hash64 on BE side
quic_newcid_from_hash64 is an external callback. If defined, it serves
as a CID method generation, as an alternative to the default random
implementation.

This mechanism was not correctly implemented on the backend side.
Indeed, <hash64> quic_conn member is only setted for frontend
connections. The simplest solution would be to properly define it also
for backend ones. However, quic_newcid_from_hash64 derivation is really
only useful for the frontend side for now. Thus, this patch disables
using it on the backend side in favor of the default random generator.

To implement this, quic_cid_generate() is splitted in two functions, for
both methods of CIDs generation. This is the responsibility of the
caller to select the proper method. On backend side, only random
implementation is now used.
2025-11-17 10:11:04 +01:00
Christopher Faulet
fc6e3e9081 MINOR: stick-tables: Rename stksess shards to use buckets
The shard keyword is already used by the peers and on the server lines. And
it is unrelated with the session keys distribution. So instead of talking
about shard for the session key hashing, we now use the term "bucket".
2025-11-17 07:42:51 +01:00
Frederic Lecaille
54eeda4b01 BUG/MINOR: quic-be: backend SSL session reuse fix (OpenSSL 3.5)
This bug impacts only the QUIC backends when haproxy is compiled against
OpenSSL 3.5 with QUIC API(HAVE_OPENSSL_QUIC).

The QUIC clients could not reuse their SSL session because the TLS tickets
received from the servers could not be provided to the TLS stack. This should
be done when the stack calls ha_quic_ossl_crypto_recv_rcd()
(OSSL_FUNC_SSL_QUIC_TLS_CRYPTO_RECV_RCD callback).

According to OpenSSL team, an SSL_read() call must be done after the handshake
completion. It seems the correct location is at the same level as for
SSL_process_quic_post_handshake() for quictls.

Thank you to @mattcaswell, @Sashan and @vdukhovni for having helped in solving
this issue.

Must be backported to 3.1
2025-11-14 17:50:49 +01:00
Frederic Lecaille
644bf585c3 CLEANUP: quic: Missing succesful SSL handshake backend trace (OpenSSL 3.5)
This very minor issue impacts only the backend when compiled against OpenSSL 3.5
with QUIC API (HAVE_OPENSSL_QUIC).

The "SSL handshake OK" trace was not dumped by a TRACE() call. This was very
annoying when debugging.

Modify the concerned code section which is a bit ugly and simplify it.
The TRACE() call is done at a unique location for now on.

Should be backported to 3.2 to ease any further backport.
2025-11-14 17:50:49 +01:00