]> git.kaiwu.me - haproxy.git/log
haproxy.git
25 hours agoBUG/MINOR: mqtt: connack parser returns MQTT_NEED_MORE_DATA on unknown property
Willy Tarreau [Mon, 11 May 2026 13:32:34 +0000 (15:32 +0200)]
BUG/MINOR: mqtt: connack parser returns MQTT_NEED_MORE_DATA on unknown property

In mqtt_parse_connack(), the switch statement's default case for unknown
MQTT properties was using 'return 0' which returns MQTT_NEED_MORE_DATA.
This is misleading: an unknown property should be treated as an invalid
message (MQTT_INVALID_MESSAGE), like other functions do. This branches to
the "end" label without touching the preset return value instead. This can
be backported if needed.

25 hours agoBUG/MINOR: cfgcond: make KQUEUE check for GTUNE_USE_KQUEUE not GTUNE_USE_EPOLL
Willy Tarreau [Mon, 11 May 2026 13:27:51 +0000 (15:27 +0200)]
BUG/MINOR: cfgcond: make KQUEUE check for GTUNE_USE_KQUEUE not GTUNE_USE_EPOLL

In cfg_eval_cond_enabled(), the "KQUEUE" option incorrectly checks
GTUNE_USE_EPOLL instead of GTUNE_USE_KQUEUE. This is a copy-paste bug
from the preceding EPOLL case. It can be backported though it's harmless.

25 hours agoBUG/MINOR: cache: fix memory leak in parse_cache_rule error path
Willy Tarreau [Mon, 11 May 2026 13:26:32 +0000 (15:26 +0200)]
BUG/MINOR: cache: fix memory leak in parse_cache_rule error path

When the filter config (fconf) allocation fails in parse_cache_rule,
the previously allocated cache_flt_conf (cconf) and its strdup'd name
string are not freed. The error path only freed cconf but not
cconf->c.name, causing a memory leak.

No backport is needed.

25 hours agoBUG/MINOR: uri-auth: avoid leaks on initialization error
Willy Tarreau [Mon, 11 May 2026 13:23:18 +0000 (15:23 +0200)]
BUG/MINOR: uri-auth: avoid leaks on initialization error

When stats_add_scope() and stats_add_auth() fail to initialize a field,
they just leave a partially allocated and initialized structure behind
them that is leaked. The whole architecture doesn't provide clean
unrolling abilities since everything is shared and assigned unconditionally,
but let's at least release what was just allocated. The whole approach would
probably deserve being revisited if one day this becomes more dynamic.

No backport needed.

25 hours agoBUG/MINOR: auth: free user groups on error paths in userlist_postinit()
Willy Tarreau [Mon, 11 May 2026 13:06:41 +0000 (15:06 +0200)]
BUG/MINOR: auth: free user groups on error paths in userlist_postinit()

In userlist_postinit(), when an error occurs (missing group, missing user, or
allocation failure), the function returned immediately without freeing the
auth_groups_list linked lists that were built for all users in the first loop.
Each user's curuser->u.groups pointed to these allocated nodes, which leaked
on every error path.

Fix by replacing direct returns with a goto to a centralized cleanup label
that frees all users' groups lists before returning the error. Also fix a
trailing double space in one error return statement while refactoring.

Note that the impact is very low since we're supposed to fail to boo after
such errors.

25 hours agoBUG/MINOR: tools: fix memory leak in env_expand() error path
Willy Tarreau [Mon, 11 May 2026 13:04:19 +0000 (15:04 +0200)]
BUG/MINOR: tools: fix memory leak in env_expand() error path

When my_realloc2() fails in env_expand(), the code jumps to 'leave:' and
returns NULL, but the original input 'in' is never freed (it's only freed
at line 4919 in the success case). Given that callers typically pass it
the direct return of strdup(), it looks like it is expected to always be
freed. This can be backported everywhere.

25 hours agoBUG/MINOR: http-act: set-status() must check the response message, not the request
Willy Tarreau [Mon, 11 May 2026 13:01:30 +0000 (15:01 +0200)]
BUG/MINOR: http-act: set-status() must check the response message, not the request

action_http_set_status() checks for soft rewrite on the request message
by mistake instead of the response message. This could possibly cause a
rewrite failure when soft rewrite is enabled since it will not be seen
there, though the impact is extremely low. It can be backported.

25 hours agoBUG/MINOR: http-fetch: make http_first_req() check for HTTP first
Willy Tarreau [Mon, 11 May 2026 12:58:45 +0000 (14:58 +0200)]
BUG/MINOR: http-fetch: make http_first_req() check for HTTP first

smp_fetch_http_first_req() reads ->txn.http->flags without first
checking if txn.http is properly allocated. In theory if called from
the wrong context it could crash, even though tests where it's called
from "tcp-request content" don't seem to have any effect. Let's fix
it regardless, at least to dissipate the doubt. It can be backported
everywhere.

25 hours agoBUG/MINOR: http-fetch: fix smp_fetch_hdr_ip()'s handling of brackets for IPv6
Willy Tarreau [Mon, 11 May 2026 12:56:22 +0000 (14:56 +0200)]
BUG/MINOR: http-fetch: fix smp_fetch_hdr_ip()'s handling of brackets for IPv6

IPv6 addresses can be read enclosed in brackets, but the length of the
string is not checked before checking them. If by lack of luck, the
buffer is empty but already contains '[' in the first place, we'd read
the byte at position -1, possibly crashing (even though in practice it
will not since allocated blocks will be precedeed by the malloc meta-
data). At least it could make asan/valgrind unhappy.

This can be backported to all versions.

25 hours agoBUG/MINOR: mux-h1: only check h1s if not NULL
Willy Tarreau [Mon, 11 May 2026 12:44:12 +0000 (14:44 +0200)]
BUG/MINOR: mux-h1: only check h1s if not NULL

Since we can emit glitches during an H2 upgrade, we no longer have a
guaranteed h1s, so _h1_report_glitch() must check h1s before
dereferencing it. No backport is needed as this arrived in 3.4-dev11
with commit 72fd357814 ("MEDIUM: mux-h1: Return an error on h2 upgrade
attempts if not allowed").

25 hours agoCLEANUP: h1/htx: fix a few typos in warning, debug and trace messages
Willy Tarreau [Sun, 10 May 2026 17:39:25 +0000 (17:39 +0000)]
CLEANUP: h1/htx: fix a few typos in warning, debug and trace messages

Just a few minor user visible issues issues found in mux_h1 and http_htx
(traces, warnings and debug output). This may be backported though isn't
important at all.

25 hours agoCLEANUP: tree-wide: fix typos in non user-visible comments in 15 files
Willy Tarreau [Sun, 10 May 2026 17:36:51 +0000 (17:36 +0000)]
CLEANUP: tree-wide: fix typos in non user-visible comments in 15 files

This fixes typos and spelling mistakes in the following files:

  channel-t.h channel.h filters-t.h http_htx.h htx-t.h tools.h
  cfgcond.c channel.c flt_http_comp.c http_ana.c htx.c mqtt.c
  mux_h1.c regex.c stats-proxy.c

32 hours agoBUG/MINOR: cfgparse-listen: do not emit extraneous line in rule order warnings
Willy Tarreau [Mon, 11 May 2026 07:32:41 +0000 (09:32 +0200)]
BUG/MINOR: cfgparse-listen: do not emit extraneous line in rule order warnings

Some functions such as tcp_parse_tcp_req() are able to emit their own
warnings by relying on warnif_misplaced_*() which directly prints the
warning. However when doing so they still increment the warning counter
which makes cfg_parse_listen() try to emit it, except that what's in the
variable is NULL, so we end up with:

  [WARNING]  (260) : config : parsing [/etc/haproxy/haproxy.cfg:17] : (null)

Let's just check the errmsg variable before printing the error. If it's
NULL, it's because the message was already printed.

This can be backported to all branches.

32 hours agoMINOR: lb: make LB initialization even more declarative
Maxime Henrion [Wed, 29 Apr 2026 17:56:34 +0000 (13:56 -0400)]
MINOR: lb: make LB initialization even more declarative

This lets lb_ops specify the conditions necessary to bind to this set of
ops. The condition is expressed as a list of mask and match fields on
the algorithm flags. This is then used in proxy_finalize() to locate the
lb_ops corresponding to the current configuration, by iterating  over
the list of lb_ops structures. This list is implemented using the same
mechanisms used for configuration keywords: an INITCALL1 macro to a
registration function.

This also moves the lookup and property flags into the lb_ops structure
that were previously applied manually on a case by case basis.

2 days agoMINOR: mux-h2: consider the elastic streams limit on frontend
Willy Tarreau [Sat, 9 May 2026 15:58:31 +0000 (17:58 +0200)]
MINOR: mux-h2: consider the elastic streams limit on frontend

Now the streams-elasticity limit applies to h2 frontend connections.
It allows to reduce the number of advertised streams based on the
number of concurrent connections.

2 days agoMINOR: connection: add a function to calculate elastic streams limit
Willy Tarreau [Sat, 9 May 2026 14:37:25 +0000 (16:37 +0200)]
MINOR: connection: add a function to calculate elastic streams limit

This adds a new tune.streams-elasticity parameter. This parameter
indicates, as a percentage, the average number of streams per connection
at full load. It is used to calculate limits of the number of streams to
advertise on new connections. 0 means that no such limit is set.

When a limit is set, the new function conn_calc_max_streams() determines
the optimal number of streams to allow on a connection. It will assign at
least the ratio of streams left to connections left, and at least a fair
share of what's left times the number of desired streams. It will always
ensure that each connection gets at least 1 stream, and everything beyond
this will be evenly distributed. For now the function is not used.

2 days agoMINOR: tinfo: store the number of committed extra streams in the tgroup
Willy Tarreau [Sat, 9 May 2026 14:19:54 +0000 (16:19 +0200)]
MINOR: tinfo: store the number of committed extra streams in the tgroup

In order to be able to enforce global streams limitations, we'll first
have to be able to account how many streams we promised to serve via
frontend muxes. We'll always need to support at least one stream, which
is why here we're only counting extra streams beyond the first one. It
also has the benefit of leaving H1 out of this, and save it from updating
a variable. Also in order to avoid an important update cost, we're storing
this value per thread group. For now only H2 is implemented, but QUIC
should follow shortly and should only count bidirectional streams.

2 days agoBUG/MEDIUM: servers: Only requeue servers if they are up
Olivier Houchard [Sat, 9 May 2026 17:27:12 +0000 (19:27 +0200)]
BUG/MEDIUM: servers: Only requeue servers if they are up

In init_srv_requeue(), only attempt to run the tasklet if the server is
actually running, otherwise it will end up being queued a second time,
when the server is actually brought up, and that will lead to a
corrupted mt_list.
This can easily be reproduced by adding a dynamic server, as those start
disabled, and then enabling and disabling it a couple of times.
This should fix github issue #3360.

This should be backported up to 3.2.

4 days agoSCRIPTS: announce-release: add a link to the OpenTelemetry filter
Willy Tarreau [Fri, 8 May 2026 10:04:04 +0000 (12:04 +0200)]
SCRIPTS: announce-release: add a link to the OpenTelemetry filter

It moved to its own repository, but we forgot to add the link, and
the build instructions are there.

4 days ago[RELEASE] Released version 3.4-dev11 v3.4-dev11
Willy Tarreau [Fri, 8 May 2026 03:22:55 +0000 (05:22 +0200)]
[RELEASE] Released version 3.4-dev11

Released version 3.4-dev11 with the following main changes :
    - BUG/MEDIUM: acme: fix segfault on newOrder with empty authorizations
    - BUG/MINOR: acme: skip auth/challenge steps when newOrder returns a certificate
    - BUG/MINOR: sink: do not free existing sinks on allocation error
    - CLEANUP: net_helper: fix incorrect const pointers in writev_n16()
    - BUG/MINOR: vars: make parse_store() return error on var_set() failure
    - BUG/MINOR: vars: don't store the variable twice with set-var-fmt
    - BUG/MINOR: vars: only print first invalid char in fill_desc()
    - BUG/MINOR: hpack: validate idx > 0 in hpack_valid_idx()
    - MINOR: add an MPSC ring buffer implementation
    - OPTIM: quic: rework the QUIC RX code
    - MINOR: quic: store the DCID as an offset
    - OPTIM: quic: reduce the size of struct quic_dgram
    - BUG/MINOR: quic: handle cases where we don't have an address
    - BUG/MEDIUM: cli: fix master CLI connection slot leak on client disconnect
    - MEDIUM: mux-quic: extend shut to app proto layer
    - MINOR: h3/hq_interop: implement stream reset on shut abort/kill-conn
    - BUG/MINOR: acl: fix a possible arg corruption in smp_fetch_acl_parse()
    - BUG/MINOR: map: do not leak a map descriptor on load error
    - CLEANUP: map/cli: fix some map-related help messages
    - BUG/MINOR: pattern: release the reference on failure to load from file
    - CLEANUP: acl: remove duplicate test in parse_acl_expr() and unused variable
    - CI: github: add DEBUG_STRICT=2 to ASAN jobs
    - BUG/MINOR: quic: fix buffer overflow with sockaddr_in46
    - BUG/MEDIUM: acme: fix stalled renewal when opportunistic DNS check fails
    - BUG/MINOR: quic: fix trace crash on datagram receive
    - MINOR: quic: fix trace spacing when datagram is displayed
    - CLEANUP: mux-h2: remove the outdated condition to release h2c on timeout
    - BUILD: add an EXTRA_MAKE option to build addons easily
    - BUILD: otel: removed USE_OTEL, addon is now built via EXTRA_MAKE
    - CLEANUP: otel: move opentelemetry outside haproxy sources
    - BUG/MEDIUM: mux-h2: fix the body_len to check when parsing request trailers
    - BUG/MAJOR: mux-h2: preset MSGF_BODY_CL on H2_SF_DATA_CLEN in h2c_dec_hdrs()
    - DOC: otel: update the filter's status and URL in the docs
    - DOC: acme: document missing acme-vars and provider-name keywords
    - BUG/MINOR: dns: always validate the source address in responses
    - BUG/MINOR: tcpcheck: Properly report error for http health-checks
    - CLEANUP: resolvers: Remove duplicated line when resolvers proxy is initialized
    - BUG/MINOR: resolvers: Free new requester on error when linking a resolution
    - BUG/MINOR: resolvers: Fix lookup for a hostname in the state-file tree
    - BUG/MINOR: resolvers: Free opts on parse error in resolv_parse_do_resolve()
    - BUG/MAJOR: net_helper: also fix tcp_options_list for OOB write loop
    - BUG/MEDIUM: ssl/sample: check output buffer size in aes_cbc_enc converter
    - BUG/MAJOR: http-ana: fix private session retrieval on NTLM
    - REGTESTS: add a regtest to validate various NTLM transitions
    - BUG/MEDIUM: mworker/cli: fix user and operator permission via @@<pid> in master CLI
    - BUG/MINOR: mworker/cli: check ci_insert() return value in pcli_parse_request()
    - REGTESTS: http-messaging: always send RFC8441 client settings to use ext connect
    - BUG/MINOR: h2: add decoding for :protocol in traces
    - BUG/MINOR: mux-h2: condition the processing of 8441 extension to global setting
    - MINOR: mux-h2: add a new message flag to indicate ext connect support
    - BUG/MINOR: h2: only accept :protocol with extended CONNECT
    - BUG/MINOR: acme: contact mail should be optional, don't pass ToS bool
    - CLEANUP: http-fetch: Remove duplcated return statement in smp_fetch_stver()
    - CLEANUP: http-fetch: Adjust smp_fetch_url32_src() comment
    - CLEANUP: http-fetch: Fix indentation of sample_fetch_keywords
    - BUG/MINOR: http_fetch: Check return values of unchecked buffer operations
    - BUG/MINOR: http-fetch: Fix http_auth_bearer() when custom header is used
    - BUG/MEDIUM: h1_htx: Remove reverved block on error during contig chunks parsing
    - CLEANUP: haterm: Remove duplicated bloc to know if haterm must drain
    - BUG/MINOR: haterm: Immediately report error when draining the request
    - CLEANUP: haterm: Remove useless IS_HTX_SC() test
    - BUG/MINOR: haterm: Fix a possible integer overflow on the request body length
    - BUG/MEDIUM: haterm: Subscribe for receives until request was fully drained
    - BUG/MINOR: haterm: Don't set HTX_FL_EOM flag on 100-Continue responses
    - BUG/MEDIUM: haterm: Properly handle end of request and end of response
    - BUG/MEDIUM: haterm: Properly handle client timeout
    - BUG/MINOR: haterm: Fix condition to use direct data forwarding
    - BUG/MINOR: haterm: Report a 400-bad-request error on receive error
    - DEBUG: haterm: Add hstream flags in the trace messages
    - MINOR: haterm: Remove now useless req_body field from hstream
    - MINOR: mux_quic: reset stream after app shutdown for HTTP/0.9
    - MINOR: mux_quic: do not perform unnecessary timeout handling on BE side
    - BUG/MEDIUM: mux_quic: adjust qcc_is_dead() to account detached streams
    - MINOR: mux_quic: simplify MUX_CTL_GET_NBSTRM
    - MINOR: ssl: Export 'current_crtstore_name'
    - MINOR: ssl: Factorize code from "new/set ssl cert" CLI command
    - MINOR: ssl: Factorize ckch instance rebuild process
    - MEDIUM: ssl: Refactorize "commit ssl cert"
    - BUG/MINOR: ssl: Use the sequence number with kTLS and TLS 1.2
    - BUG/MINOR: mux_quic: fix max stream ID reuse estimation
    - MINOR: mux_quic: release BE conns if reuse definitely blocked
    - BUG/MINOR: mux_quic: refresh timeout only if I/O performed
    - MEDIUM: mux-h1: Return an error on h2 upgrade attempts if not allowed
    - BUG/MEDIUM: mux-h2: Properly consume padding for DATA frames
    - MEDIUM: tools: read_line_to_trash() handle empty files without \n
    - MINOR: jws: support HMAC in jws_b64_protected(), make nonce optional
    - MINOR: jws: introduce jws_b64_hmac_signature() function for HMAC signing
    - MINOR: acme: implement EAB - external account binding
    - MINOR: acme: allow specifying custom MAC alg for EAB
    - REGTESTS: Fix h1_to_h2_upgrade.vtc to force h2 on first bind line
    - MINOR: cli: allow specifying a tgid with show fd
    - Revert "BUG/MEDIUM: cli: fix master CLI connection slot leak on client disconnect"
    - BUILD: use Makefile.mk instead of Makefile.inc in EXTRA_MAKE
    - Revert "BUG/MINOR: mux-h2: condition the processing of 8441 extension to global setting"
    - BUG/MEDIUM: mux-h2: fix the detection of the ext connect support
    - MINOR: jwe: Add option to enable/disable algorithms or encryption algorithms for jwt_decrypt
    - MINOR: jwe: Disable 'RSA1_5' algorithm by default in jwt_decrypt converters
    - BUG/MEDIUM: jwe: Fix jwt.decrypt_alg_list to work correctly
    - BUG/MEDIUM: stick-table: properly check permissions on CLI's set/clear cmd
    - DOC: acme: EAB is now supported

4 days agoDOC: acme: EAB is now supported
William Lallemand [Thu, 7 May 2026 16:49:58 +0000 (18:49 +0200)]
DOC: acme: EAB is now supported

Remove the line mentioning than External Account Binding is not
supported. Since it was implemented in 3.4.

4 days agoBUG/MEDIUM: stick-table: properly check permissions on CLI's set/clear cmd
Willy Tarreau [Thu, 7 May 2026 16:31:40 +0000 (18:31 +0200)]
BUG/MEDIUM: stick-table: properly check permissions on CLI's set/clear cmd

The "set stick-table" CLI command's permissions are checked a bit too
late in the I/O handler, because the lookups performed at parsing time
can already cause an entry to be created at level "user" even though the
user does not have the permission to go further and to fill the data in.

Note that the impact remains pretty low since the entry is created without
data being touchable, and all within the table's settings (max entries,
expire etc). In addition it cannot even be used to periodically refresh
an entry and prevent it from expiring because only a creation is handled
at this point.

Let's add the check in cli_parse_table_req() so that these privileged
commands are entirely denied past the table lookup. This way it remains
possible to know that the table doesn't exist, like for the "show" command
but not more.

This should be backported to all stable branches, because the bug right
now cannot result in an accidental use (entries are not properly created
and deletion does not work).

Thanks to Omkhar Arasaratnam for finding and reporting this.

4 days agoBUG/MEDIUM: jwe: Fix jwt.decrypt_alg_list to work correctly
Olivier Houchard [Thu, 7 May 2026 16:27:58 +0000 (18:27 +0200)]
BUG/MEDIUM: jwe: Fix jwt.decrypt_alg_list to work correctly

Function jwe_parse_global_alg_enc_list() handles both
jwt.decrypt_alg_list and jwd.decrypt_enc_list, but to know which array
to use, between the algorithms and encoding arrays to use, it was
checking the string to see if it matched jwe.supported_algorithms, so it
was always considering we were dealing with encodings, and
jwt.decrypt_alg_list could not possibly work.
Fix that by checking the right string.

4 days agoMINOR: jwe: Disable 'RSA1_5' algorithm by default in jwt_decrypt converters
Remi Tricot-Le Breton [Thu, 7 May 2026 15:05:17 +0000 (17:05 +0200)]
MINOR: jwe: Disable 'RSA1_5' algorithm by default in jwt_decrypt converters

In RFC8725, section 3.2, they suggest to "Avoid all RSA-PKCS1 v1.5
encryption algorithms" so this algorithm gets disabled by default.
Tokens having this "alg" won't be decrypted unless it is explicitly
reenabled thanks to 'jwt.decrypt_alg_list' global option.

Thanks to Omkhar Arasaratnam for raising our awareness about this!

4 days agoMINOR: jwe: Add option to enable/disable algorithms or encryption algorithms for...
Remi Tricot-Le Breton [Thu, 7 May 2026 15:05:16 +0000 (17:05 +0200)]
MINOR: jwe: Add option to enable/disable algorithms or encryption algorithms for jwt_decrypt

Some users of the jwt_decrypt_XXX converters might want to reject JWT
tokens with a specific algorithm or encryption algorithm ("alg" or "enc"
field respectively) in order to avoid weak algorithms for instance.
This could be done from the configuration but would be tedious.

This patch adds the new 'jwt.decrypt_alg_list' and
'jwt.decrypt_enc_list' global options that can be used to define a
subset of accepted algorithms

5 days agoBUG/MEDIUM: mux-h2: fix the detection of the ext connect support
Willy Tarreau [Thu, 7 May 2026 15:15:06 +0000 (17:15 +0200)]
BUG/MEDIUM: mux-h2: fix the detection of the ext connect support

As reported by Huangbin Zhan (@zhanhb) in github issue #3355, latest
commit 96f7ff4fdd ("MINOR: mux-h2: add a new message flag to indicate
ext connect support") was not correct and can break RFC8441-compliant
clients, as it did for them with a variant of Chrome 142.

The problem is that while RFC9113 says that new pseudo-headers are only
permitted with *negotiated* extensions, and RFC8441 doesn't indicate
whether or not SETTINGS_ENABLE_CONNECT_PROTOCOL is needed from clients,
it only says that clients know that servers support the extension when
seeing it in their settings and can use it, which seems to imply that
they don't need to send it to indicate their willingness to use it.
This also means that the server cannot know if a client is expected to
use it or not by default. It only know that a client is not allowed to
use it if the server didn't emit support mentioning it, which haproxy
can do using h2-workaround-bogus-websocket-clients.

Thus the fix proposed by @zhanhb is right, when presetting the flag for
the parser to indicate whether or not we're willing to accept RFC8441's
:protocol pseudo-header, we should:
  - consider the received setting on the backend side (though the
    pseudo-header is neither used nor supported there, but at least
    we pass the info regarding the support of the extension)
  - consider the configuration for the frontend (since it's the only
    place where we can decide on support or not)

This patch does just that and reverts the accompanying changes to the
regtests that made them want to see the client's setting. It must be
backported to 2.6.

In the mean time, placing this option in the global section will force
the clients to downgrade to h1:

    h2-workaround-bogus-websocket-clients

Many thanks again to @zhanbb this feedback and proposing a tested fix.

5 days agoRevert "BUG/MINOR: mux-h2: condition the processing of 8441 extension to global setting"
Willy Tarreau [Thu, 7 May 2026 15:06:13 +0000 (17:06 +0200)]
Revert "BUG/MINOR: mux-h2: condition the processing of 8441 extension to global setting"

This reverts commit 9986ad65a4af0b5e4212f1d12e108090490a8c2d.

The protocol was not super clear on one point when compared to RFC9113
and our internal setting GTUNE_DISABLE_H2_WEBSOCKET. While RFC9113 says
that protocol extensions are negotiated, RFC8441 is only advertised by
the server, which thus doesn't know if the client supports it or not
until it faces it. In addition, GTUNE_DISABLE_H2_WEBSOCKET doesn't
apply to the protocol support as it name seems to imply, but to the
frontend only since the corresponding option is
"h2-workaround-bogus-websocket-clients". As such, haproxy should not
expect the client to advertise anything regarding the setting, and
should not consider the option when receiving the server's setting.

This needs to be backported to 2.6 where the commit above was
backported.

5 days agoBUILD: use Makefile.mk instead of Makefile.inc in EXTRA_MAKE
William Lallemand [Thu, 7 May 2026 14:49:56 +0000 (16:49 +0200)]
BUILD: use Makefile.mk instead of Makefile.inc in EXTRA_MAKE

Use an external Makefile called Makefile.mk in order to build complex
addons.

    make TARGET=linux-glibc ... EXTRA_MAKE="/path/to/addon1" \
    EXTRA_MAKE+="/path/to/addon2"

5 days agoRevert "BUG/MEDIUM: cli: fix master CLI connection slot leak on client disconnect"
Willy Tarreau [Thu, 7 May 2026 14:28:46 +0000 (16:28 +0200)]
Revert "BUG/MEDIUM: cli: fix master CLI connection slot leak on client disconnect"

This reverts commit 64383e655b23e1240dd0043a18ca020994c60022.

As reported by Alexander Stephan in issue #3351, it causes problems.
First, as seen in the issue, the "reload" operation, handled by an applet
local to the master process, is being interrupted by the timeout so that
the client never gets the result (though the timeout is applied). A fix
for this was found (ignore client-fin/server-fin on applets, as they make
no sense there), but it only hides a deeper problem. Indeed, issuing
"@1 debug dev delay 2000" still stops at 1s with an error, indicating
that commands are systematically being sent with a shutdown, and thus
that the server-fin always applies. This is a problem because it means
that any long command will now be interrupted after one second.

All of this needs to be put back into perspective before progressing
further on this issue, and the reason for sending the shutdown should
be reconsidered in the context of the current version, as it looks
like this was once necessary but no longer is.

In addition, the issue encountered by Alexander, of a frozen worker,
was essentially reported once in many years, so it's totally acceptable
to leave older versions unfixed and figure what's the best solution for
modern versions only.

Let's just revert to the pre-fix situation so as to avoid causing
breakage everywhere. This revert should be backported to all versions
(2.4 included).

5 days agoMINOR: cli: allow specifying a tgid with show fd
Maxime Henrion [Mon, 27 Apr 2026 13:26:55 +0000 (09:26 -0400)]
MINOR: cli: allow specifying a tgid with show fd

This will become useful when we implement using unshare() to split fd
tables per thread group. For now, the tgid is parsed but completely
ignored.

5 days agoREGTESTS: Fix h1_to_h2_upgrade.vtc to force h2 on first bind line
Christopher Faulet [Thu, 7 May 2026 14:15:54 +0000 (16:15 +0200)]
REGTESTS: Fix h1_to_h2_upgrade.vtc to force h2 on first bind line

With VTEST, It seems possible to receive the H2 preface in 2 packets. So the
preface cannot be matched and the H1 to H2 upgrade is not performed as
expected. The script was fixed by forcing the H2 proto on the first bind
line.

The problem with the preface matching will be reviewed later.

5 days agoMINOR: acme: allow specifying custom MAC alg for EAB
Mia Kanashi [Wed, 6 May 2026 21:17:43 +0000 (00:17 +0300)]
MINOR: acme: allow specifying custom MAC alg for EAB

This implements configuration for custom mac alg in EAB.
I don't think there are any reasons to allow that TBH,
but it is something that exists in the spec.

Depends on the EAB impl.
No backport needed

5 days agoMINOR: acme: implement EAB - external account binding
Mia Kanashi [Wed, 6 May 2026 21:17:42 +0000 (00:17 +0300)]
MINOR: acme: implement EAB - external account binding

Patch introduces ACME EAB support.

Configuring EAB requires two parts: Key ID and MAC Key.
Key ID is an ASCII string that specifies the name of the record CA
should look up. MAC Key is a base64url encoded key that is used
for the sake of JWS signing, using HS256 or other algorithms.
They are the credentials so must be stored securely.

A thing about EAB is that it is required only during account creation
so it is unexpectedly complex to think about.
Some CAs provide EAB credential pair that is reused between
multiple account order requests, for example ZeroSSL, but others like
Google Trusted Services require an unique EAB credential for each new
account creation request.

There are a lot of ways config could be implemented, I decided to make
so that Key ID and MAC Key are stored in separate files on disk,
that decision was made because of the security concerns.
File based approach in particular works well with systemd credentials,
works well with systems that have config world readable, or immutable,
and is compatible with existing setups that specify credentials in a
file.

EAB is configured through options like this in an acme section:

eab-mac-alg HS512
eab-mac-key pebble.eab.mac-key
eab-key-id pebble.eab.key-id

I decided to not error out on empty files, but issue a log msg instead,
so that credentials can be removed without changing the haproxy config.

Used read_line_to_trash function from tools.c for reading files,
that is something that could be replaced by a dedicated function too.

No backport needed

5 days agoMINOR: jws: introduce jws_b64_hmac_signature() function for HMAC signing
Mia Kanashi [Wed, 6 May 2026 21:17:41 +0000 (00:17 +0300)]
MINOR: jws: introduce jws_b64_hmac_signature() function for HMAC signing

New jws_b64_hmac_signature() duplicates the same functionality as
jws_b64_signature(), but for the use case of HMAC signing.
Intended to be used for ACME EAB.

OpenSSL allows to use EVP_PKEY for HMAC functionality, so
jws_b64_signature() could be reused, but the problem is that although
isn't deprecated it was removed in BoringSSL, and was removed
(due to BoringSSL roots) but then readded back in AWS-LC, because of
"legacy clients" (citing them), for that reason alone I say that having
a dedicated function for hmac is better, HMAC() macro seems to be widely
supported unlike other ways of doing same thing. Another alternative
would be to use EVP_MD API, but it was introduced in OpenSSL 3.0,
so not as widely supported.

5 days agoMINOR: jws: support HMAC in jws_b64_protected(), make nonce optional
Mia Kanashi [Wed, 6 May 2026 21:17:40 +0000 (00:17 +0300)]
MINOR: jws: support HMAC in jws_b64_protected(), make nonce optional

This adds support for HMAC algorithms in jws_b64_protected(), but also
makes nonce field optional, because it isn't needed in some cases where
HMAC is used, primarily ACME EAB requires that nonce field must not
exist.

5 days agoMEDIUM: tools: read_line_to_trash() handle empty files without \n
Mia Kanashi [Wed, 6 May 2026 21:17:39 +0000 (00:17 +0300)]
MEDIUM: tools: read_line_to_trash() handle empty files without \n

fgets() returns NULL when EOF is reached before newline, handle
that as a success for consistency, current behaviour is arguably a bug,
the API of fgets() is pretty weird after all so someone probably forgot.

5 days agoBUG/MEDIUM: mux-h2: Properly consume padding for DATA frames
Christopher Faulet [Thu, 7 May 2026 09:41:51 +0000 (11:41 +0200)]
BUG/MEDIUM: mux-h2: Properly consume padding for DATA frames

Since the commit 617592c9e ("MEDIUM: mux-h2: try to coalesce outgoing
WINDOW_UPDATE frames"), padding of DATA frames is no longer
consumed. Instead, this padidng is left in the demux buffer and used as the
header of the next frame. Because all bytes of the padding must be zero,
this lead to trigger a PROTOCOL_ERROR because haproxy erroneously thinks the
peer sent a DATA frame for the stream-id 0. It is true for a padding of 9
bytes or more, but similar issues may be exprienced with smaller padding.

Before the commit above, the padding was consumed in h2_process_demux to
restore the H2_CS_FRAME_H state at the end of the while loop processing
received frames.

However, it seems a bit strange to deal with the padding at this stage,
espcially because it is not obvious at all. So to fix the issue, the padding
is now consumed at the end of h2_frt_transfer_data(), inside "end_tranfer"
label. At the stage, we know all payload of the current DATA frame were
consumed and only the padding is still there, if any. We must only take care
to not consume more than available in the demux buffer. The padding may have
been partially received.

This patch should fix the issue #3354. It must be backported as far as 2.8.

5 days agoMEDIUM: mux-h1: Return an error on h2 upgrade attempts if not allowed
Christopher Faulet [Wed, 6 May 2026 20:30:54 +0000 (22:30 +0200)]
MEDIUM: mux-h1: Return an error on h2 upgrade attempts if not allowed

If h1 to h2 upgrades are not allowed, a 405-method-not-allowed error is now
returned from the H1 multiplexer itself instead of dealing with "PRI *
HTTP/2.0\r\n\r\n" request as a normal request.

Before this kind of request was caught by the HTTP analyzers and a
400-bad-request was returned. This was added before the multiplexers era to
protect backend apps against unexpected H1 to H2 uprade on server side.

Now, it is possible to handle the error in the H1 multiplexer. One benefit
is to be able to increment the glichtes counters. However, the error is
still handled in HTTP analyzers to be sure to detect unwanted upgrades that
can be hidden in H2 or H3 requests.

There is a special case. TCP > H1 > H2 upgrades. In that case, a H1 stream
exist. So we must report an error to the upper layer too.

A reg-test script was added to validate the feature. In addition,
tcp_to_http_upgrade.vtc was updated accordingly.

5 days agoBUG/MINOR: mux_quic: refresh timeout only if I/O performed quic-interop
Amaury Denoyelle [Thu, 30 Apr 2026 15:47:28 +0000 (17:47 +0200)]
BUG/MINOR: mux_quic: refresh timeout only if I/O performed

Previously, QUIC MUX timeout was refreshed on every qcc_io_cb()
execution. This is not desired if no send/receive were performed, as in
this case the connection may be stuck.

This patch fixes this by refreshing timeout only if some progress is
performed during qcc_io_cb(). To implement this, return value of
qcc_io_recv() has been adjusted to return the number of newly decoded
bytes.

This patch is considered as a bug fix as without it there is a risk of
QUIC MUX inactivity timeout to be less efficient and to maintain a
connection too long.

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

5 days agoMINOR: mux_quic: release BE conns if reuse definitely blocked
Amaury Denoyelle [Thu, 30 Apr 2026 14:58:18 +0000 (16:58 +0200)]
MINOR: mux_quic: release BE conns if reuse definitely blocked

avail_streams callback serves to indicates how many streams can be
attached for a backend connection. On QUIC mux, this relies on several
parameters, first based on static limitation which only decreases over
time, but also on flow control which is dynamically adjusted by the peer
and can be increased or decreased at will.

qcc_is_dead() on the other hand serves to determine if a connection can
be removed. First, it must be inactive (no request in progress). Then,
if a backend connection cannot be reused due to some of the above
limitation reached, it is definitely useless and should be removed as
soon as possible. However, prior to this patch, qcc_is_dead() did not
take into account the same set of parameters than avail_streams : only
if graceful shutdown was initiated by the peer was considered.

The purpose of this patch is to linked these two functions together.
Reuse calcul based on static limits is extracted from avail_streams()
into new qcc_be_is_reusable(). This function is used directly in
qcc_is_dead(), which now for example takes into account the server
max-reuse parameter.

This patch should ensure that a backend connection which can not be
reuse anymore is release as soon as possible. This could improve
slightly reuse rate in some specific scenarii as non-reusable
connections should not pollute the idle cache.

Return value of QUIC avail_streams() is changed by this patch as server
max-reuse and max stream ID limits are now only taken into account when
already exceeded or if a single stream remains. However, this has no
consequence as callers of avail_streams() do not differentiates return
value of 2 or more.

5 days agoBUG/MINOR: mux_quic: fix max stream ID reuse estimation
Amaury Denoyelle [Thu, 7 May 2026 08:28:51 +0000 (10:28 +0200)]
BUG/MINOR: mux_quic: fix max stream ID reuse estimation

The following patch adjusts QUIC mux avail_streams() to ensure maximum
stream ID is never exceeded.

  commit 143d0034c912f1490812b6302f0dffb37f3ec02d
  BUG/MINOR: mux_quic: limit avail_streams() to 2^62

However, the calcul is incorrect, as <next_bidi_l> member value is set
to the next ID available, not the last one in use. Also, when the last
stream is closed, it will be greater than QCS_ID_MAX_STRM_CL_BIDI,
resulting in a substraction wrapping.

Fix this by using the simplest approach. Return value of avail_streams()
is only reduced if either the maximum stream ID limit is already
exceeded, or there is only a single stream still usable. In other cases,
return value is left as is.

Note that this bug is unlikely to have any impact as the maximum stream
ID is a very large value.

This should be backported up to 3.3.

5 days agoBUG/MINOR: ssl: Use the sequence number with kTLS and TLS 1.2
Olivier Houchard [Wed, 6 May 2026 16:32:51 +0000 (18:32 +0200)]
BUG/MINOR: ssl: Use the sequence number with kTLS and TLS 1.2

When using TLS 1.2 and kTLS, use the sequence number as the explicit
nonce (what the linux kTLS API calls "iv"), as is strongly recommanded,
and done by most TLS implementations, instead of trying to generate a
pseudo random-number.
In practice, it changes nothing, because the kernel would override that
with the sequence number anyway, but there is no need to have confusing
code that uses statistical_prng_range() anyway.

This should be backported to 3.3.

5 days agoMEDIUM: ssl: Refactorize "commit ssl cert"
Remi Tricot-Le Breton [Wed, 6 May 2026 12:16:41 +0000 (14:16 +0200)]
MEDIUM: ssl: Refactorize "commit ssl cert"

In order for the code behind the "commit ssl cert" logic to be usable
outside of the CLI context, some new "ckch_store_update_" functions are
created. They allow to perform all the operations on ckch_stores to be
performed without needing an appctx.
The first function being called is ckch_store_update_init which mainly
takes the ckch_store lock and checks that there is an ongoing
transaction with the proper path (which was already done in
cli_parse_commit_cert).
The main one is ckch_store_update_process which replicates the logic
that could be found in the cli_io_handler_commit_cert function. We
iterate over the ckch instances of an existing ckch store and duplicate
them in the new ckch store which is still detached from the tree, before
replacing the old store with the new one. This whole operation could
take some time so we were yielding every 10 instances or when
applet_putstr calls would fail. The actual ckch_store operations and the
applet related calls are now decorrelated in order to stop having to
have an appctx during the ckch store/instances processing.
The ckch_store_update_process will now update a "msg" buffer and a
"state" that allow to send processing messages to the caller as well as
keep the state of the processing "state machine".
When the ckch_store_update_process loop is over,
ckch_store_update_cleanup can be called to release the lock and free
some now useless structures.

5 days agoMINOR: ssl: Factorize ckch instance rebuild process
Remi Tricot-Le Breton [Wed, 6 May 2026 12:16:40 +0000 (14:16 +0200)]
MINOR: ssl: Factorize ckch instance rebuild process

The ckch instances for a given ckch_store have to be rebuilt when a
certificate is updated during runtime (via cli or lua). The code was
duplicated in lua so factorizing the actual loop avoids future errors
if the code changes. The new 'ckch_store_rebuild_instances' will have a
dedicated 0 return code if it needs to be called again (because of the
yielding logic since ckch instance rebuild might take some time).

5 days agoMINOR: ssl: Factorize code from "new/set ssl cert" CLI command
Remi Tricot-Le Breton [Wed, 6 May 2026 12:16:39 +0000 (14:16 +0200)]
MINOR: ssl: Factorize code from "new/set ssl cert" CLI command

This allows to perform the same kind of operation without the need for
an appctx.

5 days agoMINOR: ssl: Export 'current_crtstore_name'
Remi Tricot-Le Breton [Wed, 6 May 2026 12:16:38 +0000 (14:16 +0200)]
MINOR: ssl: Export 'current_crtstore_name'

Make the 'current_crtstore_name' global variable visible during parsing.

6 days agoMINOR: mux_quic: simplify MUX_CTL_GET_NBSTRM
Amaury Denoyelle [Wed, 6 May 2026 07:08:35 +0000 (09:08 +0200)]
MINOR: mux_quic: simplify MUX_CTL_GET_NBSTRM

Since the previous patch, accounting of HTTP requests in progress on MUX
QUIC as been simplified. Now QCC <nb_hreq> identifies them until the QCS
free.

Thus, MUX_CTL_GET_NBSTRM can be simplified. Instead of relying on
<nb_sc> plus the <opening_list>, simply return <nb_hreq> value which
should be slighly identical.

6 days agoBUG/MEDIUM: mux_quic: adjust qcc_is_dead() to account detached streams
Amaury Denoyelle [Wed, 22 Apr 2026 08:06:31 +0000 (10:06 +0200)]
BUG/MEDIUM: mux_quic: adjust qcc_is_dead() to account detached streams

Muxes are responsible to release connections once they are inactive and
won't be reusable. In QUIC mux, such connections are detected via
qcc_is_dead(). The first precondition is that there is no more upper
streams attached. This was accounted via QCC <nb_sc> counter.

A special characteristic of QCS instances is that they can be in
detached state : upper stream has been removed but there is still data
to emit. Such QCS were not taken into account in qcc_is_dead(), so a
connection could be freed with some remaining data not yet emitted.

It is also not possible for QUIC MUX to simply look at the QCS tree to
determine if the connection is inactive. Indeed, some streams are opened
for protocol internal usage. This is the case for example with HTTP/3
unidirectional control stream or QPACK encoder/decoder streams. These
streams are never closed. In the end, only requests streams should be
taken into account for the connection activity.

This patch improves the situation by reworking <nb_hreq> QCC counter.
Previously, it served for http-request timeout implementation. However,
this timeout only relies on <opening_list> now. Thus, <nb_hreq> scope is
changed : it is now incremented via qcs_wait_http_req(), used by app
protocol layer once a request stream is identified. Decrement is
performed on qcs_free(), so this guarantees that a connection cannot be
freed anymore if request streams still exists, unless if inactivity
timeout fires. As such, <nb_hreq> now supersedes <nb_sc> entirely, so
the qcc_is_dead() can now relies on the former.

Along with this change, qcc_timeout_task() must be updated. Call to
qcc_is_dead() was unnecessary prior to this patch as timeout handling
was only active when no upper streams were attached. When tested, both
<nb_sc> and QCC <task> were already null, so a connection was always
released on timeout, as expected. With qcc_is_dead() now checking
<nb_hreq> instead, this is not always the case anymore. In fact, this
check is unnecessary as inactivity timeout serves precisely to free a
stucked connection with remaining data to emit.

This patch also has some impact on http-keep-alive timeout. Previously,
this timeout could be armed if only detached streams remained. Now, it
is only applicable if all QCS request instances are closed and freed.
Thus, qcc_reset_idle_start() is now closed directly on qcs_free().

Ideally this should be backported up to 2.6, or at least 2.8 as QUIC
experimental status was removed there.

6 days agoMINOR: mux_quic: do not perform unnecessary timeout handling on BE side
Amaury Denoyelle [Tue, 21 Apr 2026 15:58:27 +0000 (17:58 +0200)]
MINOR: mux_quic: do not perform unnecessary timeout handling on BE side

MUX implements a timeout for HTTP keep-alive which monitors the delay
between two HTTP requests. This is only applicable for frontend
connections, as on the backend side idle connections can be kept in the
server pool. In QUIC mux, this timeout relies on QCC <idle_start> which
is refresh when the last request is terminated.

This patch modifies the refresh operation so that it is only performed
for frontend connections. This is not strictly necessary but the timeout
timeout management is now clearer and it eliminates an unnecessary
operation for backend connections.

Similarly, http-request timeout is also only applicable for frontend
connections. This relies on qcs_wait_http_req() function. A request QCS
is inserted in <opening_list> until the headers are received. This is
unnecessary on the backend side so this is excluded as well.

6 days agoMINOR: mux_quic: reset stream after app shutdown for HTTP/0.9
Amaury Denoyelle [Wed, 22 Apr 2026 07:28:24 +0000 (09:28 +0200)]
MINOR: mux_quic: reset stream after app shutdown for HTTP/0.9

HTTP/3 implements a GOAWAY frame for graceful shutdown. This allows to
reject any new stream opening with a larger ID. This is implemented via
HTTP/3 attach() callback called by qcs_new().

When HTTP/0.9 is used, there is no similar mechanism. This renders some
feature such as server max-reuse difficult to implement. This patch now
provides a method for such protocols with no graceful shutdown support.
Instead of invoking attach() callback, a stream is now immediately
resetted if the application protocol layer is already closed.

This patch does not change the behavior for HTTP/3. Only limited
protocols (currently only HTTP/0.9) without graceful shutdown are
impacted. These protocols are identified as their shutdown() callback is
nul.

This change is only necessary for HTTP/0.9 as there is no equivalent of
HTTP/3 GOAWAY in this case.

6 days agoMINOR: haterm: Remove now useless req_body field from hstream
Christopher Faulet [Tue, 5 May 2026 16:58:36 +0000 (18:58 +0200)]
MINOR: haterm: Remove now useless req_body field from hstream

req_body field is no longer used, except in trace messages. And in fact, it
is not necessarily true if some data are received with the request headers.
So no reason to still use it.

6 days agoDEBUG: haterm: Add hstream flags in the trace messages
Christopher Faulet [Tue, 5 May 2026 16:35:15 +0000 (18:35 +0200)]
DEBUG: haterm: Add hstream flags in the trace messages

It could be useful to know the hstream state on debugging sessions.

6 days agoBUG/MINOR: haterm: Report a 400-bad-request error on receive error
Christopher Faulet [Tue, 5 May 2026 16:31:57 +0000 (18:31 +0200)]
BUG/MINOR: haterm: Report a 400-bad-request error on receive error

When an error is reported when reading request data, the hstream now try to
send a 400-bad-request to the client. Before, the connection was just closed
with no error message.

6 days agoBUG/MINOR: haterm: Fix condition to use direct data forwarding
Christopher Faulet [Tue, 5 May 2026 16:25:27 +0000 (18:25 +0200)]
BUG/MINOR: haterm: Fix condition to use direct data forwarding

The direct fowarding support was only relying on "hs->to_write" value. But
we must be sure to retry if fast-forward data are still there in the I/O
buffer.

6 days agoBUG/MEDIUM: haterm: Properly handle client timeout
Christopher Faulet [Tue, 5 May 2026 16:13:21 +0000 (18:13 +0200)]
BUG/MEDIUM: haterm: Properly handle client timeout

No client timeout was set with haterm. It could be an issue with
unresponsive clients. So the I/O timeout of the SC is initialized to the
frontend client timeout when the hstream is created. Then a read activity is
reported when data are received. This read activity is used to set an
expiration date on the hstream task and test it when the hstream is woken up
with TASK_WOKEN_TIMER reason.

When a client timeout is detected, the hstream try to send a 408 and report
an error.

6 days agoBUG/MEDIUM: haterm: Properly handle end of request and end of response
Christopher Faulet [Tue, 5 May 2026 14:11:31 +0000 (16:11 +0200)]
BUG/MEDIUM: haterm: Properly handle end of request and end of response

There were several issues with the handling of end of the request or end of
response. The main problem was about the request draining.

To help to fix these issues, two flags were introduced:

 * HS_ST_HTTP_EOM_RCVD: to know the request was fully received
 * HS_ST_HTTP_EOM_SENT: to know the response was fully sent

Thanks to these flags some parts were reviewed and simplified.

In the I/O callback function, outside of any error, the hstream task is now
woken when one of the direction is not finished or when there are still some
data in a buffer.

The function hstream_must_drain() was reworked to properly drain request
with no content-length before replying.

The condition to wake hstream up to drain the request after replying was
also reworked, and moved ouside of the else block. Indeed, it must also be
evaluated when the response was fully sent in one call, when request headers
were processed.

Finally, the condition to shut the hstream was slighly adapted to use the
new flags. In addition, we now rely on se_shutdown().

6 days agoBUG/MINOR: haterm: Don't set HTX_FL_EOM flag on 100-Continue responses
Christopher Faulet [Tue, 5 May 2026 14:07:13 +0000 (16:07 +0200)]
BUG/MINOR: haterm: Don't set HTX_FL_EOM flag on 100-Continue responses

A 100-Continue response is an intermediary message. So the end of message
must not be announed.

6 days agoBUG/MEDIUM: haterm: Subscribe for receives until request was fully drained
Christopher Faulet [Tue, 5 May 2026 14:02:01 +0000 (16:02 +0200)]
BUG/MEDIUM: haterm: Subscribe for receives until request was fully drained

When draining the request, if some data were received, no subscribe for
receives was performed to get the remaining. However, because request data
are just ignored, we must always subscribe until it was fully
drained. Otherwise, haterm will never be woken up to drain more data.

6 days agoBUG/MINOR: haterm: Fix a possible integer overflow on the request body length
Christopher Faulet [Tue, 5 May 2026 13:54:21 +0000 (15:54 +0200)]
BUG/MINOR: haterm: Fix a possible integer overflow on the request body length

When request data were received, the request body length was decremented
accordingly with no check on it to be sure it was set. However, it remains
equal to 0 for chunked requests or H2/H3 requests with no content-length.

So now, it is only decremented when it is greater than 0.

6 days agoCLEANUP: haterm: Remove useless IS_HTX_SC() test
Christopher Faulet [Tue, 5 May 2026 13:51:24 +0000 (15:51 +0200)]
CLEANUP: haterm: Remove useless IS_HTX_SC() test

Haterm is an HTTP endpoint. No reason to test if its sc is an HTX sc or
not. Let's remove Is_HTX_SC() test.

6 days agoBUG/MINOR: haterm: Immediately report error when draining the request
Christopher Faulet [Tue, 5 May 2026 13:45:12 +0000 (15:45 +0200)]
BUG/MINOR: haterm: Immediately report error when draining the request

When draining the request data, if an error was reported while some data
were received, the error was not processed immediately. This part was copied
from tcpchecks where the response should be processed first. For haterm, the
request data are ignored. So no reason to wait to handle the error. It may
be an issue because the response may be sent in the meanwhile.

6 days agoCLEANUP: haterm: Remove duplicated bloc to know if haterm must drain
Christopher Faulet [Tue, 5 May 2026 06:44:28 +0000 (08:44 +0200)]
CLEANUP: haterm: Remove duplicated bloc to know if haterm must drain

When haterm was waiting for request headers, there was two test to know if
it had to drain the request data before replying. One of them was useless
and was thus removed.

6 days agoBUG/MEDIUM: h1_htx: Remove reverved block on error during contig chunks parsing
Christopher Faulet [Tue, 5 May 2026 13:05:57 +0000 (15:05 +0200)]
BUG/MEDIUM: h1_htx: Remove reverved block on error during contig chunks parsing

In h1_parse_full_contig_chunks(), we first try to reserve the bigger HTX
DATA block as possible. It is ajusted at the end of chunks parsing or
removed if no data was copied. However, it should also be removed when a
parsing error is triggered. It could be an issue for http health checks and
haterm to properly handle errors.

This patch should be backported as far as 2.6.

6 days agoBUG/MINOR: http-fetch: Fix http_auth_bearer() when custom header is used
Christopher Faulet [Mon, 4 May 2026 14:42:50 +0000 (16:42 +0200)]
BUG/MINOR: http-fetch: Fix http_auth_bearer() when custom header is used

When http_auth_bearer() sample fetch function is called with a custom header
and the header is not found or type didn't match 'Bearer', a mismatch must
be reported instead of an empty string.

This patch should be backported as far as 2.6.

6 days agoBUG/MINOR: http_fetch: Check return values of unchecked buffer operations
Willy Tarreau [Wed, 29 Apr 2026 06:55:23 +0000 (08:55 +0200)]
BUG/MINOR: http_fetch: Check return values of unchecked buffer operations

Several return value for chunk_istcat() or chunk_memcat() calls were not
tested. Now, 0 is returned on failure.

Concretly, for now, it is unexpected to trigger error because the result
cannot exceed the buffer size. Data are extracted from an HTX message.

At first glance, no reason to backport it.

6 days agoCLEANUP: http-fetch: Fix indentation of sample_fetch_keywords
Christopher Faulet [Mon, 4 May 2026 15:46:33 +0000 (17:46 +0200)]
CLEANUP: http-fetch: Fix indentation of sample_fetch_keywords

Misplaced spaces before comma in 'urlp' keyword table entry.

6 days agoCLEANUP: http-fetch: Adjust smp_fetch_url32_src() comment
Christopher Faulet [Mon, 4 May 2026 15:44:11 +0000 (17:44 +0200)]
CLEANUP: http-fetch: Adjust smp_fetch_url32_src() comment

smp_fetch_base32() function was referenced instead of
smp_fetch_url32(). Let's fix it.

6 days agoCLEANUP: http-fetch: Remove duplcated return statement in smp_fetch_stver()
Christopher Faulet [Mon, 4 May 2026 15:41:36 +0000 (17:41 +0200)]
CLEANUP: http-fetch: Remove duplcated return statement in smp_fetch_stver()

the return statement was needlessly repeated. Let's remove the second one.

6 days agoBUG/MINOR: acme: contact mail should be optional, don't pass ToS bool
Mia Kanashi [Fri, 1 May 2026 18:06:17 +0000 (21:06 +0300)]
BUG/MINOR: acme: contact mail should be optional, don't pass ToS bool

According to ACME RFC contact email is optional.
Letsencrypt used it some long time ago, but not today.
Currently HAProxy always sets the value of the contact mail to a string
that is read from the config, but if that string is not specified,
it sets %s in mailto:%s to null, which cases new account request
to fail in pebble.

Also HAProxy currently passes termsOfServiceAgreed bool to requests
that contain onlyReturnExisting, that isn't needed according to the RFC
and other ACME impls.

This patch dynamically builds the account request JSON to address that.

Can be backported to 3.2

7 days agoBUG/MINOR: h2: only accept :protocol with extended CONNECT
Willy Tarreau [Tue, 5 May 2026 11:33:05 +0000 (13:33 +0200)]
BUG/MINOR: h2: only accept :protocol with extended CONNECT

As reported by Huangbin Zhan in github issue #3355, we're too lax on
the :protocol pseudo header. It is currently accepted with regular
CONNECT as well as non-CONNECT methods while it only ought to be
accepted with extended CONNECT (i.e. CONNECT after the connection
negotiated the RFC8441 extension). Let's refine the check in H2 by
leveraging the new flag H2_MSGF_EXT_CONN_OK that is passed by the
caller when the connection supports the extension. This is sufficient
to sort the various cases.

The proto upgrade regtest was updated to verify that CONNECT with
:protocol without nego and another method with nego and :protocol
both fail.

Thanks to Huangbin Zhan (@zhanhb) for the report and helpful reproducer.

This needs to be backported to all versions. It relies on these patches
first:

  REGTESTS: http-messaging: always send RFC8441 client settings to use ext connect
  BUG/MINOR: mux-h2: condition the processing of 8441 extension to global setting
  MINOR: mux-h2: add a new message flag to indicate ext connect support

7 days agoMINOR: mux-h2: add a new message flag to indicate ext connect support
Willy Tarreau [Tue, 5 May 2026 11:26:43 +0000 (13:26 +0200)]
MINOR: mux-h2: add a new message flag to indicate ext connect support

The new message flag H2_MSGF_EXT_CONN_OK indicates that the connection
supports extended connect. This will be used in a subsequent fix.

7 days agoBUG/MINOR: mux-h2: condition the processing of 8441 extension to global setting
Willy Tarreau [Tue, 5 May 2026 09:40:29 +0000 (11:40 +0200)]
BUG/MINOR: mux-h2: condition the processing of 8441 extension to global setting

When rfc8441 (extended connect) is disabled via
h2-workaround-bogus-websocket-clients, we properly refrain from
advertising support for extended connect, but we should also ignore
the incoming setting, otherwise it can remain enabled if the client
advertises it.

This should be backported to stable versions.

7 days agoBUG/MINOR: h2: add decoding for :protocol in traces
Willy Tarreau [Tue, 5 May 2026 09:15:26 +0000 (11:15 +0200)]
BUG/MINOR: h2: add decoding for :protocol in traces

Function h2_phdr_to_list() was missing the decoding for the :protocol
header and would emit :UNKNOWN in this case. It's only used in traces
so it's not important. The fix can be backported in all versions.

7 days agoREGTESTS: http-messaging: always send RFC8441 client settings to use ext connect
Willy Tarreau [Tue, 5 May 2026 11:24:50 +0000 (13:24 +0200)]
REGTESTS: http-messaging: always send RFC8441 client settings to use ext connect

The tests were validating extended connect without sending the setting
in the client settings frame. It currently works due to a bug, so let's
fix the vtc first.

7 days agoBUG/MINOR: mworker/cli: check ci_insert() return value in pcli_parse_request()
William Lallemand [Mon, 4 May 2026 17:00:27 +0000 (19:00 +0200)]
BUG/MINOR: mworker/cli: check ci_insert() return value in pcli_parse_request()

All ci_insert() calls in pcli_parse_request() were ignoring the return
value, silently miscounting the bytes to forward if an insertion failed.

Add a check on each call and return -1 on failure. In practice this has
no impact: the channel receive machinery enforces a maxrewrite reserve,
so there is always sufficient room in the buffer for these small
prefixes by the time pcli_parse_request() is called.

Must be backported in every maintained versions, the list of available
commands might change.

7 days agoBUG/MEDIUM: mworker/cli: fix user and operator permission via @@<pid> in master CLI
William Lallemand [Mon, 4 May 2026 16:35:46 +0000 (18:35 +0200)]
BUG/MEDIUM: mworker/cli: fix user and operator permission via @@<pid> in master CLI

When @@<pid> is matched in pcli_parse_request(), no "operator -" or
"user -" is being sent before the command, like it's done for @<pid>.

It leads to privileges not being respected and commands are sent as
admin.

Fix this by applying the access-level downgrade in the @@<pid> path,
like it's done for @<pid>.

Must be backported to 3.2.

Reported-by: Omkhar Arasaratnam <omkhar@linkedin.com>
7 days agoREGTESTS: add a regtest to validate various NTLM transitions
Willy Tarreau [Mon, 4 May 2026 16:53:33 +0000 (18:53 +0200)]
REGTESTS: add a regtest to validate various NTLM transitions

This test first performs two successive requests over the same
connection where reuse is expected, then perform two 401 which must
both work, testing both the transition from null->sess, and sess->sess.

This test could be backported to detect changes related to private
sessions.

Thanks to Omkhar Arasaratnam for the test.

7 days agoBUG/MAJOR: http-ana: fix private session retrieval on NTLM
Willy Tarreau [Mon, 4 May 2026 15:42:45 +0000 (17:42 +0200)]
BUG/MAJOR: http-ana: fix private session retrieval on NTLM

During the architectural review leading to commit 90b2154d93 ("MEDIUM:
muxes: always set conn->owner to the session that owns the connection"),
we wondered whether srv_conn->owner could ever be NULL or even invalid,
or if it ought to be changed to sess, and the projections of various use
cases, as well as a number of attempts to fool it led us to conclude
that it was always valid since the connection is private. So it was
considered safer not to start fiddling with the pointer in case it
could still match a previous session after a reuse, which would match
the scenario described in the session_add_conn() comment.

Actually there was exactly one case where a NULL could be met, and that
was covered by the preliminary call to conn_set_owner() that was removed
in that patch, precisely related to the one that the next patch tried to
address: in http-reuse always, after the second request on a connection
releases the connection, the owner can now become NULL, so if an NTLM
header is seen at this point, it will crash.

Interestingly, after the immediately following commit was merged,
d93c53b0df ("MEDIUM: session: always reset the conn->owner on backend
when installing mux"), the problem became immediate as the conn's
owner is now null during operation if the connection is not private, and
now the first response in NTLM is sufficient to crash the process. On
the other hand, thanks to the two patches above, we're now certain never
to meet a different session, which was the sought goal: either the session
is normal and it has no owner, or it's private and it has <sess> as owner.
Also with HTTP/1 (since the code explicitly checks for H1), there may be
a single request at a time on a connection so the owner should either be
the session or NULL.

So this patch finally implements the original plan, to pass <sess> to
session_add_conn(). The call is idempotent if the owner is already set,
but at least the function performs some preliminary sanity checks which
are quite welcome, so better continue to always call it.

Note that this is only for 3.4 or any branch that has exactly the two
patches above. And if the patches above were to ever be backported
(together), this one would be needed as well.

Thanks to Omkhar Arasaratnam for reporting this regression.

8 days agoBUG/MEDIUM: ssl/sample: check output buffer size in aes_cbc_enc converter
William Lallemand [Mon, 4 May 2026 15:34:13 +0000 (17:34 +0200)]
BUG/MEDIUM: ssl/sample: check output buffer size in aes_cbc_enc converter

AES-CBC uses a 16-byte block size, and PKCS padding always adds at least
one byte (up to a full 16 bytes when input is already block-aligned), so
the encrypted output is always larger than the input. Without checking
that the output buffer can hold the padded result, encryption could
overflow it. Add a pre-encryption guard for block cipher (blksize > 1)
that rejects the operation when the output buffer is too small.

No backport needed.

Reported-by: Omkhar Arasaratnam <omkhar@linkedin.com>
8 days agoBUG/MAJOR: net_helper: also fix tcp_options_list for OOB write loop
Willy Tarreau [Mon, 4 May 2026 15:08:22 +0000 (17:08 +0200)]
BUG/MAJOR: net_helper: also fix tcp_options_list for OOB write loop

The exact same issue that was fixed for ip.fp with commit dbf471f99a
("BUG/MAJOR: net_helper: ip.fp infinite loop on malformed tcp options")
also exists for tcp_options_list: an option with a zero size will prevent
the offset from making any progress and will loop forever. In this case,
since we produce output, trash->data gets incremented on each loop and
the byte at ofs is used to fill the memory there, quickly overflowing the
area.

The exact same fix as above was applied here again, including the uchar
cast to make sure we don't go back-and-forth between two positions.

Such TCP options are not valid and will not be reported by the TCP stack,
however they can happen in case options are passed in headers by a first
proxy, or are offered in a return directive fed from a query string as a
means of providing a debugging tool for admins.

Thanks to Omkhar Arasaratnam for reporting this issue.

This fix must be backported to 3.2 where the commits above were
backported.

8 days agoBUG/MINOR: resolvers: Free opts on parse error in resolv_parse_do_resolve()
Christopher Faulet [Mon, 4 May 2026 12:59:24 +0000 (14:59 +0200)]
BUG/MINOR: resolvers: Free opts on parse error in resolv_parse_do_resolve()

The error handler at do_resolve_parse_error freed varname and resolvers_id
but missed freeing rule->arg.resolv.opts (allocated via calloc). Added
ha_free(&rule->arg.resolv.opts) to the cleanup path.

This patch could be backported to all stable branches.

8 days agoBUG/MINOR: resolvers: Fix lookup for a hostname in the state-file tree
Christopher Faulet [Mon, 4 May 2026 12:53:58 +0000 (14:53 +0200)]
BUG/MINOR: resolvers: Fix lookup for a hostname in the state-file tree

In resolv_check_response(), the condition 'if (!srvrq->named_servers)' was
inverted - it ran the named server lookup when the tree was empty/NULL
instead of when it was populated. This prevented proper hostname-based
matching of SRV records to servers from the state file.

The issue was introduced when tree of servers was replaced by a cebis tree
(fdf6fd5b45).

This patch must be backported to 3.3.

8 days agoBUG/MINOR: resolvers: Free new requester on error when linking a resolution
Christopher Faulet [Mon, 4 May 2026 06:47:58 +0000 (08:47 +0200)]
BUG/MINOR: resolvers: Free new requester on error when linking a resolution

If an error is triggered while the requester was allocated, it is not
immediately released. It is not really a memory leak because the requester
will be reused laster, on a next attempt, or released on deinit. For a
do-resolv action, the requester is released with the stream. So no leak
here. But it is probably not expected to keep a newly allocated requester in
case of error.

This patch could be backported as far as 2.6.

8 days agoCLEANUP: resolvers: Remove duplicated line when resolvers proxy is initialized
Christopher Faulet [Mon, 4 May 2026 06:29:21 +0000 (08:29 +0200)]
CLEANUP: resolvers: Remove duplicated line when resolvers proxy is initialized

In resolvers_setup_proxy(), "px->conn_retries" was initialized twice. Let's
remove the line with no comment.

8 days agoBUG/MINOR: tcpcheck: Properly report error for http health-checks
Christopher Faulet [Mon, 4 May 2026 05:52:41 +0000 (07:52 +0200)]
BUG/MINOR: tcpcheck: Properly report error for http health-checks

When an error is reported on an expect rule for tcp and http health-checks,
a dedicated message is reported with details about the wrong match. However,
this was never performed for HTTP health-check because of the wrong test on
the check type.

In addition, when an error was reported on an "expect hdr" rule, a break
statement was missing. So the error message could be truncated (but never
emitted because of the issue above).

This patch should be backported to all stable versions.

8 days agoBUG/MINOR: dns: always validate the source address in responses
Willy Tarreau [Mon, 4 May 2026 14:10:20 +0000 (16:10 +0200)]
BUG/MINOR: dns: always validate the source address in responses

When we removed the use of connect() to reach DNS servers in 3.3 with
commit 2c7e05f80e ("MEDIUM: dns: don't call connect to dest socket for
AF_INET*"), we accidentally lost a check on the server's address in
responses, opening the possibility of spoofed DNS responses for someone
who knows both haproxy's IP:port and the transaction ID.

In practice, the impact is very low, because:
  - DNS servers IP addresses are almost always known, and often even among
    the widely used ones (1.1.1.1, 8.8.8.8 etc), and their port is 53.
  - all DNS "security" relies on the ignorance of the transaction ID and
    is possible source port, so if either the attacker is on-path and sees
    them, or it's off-path and has to guess them, but in any case it's
    trivial to spoof the known server in responses, with or without the
    check.

Regardless, let's not further weaken the protocol and do the check.

Thanks to Omkhar Arasaratnam for reporting this issue.

An interesting observation while testing this fix was that the code does
support UNIX dgram sockets (via connect()) but that since we don't bind
to a local UNIX socket to send requests, the server's recvfrom() doesn't
get any address and has nowhere to respond to. So in practice while the
code is designed to deal with UNIX sockets, these cannot work by design.

This fix must be backported to 3.2 where the commit above was backported.

8 days agoDOC: acme: document missing acme-vars and provider-name keywords
William Lallemand [Mon, 4 May 2026 12:40:20 +0000 (14:40 +0200)]
DOC: acme: document missing acme-vars and provider-name keywords

Both keywords are used with dns-01 and dns-persist-01 challenges to pass
information to an external DNS provisioning tool (e.g. the dataplaneAPI)
via the "dpapi" sink. provider-name sets the DNS provider identifier and
acme-vars passes arbitrary tool-specific variables.

Thanks to @oliwer for reporting the issue.

Must be backported to 3.2, however previous version don't have
"dns-persist-01".

8 days agoDOC: otel: update the filter's status and URL in the docs
Willy Tarreau [Mon, 4 May 2026 12:37:02 +0000 (14:37 +0200)]
DOC: otel: update the filter's status and URL in the docs

The docs (readme and configuration.txt) still used to mention that OTEL
was under development. Now that it's released, let's indicate that it's
ready with the download URL.

8 days agoBUG/MAJOR: mux-h2: preset MSGF_BODY_CL on H2_SF_DATA_CLEN in h2c_dec_hdrs()
Willy Tarreau [Mon, 4 May 2026 11:51:36 +0000 (13:51 +0200)]
BUG/MAJOR: mux-h2: preset MSGF_BODY_CL on H2_SF_DATA_CLEN in h2c_dec_hdrs()

Commit d12edebe4a ("BUG/MAJOR: mux-h2: detect incomplete transfers on
HEADERS frames as well") tried to enforce strict matching between
advertised content-length and transferred data when dealing with ES on
a headers frame. It purposely arranged the code so that it would cover
both headers and trailers. The problem is, in h2c_dec_hdrs() we preset
message flags (msgf) based on the current state and knowledge related
to the stream being processed, then we pass these flags to the headers
parser and use their final state to perform some extra checks.

MSGF_BODY_CL was set by the parsers themselves when processing a
content-length header, but when parsing a trailers frame, it will not
be set, and due to this the matching between the remaining expected
content-length and the transferred data is not verified, so the fix
above doesn't work for trailers.

This patch sets MSGF_BODY_CL to the same value as H2_SF_DATA_CLEN so
that during headers it remains zero, but it matches what was learned
during headers when processing trailers. It is sufficient to re-enable
the check that was attempted in the commit above.

The impact remains the same as the one indicated in the commit above: in
practice this can be used to force subsequent requests to fail, or when
running with "http-reuse never" or when running with a totally idle server,
to perform a request smuggling by constructing specially crafted request
pairs where the first one is used to trigger an early response and hide
parts of or all headers of the second one, to instead use a second
embedded one that was not subject to analysis. As such, the risk remains
moderate given the low prevalence of "http-reuse never" in production
environments, and of idle servers. Again, a temporary alternative to the
fix is to disable HTTP/2 by specifying "alpn http/1.1" on "bind" lines,
and adding "option disable-h2-upgrade" in HTTP frontends.

Many thanks to Pratham Gupta / alchemy1729 for spotting and analyzing
this problem, and for providing a lightweight reproducer to illustrate
the problem!

This fix must be backported to all versions where the fix above was
backported (i.e. all). Note that it depends on this previous commit
otherwise trailers will always break:

  BUG/MEDIUM: mux-h2: fix the body_len to check when parsing request trailers

As a side note, it's worth noting that these temporary message flags have
reached a level of pain and fragility that really warrants a complete
rework. Ideally we should have a pair of such flags in the h2s (one per
direction) and the callers of the parsers should point to them so that
they are always up to date. And by having generic HTTP flags instead of
H2, we could better unify the h1/h2/h3/fcgi processors (and maybe avoid
some HTX conversion). One flag could even indicate that trailers are
being parsed (since they're last) so as to ease this detection down the
chain.

8 days agoBUG/MEDIUM: mux-h2: fix the body_len to check when parsing request trailers
Willy Tarreau [Mon, 4 May 2026 11:42:52 +0000 (13:42 +0200)]
BUG/MEDIUM: mux-h2: fix the body_len to check when parsing request trailers

The h2 content-length validation in commit d12edebe4a ("BUG/MAJOR:
mux-h2: detect incomplete transfers on HEADERS frames as well") was
insufficient. The content-length check is still ineffective on request
trailers and it could not work by default due to the fact that the
default body_len is used in h2c_frt_handle_headers() when processing
trailers, instead of passing h2s->body_len, which was necessarily parsed
before reaching trailers. Let's fix this point first, otherwise fixing
the second issue would break trailers.

Many thanks to Pratham Gupta / alchemy1729 for spotting and analyzing
this problem, and for providing a lightweight reproducer to illustrate
the problem!

This fix must be backported to all versions where the fix above was
backported (i.e. all).

8 days agoCLEANUP: otel: move opentelemetry outside haproxy sources
William Lallemand [Mon, 4 May 2026 12:18:40 +0000 (14:18 +0200)]
CLEANUP: otel: move opentelemetry outside haproxy sources

The opentelemetry addons now live outside haproxy sources and is
available at https://github.com/haproxytech/haproxy-opentelemetry/

The addon must be built using the EXTRA_MAKE option from HAProxy
Makefile:

$ PKG_CONFIG_PATH=/opt/lib/pkgconfig make -j8 TARGET=linux-glibc
  EXTRA_MAKE="/tmp/a/a/haproxy-opentelemetry" OTEL_DEBUG=1 OTEL_USE_VARS=1

8 days agoBUILD: otel: removed USE_OTEL, addon is now built via EXTRA_MAKE
Miroslav Zagorac [Mon, 4 May 2026 09:45:52 +0000 (11:45 +0200)]
BUILD: otel: removed USE_OTEL, addon is now built via EXTRA_MAKE

The OpenTelemetry filter has been moved out of the haproxy source tree and
now lives and is developed in the haproxy-opentelemetry repository as an
external addon.  Removed all hard-coded references to USE_OTEL and to the
addons/otel directory from the main Makefile, as the addon is now plugged
in through the generic EXTRA_MAKE hook added in the previous commit.

8 days agoBUILD: add an EXTRA_MAKE option to build addons easily
William Lallemand [Thu, 30 Apr 2026 16:27:27 +0000 (18:27 +0200)]
BUILD: add an EXTRA_MAKE option to build addons easily

Allow to call an external Makefile called Makefile.inc in order to build
complex addons.

make TARGET=linux-glibc ... EXTRA_MAKE="/path/to/addon1" \
     EXTRA_MAKE+="/path/to/addon2"

8 days agoCLEANUP: mux-h2: remove the outdated condition to release h2c on timeout
Willy Tarreau [Mon, 4 May 2026 09:57:12 +0000 (11:57 +0200)]
CLEANUP: mux-h2: remove the outdated condition to release h2c on timeout

The historical code dealing with timeout was left with a confusing
condition that is always true but always requires some analysis. It
would check if some streams were left pending before deciding to
release the connection. It could indeed be problematic to leave with
no timeout and an active connection!

As Christopher figured, the situation cannot exist because a first
check ensures there's no more h2c via h2c_may_expire(), then a call
to h2_wake_some_streams() will call h2s_wake_one_stream() for each
of the h2s, and all those with no h2c are purged. Thus on return
from h2_wake_some_streams() we're guaranteed to have an empty tree.

Let's just remove the condition and clean up the code.

8 days agoMINOR: quic: fix trace spacing when datagram is displayed
Amaury Denoyelle [Mon, 4 May 2026 09:18:47 +0000 (11:18 +0200)]
MINOR: quic: fix trace spacing when datagram is displayed

Adjust spacing between individual arguments for the QUIC trace
QUIC_EV_CONN_RCV when a datagram is displayed.

8 days agoBUG/MINOR: quic: fix trace crash on datagram receive
Amaury Denoyelle [Mon, 4 May 2026 09:12:08 +0000 (11:12 +0200)]
BUG/MINOR: quic: fix trace crash on datagram receive

Recently, datagram reception architecture has been completely reworked
to improve performance. A regression has been introduced when using
traces in qc_rcv_buf() : datagram argument is uninitialized after recv
syscall. This may cause a crash as CIDs buffer is dereferenced.

Fix this by removing dgram argument from the affected trace. A new trace
is added after quic_dgram_init() to keep the ability to display the
received content.

This issue has caused failure of all QUIC interop testing.

No need to backport.

8 days agoBUG/MEDIUM: acme: fix stalled renewal when opportunistic DNS check fails
William Lallemand [Thu, 30 Apr 2026 18:24:59 +0000 (20:24 +0200)]
BUG/MEDIUM: acme: fix stalled renewal when opportunistic DNS check fails

In ACME_INITIAL_RSLV_READY, when the opportunistic DNS propagation check
fails and the code falls back to ACME_CLI_WAIT, ACME_RDY_INITIAL_DNS was
left set in cond_ready. Since the CLI-wait path only ever sets ACME_RDY_CLI
on auth->ready, the readiness check in ACME_CLI_WAIT could never be
satisfied, permanently stalling certificate renewal.

Fix this by stripping ACME_RDY_INITIAL_DNS from cond_ready before falling
back to the regular CLI-wait flow. Also replace the &= with a plain
assignment in the success path to make the intent explicit.

No backport needed, 3.4 only.

8 days agoBUG/MINOR: quic: fix buffer overflow with sockaddr_in46
Amaury Denoyelle [Mon, 4 May 2026 08:22:42 +0000 (10:22 +0200)]
BUG/MINOR: quic: fix buffer overflow with sockaddr_in46

New type sockaddr_in46 has been recently introduced. It serves as a
union which can store either an IPv4 or IPv6 address. The objective is
to reduce the storage size for QUIC datagrams which previously uses a
sockaddr_storage field.

On qc_new_conn(), source and destination addresses from the datagram are
passed to the function as sockaddr_storage so that they are copied into
the newly built quic_conn instance. However, the involved memcpy() is
producing a buffer overflow as sockaddr_in46 is smaller than
sockaddr_storage type.

This patch fixes this by defining a new helper function
in46un_to_addr(). This allows to convert safely sockaddr_in46 to a plain
sockaddr type. The function is now used before invoking qc_new_conn().

Note that there is still other several places where union sockaddr_in46
is casted as sockaddr_storage type. However, these should be safe as in
these cases sockaddr fields are accessed individually after checking
ss_family. The memory issue only exists when plain memcpy is used.

This bug was detected using ASAN. It generates the following traces when
a QUIC connection is instantiated.

==37474==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7c3bb9a61100 at pc 0x5631f52c3946 bp 0x7ffc83e45b50 sp 0x7ffc83e45310
READ of size 128 at 0x7c3bb9a61100 thread T0
    #0 0x5631f52c3945 in __asan_memcpy (/home/amaury/work/haproxy-quic-dev/haproxy+0x3ae945) (BuildId: a7ccfd74b7a71a869b8ff8d13f6dcde8c82c1487)
    #1 0x5631f55f9e34 in qc_new_conn /home/amaury/work/haproxy-quic-dev/src/quic_conn.c:1311:2
    #2 0x5631f558d5c3 in quic_rx_pkt_retrieve_conn /home/amaury/work/haproxy-quic-dev/src/quic_rx.c:1875:10
    #3 0x5631f558330b in quic_dgram_parse /home/amaury/work/haproxy-quic-dev/src/quic_rx.c:2463:29
    #4 0x5631f5625da6 in quic_lstnr_dghdlr /home/amaury/work/haproxy-quic-dev/src/quic_sock.c:206:3
    #5 0x5631f6a64173 in run_tasks_from_lists /home/amaury/work/haproxy-quic-dev/src/task.c:660:26
    #6 0x5631f6a6ba1e in process_runnable_tasks /home/amaury/work/haproxy-quic-dev/src/task.c:913:9
    #7 0x5631f5e984c3 in run_poll_loop /home/amaury/work/haproxy-quic-dev/src/haproxy.c:2982:3
    #8 0x5631f5e9a715 in run_thread_poll_loop /home/amaury/work/haproxy-quic-dev/src/haproxy.c:3212:2
    #9 0x5631f5e9f732 in main /home/amaury/work/haproxy-quic-dev/src/haproxy.c:3853:2
    #10 0x7f2bba8276c0  (/usr/lib/libc.so.6+0x276c0) (BuildId: ca0db5ab57a36507d61bbcf4988d344974331f19)
    #11 0x7f2bba8277f8 in __libc_start_main (/usr/lib/libc.so.6+0x277f8) (BuildId: ca0db5ab57a36507d61bbcf4988d344974331f19)
    #12 0x5631f51be594 in _start (/home/amaury/work/haproxy-quic-dev/haproxy+0x2a9594) (BuildId: a7ccfd74b7a71a869b8ff8d13f6dcde8c82c1487)

No need to backport.

12 days agoCI: github: add DEBUG_STRICT=2 to ASAN jobs
William Lallemand [Thu, 30 Apr 2026 15:24:55 +0000 (17:24 +0200)]
CI: github: add DEBUG_STRICT=2 to ASAN jobs

Add an DEBUG_STRICT=2 option to the ASAN jobs in order to trigger the
BUG_ON_HOT() conditions.

12 days agoCLEANUP: acl: remove duplicate test in parse_acl_expr() and unused variable
Willy Tarreau [Thu, 30 Apr 2026 13:53:21 +0000 (15:53 +0200)]
CLEANUP: acl: remove duplicate test in parse_acl_expr() and unused variable

aclkw->match_type was compared twice to PAT_MATCH_DOM in parse_acl_expr().
After auditing the involved types, it's only a copy-paste mistake, as no
other matching method is missing, so let's drop it to avoid the confusion.
Also drop variable ckw which is assigned NULL and passed to free(), and is
clearly a leftover from a previous version.

No backport needed.