]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
2 years agoMINOR: backend: always satisfy the first req reuse rule with l7 retries
Willy Tarreau [Thu, 1 Sep 2022 17:58:58 +0000 (19:58 +0200)] 
MINOR: backend: always satisfy the first req reuse rule with l7 retries

The "first req" rule consists in not delivering a connection's first
request to a connection that's not known for being safe so that we
don't deliver a broken page to a client if the server didn't intend to
keep it alive. That's what's used by "http-reuse safe" particularly.

But the reason this rule was created was precisely because haproxy was
not able to re-emit the request to the server in case of connection
breakage, which is precisely what l7 retries later brought. As such,
there's no reason for enforcing this rule when l7 retries are properly
enabled because such a blank page will trigger a retry and will not be
delivered to the client.

This patch simply checks that the l7 retries are enabled for the 3 cases
that can be triggered on a dead or dying connection (failure, empty, and
timeout), and if all 3 are enabled, then regular idle connections can be
reused.

This could almost be marked as a bug fix because a lot of users relying
on l7 retries do not necessarily think about using http-reuse always due
to the recommendation against it in the doc, while the protection that
the safe mode offers is never used in that mode, and it forces the http
client not to reuse existing persistent connections since it never sets
the "not first" flag.

It could also be decided that the protection is not used either when
the origin is an applet, as in this case this is internal code that
we can decide to let handle the retry by itself (all info are still
present). But at least the httpclient will be happy with this alone.

It would make sense to backport this at least to 2.6 in order to let
the httpclient reuse connections, maybe to older releases if some
users report low reuse counts.

2 years agoBUG/MEDIUM: mux-h1: always use RST to kill idle connections in pools
Willy Tarreau [Thu, 1 Sep 2022 13:49:23 +0000 (15:49 +0200)] 
BUG/MEDIUM: mux-h1: always use RST to kill idle connections in pools

When idle H1 connections cannot be stored into a server pool or are later
evicted, they're often seen closed with a FIN then an RST. The problem is
that this is sufficient to leave them in TIME_WAIT in the local sockets
table and port exhaustion may happen.

The reason is that in h1_release() we rely on h1_shutw_conn() which itself
decides whether to close in silent or normal mode only based on the
H1C_F_ST_SILENT_SHUT flag. This flag is only set by h1_shutw() based on
the requested mode. But when the connection is in the idle list, the mode
ought to always be silent.

What this patch does is to set the flag before trying to add to the idle
list, and remove it after removing from the idle list. This way if the
connection fails to be added or has to be killed, it's closed with an
RST.

This must be backported as far as 2.4. It's not sure whether older
versions need an equivalent.

2 years agoREGTESTS: http_request_buffer: Add a barrier to not mix up log messages
Christopher Faulet [Thu, 1 Sep 2022 17:46:28 +0000 (19:46 +0200)] 
REGTESTS: http_request_buffer: Add a barrier to not mix up log messages

Depending on the timing, time to time, the log messages can be mixed. A
client can start and be fully handled by HAProxy (including its log message)
before the log message of the previous client was emitted or received.  To
fix the issue, a barrier was added to be sure to eval the "expect" rule on
logs before starting the next client.

This patch should fix the issue #1847. It may be backported to all branches
containing this reg-tests.

2 years agoBUG/MINOR: regex: Properly handle PCRE2 lib compiled without JIT support
Christopher Faulet [Thu, 1 Sep 2022 17:34:00 +0000 (19:34 +0200)] 
BUG/MINOR: regex: Properly handle PCRE2 lib compiled without JIT support

The PCRE2 JIT support is buggy. If HAProxy is compiled with USE_PCRE2_JIT
option while the PCRE2 library is compiled without the JIT support, any
matching will fail because pcre2_jit_compile() return value is not properly
handled. We must fall back on pcre2_match() if PCRE2_ERROR_JIT_BADOPTION
error is returned.

This patch should fix the issue #1848. It must be backported as far as 2.4.

2 years agoMINOR: sink/ring: rotate non-empty file-backed contents only
Willy Tarreau [Wed, 31 Aug 2022 16:52:17 +0000 (18:52 +0200)] 
MINOR: sink/ring: rotate non-empty file-backed contents only

If the service is rechecked before a reload, that may cause the config
to be parsed twice and file-backed rings to be lost.

Here we make sure that such a ring does contain information before
deciding to rotate it. This way the first process starting after some
writes will cause a rotate but not subsequent ones until new writes
are applied.

An attempt was also made to disable rotations on checks but this was a
bad idea, as the ring is still initialized and this causes the contents
to be lost. The choice of initializing the ring during parsing is
questionable but the config check ought to be as close as possible to a
real start, and we could imagine that the ring is used by some code
during startup (e.g. lua). So this approach was abandonned and config
checks also cause a rotation, as the purpose of this rotation is to
preserve latest information against accidental removal.

2 years agoBUG/MINOR: ssl: leak of ckch_inst_link in ckch_inst_free() v2
William Lallemand [Wed, 31 Aug 2022 12:26:49 +0000 (14:26 +0200)] 
BUG/MINOR: ssl: leak of ckch_inst_link in ckch_inst_free() v2

ckch_inst_free() unlink the ckch_inst_link structure but never free it.

It can't be fixed simply because cli_io_handler_commit_cafile_crlfile()
is using a cafile_entry list to iterate a list of ckch_inst entries
to free. So both cli_io_handler_commit_cafile_crlfile() and
ckch_inst_free() would modify the list at the same time.

In order to let the caller manipulate the ckch_inst_link,
ckch_inst_free() now checks if the element is still attached before
trying to detach and free it.

For this trick to work, the caller need to do a LIST_DEL_INIT() during
the iteration over the ckch_inst_link.

list_for_each_entry was also replace by a while (!LIST_ISEMPTY()) on the
head list in cli_io_handler_commit_cafile_crlfile() so the iteration
works correctly, because it could have been stuck on the first detached
element. list_for_each_entry_safe() is not enough to fix the issue since
multiple element could have been removed.

Must be backported as far as 2.5.

2 years agoBUG/MINOR: quic: TX frames memleak
Frédéric Lécaille [Wed, 31 Aug 2022 13:02:53 +0000 (15:02 +0200)] 
BUG/MINOR: quic: TX frames memleak

Missing call to pool_free() for quic_frame objects

Must be backported to 2.6.

2 years agoMINOR: quic: Move traces about RX/TX bytes from QUIC_EV_CONN_PRSAFRM event
Frédéric Lécaille [Tue, 30 Aug 2022 13:25:47 +0000 (15:25 +0200)] 
MINOR: quic: Move traces about RX/TX bytes from QUIC_EV_CONN_PRSAFRM event

Move these traces to QUIC_EV_CONN_SPPKTS trace event. They were displayed
at a useless location. Make them displayed just after having sent a packet
and when checking the anti-amplication limit.
Useful to diagnose issues in relation with the recovery.

2 years agoBUILD: debug: make sure debug macros are never empty
Willy Tarreau [Wed, 31 Aug 2022 08:52:25 +0000 (10:52 +0200)] 
BUILD: debug: make sure debug macros are never empty

As outlined in commit f7ebe584d7 ("BUILD: debug: Add braces to if
statement calling only CHECK_IF()"), the BUG_ON() family of macros
is incorrectly defined to be empty when debugging is disabled, and
that can lead to trouble. Make sure they always fall back to the
usual "do { } while (0)". This may be backported to 2.6 if needed,
though no such issue was met there to date.

2 years agoBUG/MINOR: dev/udp: properly preset the rx address size
Willy Tarreau [Wed, 31 Aug 2022 06:55:12 +0000 (08:55 +0200)] 
BUG/MINOR: dev/udp: properly preset the rx address size

addrlen was not preset to sizeof(addr) on rx, resulting in the address
often not being filled and response packets not always flowing back.

Let's also consistently use "addr" in the bind call (it points to
frt_addr there but it's a bit confusing).

2 years agoBUG/MINOR: ssl: revert two wrong fixes with ckhi_link
William Lallemand [Tue, 30 Aug 2022 15:32:38 +0000 (17:32 +0200)] 
BUG/MINOR: ssl: revert two wrong fixes with ckhi_link

This reverts commit 056ad01d55675ab2d65c7b41a2e1096db27b3d14.
This reverts commit ddd480cbdc0d54b3426ce9b6dd68cd849747cb07.

The architecture is ambiguous here: ckch_inst_free() is detaching and
freeing the "ckch_inst_link" linked list which must be free'd only from
the cafile_entry side.

The problem was also hidden by the fix ddd480c ("BUG/MEDIUM: ssl: Fix a
UAF when old ckch instances are released") which change the ckchi_link
inner loop by a safe one. However this can't fix entirely the problem
since both __ckch_inst_free_locked() could remove several nodes in the
ckchi_link linked list.

This revert is voluntary reintroducing a memory leak before really fixing
the problem.

Must be backported in 2.5 + 2.6.

2 years agoBUG/MEDIUM: ssl: Fix a UAF when old ckch instances are released
Christopher Faulet [Tue, 30 Aug 2022 14:27:49 +0000 (16:27 +0200)] 
BUG/MEDIUM: ssl: Fix a UAF when old ckch instances are released

When old chck instances is released at the end of "commit ssl ca-file" or
"commit ssl crl-file" commands, the link is released. But we walk through
the list using the unsafe macro. list_for_each_entry_safe() must be used.

This bug was introduced by commit 056ad01d5 ("BUG/MINOR: ssl: leak of
ckch_inst_link in ckch_inst_free()"). Thus this patch must be backported as
far as 2.5.

2 years agoBUG/MINOR: tcpcheck: Disable QUICKACK for default tcp-check (with no rule)
Christopher Faulet [Tue, 30 Aug 2022 08:31:15 +0000 (10:31 +0200)] 
BUG/MINOR: tcpcheck: Disable QUICKACK for default tcp-check (with no rule)

The commit 871dd8211 ("BUG/MINOR: tcpcheck: Disable QUICKACK only if data
should be sent after connect") introduced a regression. It removes the test
on the next rule to be able to disable TCP_QUICKACK when only a connect is
performed (so no next rule).

This patch must be backported as far as 2.2.

2 years agoBUG/MINOR: ssl: leak of ckch_inst_link in ckch_inst_free()
William Lallemand [Mon, 29 Aug 2022 16:53:34 +0000 (18:53 +0200)] 
BUG/MINOR: ssl: leak of ckch_inst_link in ckch_inst_free()

ckch_inst_free() unlink the ckch_inst_link structure but never free it.
It can cause a memory leak upon a ckch_inst_free() done with CLI
operation.

Bug introduced by commit 4458b97 ("MEDIUM: ssl: Chain ckch instances in
ca-file entries").

Must be backported as far as 2.5.

2 years agoBUG/MINOR: ssl: fix deinit of the ca-file tree
William Lallemand [Mon, 29 Aug 2022 16:36:18 +0000 (18:36 +0200)] 
BUG/MINOR: ssl: fix deinit of the ca-file tree

Commit b0c4827 ("BUG/MINOR: ssl: free the cafile entries on deinit")
introduced a double free.

The node was never removed from the tree before its free.

Fix issue #1836.

Must be backported where b0c4827 was backported. (2.6 for now).

2 years agoMINOR: quic: Add a trace to distinguish the datagram from the packets inside
Frédéric Lécaille [Mon, 29 Aug 2022 16:05:44 +0000 (18:05 +0200)] 
MINOR: quic: Add a trace to distinguish the datagram from the packets inside

Without such a trace, we do not know when a datagram is sent. Only trace for
the packets inside the datagrams were displayed.

Must be backported to 2.6.

2 years agoBUG/MINOR: quic: Missing header protection AES cipher context initialisations (draft-v2)
Frédéric Lécaille [Mon, 29 Aug 2022 14:42:06 +0000 (16:42 +0200)] 
BUG/MINOR: quic: Missing header protection AES cipher context initialisations (draft-v2)

This bug arrived with this commit:
   "MINOR: quic: Add reusable cipher contexts for header protection"

haproxy could crash because of missing cipher contexts initializations for
the header protection and draft-v2 Initial secrets. This was due to the fact
that these initialization both for RX and TX secrets were done outside of
qc_new_isecs(). The role of this function is definitively to initialize these
cipher contexts in addition to the derived secrets. Indeed this function is called
by qc_new_conn() which initializes the connection but also by qc_conn_finalize()
which also calls qc_new_isecs() in case of a different QUIC version was negotiated
by the peers from the one used by the client for its first Initial packet.

This was reported by "v2" QUIC interop test with at least picoquic as client.

Must be backported to 2.6.

2 years agoMINOR: raw-sock: don't try to send if an error was already reported
Willy Tarreau [Mon, 29 Aug 2022 14:48:14 +0000 (16:48 +0200)] 
MINOR: raw-sock: don't try to send if an error was already reported

There's no point trying to send() on a socket on which an error was already
reported. This wastes syscalls. Till now it was possible to occasionally
see an attempt to sendto() after epoll_wait() had reported EPOLLERR.

2 years agoBUG/MINOR: epoll: do not actively poll for Rx after an error
Willy Tarreau [Mon, 29 Aug 2022 16:15:11 +0000 (18:15 +0200)] 
BUG/MINOR: epoll: do not actively poll for Rx after an error

In 2.2, commit 5d7dcc2a8 ("OPTIM: epoll: always poll for recv if neither
active nor ready") was added to compensate for the fact that our iocbs
are almost always asynchronous now and do not have the opportunity to
update the FD correctly. As such, they just perform a wakeup, the FD is
turned to inactive, the tasklet wakes up, performs the I/O, updates the
FD, most of the time this is done withing the same polling loop, and the
update cancels itself in the poller without having to switch the FD off
then on.

The issue was that when deciding to claim an FD was active for reads
if it was active for writes, we forgot one situation that unfortunately
causes excessive wakeups: dealing with errors. Indeed, errors are
reported and keep ringing as long as the FD is active for sending even
if the consumer disabled the FD for receiving. Usually this only causes
one extra wakeup for the time it takes to consider a potential write
subscriber and to call it, though with many tasks in a run queue, it
can last a bit longer and be reported more often.

The fix consists in checking that we really want to get more receive
events on this FD, that is:
  - that no prevous EPOLLERR was reported
  - that the FD doesn't carry a sticky error
  - that the FD is not shut for reads

With this, after the last epoll_wait() reports EPOLLERR, one last recv()
is performed to flush pending data and the FD is immediately unregistered.

It's probably not needed to backport this as its effects are not much
visible, though it should not harm.

Before, EPOLLERR was seen twice:

  accept4(4, {sa_family=AF_INET, sin_port=htons(22314), sin_addr=inet_addr("127.0.0.1")}, [128 => 16], SOCK_NONBLOCK) = 8
  accept4(4, 0x261b160, [128], SOCK_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
  recvfrom(8, "POST / HTTP/1.1\r\nConnection: close\r\nTransfer-encoding: chunk"..., 16320, 0, NULL, NULL) = 66
  socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 9
  connect(9, {sa_family=AF_INET, sin_port=htons(8002), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
  epoll_ctl(3, EPOLL_CTL_ADD, 8, {events=EPOLLIN|EPOLLRDHUP, data={u32=8, u64=8}}) = 0
  epoll_ctl(3, EPOLL_CTL_ADD, 9, {events=EPOLLIN|EPOLLOUT|EPOLLRDHUP, data={u32=9, u64=9}}) = 0
  epoll_wait(3, [{events=EPOLLOUT, data={u32=9, u64=9}}], 200, 355) = 1
  recvfrom(9, 0x25cfb30, 16320, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
  sendto(9, "POST / HTTP/1.1\r\ntransfer-encoding: chunked\r\n\r\n", 47, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 47
  epoll_ctl(3, EPOLL_CTL_MOD, 9, {events=EPOLLIN|EPOLLRDHUP, data={u32=9, u64=9}}) = 0
  epoll_wait(3, [{events=EPOLLIN|EPOLLERR|EPOLLHUP|EPOLLRDHUP, data={u32=9, u64=9}}], 200, 354) = 1
  recvfrom(9, "HTTP/1.1 200 OK\r\ncontent-length: 0\r\nconnection: close\r\n\r\n", 16320, 0, NULL, NULL) = 57
  sendto(8, "HTTP/1.1 200 OK\r\ncontent-length: 0\r\nconnection: close\r\n\r\n", 57, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 57
->epoll_wait(3, [{events=EPOLLIN|EPOLLERR|EPOLLHUP|EPOLLRDHUP, data={u32=9, u64=9}}], 200, 354) = 1
  epoll_ctl(3, EPOLL_CTL_DEL, 9, 0x7ffe0b65fb24) = 0
  epoll_wait(3, [{events=EPOLLIN, data={u32=8, u64=8}}], 200, 354) = 1
  recvfrom(8, "A\n0123456789\r\n0\r\n\r\n", 16320, 0, NULL, NULL) = 19
  close(9)                          = 0
  close(8)                          = 0

After, EPOLLERR is only seen only once, with one less call to epoll_wait():

  accept4(4, {sa_family=AF_INET, sin_port=htons(22362), sin_addr=inet_addr("127.0.0.1")}, [128 => 16], SOCK_NONBLOCK) = 8
  accept4(4, 0x20d0160, [128], SOCK_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
  recvfrom(8, "POST / HTTP/1.1\r\nConnection: close\r\nTransfer-encoding: chunk"..., 16320, 0, NULL, NULL) = 66
  socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 9
  connect(9, {sa_family=AF_INET, sin_port=htons(8002), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
  epoll_ctl(3, EPOLL_CTL_ADD, 8, {events=EPOLLIN|EPOLLRDHUP, data={u32=8, u64=8}}) = 0
  epoll_ctl(3, EPOLL_CTL_ADD, 9, {events=EPOLLIN|EPOLLOUT|EPOLLRDHUP, data={u32=9, u64=9}}) = 0
  epoll_wait(3, [{events=EPOLLOUT, data={u32=9, u64=9}}], 200, 411) = 1
  recvfrom(9, 0x2084b30, 16320, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
  sendto(9, "POST / HTTP/1.1\r\ntransfer-encoding: chunked\r\n\r\n", 47, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 47
  epoll_ctl(3, EPOLL_CTL_MOD, 9, {events=EPOLLIN|EPOLLRDHUP, data={u32=9, u64=9}}) = 0
  epoll_wait(3, [{events=EPOLLIN|EPOLLERR|EPOLLHUP|EPOLLRDHUP, data={u32=9, u64=9}}], 200, 411) = 1
  recvfrom(9, "HTTP/1.1 200 OK\r\ncontent-length: 0\r\nconnection: close\r\n\r\n", 16320, 0, NULL, NULL) = 57
  sendto(8, "HTTP/1.1 200 OK\r\ncontent-length: 0\r\nconnection: close\r\n\r\n", 57, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 57
  epoll_ctl(3, EPOLL_CTL_DEL, 9, 0x7ffc95d46f04) = 0
  epoll_wait(3, [{events=EPOLLIN, data={u32=8, u64=8}}], 200, 411) = 1
  recvfrom(8, "A\n0123456789\r\n0\r\n\r\n", 16320, 0, NULL, NULL) = 19
  close(9)                          = 0
  close(8)                          = 0

2 years agoBUG/MEDIUM: mux-h1: do not refrain from signaling errors after end of input
Willy Tarreau [Mon, 29 Aug 2022 08:22:56 +0000 (10:22 +0200)] 
BUG/MEDIUM: mux-h1: do not refrain from signaling errors after end of input

In 2.6-dev4, a fix for truncated response was brought with commit 99bbdbcc2
("BUG/MEDIUM: mux-h1: only turn CO_FL_ERROR to CS_FL_ERROR with empty ibuf"),
trying to address the situation where an error is present at the connection
level but some data are still pending to be read by the stream. However,
this patch did not consider the case where the stream was no longer willing
to read the pending data, resulting in a situation where some aborted
transfers could lead to excessive CPU usage by causing constant stream
wakeups for which no error was reported. This perfectly matches what was
observed and reported in github issue #1842. It's not trivial to reproduce,
but aborting HTTP/1 pipelining in the middle of transfers seems to give
good results (using h2load and Ctrl-C in the middle).

The fix was incorrct as the error should be held only if there were data
that the stream was able to read. This is the approach taken by this patch,
which also checks via SE_FL_EOI | SE_FL_EOS that the stream will be able
to consume the pending data.

Note that the loop was provoked by the attempt by sc_conn_io_cb() itself
to call sc_conn_send() which resulted in a write subscription in
h1_subscribe() which immediately calls a tasklet_wakeup() since the
event is ready, and that it is now stopped by the presence of SE_FL_ERROR
that is checked in sc_conn_io_cb(). It seems that an extra check down the
send() path to refrain from subscribing when the connection is in error
could speed up error detection or at least avoid a risk of loops in this
case, but this is tricky. In addition, there's already SE_FL_ERR_PENDING
that seems more suitable for reporting when there are pending data, but
similarly, it probably isn't checked well enough to be suitable for
backports.

FWIW the issue may (unreliably) be reproduced by chaining haproxy to
httpterm and issuing:

  (printf "GET /?s=10g HTTP/1.1\r\n\r\n"; sleep 0.1; printf "\r\n") | \
    nc6 --half-close 0 8001 | head -c1000000000 >/dev/null

It's necessary to play with the size of the head command that's supposed
to trigger the error at some point. A variant involving h2load in h1 mode
and multiple pipelined streams, that is stopped with Ctrl-C also tends to
work.

As the fix above was backported as far as 2.0, it would be tempting to
backport this one as far. However tests have shown that the oldest
version that can trigger this issue is 2.5, maybe due to subtle
differences in older ones, so it's probably not worth going further
until an issue is reported. Note that in 2.5 and older, the SE_FL_*
flags are applied on the conn_stream instead, as CS_FL_*.

Special thanks go to Felipe W Damasio for providing lots of detailed data
allowing to quickly spot the root cause of the problem.

2 years agoBUG/MINOR: hlua: Rely on CF_EOI to detect end of message in HTTP applets
Christopher Faulet [Mon, 29 Aug 2022 13:37:16 +0000 (15:37 +0200)] 
BUG/MINOR: hlua: Rely on CF_EOI to detect end of message in HTTP applets

applet:getline() and applet:receive() functions for HTTP applets must rely
on the channel flags to detect the end of the message and not on HTX
flags. It means CF_EOI must be used instead of HTX_FL_EOM.

It is important because the HTX flag is transient. Because there is no flag
on HTTP applets to save the info, it is not reliable. However CF_EOI once
set is never removed. So it is safer to rely on it. Otherwise, the call to
these functions hang.

This patch must be backported as far as 2.4.

2 years agoBUG/MEDIUM: peers: Don't start resync on reload if local peer is not up-to-date
Christopher Faulet [Fri, 26 Aug 2022 16:46:16 +0000 (18:46 +0200)] 
BUG/MEDIUM: peers: Don't start resync on reload if local peer is not up-to-date

On a reload, if the previous resync was not finished, the freshly old worker
must not try to start a new resync. Otherwise, it will compete with the
older wokers, slowing down or blocking the resync. Only an up-to-date woker
must try to perform a local resync.

This patch must be backported as far as 2.0 (and maybe to 1.8 too).

2 years agoBUG/MEDIUM: peers: Don't use resync timer when local resync is in progress
Christopher Faulet [Fri, 26 Aug 2022 16:40:46 +0000 (18:40 +0200)] 
BUG/MEDIUM: peers: Don't use resync timer when local resync is in progress

When a worker is stopped, the resync timer is used to limit in time the
connection stage to the new worker to perform the local resync. However,
this timer must be stopped when the resync is in progress and it must be
re-armed if the resync is interrupted (for instance because another
reload). Otherwise, if the resync is a bit long, an old worker may be killed
too early.

This bug was introduce by the commit 160fff665 ("BUG/MEDIUM: peers: limit
reconnect attempts of the old process on reload"). It must be backported as
far as 2.0.

2 years agoBUG/MEDIUM: peers: Add connect and server timeut to peers proxy
Christopher Faulet [Mon, 29 Aug 2022 09:32:26 +0000 (11:32 +0200)] 
BUG/MEDIUM: peers: Add connect and server timeut to peers proxy

Only the client timeout was set. Nothing prevent a peer applet to stall
during a connect or waiting a message from a remote peer. To avoid any
issue, it is important to also set connection and server timeouts. The
connect timeout is set to 1s and the server timeout is set to 5s.

This patch must be backported to all supported versions.

2 years agoBUG/MEDIUM: spoe: Properly update streams waiting for a ACK in async mode
Christopher Faulet [Thu, 25 Aug 2022 16:50:18 +0000 (18:50 +0200)] 
BUG/MEDIUM: spoe: Properly update streams waiting for a ACK in async mode

A bug was introduced by the commit b042e4f6f ("BUG/MAJOR: spoe: properly
detach all agents when releasing the applet"). The fix is not correct. We
really want to known if the released appctx is the last one or not. It is
important when async mode is used. If there are still running applets, we
just need to remove the reference on the current applet from streams in the
async waiting queue.

With the commit above, in async mode, if there are still running applets, it
will work as expected. Otherwise a processing timeout will be reported for
all these streams. So it is not too bad. But for other modes (sync and
pipelining), the async waiting queue is always empty. If at least one stream
is waiting to send a message, a new applet is created. It is an issue if the
SPOA is unhealthy because the number of running applets may explode.

However, the commit above tried to fix an issue. The bug is in fact when an
new SPOE applet is created. On success, we must remove reference on the
current appctx from the streams in the async waiting queue.

This patch must be backported as far as 1.8.

2 years agoBUG/MINOR: quic: Frames added to packets even if not built.
Frédéric Lécaille [Sat, 27 Aug 2022 13:51:30 +0000 (15:51 +0200)] 
BUG/MINOR: quic: Frames added to packets even if not built.

Several frames could remain as not build into <frm_list> built by qc_build_frms()
after having stopped at the first building error. So only one frame was reinserted in
the frame list passed as parameter to qc_do_build_pkt(). Then <frm_list> was
spliced to the packet frame list even its frames were not built, nor attached to
any packet. Such frames had their ->pkt member set to NULL, but considered as
built, then sent leading to a crash in qc_release_frm() where ->pkt is dereferenced.

This issue was again reported by useful traces provided by Tristan in GH #1808.

Must be backported to 2.6.

2 years agoBUG/MINOR: quic: Null packet dereferencing from qc_dup_pkt_frms() trace
Frédéric Lécaille [Sat, 27 Aug 2022 08:19:42 +0000 (10:19 +0200)] 
BUG/MINOR: quic: Null packet dereferencing from qc_dup_pkt_frms() trace

This function must duplicate frames be resent from packets. Some of
them are still in flight, others have already been detected as lost.
In this case the original frame ->pkt member is NULL.
Add a trace to distinguish these cases.

Thank you to Tristan for having reported this issue in GH #1808.

Must be backported to 2.6.

2 years agoDOC: configuration.txt: do-resolve must use host_only to remove its port.
William Lallemand [Fri, 26 Aug 2022 14:48:07 +0000 (16:48 +0200)] 
DOC: configuration.txt: do-resolve must use host_only to remove its port.

The do-resolve action does not support a port in its parameter string,
the host_only converter must be used.

Must be backported to 2.6.

2 years agoBUG/MINOR: httpclient: fix resolution with port
William Lallemand [Fri, 26 Aug 2022 14:45:13 +0000 (16:45 +0200)] 
BUG/MINOR: httpclient: fix resolution with port

Fix the resolution in the httpclient when a port is associated to a
domain. The do-resolve action doesn't support a port in its input.

Must be backported to 2.6. Require the "host_only" converter to be
backported.

2 years agoMINOR: sample: add the host_only and port_only converters
William Lallemand [Fri, 26 Aug 2022 14:21:28 +0000 (16:21 +0200)] 
MINOR: sample: add the host_only and port_only converters

Add 2 converters that can manipulate the value of an Host header.
host_only will return the host without any port, and port_only will
return the port.

2 years agoDOC: configuration: do-resolve doesn't work with a port in the string
William Lallemand [Fri, 26 Aug 2022 14:38:43 +0000 (16:38 +0200)] 
DOC: configuration: do-resolve doesn't work with a port in the string

Fix the documentation about do-resolve to handle the case where a port
is associated to the hostname in the Host header.

Must be backported as far as 2.0.

2 years agoRevert "MINOR: quic: Remove useless traces about references to TX packets"
Frédéric Lécaille [Thu, 25 Aug 2022 14:06:48 +0000 (16:06 +0200)] 
Revert "MINOR: quic: Remove useless traces about references to TX packets"

This reverts commit f61398a7caa35d780639a5961d2b1ea427f710b6.
After having checked a version with more traces and reproduced the issue
as reported by Tristan in GH #1808, there are remaining cases where
a duplicated but not already sent frame have to be marked as acked because
the frame it was copied from was acknowledeged before its copied was sent.

Must be backported to 2.6.

2 years agoMINOR: quic: Remove useless traces about references to TX packets
Frédéric Lécaille [Thu, 25 Aug 2022 05:13:33 +0000 (07:13 +0200)] 
MINOR: quic: Remove useless traces about references to TX packets

Since this commit:
    "BUG/MINOR: quic: Wrong list_for_each_entry() use when building packets from
     qc_do_build_pkt()"
there is no more reason that frames can be released without having been
sent, i.e. frames with non null ->pkt member. This ->pkt is the packet
the frame is attached to.

Must be backported to 2.6.

2 years agoCLEANUP: quic: Remove a useless check in qc_lstnr_pkt_rcv()
Frédéric Lécaille [Wed, 24 Aug 2022 16:59:23 +0000 (18:59 +0200)] 
CLEANUP: quic: Remove a useless check in qc_lstnr_pkt_rcv()

This function parses the QUIC packet from a UDP datagram. It was originally
supposed to be run by several thread. Here we remove a section of code
where the current thread checks there is not another thread which has already
inserted the new quic_conn it is trying to insert in the connections tree.

Must be backported to 2.6 to ease the future backports to come.

2 years agoCLEANUP: quic: No more use ->rx_list MT_LIST entry point (quic_rx_packet)
Frédéric Lécaille [Wed, 24 Aug 2022 16:17:13 +0000 (18:17 +0200)] 
CLEANUP: quic: No more use ->rx_list MT_LIST entry point (quic_rx_packet)

This quic_rx_packet is definitively no more used.

Should be backported to 2.6 to ease the future backports.

2 years agoBUG/MINOR: quic: Stalled connections (missing I/O handler wakeup)
Frédéric Lécaille [Wed, 24 Aug 2022 15:57:09 +0000 (17:57 +0200)] 
BUG/MINOR: quic: Stalled connections (missing I/O handler wakeup)

This was due to a missing I/O handler tasklet wakeup in process_timer() when
detecting packet loss. As, qc_release_lost_pkts() could remove the lost packets
from the in flight packets count, qc_set_timer() could cancel the timer used
to wakeup the connection I/O handler. Then the connection could remain idle
until it ends.

Must be backported to 2.6.

2 years agoBUG/MINOR: quic: Leak in qc_release_lost_pkts() for non in flight TX packets
Frédéric Lécaille [Wed, 24 Aug 2022 15:06:04 +0000 (17:06 +0200)] 
BUG/MINOR: quic: Leak in qc_release_lost_pkts() for non in flight TX packets

Packets with null "in flight" lengths are kept as the others packets as sent
but not already acknowledeged in the by packet number space trees.
But qc_release_lost_pkts() relied on this in fligh length to release the
memory allocated for this packets. We must release the memory allocated for
all the lost packets regardless of their in fligh lengths.

Modify this function to do nothing if the list of lost packets passed
as argument is empty. Stop using <lost_bytes> variable to decide if some packets
memory must be released or not.
Modify the callers to stop checking if this list is empty.

Should helping in fixing memory leak as reported by Tristan in GH #1801.

Must be backported to 2.6.

2 years agoRevert "BUG/MINOR: quix: Memleak for non in flight TX packets"
Frédéric Lécaille [Wed, 24 Aug 2022 14:23:44 +0000 (16:23 +0200)] 
Revert "BUG/MINOR: quix: Memleak for non in flight TX packets"

This reverts commit da9c441886dbfa02840a93e367f65fd6d312c835.

Indeed this commit prevented the ACK only packets to be used as other packets
when they are acknowledged. Even if not ack-eliciting packets they are
acknowledged alongside others packets. Such acknowledged ACK only packets
must be used for instance to compute the RTT.

Must be backported to 2.6 if da9c441 was backported to 2.6.

2 years agoMINOR: resolvers: shut the warning when "default" resolvers is implicit
William Lallemand [Wed, 24 Aug 2022 12:50:32 +0000 (14:50 +0200)] 
MINOR: resolvers: shut the warning when "default" resolvers is implicit

Shut the connect() warning of resolvers_finalize_config() when the
configuration was not emitted manually.

This shuts the warning for the "default" resolvers which is created
automatically for the httpclient.

Must be backported in 2.6.

2 years agoREGTESTS: Fix prometheus script to perform HTTP health-checks
Christopher Faulet [Wed, 24 Aug 2022 10:17:31 +0000 (12:17 +0200)] 
REGTESTS: Fix prometheus script to perform HTTP health-checks

TCP Health-checks are enabled on server "s2". However it expects to receive
an HTTP requests. So HAProxy configuration must be changed to perform HTTP
health-checks instead. Otherwise, depending on the timing, an error can be
triggered if a check is performed before the end of the script.

This scripts never failed because TCP_QUICKACK was disabled, adding some
latency on health-checks. But since the last fix, it is an issue.

This patch should be backported as far as 2.4.

2 years agoBUG/MINOR: tcpcheck: Disable QUICKACK only if data should be sent after connect
Christopher Faulet [Wed, 24 Aug 2022 09:38:03 +0000 (11:38 +0200)] 
BUG/MINOR: tcpcheck: Disable QUICKACK only if data should be sent after connect

It is only a real problem for agent-checks when there is no agent string to
send. The condition to disable TCP_QUICKACK was only based on the action
type following the connect one. But it is not always accurate. indeed, for
agent-checks, there is always a SEND action. But if there is no "agent-send"
string defined, nothing is sent. In this case, this adds 200ms of latency
with no reason.

To fix the bug, a flag is now used on the CONNECT action to instruct there
are data that should be sent after the connect. For health-checks, this flag
is set if the action following the connect is a SEND action. For
agent-checks, it is set if an "agent-send" string is defined.

This patch should fix the issue #1836. It must be backported as far as 2.2.

2 years agoBUG/MINOR: mworker: does not create the "default" resolvers in wait mode
William Lallemand [Wed, 24 Aug 2022 09:15:08 +0000 (11:15 +0200)] 
BUG/MINOR: mworker: does not create the "default" resolvers in wait mode

When doing a re-exec, the master was creating a "default" resolvers,
which could result in a warning emitted because the "default" resolvers
of the configuration file is not available anymore.

Skip the creating of the "default" resolvers in wait mode, this is not
useful in the master.

Must be backported as far as 2.6.

2 years agoBUG/MINOR: resolvers: return the correct value in resolvers_finalize_config()
William Lallemand [Wed, 24 Aug 2022 07:58:31 +0000 (09:58 +0200)] 
BUG/MINOR: resolvers: return the correct value in resolvers_finalize_config()

Patch c31577f ("MEDIUM: resolvers: continue startup if network is
unavailable") was not working correctly. Indeed
resolvers_finalize_config() was returning a ERR type, but a postparser
is supposed to return 0 or 1.

The return value was never right, however it was only a problem since c31577f.

Must be backported in every stable branch.

2 years agoBUILD: tcp_sample: fix build of get_tcp_info() on OpenBSD
Brad Smith [Sat, 13 Aug 2022 02:23:13 +0000 (22:23 -0400)] 
BUILD: tcp_sample: fix build of get_tcp_info() on OpenBSD

The build on OpenBSD is broken since commit 5c83e3a15 ("MINOR: tcp_sample:
clarifying samples support per os, for further expansion."), hence it
only affects 2.7 and 2.6.

It looks like this changed things in such a way that if TCP_INFO is added
but the OS is not added to the list of OS's it will not build.

Extend support for get_tcp_info to OpenBSD.

This must be backported to 2.6.

2 years agoMEDIUM: peers: limit the number of updates sent at once
Willy Tarreau [Tue, 19 Jul 2022 18:17:38 +0000 (20:17 +0200)] 
MEDIUM: peers: limit the number of updates sent at once

As seen in GH issue #1770, peers synchronization do not cope well with
very large buffers because by default the only two reasons for stopping
the processing of updates is either that the end was reached or that
the buffer is full. This can cause high latencies, and even rightfully
trigger the watchdog when the operations are numerous and slowed down
by competition on the stick-table lock.

This patch introduces a limit to the number of messages one may send
at once, which now defaults to 200, regardless of the buffer size. This
means taking and releasing the lock up to 400 times in a row, which is
costly enough to let some other parts work.

After some observation this could be backported to 2.6. If so, however,
previous commits "BUG/MEDIUM: applet: fix incorrect check for abnormal
return condition from handler" and "BUG/MINOR: applet: make the call_rate
only count the no-progress calls" must be backported otherwise the call
rate might trigger the looping protection.

2 years agoBUG/MINOR: applet: make the call_rate only count the no-progress calls
Willy Tarreau [Tue, 19 Jul 2022 18:36:15 +0000 (20:36 +0200)] 
BUG/MINOR: applet: make the call_rate only count the no-progress calls

This is very similar to what we did in commit 6c539c4b8 ("BUG/MINOR:
stream: make the call_rate only count the no-progress calls"), it's
better to only count the call rate with no progress than to count all
calls and try to figure if there's no progress, because a fast running
applet might once satisfy the whole condition and trigger the bug. This
typically happens when artificially limiting the number of messages sent
at once by an applet, but could happen with plenty of highly interactive
applets.

This patch could be backported to stable versions if there are any
indications that it might be useful there.

2 years agoBUG/MEDIUM: applet: fix incorrect check for abnormal return condition from handler
Willy Tarreau [Tue, 23 Aug 2022 07:01:30 +0000 (09:01 +0200)] 
BUG/MEDIUM: applet: fix incorrect check for abnormal return condition from handler

We have quite numerous checks for abnormal applet handler behavior which
are supposed to trigger the loop protection. However, consecutive to
commit 15252cd9c ("MEDIUM: stconn: move the RXBLK flags to the stream
connector") that was merged into 2.6-dev12, one flag was incorrectly
renamed, and the check for an applet waiting for a buffer that is present
mistakenly turned to a check for missing room in the buffer. This erroneous
test could mistakenly trigger on applets that perform intensive I/Os doing
small exchanges each (e.g. cache, peers or HTTP client) if the load would
be sustained (>100k iops). For the cache this could represent higher than
13 Gbps on an object at least 1.6 GB large for example, which is quite
unlikely but theoretically possible.

This fix needs to be backported to 2.6.

2 years agoMINOR: quic: Replace MT_LISTs by LISTs for RX packets.
Frédéric Lécaille [Tue, 23 Aug 2022 15:45:52 +0000 (17:45 +0200)] 
MINOR: quic: Replace MT_LISTs by LISTs for RX packets.

Replace ->rx.pqpkts quic_enc_level struct member MT_LIST by an LIST.
Same thing for ->list quic_rx_packet struct member MT_LIST.
Update the code consequently. This was a reminisence of the multithreading
support (several threads by connection).

Must be backported to 2.6

2 years agoBUG/MINOR: quic: Safer QUIC frame builders
Frédéric Lécaille [Tue, 23 Aug 2022 15:40:09 +0000 (17:40 +0200)] 
BUG/MINOR: quic: Safer QUIC frame builders

Do not rely on the fact the callers of qc_build_frm() handle their
buffer passed to function the correct way (without leaving garbage).
Make qc_build_frm() update the buffer passed as argument only if
the frame it builds is well formed.

As far as I sse, there is no such callers which does not handle
carefully such buffers.

Must be backported to 2.6.

2 years agoBUG/MINOR: quic: Wrong list_for_each_entry() use when building packets from qc_do_bui...
Frédéric Lécaille [Tue, 23 Aug 2022 09:42:48 +0000 (11:42 +0200)] 
BUG/MINOR: quic: Wrong list_for_each_entry() use when building packets from qc_do_build_pkt()

This is list_for_each_entry_safe() which must be used if we want to delete elements
inside its code block. This could explain that some frames which were not built were added
to packets with a NULL ->pkt member.

Thank you to Tristan for having reported this issue through backtraces in GH #1808

Must be backported to 2.6.

2 years agoBUG/MINOR: quix: Memleak for non in flight TX packets
Frédéric Lécaille [Mon, 22 Aug 2022 16:47:51 +0000 (18:47 +0200)] 
BUG/MINOR: quix: Memleak for non in flight TX packets

First, these packets must not be inserted in the tree of TX packets.
They are never explicitely acknowledged (for instance an ACK only
packet will never be acknowledged). Furthermore, if taken into an account
these packets may uselessly disturb the congestion control. We do not care
if they are lost or not. Furthermore as the ->in_fligh_len member value is null
they were not released by qc_release_lost_pkts() which rely on these values
to decide to release the allocated memory for such packets.

Must be backported to 2.6.

2 years agoREGTESTS: launch http_reuse_always in mworker mode
William Lallemand [Mon, 22 Aug 2022 10:59:50 +0000 (12:59 +0200)] 
REGTESTS: launch http_reuse_always in mworker mode

We don't have enough tests with the mworker mode, and even less that
have no master CLI (-S) configured. Let's run this one with -W, it
shouldn't have any impact.

VTest won't be able to catch a lot of things for now, but that's a first
step.

2 years agoBUG/MAJOR: mworker: fix infinite loop on master with no proxies.
Emeric Brun [Mon, 22 Aug 2022 08:25:11 +0000 (10:25 +0200)] 
BUG/MAJOR: mworker: fix infinite loop on master with no proxies.

The master is re-exec with an empty proxies list if no master CLI is
configured.

This results in infinite loop since last patch:
3b68b602 ("BUG/MAJOR: log-forward: Fix log-forward proxies not fully initialized")

This patch avoid to loop again on log-forward proxies list if empty.

This patch should be backported until v2.3

2 years agoMINOR: cpu-map: remove obsolete diag warning about combined ranges
Willy Tarreau [Mon, 22 Aug 2022 08:46:13 +0000 (10:46 +0200)] 
MINOR: cpu-map: remove obsolete diag warning about combined ranges

We used to emit a diag warning in case ranges were used both with the
process and thread part of a thread spec. Now with groups it's not
longer a problem, so let's just kill this warning.

2 years agoBUG/MEDIUM: cpu-map: fix thread 1's affinity affecting all threads
Willy Tarreau [Mon, 22 Aug 2022 08:38:00 +0000 (10:38 +0200)] 
BUG/MEDIUM: cpu-map: fix thread 1's affinity affecting all threads

Since 2.7-dev2 with commit 5b09341c02 ("MEDIUM: cpu-map: replace the
process number with the thread group number"), the thread group has
replaced the process number in the "cpu-map" directive. In part due to
a design limit in 2.4 and 2.5, a special case was made of thread 1 in
commit bda7c1decd ("MEDIUM: config: simplify cpu-map handling"), because
there was no other location to store a single-threaded setup's mask by
then. The combination of the two resulted in a problem with thread
groups, by which as soon as one line exhibiting thread number 1 alone
was found in a config, the mask would be applied to all threads in the
group.

The loop was reworked to avoid this obsolete special case, and was
factored for better legibility. One obsolete comment about nbproc
was also removed. No backport is needed.

2 years agoBUG/MINOR: mux-quic: Fix memleak on QUIC stream buffer for unacknowledged data
Frédéric Lécaille [Sat, 20 Aug 2022 16:59:36 +0000 (18:59 +0200)] 
BUG/MINOR: mux-quic: Fix memleak on QUIC stream buffer for unacknowledged data

Some clients send CONNECTION_CLOSE frame without acknowledging the STREAM
data haproxy has sent. In this case, when closing the connection if
there were remaining data in QUIC stream buffers, they were not released.

Add a <closing> boolean option to qc_stream_desc_free() to force the
stream buffer memory releasing upon closing connection.

Thank you to Tristan for having reported such a memory leak issue in GH #1801.

Must be backported to 2.6.

2 years ago[RELEASE] Released version 2.7-dev4 v2.7-dev4
Willy Tarreau [Sat, 20 Aug 2022 13:56:31 +0000 (15:56 +0200)] 
[RELEASE] Released version 2.7-dev4

Released version 2.7-dev4 with the following main changes :
    - BUG/MEDIUM: quic: Wrong packet length check in qc_do_rm_hp()
    - MINOR: quic: Too much useless traces in qc_build_frms()
    - BUG/MEDIUM: quic: Missing AEAD TAG check after removing header protection
    - MINOR: quic: Replace pool_zalloc() by pool_malloc() for fake datagrams
    - MINOR: debug: make the mem_stats section aligned to void*
    - MINOR: debug: store and report the pool's name in struct mem_stats
    - MINOR: debug: also store the function name in struct mem_stats
    - MINOR: debug/memstats: automatically determine first column size
    - MINOR: debug/memstats: permit to pass the size to free()
    - CLEANUP: mux-quic: remove loop on sending frames
    - MINOR: quic: replace custom buf on Tx by default struct buffer
    - MINOR: quic: release Tx buffer on each send
    - MINOR: quic: refactor datagram commit in Tx buffer
    - MINOR: quic: skip sending if no frame to send in io-cb
    - BUG/MINOR: mux-quic: open stream on STOP_SENDING
    - BUG/MINOR: quic: fix crash on handshake io-cb for null next enc level
    - BUG/MEDIUM: quic: always remove the connection from the accept list on close
    - BUG/MEDIUM: poller: use fd_delete() to release the poller pipes
    - BUG/MEDIUM: task: relax one thread consistency check in task_unlink_wq()
    - MEDIUM: quic: xprt traces rework
    - BUILD: stconn: fix build warning at -O3 about possible null sc
    - MINOR: quic: Remove useless lock for RX packets
    - BUG/MINOR: quic: Possible infinite loop in quic_build_post_handshake_frames()
    - CLEANUP: quic: Remove trailing spaces
    - MINOR: mux-quic: adjust enter/leave traces
    - MINOR: mux-quic: define protocol error traces
    - CLEANUP: mux-quic: adjust traces level
    - MINOR: mux-quic: define new traces
    - BUG/MEDIUM: mux-quic: fix crash due to invalid trace arg
    - BUG/MEDIUM: quic: Possible use of uninitialized <odcid> variable in qc_lstnr_params_init()
    - BUG/MEDIUM: ring: fix too lax 'size' parser
    - BUG/MEDIUM: quic: Wrong use of <token_odcid> in qc_lsntr_pkt_rcv()
    - BUILD: ring: forward-declare struct appctx to avoid a build warning
    - MINOR: ring: support creating a ring from a linear area
    - MINOR: ring: add support for a backing-file
    - DEV: haring: add a simple utility to read file-backed rings
    - DEV: haring: support remapping LF in contents with CR VT
    - BUG/MINOR: quic: memleak on wrong datagram receipt
    - BUILD: sink: replace S_IRUSR, S_IWUSR with their octal value
    - MINOR: ring: archive a previous file-backed ring on startup
    - BUG/MINOR: mux-quic: fix crash with traces in qc_detach()
    - BUG/MINOR: quic: MIssing check when building TX packets
    - BUG/MINOR: quic: Wrong status returned by qc_pkt_decrypt()
    - MINOR: memprof: export the minimum definitions for memory profiling
    - MINOR: pool/memprof: report pool alloc/free in memory profiling
    - MINOR: pools/memprof: store and report the pool's name in each bin
    - MINOR: chunk: inline alloc_trash_chunk()
    - MINOR: stick-table: Add table_expire() and table_idle() new converters
    - CLEANUP: exclude haring with .gitignore
    - MINOR: quic: adjust quic_frame flag manipulation
    - MINOR: h3: report error on control stream close
    - MINOR: qpack: report error on enc/dec stream close
    - BUG/MEDIUM: mux-quic: reject uni stream ID exceeding flow control
    - MINOR: mux-quic: adjust traces on stream init
    - MINOR: mux-quic: add missing args on some traces
    - MINOR: quic: refactor application send
    - BUG/MINOR: quic: do not notify MUX on frame retransmit
    - BUG/MEDIUM: http-ana: fix crash or wrong header deletion by http-restrict-req-hdr-names
    - BUG/MINOR: quic: Missing initializations for ducplicated frames.
    - BUG/MEDIUM: quic: fix crash on MUX send notification
    - REORG: h2: extract cookies concat function in http_htx
    - REGTESTS: add test for HTTP/2 cookies concatenation
    - MEDIUM: h3: concatenate multiple cookie headers
    - MINOR: applet: add a function to reset the svcctx of an applet
    - BUG/MEDIUM: cli: always reset the service context between commands
    - BUG/MEDIUM: mux-h2: do not fiddle with ->dsi to indicate demux is idle
    - MINOR: mux-h2/traces: report transition to SETTINGS1 before not after
    - MINOR: mux-h2: make streams know if they need to send more data
    - BUG/MINOR: mux-h2: send a CANCEL instead of ES on truncated writes
    - BUG/MINOR: quic: Possible crashes when dereferencing ->pkt quic_frame struct member
    - MINOR: quic: Add frame addresses to QUIC_EV_CONN_PRSAFRM event traces
    - BUG/MINOR: quic: Wrong splitted duplicated frames handling
    - MINOR: quic: Add the QUIC connection to mux traces
    - MINOR: quic: Trace fix in qc_release_frm()
    - BUG/MAJOR: log-forward: Fix log-forward proxies not fully initialized
    - BUG/MAJOR: log-forward: Fix ssl layer not initialized on bind even if configured
    - MINOR: quic: Add reusable cipher contexts for header protection
    - BUG/MINOR: ssl/cli: error when the ca-file is empty
    - MINOR: ssl: handle ca-file appending in cafile_entry
    - MINOR: ssl/cli: implement "add ssl ca-file"

2 years agoMINOR: ssl/cli: implement "add ssl ca-file"
William Lallemand [Fri, 29 Jul 2022 15:50:58 +0000 (17:50 +0200)] 
MINOR: ssl/cli: implement "add ssl ca-file"

In ticket #1805 an user is impacted by the limitation of size of the CLI
buffer when updating a ca-file.

This patch allows a user to append new certificates to a ca-file instead
of trying to put them all with "set ssl ca-file"

The implementation use a new function ssl_store_dup_cafile_entry() which
duplicates a cafile_entry and its X509_STORE.

ssl_store_load_ca_from_buf() was modified to take an apped parameter so
we could share the function for "set" and "add".

2 years agoMINOR: ssl: handle ca-file appending in cafile_entry
William Lallemand [Fri, 29 Jul 2022 15:08:02 +0000 (17:08 +0200)] 
MINOR: ssl: handle ca-file appending in cafile_entry

In order to be able to append new CA in a cafile_entry,
ssl_store_load_ca_from_buf() was reworked and a "append" parameter was
added.

The function is able to keep the previous X509_STORE which was already
present in the cafile_entry.

2 years agoBUG/MINOR: ssl/cli: error when the ca-file is empty
William Lallemand [Thu, 18 Aug 2022 13:53:02 +0000 (15:53 +0200)] 
BUG/MINOR: ssl/cli: error when the ca-file is empty

"set ssl ca-file" does not return any error when a ca-file is empty or
only contains comments. This could be a problem is the file was
malformated and did not contain any PEM header.

It must be backported as far as 2.5.

2 years agoMINOR: quic: Add reusable cipher contexts for header protection
Frédéric Lécaille [Fri, 19 Aug 2022 16:18:13 +0000 (18:18 +0200)] 
MINOR: quic: Add reusable cipher contexts for header protection

Implement quic_tls_rx_hp_ctx_init() and quic_tls_tx_hp_ctx_init() to initiliaze
such header protection cipher contexts for each RX and TX parts and for each
packet number spaces, only one time by connection.
Make qc_new_isecs() call these two functions to initialize the cipher contexts
of the Initial secrets. Same thing for ha_quic_set_encryption_secrets() to
initialize the cipher contexts of the subsequent derived secrets (ORTT, 1RTT,
Handshake).
Modify qc_do_rm_hp() and quic_apply_header_protection() to reuse these
cipher contexts.
Note that there is no need to modify the key update for the header protection.
The header protection secrets are never updated.

2 years agoBUG/MAJOR: log-forward: Fix ssl layer not initialized on bind even if configured
Emeric Brun [Fri, 19 Aug 2022 13:16:26 +0000 (15:16 +0200)] 
BUG/MAJOR: log-forward: Fix ssl layer not initialized on bind even if configured

Since commit 2071a99df ("MINOR: listener/ssl: set the SSL xprt layer only
once the whole config is known") the xprt is initialized for ssl directly
from a generic funtion used to parse bind args.

But the 'bind' lines from 'log-forward' sections were forgotten in commit
55f0f7bb5 ("MINOR: config: use the new bind_parse_args_list() to parse a
"bind" line").

This patch re-works 'log-forward' section parsing to use the generic
function to parse bind args and fix the issue.

Since the generic way to parse was introduced in 2.6, this patch
should be backported as far as this version.

2 years agoBUG/MAJOR: log-forward: Fix log-forward proxies not fully initialized
Emeric Brun [Thu, 18 Aug 2022 13:53:21 +0000 (15:53 +0200)] 
BUG/MAJOR: log-forward: Fix log-forward proxies not fully initialized

Some initialisation for log forward proxies was missing such
as ssl configuration on 'log-forward's 'bind' lines.

After the loop on the proxy initialization code for proxies present
in the main proxies list, this patch force to loop again on this code
for proxies present in the log forward proxies list.

Those two lists should be merged. This will be part of a global
re-work of proxy initialization including peers proxies and resolver
proxies.

This patch was made in first attempt to fix the bug and to facilitate
the backport on older branches waiting for a cleaner re-work on proxies
initialization on the dev branch.

This patch should be backported as far as 2.3.

2 years agoMINOR: quic: Trace fix in qc_release_frm()
Frédéric Lécaille [Fri, 19 Aug 2022 10:08:13 +0000 (12:08 +0200)] 
MINOR: quic: Trace fix in qc_release_frm()

This wrong trace came with this commit:
  "BUG/MINOR: quic: Possible crashes when dereferencing ->pkt quic_frame struct member"
In qc_release_frm() we mark frames as acked. Nothing to see with references
to frames.

Thank you to Willy for having caught this one.

Must be backported to 2.6 as these traces arrived with a bug fix to be backported
to 2.6.

2 years agoMINOR: quic: Add the QUIC connection to mux traces
Frédéric Lécaille [Fri, 19 Aug 2022 10:02:29 +0000 (12:02 +0200)] 
MINOR: quic: Add the QUIC connection to mux traces

This should help for debugging purpose.

Should be backported to 2.6

2 years agoBUG/MINOR: quic: Wrong splitted duplicated frames handling
Frédéric Lécaille [Fri, 19 Aug 2022 07:32:14 +0000 (09:32 +0200)] 
BUG/MINOR: quic: Wrong splitted duplicated frames handling

When duplicated frames are splitted, we must propagate this information
to the new allocated frame and add a reference to this new frame
to the reference list of the original frame.

Must be backported to 2.6

2 years agoMINOR: quic: Add frame addresses to QUIC_EV_CONN_PRSAFRM event traces
Frédéric Lécaille [Fri, 19 Aug 2022 07:23:15 +0000 (09:23 +0200)] 
MINOR: quic: Add frame addresses to QUIC_EV_CONN_PRSAFRM event traces

This should be useful to diagnose some issues.

Should be backported to 2.6.

2 years agoBUG/MINOR: quic: Possible crashes when dereferencing ->pkt quic_frame struct member
Frédéric Lécaille [Thu, 18 Aug 2022 15:21:19 +0000 (17:21 +0200)] 
BUG/MINOR: quic: Possible crashes when dereferencing ->pkt quic_frame struct member

This was done at several places. First in qc_requeue_nacked_pkt_tx_frms.
This aim of this function is, if needed, to requeue all the TX frames of a lost
<pkt> packet passed as argument and detach them from this packet they have been
sent from. They are possible cases where the frm->pkt quic_frame struct member could
be NULL, as a result of a duplication of an original frame by qc_dup_pkt_frms(). This
function adds the duplicated frame to the original frame reference list:
        LIST_APPEND(&origin->reflist, &dup_frm->ref);
But, in this function, the packet which contains the frame is the one which is passed
as argument (for debug purpose). So let us prefer using this variable.
Also do not dereference this ->pkt quic_frame member in qc_release_frm() and
qc_frm_unref() and add a trace to catch the frame with a null ->pkt member.
They are logically frames which have not already been sent.

Thank you to Tristan for having reported such crashes in GH #1808.

Must be backported to 2.6

2 years agoBUG/MINOR: mux-h2: send a CANCEL instead of ES on truncated writes
Willy Tarreau [Thu, 18 Aug 2022 14:12:15 +0000 (16:12 +0200)] 
BUG/MINOR: mux-h2: send a CANCEL instead of ES on truncated writes

If a POST upload is cancelled after having advertised a content-length,
or a response body is truncated after a content-length, we're not allowed
to send ES because in this case the total body length must exactly match
the advertised value. Till now that's what we were doing, and that was
causing the other side (possibly haproxy) to respond with an RST_STREAM
PROTOCOL_ERROR due to "ES on DATA frame before content-length".

We can behave a bit cleaner here. Let's detect that we haven't sent
everything, and send an RST_STREAM(CANCEL) instead, which is designed
exactly for this purpose.

This patch could be backported to older versions but only a little bit
of exposure to make sure it doesn't wake up a bad behavior somewhere.
It relies on the following previous commit:

   "MINOR: mux-h2: make streams know if they need to send more data"

2 years agoMINOR: mux-h2: make streams know if they need to send more data
Willy Tarreau [Thu, 18 Aug 2022 14:03:51 +0000 (16:03 +0200)] 
MINOR: mux-h2: make streams know if they need to send more data

H2 streams do not even know if they are expected to send more data or
not, which is problematic when closing because we don't know if we're
closing too early or not. Let's start by adding a new stream flag
"H2_SF_MORE_HTX_DATA" to indicate this on the tx path.

2 years agoMINOR: mux-h2/traces: report transition to SETTINGS1 before not after
Willy Tarreau [Thu, 18 Aug 2022 13:30:41 +0000 (15:30 +0200)] 
MINOR: mux-h2/traces: report transition to SETTINGS1 before not after

Traces indicating "switching to XXX" generally apply before the transition
so that the current connection state is visible in the trace. SETTINGS1
was incorrect in this regard, with the trace being emitted after. Let's
fix this.

No need to backport this, as this is purely cosmetic.

2 years agoBUG/MEDIUM: mux-h2: do not fiddle with ->dsi to indicate demux is idle
Willy Tarreau [Thu, 18 Aug 2022 09:19:57 +0000 (11:19 +0200)] 
BUG/MEDIUM: mux-h2: do not fiddle with ->dsi to indicate demux is idle

When switching to H2_CS_FRAME_H, we do not want to present the previous
frame's state, flags, length etc in traces, or we risk to confuse the
analysis, making the reader think that the header information presented
is related to the new frame header being analysed. A naive approach could
have consisted in simply relying on the current parser state (FRAME_H
being that state), but traces are emitted before switching the state,
so traces cannot rely on this.

This was initially addressed by commit 73db434f7 ("MINOR: h2/trace: report
the frame type when known") which used to set dsi to -1 when the connection
becomes idle again, but was accidentally broken by commit 5112a603d
("BUG/MAJOR: mux_h2: Don't consume more payload than received for skipped
frames") which moved dsi after calling the trace function.

But in both cases there's problem with this approach. If an RST or WU frame
cannot be uploaded due to a busy mux, and at the same time we complete
processing on a perfect end of frame with no single new frame header, we
can leave the demux loop with dsi=-1 and with RST or WU to be sent, and
these ones will be sent for stream ID -1. This is what was reported in
github issue #1830. This can be reproduced with a config chaining an h1->h2
proxy to an empty h2 frontend, and uploading a large body such as below:

  $ (printf "POST / HTTP/1.1\r\nContent-length: 1000000000\r\n\r\n";
     cat /dev/zero) |  nc 0 4445 > /dev/null

This shows that we must never affect ->dsi which must always remain valid,
and instead we should set "something else". That something else could be
served by the demux frame type, but that one also needs to be preserved
for the RST_STREAM case. Instead, let's just add a connection flag to say
that the demuxing is in progress. This will be set once a new demux header
is set and reset after the end of a frame. This way the trace subsystem
can know that dft/dfl must not be displayed, without affecting the logic
relying on such values.

Given that the commits above are old and were backported to 1.8, this
new one also needs to be backported as far as 1.8.

Many thanks to David le Blanc (@systemmonkey42) for spotting, reporting,
capturing and analyzing this bug; his work permitted to quickly spot the
problem.

2 years agoBUG/MEDIUM: cli: always reset the service context between commands
Willy Tarreau [Thu, 18 Aug 2022 16:04:37 +0000 (18:04 +0200)] 
BUG/MEDIUM: cli: always reset the service context between commands

Erwan Le Goas reported that chaining certain commands on the CLI would
systematically crash the process; for example, "show version; show sess".
This happened since the conversion of cli context to appctx->svcctx,
because if applet_reserve_svcctx() is called a first time for a tiny
context, it's allocated in-situ, and later a keyword that wants a
larger one will see that it's not null and will reuse it and will
overwrite the end of the first one's context.

What is missing is a reset of the svcctx when looping back to
CLI_ST_GETREQ.

This needs to be backported to 2.6, and relies on previous commit
"MINOR: applet: add a function to reset the svcctx of an applet".

2 years agoMINOR: applet: add a function to reset the svcctx of an applet
Willy Tarreau [Thu, 18 Aug 2022 16:13:34 +0000 (18:13 +0200)] 
MINOR: applet: add a function to reset the svcctx of an applet

The CLI needs to reset the svcctx between commands, and there was nothing
done to handle this. Let's add appctx_reset_svcctx() to do that, it's the
closing equivalent of appctx_reserve_svcctx().

This will have to be backported to 2.6 as it will be used by a subsequent
patch to fix a bug.

2 years agoMEDIUM: h3: concatenate multiple cookie headers
Amaury Denoyelle [Wed, 17 Aug 2022 16:02:47 +0000 (18:02 +0200)] 
MEDIUM: h3: concatenate multiple cookie headers

As specified by RFC 9114, multiple cookie headers must be concatenated
into a single entry before passing it to a HTTP/1.1 connection. To
implement this, reuse the same function as already used for HTTP/2
module.

This should answer to feature requested in github issue #1818.

2 years agoREGTESTS: add test for HTTP/2 cookies concatenation
Amaury Denoyelle [Wed, 17 Aug 2022 14:34:13 +0000 (16:34 +0200)] 
REGTESTS: add test for HTTP/2 cookies concatenation

Write a regtest to test RFC 7540 compliance in regards to multiple
cookie headers concatenation.

2 years agoREORG: h2: extract cookies concat function in http_htx
Amaury Denoyelle [Wed, 17 Aug 2022 14:33:53 +0000 (16:33 +0200)] 
REORG: h2: extract cookies concat function in http_htx

As specified by RFC 7540, multiple cookie headers are merged in a single
entry before passing it to a HTTP/1.1 connection. This step is
implemented during headers parsing in h2 module.

Extract this code in the generic http_htx module. This will allow to
reuse it quickly for HTTP/3 implementation which has the same
requirement for cookie headers.

2 years agoBUG/MEDIUM: quic: fix crash on MUX send notification
Amaury Denoyelle [Wed, 17 Aug 2022 14:33:13 +0000 (16:33 +0200)] 
BUG/MEDIUM: quic: fix crash on MUX send notification

MUX notification on TX has been edited recently : it will be notified
only when sending its own data, and not for example on retransmission by
the quic-conn layer. This is subject of the patch :
  b29a1dc2f4a334c1c7fea76c59abb4097422c05c
  BUG/MINOR: quic: do not notify MUX on frame retransmit

A new flag QUIC_FL_CONN_RETRANS_LOST_DATA has been introduced to
differentiate qc_send_app_pkts invocation by MUX and directly by the
quic-conn layer in quic_conn_app_io_cb(). However, this is a first
problem as internal quic-conn layer usage is not limited to
retransmission. For example for NEW_CONNECTION_ID emission.

Another problem much important is that send functions are also called
through quic_conn_io_cb() which has not been protected from MUX
notification. This could probably result in crash when trying to notify
the MUX.

To fix both problems, quic-conn flagging has been inverted : when used
by the MUX, quic-conn is flagged with QUIC_FL_CONN_TX_MUX_CONTEXT. To
improve the API, MUX must now used qc_send_mux which ensure the flag is
set. qc_send_app_pkts is now static and can only be used by the
quic-conn layer.

This must be backported wherever the previously mentionned patch is.

2 years agoBUG/MINOR: quic: Missing initializations for ducplicated frames.
Frédéric Lécaille [Thu, 18 Aug 2022 06:20:47 +0000 (08:20 +0200)] 
BUG/MINOR: quic: Missing initializations for ducplicated frames.

When duplication frames in qc_dup_pkt_frms(), ->pkt member was not correctly
initialized (copied from the original frame). This could not have any impact
because this member is initialized whe the frame is added to a packet.
This was also the case for ->flags.
Also replace the pool_zalloc() call by a call to pool_alloc().

Must be backported to 2.6.

2 years agoBUG/MEDIUM: http-ana: fix crash or wrong header deletion by http-restrict-req-hdr...
Mateusz Malek [Wed, 17 Aug 2022 12:22:09 +0000 (14:22 +0200)] 
BUG/MEDIUM: http-ana: fix crash or wrong header deletion by http-restrict-req-hdr-names

When using `option http-restrict-req-hdr-names delete`, HAproxy may
crash or delete wrong header after receiving request containing multiple
forbidden characters in single header name; exact behavior depends on
number of request headers, number of forbidden characters and position
of header containing them.

This patch fixes GitHub issue #1822.

Must be backported as far as 2.2 (buggy feature got included in 2.2.25,
2.4.18 and 2.5.8).

2 years agoBUG/MINOR: quic: do not notify MUX on frame retransmit
Amaury Denoyelle [Fri, 12 Aug 2022 12:30:04 +0000 (14:30 +0200)] 
BUG/MINOR: quic: do not notify MUX on frame retransmit

On STREAM emission, quic-conn notifies MUX through a callback named
qcc_streams_sent_done(). This also happens on retransmission : in this
case offset are examined and notification is ignored if already seen.

However, this behavior has slightly changed since
  e53b489826ba9760a527b461095402ca05d2b6be
  BUG/MEDIUM: mux-quic: fix server chunked encoding response

Indeed, if offset diff is NULL, frame is now not ignored. This is to
support FIN notification with a final empty STREAM frame. A side-effect
of this is that if the last stream frame is retransmitted, it won't be
ignored in qcc_streams_sent_done().

In most cases, this side-effect is harmless as qcs instance will soon be
freed after being closed. But if qcs is still alive, this will cause a
BUG_ON crash as it is considered as locally closed.

This bug depends on delay condition and seems to be extremely rare. But
it might be the reason for a crash seen on interop with s2n client on
http3 testcase :

FATAL: bug condition "qcs->st == QC_SS_CLO" matched at src/mux_quic.c:372
  call trace(16):
  | 0x558228912b0d [b8 01 00 00 00 c6 00 00]: main-0x1c7878
  | 0x558228917a70 [48 8b 55 d8 48 8b 45 e0]: qcc_streams_sent_done+0xcf/0x355
  | 0x558228906ff1 [e9 29 05 00 00 48 8b 05]: main-0x1d3394
  | 0x558228907cd9 [48 83 c4 10 85 c0 0f 85]: main-0x1d26ac
  | 0x5582289089c1 [48 83 c4 50 85 c0 75 12]: main-0x1d19c4
  | 0x5582288f8d2a [48 83 c4 40 48 89 45 a0]: main-0x1e165b
  | 0x5582288fc4cc [89 45 b4 83 7d b4 ff 74]: qc_send_app_pkts+0xc6/0x1f0
  | 0x5582288fd311 [85 c0 74 12 eb 01 90 48]: main-0x1dd074
  | 0x558228b2e4c1 [48 c7 c0 d0 60 ff ff 64]: run_tasks_from_lists+0x4e6/0x98e
  | 0x558228b2f13f [8b 55 80 29 c2 89 d0 89]: process_runnable_tasks+0x7d6/0x84c
  | 0x558228ad9aa9 [8b 05 75 16 4b 00 83 f8]: run_poll_loop+0x80/0x48c
  | 0x558228ada12f [48 8b 05 aa c5 20 00 48]: main-0x256
  | 0x7ff01ed2e609 [64 48 89 04 25 30 06 00]: libpthread:+0x8609
  | 0x7ff01e8ca163 [48 89 c7 b8 3c 00 00 00]: libc:clone+0x43/0x5e

To reproduce it locally, code was artificially patched to produce
retransmission and avoid qcs liberation.

In order to fix this and avoid future class of similar problem, the best
way is to not call qcc_streams_sent_done() to notify MUX for
retranmission. To implement this, we test if any of
QUIC_FL_CONN_RETRANS_OLD_DATA or the new flag
QUIC_FL_CONN_RETRANS_LOST_DATA is set. A new wrapper
qc_send_app_retransmit() has been added to set the new flag as a
complement to already existing qc_send_app_probing().

This must be backported up to 2.6.

2 years agoMINOR: quic: refactor application send
Amaury Denoyelle [Wed, 17 Aug 2022 08:08:16 +0000 (10:08 +0200)] 
MINOR: quic: refactor application send

Adjust qc_send_app_pkts function : remove <old_data> arg and provide a
new wrapper function qc_send_app_probing() which should be used instead
when probing with old data.

This simplifies the interface of the default function, most notably for
the MUX which does not interfer with retransmission.
QUIC_FL_CONN_RETRANS_OLD_DATA flag is set/unset directly in the wrapper
qc_send_app_probing().

At the same time, function documentation has been updated to clarified
arguments and return values.

This commit will be useful for the next patch to differentiate MUX and
retransmission send context. As a consequence, the current patch should
be backported wherever the next one will be.

2 years agoMINOR: mux-quic: add missing args on some traces
Amaury Denoyelle [Thu, 11 Aug 2022 16:35:55 +0000 (18:35 +0200)] 
MINOR: mux-quic: add missing args on some traces

Complete some MUX traces by adding qcc or qcs instance as arguments when
this is possible. This will be useful when several connections are
interleaved.

2 years agoMINOR: mux-quic: adjust traces on stream init
Amaury Denoyelle [Tue, 16 Aug 2022 09:13:45 +0000 (11:13 +0200)] 
MINOR: mux-quic: adjust traces on stream init

Adjust traces on qcc_init_stream_remote() : replace "opening" by
"initializing" to avoid confusion with traces dealing with OPEN stream
state.

2 years agoBUG/MEDIUM: mux-quic: reject uni stream ID exceeding flow control
Amaury Denoyelle [Tue, 16 Aug 2022 09:29:08 +0000 (11:29 +0200)] 
BUG/MEDIUM: mux-quic: reject uni stream ID exceeding flow control

Emit STREAM_LIMIT_ERROR if a client tries to open an unidirectional
stream with an ID greater than the value specified by our flow-control
limit. The code is similar to the bidirectional stream opening.

MAX_STREAMS_UNI emission is not implement for the moment and is left as
a TODO. This should not be too urgent for the moment : in HTTP/3, a
client has only a limited use for unidirectional streams (H3 control
stream + 2 QPACK streams). This is covered by the value provided by
haproxy in transport parameters.

This patch has been tagged with BUG as it should have prevented last
crash reported on github issue #1808 when opening a new unidirectional
streams with an invalid ID. However, it is probably not the main cause
of the bug contrary to the patch
  commit 11a6f4007b908b49ecd3abd5cd10fba177f07c11
  BUG/MINOR: quic: Wrong status returned by qc_pkt_decrypt()

This must be backported up to 2.6.

2 years agoMINOR: qpack: report error on enc/dec stream close
Amaury Denoyelle [Tue, 16 Aug 2022 15:42:47 +0000 (17:42 +0200)] 
MINOR: qpack: report error on enc/dec stream close

As specified by RFC 9204, encoder and decoder streams must not be
closed. If the peer behaves incorrectly and closes one of them, emit a
H3_CLOSED_CRITICAL_STREAM connection error.

To implement this, QPACK stream decoding API has been slightly adjusted.
Firstly, fin parameter is passed to notify about FIN STREAM bit.
Secondly, qcs instance is passed via unused void* context. This allows
to use qcc_emit_cc_app() function to report a CONNECTION_CLOSE error.

2 years agoMINOR: h3: report error on control stream close
Amaury Denoyelle [Tue, 16 Aug 2022 15:16:47 +0000 (17:16 +0200)] 
MINOR: h3: report error on control stream close

As specified by RFC 9114 the control stream must not be closed. If the
peer behaves incorrectly and closes it, emit a H3_CLOSED_CRITICAL_STREAM
connection error.

2 years agoMINOR: quic: adjust quic_frame flag manipulation
Amaury Denoyelle [Tue, 16 Aug 2022 12:41:57 +0000 (14:41 +0200)] 
MINOR: quic: adjust quic_frame flag manipulation

Replace a plain '=' operator by '|=' when setting quic_frame
QUIC_FL_TX_FRAME_LOST flag.

For the moment, this change has no impact as only two exclusive flags
are defined for quic_frame. On the edited code path we are certain that
QUIC_FL_TX_FRAME_ACKED is not set due to a previous if statement, so a
plain equal or a binary OR is strictly identical.

This change will be useful if new flags are defined for quic_frame in
the future. These new flags won't be resetted automatically thanks to
binary OR without explictly intended, which otherwise could easily lead
to new bugs.

2 years agoCLEANUP: exclude haring with .gitignore
Amaury Denoyelle [Tue, 16 Aug 2022 09:13:59 +0000 (11:13 +0200)] 
CLEANUP: exclude haring with .gitignore

haring is a new utility to decode file-backed rings. It is compiled in
dev/ directory and so the binary should be specified in .gitignore to
not clutter git status output.

2 years agoMINOR: stick-table: Add table_expire() and table_idle() new converters
Frédéric Lécaille [Tue, 16 Aug 2022 16:11:25 +0000 (18:11 +0200)] 
MINOR: stick-table: Add table_expire() and table_idle() new converters

table_expire() returns the expiration delay for a stick-table entry associated
to an input sample. Its counterpart table_idle() returns the time the entry
remained idle since the last time it was updated.
Both converters may take a default value as second argument which is returned
when the entry is not present.

2 years agoMINOR: chunk: inline alloc_trash_chunk()
Willy Tarreau [Wed, 17 Aug 2022 08:45:22 +0000 (10:45 +0200)] 
MINOR: chunk: inline alloc_trash_chunk()

This function is responsible for all calls to pool_alloc(trash), whose
total size can be huge. As such it's quite a pain that it doesn't provide
more hints about its users. However, since the function is tiny, it fully
makes sense to inline it, the code is less than 0.1% larger with this.
This way we can now detect where the callers are via "show profiling",
e.g.:

       0 1953671           0 32071463136| 0x59960f main+0x10676f p_free(-16416) [pool=trash]
       0       1           0       16416| 0x59960f main+0x10676f p_free(-16416) [pool=trash]
 1953672       0 32071479552           0| 0x599561 main+0x1066c1 p_alloc(16416) [pool=trash]
       0  976835           0 16035723360| 0x576ca7 http_reply_to_htx+0x447/0x920 p_free(-16416) [pool=trash]
       0       1           0       16416| 0x576ca7 http_reply_to_htx+0x447/0x920 p_free(-16416) [pool=trash]
  976835       0 16035723360           0| 0x576a5d http_reply_to_htx+0x1fd/0x920 p_alloc(16416) [pool=trash]
       1       0       16416           0| 0x576a5d http_reply_to_htx+0x1fd/0x920 p_alloc(16416) [pool=trash]

2 years agoMINOR: pools/memprof: store and report the pool's name in each bin
Willy Tarreau [Wed, 17 Aug 2022 07:35:16 +0000 (09:35 +0200)] 
MINOR: pools/memprof: store and report the pool's name in each bin

Storing the pointer to the pool along with the stats is quite useful as
it allows to report the name. That's what we're doing here. We could
store it in place of another field but that's not convenient as it would
require to change all functions that manipulate counters. Thus here we
store one extra field, as well as some padding because the struct turns
56 bytes long, thus better go to 64 directly. Example of output from
"show profiling memory":

      2      0       48         0|  0x4bfb2c ha_quic_set_encryption_secrets+0xcc/0xb5e p_alloc(24) [pool=quic_tls_iv]
      0  55252        0  10608384|  0x4bed32 main+0x2beb2 free(-192)
     15      0     2760         0|  0x4be855 main+0x2b9d5 p_alloc(184) [pool=quic_frame]
      1      0     1048         0|  0x4be266 ha_quic_add_handshake_data+0x2b6/0x66d p_alloc(1048) [pool=quic_crypto]
      3      0      552         0|  0x4be142 ha_quic_add_handshake_data+0x192/0x66d p_alloc(184) [pool=quic_frame]
  31276      0  6755616         0|  0x4bb8f9 quic_sock_fd_iocb+0x689/0x69b p_alloc(216) [pool=quic_dgram]
      0  31424        0   6787584|  0x4bb7f3 quic_sock_fd_iocb+0x583/0x69b p_free(-216) [pool=quic_dgram]
    152      0    32832         0|  0x4bb4d9 quic_sock_fd_iocb+0x269/0x69b p_alloc(216) [pool=quic_dgram]

2 years agoMINOR: pool/memprof: report pool alloc/free in memory profiling
Willy Tarreau [Wed, 17 Aug 2022 07:12:53 +0000 (09:12 +0200)] 
MINOR: pool/memprof: report pool alloc/free in memory profiling

Pools are being used so well that it becomes difficult to profile their
usage via the regular memory profiling. Let's add new entries for pools
there, named "p_alloc" and "p_free" that correspond to pool_alloc() and
pool_free(). Ideally it would be nice to only report those that fail
cache lookups but that's complicated, particularly on the free() path
since free lists are released in clusters to the shared pools.

It's worth noting that the alloc_tot/free_tot fields can easily be
determined by multiplying alloc_calls/free_calls by the pool's size, and
could be better used to store a pointer to the pool itself. However it
would require significant changes down the code that sorts output.

If this were to cause a measurable slowdown, an alternate approach could
consist in using a different value of USE_MEMORY_PROFILING to enable pools
profiling. Also, this profiler doesn't depend on intercepting regular malloc
functions, so we could also imagine enabling it alone or the other one alone
or both.

Tests show that the CPU overhead on QUIC (which is already an extremely
intensive user of pools) jumps from ~7% to ~10%. This is quite acceptable
in most deployments.

2 years agoMINOR: memprof: export the minimum definitions for memory profiling
Willy Tarreau [Wed, 17 Aug 2022 06:53:36 +0000 (08:53 +0200)] 
MINOR: memprof: export the minimum definitions for memory profiling

Right now it's not possible to feed memory profiling info from outside
activity.c, so let's export the function and move the enum and struct
to the include file.

2 years agoBUG/MINOR: quic: Wrong status returned by qc_pkt_decrypt()
Frédéric Lécaille [Tue, 16 Aug 2022 12:48:59 +0000 (14:48 +0200)] 
BUG/MINOR: quic: Wrong status returned by qc_pkt_decrypt()

This bug came with this big commit:
     "MEDIUM: quic: xprt traces rework"

This is the <ret> variable value which must be returned by most of the xprt functions.
This leaded packets which could not be decrypted to be parsed, with weird frames
to be parsed as found by Tristan in GH #1808.

To be backported where the commit above was backported.

2 years agoBUG/MINOR: quic: MIssing check when building TX packets
Frédéric Lécaille [Tue, 16 Aug 2022 10:03:00 +0000 (12:03 +0200)] 
BUG/MINOR: quic: MIssing check when building TX packets

When building an ack-eliciting frame only packet, if we did not manage to add
at least one such a frame to the packet, we did not notify the caller about
the fact the packet is empty. This could lead the caller to believe
everything was ok and make it endlessly try to build packet again and again.
This issue was amplified by the recent changes where a while(1) loop has been
added to qc_send_app_pkt() which calls qc_do_build_pkt() through qc_prep_app_pkts()
until we could not prepare packets. Before this recent change, I guess only
one empty packet was sent.
This patch checks that non empty packets could be built by qc_do_build_pkt()
and makes this function return an error if this was the case. Also note that
such an issue could happened only when the packet building was limited by
the congestion control.

Thank you to Tristan for having reported this issue in GH #1808.

Must be backported to 2.6.

2 years agoBUG/MINOR: mux-quic: fix crash with traces in qc_detach()
Amaury Denoyelle [Fri, 12 Aug 2022 13:56:21 +0000 (15:56 +0200)] 
BUG/MINOR: mux-quic: fix crash with traces in qc_detach()

qc_detach() is used to free a qcs as notified by sedesc. If there is no
more stream active and the connection is considered as dead, it will
then be freed. This prevent to dereference qcc in TRACE macro. Else this
will cause a crash.

Use a different code-path on release for qc_detach() to fix this bug.

This will fix the last occurence of crash on github issue #1808.

This has been introduced by recent QUIC MUX traces rework. Thus, it does
not need to be backport.

2 years agoMINOR: ring: archive a previous file-backed ring on startup
Willy Tarreau [Fri, 12 Aug 2022 13:38:20 +0000 (15:38 +0200)] 
MINOR: ring: archive a previous file-backed ring on startup

In order to ensure that an instant restart of the process will not wipe
precious debugging information, and to leave time for an admin to archive
a copy of a ring, now upon startup, any previously existing file will be
renamed with the extra suffix ".bak", and any previously existing file
with suffix ".bak" will be removed.

2 years agoBUILD: sink: replace S_IRUSR, S_IWUSR with their octal value
Willy Tarreau [Fri, 12 Aug 2022 13:03:12 +0000 (15:03 +0200)] 
BUILD: sink: replace S_IRUSR, S_IWUSR with their octal value

The build broke on freebsd with S_IRUSR undefined after commit 0b8e9ceb1
("MINOR: ring: add support for a backing-file"). Maybe another include
is needed there, but the point is that we really don't care about these
symbolic names, file modes are more readable as 0600 than via these
cryptic names anyway, so let's go back to 0600. This will teach me not
to try to make things too clean.

No backport is needed.

2 years agoBUG/MINOR: quic: memleak on wrong datagram receipt
Frédéric Lécaille [Fri, 12 Aug 2022 09:55:20 +0000 (11:55 +0200)] 
BUG/MINOR: quic: memleak on wrong datagram receipt

There was a missing pool_free() call for such datagrams. As far as I see
there is no leak on valid datagram receipt.

Must be backported to 2.6.