]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
14 months agoMEDIUM: evports: permit to report multiple events at once
Willy Tarreau [Wed, 17 Apr 2024 14:37:04 +0000 (16:37 +0200)] 
MEDIUM: evports: permit to report multiple events at once

Since the beginning in 2.0 the nevlist parameter was set to 1 before
calling port_getn(), which means that a single FD event will be reported
per polling loop. This is extremely inefficient, and all the code was
designed to use global.tune.maxpollevents. It looks like it's a leftover
of a temporary debugging change. No apparent issues were found by setting
it to a higher value, so better do that.

That code is not much used nowadays with Solaris disappearing from the
landscape, so even if this definitely was a bug, it's preferable not to
backport that fix as it could uncover other subtle bugs that were never
raised yet.

14 months agoBUG/MEDIUM: evports: do not clear returned events list on signal
Willy Tarreau [Wed, 17 Apr 2024 14:25:20 +0000 (16:25 +0200)] 
BUG/MEDIUM: evports: do not clear returned events list on signal

Since 2.0 with commit 0ba4f483d2 ("MAJOR: polling: add event ports
support (Solaris)"), the polling system on Solaris suffers from a
signal handling problem. It turns out that this API is very bizarre,
as reported events are automatically unregistered and their counter
is updated in the same variable that was used to pass the count on
input, making it difficult to handle certain error codes (how should
one handle ENOSYS for example?). And to complete everything, the API
is able to return both EINTR and an event if a signal is reported.

The code tries to deal with certain such cases (e.g. ETIME for timeout
can also report an event), otherwise it defaults to clearing the
event counter upon error. This has the effect that EINTR clears the
list of events, which are also automatically cleared from the set by
the system.

This is visible when using external checks where the SIGCHLD of the
leaving child causes a wakeup that ruins the event counter and causes
endless loops, apparently due to the queued inter-thread byte in the
pipe used to wake threads up that never gets removed in this case.
Note that extcheck would also deserve deeper investigation because it
can immediately re-trigger a check in such a case, which is not normal.

Removing the wiping of the nevlist variable fixes the problem.

This can be backported to all versions since it affects 2.0.

14 months agoCLEANUP: assorted typo fixes in the code and comments
Ilya Shipitsin [Sun, 14 Apr 2024 07:23:52 +0000 (09:23 +0200)] 
CLEANUP: assorted typo fixes in the code and comments

This is 41st iteration of typo fixes

14 months agoCI: reduce ASAN log redirection umbrella size
Ilya Shipitsin [Sun, 14 Apr 2024 07:23:51 +0000 (09:23 +0200)] 
CI: reduce ASAN log redirection umbrella size

previously ASAN_OPTIONS=log_path=asan.log was intended for VTest
execution only, it should not affect "haproxy -vv" and hsproxy
config smoke testing

14 months agoBUILD: xxhash: silence a build warning on Solaris + gcc-5.5
Willy Tarreau [Wed, 17 Apr 2024 07:41:30 +0000 (09:41 +0200)] 
BUILD: xxhash: silence a build warning on Solaris + gcc-5.5

Testing an undefined macro emits warnings due to -Wundef, and we have
exactly one such case in xxhash:

  include/import/xxhash.h:3390:42: warning: "__cplusplus" is not defined [-Wundef]
   #if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */

Let's just prepend "defined(__cplusplus) &&" before __cplusplus to
resolve the problem. Upstream is still affected apparently.

14 months agoBUILD: cache: fix a build warning with gcc < 7
Willy Tarreau [Wed, 17 Apr 2024 07:36:33 +0000 (09:36 +0200)] 
BUILD: cache: fix a build warning with gcc < 7

Gcc before 7 does really not like direct operations on cast pointers
such as "((struct a*)b)->c += d;". It turns our that we have exactly
that construct in 3.0 since commit 5baa9ea168 ("MEDIUM: cache: Save
body size of cached objects and track it on delivery").

It's generally sufficient to use an intermediary variable such as :
"({ (struct a*) _ = b; _; })->c +=d;" but that's ugly. Fortunately
DISGUISE() implicitly does something very similar and works fine, so
let's use that.

No backport is needed.

14 months agoBUG/MEDIUM: stconn: Don't forward channel data if input data must be filtered
Christopher Faulet [Mon, 15 Apr 2024 17:09:01 +0000 (19:09 +0200)] 
BUG/MEDIUM: stconn: Don't forward channel data if input data must be filtered

Once data are received and placed in a channel buffer, if it is possible,
outgoing data are immediately forwarded. But we must take care to not do so
if there is also pending input data and a filter registered on the
channel. It is especially important for HTX streams because the HTX may be
altered, especially the extra field. And it is indeed an issue with the HTTP
compression filter and the H1 multiplexer. The wrong chunk size may be
announced leading to an internal error.

This patch should fix the issue #2530. It must be backported to all stable
versions.

14 months agoMINOR: peer: Restore previous peer flags value to ease debugging
Christopher Faulet [Tue, 16 Apr 2024 09:05:53 +0000 (11:05 +0200)] 
MINOR: peer: Restore previous peer flags value to ease debugging

The last fixes on the peers to improve the locking mechanism introduced new
peer flags and the value of some old flags was changed. This was done in the
commit 9b78e33837 ("MINOR: peers: Add 2 peer flags about the peer learn
status"). But, to ease the debugging of the peers team, old values are
restored.

This patch must be backported with the commit above.

14 months agoMEDIUM: peers: Only lock one peer at a time in the sync process function
Christopher Faulet [Fri, 22 Mar 2024 16:39:46 +0000 (17:39 +0100)] 
MEDIUM: peers: Only lock one peer at a time in the sync process function

Thanks to all previous changes, it is now possible to stop locking all peers
at once in the resync process function. Peer are locked one after the
other. Wen a peer is locked, another one may be locked when all peer sharing
the same shard must be updated. Otherwise, at anytime, at most one peer is
locked. This should significantly improve the situation.

This patch depends on the following patchs:

 * BUG/MAJOR: peers: Update peers section state from a thread-safe manner
 * BUG/MINOR: peers: Report a resync was explicitly requested from a thread-safe manner
 * MINOR: peers: Add functions to commit peer changes from the resync task
 * MINOR: peers: sligthly adapt part processing the stopping signal
 * MINOR: peers: Add flags to report the peer state to the resync task
 * MINOR: peers: Add 2 peer flags about the peer learn status
 * MINOR: peers: Split resync process function to separate running/stopping states

It may be good to backport it to 2.9. All the seris should fix the issue #2470.

14 months agoBUG/MAJOR: peers: Update peers section state from a thread-safe manner
Christopher Faulet [Fri, 22 Mar 2024 16:39:04 +0000 (17:39 +0100)] 
BUG/MAJOR: peers: Update peers section state from a thread-safe manner

It is the main part of this series. In the peer applet, only the peer flags
are updated. It is now the responsibility of the resync process function to
check changes on each peer to update the peers section state accordingly.

Concretly, changes on the connection state (accepted, connected, released or
renewed) are first reported at the peer level and then handled in
__process_peer_state() function.

In the same manner, when the learn status of a peer changes, the peers
section state is no longer updated immediately. The resync task is woken up
to deal with this changes.

Thanks to these changes, the peers should be now really thread-safe.

This patch relies on the following ones:

  * BUG/MINOR: peers: Report a resync was explicitly requested from a thread-safe manner
  * MINOR: peers: Add functions to commit peer changes from the resync task
  * MINOR: peers: sligthly adapt part processing the stopping signal
  * MINOR: peers: Add flags to report the peer state to the resync task
  * MINOR: peers: Add 2 peer flags about the peer learn status
  * MINOR: peers: Split resync process function to separate running/stopping states

No bug was reported about the thread-safety of peers. Only a performance
issue was encountered with a huge number of peers (> 50). So there is no
reason to backport all these patches further than 2.9.

14 months agoBUG/MINOR: peers: Report a resync was explicitly requested from a thread-safe manner
Christopher Faulet [Fri, 22 Mar 2024 15:27:13 +0000 (16:27 +0100)] 
BUG/MINOR: peers: Report a resync was explicitly requested from a thread-safe manner

Flags on the peers section state must be updated from a thread-safe manner.
It is not true today. With this patch we take care PEERS_F_RESYNC_REQUESTED
flag is only set by the resync task. To do so, a peer flag is used. This
flag is only set once and never removed. It is juste used for debugging
purpose. So it is enough to set it on a peer and be sure to report it on the
peers section when the sync task is executed.

This patch relies on previous ones:

 * MINOR: peers: Add functions to commit peer changes from the resync task
 * MINOR: peers: sligthly adapt part processing the stopping signal
 * MINOR: peers: Add flags to report the peer state to the resync task
 * MINOR: peers: Add 2 peer flags about the peer learn status
 * MINOR: peers: Split resync process function to separate running/stopping states

14 months agoMINOR: peers: Add functions to commit peer changes from the resync task
Christopher Faulet [Fri, 22 Mar 2024 15:23:40 +0000 (16:23 +0100)] 
MINOR: peers: Add functions to commit peer changes from the resync task

For now, nothing is done in these functions. It is only a patch to prepare
the huge part of the refactoring about the locking mechanism of the peers.
These functions will be responsible to check peers state and their learn
status to update the peers section flags accordingly.

14 months agoMINOR: peers: sligthly adapt part processing the stopping signal
Christopher Faulet [Fri, 22 Mar 2024 13:51:24 +0000 (14:51 +0100)] 
MINOR: peers: sligthly adapt part processing the stopping signal

The signal and the PEERS_F_DONOTSTOP flag are now handled in the loop on peers
to force sessions shutdown. We will need to loop on all peers to update their
state. It is easier this way.

14 months agoMINOR: peers: Add flags to report the peer state to the resync task
Christopher Faulet [Fri, 22 Mar 2024 13:34:21 +0000 (14:34 +0100)] 
MINOR: peers: Add flags to report the peer state to the resync task

As the previous patch, this patch is also part of the refactoring of peer
locking mechanisme. Here we add flags to represent a transitional state for
a peer. It will be the resync task responsibility to update the peers state
accordingly.

A peer may be in 4 transitional states:

  * accepted : a connection was accepted from a peer
  * connected: a connection to a peer was established
  * release  : a peer session was released
  * renewed  : a peer session was released because it was replaced by a new
               one. Concretly, this will be equivalent to released+accepted

If none of these flags is set, it means the transition, if any, was
processed by the resync task, or no transition happened.

14 months agoMINOR: peers: Add 2 peer flags about the peer learn status
Christopher Faulet [Fri, 22 Mar 2024 13:26:49 +0000 (14:26 +0100)] 
MINOR: peers: Add 2 peer flags about the peer learn status

PEER_F_LEARN_PROCESS and PEER_F_LEARN_FINISHED flags are added to help to
fix locking issue about peers. Indeed, a peer is able to update the peers
"section" state under its own lock. Because the resync task locks all peers
at once, there is no conflict at this level. But there is nothing to prevent
2 peers to update the peers state in same time. So it seems there is no real
issue here, but there is a theorical thread-safety issue here. And it means
the locking mechanism of the peers must be reviewed.

In this context, the 2 flags above will help to move all update of the peers
state in the scope of resync task. Each peer will be able to update its own
state and the resync task will be responsible to update the peers state
accordingly.

14 months agoMINOR: peers: Split resync process function to separate running/stopping states
Christopher Faulet [Fri, 22 Mar 2024 13:20:32 +0000 (14:20 +0100)] 
MINOR: peers: Split resync process function to separate running/stopping states

The function responsible to deal with resynchro between all peers is now split
in two subfunctions. The first one is used when HAProxy is running while the
other one is used in soft-stop case.

This patch is required to be able to refactor locking mechanism of the peers.

14 months agoBUG/MEDIUM: grpc: Fix several unaligned 32/64 bits accesses
Frederic Lecaille [Mon, 15 Apr 2024 07:57:37 +0000 (09:57 +0200)] 
BUG/MEDIUM: grpc: Fix several unaligned 32/64 bits accesses

There were several places in grpc and its dependency protobuf where unaligned
accesses were done. Read accesses to 32 (resp. 64) bits values should be performed
by read_u32() (resp. read_u64()).
Replace these unligned read accesses by correct calls to these functions.
Same fixes for doubles and floats.

Such unaligned read accesses could lead to crashes with bus errors on CPU
archictectures which do not fix them at run time.

This patch depends on this previous commit:
    861199fa71 MINOR: net_helper: Add support for floats/doubles.

Must be backported as far as 2.6.

14 months agoMINOR: net_helper: Add support for floats/doubles.
Frederic Lecaille [Mon, 15 Apr 2024 07:52:25 +0000 (09:52 +0200)] 
MINOR: net_helper: Add support for floats/doubles.

Implement (read|write)_flt() (resp. (read|write)_dbl()) to read/write floats
(resp. read/write doubles) from/to an unaligned buffer.

14 months agoMINOR: ssl: 'key-base' allows to load a 'key' from a specific path
William Lallemand [Mon, 15 Apr 2024 12:33:24 +0000 (14:33 +0200)] 
MINOR: ssl: 'key-base' allows to load a 'key' from a specific path

The global 'key-base' keyword allows to read the 'key' parameter of a
crt-store load line using a path prefix.

This is the equivalent of the 'crt-base' keyword but for 'key'.

It only applies on crt-store.

14 months agoMINOR: ssl: supports crt-base in crt-store
William Lallemand [Mon, 15 Apr 2024 12:01:11 +0000 (14:01 +0200)] 
MINOR: ssl: supports crt-base in crt-store

Add crt-base support for "crt-store". It will be used by 'crt', 'ocsp',
'issuer', 'sctl' load line parameter.

In order to keep compatibility with previous configurations and scripts
for the CLI, a crt-store load line will save its ckch_store using the
absolute crt path with the crt-base as the ckch tree key. This way, a
`show ssl cert` on the CLI will always have the completed path.

14 months agoCLEANUP: ssl: remove dead code in cfg_parse_crtstore()
William Lallemand [Mon, 15 Apr 2024 07:04:37 +0000 (09:04 +0200)] 
CLEANUP: ssl: remove dead code in cfg_parse_crtstore()

Remove dead code reported in #2531.

14 months agoMINOR: ring: always check that the old ring fits in the new one in ring_dup()
Willy Tarreau [Mon, 15 Apr 2024 06:31:01 +0000 (08:31 +0200)] 
MINOR: ring: always check that the old ring fits in the new one in ring_dup()

Let's add a BUG_ON() to make sure we don't accidentally shrink a buffer.

14 months agoBUG/MAJOR: ring: use the correct size to reallocate startup_logs
Willy Tarreau [Mon, 15 Apr 2024 06:26:41 +0000 (08:26 +0200)] 
BUG/MAJOR: ring: use the correct size to reallocate startup_logs

In 3.0-dev, with commit 7c9ce715c9 ("MINOR: ring: make callers use
ring_data() and ring_size(), not ring->buf"), we made startup_logs_dup()
use ring_size() to get the old ring size and pass it to ring_new() to
create a new ring. But due to the ambiguity of the allocate vs usable
size, this resulted in slightly shrinking the buffer compared to the
previous one, occasionally causing crashes if the first one was already
full of warnings, as seen in GH issue #2529. We need to use the allocated
size instead, thanks to the function brought by previous commit.

No backport is needed, this only affects 3.0-dev. Thanks to @felipewd
for the detailed report that allowed to spot the problem.

14 months agoMINOR: ring: clarify the usage of ring_size() and add ring_allocated_size()
Willy Tarreau [Mon, 15 Apr 2024 06:25:03 +0000 (08:25 +0200)] 
MINOR: ring: clarify the usage of ring_size() and add ring_allocated_size()

There's currently an abiguity around ring_size(), it's said to return
the allocated size but returns the usable size. We can't change it as
it's used everywhere in the code like this. Let's fix the comment and
add ring_allocated_size() instead for anything related to allocation.

14 months agoCI: revert kernel addr randomization introduced in 3a0fc864
Ilya Shipitsin [Sat, 6 Apr 2024 13:37:34 +0000 (15:37 +0200)] 
CI: revert kernel addr randomization introduced in 3a0fc864

It has been resolved on image generation side:
https://github.com/actions/runner-images/issues/9491

It is no harm to keep it on our side as well, but we can drop it.

14 months agoDOC: management: fix typos
Andrey Lebedev [Fri, 12 Apr 2024 09:47:07 +0000 (11:47 +0200)] 
DOC: management: fix typos

[WT: some of them seem to be relevant to older versions, so it might
 be worth backporting the relevant parts.]

14 months agoBUG/MINOR: lru: fix the standalone test case for invalid revision
Willy Tarreau [Sun, 7 Apr 2024 16:27:06 +0000 (18:27 +0200)] 
BUG/MINOR: lru: fix the standalone test case for invalid revision

In 2.6, a build issue for LRU in standalone test mode was addressed by
commit bf9c07fd9 ("BUILD/DEBUG: lru: update the standalone code to
support the revision"), but using revision 1 while looking up rev 0
results in 100% misses. Let's fix this and commit with revision 0 as
well.

No backport is needed, this only happens when hacking on the code.

14 months agoMINOR: proto_quic: add proto name in alert
Valentine Krasnobaeva [Wed, 10 Apr 2024 13:18:25 +0000 (15:18 +0200)] 
MINOR: proto_quic: add proto name in alert

In quic_alloc_dghdlrs() add proto name in the last alert. This helps to
identify potential problem immediately and makes log messages more uniform.

14 months agoMINOR: listener/protocol: add proto name in alerts
Valentine Krasnobaeva [Wed, 10 Apr 2024 12:18:47 +0000 (14:18 +0200)] 
MINOR: listener/protocol: add proto name in alerts

Frontend and listen sections allow unlimited number of bind statements, it is
often, when there is a bind statement per supported protocol, like below:

listen test
  mode http
  bind quic4@0.0.0.0:443 name quic ssl crt ...
  bind 0.0.0.0:443 name https ssl alpn http/1.1,h2 crt ...
  bind 0.0.0.0:8080 ...
  ...

It seems useful to show corresponded protocol name in alerts and warnings,
when problem occures with port binding, connection resuming or sharding. This
helps to figure out immediately, which bind statement has a wrong setting or
which protocol module is the root cause of the issue.

14 months agoDEBUG: pools: report the data around the offending area in case of mismatch
Willy Tarreau [Fri, 12 Apr 2024 15:54:51 +0000 (17:54 +0200)] 
DEBUG: pools: report the data around the offending area in case of mismatch

When the integrity check fails, it's useful to get a dump of the area
around the first faulty byte. That's what this patch does. For example
it now shows this before reporting info about the tag itself:

  Contents around first corrupted address relative to pool item:.
  Contents around address 0xe4febc0792c0+40=0xe4febc0792e8:
    0xe4febc0792c8 [80 75 56 d8 fe e4 00 00] [.uV.....]
    0xe4febc0792d0 [a0 f7 23 a4 fe e4 00 00] [..#.....]
    0xe4febc0792d8 [90 75 56 d8 fe e4 00 00] [.uV.....]
    0xe4febc0792e0 [d9 93 fb ff fd ff ff ff] [........]
    0xe4febc0792e8 [d9 93 fb ff ff ff ff ff] [........]
    0xe4febc0792f0 [d9 93 fb ff ff ff ff ff] [........]
    0xe4febc0792f8 [d9 93 fb ff ff ff ff ff] [........]
    0xe4febc079300 [d9 93 fb ff ff ff ff ff] [........]

This may be backported to 2.9 and maybe even 2.8 as it does help spot
the cause of the memory corruption.

14 months agoREORG: pool: move the area dump with symbol resolution to tools.c
Willy Tarreau [Fri, 12 Apr 2024 14:18:34 +0000 (16:18 +0200)] 
REORG: pool: move the area dump with symbol resolution to tools.c

This function is particularly useful to dump unknown areas watching
for opportunistic symbols, so let's move it to tools.c so that we can
reuse it a little bit more.

14 months agoDEBUG: pool: improve decoding of corrupted pools
Willy Tarreau [Fri, 12 Apr 2024 13:56:18 +0000 (15:56 +0200)] 
DEBUG: pool: improve decoding of corrupted pools

When a corruption was detected in an object, it's often said that the
tag doesn't match the pool, but it should also check if it matches the
location of an earlier pool_free() call, which happens when -dMcaller
is used. That's what we're doing now.

14 months agoBUG/MAJOR: stick-tables: fix race with peers in entry expiration
Willy Tarreau [Fri, 12 Apr 2024 15:31:00 +0000 (17:31 +0200)] 
BUG/MAJOR: stick-tables: fix race with peers in entry expiration

In 2.9 with commit 7968fe3889 ("MEDIUM: stick-table: change the ref_cnt
atomically") we significantly relaxed the stick-tables locking when
dealing with peers by adjusting the ref_cnt atomically and moving it
out of the lock.

However it opened a tiny window that became problematic in 3.0-dev7
when the table's contention was lowered by commit 1a088da7c2 ("MAJOR:
stktable: split the keys across multiple shards to reduce contention").

What happens is that some peers may access the entry for reading at
the moment it's about to expire, and while the read accesses to push
the data remain unnoticed (possibly that from time to time we push
crap), but the releasing of the refcount causes a new write that may
damage anything else. The scenario is the following:

  process_table_expire()               peer_send_teachmsgs()

                                       RDLOCK(&updt_lock);
     tick_is_expired() != 0

     ebmb_delete(ts->key);

     if (ts->upd.node.leaf_p) {
                                       HA_ATOMIC_INC(&ts->ref_cnt);
                                       RDUNLOCK(&updt_lock);
          WRLOCK(&updt_lock);
          eb32_delete(&ts->upd);
     }
     __stksess_free(t, ts);
                                       peer_send_updatemsg(ts);
                                       RDLOCK(&updt_lock);
                                       HA_ATOMIC_DEC(&ts->ref_cnt);

Here it's clear that the bottom part of peer_send_teachmsgs() believes
to be protected but may act on freed data.

This is more visible when enabling -dMtag,no-merge,integrity because
the ATOMIC_DEC(&ref_cnt) decrements one byte in the area, that makes
the eviction check fail while the tag has the address of the left
__stksess_free(), proving a completed pool_free() before the decrement,
and the anomaly there is pretty visible in the crash dump. Changing
INC()/DEC() with ADD(2)/DEC(2) shows that the byte is now off by two,
confirming that the operation happened there.

The solution is not very hard, it consists in checking for the ref_cnt
on the left after grabbing the lock, and doing both before deleting the
element, so that we have the guarantee that either the peer will not
take it or that it has already started taking it.

This was proven to be sufficient, as instead of crashing after 3s of
injection with 4 peers, 16 threads and 130k RPS, it survived for 15mn.

In order to stress the setup, a config involving 4+ peers, tracking
HTTP request with randoms and applying a bwlim-out filter with a
random key, with a client made of 160 h2 conns downloading 10 streams
of 4MB objects in parallel managed to trigger it within a few seconds:

  frontend ft
    http-request track-sc0 rand(100000) table tbl
    filter bwlim-out lim-out limit 2047m key rand(100000000),ipmask(32) min-size 1 table tbl
    http-request set-bandwidth-limit lim-out
    use_backend bk

  backend bk
    server s1 198.18.0.30:8000
    server s2 198.18.0.34:8000

  backend tbl
        stick-table type ip size 1000k expire 1s store http_req_cnt,bytes_in_rate(1s),bytes_out_rate(1s) peers peers

This seems to be very dependent on the timing and setup though.

This will need to be backported to 2.9. This part of the code was
reindented with shards but the block should remain mostly unchanged.
The logic to apply is the same.

14 months agoBUG/MEDIUM: peers/trace: fix crash when listing event types
Willy Tarreau [Fri, 12 Apr 2024 10:01:31 +0000 (12:01 +0200)] 
BUG/MEDIUM: peers/trace: fix crash when listing event types

Sending "trace peers event" on the CLI crashes because the event list
in the peers is not finished. This was introduced in 2.4 by commit
d865935f32 ("MINOR: peers: Add traces to peer_treat_updatemsg().")
so this must be backported to 2.4.

14 months agoCLEANUP: stick-tables: always respect the to_batch limit when trashing
Willy Tarreau [Fri, 12 Apr 2024 08:02:26 +0000 (10:02 +0200)] 
CLEANUP: stick-tables: always respect the to_batch limit when trashing

When adding the shards support to tables with commit 1a088da7c ("MAJOR:
stktable: split the keys across multiple shards to reduce contention"),
the condition to stop eliminating entries based on the batch size being
reached is based on a pre-decrement of the max_search counter, but now
it goes back into the outer loop which doesn't check it, so next time
it does it when entering the next shard, it will become even more
negative and will properly stop, but at first glance it looks like an
int overflow (which it is not). Let's make sure the outer loop stops
on this condition so that we don't continue searching when the limit
is reached.

14 months agoBUG/MEDIUM: stick-tables: fix the task's next expiration date
Willy Tarreau [Fri, 12 Apr 2024 07:57:32 +0000 (09:57 +0200)] 
BUG/MEDIUM: stick-tables: fix the task's next expiration date

While changing the stick-table indexing that led to commit 1a088da7c
("MAJOR: stktable: split the keys across multiple shards to reduce
contention"), I met a problem with the task's expiration date being
incorrectly updated, I fixed it and apparently I committed the wrong
version :-/

The effect is that the task's date is only correctly reset if the
table is empty, otherwise the task wakes up again and is queued at
the previous date, eating 100% CPU. The tick_isfirst() must not be
used when storing the last result.

No backport is needed as this was only merged in 3.0-dev7.

14 months agoMINOR: ssl/crtlist: alloc ssl_conf only when a valid keyword is found
William Lallemand [Wed, 10 Apr 2024 17:05:15 +0000 (19:05 +0200)] 
MINOR: ssl/crtlist: alloc ssl_conf only when a valid keyword is found

crt-list will be enhanced with ckch_conf keywords, however these keywords
does not fill the 'ssl_conf' structure. So we don't need to allocate the
ssl_conf for every options between [ ] but only when we found a relevant
one.

14 months agoMINOR: ssl: rename ckchs_load_cert_file to new_ckch_store_load_files_path
William Lallemand [Thu, 11 Apr 2024 13:55:16 +0000 (15:55 +0200)] 
MINOR: ssl: rename ckchs_load_cert_file to new_ckch_store_load_files_path

Remove the ambiguous "ckchs" name and reflect the fact that its loaded
from a path.

14 months agoREGTESTS: ssl: test simple case of crt-store
William Lallemand [Mon, 8 Apr 2024 15:52:08 +0000 (17:52 +0200)] 
REGTESTS: ssl: test simple case of crt-store

Test the crt-store loading with some basic cases.

14 months agoDOC: configuration: Add 3.12 Certificate Storage
William Lallemand [Tue, 13 Feb 2024 15:57:34 +0000 (16:57 +0100)] 
DOC: configuration: Add 3.12 Certificate Storage

The 3.12. Certificate Storage section, explain how to configure a
"crt-store" section.

14 months agoMINOR: ssl: add the section parser for 'crt-store'
William Lallemand [Fri, 9 Feb 2024 14:12:15 +0000 (15:12 +0100)] 
MINOR: ssl: add the section parser for 'crt-store'

'crt-store' is a new section useful to define the struct ckch_store.

The "load" keyword in the "crt-store" section allows to define which
files you want to load for a specific certificate definition.

Ex:
    crt-store
        load crt "site1.crt" key "site1.key"
        load crt "site2.crt" key "site2.key"

    frontend in
        bind *:443 ssl crt "site1.crt" crt "site2.crt"

This is part of the certificate loading which was discussed in #785.

15 months agoBUG/MEDIUM: cache/stats: Handle inbuf allocation failure in the I/O handler
Christopher Faulet [Fri, 12 Apr 2024 12:36:47 +0000 (14:36 +0200)] 
BUG/MEDIUM: cache/stats: Handle inbuf allocation failure in the I/O handler

When cache and stats applets were changed to use their own buffers, a change
was also performed to no longer access the stream from the I/O
handller. Among other things, the HTTP start-line of the request is now
retrieved to get the method. But, when these changes were brought, the inbuf
buffer allocation failures were not handled.

It is of course not so common. But if this happens, a crash may be
experienced. To fix the issue, we now check for inbuf allocation failures
before accessing it.

No backported needed.

15 months agoBUG/MINOR: server: fix slowstart behavior
Damien Claisse [Tue, 9 Apr 2024 15:37:07 +0000 (15:37 +0000)] 
BUG/MINOR: server: fix slowstart behavior

We observed that a dynamic server which health check is down for longer
than slowstart delay at startup doesn't trigger the warmup phase, it
receives full traffic immediately. This has been confirmed by checking
haproxy UI, weight is immediately the full one (e.g. 75/75), without any
throttle applied. Further tests showed that it was similar if it was in
maintenance, and even when entering a down or maintenance state after
being up.
Another issue is that if the server is down for less time than
slowstart, when it comes back up, it briefly has a much higher weight
than expected for a slowstart.

An easy way to reproduce is to do the following:
- Add a server with e.g. a 20s slowstart and a weight of 10 in config
  file
- Put it in maintenance using CLI (set server be1/srv1 state maint)
- Wait more than 20s, enable it again (set server be1/srv1 state ready)
- Observe UI, weight will show 10/10 immediately.
If server was down for less than 20s, you'd briefly see a weight and
throttle value that is inconsistent, e.g. 50% throttle value and a
weight of 5 if server comes back up after 10s before going back to
6% after a second or two.

Code analysis shows that the logic in server_recalc_eweight stops the
warmup task by setting server's next state to SRV_ST_RUNNING if it
didn't change state for longer than the slowstart duration, regardless
of its current state. As a consequence, a server being down or disabled
for longer than the slowstart duration will never enter the warmup phase
when it will be up again.

Regarding the weight when server comes back up, issue is that even if
the server is down, we still compute its next weight as if it was up,
hence when it comes back up, it can briefly have a much higher weight
than expected during slowstart, until the warmup task is called again
after last_change is updated.

This patch aims to fix both issues.

15 months agoDOC: install: clarify the build process by splitting it into subsections
Willy Tarreau [Thu, 11 Apr 2024 15:59:19 +0000 (17:59 +0200)] 
DOC: install: clarify the build process by splitting it into subsections

The doc about the build process has grown to a point where it was painful
to read when searching a specific element. This commit cuts it into a few
sub-categories for ease of searching, and it also adds a summary of the
most commonly used makefile variables, their usage and default settings.

15 months agoCLEANUP: makefile: make the output of the "opts" target more readable
Willy Tarreau [Thu, 11 Apr 2024 15:20:42 +0000 (17:20 +0200)] 
CLEANUP: makefile: make the output of the "opts" target more readable

"make opts" is nice because it shows all options being used, but it
does so in a copy-pastable way that aggregates everything on a single
line, rendering very poorly and making it hard to spot the relevant
variables.

Let's break lines and append a trailing backslash to them instead. This
gives something much more readable which remains copy-pastable. Options
can be inspected and more easily replicated. It was also verified that
copy-pasting the whole block after "make" does continue to work like
before and produces the same output.

15 months agoBUILD: makefile: also drop DEBUG_CFLAGS
Willy Tarreau [Wed, 10 Apr 2024 16:21:18 +0000 (18:21 +0200)] 
BUILD: makefile: also drop DEBUG_CFLAGS

This one is often used as a gateway to inject regular CFLAGS, even though
not designed for this. It's now ignored, but any attempt at setting it
reports a warning suggesting to use CFLAGS or ARCH_FLAGS instead.

15 months agoBUILD: makefile: do not pass warnings to VERBOSE_CFLAGS
Willy Tarreau [Thu, 11 Apr 2024 13:51:38 +0000 (15:51 +0200)] 
BUILD: makefile: do not pass warnings to VERBOSE_CFLAGS

The VERBOSE_CFLAGS variable is used to report the CFLAGS used in the
output of "haproxy -vv". It currently contains all -Wxxx and -Wno-xxx
because there was no other possibility till now, but these warnings
are highly specific to the compiler version in use, are automatically
detected and do not bring value being presented here. Worse, by
encouraging users to copy-paste them, they can end up with warnings
that are not relevant to their build environment.

In addition, their presence there doesn't give indication of whether
or not they triggered, so they cannot vouch for the output code quality.

Better just not report them there. However, as part of VERBOSE_CFLAGS
they were also used to detect whether or not to rebuild, via build_opts,
so they still have to be explicitly mentioned there if we want to make
sure that changing warning options triggers a rebuild to see their
effect.

Now we can have more useful outputs like this one which indicate precisely
what to use to safely rebuild the executable:

  Build options :
    TARGET  = linux-glibc
    CC      = gcc
    CFLAGS  = -O2 -g -fwrapv
    OPTIONS = USE_OPENSSL=1 USE_LUA=1 USE_ZLIB= USE_SLZ=1 USE_DEVICEATLAS=1 USE_51DEGREES=1 USE_WURFL=1 USE_QUIC=1 USE_PROMEX=1 USE_PCRE=1
    DEBUG   = -DDEBUG_DONT_SHARE_POOLS -DDEBUG_MEMORY_POOLS -DDEBUG_EXPR -DDEBUG_STRICT=2 -DDEBUG_DEV -DDEBUG_MEM_STATS -DDEBUG_POOL_TRACING

15 months agoBUILD: makefile: rename SPEC_CFLAGS to NOWARN_CFLAGS
Willy Tarreau [Thu, 11 Apr 2024 13:46:54 +0000 (15:46 +0200)] 
BUILD: makefile: rename SPEC_CFLAGS to NOWARN_CFLAGS

Now that the variable only serves to disable warnings, let's give it a
more suitable name and document its (rare) usage for package maintainers.

15 months agoBUILD: makefile: split WARN_CFLAGS from SPEC_CFLAGS
Willy Tarreau [Thu, 11 Apr 2024 13:29:42 +0000 (15:29 +0200)] 
BUILD: makefile: split WARN_CFLAGS from SPEC_CFLAGS

It's currently not possible to only set some -Wno... without breaking
the -W... and conversely. Let's split both sets apart so that it's now
possible to set -W... alone in WARN_CFLAGS to enable only some warnings,
and pass the -Wno... in SPEC_CFLAGS without losing the enabled ones.

15 months agoBUILD: makefile: extract -Werror/-Wfatal-errors from automatic CFLAGS
Willy Tarreau [Thu, 11 Apr 2024 13:20:46 +0000 (15:20 +0200)] 
BUILD: makefile: extract -Werror/-Wfatal-errors from automatic CFLAGS

The compiler-specific CFLAGS that are automatically detected (SPEC_CFLAGS)
are currently the ones affected by ERR and FAILFAST. Not only this makes
these options useless as soon as SPEC_CFLAGS is forced, but it also means
that any change to them causes a rebuild, so disabling FAILFAST or
enabling ERR to get more info on a faulty object causes a full rebuild
of all others. Let's just move them to ERROR_CFLAGS that only contains
these two.  It's not documented outside of the makefile because it's not
supposed to be touched.

15 months agoBUILD: makefile: add FAILFAST to select the -Wfatal-errors behavior
Willy Tarreau [Thu, 11 Apr 2024 13:08:14 +0000 (15:08 +0200)] 
BUILD: makefile: add FAILFAST to select the -Wfatal-errors behavior

-Wfatal-errors is set by default and is not supported on older compilers.
Since it's part of all the automatically detected flags, it's painful to
remove when needed. Also it's a matter of taste, some developers might
prefer to get a long list of all errors at once, others prefer that the
build stops immediately after the root cause.

The default is now back to no -Wfatal-errors, and when FAILFAST is set to
any non-empty non-zero value, -Wfatal-errors is added:

 $ make TARGET=linux-glibc USE_OPENSSL=0 USE_QUIC=1 FAILFAST=0 2>&1 | wc
    132     536    6111

 $ make TARGET=linux-glibc USE_OPENSSL=0 USE_QUIC=1 FAILFAST=1 2>&1 | wc
      8      39     362

15 months agoBUILD: makefile: make the ERR variable also support 0
Willy Tarreau [Thu, 11 Apr 2024 13:03:12 +0000 (15:03 +0200)] 
BUILD: makefile: make the ERR variable also support 0

It's among the options that change a lot on the developer's side and it's
tempting to change from ERR=1 to ERR=0 on the make command line by reusing
the history, except it doesn't work. Let's explictily permit ERR=0 to
disable -Werror like ERR= does.

15 months agoBUILD: makefile: move the fwrapv option to STD_CFLAGS
Willy Tarreau [Wed, 10 Apr 2024 16:48:20 +0000 (18:48 +0200)] 
BUILD: makefile: move the fwrapv option to STD_CFLAGS

We now have a separate CFLAGS variable for sensitive options that affect
code generation and/or standard compliance. This one must not be mixed
with the warnings auto-detection because changing such warnings can
result in losing the options. Now it's easier to affect them separately.
The option was not listed in the series of variables useful to packagers
because they're not supposed to touch it.

15 months agoBUILD: makefile: extract ARCH_FLAGS out of LDFLAGS
Willy Tarreau [Wed, 10 Apr 2024 16:16:44 +0000 (18:16 +0200)] 
BUILD: makefile: extract ARCH_FLAGS out of LDFLAGS

ARCH_FLAGS used to be merged into LDFLAGS so that it was not possible to
pass extra options to LDFLAGS without losing ARCH_FLAGS. This commit now
splits them apart and leaves LDFLAGS empty by default. The doc explains
how to use it for rpath and such occasional use cases.

15 months agoBUILD: makefile: drop the ARCH variable and better document ARCH_FLAGS
Willy Tarreau [Wed, 10 Apr 2024 15:58:00 +0000 (17:58 +0200)] 
BUILD: makefile: drop the ARCH variable and better document ARCH_FLAGS

ARCH_FLAGS was always present and is documented as being fed to both
CC and LD during the build. This is meant for options that need to be
consistent between the two stages such as -pg, -flto, -fsanitize=address,
-m64, -g etc. Its doc was lacking a bit of clarity though, and it was
not enumerated in the makefile's variables list.

ARCH however was only documented as affecting ARCH_FLAGS, and was just
never used as the only two really usable and supported ARCH_FLAGS options
were -m32 and -m64. In addition it was even written in the makefile that
it was CPU that was affecting the ARCH_FLAGS. Let's just drop ARCH and
improve the documentation on ARCH_FLAGS. Again, if ARCH is set, a warning
is emitted explaining how to proceed.

ARCH_FLAGS is now preset to -g so that we finally have a correct place
to deal with such debugging options that need to be passed to both
stages. The fedora and musl CI workflows were updated to also use it
instead of sticking to duplicate DEBUG_CFLAGS+LDFLAGS.

It's also worth noting that BUILD_ARCH was being passed to the build
process and never used anywhere in the code, so its removal will not
be noticed.

15 months agoBUILD: makefile: get rid of the CPU variable
Willy Tarreau [Wed, 10 Apr 2024 15:00:10 +0000 (17:00 +0200)] 
BUILD: makefile: get rid of the CPU variable

The CPU variable, when used, is almost always exclusively used with
"generic" to disable any CPU-specific optimizations, or "native" to
enable "-march=native". Other options are not used and are just making
CPU_CFLAGS more confusing.

This commit just drops all pre-configured variants and replaces them
with documentation about examples of supported options. CPU_CFLAGS is
preserved as it appears that it's mostly used as a proxy to inject the
distro's CFLAGS, and it's just empty by default.

The CPU variable is checked, and if set to anything but "generic", it
emits a warning about its deprecation and invites the user to read
INSTALL.

Users who would just set CPU_CFLAGS will be able to continue to do so,
those who were using CPU=native will have to pass CPU_CFLAGS=-march=native
and those who were passing one of the other options will find it in the
doc as well.

Note that this also removes the "CPU=" line from haproxy -vv, that most
users got used to seeing set to "generic" or occasionally "native"
anyway, thus that didn't provide any useful information.

15 months agoBUILD: makefile: move -O2 from CPU_CFLAGS to OPT_CFLAGS
Willy Tarreau [Wed, 10 Apr 2024 14:26:34 +0000 (16:26 +0200)] 
BUILD: makefile: move -O2 from CPU_CFLAGS to OPT_CFLAGS

CPU_CFLAGS is meant to set the CPU-specific options (-mcpu, -march etc).
The fact that it also includes the optimization level is annoying because
one cannot be set without replacing the other. Let's move the optimization
level to a new independent OPT_CFLAGS that is added early to the list, so
that other CFLAGS (including CPU_CFLAGS) can continue to override it if
necessary.

15 months agoBUILD: makefile: drop the SMALL_OPTS settings
Willy Tarreau [Wed, 10 Apr 2024 13:16:02 +0000 (15:16 +0200)] 
BUILD: makefile: drop the SMALL_OPTS settings

These settings were appended to the final build CFLAGS and used to
contain a mix of obsolete settings that can equally be passed in one
of the many other variables such as DEFINE or more recently CFLAGS.
Let's just drop the obsolete comment about it, and check if anything
was forced there, then emit a warning suggesting to move that to other
variables such as DEFINE or CFLAGS, so as to be kind to package
maintainers.

15 months agoBUILD: makefile: allow to use CFLAGS to append build options
Willy Tarreau [Wed, 10 Apr 2024 09:29:49 +0000 (11:29 +0200)] 
BUILD: makefile: allow to use CFLAGS to append build options

CFLAGS has always been a troublemaker because the variable was preset
based on other options, including dynamically detected ones, so
overriding it would just lose the original contents, forcing users
to resort to various alternatives such as DEFINE, ADDINC or SMALL_OPTS.

Now that the variable's usage was cleared, let's just preset it to
empty (and it MUST absolutely remain like this) and append it at the
end of the compiler's options. This will now allow to change an
optimization level, force a CPU type or disable a warning as users
commonly expect from CFLAGS passed to a makefile, and not to override
*all* the compiler flags as it has progressively become.

15 months agoBUILD: makefile: get rid of the config CFLAGS variable
Willy Tarreau [Wed, 10 Apr 2024 07:36:48 +0000 (09:36 +0200)] 
BUILD: makefile: get rid of the config CFLAGS variable

CFLAGS currently is a concatenation of 4 other variables, some of which
are dynamically determined. This has long been totally unusable to pass
any extra option. Let's just get rid of it and pass the 4 variables at
the 3 only places CFLAGS was used. This will later allow us to make
CFLAGS something really usable.

This also has the benefit of implicitly restoring the build on AIX5
which needs to disable DEBUG_CFLAGS to solve symbol issues when built
with -g. Indeed, that one got ignored since the targets moved past the
CFLAGS definition which collects DEBUG_CFLAGS.

15 months agoCI: update the build options to get rid of unneeded DEBUG options
Willy Tarreau [Wed, 10 Apr 2024 07:28:24 +0000 (09:28 +0200)] 
CI: update the build options to get rid of unneeded DEBUG options

Now that DEBUG_STRICT and DEBUG_MEMORY_POOLS are the default, we can
drop them from the build options.

15 months agoBUILD: pools: make DEBUG_MEMORY_POOLS=1 the default option
Willy Tarreau [Wed, 10 Apr 2024 07:20:19 +0000 (09:20 +0200)] 
BUILD: pools: make DEBUG_MEMORY_POOLS=1 the default option

This option has been set by default for a very long time and also
complicates the manipulation of the DEBUG variable. Let's make it
the official default and permit to unset it by setting it to zero.
The other pool-related DEBUG options were adjusted to also explicitly
check for the zero value for consistency.

15 months agoBUILD: debug: make DEBUG_STRICT=1 the default
Willy Tarreau [Wed, 10 Apr 2024 07:02:28 +0000 (09:02 +0200)] 
BUILD: debug: make DEBUG_STRICT=1 the default

We continue to carry it in the makefile, which adds to the difficulty
of passing new options. Let's make DEBUG_STRICT=1 the default so that
one has to explicitly pass DEBUG_STRICT=0 to disable it. This allows us
to remove the option from the default DEBUG variable in the makefile.

15 months agoBUILD: cache: fix non-inline vs inline declaration mismatch to silence a warning
Willy Tarreau [Thu, 11 Apr 2024 15:19:08 +0000 (17:19 +0200)] 
BUILD: cache: fix non-inline vs inline declaration mismatch to silence a warning

Some compilers report this on the cache:
  src/cache.c:235: warning: 'release_entry_locked' declared inline after being called
  src/cache.c:235: warning: previous declaration of 'release_entry_locked' was here

And indeed, the function is first declared non-inline and later inline.
Let's just set the inline status from the beginning. It's not really
needed to backport this.

15 months agoBUG/MINOR: debug: make sure DEBUG_STRICT=0 does work as documented
Willy Tarreau [Wed, 10 Apr 2024 07:07:31 +0000 (09:07 +0200)] 
BUG/MINOR: debug: make sure DEBUG_STRICT=0 does work as documented

Setting DEBUG_STRICT=0 only validates the defined(DEBUG_STRICT) test
regarding DEBUG_STRICT_ACTION, which is equivalent to DEBUG_STRICT>=0.
Let's make sure the test checks for >0 so that DEBUG_STRICT=0 properly
disables DEBUG_STRICT.

15 months agoBUILD: atomic: fix peers build regression on gcc < 4.7 after recent changes
Willy Tarreau [Thu, 11 Apr 2024 14:34:03 +0000 (16:34 +0200)] 
BUILD: atomic: fix peers build regression on gcc < 4.7 after recent changes

Recent commit 4c1480f13b ("MINOR: stick-tables: mark the seen stksess
with a flag "seen"") introduced a build regression on older versions of
gcc before 4.7. This is in the old __sync_ API, the HA_ATOMIC_LOAD()
implementation uses an intermediary return value called "ret" that is
of the same name as the variable passed in argument to the macro in the
aforementioned commit. As such, the compiler complains with a cryptic
error:
  src/peers.c: In function 'peer_teach_process_stksess_lookup':
  src/peers.c:1502: error: invalid type argument of '->' (have 'int')

The solution is to avoid referencing the argument in the expression and
using an intermediary variable for the pointer as done elsewhere in the
code. It seems there's no other place affected with this. It probably
does not need to be backported since this code is antique and very rarely
used nowadays.

15 months agoBUG/MINOR: guid: fix crash on invalid guid name
Amaury Denoyelle [Thu, 11 Apr 2024 09:05:02 +0000 (11:05 +0200)] 
BUG/MINOR: guid: fix crash on invalid guid name

Using an invalid GUID for guid_insert() causes a crash. This is easily
reproducible using for example an invalid character with "guid" keyword.
Here is the provided backtrace :

  Thread 1 "haproxy" received signal SIGSEGV, Segmentation fault.
  0x00005555561fda95 in guid_insert (objt=0x520000002080, uid=0x519000002dac "@foo2", errmsg=0x7ffff4c0a7a0)
      at src/guid.c:83
  83              ha_free(&guid->node.key);

This error is present in guid_insert() cleanup parts. GUID node is not
allocated in case of an early error so it's impossible to dereference it
to free guid.node.key. Fix this simply by using an intermediary pointer
key.

This does not need to be backported.

15 months agoBUILD: makefile: support USE_xxx=0 as well
Willy Tarreau [Thu, 11 Apr 2024 08:41:39 +0000 (10:41 +0200)] 
BUILD: makefile: support USE_xxx=0 as well

William rightfully reported that not supporting =0 to disable a USE_xxx
option is sometimes painful (e.g. a script might do USE_xxx=$(command)).
It's not that difficult to handle actually, we just need to consider the
value 0 as empty at the few places that test for an empty string in
options.mk, and in each "ifneq" test in the main Makefile, so let's do
that. We even take care of preserving the original value in the build
options string so that building with USE_OPENSSL=0 will be reported
as-is in haproxy -vv, and with "-OPENSSL" in the feature list.

15 months agoBUILD: makefile: warn about unknown USE_* variables
Willy Tarreau [Thu, 11 Apr 2024 06:27:18 +0000 (08:27 +0200)] 
BUILD: makefile: warn about unknown USE_* variables

William suggested that it would be nice to warn about unknown USE_*
variables to more easily catch misspelled ones. The valid ones are
present in use_opts, so by appending "=%" to each of them, we can
build a series of patterns to exclude from MAKEOVERRIDES and emit
a warning for the ones that stand out.

Example:

  $ make TARGET=linux-glibc  USE_QUIC_COMPAT_OPENSSL=1
  Makefile:338: Warning: ignoring unknown build option: USE_QUIC_COMPAT_OPENSSL=1
    CC      src/slz.o

15 months agoBUG/MINOR: http-ana: Fix TX_L7_RETRY and TX_D_L7_RETRY values
Christopher Faulet [Mon, 8 Apr 2024 17:14:46 +0000 (19:14 +0200)] 
BUG/MINOR: http-ana: Fix TX_L7_RETRY and TX_D_L7_RETRY values

These values are obviously wrong. There is an extra zero at the end for both
defines. By chance, it is harmless. But it is better to fix it.

This patch should be backported as far as 2.6.

15 months agoBUG/MEDIUM: http-ana: Deliver 502 on keep-alive for fressh server connection
Christopher Faulet [Tue, 9 Apr 2024 06:19:01 +0000 (08:19 +0200)] 
BUG/MEDIUM: http-ana: Deliver 502 on keep-alive for fressh server connection

In HTTP keep-alive, if we face a connection error to the server while
sending the request, the error should not be reported, and the client-side
connection should simply be closed, so that client knows it can retry.

If the error happens during the connection stage, there is two cases. We
have a connection timeout or an allocation error. In this case, the 503
response must be skipped if it is not the first request on the client-side
connection. Or we have a connection error. In this case, the 503 response
must be skipped if it is a reused server connection. Otherwise, during the
connection stage, the 503-Service-unavailable response is delivered to the
client. The part works properly.

If the error happens after this stage, the 502-Bad-gateway response
delivering should only be based on the server-side connection status. For a
reused server connection, the client-side connection must be closed with no
reponses. However, for a fresh server-side connection, a 502-Bad-gateway
response must be delivered to the client. Unfortunately, This part is
buggy. Only the client-side connection state is considered and the response
is skipped if it is not the first request for the same client connection.

The bug is not so visbile in HTTP/1.1 but in H2 and H3 it is pretty annoying
because for a connection, requests are multiplexed, in parallels. It means
there is no first request. So, because of this bug, for H2 and H3,
502-Bad-gateway responses because of a connection error before receiveing
the response are always skipped.

To fix the issue, in http_wait_for_response() analyser, we must only rely on
SF_SRV_REUSED stream flag to skip the 502 response or not. This flag is set
if the server connection was reused.

The bug is their since a while. SF_SRV_REUSED flag was added in the version
1.5 especially to fix this kind of bug. But only the 503 case was fixed.

This patch should fix the issue #2285. It must be backported to every stable
versions.

15 months agoOPTIM: quic: do not call qc_prep_pkts() if everything sent
Amaury Denoyelle [Wed, 10 Apr 2024 07:38:00 +0000 (09:38 +0200)] 
OPTIM: quic: do not call qc_prep_pkts() if everything sent

qc_send() is implemented as a loop to repeatedly invoke
qc_prep_pkts()/qc_send_ppkts(). This ensures that all data are emitted
even if bigger that a single Tx buffer instance. This is useful if
congestion window is empty but big enough for application data.

Looping is interrupted if qc_prep_pkts() returns a negative error
code, for example due to no space left in congestion window. It can also
returns 0 if no input data to sent, which also interrupt the loop.

To limit this last case, removed quic_enc_level from send_list each time
everything already send via qc_prep_pkts(). Loop can then be interrupted
as soon as send_list is empty, avoiding an extra superfluous call to
qc_prep_pkts().

15 months agoOPTIM: quic: do not call qc_send() if nothing to emit
Amaury Denoyelle [Wed, 10 Apr 2024 08:14:01 +0000 (10:14 +0200)] 
OPTIM: quic: do not call qc_send() if nothing to emit

qc_send() was systematically called by quic_conn IO handlers with all
instantiated quic_enc_level. Change this to only register quic_enc_level
for send if needed. Do not call at all qc_send() if no qel registered.

A new function qel_need_sending() is defined to detect if sending is
required. First, it checks if quic_enc_level has prepared frames or
probing is set. It can also returns true if ACK required either on
quic_enc_level itself or because of quic_conn ack timer fired. Finally,
a CONNECTION_CLOSE emission for quic_conn is also a valid case.

This should reduce the number of invocations of qc_send(). This could
improve slightly performance, as well as simplify traces debugging.

15 months agoMEDIUM: quic: remove duplicate hdshk/app send functions
Amaury Denoyelle [Fri, 5 Apr 2024 16:04:32 +0000 (18:04 +0200)] 
MEDIUM: quic: remove duplicate hdshk/app send functions

A series of previous patches have clean up sending function for
handshake case. Their new exposed API is now flexible enough to convert
app case to use the same functions.

As such, qc_send_hdshk_pkts() is renamed qc_send() and become the single
entry point for QUIC emission. It is used during application packets
emission in quic_conn_app_io_cb(), qc_send_mux(). Also the internal
function qc_prep_hpkts() is renamed qc_prep_pkts().

Remove the new unneeded qc_send_app_pkts() and qc_prep_app_pkts().

Also removed qc_send_app_probing(). It was a simple wrapper over other
application send functions. Now, default qc_send() can be reuse for such
cases with <old_data> argument set to true.

An adjustment was needed when converting qc_send_hdshk_pkts() to the
general qc_send() version. Previously, only a single packets
encoding/emission cycle was performed. This was enough as handshake
packets are always smaller than Tx buffer. However, it may be possible
to emit more application data. As such, a loop is necessary to perform
multiple encoding/emission cycles, as this was already the case in
qc_send_app_pkts().

No functional difference should happen with this commit. However, as
these are critcal functions with a lot of changes, this patch is
labelled as medium.

15 months agoMINOR: quic: use qc_send_hdshk_pkts() in handshake IO cb
Amaury Denoyelle [Mon, 8 Apr 2024 07:46:46 +0000 (09:46 +0200)] 
MINOR: quic: use qc_send_hdshk_pkts() in handshake IO cb

quic_conn_io_cb() manually implements emission by using lower level
functions qc_prep_pkts() and qc_send_ppkts(). Replace this by using the
higher level function qc_send_hdshk_pkts() which notably handle buffer
allocation and purging.

This allows to clean up send API by flagging qc_prep_pkts() and
qc_send_ppkts() as static. They are now used in a single location inside
qc_send_hdshk_pkts().

15 months agoMINOR: quic: improve sending API on retransmit
Amaury Denoyelle [Fri, 5 Apr 2024 15:43:38 +0000 (17:43 +0200)] 
MINOR: quic: improve sending API on retransmit

qc_send_hdshk_pkts() is a wrapper for qc_prep_hpkts() used on
retransmission. It was restricted to use two quic_enc_level pointers as
distinct arguments. Adapt it to directly use the same list of
quic_enc_level which is passed then to qc_prep_hpkts().

Now for retransmission quic_enc_level send list is built directly into
qc_dgrams_retransmit() which calls qc_send_hdshk_pkts().

Along this change, a new utility function qel_register_send() is
defined. It is an helper to build the quic_enc_level send list. It
enfores that each quic_enc_level instance is only registered in a single
list to prevent memory issues. It is both used in qc_dgrams_retransmit()
and quic_conn_io_cb().

15 months agoMINOR: quic: uniformize sending methods for handshake
Amaury Denoyelle [Fri, 5 Apr 2024 15:23:54 +0000 (17:23 +0200)] 
MINOR: quic: uniformize sending methods for handshake

Emission of packets during handshakes was implemented via an API which
uses two alternative ways to specify the list of frames.

The first one uses a NULL list of quic_enc_level as argument for
qc_prep_hpkts(). This was an implicit method to iterate on all qels
stored in quic_conn instance, with frames already inserted in their
corresponding quic_pktns.

The second method was used for retransmission. It uses a custom local
quic_enc_level list specified by the caller as input to qc_prep_hpkts().
Frames were accessible through <retransmit> list pointers of each
quic_enc_level used in an implicit mechanism.

This commit clarifies the API by using a single common method. Now
quic_enc_level list must always be specified by the caller. As for
frames list, each qels must set its new field <send_frms> pointer to the
list of frames to send. Callers of qc_prep_hpkts() are responsible to
always clear qels send list. This prevent a single instance of
quic_enc_level to be inserted while being attached to another list.

This allows notably to clean up some unnecessary code. First,
<retransmit> list of quic_enc_level is removed as it is replaced by new
<send_frms>. Also, it's now possible to use proper list_for_each_entry()
inside qc_prep_hpkts() to loop over each qels. Internal functions for
quic_enc_level selection is now removed.

15 months agoMINOR: quic: simplify qc_send_hdshk_pkts() return
Amaury Denoyelle [Mon, 8 Apr 2024 13:25:56 +0000 (15:25 +0200)] 
MINOR: quic: simplify qc_send_hdshk_pkts() return

Clean up trailer of qc_send_hdshk_pkts() by removing label "leave". Only
"out" label is now used. This operation is safe as LIST_DEL_INIT() is
idempotent. Caller of qc_send_hdshk_pkts() also ensures input frame
lists are freed, so it's better to always reset quic_enc_level
<retrans_frms> member.

Also take the opportunity to reset QUIC_FL_CONN_RETRANS_OLD_DATA only if
already set. This is considered more robust and will also remove
unneeded trace occurences.

No functional change. The main objective of this commit is to clean up
code in preparation of a refactoring on send functions.

15 months agoCLEANUP: log: lf_text_len() returns a pointer not an integer
Aurelien DARRAGON [Tue, 9 Apr 2024 13:28:00 +0000 (15:28 +0200)] 
CLEANUP: log: lf_text_len() returns a pointer not an integer

In c83684519 ("MEDIUM: log: add the ability to include samples in logs")
we checked the return value of lf_text_len() as an integer instead of
comparing the pointer with NULL explicitly. Since this may be confusing,
let's test the return value against NULL.

[ada: for backports, the patch needs to be applied manually because of
 c6a713842 ("MINOR: log: simplify last_isspace in sess_build_logline()")]

15 months agoBUG/MINOR: log: invalid snprintf() usage in sess_build_logline()
Aurelien DARRAGON [Tue, 9 Apr 2024 13:59:42 +0000 (15:59 +0200)] 
BUG/MINOR: log: invalid snprintf() usage in sess_build_logline()

According to snprintf() man page:

       The  functions snprintf() and vsnprintf() do not write more than
       size bytes (including the terminating null byte ('\0')).  If the
       output was truncated due to this limit, then the return value is
       the number of  characters  (excluding  the  terminating null byte)
       which would have been written to the final string if enough space
       had been available.  Thus, a return value of size or more means
       that the output was truncated.

However, in sess_build_logline(), each time we need to check the return
value of snprintf(), here is how we proceed:

       iret = snprintf(tmplog, max, ...);
       if (iret < 0 || iret > max)
           // error
       // success
       tmplog += iret;

Here is the issue: if snprintf() lacks 1 byte space to write the
terminating NULL byte, it will return max. Which means in this case
that we fail to know that snprintf() truncated the output in reality,
and we still add iret to tmplog pointer. Considering sess_build_logline()
should NOT write more than <maxsize> bytes (including the terminating NULL
byte) as per the function description, in this case the function would
write <maxsize>+1 byte (to write the terminating NULL byte upon return),
which may lead to invalid write if <dst> was meant to hold <maxsize> bytes
at maximum.

Hopefully, this bug wasn't triggered so far because sess_build_logline()
is called with logline as <dst> argument and <global.max_syslog_len> as
<maxsize> argument, logline being initialized with 1 extra byte upon
startup.

But we better fix this to comply with the function description and prevent
any side-effect since some sess_build_logline() helpers may assume that
'tmplog-dst < maxsize' is always true. Also sess_build_logline() users
probably don't expect NULL-byte to be accounted for in the produced
logline length.

This should be backported to all stable versions.

[ada: for backports, the patch needs to be applied manually because of
 c6a713842 ("MINOR: log: simplify last_isspace in sess_build_logline()")]

15 months agoBUG/MINOR: tools/log: invalid encode_{chunk,string} usage
Aurelien DARRAGON [Tue, 9 Apr 2024 09:44:54 +0000 (11:44 +0200)] 
BUG/MINOR: tools/log: invalid encode_{chunk,string} usage

encode_{chunk,string}() is often found to be used this way:

  ret = encode_{chunk,string}(start, stop...)
  if (ret == NULL || *ret != '\0') {
//error
  }
  //success

Indeed, encode_{chunk,string} will always try to add terminating NULL byte
to the output string, unless no space is available for even 1 byte.
However, it means that for the caller to be able to spot an error, then it
must provide a buffer (here: start) which is already initialized.

But this is wrong: not only this is very tricky to use, but since those
functions don't return NULL on failure, then if the output buffer was not
properly initialized prior to calling the function, the caller will
perform invalid reads when checking for failure this way. Moreover, even
if the buffer is initialized, we cannot reliably tell if the function
actually failed this way because if the buffer was previously initialized
with NULL byte, then the caller might think that the call actually
succeeded (since the function didn't return NULL and didn't update the
buffer).

Also, sess_build_logline() relies lf_encode_{chunk,string}() functions
which are in fact wrappers for encode_{chunk,string}() functions and thus
exhibit the same error handling mechanism. It turns out that
sess_build_logline() makes unsafe use of those functions because it uses
the error-checking logic mentionned above while buffer (tmplog) is not
guaranteed to be initialized when entering the function. This may
ultimately cause malfunctions or invalid reads if the output buffer is
lacking space.

To fix the issue once and for all and prevent similar bugs from being
introduced, we make it so encode_{string, chunk} and escape_string()
(based on encode_string()) now explicitly return NULL on failure
(when the function failed to write at least the ending NULL byte)

lf_encode_{string,chunk}() helpers had to be patched as well due to code
duplication.

This should be backported to all stable versions.

[ada: for 2.4 and 2.6 the patch won't apply as-is, it might be helpful to
 backport ae1e14d65 ("CLEANUP: tools: removing escape_chunk() function")
 first, considering it's not very relevant to maintain a dead function]

15 months agoBUG/MINOR: log: fix lf_text_len() truncate inconsistency
Aurelien DARRAGON [Tue, 9 Apr 2024 09:15:23 +0000 (11:15 +0200)] 
BUG/MINOR: log: fix lf_text_len() truncate inconsistency

In c5bff8e550 ("BUG/MINOR: log: improper behavior when escaping log data")
we fixed lf_text_len() behavior with +E (escape) option.

However we introduced an inconsistency if output buffer is too small to
hold the whole output and truncation occurs: indeed without +E option up
to <size> bytes (including NULL byte) will be used whereas with +E option
only <size-1> bytes will be used. Fixing the function and related comment
so that the function behaves the same in regards to truncation whether +E
option is used or not.

This should be backported to all stable versions.

15 months agoBUG/MINOR: listener: always assign distinct IDs to shards
Willy Tarreau [Tue, 9 Apr 2024 06:41:06 +0000 (08:41 +0200)] 
BUG/MINOR: listener: always assign distinct IDs to shards

When sharded listeners were introdcued in 2.5 with commit 6dfbef4145
("MEDIUM: listener: add the "shards" bind keyword"), a point was
overlooked regarding how IDs are assigned to listeners: they are just
duplicated! This means that if a "option socket-stats" is set and a
shard is configured, or multiple thread groups are enabled, then a stats
dump will produce several lines with exactly the same socket name and ID.

This patch tries to address this by trying to assign consecutive numbers
to these sockets. The usual algo is maintained, but with a preference for
the next number in a shard. This will help users reserve ranges for each
socket, for example by using multiples of 100 or 1000 on each bind line,
leaving enough room for all shards to be assigned.

The mechanism however is quite tricky, because the configured listener
currently ends up being the last one of the shard. This helps insert them
before the current position without having to revisit them. But here it
causes a difficulty which is that we'd like to restart from the current
ID and assign new ones on top of it. What is done is that the number is
passed between shards and the current one is cleared (and removed from
the tree) so that we instead insert the new one. It's tricky because of
the situation which depends whether it's the listener that was already
assigned on the bind line or not. But overall, always removing the entry,
always adding the new one when the ID is not zero, and passing them from
the reference to the next one does the trick.

This may be backported to all versions till 2.6.

15 months agoBUG/MINOR: cli: Don't warn about a too big command for incomplete commands
Christopher Faulet [Mon, 8 Apr 2024 05:41:17 +0000 (07:41 +0200)] 
BUG/MINOR: cli: Don't warn about a too big command for incomplete commands

When a command is too big to fit in a buffer, a error is returned before
closing. However, the error is also returned if the command is small enough
but incomplete. It happens on abort. In this case, the error must not be
reported. The regression was introduced when a dedicated sn_buf callbac
function was added.

To fix the issue, both cases are now handled separately.

No backport needed.

15 months ago[RELEASE] Released version 3.0-dev7 v3.0-dev7
Willy Tarreau [Sat, 6 Apr 2024 15:02:07 +0000 (17:02 +0200)] 
[RELEASE] Released version 3.0-dev7

Released version 3.0-dev7 with the following main changes :
    - BUG/MINOR: ssl: Wrong ocsp-update "incompatibility" error message
    - BUG/MINOR: ssl: Detect more 'ocsp-update' incompatibilities
    - MEDIUM: ssl: Add 'tune.ssl.ocsp-update.mode' global option
    - REGTESTS: ssl: Add OCSP update compatibility tests
    - REGTESTS: ssl: Add functional test for global ocsp-update option
    - BUG/MINOR: server: reject enabled for dynamic server
    - BUG/MINOR: server: fix persistence cookie for dynamic servers
    - MINOR: server: allow cookie for dynamic servers
    - REGTESTS: Fix script about OCSP update compatibility tests
    - BUG/MINOR: cli: Report an error to user if command or payload is too big
    - MINOR: sc_strm: Add generic version to perform sync receives and sends
    - MEDIUM: stream: Use generic version to perform sync receives and sends
    - MEDIUM: buf: Add b_getline() and b_getdelim() functions
    - MEDIUM: applet: Handle applets with their own buffers in put functions
    - MEDIUM: cli/applet: Stop to test opposite SC in I/O handler of CLI commands
    - MINOR: applet: Always use applet API to set appctx flags
    - BUG/MEDIUM: applet: State appctx have more data if its EOI/EOS/ERROR flag is set
    - MAJOR: cli: Update the CLI applet to handle its own buffers
    - MINOR: applet: Let's applets .snd_buf function deal with full input buffers
    - MINOR: stconn: Add a connection flag to notify sending data are the last ones
    - MAJOR: cli: Use a custom .snd_buf function to only copy the current command
    - DOC: config: balance 'first' not usable in LOG mode
    - BUG/MINOR: log/balance: detect if user tries to use unsupported algo
    - MINOR: lbprm: implement true "sticky" balance algo
    - MEDIUM: log/balance: leverage lbprm api for log load-balancing
    - BUG/BUILD: debug: fix unused variable error
    - MEDIUM: lb-chash: Deterministic node hashes based on server address
    - BUG/MEDIUM: stick-tables: fix a small remaining race in expiration task
    - REGTESTS: Do not use REQUIRE_VERSION for HAProxy 2.5+ (4)
    - REGTESTS: Remove REQUIRE_VERSION=1.9 from all tests (2)
    - CLEANUP: Reapply ist.cocci (3)
    - CLEANUP: Reapply strcmp.cocci (2)
    - CLEANUP: Reapply xalloc_cast.cocci
    - CLEANUP: Reapply ha_free.cocci
    - CI: vtest: show coredumps if any
    - REGTESTS: ssl: disable ssl/ocsp_auto_update.vtc
    - BUG/MINOR: backend: properly handle redispatch 0
    - MINOR: quic: HyStart++ implementation (RFC 9406)
    - BUG/MEDIUM: stconn: Don't forward shutdown to SE if iobuf is not empty
    - BUG/MEDIUM: stick-table: use the update lock when reading tables from peers
    - BUG/MAJOR: applet: fix a MIN vs MAX usage in appctx_raw_rcv_buf()
    - OPTIM: peers: avoid the locking dance around peer_send_teach_process_msgs()
    - BUILD: quic: 32 bits compilation issue (QUIC_MIN() usage)
    - BUG/MEDIUM: server/lbprm: fix crash in _srv_set_inetaddr_port()
    - MEDIUM: mworker: get rid of libsystemd
    - BUILD: systemd: fix build error on non-systemd systems with USE_SYSTEMD=1
    - BUG/MINOR: bwlim/config: fix missing '\n' after error messages
    - MINOR: stick-tables: mark the seen stksess with a flag "seen"
    - OPTIM: stick-tables: check the stksess without taking the read lock
    - MAJOR: stktable: split the keys across multiple shards to reduce contention
    - CI: extend Fedora Rawhide, add m32 mode
    - BUG/MINOR: stick-tables: Missing stick-table key nullity check
    - BUILD: systemd: enable USE_SYSTEMD by default with TARGET=linux-glibc
    - MINOR: systemd: Include MONOTONIC_USEC field in RELOADING=1 message
    - BUG/MINOR: proxy: fix logformat expression leak in use_backend rules
    - MEDIUM: log: rename logformat var to logformat tag
    - MINOR: log: expose logformat_tag struct
    - MEDIUM: log: carry tag context in logformat node
    - MEDIUM: tree-wide: add logformat expressions wrapper
    - MINOR: proxy: add PR_FL_CHECKED flag
    - MAJOR: log: implement proper postparsing for logformat expressions
    - MEDIUM: log: add compiling logic to logformat expressions
    - MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
    - MINOR: guid: introduce global UID module
    - MINOR: guid: restrict guid format
    - MINOR: proxy: implement GUID support
    - MINOR: server: implement GUID support
    - MINOR: listener: implement GUID support
    - DOC: configuration: grammar fixes for strict-sni
    - BUG/MINOR: init: relax LSTCHK_NETADM checks for non root
    - MEDIUM: capabilities: check process capabilities sets
    - CLEANUP: global: remove LSTCHK_CAP_BIND
    - BUG/MEDIUM: quic: don't blindly rely on unaligned accesses

15 months agoBUG/MEDIUM: quic: don't blindly rely on unaligned accesses
Willy Tarreau [Fri, 5 Apr 2024 21:54:17 +0000 (23:54 +0200)] 
BUG/MEDIUM: quic: don't blindly rely on unaligned accesses

There are several places where the QUIC low-level code performs unaligned
accesses by casting unaligned char* pointers to uint32_t, but this is
totally forbidden as it only works on machines that support unaligned
accesses, and either crashes on other ones (SPARC, MIPS), can result in
reading garbage (ARMv5) or be very slow due to the access being emulated
(RISC-V). We do have functions for this, such as read_u32() and write_u32()
that rely on the compiler's knowledge of the machine's capabilities to
either perform an unaligned access or do it one byte at a time.

This must be backported at least as far as 2.6. Some of the code moved a
few times since, so in order to figure the points that need to be fixed,
one may look for a forced pointer cast without having verified that either
the machine is compatible or that the pointer is aligned using this:

  $ git grep 'uint[36][24]_t \*)'

Or build and run the code on a MIPS or SPARC and perform requests using
curl to see if they work or crash with a bus error. All the places fixed
in this commit were found thanks to an immediate crash on the first
request.

This was tagged medium because the affected archs are not the most common
ones where QUIC will be found these days.

15 months agoCLEANUP: global: remove LSTCHK_CAP_BIND
Valentine Krasnobaeva [Fri, 15 Mar 2024 15:11:25 +0000 (16:11 +0100)] 
CLEANUP: global: remove LSTCHK_CAP_BIND

Remove LSTCHK_CAP_BIND as it is never set and never checked.

15 months agoMEDIUM: capabilities: check process capabilities sets
Valentine Krasnobaeva [Fri, 15 Mar 2024 17:02:05 +0000 (18:02 +0100)] 
MEDIUM: capabilities: check process capabilities sets

Since the Linux capabilities support add-on (see the commit bd84387beb26
("MEDIUM: capabilities: enable support for Linux capabilities")), we can also
check haproxy process effective and permitted capabilities sets, when it
starts and runs as non-root.

Like this, if needed network capabilities are presented only in the process
permitted set, we can get this information with capget and put them in the
process effective set via capset. To do this properly, let's introduce
prepare_caps_from_permitted_set().

First, it checks if binary effective set has CAP_NET_ADMIN or CAP_NET_RAW. If
there is a match, LSTCHK_NETADM is removed from global.last_checks list to
avoid warning, because in the initialization sequence some last configuration
checks are based on LSTCHK_NETADM flag and haproxy process euid may stay
unpriviledged.

If there are no CAP_NET_ADMIN and CAP_NET_RAW in the effective set, permitted
set will be checked and only capabilities given in 'setcap' keyword will be
promoted in the process effective set. LSTCHK_NETADM will be also removed in
this case by the same reason. In order to be transparent, we promote from
permitted set only capabilities given by user in 'setcap' keyword. So, if
caplist doesn't include CAP_NET_ADMIN or CAP_NET_RAW, LSTCHK_NETADM would not
be unset and warning about missing priviledges will be emitted at
initialization.

Need to call it before protocol_bind_all() to allow binding to priviledged
ports under non-root and 'setcap cap_net_bind_service' must be set in the
global section in this case.

15 months agoBUG/MINOR: init: relax LSTCHK_NETADM checks for non root
Valentine Krasnobaeva [Mon, 18 Mar 2024 13:50:26 +0000 (14:50 +0100)] 
BUG/MINOR: init: relax LSTCHK_NETADM checks for non root

Linux capabilities support and ability to preserve it for running process
after switching to a global.uid was added recently by the commit bd84387beb26
("MEDIUM: capabilities: enable support for Linux capabilities")).
This new feature hasn't yet been taken into account by last config checks,
which are performed at initialization stage.

So, to update it, let's perform it after set_identity() call. Like this,
current EUID is already changed to a global.uid and prepare_caps_for_setuid()
would unset LSTCHK_NETADM flag, only if capabilities given in the 'setcap'
keyword in the configuration file were preserved.

Otherwise, if system doesn't support Linux capabilities or they were not set
via 'setcap', we keep the previous strict behaviour: process will terminate
with an alert, in order to insist that user: either needs to change
run UID (worst case: start and run as root), or he needs to set/recheck
capabilities listed as 'setcap' arguments.

In the case, when haproxy will start and run under a non-root user this patch
doesn't change the previous behaviour: we'll still let him try the
configuration, but we inform via warning that unexpected things may occur.

Need to be backported until v2.9, including v2.9.

15 months agoDOC: configuration: grammar fixes for strict-sni
Nicolas CARPi [Wed, 3 Apr 2024 11:43:59 +0000 (13:43 +0200)] 
DOC: configuration: grammar fixes for strict-sni

Fix incorrect grammar in strict-sni:
* is allow -> is allowed
* which match -> that matches
* allows to start -> allows starting

15 months agoMINOR: listener: implement GUID support
Amaury Denoyelle [Tue, 2 Apr 2024 08:44:08 +0000 (10:44 +0200)] 
MINOR: listener: implement GUID support

This commit is similar with the two previous ones. Its purpose is to add
GUID support on listeners. Due to bind_conf and listeners configuration,
some specifities were required.

Its possible to define several listeners on a single bind line, for
example by specifying multiple addresses. As such, it's impossible to
support a "guid" keyword on a bind line. The problem is exacerbated by
the cloning of listeners when sharding is used.

To resolve this, a new keyword "guid-prefix" is defined for bind lines.
It allows to specify a string which will be used as a prefix for
automatically generated GUID for each listeners attached to a bind_conf.

Automatic GUID listeners generation is implemented via a new function
bind_generate_guid(). It is called on post-parsing, after
bind_complete_thread_setup(). For each listeners on a bind_conf, a new
GUID is generated with bind_conf prefix and the index of the listener
relative to other listeners in the bind_conf. This last value is stored
in a new bind_conf field named <guid_idx>. If a GUID cannot be inserted,
for example due to a non-unique value, an error is returned, startup is
interrupted with configuration rejected.

15 months agoMINOR: server: implement GUID support
Amaury Denoyelle [Tue, 26 Mar 2024 14:01:35 +0000 (15:01 +0100)] 
MINOR: server: implement GUID support

This commit is similar to previous one, except that it implements GUID
support for server instances. A guid_node field is inserted into server
structure. A new "guid" server keyword is defined.

15 months agoMINOR: proxy: implement GUID support
Amaury Denoyelle [Tue, 26 Mar 2024 14:26:43 +0000 (15:26 +0100)] 
MINOR: proxy: implement GUID support

Implement proxy identiciation through GUID. As such, a guid_node member
is inserted into proxy structure. A proxy keyword "guid" is defined to
allow user to fix its value.

15 months agoMINOR: guid: restrict guid format
Amaury Denoyelle [Wed, 27 Mar 2024 14:15:19 +0000 (15:15 +0100)] 
MINOR: guid: restrict guid format

GUID format is unspecified to allow users to choose the naming scheme.
Some restrictions however are added by this patch, mainly to ensure
coherence and memory usage.

The first restriction is on the length of GUID. No more than 127
characters can be used to prevent memory over consumption.

The second restriction is on the character set allowed in GUID. Utility
function invalid_char() is used for this : it allows alphanumeric
values and '-', '_', '.' and ':'.

15 months agoMINOR: guid: introduce global UID module
Amaury Denoyelle [Mon, 25 Mar 2024 10:27:23 +0000 (11:27 +0100)] 
MINOR: guid: introduce global UID module

Define a new module guid. Its purpose is to be able to attach a global
identifier for various objects such as proxies, servers and listeners.

A new type guid_node is defined. It will be stored in the objects which
can be referenced by such GUID. Several functions are implemented to
properly initialized, insert, remove and lookup GUID in a global tree.
Modification operations should only be conducted under thread isolation.

15 months agoMEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Aurelien DARRAGON [Tue, 5 Mar 2024 14:44:43 +0000 (15:44 +0100)] 
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing

Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().

Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)

Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.

Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)

15 months agoMEDIUM: log: add compiling logic to logformat expressions
Aurelien DARRAGON [Thu, 29 Feb 2024 13:54:43 +0000 (14:54 +0100)] 
MEDIUM: log: add compiling logic to logformat expressions

split parse_logformat_string() into two functions:

parse_logformat_string() sticks to the same behavior, but now becomes an
helper for lf_expr_compile() which uses explicit arguments so that it
becomes possible to use lf_expr_compile() without a proxy, but also
compile an expression which was previously prepared for compiling (set
string and config hints within the logformat expression to avoid manually
storing string and config context if the compiling step happens later).

lf_expr_dup() may be used to duplicate an expression before it is
compiled, lf_expr_xfer() now makes sure that the input logformat is
already compiled.

This is some prerequisite works for log-profiles implementation, no
functional change should be expected.

15 months agoMAJOR: log: implement proper postparsing for logformat expressions
Aurelien DARRAGON [Fri, 23 Feb 2024 16:26:32 +0000 (17:26 +0100)] 
MAJOR: log: implement proper postparsing for logformat expressions

This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.

Here's a config example that illustrates the issue:

  defaults
     mode tcp

  listen test
     bind :8888
     http-response set-header custom-hdr "%trl" # needs http
     mode http

The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:

  [ALERT]    (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.

To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:

  - split parse_logformat_string() (and subfonctions) in order to create a
    new lf_expr_postcheck() function that must be called to finish
    preparing and checking the logformat expression once the proxy type is
    known.
  - save some config hints info during parse_logformat_string() to
    generate more precise error messages during lf_expr_postcheck(), if
    needed, we rely on curpx->conf.args.{file,line} hints for that because
    parse_logformat_string() doesn't know about current file and line
    number.
  - lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
    function may try to make the proxy compatible with the expression, or
    if it should simply fail as soon as an incompatibility is detected.
  - if parse_logformat_string() is called from an unchecked proxy, then
    schedule the expression for postparsing, else (ie: during runtime),
    run the postcheck right away.

This change will also allow for some logformat expression error handling
simplifications in the future.

15 months agoMINOR: proxy: add PR_FL_CHECKED flag
Aurelien DARRAGON [Sat, 9 Mar 2024 21:18:51 +0000 (22:18 +0100)] 
MINOR: proxy: add PR_FL_CHECKED flag

PR_FL_CHECKED is set on proxy once the proxy configuration was fully
checked (including postparsing checks).

This information may be useful to functions that need to know if some
config-related proxy properties are likely to change or not due to parsing
or postparsing/check logics. Also, during runtime, except for some rare cases
config-related proxy properties are not supposed to be changed.

15 months agoMEDIUM: tree-wide: add logformat expressions wrapper
Aurelien DARRAGON [Fri, 23 Feb 2024 14:57:21 +0000 (15:57 +0100)] 
MEDIUM: tree-wide: add logformat expressions wrapper

log format expressions are broadly used within the code: once they are
parsed from input string, they are converted to a linked list of
logformat nodes.

We're starting to face some limitations because we're simply storing the
converted expression as a generic logformat_node list.

The first issue we're facing is that storing logformat expressions that
way doesn't allow us to add metadata alongside the list, which is part
of the prerequites for implementing log-profiles.

Another issue with storing logformat expressions as generic lists of
logformat_node elements is that it's starting to become really hard to
tell when we rely on logformat expressions or not in the code given that
there isn't always a comment near the list declaration or manipulation
to indicate that it's relying on logformat expressions under the hood,
so this adds some complexity for code maintenance.

This patch looks quite impressive due to changes in a lot of header and
source files (since logformat expressions are broadly used), but it does
a simple thing: it defines the lf_expr structure which itself holds a
generic list of logformat nodes, and then declares some helpers to
manipulate lf_expr elements and fixes the code so that we now exclusively
manipulate logformat_node lists as lf_expr elements outside of log.c.

For now, lf_expr struct only contains the list of logformat nodes (no
additional metadata), but now that we have dedicated type and helpers,
doing so in the future won't be problematic at all and won't require
extensive code changes.