Hi, HAProxy 2.4.29 was released on 2025/04/22. It added 67 new commits after version 2.4.28.
This version catches up with the last 5 months of fixes, corresponding to what was merged in 2.6 since 2.6.20. Again, there's nothing really important but a lot of small stuff: - The H1 multiplexer was only able to handle timeouts if the client or server timeouts were defined, depending on the side. So, it was possible to ignore client-fin/server-fin and http-keep-alive/http-request timeouts. - The way to deal with too many headers in received H2. The maximum number of headers allowed in HEADERS frames on sending path was lower than on receiving path. This could lead to report sending errors while the message was accepted. It could be confusing. In addition, unlike H1, the number of headers must be limited when H2 messages are sent to comply to limitation imposed by the protocol. This limit was increased to support headers rewriting without issue. - On the H2 multiplexer, on server side, it was possible to send RST_STREAM frame for streams with unassigned ID, so before the formatting of the HEADERS frame, because the session was aborted during the connection stage. It was an issue if this happened before the H2 PREFACE was sent because this prevent the servers to recognize it as a H2 connection, leading to an early connection closure. We now take care to not emit RST_STREAM frame in that case. - Four issues with the L7 retries were fixed. First, the server status was not adjusted at each retry, while it should be. Only the last connection attempt was considered. Then, the buffer used to save the request to be able to perform a L7 retry was released to early in some rare cases and the request could be lost. It is of course unexpected and this could lead to crash. The request state was not properly reset on L7 retry. The request channel flag stating some data were sent was not reset on retry. This could lead to consider a subsequent connection error as a L7 error while the request was never sent. In that case too, the request could be lost, leading to crash. Finally, the L7 retries could be ignored if a server abort was detected during the request forwarding when the request was already in DONE state. In that case, the server abort must be handled on the response analysis side to be able to properly handle the L7 retries. - The reason was missing in H2 responses forwarded to H1 clients while it was stated in the configuration manual that HAProxy should add one that matched the status code. It is now fixed. - HAPROXY_CLI and HAPROXY_MASTER_CLI could exposed the internal sockpairs which should be only used for the master CLI. These internal sockpairs are now always hidden. - The SIGINT signal could be missed by HAProxy when it was started in background in a subshell. It is the root cause of some unexpected timeouts with Vtest scripts. To fix the issue, the default signal handler is registered for the SIGINT signal during init. - A weird issue was fixed about the epoll poller. Over the last two years, there were few reports about immediate closes spuriously happening on connections where network captures proved that the server had not closed at all (and sometimes even received the request and responded to it after HAProxy had closed). The logs shown that a successful connection was immediately reported on error after the request was sent. After investigations, it appeared that a EPOLLUP, or eventually a EPOLLRDHUP, can be reported by epool_wait() during the connect() but in sock_conn_check(), the connect() reports a success. So the connection was validated but the HUP was handled on the first receive and an error was reported. So, to workaround the issue, we have decided to remove FD_POLL_HUP flag on the FD during the connection establishment if FD_POLL_ERR is not reported too in sock_conn_check(). This way, the call to connect() is able to validate or reject the connection. At the end, if the HUP or RDHUP flags were valid, either connect() would report the error itself, or the next recv() would return 0 confirming the closure that the poller tried to report. EPOLL_RDHUP is only an optimization to save a syscall anyway, and this pattern is so rare that nobody will ever notice the extra call to recv(). Please note that at least one reporter confirmed that using poll() instead of epoll() also addressed the problem, so that can also be a temporary workaround for those discovering the problem without the ability to immediately upgrade. - The expiration date for the task responsible for cleaning up the server resolution status when outdated info were inherited from the state file was fixed. "hold.timeout" was initially used. But is was not accurate, especially because it could be set to a high value or 0. Now the expiration date is based on the resolver "resolve" and "retry" timeouts. In addition, when a resolver was woken up to process DNS resolutions, it was possible to trigger an infinite loop on the resolver's wait list because delayed resolutions were always reinserted at the end of this list. This led the watchdog to kill the process. By re-inserting them in front of the list fixed the issue. - an API issue in the applets could have resulted in some shutdown or error conditions to be missed in the future, so as a prevention it was fixed. Turns out, after fixing this, it uncovered a bug in the CLI's "_getsocks" handler that was causing an infinite loop during reloads, and another one in the SPOE applet where the appled would never shut down (neither appeared in a released version), and these bug were also fixed. - reloads that transfer listening sockets to the new worker process could make the older worker consume a lot of CPU for no apparent reason for the time it remained present. The cause was that these FDs were registered in epoll and when a new connection arrived to the new process, the old one would also be notified without being able to unregister it since already closed (well-known epoll pitfall). Now these FDs are properly unregistered after being transfered so it's possible that some users with long-running old processes will observe a lower CPU usage on these old processes. - a BUG_ON() could be triggered when using filters with no http_payload callback. - a bug in htx_xfer_blks() could result in occasionally transfering more blocks than requested on 32-bit platforms. - some TLSv1.3 signature algorithms were not recognized by the ClientHello parser which was written before TLSv1.3. The ones that were not correctly supported were based on RSA-PSS and would have resulted in presenting a possibly wrong certificate when both RSA and ECDSA ones were present for the same SNI. - disabling the send-proxy-v2 feature on a "server" line after some fields had been enabled in the defaults section would result in an attempt to send a PROXY-v1 line because the presence of any field was tested to decide to send the PROXY header. - a use-after-free condition was occasionally possible in Lua applets handling CLI keywords, causing random crashes. It was apparently difficult to trigger and did apparently not happen before 3.0. - SPOE applets could be woken in loops during stopping, thus eating a lot of CPU until the process stopped. - usesrc clientip would accidentally include the client's port in the hash calculation, resulting in a very low connection reuse ratio. - leading and trailing spaces are now properly trimmed from h2 header values. It had been observed that some rare clients keep the space after the comma when splitting "cookie" values, causing errors between haproxy and servers, so we can reasonably expect that this would happen with h3 too if the same clients support both protocols. - stick-tables could learn entries from peers with an expiration date further in the future than what their own expire time permits, causing entries resulting from a temporary misconfiguration to be very difficult to evict from a cluster (e.g. mistakenly write "24d" instead of "24h" and entries persist for 3 weeks even across reloads). Now the entries' expiration date will be capped to the stick table's setting. - the regsub converter, used to perform regex-based substitutions, would check the remaining room in the buffer against the initially available size for each replaced pattern instead of checking it against the remaining size. This was reported by Aleandro Prudenzano of Doyensec and Edoardo Geraci of Codean Labs, and was assigned CVE-2025-32464. The risk is quite low since such configs are quite unlikely and in the rare cases they will happen, the replacement will involve static contents, thus essentially a risk of crash. - a few issues on the peers section parser and config consistency checker possibly causing issues or even a segfault. - a few minor memory leaks were found in error paths (auth, _getsock) - FCGI would always force the status to 302 when seeing a Location header, possibly overwriting another status code. - a pending close from the server could be forwarded to the client despite a pending tcp-response content evaluation. Given that 2.4 is in critical fixes status, I'd suggest 2.4 users to have a look at it in case they estimate that they might be affected by one of the issues fixed above, and possibly plan for an update. In any case, please remember to at least update before reporting an issue. But so far, no need to immediately jump on this one if what you have works well for you. Please find the usual URLs below : Site index : https://www.haproxy.org/ Documentation : https://docs.haproxy.org/ Wiki : https://github.com/haproxy/wiki/wiki Discourse : https://discourse.haproxy.org/ Slack channel : https://slack.haproxy.org/ Issue tracker : https://github.com/haproxy/haproxy/issues Sources : https://www.haproxy.org/download/2.4/src/ Git repository : https://git.haproxy.org/git/haproxy-2.4.git/ Git Web browsing : https://git.haproxy.org/?p=haproxy-2.4.git Changelog : https://www.haproxy.org/download/2.4/src/CHANGELOG Dataplane API : https://github.com/haproxytech/dataplaneapi/releases/latest Pending bugs : https://www.haproxy.org/l/pending-bugs Reviewed bugs : https://www.haproxy.org/l/reviewed-bugs Code reports : https://www.haproxy.org/l/code-reports Latest builds : https://www.haproxy.org/l/dev-packages Willy --- Complete changelog : Amaury Denoyelle (3): BUG/MINOR: backend: do not overwrite srv dst address on reuse BUG/MINOR: h1: do not forward h2c upgrade header token BUG/MINOR: h2: reject extended connect for h2c protocol Aurelien DARRAGON (8): DOC: lua: fix yield-dependent methods expected contexts BUG/MEDIUM: pattern: prevent uninitialized reads in pat_match_{str,beg} BUG/MINOR: stktable: fix big-endian compatiblity in smp_to_stkey() DOC: management: rename some last occurences from domain "dns" to "resolvers" BUG/MINOR: cfgparse/peers: fix inconsistent check for missing peer server BUG/MINOR: cfgparse/peers: properly handle ignored local peer case BUG/MEDIUM: hlua/cli: fix cli applet UAF in hlua_applet_wakeup() BUG/MINOR: hlua: fix invalid errmsg use in hlua_init() Christopher Faulet (24): BUG/MEDIUM: resolvers: Insert a non-executed resulution in front of the wait list BUG/MEDIUM: mux-h2: Don't send RST_STREAM frame for streams with no ID BUG/MINOR: http_ana: Report -1 for %Tr for invalid response only DOC: config: Slightly improve the %Tr documentation BUG/MINOR: http-ana: Adjust the server status before the L7 retries BUG/MEDIUM: mux-h2: Increase max number of headers when encoding HEADERS frames BUG/MEDIUM: mux-h2: Check the number of headers in HEADERS frame after decoding BUG/MEDIUM: http-ana: Don't release too early the L7 buffer BUG/MEDIUM: sock: Remove FD_POLL_HUP during connect() if FD_POLL_ERR is not set BUG/MEDIUM: http-ana: Reset request flag about data sent to perform a L7 retry BUG/MINOR: h1-htx: Use default reason if not set when formatting the response BUG/MINOR: server-state: Fix expiration date of srvrq_check tasks BUG/MEDIUM: mux-h1: Fix how timeouts are applied on H1 connections BUG/MINOR: spoe: Check the shared waiting queue to shut applets during stopping BUG/MINOR: spoe: Allow applet creation when closing the last one during stopping BUG/MEDIUM: spoe: Don't wakeup idle applets in loop during stopping REGTESTS: Fix truncated.vtc to send 0-CRLF BUG/MINOR: cli: Wait for the last ACK when FDs are xferred from the old worker BUG/MEDIUM: filters: Handle filters registered on data with no payload callback BUG/MINOR: fcgi: Don't set the status to 302 if it is already set BUG/MINOR: tcp-rules: Don't forward close during tcp-response content rules eval BUG/MINOR: cli: Fix memory leak on error for _getsocks command BUG/MINOR: cli: Fix a possible infinite loop in _getsocks() BUG/MINOR: stats-json: Define JSON_INT_MAX as a signed integer Dragan Dosen (1): BUG/MINOR: server: fix the "server-template" prefix memory leak Emeric Brun (2): BUG/MINOR: peers: fix expire learned from a peer not converted from ms to ticks BUG/MEDIUM: peers: prevent learning expiration too far in futur from unsync node Ilia Shipitsin (1): BUG/MINOR: namespace: handle a possible strdup() failure Lukas Tribus (1): DOC: option redispatch should mention persist options Nathan Wehrman (1): DOC: config: correct the table for option tcplog Olivier Houchard (1): TESTS: Fix build for filltab25.c Valentine Krasnobaeva (6): BUG/MINOR: cli: don't show sockpairs in HAPROXY_CLI and HAPROXY_MASTER_CLI BUG/MINOR: signal: register default handler for SIGINT in signal_init() BUG/MINOR: ssl: put ssl_sock_load_ca under SSL_NO_GENERATE_CERTIFICATES BUG/MINOR: cfgparse: fix NULL ptr dereference in cfg_parse_peers BUG/MEIDUM: startup: return to initial cwd only after check_config_validity() BUG/MINOR: log: fix gcc warn about truncating NUL terminator while init char arrays William Lallemand (5): BUG/MINOR: ssl: can't load a separated key file with openssl > 3.0 BUG/MEDIUM: ssl: chosing correct certificate using RSA-PSS with TLSv1.3 BUG/MEDIUM: htx: wrong count computation in htx_xfer_blks() DOC: htx: clarify <mark> parameter for htx_xfer_blks() TESTS: ist: fix wrong array size Willy Tarreau (14): BUG/MEDIUM: checks: make sure to always apply offsets to now_ms in expiration BUG/MEDIUM: mailers: make sure to always apply offsets to now_ms in expiration BUG/MINOR: peers: make sure to always apply offsets to now_ms in expiration DOC: configuration: explain quotes and spaces in conditional blocks BUG/MEDIUM: clock: make sure now_ms cannot be TICK_ETERNITY BUG/MEDIUM: fd: mark FD transferred to another process as FD_CLONED MINOR: cli: export cli_io_handler() to ease symbol resolution DOC: config: fix two missing "content" in "tcp-request" examples BUG/MEDIUM: sample: fix risk of overflow when replacing multiple regex back-refs BUG/MINOR: backend: do not use the source port when hashing clientip DOC: config: add the missing "profiling.memory" to the global kw index BUG/MINOR: h2: always trim leading and trailing LWS in header values BUG/MINOR: server: check for either proxy-protocol v1 or v2 to send hedaer BUILD: makefile: silence deprecated declarations when using OpenSSL ---