]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
4 months agoMINOR: compiler: add a simple macro to concatenate resolved strings
Willy Tarreau [Wed, 12 Mar 2025 17:06:55 +0000 (18:06 +0100)] 
MINOR: compiler: add a simple macro to concatenate resolved strings

It's often useful to be able to concatenate strings after resolving
them (e.g. __FILE__, __LINE__ etc). Let's just have a CONCAT() macro
to do that, which calls _CONCAT() with the same arguments to make
sure the contents are resolved before being concatenated.

4 months agoBUG/MEDIUM: thread: use pthread_self() not ha_pthread[tid] in set_affinity
Willy Tarreau [Wed, 12 Mar 2025 14:54:36 +0000 (15:54 +0100)] 
BUG/MEDIUM: thread: use pthread_self() not ha_pthread[tid] in set_affinity

A bug was uncovered by the work on NUMA. It only triggers in the CI
with libmusl due to a race condition. What happens is that the call
to set_thread_cpu_affinity() is done very early in the polling loop,
and that it relies on ha_pthread[tid] instead of pthread_self(). The
problem is that ha_pthread[tid] is only set by the return from
pthread_create(), which might happen later depending on the number of
CPUs available to run the starting thread.

Let's just use pthread_self() here. ha_pthread[] is only used to send
signals between threads, there's no point in using it here.

This can be backported to 2.6.

4 months agoMEDIUM: log: change default "host" strategy for log-forward section
Aurelien DARRAGON [Tue, 11 Mar 2025 14:15:34 +0000 (15:15 +0100)] 
MEDIUM: log: change default "host" strategy for log-forward section

Historically, log-forward proxy used to preserve host field from input
message as much as possible, and if syslog host wasn't provided
(rfc5424 '-' or bad rfc3164 or rfc5424 message) then "localhost" or "-"
would be used as host when outputting message using rfc3164 or rfc5424.

We change that behavior (which corresponds to "keep" host option), so that
log-forward now uses "fill" strategy as default: if the host is provided
in input message, it is preserved. However if it is missing and IP address
from sender is available, we use it.

4 months agoMINOR: log: handle log-forward "option host"
Aurelien DARRAGON [Mon, 10 Mar 2025 09:02:53 +0000 (10:02 +0100)] 
MINOR: log: handle log-forward "option host"

Following previous patch, we know implement the logic for the host
option under log-forward section. Possible strategies are:

      replace If input message already contains a value for the host
              field, we replace it by the source IP address from the
              sender.
              If input message doesn't contain a value for the host field
              (ie: '-' as input rfc5424 message or non compliant rfc3164
              or rfc5424 message), we use the source IP address from the
              sender as host field.

      fill    If input message already contains a value for the host field,
              we keep it.
              If input message doesn't contain a value for the host field
              (ie: '-' as input rfc5424 message or non compliant rfc3164
              or rfc5424 message), we use the source IP address from the
              sender as host field.

      keep    If input message already contains a value for the host field,
              we keep it.
              If input message doesn't contain a value for the host field,
              we set it to localhost (rfc3164) or '-' (rfc5424).
              (This is the default)

      append  If input message already contains a value for the host field,
              we append a comma followed by the IP address from the sender.
              If input message doesn't contain a value for the host field,
              we use the source IP address from the sender.

Default value (unchanged) is "keep" strategy. option host is only relevant
with rfc3164 or rfc5424 format on log targets. Also, if the source address
is not available (ie: UNIX socket), default behavior prevails.

Documentation was updated.

4 months agoMINOR: log: add "option host" log-forward option
Aurelien DARRAGON [Fri, 7 Mar 2025 09:29:12 +0000 (10:29 +0100)] 
MINOR: log: add "option host" log-forward option

add only the parsing part, options are currently unused

4 months agoMINOR: tools: only print address in sa2str() when port == -1
Aurelien DARRAGON [Mon, 10 Mar 2025 21:25:09 +0000 (22:25 +0100)] 
MINOR: tools: only print address in sa2str() when port == -1

Support special value for port in sa2str: if port is equal to -1, only
print the address without the port, also ignoring <map_ports> value.

4 months agoMINOR: log: provide source address information in syslog_process_message()
Aurelien DARRAGON [Mon, 10 Mar 2025 20:08:57 +0000 (21:08 +0100)] 
MINOR: log: provide source address information in syslog_process_message()

provide struct sockaddr_storage pointer from the message sender in
syslog_process_message()

4 months agoMINOR: log: migrate log-forward options from proxy->options2 to options3
Aurelien DARRAGON [Fri, 7 Mar 2025 10:00:59 +0000 (11:00 +0100)] 
MINOR: log: migrate log-forward options from proxy->options2 to options3

Migrate recently added log-forward section options, currently stored under
proxy->options2 to proxy->options3 since proxy->options2 is running out of
space and we plan on adding more log-forward options.

4 months agoMINOR: proxy: add proxy->options3
Aurelien DARRAGON [Fri, 7 Mar 2025 09:55:31 +0000 (10:55 +0100)] 
MINOR: proxy: add proxy->options3

proxy->options2 is almost full, yet we will add new log-forward options
in upcoming patches so we anticipate that by adding a new {no_}options3
and cfg_opts3[] to further extend proxy options

4 months agoCLEANUP: log: add syslog_process_message() helper
Aurelien DARRAGON [Mon, 10 Mar 2025 11:15:32 +0000 (12:15 +0100)] 
CLEANUP: log: add syslog_process_message() helper

Prevent code duplication under syslog_fd_handler() and syslog_io_handler()
by merging common code path in a single syslog_process_message() helper
that processed a single message stored in <buf> according to <frontend>
settings.

4 months agoCLEANUP: log-forward: remove useless options2 init
Aurelien DARRAGON [Fri, 7 Mar 2025 09:57:04 +0000 (10:57 +0100)] 
CLEANUP: log-forward: remove useless options2 init

It is actually not required to zero out proxy->options2 since proxy is
allocated using calloc() which already does it.

4 months agoCI: github: add "jose" to apt dependencies
William Lallemand [Tue, 11 Mar 2025 19:18:54 +0000 (20:18 +0100)] 
CI: github: add "jose" to apt dependencies

jose is used in the JWS unit-test, let's add it to the CI.

4 months agoTESTS: jws: implement a test for JWS signing
William Lallemand [Thu, 6 Mar 2025 16:15:23 +0000 (17:15 +0100)] 
TESTS: jws: implement a test for JWS signing

This test returns a JWS payload signed a specified private key in the
PEM format, and uses the "jose" command tool to check if the signature
is correct against the jwk public key.

The test could be improved later by using the code from jwt.c allowing
to check a signature.

4 months agoMINOR: jws: implement JWS signing
William Lallemand [Thu, 6 Mar 2025 16:14:26 +0000 (17:14 +0100)] 
MINOR: jws: implement JWS signing

This commits implement JWS signing, this is divided in 3 parts:

- jws_b64_protected() creates a JWS "protected" header, which takes the
  algorithm, kid or jwk, nonce and url as input, and fill a destination
  buffer with the base64url version of the header
- jws_b64_payload() just encode a payload in base64url
- jws_b64_signature() generates a signature using as input the protected
  header and the payload, it supports ES256, ES384 and ES512 for ECDSA
  keys, and RS256 for RSA ones. The RSA signature just use the
  EVP_DigestSign() API with its result encoded in base64url. For ECDSA
  it's a little bit more complicated, and should follow section 3.4 of
  RFC7518, R and S should be padded to byte size.

Then the JWS can be output with jws_flattened() which just formats the 3
base64url output in a JSON representation with the 3 fields, protected,
payload and signature.

4 months ago[RELEASE] Released version 3.2-dev7 v3.2-dev7
Willy Tarreau [Fri, 7 Mar 2025 15:37:57 +0000 (16:37 +0100)] 
[RELEASE] Released version 3.2-dev7

Released version 3.2-dev7 with the following main changes :
    - BUG/MEDIUM: applet: Don't handle EOI/EOS/ERROR is applet is waiting for room
    - BUG/MEDIUM: spoe/mux-spop: Introduce an NOOP action to deal with empty ACK
    - BUG/MINOR: cfgparse: fix NULL ptr dereference in cfg_parse_peers
    - BUG/MEDIUM: uxst: fix outgoing abns address family in connect()
    - REGTESTS: fix reg-tests/server/abnsz.vtc
    - BUG/MINOR: log: fix outgoing abns address family
    - BUG/MINOR: sink: add tempo between 2 connection attempts for sft servers
    - MINOR: clock: always use atomic ops for global_now_ms
    - CI: QUIC Interop: clean old docker images
    - BUG/MINOR: stream: do not call co_data() from __strm_dump_to_buffer()
    - BUG/MINOR: mux-h1: always make sure h1s->sd exists in h1_dump_h1s_info()
    - MINOR: tinfo: add a new thread flag to indicate a call from a sig handler
    - BUG/MEDIUM: stream: never allocate connection addresses from signal handler
    - MINOR: freq_ctr: provide non-blocking read functions
    - BUG/MEDIUM: stream: use non-blocking freq_ctr calls from the stream dumper
    - MINOR: tools: use only opportunistic symbols resolution
    - CLEANUP: task: move the barrier after clearing th_ctx->current
    - MINOR: compression: Introduce minimum size
    - BUG/MINOR: h2: always trim leading and trailing LWS in header values
    - MINOR: tinfo: split the signal handler report flags into 3
    - BUG/MEDIUM: stream: don't use localtime in dumps from a signal handler
    - OPTIM: connection: don't try to kill other threads' connection when !shared
    - BUILD: add possibility to use different QuicTLS variants
    - MEDIUM: fd: Wait if locked in fd_grab_tgid() and fd_take_tgid().
    - MINOR: fd: Add fd_lock_tgid_cur().
    - MEDIUM: epoll: Make sure we can add a new event
    - MINOR: pollers: Add a fixup_tgid_takeover() method.
    - MEDIUM: pollers: Drop fd events after a takeover to another tgid.
    - MEDIUM: connections: Allow taking over connections from other tgroups.
    - MEDIUM: servers: Add strict-maxconn.
    - BUG/MEDIUM: server: properly initialize PROXY v2 TLVs
    - BUG/MINOR: server: fix the "server-template" prefix memory leak
    - BUG/MINOR: h3: do not report transfer as aborted on preemptive response
    - CLEANUP: h3: fix documentation of h3_rcv_buf()
    - MINOR: hq-interop: properly handle incomplete request
    - BUG/MEDIUM: mux-fcgi: Try to fully fill demux buffer on receive if not empty
    - MINOR: h1: permit to relax the websocket checks for missing mandatory headers
    - BUG/MINOR: hq-interop: fix leak in case of rcv_buf early return
    - BUG/MINOR: server: check for either proxy-protocol v1 or v2 to send hedaer
    - MINOR: jws: implement a JWK public key converter
    - DEBUG: init: add a way to register functions for unit tests
    - TESTS: add a unit test runner in the Makefile
    - TESTS: jws: register a unittest for jwk
    - CI: github: run make unit-tests on the CI
    - TESTS: add config smoke checks in the unit tests
    - MINOR: jws: conversion to NIST curves name
    - CI: github: remove smoke tests from vtest.yml
    - TESTS: ist: fix wrong array size
    - TESTS: ist: use the exit code to return a verdict
    - TESTS: ist: add a ist.sh to launch in make unit-tests
    - CI: github: fix h2spec.config proxy names
    - DEBUG: init: Add a macro to register unit tests
    - MINOR: sample: allow custom date format in error-log-format
    - CLEANUP: log: removing "log-balance" references
    - BUG/MINOR: log: set proper smp size for balance log-hash
    - MINOR: log: use __send_log() with exact payload length
    - MEDIUM: log: postpone the decision to send or not log with empty messages
    - MINOR: proxy: make pr_mode enum bitfield compatible
    - MINOR: cfgparse-listen: add and use cfg_parse_listen_match_option() helper
    - MINOR: log: add options eval for log-forward
    - MINOR: log: detach prepare from parse message
    - MINOR: log: add dont-parse-log and assume-rfc6587-ntf options
    - BUG/MEIDUM: startup: return to initial cwd only after check_config_validity()
    - TESTS: change the output of run-unittests.sh
    - TESTS: unit-tests: store sh -x in a result file
    - CI: github: show results of the Unit tests
    - BUG/MINOR: cfgparse/peers: fix inconsistent check for missing peer server
    - BUG/MINOR: cfgparse/peers: properly handle ignored local peer case
    - BUG/MINOR: server: dont return immediately from parse_server() when skipping checks
    - MINOR: cfgparse/peers: provide more info when ignoring invalid "peer" or "server" lines
    - BUG/MINOR: stream: fix age calculation in "show sess" output
    - MINOR: stream/cli: rework "show sess" to better consider optional arguments
    - MINOR: stream/cli: make "show sess" support filtering on front/back/server
    - TESTS: quic: create first quic unittest
    - MINOR: h3/hq-interop: restore function for standalone FIN receive
    - MINOR/OPTIM: mux-quic: do not allocate rxbuf on standalone FIN
    - MINOR: mux-quic: refine reception of standalone STREAM FIN
    - MINOR: mux-quic: define globally stream rxbuf size
    - MINOR: mux-quic: define rxbuf wrapper
    - MINOR: mux-quic: store QCS Rx buf in a single-entry tree
    - MINOR: mux-quic: adjust Rx data consumption API
    - MINOR: mux-quic: adapt return value of qcc_decode_qcs()
    - MAJOR: mux-quic: support multiple QCS RX buffers
    - MEDIUM: mux-quic: handle too short data splitted on multiple rxbuf
    - MAJOR: mux-quic: increase stream flow-control for multi-buffer alloc
    - BUG/MINOR: cfgparse-tcp: relax namespace bind check
    - MINOR: startup: adjust alert messages, when capabilities are missed

4 months agoMINOR: startup: adjust alert messages, when capabilities are missed
Valentine Krasnobaeva [Fri, 7 Mar 2025 12:42:27 +0000 (13:42 +0100)] 
MINOR: startup: adjust alert messages, when capabilities are missed

CAP_SYS_ADMIN support was added, in order to access sockets in namespaces. So
let's adjust the alert at startup, where we check preserved capabilities from
global.last_checks. Let's mention here cap_sys_admin as well.

4 months agoBUG/MINOR: cfgparse-tcp: relax namespace bind check
Damien Claisse [Fri, 20 Dec 2024 13:36:34 +0000 (13:36 +0000)] 
BUG/MINOR: cfgparse-tcp: relax namespace bind check

Commit 5cbb278 introduced cap_sys_admin support, and enforced checks for
both binds and servers. However, when binding into a namespace, the bind
is done before dropping privileges. Hence, checking that we have
cap_sys_admin capability set in this case is not needed (and it would
decrease security to add it).
For users starting haproxy with other user than root and without
cap_sys_admin, bind should have already failed.
As a consequence, relax runtime check for binds into a namespace.

4 months agoMAJOR: mux-quic: increase stream flow-control for multi-buffer alloc
Amaury Denoyelle [Tue, 4 Mar 2025 14:25:44 +0000 (15:25 +0100)] 
MAJOR: mux-quic: increase stream flow-control for multi-buffer alloc

Support for multiple Rx buffers per QCS instance has been introduced by
previous patches. However, due to flow-control initial values, client
were still unable to fully used this to increase their upload
throughput.

This patch increases max-stream-data-bidi-remote flow-control initial
values. A new define QMUX_STREAM_RX_BUF_FACTOR will fix the number of
concurrent buffers allocable per QCS. It is set to 90.

Note that connection flow-control initial value did not changed. It is
still configured to be equivalent to bufsize multiplied by the maximum
concurrent streams. This ensures that Rx buffers allocation is still
constrained per connection, so that it won't be possible to have all
active QCS instances using in parallel their maximum Rx buffers count.

4 months agoMEDIUM: mux-quic: handle too short data splitted on multiple rxbuf
Amaury Denoyelle [Wed, 5 Mar 2025 14:29:24 +0000 (15:29 +0100)] 
MEDIUM: mux-quic: handle too short data splitted on multiple rxbuf

Previous commit introduces support for multiple Rx buffers per QCS
instance. Contiguous data may be splitted accross multiple buffers
depending on their offset.

A particular issue could arise with this new model. Indeed, app_ops
rcv_buf callback can still deal with a single buffer at a time. This may
cause a deadlock in decoding if app_ops layer cannot proceed due to
partial data, but such data are precisely divided on two buffers. This
can for example intervene during HTTP/3 frame header parsing.

To deal with this, a new function is implemented to force data realign
between two contiguous buffers. This is called only when app_ops rcv_buf
returned 0 but data is available in the next buffer after the current
one. In this case, data are transferred from the next into the current
buffer via qcs_transfer_rx_data(). Decoding is then restarted, which
should ensure that app_ops layer has enough data to advance.

During this operation, special care is ensure to removed both
qc_stream_rxbuf entries, as their offset are adjusted. The next buffer
is only reinserted if there is remaining data in it, else it can be
freed.

This case is not easily reproducible as it depends on the HTTP/3 framing
used by the client. It seems to be easily reproduced though with quiche.
$ quiche-client --http-version HTTP/3 --method POST --body /tmp/100m \
  "https://127.0.0.1:20443/post"

4 months agoMAJOR: mux-quic: support multiple QCS RX buffers
Amaury Denoyelle [Fri, 7 Mar 2025 10:43:01 +0000 (11:43 +0100)] 
MAJOR: mux-quic: support multiple QCS RX buffers

Implement support for multiple Rx buffers per QCS instances. This
requires several changes mostly in qcc_recv() / qcc_decode_qcs() which
deal with STREAM frames reception and decoding. These multiple buffers
can be stored in QCS rx.bufs tree which was introduced in an earlier
patch.

On STREAM frame reception, a buffer is retrieved from QCS bufs tree, or
allocated if necessary, based on the data starting offset. Each buffers
are aligned on bufsize for convenience. This ensures there is no overlap
between two contiguous buffers. Special care is taken when dealing with
a STREAM frame which must be splitted and stored in two contiguous
buffers.

When decoding input data, qcc_decode_qcs() is still invoked with a
single buffer as input. This requires a new while loop to ensure
decoding is performed accross multiple contiguous buffers until all data
are decoded or app stream buffer is full.

Also, after qcs_consume() has been performed, the stream Rx channel is
immediately closed if FIN was already received and QCS now contains only
a single buffer with all remaining data. This is necessary as qcc_recv()
is unable to close the Rx channel if FIN is received for a buffer
different from the current readable offset.

Note that for now stream flow-control value is still too low to fully
utilizing this new infrastructure and improve clients upload throughput.
Indeed, flow-control max-stream-data initial values are set to match
bufsize. This ensures that each QCS will use 1 buffer, or at most 2 if
data are splitted. A future patch will increase this value to unblock
this limitation.

4 months agoMINOR: mux-quic: adapt return value of qcc_decode_qcs()
Amaury Denoyelle [Mon, 3 Mar 2025 09:01:07 +0000 (10:01 +0100)] 
MINOR: mux-quic: adapt return value of qcc_decode_qcs()

Change return value of qcc_decode_qcs(). It now directly returns the
value from app_ops rcv_buf callback. Function documentation is updated
to reflect this.

For now, qcc_decode_qcs() return value is ignored by callers, so this
patch should not have any functional change. However, it will become
necessary when implementing multiple Rx buffers per QCS, as a loop will
be implemented to invoke qcc_decode_qcs() on several contiguous buffers.
Decoding must be stopped however as soon as an error is returned by
rcv_buf callback. This is also the case in case of a null value, which
indicates there is not enough data to continue decoding.

4 months agoMINOR: mux-quic: adjust Rx data consumption API
Amaury Denoyelle [Tue, 4 Mar 2025 14:23:28 +0000 (15:23 +0100)] 
MINOR: mux-quic: adjust Rx data consumption API

HTTP/3 data are converted into HTX via qcc_decode_qcs() function. On
completion, these data are removed from QCS Rx buffer via qcs_consume().

This patch adjust qcs_consume() API with several changes. Firstly, the
Rx buffer instance to operate on must now be specified as a new argument
to the function. Secondly, buffer liberation when all data were removed
from qcs_consume() is extracted up to qcc_decode_qcs() caller.

No functional change with this patch. The objective is to have an API
which can be better adapted to multiple Rx buffers per QCS instance.

4 months agoMINOR: mux-quic: store QCS Rx buf in a single-entry tree
Amaury Denoyelle [Mon, 24 Feb 2025 15:28:50 +0000 (16:28 +0100)] 
MINOR: mux-quic: store QCS Rx buf in a single-entry tree

Convert QCS rx buffer pointer to a tree container. Additionnaly, offset
field of qc_stream_rxbuf is thus transformed into a node tree.

For now, only a single Rx buffer is stored at most in QCS tree. Multiple
Rx buffers will be implemented in a future patch to improve QUIC clients
upload throughput.

4 months agoMINOR: mux-quic: define rxbuf wrapper
Amaury Denoyelle [Mon, 24 Feb 2025 15:22:22 +0000 (16:22 +0100)] 
MINOR: mux-quic: define rxbuf wrapper

Define a new type qc_stream_rxbuf. This is used as a wrapper around QCS
Rx buffer with encapsulation of the ncbuf storage. It is allocated via a
new pool. Several functions are adapted to be able to deal with
qc_stream_rxbuf as a wrapper instead of the previous plain ncbuf
instance.

No functional change should happen with this patch. For now, only a
single qc_stream_rxbuf can be instantiated per QCS. However, this new
type will be useful to implement multiple Rx buffer storage in a future
commit.

4 months agoMINOR: mux-quic: define globally stream rxbuf size
Amaury Denoyelle [Wed, 26 Feb 2025 10:27:42 +0000 (11:27 +0100)] 
MINOR: mux-quic: define globally stream rxbuf size

QCS uses ncbuf for STREAM data storage. This serves as a limit for
maximum STREAM buffering capacity, advertised via QUIC transport
parameters for initial flow-control values.

Define a new function qmux_stream_rx_bufsz() which can be used to
retrieve this Rx buffer size. This can be used both in MUX/H3 layers and
in QUIC transport parameters.

4 months agoMINOR: mux-quic: refine reception of standalone STREAM FIN
Amaury Denoyelle [Tue, 4 Mar 2025 08:41:44 +0000 (09:41 +0100)] 
MINOR: mux-quic: refine reception of standalone STREAM FIN

Reception of standalone STREAM FIN is a corner case, which may be
difficult to handle. In particular, care must be taken to ensure app_ops
rcv_buf() is always called to be notify about FIN, even if Rx buffer is
empty or full demux flag is set. If this is the case, it could prevent
closure of QCS Rx channel.

To ensure this, rcv_buf() was systematically called if FIN was received,
with or without data payload. This could called unnecessary invokation
when FIN is transmitted with data and full demux flag is set, or data
are received out-of-order.

This patches improve qcc_recv() by detecting explicitely a standalone
FIN case. Thus, rcv_buf() is only forcefully called in this case and if
all data were already previously received.

4 months agoMINOR/OPTIM: mux-quic: do not allocate rxbuf on standalone FIN
Amaury Denoyelle [Thu, 27 Feb 2025 10:35:41 +0000 (11:35 +0100)] 
MINOR/OPTIM: mux-quic: do not allocate rxbuf on standalone FIN

STREAM FIN may be received without any payload. However, qcc_recv()
always called qcs_get_ncbuf() indiscriminately, which may allocate a QCS
Rx buffer. This is unneeded as there is no payload to store.

Improve this by skipping qcs_get_ncbuf() invokation when dealing with a
standalone FIN signal. This should prevent superfluous buffer
allocation.

4 months agoMINOR: h3/hq-interop: restore function for standalone FIN receive
Amaury Denoyelle [Thu, 27 Feb 2025 10:33:21 +0000 (11:33 +0100)] 
MINOR: h3/hq-interop: restore function for standalone FIN receive

Previously, a function qcs_http_handle_standalone_fin() was implemented
to handle a received standalone FIN, bypassing app_ops layer decoding.
However, this was removed as app_ops layer interaction is necessary. For
example, HTTP/3 checks that FIN is never sent on the control uni stream.

This patch reintroduces qcs_http_handle_standalone_fin(), albeit in a
slightly diminished version. Most importantly, it is now the
responsibility of the app_ops layer itself to use it, to avoid the
shortcoming described above.

The main objective of this patch is to be able to support standalone FIN
in HTTP/0.9 layer. This is easily done via the reintroduction of
qcs_http_handle_standalone_fin() usage. This will be useful to perform
testing, as standalone FIN is a corner case which can easily be broken.

4 months agoTESTS: quic: create first quic unittest
Amaury Denoyelle [Wed, 5 Mar 2025 09:24:44 +0000 (10:24 +0100)] 
TESTS: quic: create first quic unittest

Define a first unit-test dedicated to QUIC. A single test for now
ensures that variable length decoding is compliant. This should be
extended in the future with new set of tests.

4 months agoMINOR: stream/cli: make "show sess" support filtering on front/back/server
Willy Tarreau [Fri, 7 Mar 2025 09:34:19 +0000 (10:34 +0100)] 
MINOR: stream/cli: make "show sess" support filtering on front/back/server

With "show sess", particularly "show sess all", we're often missing the
ability to inspect only streams attached to a frontend, backend or server.
Let's just add these filters to the command. Only one at a time may be set.

One typical use case could be to dump streams attached to a server after
issuing "shutdown sessions server XXX" to figure why any wouldn't stop
for example.

4 months agoMINOR: stream/cli: rework "show sess" to better consider optional arguments
Willy Tarreau [Fri, 7 Mar 2025 09:21:21 +0000 (10:21 +0100)] 
MINOR: stream/cli: rework "show sess" to better consider optional arguments

The "show sess" CLI command parser is getting really annoying because
several options were added in an exclusive mode as the single possible
argument. Recently some cumulable options were added ("show-uri") but
the older ones were not yet adapted. Let's just make sure that the
various filters such as "older" and "age" now belong to the options
and leave only <id>, "all", and "help" for the first ones. The doc was
updated and it's now easier to find these options.

4 months agoBUG/MINOR: stream: fix age calculation in "show sess" output
Willy Tarreau [Thu, 6 Mar 2025 17:56:13 +0000 (18:56 +0100)] 
BUG/MINOR: stream: fix age calculation in "show sess" output

The "show sess" output reports an age that's based on the last byte of
the HTTP request instead of the stream creation date, due to a confusion
between logs->request_ts and the request_date sample fetch function. Most
of the time these are equal except when the request is not yet full for
any reason (e.g. wait-body). This explains why a few "show sess" could
report a few new streams aged by 99 days for example.

Let's perform the correct request timestamp calculation like the sample
fetch function does, by adding t_idle and t_handshake to the accept_ts.
Now the stream's age is correct and can be correctly used with the
"show sess older <age>" variant.

This issue was introduced in 2.9 and the fix can be backported to 3.0.

4 months agoMINOR: cfgparse/peers: provide more info when ignoring invalid "peer" or "server...
Aurelien DARRAGON [Fri, 7 Mar 2025 08:30:47 +0000 (09:30 +0100)] 
MINOR: cfgparse/peers: provide more info when ignoring invalid "peer" or "server" lines

Invalid (incomplete) "server" or "peer" lines under peers section are now
properly ignored. For completeness, in this patch we add some reports so
that the user knows that incomplete lines were ignored.

For an incomplete server line, since it is tolerated (see GH #565), we
only emit a diag warning.

For an incomplete peer line, we report a real warning, as it is not
expected to have a peer line without an address:port specified.

Also, 'newpeer == curpeers->local' check could be simplified since
we already have the 'local_peer' variable which tells us that the
parsed line refers to a local peer.

4 months agoBUG/MINOR: server: dont return immediately from parse_server() when skipping checks
Aurelien DARRAGON [Fri, 7 Mar 2025 08:11:21 +0000 (09:11 +0100)] 
BUG/MINOR: server: dont return immediately from parse_server() when skipping checks

If parse_server() is called under peers section parser, and the address
needs to be parsed but it is missing, we directly return from the function

However since 0fc136ce5b ("REORG: server: use parsing ctx for server
parsing"), parse_server() uses parsing ctx to emit warning/errors, and
the ctx must be reset before returning from the function, yet this early
return was overlooked. Because of that, any ha_{warning,alert..} message
reported after early return from parse_server() could cause messages to
have an extra "parsing [file:line]" info.

We fix that by ensuring parse_server() doesn't return without resetting
the parsing context.

It should be backported up to 2.6

4 months agoBUG/MINOR: cfgparse/peers: properly handle ignored local peer case
Aurelien DARRAGON [Thu, 6 Mar 2025 08:29:05 +0000 (09:29 +0100)] 
BUG/MINOR: cfgparse/peers: properly handle ignored local peer case

In 8ba10fea6 ("BUG/MINOR: peers: Incomplete peers sections should be
validated."), some checks were relaxed in parse_server(), and extra logic
was added in the peers section parser in an attempt to properly ignore
incomplete "server" or "peer" statement under peers section.

This was done in response to GH #565, the main intent was that haproxy
should already complain about incomplete peers section (ie: missing
localpeer).

However, 8ba10fea69 explicitly skipped the peer cleanup upon missing
srv association for local peers. This is wrong because later haproxy
code always assumes that peer->srv is valid. Indeed, we got reports
that the (invalid) config below would cause segmentation fault on
all stable versions:

 global
   localpeer 01JM0TEPAREK01FQQ439DDZXD8

 peers my-table
   peer 01JM0TEPAREK01FQQ439DDZXD8

 listen dummy
   bind localhost:8080

To fix the issue, instead of by-passing some cleanup for the local
peer, handle this case specifically by doing the regular peer cleanup
and reset some fields set on the curpeers and curpeers proxy because
of the invalid local peer (do as if the peer was not declared).

It should still comply with requirements from #565.

This patch should be backported to all stable versions.

4 months agoBUG/MINOR: cfgparse/peers: fix inconsistent check for missing peer server
Aurelien DARRAGON [Thu, 6 Mar 2025 08:05:23 +0000 (09:05 +0100)] 
BUG/MINOR: cfgparse/peers: fix inconsistent check for missing peer server

In the "peers" section parser, right after parse_server() is called, we
used to check whether the curpeers->peers_fe->srv pointer was set or not
to know if parse_server() successfuly added a server to the peers proxy,
server that we can then associate to the new peer.

However the check is wrong, as curpeers->peers_fe->srv points to the
last added server, if a server was successfully added before the
failing one, we cannot detect that the last parse_server() didn't
add a server. This is known to cause bug with bad "peer"/"server"
statements.

To fix the issue, we save a pointer on the last known
curpeers->peers_fe->srv before parse_server() is called, and we then
compare the save with the pointer after parse_server(), if the value
didn't change, then parse_server() didn't add a server. This makes
the check consistent in all situations.

It should be backported to all stable versions.

4 months agoCI: github: show results of the Unit tests
William Lallemand [Thu, 6 Mar 2025 20:02:02 +0000 (21:02 +0100)] 
CI: github: show results of the Unit tests

Add a "Show Unit-Tests results" section which show each unit test which
failed by displaying their result file.

4 months agoTESTS: unit-tests: store sh -x in a result file
William Lallemand [Thu, 6 Mar 2025 19:57:36 +0000 (20:57 +0100)] 
TESTS: unit-tests: store sh -x in a result file

Store `sh -e -x` of the test in a result file. This file is deleted upon
success, but can be consulted if the test fails

4 months agoTESTS: change the output of run-unittests.sh
William Lallemand [Thu, 6 Mar 2025 16:43:11 +0000 (17:43 +0100)] 
TESTS: change the output of run-unittests.sh

- "check" is run with sh -e so it will stop at the first error
- output of "check" is not shown anymore
- add a line with the name of the failed test

4 months agoBUG/MEIDUM: startup: return to initial cwd only after check_config_validity()
Valentine Krasnobaeva [Tue, 4 Mar 2025 10:04:01 +0000 (11:04 +0100)] 
BUG/MEIDUM: startup: return to initial cwd only after check_config_validity()

In check_config_validity() we evaluate some sample fetch expressions
(log-format, server rules, etc). These expressions may use external files like
maps.

If some particular 'default-path' was set in the global section before, it's no
longer applied to resolve file pathes in check_config_validity(). parse_cfg()
at the end of config parsing switches back to the initial cwd.

This fixes the issue #2886.

This patch should be backported in all stable versions since 2.4.0, including
2.4.0.

4 months agoMINOR: log: add dont-parse-log and assume-rfc6587-ntf options
Roberto Moreda [Mon, 3 Mar 2025 20:57:52 +0000 (21:57 +0100)] 
MINOR: log: add dont-parse-log and assume-rfc6587-ntf options

This commit introduces the dont-parse-log option to disable log message
parsing, allowing raw log data to be forwarded without modification.

Also, it adds the assume-rfc6587-ntf option to frame log messages
using only non-transparent framing as per RFC 6587. This avoids
missparsing in certain cases (mainly with non RFC compliant messages).

The documentation is updated to include details on the new options and
their intended use cases.

This feature was discussed in GH #2856

4 months agoMINOR: log: detach prepare from parse message
Roberto Moreda [Sun, 2 Mar 2025 21:02:25 +0000 (22:02 +0100)] 
MINOR: log: detach prepare from parse message

This commit adds a new function `prepare_log_message` to initialize log
message buffers and metadata. This function sets default values for log
level and facility, ensuring a consistent starting state for log
processing. It also prepares the buffer and metadata fields, simplifying
subsequent log parsing and construction.

4 months agoMINOR: log: add options eval for log-forward
Roberto Moreda [Mon, 3 Mar 2025 19:48:01 +0000 (20:48 +0100)] 
MINOR: log: add options eval for log-forward

This commit adds parsing of options in log-forward config sections and
prepares the scenario to implement actual changes of behaviuor. So far
we only take in account proxy->options2, which is the bit container with
more available positions.

4 months agoMINOR: cfgparse-listen: add and use cfg_parse_listen_match_option() helper
Aurelien DARRAGON [Wed, 5 Mar 2025 19:55:41 +0000 (20:55 +0100)] 
MINOR: cfgparse-listen: add and use cfg_parse_listen_match_option() helper

cfg_parse_listen_match_option() takes cfg_opt array as parameter, as well
current args, expected mode and cap bitfields.

It is expected to be used under cfg_parse_listen() function or similar.
Its goal is to remove code duplication around proxy->options and
proxy->options2 handling, since the same checks are performed for the
two. Also, this function could help to evaluate proxy options for
mode-specific proxies such as log-forward section for instance:
by giving the expected mode and capatiblity as input, the function
would only match compatible options.

4 months agoMINOR: proxy: make pr_mode enum bitfield compatible
Aurelien DARRAGON [Wed, 5 Mar 2025 15:53:56 +0000 (16:53 +0100)] 
MINOR: proxy: make pr_mode enum bitfield compatible

Current pr_mode enum is a regular enum because a proxy only supports one
mode at a time. However it can be handy for a function to be given a
list of compatible modes for a proxy, and we can't do that using a
bitfield because pr_mode is not bitfield compatible (values share
the same bits).

In this patch we manually define pr_mode values so that they are all
using separate bits and allows a function to take a bitfield of
compatible modes as parameter.

4 months agoMEDIUM: log: postpone the decision to send or not log with empty messages
Aurelien DARRAGON [Wed, 5 Mar 2025 10:28:14 +0000 (11:28 +0100)] 
MEDIUM: log: postpone the decision to send or not log with empty messages

As reported by Nick Ramirez in GH #2891, it is currently not possible to
use log-profile without a log-format set on the proxy.

This is due to historical reason, because all log sending functions avoid
trying to send a log with empty message. But now with log-profile which
can override log-format, it is possible that some loggers may actually
end up generating a valid log message that should be sent! Yet from the
upper logging functions we don't know about that because loggers are
evaluated in lower API functions.

Thus, to avoid skipping potentially valid messages (thanks to log-profile
overrides), in this patch we postpone the decision to send or not empty
log messages in lower log API layer, ie: _process_send_log_final(), once
the log-profile settings were evaluated for a given logger.

A known side-effect of this change is that fe->log_count statistic may
be increased even if no log message is sent because the message was empty
and even the log-profile didn't help to produce a non empty log message.
But since configurations lacking proxy log-format are not supposed to be
used without log-profile (+ log steps combination) anyway it shouldn't be
an issue.

4 months agoMINOR: log: use __send_log() with exact payload length
Aurelien DARRAGON [Wed, 5 Mar 2025 11:52:17 +0000 (12:52 +0100)] 
MINOR: log: use __send_log() with exact payload length

Historically, __send_log() was called with terminating NULL byte after
the message payload. But now that __send_log() supports being called
without terminating NULL byte (thanks to size hint), and that __sendlog()
actually stips any \n or NULL byte, we don't need to bother with that
anymore. So let's remove extra logic around __send_log() users where we
added 1 extra byte for the terminating NULL byte.

No change of behavior should be expected.

4 months agoBUG/MINOR: log: set proper smp size for balance log-hash
Aurelien DARRAGON [Wed, 5 Mar 2025 11:01:34 +0000 (12:01 +0100)] 
BUG/MINOR: log: set proper smp size for balance log-hash

result.data.u.str.size was set to size+1 to take into account terminating
NULL byte as per the comment. But this is wrong because the caller is free
to set size to just the right amount of bytes (without terminating NULL
byte). In fact all smp API functions will not read past str.data so there
is not risk about uninitialized reads, but this leaves an ambiguity for
converters that may use all the smp size to perform transformations, and
since we don't know about the "message" memory origin, we cannot assume
that its size may be greater than size. So we max it out to size just to
be safe.

This bug was not known to cause any issue, it was spotted during code
review. It should be backported in 2.9 with b30bd7a ("MEDIUM: log/balance:
support for the "hash" lb algorithm")

4 months agoCLEANUP: log: removing "log-balance" references
Aurelien DARRAGON [Wed, 5 Mar 2025 10:33:06 +0000 (11:33 +0100)] 
CLEANUP: log: removing "log-balance" references

This is a complementary patch to 0e1f389fe9 ("DOC: config: removing
"log-balance" references"): we properly removed all log-balance
references in the doc but there remained some in the code, let's fix
that.

It could be backported in 2.9 with 0e1f389fe9

4 months agoMINOR: sample: allow custom date format in error-log-format
Valentine Krasnobaeva [Tue, 4 Mar 2025 15:35:05 +0000 (16:35 +0100)] 
MINOR: sample: allow custom date format in error-log-format

Sample fetches %[accept_date] and %[request_date] with converters can be used
in error-log-format string. But in the most error cases they fetches nothing,
as error logs are produced on SSL handshake issues or when invalid PROXY
protocol header is used. Stream object is never allocated in such cases and
smp_fetch_accept_date() just simply returns 0.

There is a need to have a custom date format (ISO8601) also in the error logs,
along with normal logs. When sess_build_logline_orig() builds log line it
always copies the accept date to strm_logs structure. When stream is absent,
accept date is copied from the session object.

So, if the steam object wasn't allocated, let's use the session date info in
smp_fetch_accept_date(). This allows then, in sample_process(), to apply to the
fetched date different converters and formats.

This fixes the issue #2884.

4 months agoDEBUG: init: Add a macro to register unit tests
Olivier Houchard [Tue, 4 Mar 2025 16:46:18 +0000 (17:46 +0100)] 
DEBUG: init: Add a macro to register unit tests

Add a new macro, REGISTER_UNITTEST(), that will automatically make sure
we call hap_register_unittest(), instead of having to create a function
that will do so.

4 months agoCI: github: fix h2spec.config proxy names
William Lallemand [Tue, 4 Mar 2025 10:44:03 +0000 (11:44 +0100)] 
CI: github: fix h2spec.config proxy names

h2spec.config config file emitted a warning because the frontend name
has the same name as the backend.

4 months agoTESTS: ist: add a ist.sh to launch in make unit-tests
William Lallemand [Tue, 4 Mar 2025 10:23:33 +0000 (11:23 +0100)] 
TESTS: ist: add a ist.sh to launch in make unit-tests

Compile and run the ist unit tests from ist.sh

4 months agoTESTS: ist: use the exit code to return a verdict
William Lallemand [Tue, 4 Mar 2025 10:20:35 +0000 (11:20 +0100)] 
TESTS: ist: use the exit code to return a verdict

Use the exit code to return a verdict on the test.

4 months agoTESTS: ist: fix wrong array size
William Lallemand [Tue, 4 Mar 2025 09:47:08 +0000 (10:47 +0100)] 
TESTS: ist: fix wrong array size

test_istzero() and test_istpad() has the wrong array size buf[] which
lacks the space for the '\0';

Could be backported in every stable branches.

4 months agoCI: github: remove smoke tests from vtest.yml
William Lallemand [Mon, 3 Mar 2025 11:46:20 +0000 (12:46 +0100)] 
CI: github: remove smoke tests from vtest.yml

Smoke tests from the vtest.yml are not useful anymore since they are run
directly by tests/unit/smoke/test.sh. This patch removes them.

4 months agoMINOR: jws: conversion to NIST curves name
William Lallemand [Sat, 1 Mar 2025 22:58:48 +0000 (23:58 +0100)] 
MINOR: jws: conversion to NIST curves name

OpenSSL version greater than 3.0 does not use the same API when
manipulating EVP_PKEY structures, the EC_KEY API is deprecated and it's
not possible anymore to get an EC_GROUP and simply call
EC_GROUP_get_curve_name().

Instead, one must call EVP_PKEY_get_utf8_string_param with the
OSSL_PKEY_PARAM_GROUP_NAME parameter, but this would result in a SECG
curves name, instead of a NIST curves name in previous version.
(ex: secp384r1 vs P-384)

This patch adds 2 functions:

- the first one look for a curves name and converts it to an openssl
  NID.

- the second one converts a NID to a NIST curves name

The list only contains: P-256, P-384 and P-521 for now, it could be
extended in the fure with more curves.

4 months agoTESTS: add config smoke checks in the unit tests
William Lallemand [Sat, 1 Mar 2025 18:16:18 +0000 (19:16 +0100)] 
TESTS: add config smoke checks in the unit tests

vtest.yml contains some config checks that are used to check the
memleaks.

This patch adds a unit test which runs the same tests.

4 months agoCI: github: run make unit-tests on the CI
William Lallemand [Sat, 1 Mar 2025 17:20:15 +0000 (18:20 +0100)] 
CI: github: run make unit-tests on the CI

Run the new make unit-tests on the CI.

It requires HAProxy to be built with -DDEBUG_UNIT so the -U option is
available in HAProxy

4 months agoTESTS: jws: register a unittest for jwk
William Lallemand [Fri, 28 Feb 2025 21:27:28 +0000 (22:27 +0100)] 
TESTS: jws: register a unittest for jwk

Add a way to test the jwk converter in the unit test system

    $ make TARGET=linux-glibc USE_OPENSSL=1 CFLAGS="-DDEBUG_UNIT=1"
    $ ./haproxy -U jwk foobar.pem.rsa
    {
        "kty": "RSA",
        "n":   "...",
        "e":   "AQAB"
    }
    $ ./haproxy -U jwk foobar.pem.ecdsa
    {
        "kty": "EC",
        "crv": "P-384",
        "x":   "...",
        "y":   "..."
    }

This is then tested by a shell script:

    $ HAPROXY_PROGRAM=${PWD}/haproxy tests/unit/jwk/test.sh
    + readlink -f tests/unit/jwk/test.sh
    + BASENAME=/haproxy/tests/unit/jwk/test.sh
    + dirname /haproxy/tests/unit/jwk/test.sh
    + TESTDIR=/haproxy/tests/unit/jwk
    + HAPROXY_PROGRAM=/haproxy/haproxy
    + mktemp
    + FILE1=/tmp/tmp.iEICxC5yNK
    + /haproxy/haproxy -U jwk /haproxy/tests/unit/jwk/ecdsa.key
    + diff -Naurp /haproxy/tests/unit/jwk/ecdsa.pub.jwk /tmp/tmp.iEICxC5yNK
    + rm /tmp/tmp.iEICxC5yNK
    + mktemp
    + FILE2=/tmp/tmp.EIrGZGaCDi
    + /haproxy/haproxy -U jwk /haproxy/tests/unit/jwk/rsa.key
    + diff -Naurp /haproxy/tests/unit/jwk/rsa.pub.jwk /tmp/tmp.EIrGZGaCDi
    + rm /tmp/tmp.EIrGZGaCDi

    $ echo $?
    0

4 months agoTESTS: add a unit test runner in the Makefile
William Lallemand [Sat, 1 Mar 2025 16:22:45 +0000 (17:22 +0100)] 
TESTS: add a unit test runner in the Makefile

`make unit-tests` would run shell scripts from tests/unit/

The run-unittests.sh script will look for any .sh in tests/unit/ and
will call it twice:

- first with the 'check' argument in order to decide if we should skip
  the test or not
- second to run the check

A simple test could be written this way:

#!/bin/sh

check() {
       ${HAPROXY_PROGRAM} -cc 'feature(OPENSSL)'
       command -v socat
}

run() {
 ${HAPROXY_PROGRAM} -dI -f ${ROOTDIR}/examples/quick-test.cfg -c
}

case "$1" in
       "check")
               check
       ;;
       "run")
               run
       ;;
esac

The tests *MUST* be written in POSIX shell in order to be portable, and
any special commands should be tested with `command -v` before using it.

Tests are run with `sh -e` so everything must be tested.

4 months agoDEBUG: init: add a way to register functions for unit tests
William Lallemand [Fri, 28 Feb 2025 20:44:35 +0000 (21:44 +0100)] 
DEBUG: init: add a way to register functions for unit tests

Doing unit tests with haproxy was always a bit difficult, some of the
function you want to test would depend on the buffer or trash buffer
initialisation of HAProxy, so building a separate main() for them is
quite hard.

This patch adds a way to register a function that can be called with the
"-U" parameter on the command line, will be executed just after
step_init_1() and will exit the process with its return value as an exit
code.

When using the -U option, every keywords after this option is passed to
the callback and could be used as a parameter, letting the capability to
handle complex arguments if required by the test.

HAProxy need to be built with DEBUG_UNIT to activate this feature.

4 months agoMINOR: jws: implement a JWK public key converter
William Lallemand [Fri, 28 Feb 2025 15:11:08 +0000 (16:11 +0100)] 
MINOR: jws: implement a JWK public key converter

Implement a converter which takes an EVP_PKEY and converts it to a
public JWK key. This is the first step of the JWS implementation.

It supports both EC and RSA keys.

Know to work with:

- LibreSSL
- AWS-LC
- OpenSSL > 1.1.1

4 months agoBUG/MINOR: server: check for either proxy-protocol v1 or v2 to send hedaer
Willy Tarreau [Mon, 3 Mar 2025 02:58:46 +0000 (03:58 +0100)] 
BUG/MINOR: server: check for either proxy-protocol v1 or v2 to send hedaer

As reported in issue #2882, using "no-send-proxy-v2" on a server line does
not properly disable the use of proxy-protocol if it was enabled in a
default-server directive in combination with other PP options. The reason
for this is that the sending of a proxy header is determined by a test on
srv->pp_opts without any distinction, so disabling PPv2 while leaving other
options results in a PPv1 header to be sent.

Let's fix this by explicitly testing for the presence of either send-proxy
or send-proxy-v2 when deciding to send a proxy header.

This can be backported to all versions. Thanks to Andre Sencioles (@asenci)
for reporting the issue and testing the fix.

4 months agoBUG/MINOR: hq-interop: fix leak in case of rcv_buf early return
Amaury Denoyelle [Thu, 27 Feb 2025 17:07:17 +0000 (18:07 +0100)] 
BUG/MINOR: hq-interop: fix leak in case of rcv_buf early return

HTTP/0.9 parser was recently updated to support truncated requests in
rcv_buf operation. However, this caused a leak as input buffer is
allocated early.

In fact, the leak was already present in case of fatal errors. Fix this
by first delaying buffer allocation, so that initial checks are
performed before. Then, ensure that buffer is released in case of a
latter error.

This is considered as minor, as HTTP/0.9 is reserved for experiment and
QUIC interop usages.

This should be backported up to 2.6.

4 months agoMINOR: h1: permit to relax the websocket checks for missing mandatory headers
Willy Tarreau [Fri, 28 Feb 2025 12:35:13 +0000 (13:35 +0100)] 
MINOR: h1: permit to relax the websocket checks for missing mandatory headers

At least one user would like to allow a standards-violating client setup
WebSocket connections through haproxy to a standards-violating server that
accepts them. While this should of course never be done over the internet,
it can make sense in the datacenter between application components which do
not need to mask the data, so this typically falls into the situation of
what the "accept-unsafe-violations-in-http-request" option and the
"accept-unsafe-violations-in-http-response" option are made for.
See GH #2876 for more context.

This patch relaxes the test on the "Sec-Websocket-Key" header field in
the request, and of the "Sec-Websocket-Accept" header in the response
when these respective options are set.

The doc was updated to reference this addition. This may be backported
to 3.1 but preferably not further.

4 months agoBUG/MEDIUM: mux-fcgi: Try to fully fill demux buffer on receive if not empty
Christopher Faulet [Fri, 28 Feb 2025 15:07:00 +0000 (16:07 +0100)] 
BUG/MEDIUM: mux-fcgi: Try to fully fill demux buffer on receive if not empty

Don't reserve space for the HTX overhead on receive if the demux buffer is
not empty. Otherwise, the demux buffer may be erroneously reported as full
and this may block records processing. Because of this bug, a ping-pong loop
till timeout between data reception and demux process can be observed.

This bug was introduced by the commit 5f927f603 ("BUG/MEDIUM: mux-fcgi:
Properly handle read0 on partial records"). To fix the issue, if the demux
buffer is not empty when we try to receive more data, all free space in the
buffer can now be used. However, if the demux buffer is empty, we still try
to keep it aligned with the HTX.

This patch must be backported to 3.1.

4 months agoMINOR: hq-interop: properly handle incomplete request
Amaury Denoyelle [Thu, 27 Feb 2025 10:34:39 +0000 (11:34 +0100)] 
MINOR: hq-interop: properly handle incomplete request

Extends HTTP/0.9 layer to be able to deal with incomplete requests.
Instead of an error, 0 is returned. Thus, instead of a stream closure.
QUIC-MUX may retry rcv_buf operation later if more data is received,
similarly to HTTP/3 layer.

Note that HTTP/0.9 is only used for testing and interop purpose. As
such, this limitation is not considered as a bug. It is probably not
worth to backport it.

4 months agoCLEANUP: h3: fix documentation of h3_rcv_buf()
Amaury Denoyelle [Thu, 27 Feb 2025 10:28:07 +0000 (11:28 +0100)] 
CLEANUP: h3: fix documentation of h3_rcv_buf()

Return value of h3_rcv_buf() is incorrectly documented. Indeed, it may
return a positive value to indicate that input bytes were converted into
HTX. This is especially important, as caller uses this value to consume
the reported data amount in QCS Rx buffer.

This should be backported up to 2.6. Note that on 2.8, h3_rcv_buf() was
named h3_decode_qcs().

4 months agoBUG/MINOR: h3: do not report transfer as aborted on preemptive response
Amaury Denoyelle [Thu, 27 Feb 2025 15:38:39 +0000 (16:38 +0100)] 
BUG/MINOR: h3: do not report transfer as aborted on preemptive response

HTTP/3 specification allows a server to emit the entire response even if
only a partial request was received. In particular, this happens when
request STREAM FIN is delayed and transmitted in an empty payload frame.

In this case, qcc_abort_stream_read() was used by HTTP/3 layer to emit a
STOP_SENDING. Remaining received data were not transmitted to the stream
layer as they were simply discared. However, this prevents FIN
transmission to the stream layer. This causes the transfer to be
considered as prematurely closed, resulting in a cL-- log line status.
This is misleading to users which could interpret it as if the response
was not sent.

To fix this, disable STOP_SENDING emission on full preemptive reponse
emission. Rx channel is kept opened until the client closes it with
either a FIN or a RESET_STREAM. This ensures that the FIN signal can be
relayed to the stream layer, which allows the transfer to be reported as
completed.

This should be backported up to 2.9.

4 months agoBUG/MINOR: server: fix the "server-template" prefix memory leak
Dragan Dosen [Wed, 26 Feb 2025 21:56:41 +0000 (22:56 +0100)] 
BUG/MINOR: server: fix the "server-template" prefix memory leak

The srv->tmpl_info.prefix was not freed in srv_free_params().

This could be backported to all stable versions.

4 months agoBUG/MEDIUM: server: properly initialize PROXY v2 TLVs
Dragan Dosen [Wed, 26 Feb 2025 18:13:31 +0000 (19:13 +0100)] 
BUG/MEDIUM: server: properly initialize PROXY v2 TLVs

The PROXY v2 TLVs were not properly initialized when defined with
"set-proxy-v2-tlv-fmt" keyword, which could have caused a crash when
validating the configuration or malfunction (e.g. when used in
combination with "server-template" and/or "default-server").

The issue was introduced with commit 6f4bfed3a ("MINOR: server: Add
parser support for set-proxy-v2-tlv-fmt").

This should be backported up to 2.9.

4 months agoMEDIUM: servers: Add strict-maxconn.
Olivier Houchard [Thu, 6 Feb 2025 16:07:48 +0000 (17:07 +0100)] 
MEDIUM: servers: Add strict-maxconn.

Maxconn is a bit of a misnomer when it comes to servers, as it doesn't
control the maximum number of connections we establish to a server, but
the maximum number of simultaneous requests. So add "strict-maxconn",
that will make it so we will never establish more connections than
maxconn.
It extends the meaning of the "restricted" setting of
tune.takeover-other-tg-connections, as it will also attempt to get idle
connections from other thread groups if strict-maxconn is set.

4 months agoMEDIUM: connections: Allow taking over connections from other tgroups.
Olivier Houchard [Thu, 30 Jan 2025 10:16:40 +0000 (11:16 +0100)] 
MEDIUM: connections: Allow taking over connections from other tgroups.

Allow haproxy to take over idle connections from other thread groups
than our own. To control that, add a new tunable,
tune.takeover-other-tg-connections. It can have 3 values, "none", where
we won't attempt to get connections from the other thread group (the
default), "restricted", where we only will try to get idle connections
from other thread groups when we're using reverse HTTP, and "full",
where we always try to get connections from other thread groups.
Unless there is a special need, it is advised to use "none" (or
restricted if we're using reverse HTTP) as using connections from other
thread groups may have a performance impact.

4 months agoMEDIUM: pollers: Drop fd events after a takeover to another tgid.
Olivier Houchard [Tue, 25 Feb 2025 17:28:45 +0000 (18:28 +0100)] 
MEDIUM: pollers: Drop fd events after a takeover to another tgid.

In pollers that support it, provide the generation number in addition to
the fd, and, when an event happened, if the generation number is the
same, but the tgid changed, then assumed the fd was taken over by a
thread from another thread group, and just delete the event from the
current thread's poller, as we no longer want to hear about it.

4 months agoMINOR: pollers: Add a fixup_tgid_takeover() method.
Olivier Houchard [Tue, 25 Feb 2025 17:26:49 +0000 (18:26 +0100)] 
MINOR: pollers: Add a fixup_tgid_takeover() method.

Add a fixup_tgid_takeover() method to pollers for which it makes sense
(epoll, kqueue and evport). That method can be called after a takeover
of a fd from a different thread group, to make sure the poller's
internal structure reflects the new state.

4 months agoMEDIUM: epoll: Make sure we can add a new event
Olivier Houchard [Tue, 25 Feb 2025 11:01:40 +0000 (12:01 +0100)] 
MEDIUM: epoll: Make sure we can add a new event

Check that the call to epoll_ctl() succeeds, and if it does not, if
we're adding a new event and it fails with EEXIST, then delete and
re-add the event. There are a few cases where we may already have events
for a fd. If epoll_ctl() fails for any reason, use BUG_ON to make sure
we immediately crash, as this should not happen.

4 months agoMINOR: fd: Add fd_lock_tgid_cur().
Olivier Houchard [Wed, 29 Jan 2025 16:03:52 +0000 (17:03 +0100)] 
MINOR: fd: Add fd_lock_tgid_cur().

Add fd_lock_tgid_cur(), a function that will lock the tgid, without
modifying its value.

4 months agoMEDIUM: fd: Wait if locked in fd_grab_tgid() and fd_take_tgid().
Olivier Houchard [Wed, 29 Jan 2025 15:51:40 +0000 (16:51 +0100)] 
MEDIUM: fd: Wait if locked in fd_grab_tgid() and fd_take_tgid().

Wait while the tgid is locked in fd_grab_tgid() and fd_take_tgid().
As that lock is barely used, it should have no impact.

4 months agoBUILD: add possibility to use different QuicTLS variants
Ilia Shipitsin [Tue, 25 Feb 2025 06:53:34 +0000 (07:53 +0100)] 
BUILD: add possibility to use different QuicTLS variants

initially QuicTLS started as a patchset on top of OpenSSL,
currently project has started its own journey as QuicTLS

somehow we need both

ML: https://www.mail-archive.com/haproxy@formilux.org/msg45574.html
GH: https://github.com/quictls/quictls/issues/244

4 months agoOPTIM: connection: don't try to kill other threads' connection when !shared
Willy Tarreau [Tue, 25 Feb 2025 07:42:45 +0000 (08:42 +0100)] 
OPTIM: connection: don't try to kill other threads' connection when !shared

Users may have good reasons for using "tune.idle-pool.shared off", one of
them being the cost of moving cache lines between cores, or the kernel-
side locking associated with moving FDs. For this reason, when getting
close to the file descriptors limits, we must not try to kill adjacent
threads' FDs when the sharing of pools is disabled. This is extremely
expensive and kills the performance. We must limit ourselves to our local
FDs only. In such cases, it's up to the users to configure a large enough
maxconn for their usages.

Before this patch, perf top reported 9% CPU usage in connect_server()
onthe trylock used to kill connections when running at 4800 conns for
a global maxconn of 6400 on a 128-thread server. Now it doesn't spend
its time there anymore, and performance has increased by 12%. Note,
it was verified that disabling the locks in such a case has no effect
at all, so better keep them and stay safe.

4 months agoBUG/MEDIUM: stream: don't use localtime in dumps from a signal handler
Willy Tarreau [Mon, 24 Feb 2025 10:43:15 +0000 (11:43 +0100)] 
BUG/MEDIUM: stream: don't use localtime in dumps from a signal handler

In issue #2861, Jarosaw Rzeszótko reported another issue with
"show threads", this time in relation with the conversion of a stream's
accept date to local time. Indeed, if the libc was interrupted in this
same function, it could have been interrupted with a lock held, then
it's no longer possible to dump the date, and we face a deadlock.
This is easy to reproduce with logging enabled.

Let's detect we come from a signal handler and do not try to resolve
the time to localtime in this case.

4 months agoMINOR: tinfo: split the signal handler report flags into 3
Willy Tarreau [Mon, 24 Feb 2025 12:37:52 +0000 (13:37 +0100)] 
MINOR: tinfo: split the signal handler report flags into 3

While signals are not recursive, one signal (e.g. wdt) may interrupt
another one (e.g. debug). The problem this causes is that when leaving
the inner handler, it removes the outer's flag, hence the protection
that comes with it. Let's just have 3 distinct flags for regular signals,
debug signal and watchdog signal. We add a 4th definition which is an
aggregate of the 3 to ease testing.

4 months agoBUG/MINOR: h2: always trim leading and trailing LWS in header values
Willy Tarreau [Mon, 24 Feb 2025 08:17:22 +0000 (09:17 +0100)] 
BUG/MINOR: h2: always trim leading and trailing LWS in header values

Annika Wickert reported some occasional disconnections between haproxy
and varnish when communicating over HTTP/2, with varnish complaining
about protocol errors while captures looked apparently normal. Nils
Goroll managed to reproduce this on varnish by injecting the capture of
the outgoing haproxy traffic and noticed that haproxy was forwarding a
header value containing a trailing space, which is now explicitly
forbidden since RFC9113.

It turns out that the only way for such a header to pass through haproxy
is to arrive in h2 and not be edited, in which case it will arrive in
HTX with its undesired spaces. Since the code dealing with HTX headers
always trims spaces around them, these are not observable in dumps, but
only when started in debug mode (-d). Conversions to/from h1 also drop
the spaces.

With this patch we trim LWS both on input and on output. This way we
always present clean headers in the whole stack, and even if some are
manually crafted by the configuration or Lua, they will be trimmed on
the output.

This must be backported to all stable versions.

Thanks to Annika for the helpful capture and Nils for the help with
the analysis on the varnish side!

4 months agoMINOR: compression: Introduce minimum size
Vincent Dechenaux [Fri, 21 Feb 2025 21:37:57 +0000 (22:37 +0100)] 
MINOR: compression: Introduce minimum size

This is the introduction of "minsize-req" and "minsize-res".
These two options allow you to set the minimum payload size required for
compression to be applied.
This helps save CPU on both server and client sides when the payload does
not need to be compressed.

4 months agoCLEANUP: task: move the barrier after clearing th_ctx->current
Willy Tarreau [Fri, 21 Feb 2025 10:22:57 +0000 (11:22 +0100)] 
CLEANUP: task: move the barrier after clearing th_ctx->current

There's a barrier after releasing the current task in the scheduler.
However it's improperly placed, it's done after pool_free() while in
fact it must be done immediately after resetting the current pointer.
Indeed, the purpose is to make sure that nobody sees the task as valid
when it's in the process of being released. This is something that
could theoretically happen if interrupted by a signal in the inlined
code of pool_free() if the compiler decided to postpone the write to
->current. In practice since nothing fancy is done in the inlined part
of the function, there's currently no risk of reordering. But it could
happen if the underlying __pool_free() were to be inlined for example,
and in this case we could possibly observe th_ctx->current pointing
to something currently being destroyed.

With the barrier between the two, there's no risk anymore.

4 months agoMINOR: tools: use only opportunistic symbols resolution
Willy Tarreau [Fri, 21 Feb 2025 14:01:13 +0000 (15:01 +0100)] 
MINOR: tools: use only opportunistic symbols resolution

As seen in issue #2861, dladdr_and_size() an be quite expensive and
will often hold a mutex in the underlying library. It becomes a real
problem when issuing lots of "show threads" or wdt warnings in parallel
because threads will queue up waiting for each other to finish, adding
to their existing latency that possibly caused the warning in the first
place.

Here we're taking a different approach. If the thread is not isolated
and not panicking, it's doing unimportant stuff like showing threads
or warnings. In this case we try to grab a lock, and if we fail because
another thread is already there, we just pretend we cannot resolve the
symbol. This is not critical because then we fall back to the already
used case which consists in writing "main+<offset>". In practice this
will almost never happen except in bad situations which could have
otherwise degenerated.

4 months agoBUG/MEDIUM: stream: use non-blocking freq_ctr calls from the stream dumper
Willy Tarreau [Fri, 21 Feb 2025 17:23:23 +0000 (18:23 +0100)] 
BUG/MEDIUM: stream: use non-blocking freq_ctr calls from the stream dumper

The stream dump function is called from signal handlers (warning, show
threads, panic). It makes use of read_freq_ctr() which might possibly
block if it tries to access a locked freq_ctr in the process of being
updated, e.g. by the current thread.

Here we're relying on the non-blocking API instead. It may return incorrect
values (typically smaller ones after resetting the curr counter) but at
least it will not block.

This needs to be backported to stable versions along with the previous
commit below:

   MINOR: freq_ctr: provide non-blocking read functions

At least 3.1 is concerned as the warnings tend to increase the risk of
this situation appearing.

4 months agoMINOR: freq_ctr: provide non-blocking read functions
Willy Tarreau [Fri, 21 Feb 2025 17:21:56 +0000 (18:21 +0100)] 
MINOR: freq_ctr: provide non-blocking read functions

Some code called by the debug handlers in the context of a signal handler
accesses to some freq_ctr and occasionally ends up on a locked one from
the same thread that is dumping it. Let's introduce a non-blocking version
that at least allows to return even if the value is in the process of being
updated, it's less problematic than hanging.

4 months agoBUG/MEDIUM: stream: never allocate connection addresses from signal handler
Willy Tarreau [Fri, 21 Feb 2025 15:45:18 +0000 (16:45 +0100)] 
BUG/MEDIUM: stream: never allocate connection addresses from signal handler

In __strm_dump_to_buffer(), we call conn_get_src()/conn_get_dst() to try
to retrieve the connection's IP addresses. But this function may be called
from a signal handler to dump a currently running stream, and if the
addresses were not allocated yet, a poll_alloc() will be performed while
we might possibly already be running pools code, resulting in pool list
corruption.

Let's just make sure we don't call these sensitive functions there when
called from a signal handler.

This must be backported at least to 3.1 and ideally all other versions,
along with this previous commit:

  MINOR: tinfo: add a new thread flag to indicate a call from a sig handler

4 months agoMINOR: tinfo: add a new thread flag to indicate a call from a sig handler
Willy Tarreau [Fri, 21 Feb 2025 15:26:24 +0000 (16:26 +0100)] 
MINOR: tinfo: add a new thread flag to indicate a call from a sig handler

Signal handlers must absolutely not change anything, but some long and
complex call chains may look innocuous at first glance, yet result in
some subtle write accesses (e.g. pools) that can conflict with a running
thread being interrupted.

Let's add a new thread flag TH_FL_IN_SIG_HANDLER that is only set when
entering a signal handler and cleared when leaving them. Note, we're
speaking about real signal handlers (synchronous ones), not deferred
ones. This will allow some sensitive call places to act differently
when detecting such a condition, and possibly even to place a few new
BUG_ON().

4 months agoBUG/MINOR: mux-h1: always make sure h1s->sd exists in h1_dump_h1s_info()
Willy Tarreau [Fri, 21 Feb 2025 10:31:36 +0000 (11:31 +0100)] 
BUG/MINOR: mux-h1: always make sure h1s->sd exists in h1_dump_h1s_info()

This function may be called from a signal handler during a warning,
a panic or a show thread. We need to be more cautious about what may
or may not be dereferenced since an h1s is not necessarily fully
initialized. Loops of "show threads" sometimes manage to crash when
dereferencing a null h1s->sd, so let's guard it and add a comment
remining about the unusual call place.

This can be backported to the relevant versions.

4 months agoBUG/MINOR: stream: do not call co_data() from __strm_dump_to_buffer()
Willy Tarreau [Fri, 21 Feb 2025 16:18:00 +0000 (17:18 +0100)] 
BUG/MINOR: stream: do not call co_data() from __strm_dump_to_buffer()

co_data() was instrumented to detect cases where c->output > data and
emits a warning if that's not correct. The problem is that it happens
quite a bit during "show threads" if it interrupts traffic anywhere,
and that in some environments building with -DDEBUG_STRICT_ACTION=3,
it will kill the process.

Let's just open-code the channel functions that make access to co_data(),
there are not that many and the operations remain very simple.

This can be backported to 3.1. It didn't trigger in earlier versions
because they didn't have this CHECK_IF_HOT() test.

4 months agoCI: QUIC Interop: clean old docker images
Ilia Shipitsin [Fri, 14 Feb 2025 20:51:04 +0000 (21:51 +0100)] 
CI: QUIC Interop: clean old docker images

currently temporary docker images are kept forever. let's delete
outdated ones

4 months agoMINOR: clock: always use atomic ops for global_now_ms
Aurelien DARRAGON [Wed, 19 Feb 2025 10:42:04 +0000 (11:42 +0100)] 
MINOR: clock: always use atomic ops for global_now_ms

global_now_ms is shared between threads so we must give hint to the
compiler that read/writes operations should be performed atomically.

Everywhere global_now_ms was used, atomic ops were used, except in
clock_update_global_date() where a read was performed without using
atomic op. In practise it is not an issue because on most systems
such reads should be atomic already, but to prevent any confusion or
potential bug on exotic systems, let's use an explicit _HA_ATOMIC_LOAD
there.

This may be backported up to 2.8

4 months agoBUG/MINOR: sink: add tempo between 2 connection attempts for sft servers
Aurelien DARRAGON [Fri, 21 Feb 2025 09:51:01 +0000 (10:51 +0100)] 
BUG/MINOR: sink: add tempo between 2 connection attempts for sft servers

When the connection for sink_forward_{oc}_applet fails or a previous one
is destroyed, the sft->appctx is instantly released.

However process_sink_forward_task(), which may run at any time, iterates
over all known sfts and tries to create sessions for orphan ones.

It means that instantly after sft->appctx is destroyed, a new one will
be created, thus a new connection attempt will be made.

It can be an issue with tcp log-servers or sink servers, because if the
server is unavailable, process_sink_forward() will keep looping without
any temporisation until the applet survives (ie: connection succeeds),
which results in unexpected CPU usage on the threads responsible for
that task.

Instead, we add a tempo logic so that a delay of 1second is applied
between two retries. Of course the initial attempt is not delayed.

This could be backported to all stable versions.

4 months agoBUG/MINOR: log: fix outgoing abns address family
Aurelien DARRAGON [Fri, 21 Feb 2025 10:03:39 +0000 (11:03 +0100)] 
BUG/MINOR: log: fix outgoing abns address family

While reviewing the code in an attempt to fix GH #2875, I stumbled
on another case similar to aac570c ("BUG/MEDIUM: uxst: fix outgoing
abns address family in connect()") that caused abns(z) addresses to
fail when used as log targets.

The underlying cause is the same as aac570c, which is the rework of the
unix socket families in order to support custom addresses for different
adressing schemes, where a real_family() was overlooked before passing
a haproxy-internal address struct to socket-oriented syscall.

To fix the issue, we first copy the target's addr, and then leverage
real_family() to set the proper low-level address family that is passed
to sendmsg() syscall.

It should be backported in 3.1

4 months agoREGTESTS: fix reg-tests/server/abnsz.vtc
Aurelien DARRAGON [Fri, 21 Feb 2025 07:16:50 +0000 (08:16 +0100)] 
REGTESTS: fix reg-tests/server/abnsz.vtc

It was proved in GH #2875 that the regtest was broken, at least for the
server-side abnsz, as the connect() was not performed using the proper
family, which results in kernel refusing to perform the call, while the
reg-test actually succeeds.

Indeed, in the test we used vtest client to connect to haproxy, which
then routed the request to another haproxy instance listening on an
abnsz socket, and this last haproxy was the one to answer the http
request.

As we only used "rxresp" in vtest client, the test succeeded with empty
responses, which was the case due to the server connection failing on the
first haproxy process.

4 months agoBUG/MEDIUM: uxst: fix outgoing abns address family in connect()
Willy Tarreau [Fri, 21 Feb 2025 06:53:21 +0000 (07:53 +0100)] 
BUG/MEDIUM: uxst: fix outgoing abns address family in connect()

Since we reworked the unix socket families in order to support custom
addresses for different addressing schemes, we've been using extra
values for the ss_family field in sockaddr_storage. These ones have
to be adjusted before calling bind() or connect(). It turns out that
after the abns/abnsz updates in 3.1, the connect() code was not adjusted
to take care of the change, resulting in AF_CUST_ABNS or AF_CUST_ABNSZ
to be placed in the address that was passed to connect().

The right approach is to locally copy the address, get its length,
fixup the family and use the fixed value and length for connect().

This must be backported to 3.1. Many thanks for @Mewp for reporting
this issue in github issue #2875.

4 months agoBUG/MINOR: cfgparse: fix NULL ptr dereference in cfg_parse_peers
Valentine Krasnobaeva [Thu, 20 Feb 2025 14:00:38 +0000 (15:00 +0100)] 
BUG/MINOR: cfgparse: fix NULL ptr dereference in cfg_parse_peers

When "peers" keyword is followed by more than one argument and it's the first
"peers" section in the config, cfg_parse_peers() detects it and exits with
"ERR_ALERT|ERR_FATAL" err_code.

So, upper layer parser, parse_cfg(), continues and parses the next keyword
"peer" and then he tries to check the global cfg_peers, which should contain
"my_cluster". The global cfg_peers is still NULL, because after alerting a user
in alertif_too_many_args, cfg_parse_peers() exited.

peers my_cluster __some_wrong_data__
peer haproxy1 1.1.1.1 1000

In order to fix this, let's add ERR_ABORT, if "peers" keyword is followed by
more than one argument. Like this parse_cfg() will stops immediately and
terminates haproxy with "too many args for peers my_cluster..." alert message.

It's more reliable, than add checks "if (cfg_peers !=NULL)" in "peer"
subparser, as we may have many "peers" sections.

peers my_another_cluster
peer haproxy1 1.1.1.2 1000

peers my_cluster  __some_wrong_data__
peer haproxy1 1.1.1.1 1000

In addition, for the example above, parse_cfg() will parse all configuration
until the end and only then terminates haproxy with the alert
"too many args...". Peer haproxy1 will be wrongly associated with
my_another_cluster.

This fixes the issue #2872.
This should be backported in all stable versions.