]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
2 years agoMINOR: cfgcond: Implement enabled condition expression
Christopher Faulet [Tue, 21 Feb 2023 10:16:08 +0000 (11:16 +0100)] 
MINOR: cfgcond: Implement enabled condition expression

Implement a way to test if some options are enabled at run-time. For now,
following options may be detected:

  POLL, EPOLL, KQUEUE, EVPORTS, SPLICE, GETADDRINFO, REUSEPORT,
  FAST-FORWARD, SERVER-SSL-VERIFY-NONE

These options are those that can be disabled on the command line. This way
it is possible, from a reg-test for instance, to know if a feature is
supported or not :

  feature cmd "$HAPROXY_PROGRAM -cc '!(globa.tune & GTUNE_NO_FAST_FWD)'"

2 years agoMINOR: cfgcond: Implement strstr condition expression
Christopher Faulet [Mon, 20 Feb 2023 16:55:58 +0000 (17:55 +0100)] 
MINOR: cfgcond: Implement strstr condition expression

Implement a way to match a substring in a string. The strstr expresionn can
now be used to do so.

2 years agoDOC: config: Add the missing tune.fail-alloc option from global listing
Christopher Faulet [Mon, 20 Feb 2023 13:33:46 +0000 (14:33 +0100)] 
DOC: config: Add the missing tune.fail-alloc option from global listing

This global option is documented but it is not in the list of supported
options for the global section. So let's add it.

This patch could be backported to all stable versions.

2 years agoBUG/MINOR: haproxy: Fix option to disable the fast-forward
Christopher Faulet [Mon, 20 Feb 2023 13:06:52 +0000 (14:06 +0100)] 
BUG/MINOR: haproxy: Fix option to disable the fast-forward

The option was renamed to only permit to disable the fast-forward. First
there is no reason to enable it because it is the default behavior. Then it
introduced a bug because there is no way to be sure the command line has
precedence over the configuration this way. So, the option is now named
"tune.disable-fast-forward" and does not support any argument. And of
course, the commande line option "-dF" has now precedence over the
configuration.

No backport needed.

2 years agoMINOR: proxy: Only consider backend httpclose option for server connections
Christopher Faulet [Mon, 20 Feb 2023 16:30:06 +0000 (17:30 +0100)] 
MINOR: proxy: Only consider backend httpclose option for server connections

For server connections, both the frontend and backend were considered to
enable the httpclose option. However, it is ambiguous because on client side
only the frontend is considerd. In addition for 2 frontends, one with the
option enabled and not for the other, the HTTP connection mode may differ
while it is a backend setting.

Thus, now, for the server side, only the backend is considered. Of course,
if the option is set for a listener, the option will be enabled if the
listener is the backend's connection.

2 years agoDOC: config: Fix description of options about HTTP connection modes
Christopher Faulet [Mon, 20 Feb 2023 16:09:34 +0000 (17:09 +0100)] 
DOC: config: Fix description of options about HTTP connection modes

Since the HTX, the decription of options about HTTP connection modes is
wrong. In fact, it is worst, all the documentation about HTTP connection
mode is wrong. But only options will be updated for now to be backported.

So, documentation of "option httpclose", "option "http-keep-alive", "option
http-server-close" and "option "http-pretend-keepalive" was reviewed. First,
it is specify these options only concern HTT/1.x connections. Then, the
descriptions were updated to reflect the HTX implementation.

The main changes concerns the fact that server connections are no longer
attached to client connections. The connection mode on one side does not
affect the connection mode on the other side. It is especially true for
t"option httpclose". For client connections, only the frontend option is
considered and for server ones, both frontend and backend options are
considered.

This patch should be backported as far as 2.2.

2 years agoDEBUG: stream: Add a BUG_ON to never exit process_stream with an expired task
Christopher Faulet [Mon, 20 Feb 2023 13:43:49 +0000 (14:43 +0100)] 
DEBUG: stream: Add a BUG_ON to never exit process_stream with an expired task

We must never exit for the stream processing function with an expired
task. Otherwise, we are pretty sure this will ends with a spinning loop. It
is really better to abort as far as possible and with the original buggy
state. This will ease the debug sessions.

2 years agoBUG/MEDIUM: quic: Missing TX buffer draining from qc_send_ppkts()
Frédéric Lécaille [Mon, 20 Feb 2023 08:28:58 +0000 (09:28 +0100)] 
BUG/MEDIUM: quic: Missing TX buffer draining from qc_send_ppkts()

If the TX buffer (->tx.buf) attached to the connection is not drained, there
are chances that this will be detected by qc_txb_release() which triggers
a BUG_ON_HOT() when this is the case as follows

[00|quic|2|c_conn.c:3477] UDP port unreachable : qc@0x5584f18d6d50 pto_count=0 cwnd=6816 ppif=1046 pif=1046
[00|quic|5|ic_conn.c:749] qc_kill_conn(): entering : qc@0x5584f18d6d50
[00|quic|5|ic_conn.c:752] qc_kill_conn(): leaving : qc@0x5584f18d6d50
[00|quic|5|c_conn.c:3532] qc_send_ppkts(): leaving : qc@0x5584f18d6d50 pto_count=0 cwnd=6816 ppif=1046 pif=1046

FATAL: bug condition "buf && b_data(buf)" matched at src/quic_conn.c:3098

Consume the remaining data in the TX buffer calling b_del().

This bug arrived with this commit:
    a2c62c314 MINOR: quic: Kill the connections on ICMP (port unreachable) packet receipt

Takes also the opportunity of this patch to modify the comments for qc_send_ppkts()
which should have arrived with a2c62c314 commit.

Must be backported to 2.7 where this latter commit is supposed to be backported.

2 years agoMINOR: mux-h2/traces: add a missing TRACE_LEAVE() in h2s_frt_handle_headers()
Willy Tarreau [Mon, 20 Feb 2023 16:05:10 +0000 (17:05 +0100)] 
MINOR: mux-h2/traces: add a missing TRACE_LEAVE() in h2s_frt_handle_headers()

Traces from this function would miss a TRACE_LEAVE() on the success path,
which had for consequences, 1) that it was difficult to figure where the
function was left, and 2) that we never had the allocated stream ID
clearly visible (actually the one returned by h2c_frt_stream_new() is
the right one but it's not obvious).

This can be backported to 2.7 and 2.6.

2 years agoMINOR: mux-h2/traces: do not log h2s pointer for dummy streams
Willy Tarreau [Mon, 20 Feb 2023 15:57:47 +0000 (16:57 +0100)] 
MINOR: mux-h2/traces: do not log h2s pointer for dummy streams

Functions which are called with dummy streams pass it down the traces
and that leads to somewhat confusing "h2s=0x1234568(0,IDL)" for example
while the nature of the called function makes this stream useless at that
place. Better not report a random pointer, especially since it always
requires to look at the code before remembering how this should be
interpreted.

Now what we're doing is that the idle stream only prints "h2s=IDL" which
is shorter and doesn't report a pointer, closed stream do not report
anything since the stream ID 0 already implies it, and other ones are
reported normally.

This could be backported to 2.7 and 2.6 as it improves traces legibility.

2 years agoMEDIUM: quic: trigger fast connection closing on process stopping
Amaury Denoyelle [Wed, 1 Feb 2023 08:28:55 +0000 (09:28 +0100)] 
MEDIUM: quic: trigger fast connection closing on process stopping

With previous commit, quic-conn are now handled as jobs to prevent the
termination of haproxy process. This ensures that QUIC connections are
closed when all data are acknowledged by the client and there is no more
active streams.

The quic-conn layer emits a CONNECTION_CLOSE once the MUX has been
released and all streams are acknowledged. Then, the timer is scheduled
to definitely free the connection after the idle timeout period. This
allows to treat late-arriving packets.

Adjust this procedure to deactivate this timer when process stopping is
in progress. In this case, quic-conn timer is set to expire immediately
to free the quic-conn instance as soon as possible. This allows to
quickly close haproxy process.

This should be backported up to 2.7.

2 years agoMINOR: quic: mark quic-conn as jobs on socket allocation
Amaury Denoyelle [Wed, 1 Feb 2023 08:28:32 +0000 (09:28 +0100)] 
MINOR: quic: mark quic-conn as jobs on socket allocation

To prevent data loss for QUIC connections, haproxy global variable jobs
is incremented each time a quic-conn socket is allocated. This allows
the QUIC connection to terminate all its transfer operation during proxy
soft-stop. Without this patch, the process will be terminated without
waiting for QUIC connections.

Note that this is done in qc_alloc_fd(). This means only QUIC connection
with their owned socket will properly support soft-stop. In the other
case, the connection will be interrupted abruptly as before. Similarly,
jobs decrement is conducted in qc_release_fd().

This should be backported up to 2.7.

2 years agoMEDIUM: mux-quic: properly implement soft-stop
Amaury Denoyelle [Tue, 24 Jan 2023 17:20:28 +0000 (18:20 +0100)] 
MEDIUM: mux-quic: properly implement soft-stop

Properly implement support for haproxy soft-stop on QUIC MUX. This code
is similar to H2 MUX :

* on timeout refresh, if stop-stop in progress, schedule the timeout to
  expire with regards to the close-spread-end window.

* after input/output processing, if soft-stop in progress, shutdown the
  connection. This is randomly spread by close-spread-end window. In the
  case of H3 connection, a GOAWAY is emitted and the connection is kept
  until all data are sent for opened streams. If the client tries to use
  new streams, they are rejected in conformance with the GOAWAY
  specification.

This ensures that MUX is able to forward all content properly before
closing the connection. The lower quic-conn layer is then responsible
for retransmission and should be closed when all data are acknowledged.
This will be implemented in the next commit to fully support soft-stop
for QUIC connections.

This should be backported up to 2.7.

2 years agoMINOR: mux-quic: implement client-fin timeout
Amaury Denoyelle [Wed, 8 Feb 2023 14:55:24 +0000 (15:55 +0100)] 
MINOR: mux-quic: implement client-fin timeout

Implement client-fin timeout for MUX quic. This timeout is used once an
applicative layer shutdown has been called. In HTTP/3, this corresponds
to the emission of a GOAWAY.

This should be backported up to 2.7.

2 years agoMINOR: mux-quic: define qc_process()
Amaury Denoyelle [Tue, 24 Jan 2023 17:19:47 +0000 (18:19 +0100)] 
MINOR: mux-quic: define qc_process()

Define a new function qc_process(). This function will regroup several
internal operation which should be called both on I/O tasklet and wake()
callback. For the moment, only streams purge is conducted there.

This patch is useful to support haproxy soft stop. This should be
backported up to 2.7.

2 years agoMINOR: mux-quic: define qc_shutdown()
Amaury Denoyelle [Tue, 24 Jan 2023 17:18:23 +0000 (18:18 +0100)] 
MINOR: mux-quic: define qc_shutdown()

Factorize shutdown operation in a dedicated function qc_shutdown(). This
will allow to call it from multiple places. A new flag QC_CF_APP_SHUT is
also defined to ensure it will only be executed once even if called
multiple times per connection.

This commit will be useful to properly support haproxy soft stop.
This should be backported up to 2.7.

2 years agoMEDIUM: h3: enforce GOAWAY by resetting higher unhandled stream
Amaury Denoyelle [Tue, 24 Jan 2023 16:42:21 +0000 (17:42 +0100)] 
MEDIUM: h3: enforce GOAWAY by resetting higher unhandled stream

When a GOAWAY has been emitted, an ID is announced to represent handled
streams. H3 RFC suggests that higher streams should be resetted with the
error code H3_REQUEST_CANCELLED. This allows the peer to replay requests
on another connection.

For the moment, the impact of this change is limitted as GOAWAY is only
used on connection shutdown just before the MUX is freed. However, for
soft-stop support, a GOAWAY can be emitted in anticipation while keeping
the MUX to finish the active streams. In this case, new streams opened
by the client are resetted.

As a consequence of this change, app_ops.attach() operation has been
delayed at the very end of qcs_new(). This ensure that all qcs members
are initialized to support RESET_STREAM sending.

This should be backported up to 2.7.

2 years agoBUG/MINOR: h3: prevent hypothetical demux failure on int overflow
Amaury Denoyelle [Thu, 26 Jan 2023 15:03:45 +0000 (16:03 +0100)] 
BUG/MINOR: h3: prevent hypothetical demux failure on int overflow

h3s stores the current demux frame type and length as a state info. It
should be big enough to store a QUIC variable-length integer which is
the maximum H3 frame type and size.

Without this patch, there is a risk of integer overflow if H3 frame size
is bigger than INT_MAX. This can typically causes demux state mismatch
and demux frame error. However, no occurence has been found yet of this
bug with the current implementation.

This should be backported up to 2.6.

2 years agoBUG/MINOR: quic: acknowledge STREAM frame even if MUX is released
Amaury Denoyelle [Mon, 20 Feb 2023 09:32:16 +0000 (10:32 +0100)] 
BUG/MINOR: quic: acknowledge STREAM frame even if MUX is released

When the MUX is freed, the quic-conn layer may stay active until all
streams acknowledgment are processed. In this interval, if a new stream
is opened by the client, the quic-conn is thus now responsible to handle
it. This is done by the emission of a STOP_SENDING + RESET_STREAM.

Prior to this patch, the received packet was not acknowledged. This is
undesirable if the quic-conn is able to properly reject the request as
this can lead to unneeded retransmission from the client.

This must be backported up to 2.6.

2 years agoBUG/MINOR: quic: also send RESET_STREAM if MUX released
Amaury Denoyelle [Mon, 20 Feb 2023 09:31:27 +0000 (10:31 +0100)] 
BUG/MINOR: quic: also send RESET_STREAM if MUX released

When the MUX is freed, the quic-conn layer may stay active until all
streams acknowledgment are processed. In this interval, if a new stream
is opened by the client, the quic-conn is thus now responsible to handle
it. This is done by the emission of a STOP_SENDING.

This process has been completed to also emit a RESET_STREAM with the
same error code H3_REQUEST_REJECTED. This is done to conform with the H3
specification to invite the client to retry its request on a new
connection.

This should be backported up to 2.6.

2 years agoMINOR: quic: adjust request reject when MUX is already freed
Amaury Denoyelle [Tue, 7 Feb 2023 13:24:54 +0000 (14:24 +0100)] 
MINOR: quic: adjust request reject when MUX is already freed

When the MUX is freed, the quic-conn layer may stay active until all
streams acknowledgment are processed. In this interval, if a new stream
is opened by the client, the quic-conn is thus now responsible to handle
it. This is done by the emission of a STOP_SENDING.

This process is closely related to HTTP/3 protocol despite being handled
by the quic-conn layer. This highlights a flaw in our QUIC architecture
which should be adjusted. To reflect this situation, the function
qc_stop_sending_frm_enqueue() is renamed qc_h3_request_reject(). Also,
internal H3 treatment such as uni-directional bypass has been moved
inside the function.

This commit is only a refactor. However, bug fix on next patches will
rely on it so it should be backported up to 2.6.

2 years agoBUG/MINOR: quic: Missing padding for short packets
Frédéric Lécaille [Thu, 16 Feb 2023 16:30:53 +0000 (17:30 +0100)] 
BUG/MINOR: quic: Missing padding for short packets

This was revealed by Amaury when setting tune.quic.frontend.max-streams-bidi to 8
and asking a client to open 12 streams. haproxy has to send short packets
with little MAX_STREAMS frames encoded with 2 bytes. In addition to a packet number
encoded with only one byte. In the case <len_frms> is the length of the encoded
frames to be added to the packet plus the length of the packet number.

Ensure the length of the packet is at least QUIC_PACKET_PN_MAXLEN adding a PADDING
frame wich (QUIC_PACKET_PN_MAXLEN - <len_frms>) as size. For instance with
a two bytes MAX_STREAMS frames and a one byte packet number length, this adds
one byte of padding.

See https://datatracker.ietf.org/doc/html/rfc9001#name-header-protection-sample.

Must be backported to 2.7 and 2.6.

2 years agoBUG/MINOR: quic: Do not drop too small datagrams with Initial packets
Frédéric Lécaille [Thu, 16 Feb 2023 10:40:11 +0000 (11:40 +0100)] 
BUG/MINOR: quic: Do not drop too small datagrams with Initial packets

When receiving an Initial packet a peer must drop it if the datagram is smaller
than 1200. Before this patch, this is the entire datagram which was dropped.

In such a case, drop the packet after having parsed its length.

Must be backported to 2.6 and 2.7

2 years agoBUG/MINOR: quic: Wrong initialization for io_cb_wakeup boolean
Frédéric Lécaille [Wed, 15 Feb 2023 10:55:21 +0000 (11:55 +0100)] 
BUG/MINOR: quic: Wrong initialization for io_cb_wakeup boolean

This bug arrives with this commit:
    982896961 MINOR: quic: split and rename qc_lstnr_pkt_rcv()
The first block of code consists in possibly setting this variable to true.
But it was already initialized to true before entering this code section.
Should be initialized to false.

Also take the opportunity to remove an unused "err" label.

Must be backported to 2.6 and 2.7.

2 years agoBUG/MINOR: quic: Do not probe with too little Initial packets
Frédéric Lécaille [Tue, 14 Feb 2023 15:00:18 +0000 (16:00 +0100)] 
BUG/MINOR: quic: Do not probe with too little Initial packets

Before probing the Initial packet number space, verify that we can at least
sent 1200 bytes by datagram. This may not be the case due to the amplification limit.

Must be backported to 2.6 and 2.7.

2 years agoMINOR: quic: Add <pto_count> to the traces
Frédéric Lécaille [Mon, 13 Feb 2023 17:39:19 +0000 (18:39 +0100)] 
MINOR: quic: Add <pto_count> to the traces

This may be useful to diagnose issues in relation with QUIC recovery.

Must be backported to 2.7.

2 years agoMINOR: quic: Add a trace to identify connections which sent Initial packet.
Frédéric Lécaille [Mon, 13 Feb 2023 16:45:36 +0000 (17:45 +0100)] 
MINOR: quic: Add a trace to identify connections which sent Initial packet.

This should help in diagnosing issues revealed by the interop runner which counts
the number of handshakes from the number of Initial packets sent by the server.

Must be backported to 2.7.

2 years agoBUG/MINOR: quic: Missing call to task_queue() in qc_idle_timer_do_rearm()
Frédéric Lécaille [Fri, 10 Feb 2023 15:35:43 +0000 (16:35 +0100)] 
BUG/MINOR: quic: Missing call to task_queue() in qc_idle_timer_do_rearm()

The aim of this function is to rearm the idle timer. The ->expire
field of the timer task was updated without being requeued.
Some connection could be unexpectedly terminated.

Must be backported to 2.6 and 2.7.

2 years agoMINOR: quic: Make qc_dgrams_retransmit() return a status.
Frédéric Lécaille [Fri, 10 Feb 2023 13:46:39 +0000 (14:46 +0100)] 
MINOR: quic: Make qc_dgrams_retransmit() return a status.

This is very helpful during retranmission when receiving ICMP port unreachable
errors after the peer has left. This is the unique case at prevent where
qc_send_hdshk_pkts() or qc_send_app_probing() may fail (when they call
qc_send_ppkts() which fails with ECONNREFUSED as errno).

Also make the callers qc_dgrams_retransmit() stop their packet process. This
is the case of quic_conn_app_io_cb() and quic_conn_io_cb().

This modifications stops definitively any packet processing when receiving
ICMP port unreachable errors.

Must be backported to 2.7.

2 years agoMINOR: quic: Add traces to qc_kill_conn()
Frédéric Lécaille [Fri, 10 Feb 2023 13:44:51 +0000 (14:44 +0100)] 
MINOR: quic: Add traces to qc_kill_conn()

Very minor modification to help in debugging issues.

Must be backported to 2.7.

2 years agoMINOR: quic: Kill the connections on ICMP (port unreachable) packet receipt
Frédéric Lécaille [Fri, 10 Feb 2023 13:13:43 +0000 (14:13 +0100)] 
MINOR: quic: Kill the connections on ICMP (port unreachable) packet receipt

The send*() syscall which are responsible of such ICMP packets reception
fails with ECONNREFUSED as errno.

  man(7) udp
  ECONNREFUSED
      No receiver was associated with the destination address.
      This might be caused by a previous packet sent over the socket.

We must kill asap the underlying connection.

Must be backported to 2.7.

2 years agoMINOR: quic: Simplication for qc_set_timer()
Frédéric Lécaille [Thu, 9 Feb 2023 06:48:33 +0000 (07:48 +0100)] 
MINOR: quic: Simplication for qc_set_timer()

There is no reason to run code for nothing if the timer task has been
released when entering qc_set_timer().

Must be backported to 2.7.

2 years agoBUG/MINOR: quic: Really cancel the connection timer from qc_set_timer()
Frédéric Lécaille [Wed, 8 Feb 2023 16:43:13 +0000 (17:43 +0100)] 
BUG/MINOR: quic: Really cancel the connection timer from qc_set_timer()

The ->expire field of the timer task to be cancelled was not reset
to TICK_ETERNITY.

Must be backported to 2.6 and 2.7.

2 years agoMINOR: quic: Move code to wakeup the timer task to avoid anti-amplication deadlock
Frédéric Lécaille [Wed, 8 Feb 2023 15:08:28 +0000 (16:08 +0100)] 
MINOR: quic: Move code to wakeup the timer task to avoid anti-amplication deadlock

This code was there because the timer task was not running on the same thread
as the one which parse the QUIC packets. Now that this is no more the case,
we can wake up this task directly.

Must be backported to 2.7.

2 years agoMINOR: quic: Add new traces about by connection RX buffer handling
Frédéric Lécaille [Tue, 7 Feb 2023 10:40:21 +0000 (11:40 +0100)] 
MINOR: quic: Add new traces about by connection RX buffer handling

Move quic_rx_pkts_del() out of quic_conn.h to make it benefit from the TRACE API.
Add traces which already already helped in diagnosing an issue encountered with
ngtcp2 which sent too much 1RTT packets before the handshake completion. This
has been fixed here after having discussed with Tasuhiro on QUIC dev slack:

https://github.com/ngtcp2/ngtcp2/pull/663

Must be backported to 2.7.

2 years agoBUG/MINOR: quic: Possible unexpected counter incrementation on send*() errors
Frédéric Lécaille [Thu, 9 Feb 2023 19:37:26 +0000 (20:37 +0100)] 
BUG/MINOR: quic: Possible unexpected counter incrementation on send*() errors

Some counters could potentially be incremented even if send*() syscall returned
no error when ret >= 0 and ret != sz. This could be the case for instance if
a first call to send*() returned -1 with errno set to EINTR (or any previous syscall
which set errno to a non-null value) and if the next call to send*() returned
something positive and smaller than <sz>.

Must be backported to 2.7 and 2.6.

2 years agoMINOR: h3: add traces on decode_qcs callback
Amaury Denoyelle [Fri, 17 Feb 2023 14:56:06 +0000 (15:56 +0100)] 
MINOR: h3: add traces on decode_qcs callback

Add traces inside h3_decode_qcs(). Every error path has now its
dedicated trace which should simplify debugging. Each early returns has
been converted to a goto invocation.

To complete the demux tracing, demux frame type and length are now
printed using the h3s instance whenever its possible on trace
invocation. A new internal value H3_FT_UNINIT is used as a frame type to
mark demuxing as inactive.

This should be backported up to 2.7.

2 years agoBUG/MINOR: mworker: prevent incorrect values in uptime
William Lallemand [Fri, 17 Feb 2023 15:23:52 +0000 (16:23 +0100)] 
BUG/MINOR: mworker: prevent incorrect values in uptime

Since the recent changes on the clocks, now.tv_sec is not to be used
between processes because it's a clock which is local to the process and
does not contain a real unix timestamp.  This patch fixes the issue by
using "data.tv_sec" which is the wall clock instead of "now.tv_sec'.
It prevents having incoherent timestamps.

It also introduces some checks on negatives values in order to never
displays a netative value if it was computed from a wrong value set by a
previous haproxy version.

It must be backported as far as 2.0.

2 years agoBUG/MINOR: mux-quic: transfer FIN on empty STREAM frame
Amaury Denoyelle [Tue, 14 Feb 2023 14:36:36 +0000 (15:36 +0100)] 
BUG/MINOR: mux-quic: transfer FIN on empty STREAM frame

Implement support for clients that emit the stream FIN with an empty
STREAM frame. For that, qcc_recv() offset comparison has been adjusted.
If offset has already been received but the FIN bit is now transmitted,
do not skip the rest of the function and call application layer
decode_qcs() callback.

Without this, streams will be kept open forever as HTX EOM is never
transfered to the upper stream layer.

This behavior was observed with mvfst client prior to its patch
  38c955a024aba753be8bf50fdeb45fba3ac23cfd
  Fix hq-interop (HTTP 0.9 over QUIC)

This notably caused the interop multiplexing test to fail as unclosed
streams on haproxy side prevented the emission of new MAX_STREAMS frame
to the client.

This shoud be backported up to 2.6. It also relies on previous commit :
  381d8137e31d941c9143a1dc8b5760d29f388fef
  MINOR: h3/hq-interop: handle no data in decode_qcs() with FIN set

2 years agoMINOR: h3/hq-interop: handle no data in decode_qcs() with FIN set
Amaury Denoyelle [Fri, 17 Feb 2023 08:51:20 +0000 (09:51 +0100)] 
MINOR: h3/hq-interop: handle no data in decode_qcs() with FIN set

Properly handle a STREAM frame with no data but the FIN bit set at the
application layer. H3 and hq-interop decode_qcs() callback have been
adjusted to not return early in this case.

If the FIN bit is accepted, a HTX EOM must be inserted for the upper
stream layer. If the FIN is rejected because the stream cannot be
closed, a proper CONNECTION_CLOSE error will be triggered.

A new utility function qcs_http_handle_standalone_fin() has been
implemented in the qmux_http module. This allows to simply add the HTX
EOM on qcs HTX buffer. If the HTX buffer is empty, a EOT is first added
to ensure it will be transmitted above.

This commit will allow to properly handle FIN notify through an empty
STREAM frame. However, it is not sufficient as currently qcc_recv() skip
the decode_qcs() invocation when the offset is already received. This
will be fixed in the next commit.

This should be backported up to 2.6 along with the next patch.

2 years agoMINOR: threads: add flags to know if a thread is started and/or running
Willy Tarreau [Fri, 17 Feb 2023 07:36:42 +0000 (08:36 +0100)] 
MINOR: threads: add flags to know if a thread is started and/or running

Several times during debugging it has been difficult to find a way to
reliably indicate if a thread had been started and if it was still
running. It's really not easy because the elements we look at are not
necessarily reliable (e.g. harmless bit or idle bit might not reflect
what we think during a signal). And such notions can be subjective
anyway.

Here we define two thread flags, TH_FL_STARTED which is set as soon as
a thread enters run_thread_poll_loop() and drops the idle bit, and
another one, TH_FL_IN_LOOP, which is set when entering run_poll_loop()
and cleared when leaving it. This should help init/deinit code know
whether it's called from a non-initialized thread (i.e. tid must not
be trusted), or shared functions know if they're being called from a
running thread or from init/deinit code outside of the polling loop.

2 years agoBUG/MEDIUM: sched: allow a bit more TASK_HEAVY to be processed when needed
Willy Tarreau [Thu, 16 Feb 2023 08:19:21 +0000 (09:19 +0100)] 
BUG/MEDIUM: sched: allow a bit more TASK_HEAVY to be processed when needed

As reported in github issue #1881, there are situations where an excess
of TLS handshakes can cause a livelock. What's happening is that normally
we process at most one TLS handshake per loop iteration to maintain the
latency low. This is done by tagging them with TASK_HEAVY, queuing these
tasklets in the TL_HEAVY queue. But if something slows down the loop, such
as a connect() call when no more ports are available, we could end up
processing no more than a few hundred or thousands handshakes per second.

If the llmit becomes lower than the rate of incoming handshakes, we will
accumulate them and at some point users will get impatient and give up or
retry. Then a new problem happens: the queue fills up with even more
handshake attempts, only one of which will be handled per iteration, so
we can end up processing only outdated handshakes at a low rate, with
basically nothing else in the queue. This can for example happen in
parallel with health checks that don't require incoming handshakes to
succeed to continue to cause some activity that could maintain the high
latency stuff active.

Here we're taking a slightly different approach. First, instead of always
allowing only one handshake per loop (and usually it's critical for
latency), we take the current situation into account:
  - if configured with tune.sched.low-latency, the limit remains 1
  - if there are other non-heavy tasks, we set the limit to 1 + one
    per 1024 tasks, so that a heavily loaded queue of 4k handshakes
    per thread will be able to drain them at ~4 per loops with a
    limited impact on latency
  - if there are no other tasks, the limit grows to 1 + one per 128
    tasks, so that a heavily loaded queue of 4k handshakes per thread
    will be able to drain them at ~32 per loop with still a very
    limited impact on latency since only I/O will get delayed.

It was verified on a 56-core Xeon-8480 that this did not degrade the
latency; all requests remained below 1ms end-to-end in full close+
handshake, and even 500us under low-lat + busy-polling.

This must be backported to 2.4.

2 years agoBUG/MINOR: sched: properly report long_rq when tasks remain in the queue
Willy Tarreau [Thu, 16 Feb 2023 08:07:00 +0000 (09:07 +0100)] 
BUG/MINOR: sched: properly report long_rq when tasks remain in the queue

There's a per-thread "long_rq" counter that is used to indicate how
often we leave the scheduler with tasks still present in the run queue.
The purpose is to know when tune.runqueue-depth served to limit latency,
due to a large number of tasks being runnable at once.

However there's a bug there, it's not always set: if after the first
run, one heavy task was processed and later only heavy tasks remain,
we'll loop back to not_done_yet where we try to pick more tasks, but
none are eligible (since heavy ones have already run) so we directly
return without incrementing the counter. This is what causes ultra-low
values on long_rq during massive SSL handshakes, that are confusing
because they make one believe that tl_class_mask doesn't have the HEAVY
flag anymore. Let's just fix that by not returning from the middle of
the function.

This can be backported as far as 2.4.

2 years agoBUG/MEDIUM: wdt: fix wrong thread being checked for sleeping
Willy Tarreau [Fri, 17 Feb 2023 13:55:41 +0000 (14:55 +0100)] 
BUG/MEDIUM: wdt: fix wrong thread being checked for sleeping

In 2.7, the method used to check for a sleeping thread changed with
commit e7475c8e7 ("MEDIUM: tasks/fd: replace sleeping_thread_mask with
a TH_FL_SLEEPING flag"). Previously there was a global sleeping mask
and now there is a flag per thread. The commit above partially broke
the watchdog by looking at the current thread's flags via th_ctx
instead of the reported thread's flags, and using an AND condition
instead of an OR to update and leave. This can cause a wrong thread
to be killed when the load is uneven. For example, when enabling
busy polling and sending traffic over a single connection, all
threads have their run time grow, and if the one receiving the
signal is also processing some traffic, it will not match the
sleeping/harmless condition and will set the stuck flag, then die
upon next invocation. While it's reproducible in tests, it's unlikely
to be met in field.

This fix should be backported to 2.7.

2 years agoREGTESTS: Remove unsupported feature command in http_splicing.vtc
Christopher Faulet [Fri, 17 Feb 2023 14:27:10 +0000 (15:27 +0100)] 
REGTESTS: Remove unsupported feature command in http_splicing.vtc

A feature command was added to detect if infinite forward is disabled to be
able to skip the script. Unfortunately, it is no supported to evaluate such
expression. Thus remove it. For now, reg-tests must not be executed with
"-dF" option.

2 years agoMINOR: haproxy: Add an command option to disable data fast-forward
Christopher Faulet [Tue, 14 Feb 2023 15:12:54 +0000 (16:12 +0100)] 
MINOR: haproxy: Add an command option to disable data fast-forward

The -dF option can now be used to disable data fast-forward. It does the
same than the global option "tune.fast-forward off". Some reg-tests may rely
on this optim. To detect the feature and skip such script, the following
vtest command must be used:

  feature cmd "$HAPROXY_PROGRAM -cc '!(globa.tune & GTUNE_NO_FAST_FWD)'"

2 years agoMINOR: global: Add an option to disable the data fast-forward
Christopher Faulet [Tue, 14 Feb 2023 14:37:14 +0000 (15:37 +0100)] 
MINOR: global: Add an option to disable the data fast-forward

The new global option "tune.fast-forward" can be set to "off" to disable the
data fast-forward. It is an debug option, thus it is internally marked as
experimental. The directive "expose-experimental-directives" must be set
first to use this one. By default, the data fast-forward is enable.

It could be usefull to force to wake the stream up when data are
received. To be sure, evreything works fine in this case. The data
fast-forward is an optim. It must work without it. But some code may rely on
the fact the stream will not be woken up. With this option, it is possible
to spot some hidden bugs.

2 years agoBUG/MEDIUM: stconn: Don't rearm the read expiration date if EOI was reached
Christopher Faulet [Tue, 14 Feb 2023 10:01:51 +0000 (11:01 +0100)] 
BUG/MEDIUM: stconn: Don't rearm the read expiration date if EOI was reached

At the stream level, the read expiration date is unset if a shutr was
received but not if the end of input was reached. If we know no more data
are excpected, there is no reason to let the read expiration date armed,
except to respect clientfin/serverfin timeout on some circumstances.

This patch could slowly be backported as far as 2.2.

2 years agoBUG/MEDIUM: http-ana: Detect closed SC on opposite side during body forwarding
Christopher Faulet [Tue, 14 Feb 2023 09:48:02 +0000 (10:48 +0100)] 
BUG/MEDIUM: http-ana: Detect closed SC on opposite side during body forwarding

During the payload forwarding, since the commit f2b02cfd9 ("MAJOR: http-ana:
Review error handling during HTTP payload forwarding"), when an error
occurred on one side, we don't rely anymore on a specific HTTP message state
to detect it on the other side. However, nothing was added to detect the
error. Thus, when this happens, a spinning loop may be experienced and an
abort because of the watchdog.

To fix the bug, we must detect the opposite side is closed by checking the
opposite SC state. Concretly, in http_end_request() and http_end_response(),
we wait for the other side iff the HTTP message state is lower to
HTTP_MSG_DONE (the message is not finished) and the SC state is not
SC_ST_CLO (the opposite side is not closed). In these function, we don't
care if there was an error on the opposite side. We only take care to detect
when we must stop waiting the other side.

This patch should fix the issue #2042. No backport needed.

2 years agoBUG/MINOR: config: crt-list keywords mistaken for bind ssl keywords
William Lallemand [Mon, 13 Feb 2023 14:24:01 +0000 (15:24 +0100)] 
BUG/MINOR: config: crt-list keywords mistaken for bind ssl keywords

This patch fixes an issue in the "-dK" keywords dumper, which was
mistakenly displaying the "crt-list" keywords for "bind ssl" keywords.

The patch fixes the issue by dumping the "crt-list" keywords in its own
section, and dumping the "bind" keywords which are in the "SSL" scope
with a "bind ssl" prefix.

This commit depends on the previous "MINOR: ssl: rename confusing
ssl_bind_kws" commit.

Must be backported in 2.6.

Diff of the `./haproxy -dKall -q -c -f /dev/null` output before and
after the patch in 2.8-dev4:

     | @@ -190,30 +190,9 @@ listen
     |   use-fcgi-app
     |   bind <addr> accept-netscaler-cip +1
     |   bind <addr> accept-proxy
     | - bind <addr> allow-0rtt
     | - bind <addr> alpn +1
     |   bind <addr> backlog +1
     | - bind <addr> ca-file +1
     | - bind <addr> ca-ignore-err +1
     | - bind <addr> ca-sign-file +1
     | - bind <addr> ca-sign-pass +1
     | - bind <addr> ca-verify-file +1
     | - bind <addr> ciphers +1
     | - bind <addr> ciphersuites +1
     | - bind <addr> crl-file +1
     | - bind <addr> crt +1
     | - bind <addr> crt-ignore-err +1
     | - bind <addr> crt-list +1
     | - bind <addr> curves +1
     |   bind <addr> defer-accept
     | - bind <addr> ecdhe +1
     |   bind <addr> expose-fd +1
     | - bind <addr> force-sslv3
     | - bind <addr> force-tlsv10
     | - bind <addr> force-tlsv11
     | - bind <addr> force-tlsv12
     | - bind <addr> force-tlsv13
     | - bind <addr> generate-certificates
     |   bind <addr> gid +1
     |   bind <addr> group +1
     |   bind <addr> id +1
     | @@ -225,48 +204,52 @@ listen
     |   bind <addr> name +1
     |   bind <addr> namespace +1
     |   bind <addr> nice +1
     | - bind <addr> no-ca-names
     | - bind <addr> no-sslv3
     | - bind <addr> no-tls-tickets
     | - bind <addr> no-tlsv10
     | - bind <addr> no-tlsv11
     | - bind <addr> no-tlsv12
     | - bind <addr> no-tlsv13
     | - bind <addr> npn +1
     | - bind <addr> prefer-client-ciphers
     |   bind <addr> process +1
     |   bind <addr> proto +1
     |   bind <addr> severity-output +1
     |   bind <addr> shards +1
     | - bind <addr> ssl
     | - bind <addr> ssl-max-ver +1
     | - bind <addr> ssl-min-ver +1
     | - bind <addr> strict-sni
     |   bind <addr> tcp-ut +1
     |   bind <addr> tfo
     |   bind <addr> thread +1
     | - bind <addr> tls-ticket-keys +1
     |   bind <addr> transparent
     |   bind <addr> uid +1
     |   bind <addr> user +1
     |   bind <addr> v4v6
     |   bind <addr> v6only
     | - bind <addr> verify +1
     |   bind <addr> ssl allow-0rtt
     |   bind <addr> ssl alpn +1
     |   bind <addr> ssl ca-file +1
     | + bind <addr> ssl ca-ignore-err +1
     | + bind <addr> ssl ca-sign-file +1
     | + bind <addr> ssl ca-sign-pass +1
     |   bind <addr> ssl ca-verify-file +1
     |   bind <addr> ssl ciphers +1
     |   bind <addr> ssl ciphersuites +1
     |   bind <addr> ssl crl-file +1
     | + bind <addr> ssl crt +1
     | + bind <addr> ssl crt-ignore-err +1
     | + bind <addr> ssl crt-list +1
     |   bind <addr> ssl curves +1
     |   bind <addr> ssl ecdhe +1
     | + bind <addr> ssl force-sslv3
     | + bind <addr> ssl force-tlsv10
     | + bind <addr> ssl force-tlsv11
     | + bind <addr> ssl force-tlsv12
     | + bind <addr> ssl force-tlsv13
     | + bind <addr> ssl generate-certificates
     |   bind <addr> ssl no-ca-names
     | + bind <addr> ssl no-sslv3
     | + bind <addr> ssl no-tls-tickets
     | + bind <addr> ssl no-tlsv10
     | + bind <addr> ssl no-tlsv11
     | + bind <addr> ssl no-tlsv12
     | + bind <addr> ssl no-tlsv13
     |   bind <addr> ssl npn +1
     | - bind <addr> ssl ocsp-update +1
     | + bind <addr> ssl prefer-client-ciphers
     |   bind <addr> ssl ssl-max-ver +1
     |   bind <addr> ssl ssl-min-ver +1
     | + bind <addr> ssl strict-sni
     | + bind <addr> ssl tls-ticket-keys +1
     |   bind <addr> ssl verify +1
     |   server <name> <addr> addr +1
     |   server <name> <addr> agent-addr +1
     | @@ -591,6 +574,23 @@ listen
     |   http-after-response unset-var*
     |  userlist
     |  peers
     | +crt-list
     | + allow-0rtt
     | + alpn +1
     | + ca-file +1
     | + ca-verify-file +1
     | + ciphers +1
     | + ciphersuites +1
     | + crl-file +1
     | + curves +1
     | + ecdhe +1
     | + no-ca-names
     | + npn +1
     | + ocsp-update +1
     | + ssl-max-ver +1
     | + ssl-min-ver +1
     | + verify +1
     |  # List of registered CLI keywords:
     |  @!<pid> [MASTER]
     |  @<relative pid> [MASTER]

2 years agoMINOR: ssl: rename confusing ssl_bind_kws
William Lallemand [Mon, 13 Feb 2023 09:58:13 +0000 (10:58 +0100)] 
MINOR: ssl: rename confusing ssl_bind_kws

The ssl_bind_kw structure is exclusively used for crt-list keyword, it
must be named otherwise to remove the confusion.

The structure was renamed ssl_crtlist_kws.

2 years ago[RELEASE] Released version 2.8-dev4 v2.8-dev4
Willy Tarreau [Tue, 14 Feb 2023 15:55:17 +0000 (16:55 +0100)] 
[RELEASE] Released version 2.8-dev4

Released version 2.8-dev4 with the following main changes :
    - BUG/MINOR: stats: fix source buffer size for http dump
    - BUG/MEDIUM: stats: fix resolvers dump
    - BUG/MINOR: stats: fix ctx->field update in stats_dump_proxy_to_buffer()
    - BUG/MINOR: stats: fix show stats field ctx for servers
    - BUG/MINOR: stats: fix STAT_STARTED behavior with full htx
    - MINOR: quic: Update version_information transport parameter to draft-14
    - BUG/MINOR: stats: Prevent HTTP "other sessions" counter underflows
    - BUG/MEDIUM: thread: fix extraneous shift in the thread_set parser
    - BUG/MEDIUM: listener/thread: bypass shards setting on failed thread resolution
    - BUG/MINOR: ssl/crt-list: warn when a line is malformated
    - BUG/MEDIUM: stick-table: do not leave entries in end of window during purge
    - BUG/MINOR: clock: do not mix wall-clock and monotonic time in uptime calculation
    - BUG/MEDIUM: cache: use the correct time reference when comparing dates
    - MEDIUM: clock: force internal time to wrap early after boot
    - BUILD: ssl/ocsp: ssl_ocsp-t.h depends on ssl_sock-t.h
    - MINOR: ssl/ocsp: add a function to check the OCSP update configuration
    - MINOR: cfgparse/server: move (min/max)conn postparsing logic into dedicated function
    - BUG/MINOR: server/add: ensure minconn/maxconn consistency when adding server
    - BUG/MEDIUM: stconn: Schedule a shutw on shutr if data must be sent first
    - BUG/MEDIUM: quic: fix crash when "option nolinger" is set in the frontend
    - MINOR: quic: implement a basic "show quic" CLI handler
    - MINOR: quic: display CIDs and state in "show quic"
    - MINOR: quic: display socket info on "show quic"
    - MINOR: quic: display infos about various encryption level on "show quic"
    - MINOR: quic: display Tx stream info on "show quic"
    - MINOR: quic: filter closing conn on "show quic"
    - BUG/MINOR: quic: fix filtering of closing connections on "show quic"
    - BUG/MEDIUM: stconn: Don't needlessly wake the stream on send during fast-forward
    - BUG/MINOR: quic: fix type bug on "show quic" for 32-bits arch
    - BUG/MINOR: mworker: fix uptime for master process
    - BUG/MINOR: clock/stats: also use start_time not start_date in HTML info
    - BUG/MEDIUM: stconn: stop to enable/disable reads from streams via si_update_rx
    - BUG/MEDIUM: quic: Buffer overflow when looking through QUIC CLI keyword list
    - DOC: proxy-protocol: fix wrong byte in provided example
    - MINOR: ssl-ckch: Stop to test CF_WRITE_ERROR to commit CA/CRL file
    - MINOR: bwlim: Remove useless test on CF_READ_ERROR to detect the last packet
    - BUG/MINOR: http-ana: Fix condition to set LAST termination flag
    - BUG/MINOR: mux-h1: Don't report an H1C error on client timeout
    - BUG/MEDIUM: spoe: Don't set the default traget for the SPOE agent frontend
    - BUG/MINOR: quic: Wrong datagram dispatch because of qc_check_dcid()
    - BUG/CRITICAL: http: properly reject empty http header field names

2 years agoBUG/CRITICAL: http: properly reject empty http header field names
Willy Tarreau [Thu, 9 Feb 2023 20:36:54 +0000 (21:36 +0100)] 
BUG/CRITICAL: http: properly reject empty http header field names

The HTTP header parsers surprizingly accepts empty header field names,
and this is a leftover from the original code that was agnostic to this.

When muxes were introduced, for H2 first, the HPACK decompressor needed
to feed headers lists, and since empty header names were strictly
forbidden by the protocol, the lists of headers were purposely designed
to be terminated by an empty header field name (a principle that is
similar to H1's empty line termination). This principle was preserved
and generalized to other protocols migrated to muxes (H1/FCGI/H3 etc)
without anyone ever noticing that the H1 parser was still able to deliver
empty header field names to this list. In addition to this it turns out
that the HPACK decompressor, despite a comment in the code, may
successfully decompress an empty header field name, and this mistake
was propagated to the QPACK decompressor as well.

The impact is that an empty header field name may be used to truncate
the list of headers and thus make some headers disappear. While for
H2/H3 the impact is limited as haproxy sees a request with missing
headers, and headers are not used to delimit messages, in the case of
HTTP/1, the impact is significant because the presence (and sometimes
contents) of certain sensitive headers is detected during the parsing.
Thus, some of these headers may be seen, marked as present, their value
extracted, but never delivered to upper layers and obviously not
forwarded to the other side either. This can have for consequence that
certain important header fields such as Connection, Upgrade, Host,
Content-length, Transfer-Encoding etc are possibly seen as different
between what haproxy uses to parse/forward/route and what is observed
in http-request rules and of course, forwarded. One direct consequence
is that it is possible to exploit this property in HTTP/1 to make
affected versions of haproxy forward more data than is advertised on
the other side, and bypass some access controls or routing rules by
crafting extraneous requests.  Note, however, that responses to such
requests will normally not be passed back to the client, but this can
still cause some harm.

This specific risk can be mostly worked around in configuration using
the following rule that will rely on the bug's impact to precisely
detect the inconsistency between the known body size and the one
expected to be advertised to the server (the rule works from 2.0 to
2.8-dev):

  http-request deny if { fc_http_major 1 } !{ req.body_size 0 } !{ req.hdr(content-length) -m found } !{ req.hdr(transfer-encoding) -m found } !{ method CONNECT }

This will exclusively block such carefully crafted requests delivered
over HTTP/1. HTTP/2 and HTTP/3 do not need content-length, and a body
that arrives without being announced with a content-length will be
forwarded using transfer-encoding, hence will not cause discrepancies.
In HAProxy 2.0 in legacy mode ("no option http-use-htx"), this rule will
simply have no effect but will not cause trouble either.

A clean solution would consist in modifying the loops iterating over
these headers lists to check the header name's pointer instead of its
length (since both are zero at the end of the list), but this requires
to touch tens of places and it's very easy to miss one. Functions such
as htx_add_header(), htx_add_trailer(), htx_add_all_headers() would be
good starting points for such a possible future change.

Instead the current fix focuses on blocking empty headers where they
are first inserted, hence in the H1/HPACK/QPACK decoders. One benefit
of the current solution (for H1) is that it allows "show errors" to
report a precise diagnostic when facing such invalid HTTP/1 requests,
with the exact location of the problem and the originating address:

  $ printf "GET / HTTP/1.1\r\nHost: localhost\r\n:empty header\r\n\r\n" | nc 0 8001
  HTTP/1.1 400 Bad request
  Content-length: 90
  Cache-Control: no-cache
  Connection: close
  Content-Type: text/html

  <html><body><h1>400 Bad request</h1>
  Your browser sent an invalid request.
  </body></html>

  $ socat /var/run/haproxy.stat <<< "show errors"
  Total events captured on [10/Feb/2023:16:29:37.530] : 1

  [10/Feb/2023:16:29:34.155] frontend decrypt (#2): invalid request
    backend <NONE> (#-1), server <NONE> (#-1), event #0, src 127.0.0.1:31092
    buffer starts at 0 (including 0 out), 16334 free,
    len 50, wraps at 16336, error at position 33
    H1 connection flags 0x00000000, H1 stream flags 0x00000810
    H1 msg state MSG_HDR_NAME(17), H1 msg flags 0x00001410
    H1 chunk len 0 bytes, H1 body len 0 bytes :

    00000  GET / HTTP/1.1\r\n
    00016  Host: localhost\r\n
    00033  :empty header\r\n
    00048  \r\n

I want to address sincere and warm thanks for their great work to the
team composed of the following security researchers who found the issue
together and reported it: Bahruz Jabiyev, Anthony Gavazzi, and Engin
Kirda from Northeastern University, Kaan Onarlioglu from Akamai
Technologies, Adi Peleg and Harvey Tuch from Google. And kudos to Amaury
Denoyelle from HAProxy Technologies for spotting that the HPACK and
QPACK decoders would let this pass despite the comment explicitly
saying otherwise.

This fix must be backported as far as 2.0. The QPACK changes can be
dropped before 2.6. In 2.0 there is also the equivalent code for legacy
mode, which doesn't suffer from the list truncation, but it would better
be fixed regardless.

CVE-2023-25725 was assigned to this issue.

2 years agoBUG/MINOR: quic: Wrong datagram dispatch because of qc_check_dcid()
Frédéric Lécaille [Mon, 13 Feb 2023 15:14:24 +0000 (16:14 +0100)] 
BUG/MINOR: quic: Wrong datagram dispatch because of qc_check_dcid()

There was a parenthesis placed in the wrong place for a memcmp().
As a consequence, clients could not reuse a UDP address for a new connection.

Must be backported to 2.7.

2 years agoBUG/MEDIUM: spoe: Don't set the default traget for the SPOE agent frontend
Christopher Faulet [Mon, 13 Feb 2023 10:37:26 +0000 (11:37 +0100)] 
BUG/MEDIUM: spoe: Don't set the default traget for the SPOE agent frontend

The commit d5983cef8 ("MINOR: listener: remove the useless ->default_target
field") revealed a bug in the SPOE. No default-target must be defined for
the SPOE agent frontend. SPOE applets are used on the frontend side and a
TCP connection is established on the backend side.

Because of this bug, since the commit above, the stream target is set to the
SPOE applet instead of the backend connection, leading to a spinning loop on
the applet when it is released because are unable to close the backend side.

This patch should fix the issue #2040. It only affects the 2.8-DEV but to
avoid any future bug, it should be backported to all stable versions.

2 years agoBUG/MINOR: mux-h1: Don't report an H1C error on client timeout
Christopher Faulet [Mon, 6 Feb 2023 17:14:47 +0000 (18:14 +0100)] 
BUG/MINOR: mux-h1: Don't report an H1C error on client timeout

When a client timeout is reported by the H1 mux, it is not an error but an
abort. Thus, H1C_F_ERROR flag must not be set. It is espacially important to
not inhibit the send. Because of this bug, a 408-Request-time-out is
reported in logs but the error message is not sent to the client.

This patch must be backported to 2.7.

2 years agoBUG/MINOR: http-ana: Fix condition to set LAST termination flag
Christopher Faulet [Thu, 26 Jan 2023 18:02:07 +0000 (19:02 +0100)] 
BUG/MINOR: http-ana: Fix condition to set LAST termination flag

We should not report LAST data in log if the response is in TUNNEL mode on
client close/timeout because there is no way to be sure it is the last
data. It means, it can only be reported in DONE, CLOSING or CLOSE states.

No backport needed.

2 years agoMINOR: bwlim: Remove useless test on CF_READ_ERROR to detect the last packet
Christopher Faulet [Thu, 26 Jan 2023 15:11:02 +0000 (16:11 +0100)] 
MINOR: bwlim: Remove useless test on CF_READ_ERROR to detect the last packet

There is already a test on CF_EOI and CF_SHUTR. The last one is always set
when a read error is reported. Thus there is no reason to check
CF_READ_ERROR.

2 years agoMINOR: ssl-ckch: Stop to test CF_WRITE_ERROR to commit CA/CRL file
Christopher Faulet [Thu, 26 Jan 2023 07:03:39 +0000 (08:03 +0100)] 
MINOR: ssl-ckch: Stop to test CF_WRITE_ERROR to commit CA/CRL file

This change was performed on all applet I/O handlers but one was missed. In
the CLI I/O handler used to commit a CA/CRL file, we can remove the test on
CF_WRITE_ERROR because there is already a test on CF_SHUTW.

2 years agoDOC: proxy-protocol: fix wrong byte in provided example
Willy Tarreau [Sun, 12 Feb 2023 08:26:48 +0000 (09:26 +0100)] 
DOC: proxy-protocol: fix wrong byte in provided example

There was a mistake in the example of proxy-proto frame
provided, it cannot end with 0x02 but only 0x20 or 0x21
since the version is in the upper 4 bits and the lower ones
are 0 for LOCAL or 1 for PROXY, hence the example should be:

  \x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x20

Thanks to Bram Grit for reporting this mistake.

2 years agoBUG/MEDIUM: quic: Buffer overflow when looking through QUIC CLI keyword list
Frédéric Lécaille [Sat, 11 Feb 2023 19:24:42 +0000 (20:24 +0100)] 
BUG/MEDIUM: quic: Buffer overflow when looking through QUIC CLI keyword list

This has been detected by libasan as follows:

=================================================================
==3170559==ERROR: AddressSanitizer: global-buffer-overflow on address 0x55cf77faad08 at pc 0x55cf77a87370 bp 0x7ffc01bdba70 sp 0x7ffc01bdba68
READ of size 8 at 0x55cf77faad08 thread T0
    #0 0x55cf77a8736f in cli_find_kw src/cli.c:335
    #1 0x55cf77a8a9bb in cli_parse_request src/cli.c:792
    #2 0x55cf77a8c385 in cli_io_handler src/cli.c:1024
    #3 0x55cf77d19ca1 in task_run_applet src/applet.c:245
    #4 0x55cf77c0b6ba in run_tasks_from_lists src/task.c:634
    #5 0x55cf77c0cf16 in process_runnable_tasks src/task.c:861
    #6 0x55cf77b48425 in run_poll_loop src/haproxy.c:2934
    #7 0x55cf77b491cf in run_thread_poll_loop src/haproxy.c:3127
    #8 0x55cf77b4bef2 in main src/haproxy.c:3783
    #9 0x7fb8b0693d09 in __libc_start_main ../csu/libc-start.c:308
    #10 0x55cf7764f4c9 in _start (/home/flecaille/src/haproxy-untouched/haproxy+0x1914c9)

0x55cf77faad08 is located 0 bytes to the right of global variable 'cli_kws' defined in 'src/quic_conn.c:7834:27' (0x55cf77faaca0) of size 104
SUMMARY: AddressSanitizer: global-buffer-overflow src/cli.c:335 in cli_find_kw
Shadow bytes around the buggy address:

According to cli_find_kw() code and cli_kw_list struct definition, the second
member of this structure ->kw[] must be a null-terminated array.
Add a last element with default initializers to <cli_kws> global variable which
is impacted by this bug.

This bug arrived with this commit:
   15c74702d MINOR: quic: implement a basic "show quic" CLI handler

Must be backported to 2.7 where this previous commit has been already
backported.

2 years agoBUG/MEDIUM: stconn: stop to enable/disable reads from streams via si_update_rx
Christopher Faulet [Fri, 10 Feb 2023 16:37:11 +0000 (17:37 +0100)] 
BUG/MEDIUM: stconn: stop to enable/disable reads from streams via si_update_rx

It is not really a bug because it does not fix any known issue. And it is
flagged as MEDIUM because it is sensitive. But if there are some extra calls
to process_stream(), it can be an issue because, in si_update_rx(), we may
disable reading for the SC when outgoing data are blocked in the input
channel. But it is not really the process_stream() job to take care of
that. This may block data receipt.

It is an old code, mainly here to avoid wakeup in loop on the stats
applet. Today, it seems useless and can lead to bugs. An endpoint is
responsible to block the SC if it waits for some room and the opposite
endpoint is responsible to unblock it when some data are sent. The stream
should not interfere on this part.

This patch could be backported to 2.7 after a period of observation. And it
should only be backported to lower versions if an issue is reported.

2 years agoBUG/MINOR: clock/stats: also use start_time not start_date in HTML info
Willy Tarreau [Fri, 10 Feb 2023 15:53:35 +0000 (16:53 +0100)] 
BUG/MINOR: clock/stats: also use start_time not start_date in HTML info

For an unknown reason in the change of uptime calculation for the HTML
page didn't make it to commit 6093ba47c ("BUG/MINOR: clock: do not mix
wall-clock and monotonic time in uptime calculation"). Let's address it
as well otherwise the stats page will display an incorrect uptime.

No backport needed unless the patch above is backported.

2 years agoBUG/MINOR: mworker: fix uptime for master process
Amaury Denoyelle [Fri, 10 Feb 2023 14:25:45 +0000 (15:25 +0100)] 
BUG/MINOR: mworker: fix uptime for master process

Uptime calculation for master process was incorrect as it used
<start_date> as its timestamp base time. Fix this by using the scheduler
time <start_time> for this.

The impact of this bug is minor as timestamp base time is only used for
"show proc" CLI output. it was highlighted by the following commit.
which caused a negative value to be displayed for the master process
uptime on "show proc" output.

  28360dc53f715c497fff822523f92769d8b1627d
  MEDIUM: clock: force internal time to wrap early after boot

This should be backported up to 2.0.

2 years agoBUG/MINOR: quic: fix type bug on "show quic" for 32-bits arch
Amaury Denoyelle [Fri, 10 Feb 2023 08:25:22 +0000 (09:25 +0100)] 
BUG/MINOR: quic: fix type bug on "show quic" for 32-bits arch

Incorrect printf format specifier "%lu" was used on "show quic" handler
for uint64_t. This breaks build on 32-bits architecture. To fix this
portability issue, force an explicit cast to unsigned long long with
"%llu" specifier.

This must be backported up to 2.7.

2 years agoBUG/MEDIUM: stconn: Don't needlessly wake the stream on send during fast-forward
Christopher Faulet [Thu, 9 Feb 2023 13:14:38 +0000 (14:14 +0100)] 
BUG/MEDIUM: stconn: Don't needlessly wake the stream on send during fast-forward

With a connection, when data are received, if these data are sent to the
opposite side because the fast-forwarding is possible, the stream may be
woken up on some conditions (at the end of sc_app_chk_snd_conn()):

  * The channel is shut for write
  * The SC is not in the "established" state
  * The stream must explicitly be woken up on write and all data was sent
  * The connection was just established.

A bug on the last condition was introduced with the commit d89884153
("MEDIUM: channel: Use CF_WRITE_EVENT instead of CF_WRITE_PARTIAL"). The
stream is now woken up on any write events.

This patch fixes this issue and restores the original behavior. No backport
is needed.

2 years agoBUG/MINOR: quic: fix filtering of closing connections on "show quic"
Amaury Denoyelle [Thu, 9 Feb 2023 17:18:45 +0000 (18:18 +0100)] 
BUG/MINOR: quic: fix filtering of closing connections on "show quic"

Filtering of closing/draining connections on "show quic" was not
properly implemented. This causes the extra argument "all" to display
all connections to be without effect. This patch fixes this and restores
the output of all connections.

This must be backported up to 2.7.

2 years agoMINOR: quic: filter closing conn on "show quic"
Amaury Denoyelle [Wed, 1 Feb 2023 16:31:02 +0000 (17:31 +0100)] 
MINOR: quic: filter closing conn on "show quic"

Reduce default "show quic" output by masking connection on
closing/draing state due to a CONNECTION_CLOSE emission/reception. These
connections can still be displayed using the special argument "all".

This should be backported up to 2.7.

2 years agoMINOR: quic: display Tx stream info on "show quic"
Amaury Denoyelle [Wed, 1 Feb 2023 16:05:36 +0000 (17:05 +0100)] 
MINOR: quic: display Tx stream info on "show quic"

Complete "show quic" handler by displaying information about
quic_stream_desc entries. These structures are used to emit stream data
and store them until acknowledgment is received.

This should be backported up to 2.7.

2 years agoMINOR: quic: display infos about various encryption level on "show quic"
Amaury Denoyelle [Wed, 1 Feb 2023 16:05:10 +0000 (17:05 +0100)] 
MINOR: quic: display infos about various encryption level on "show quic"

Complete "show quic" handler by displaying various information related
to each encryption level and packet number space. Most notably, ack
ranges and bytes in flight are present to help debug retransmission
issues.

This should be backported up to 2.7.

2 years agoMINOR: quic: display socket info on "show quic"
Amaury Denoyelle [Wed, 1 Feb 2023 16:04:26 +0000 (17:04 +0100)] 
MINOR: quic: display socket info on "show quic"

Complete "show quic" handler by displaying information related to the
quic_conn owned socket. First, the FD is printed, followed by the
address of the local and remote endpoint.

This should be backported up to 2.7.

2 years agoMINOR: quic: display CIDs and state in "show quic"
Amaury Denoyelle [Wed, 1 Feb 2023 10:54:43 +0000 (11:54 +0100)] 
MINOR: quic: display CIDs and state in "show quic"

Complete "show quic" handler. Source and destination CIDs are printed
for every connection. This is complete by a state info to reflect if
handshake is completed and if a CONNECTION_CLOSE has been emitted or
received and the allocation status of the attached MUX. Finally the idle
timer expiration is also printed.

This should be backported up to 2.7.

2 years agoMINOR: quic: implement a basic "show quic" CLI handler
Amaury Denoyelle [Wed, 1 Feb 2023 09:18:26 +0000 (10:18 +0100)] 
MINOR: quic: implement a basic "show quic" CLI handler

Implement a basic "show quic" CLI handler. This command will be useful
to display various information on all the active QUIC frontend
connections.

This work is heavily inspired by "show sess". Most notably, a global
list of quic_conn has been introduced to be able to loop over them. This
list is stored per thread in ha_thread_ctx.

Also add three CLI handlers for "show quic" in order to allocate and
free the command context. The dump handler runs on thread isolation.
Each quic_conn is referenced using a back-ref to handle deletion during
handler yielding.

For the moment, only a list of raw quic_conn pointers is displayed. The
handler will be completed over time with more information as needed.

This should be backported up to 2.7.

2 years agoBUG/MEDIUM: quic: fix crash when "option nolinger" is set in the frontend
Willy Tarreau [Thu, 9 Feb 2023 16:53:41 +0000 (17:53 +0100)] 
BUG/MEDIUM: quic: fix crash when "option nolinger" is set in the frontend

Commit 0aba11e9e ("MINOR: quic: remove unnecessary quic_session_accept()")
overlooked one problem, in session_accept_fd() at the end, there's a bunch
of FD-specific stuff that either sets up or resets the socket at the TCP
level. The tests are mostly performed for AF_INET/AF_INET6 families but
they're only for one part (i.e. to avoid setting up TCP options on UNIX
sockets). Other pieces continue to configure the socket regardless of its
family. All of this directly acts on the FD, which is not correct since
the FD is not valid here, it corresponds to the QUIC handle. The issue
is much more visible when "option nolinger" is enabled in the frontend,
because the access to fdatb[cfd].state immediately crashes on the first
connection, as can be seen in github issue #2030.

This patch bypasses this setup for FD-less connections, such as QUIC.
However some of them could definitely be relevant to the QUIC stack, or
even to UNIX sockets sometimes. A better long-term solution would consist
in implementing a setsockopt() equivalent at the protocol layer that would
be used to configure the socket, either the FD or the QUIC conn depending
on the case. Some of them would not always be implemented but that would
allow to unify all this code.

This fix must be backported everywhere the commit above is backported,
namely 2.6 and 2.7.

Thanks to github user @twomoses for the nicely detailed report.

2 years agoBUG/MEDIUM: stconn: Schedule a shutw on shutr if data must be sent first
Christopher Faulet [Wed, 8 Feb 2023 15:18:48 +0000 (16:18 +0100)] 
BUG/MEDIUM: stconn: Schedule a shutw on shutr if data must be sent first

The commit 7f59d68fe ("BUG/MEDIIM: stconn: Flush output data before
forwarding close to write side") introduced a regression. When the read side
is closed, the close is not forwarded to the write side if there are some
pending outgoind data. The idea is to foward data first and the close the
write side. However, when fast-forwarding is enabled and last data block is
received with the read0, the close is never forwarded.

We cannot revert the commit above because it really fix an issue. However,
we can schedule the shutdown for write by setting CF_SHUTW_NOW flag on the
write side. Indeed, it is the purpose of this flag.

To not replicate ugly and hardly maintainable code block at different places
in stconn.c, an helper function is used. Thus, sc_cond_forward_shutw() must
be called to know if the close can be fowarded or not. It returns 1 if it is
possible. In this case, the caller is responsible to forward the close to
the write side. Otherwise, if the close cannot be forwarded, 0 is
returned. It happens when it should not be performed at all. Or when it
should only be delayed, waiting for the input channel to be flushed. In this
last case, the CF_SHUTW_NOW flag is set in the output channel.

This patch should fix the issue #2033. It must be backported with the commit
above, thus at least as far as 2.2.

2 years agoBUG/MINOR: server/add: ensure minconn/maxconn consistency when adding server
Aurelien DARRAGON [Wed, 8 Feb 2023 10:55:08 +0000 (11:55 +0100)] 
BUG/MINOR: server/add: ensure minconn/maxconn consistency when adding server

When a new server was added through the cli using "server add" command,
the maxconn/minconn consistency check historically implemented in
check_config_validity() for static servers was missing.

As a result, when adding a server with the maxconn parameter without the
minconn set, the server was unable to handle any connection because
srv_dynamic_maxconn() would always return 0.

Consider the following reproducer:

    |  global
    |    stats socket /tmp/ha.sock mode 660 level admin expose-fd listeners
    |
    |  defaults
    |  timeout client 5s
    |  timeout server 5s
    |  timeout connect 5s
    |
    |  frontend test
    |    mode http
    |    bind *:8081
    |    use_backend farm
    |
    |  listen dummyok
    |    bind localhost:18999
    |    mode http
    |    http-request return status 200 hdr test "ok"
    |
    |  backend farm
    |    mode http

Start haproxy and perform the following :

  echo "add server farm/t1 127.0.0.1:18999 maxconn 100" | nc -U /tmp/ha.sock
  echo "enable server farm/t1" | nc -U /tmp/ha.sock

  curl localhost:8081 # -> 503 after 5s connect timeout

Thanks to ("MINOR: cfgparse/server: move (min/max)conn postparsing logic into
dedicated function"), we are now able to perform the consistency check after
the new dynamic server has been parsed.
This is enough to fix the issue documented here that was reported by
Thomas Pedoussaut on the ML.

This commit depends on:
 - ("MINOR: cfgparse/server: move (min/max)conn postparsing logic into
     dedicated function")

It must be backported to 2.6 and 2.7

2 years agoMINOR: cfgparse/server: move (min/max)conn postparsing logic into dedicated function
Aurelien DARRAGON [Wed, 8 Feb 2023 10:49:02 +0000 (11:49 +0100)] 
MINOR: cfgparse/server: move (min/max)conn postparsing logic into dedicated function

In check_config_validity() function, we performed some consistency checks to
adjust minconn/maxconn attributes for each declared server.

We move this logic into a dedicated function named srv_minmax_conn_apply()
to be able to perform those checks later in the process life when needed
(ie: dynamic servers)

2 years agoMINOR: ssl/ocsp: add a function to check the OCSP update configuration
William Lallemand [Tue, 7 Feb 2023 17:38:05 +0000 (18:38 +0100)] 
MINOR: ssl/ocsp: add a function to check the OCSP update configuration

Deduplicate the code which checks the OCSP update in the ckch_store and
in the crtlist_entry.

Also, jump immediatly to error handling when the ERR_FATAL is catched.

2 years agoBUILD: ssl/ocsp: ssl_ocsp-t.h depends on ssl_sock-t.h
William Lallemand [Tue, 7 Feb 2023 17:28:30 +0000 (18:28 +0100)] 
BUILD: ssl/ocsp: ssl_ocsp-t.h depends on ssl_sock-t.h

ssl_ocsp-t.h uses SSL_SOCK_NUM_KEYTYPES which is defined in
ssl_sock-t.h.

No backport needed.

2 years agoMEDIUM: clock: force internal time to wrap early after boot
Willy Tarreau [Tue, 7 Feb 2023 13:44:44 +0000 (14:44 +0100)] 
MEDIUM: clock: force internal time to wrap early after boot

GH issue #2034 clearly indicates yet another case of time roll-over
that went badly. Issues that happen only once every 50 days are hard
to detect and debug, and are usually reported more or less synchronized
from multiple sources. This patch finally does what had long been planned
but never done yet, which is to force the time to wrap early after boot
so that any such remaining issue can be spotted quicker. The margin delay
here is 20s (it may be changed by setting BOOT_TIME_WRAP_SEC to another
value). This value seems sufficient to permit failed health checks to
succeed and traffic to come in and possibly start to update some time
stamps (accept dates in logs, freq counters, stick-tables expiration
dates etc).

It could theoretically be helpful to have this in 2.7, but as can be
seen with the two patches below, we've already had incorrect use cases
of the internal monotonic time when the wall-clock one was needed, so
we could expect to detect other ones in the future. Note that this will
*not* induce bugs, it will only make them happen much faster (i.e. no
need to wait for 50 days before seeing them). If it were to eventually
be backported, these two previous patches must also be backported:

    BUG/MINOR: clock: use distinct wall-clock and monotonic start dates
    BUG/MEDIUM: cache: use the correct time reference when comparing dates

2 years agoBUG/MEDIUM: cache: use the correct time reference when comparing dates
Willy Tarreau [Tue, 7 Feb 2023 14:22:41 +0000 (15:22 +0100)] 
BUG/MEDIUM: cache: use the correct time reference when comparing dates

The cache makes use of dates advertised by external components, such
as "last-modified" or "date". As such these are wall-clock dates, and
not internal dates. However, all comparisons are mistakenly made based
on the internal monotonic date which is designed to drift from the wall
clock one in order to catch up with stolen time (which can sometimes be
intense in VMs). As such after some run time some objects may fail to
validate or fail to expire depending on the direction of the drift. This
is particularly visible when applying an offset to the internal time to
force it to wrap soon after startup, as it will be shifted up to 49.7
days in the future depending on the current date; what happens in this
case is that the reg-test "cache_expires.vtc" fails on the 3rd test by
returning stale contents from the cache at the date of this commit.

It is really important that all external dates are compared against
"date" and not "now" for this reason.

This fix needs to be backported to all versions.

2 years agoBUG/MINOR: clock: do not mix wall-clock and monotonic time in uptime calculation
Willy Tarreau [Tue, 7 Feb 2023 14:52:14 +0000 (15:52 +0100)] 
BUG/MINOR: clock: do not mix wall-clock and monotonic time in uptime calculation

We've had a start date even before the internal monotonic clock existed,
but once the monotonic clock was added, the start date was not updated
to distinguish the wall clock time units and the internal monotonic time
units. The distinction is important because both clocks do not necessarily
progress at the same speed. The very rare occurrences of the wall-clock
date are essentially for human consumption and communication with third
parties (e.g. report the start date in "show info" for monitoring
purposes). However currently this one is also used to measure the distance
to "now" as being the process' uptime. This is actually not correct. It
only works because for now the two dates are initialized at the exact
same instant at boot but could still be wrong if the system's date shows
a big jump backwards during startup for example. In addition the current
situation prevents us from enforcing an abritrary offset at boot to reveal
some heisenbugs.

This patch adds a new "start_time" at boot that is set from "now" and is
used in uptime calculations. "start_date" instead is now set from "date"
and will always reflect the system date for human consumption (e.g. in
"show info"). This way we're now sure that any drift of the internal
clock relative to the system date will not impact the reported uptime.

This could possibly be backported though it's unlikely that anyone has
ever noticed the problem.

2 years agoBUG/MEDIUM: stick-table: do not leave entries in end of window during purge
Aleksey Ponomaryov [Tue, 7 Feb 2023 18:27:06 +0000 (19:27 +0100)] 
BUG/MEDIUM: stick-table: do not leave entries in end of window during purge

At some moments expired stick table records stop being removed. This
happens when the internal time wraps around the 32-bit limit, or every
49.7 days. What precisely happens is that some elements that are collected
close to the end of the time window (2^32 - table's "expire" setting)
might have been updated and will be requeued further, at the beginning
of the next window. Here, three bad situations happen:

  - the incorrect integer-based comparison that is not aware of wrapping
    will result in the scan to restart from the freshly requeued element,
    skipping all those at the end of the window. The net effect of this
    is that at each wakeup of the expiration task, only one element from
    the end of the window will be expired, and other ones will remain
    there for a very long time, especially if they have to wait for all
    the predecessors to be picked one at a time after slow wakeups due
    to a long expiration ; this is what was observed in issue #2034
    making the table fill up and appear as not expiring at all, and it
    seems that issue #2024 reports the same problem at the same moment
    (since such issues happen for everyone roughly at the same time
    when the clock doesn't drift too much).

  - the elements that were placed at the beginning of the next window
    are skipped as well for as long as there are refreshed entries at
    the end of the previous window, so these ones participate to filling
    the table as well. This is cause by the restart from the current,
    updated node that is generally placed after most other less recently
    updated elements.

  - once the last element at the end of the window is picked, suddenly
    there is a large amount of expired entries at the beginning of the
    next window that all have to be requeued. If the expiration delay
    is large, the number can be big and it can take a long time, which
    can very likely explain the periodic crashes reported in issue #2025.
    Limiting the batch size as done in commit dfe79251d ("BUG/MEDIUM:
    stick-table: limit the time spent purging old entries") would make
    sense for process_table_expire() as well.

This patch addresses the incorrect tree scan algorithm to make sure that:
  - there's always a next element to compare against, even when dealing
    with the last one in the tree, the first one must be used ;

  - time comparisons used to decide whether to restart from the current
    element use tick_is_lt() as it is the only case where we know the
    current element will be placed before any other one (since the tree
    respects insertion ordering for duplicates)

In order to reproduce the issue, it was found that injecting traffic on
a random key that spans over half of the size of a table whose expiration
is set to 15s while the date is going to wrap in 20s does exhibit an
increase of the table's size 5s after startup, when entries start to be
pushed to the next window. It's more effective when a second load
generator constantly hammers a same key to be certain that none of them
is ready to expire. This doesn't happen anymore after this patch.

This fix needs to be backported to all stable versions. The bug has been
there for as long as the stick tables were introduced in 1.4-dev7 with
commit 3bd697e07 ("[MEDIUM] Add stick table (persistence) management
functions and types"). A cleanup could consists in deduplicating that
code by having process_table_expire() call __stktable_trash_oldest(),
with that one improved to support an optional time check.

2 years agoBUG/MINOR: ssl/crt-list: warn when a line is malformated
William Lallemand [Tue, 7 Feb 2023 16:06:35 +0000 (17:06 +0100)] 
BUG/MINOR: ssl/crt-list: warn when a line is malformated

Display a warning when some text exists between the filename and the
options. This part is completely ignored so if there are filters here,
they were never parsed.

This could be backported in every versions. In the older versions, the
parsing was done in ssl_sock_load_cert_list_file() in ssl_sock.c.

2 years agoBUG/MEDIUM: listener/thread: bypass shards setting on failed thread resolution
Willy Tarreau [Mon, 6 Feb 2023 17:06:14 +0000 (18:06 +0100)] 
BUG/MEDIUM: listener/thread: bypass shards setting on failed thread resolution

Aurélien reported that the BUG_ON(!new_ts.nbgrp) added in 2.8-dev3 by
commit 50440457e ("MEDIUM: config: restrict shards, not bind_conf to one
group each") can trigger on some invalid configs where the thread_set on
the "bind" line couldn't be resolved. The reason is that we still enter
the parsing loop (as it was done previously) and we possibly have no
group to work on (which was the purpose of this assertion). There we
need to bypass all this block on such a condition.

No backport is needed.

2 years agoBUG/MEDIUM: thread: fix extraneous shift in the thread_set parser
Willy Tarreau [Mon, 6 Feb 2023 17:01:50 +0000 (18:01 +0100)] 
BUG/MEDIUM: thread: fix extraneous shift in the thread_set parser

Aurélien reported a bug making a statement such as "thread 2-2" fail for
a config made of exactly 2 threads. What happens is that the parser for
the "thread" keyword scans a range of thread numbers from either 1..64
or 0,-1,-2 for special values, and presets the bit masks accordingly in
the thread set, except that due to the 1..64 range, the shift length must
be reduced by one. Not doing this causes empty masks for single-bit values
that are exactly equal to the number of threads in the group and fails to
properly parse.

No backport is needed as this was introduced in 2.8-dev3 by commit
bef43dfa6 ("MINOR: thread: add a simple thread_set API").

2 years agoBUG/MINOR: stats: Prevent HTTP "other sessions" counter underflows
Frédéric Lécaille [Mon, 6 Feb 2023 08:23:56 +0000 (09:23 +0100)] 
BUG/MINOR: stats: Prevent HTTP "other sessions" counter underflows

Due to multithreading concurrency, it is difficult at this time to figure
out how this counter may become negative. This simple patch only checks this
will never be the case.

This issue arrives with this commit:
 "9969adbcdc MINOR: stats: add by HTTP version cumulated number of sessions and requests"
So, this patch should be backported when the latter has been backported.

2 years agoMINOR: quic: Update version_information transport parameter to draft-14
Frédéric Lécaille [Mon, 6 Feb 2023 10:54:07 +0000 (11:54 +0100)] 
MINOR: quic: Update version_information transport parameter to draft-14

This is necessary to make our stack negotiate the QUIC versions with clients.
(See https://author-tools.ietf.org/iddiff?url1=draft-ietf-quic-version-negotiation-13&url2=draft-ietf-quic-version-negotiation-14&difftype=--html)

Must be backported to 2.7.

2 years agoBUG/MINOR: stats: fix STAT_STARTED behavior with full htx
Aurelien DARRAGON [Thu, 2 Feb 2023 18:01:02 +0000 (19:01 +0100)] 
BUG/MINOR: stats: fix STAT_STARTED behavior with full htx

When stats_putchk() fails to peform the dump because available data space in
htx is less than the number of bytes pending in the dump buffer, we wait
for more room in the htx (ie: sc_need_room()) to retry the dump attempt
on the next applet invocation.

To provide consistent output, we have to make sure that the stat ctx is not
updated (or at least correctly reverted) in case stats_putchk() fails so
that the new dumping attempt behaves just like the previous (failed) one.

STAT_STARTED is not following this logic, the flag is set in
stats_dump_fields_json() as soon as some data is written to the output buffer.

It's done too early: we need to delay this step after the stats_putchk() has
successfully returned if we want to correctly handle the retries attempts.

Because of this, JSON output could suffer from extraneous ',' characters which
could make json parsers unhappy.

For example, this is the kind of errors you could get when using
`python -m json.tool` on such badly formatted outputs:

   "Expecting value: line 1 column 2 (char 1)"

Unfortunately, fixing this means that the flag needs to be enabled at
multiple places, which is what we're doing in this patch.
(in stats_dump_proxy_to_buffer() where stats_dump_one_line() is involved
by underlying stats_dump_{fe,li,sv,be} functions)

Thereby, this raises the need for a cleanup to reduce code duplication around
stats_dump_proxy_to_buffer() function and simplify things a bit.

It could be backported to 2.6 and 2.7

2 years agoBUG/MINOR: stats: fix show stats field ctx for servers
Aurelien DARRAGON [Thu, 2 Feb 2023 17:13:30 +0000 (18:13 +0100)] 
BUG/MINOR: stats: fix show stats field ctx for servers

In ("MINOR: stats: introduce stats field ctx"), we forgot
to apply the patch to servers.

This prevents "BUG/MINOR: stats: fix show stat json buffer limitation"
from working with servers dump.

We're adding the missing part related to servers dump.

This commit should be backported with the aforementioned commits.

2 years agoBUG/MINOR: stats: fix ctx->field update in stats_dump_proxy_to_buffer()
Aurelien DARRAGON [Fri, 3 Feb 2023 10:43:05 +0000 (11:43 +0100)] 
BUG/MINOR: stats: fix ctx->field update in stats_dump_proxy_to_buffer()

When ctx->field was introduced with ("MINOR: stats: introduce stats field ctx")
a mistake was made for the STAT_PX_ST_LI state in stats_dump_proxy_to_buffer():

current_field reset is placed after the for loop, ie: after multiple lines
are dumped. Instead it should be placed right after each li line is dumped.

This could cause some output inconsistencies (missing fields), especially when
http dump is used with JSON output and "socket-stats" option is enabled
on the proxy, because when htx is full we restore the ctx->field with
current_field (which contains outdated value in this case).

This should be backported with ("MINOR: stats: introduce stats field ctx")

2 years agoBUG/MEDIUM: stats: fix resolvers dump
Aurelien DARRAGON [Thu, 2 Feb 2023 16:27:27 +0000 (17:27 +0100)] 
BUG/MEDIUM: stats: fix resolvers dump

In ("BUG/MEDIUM: stats: Rely on a local trash buffer to dump the stats"),
we forgot to apply the patch in resolvers.c which provides the
stats_dump_resolvers() function that is involved when dumping with "resolvers"
domain.

As a consequence, resolvers dump was broken because stats_dump_one_line(),
which is used in stats_dump_resolv_to_buffer(), implicitely uses trash_chunk
from stats.c to prepare the dump, and stats_putchk() is then called with
global trash (currently empty) as output data.

Given that trash_dump variable is static and thus only available within stats.c
we change stats_putchk() function prototype so that the function does not take
the output buffer as an argument. Instead, stats_putchk() will implicitly use
the local trash_dump variable declared in stats.c.

It will also prevent further mixups between stats_dump_* functions and
stats_putchk().

This needs to be backported with ("BUG/MEDIUM: stats: Rely on a local trash
buffer to dump the stats")

2 years agoBUG/MINOR: stats: fix source buffer size for http dump
Aurelien DARRAGON [Fri, 3 Feb 2023 07:31:42 +0000 (08:31 +0100)] 
BUG/MINOR: stats: fix source buffer size for http dump

In ("BUG/MINOR: stats: use proper buffer size for http dump"),
we used trash.size as source buffer size before applying the htx
overhead computation.

It is safer to use res->buf.size instead since res_htx (which is <htx> argument
passed to stats_putchk() in http context) is made from res->buf:

in http_stats_io_handler:
    | res_htx = htx_from_buf(&res->buf);

This will prevent the hang bug from showing up again if res->buf.size were to be
less than trash.size (which is set according to tune.bufsize).

This should be backported with ("BUG/MINOR: stats: use proper buffer size for http dump")

2 years ago[RELEASE] Released version 2.8-dev3 v2.8-dev3
Willy Tarreau [Sat, 4 Feb 2023 09:51:05 +0000 (10:51 +0100)] 
[RELEASE] Released version 2.8-dev3

Released version 2.8-dev3 with the following main changes :
    - BUG/MINOR: sink: make sure to always properly unmap a file-backed ring
    - DEV: haring: add a new option "-r" to automatically repair broken files
    - BUG/MINOR: ssl: Fix leaks in 'update ssl ocsp-response' CLI command
    - MINOR: ssl: Remove debug fprintf in 'update ssl ocsp-response' cli command
    - MINOR: connection: add a BUG_ON() to detect destroying connection in idle list
    - MINOR: mux-quic/h3: send SETTINGS as soon as transport is ready
    - BUG/MINOR: h3: fix GOAWAY emission
    - BUG/MEDIUM: mux-quic: fix crash on H3 SETTINGS emission
    - BUG/MEDIUM: hpack: fix incorrect huffman decoding of some control chars
    - BUG/MINOR: log: release global log servers on exit
    - BUG/MINOR: ring: release the backing store name on exit
    - BUG/MINOR: sink: free the forwarding task on exit
    - CLEANUP: trace: remove the QUIC-specific ifdefs
    - MINOR: trace: add a TRACE_ENABLED() macro to determine if a trace is active
    - MINOR: trace: add a trace_no_cb() dummy callback for when to use no callback
    - MINOR: trace: add the long awaited TRACE_PRINTF()
    - MINOR: h2: add h2_phdr_to_ist() to make ISTs from pseudo headers
    - MEDIUM: mux-h2/trace: add tracing support for headers
    - CLEANUP: mux-h2/trace: shorten the name of the header enc/dec functions
    - DEV: hpack: fix `trash` build regression
    - MINOR: http_htx: add http_append_header() to append value to header
    - MINOR: http_htx: add http_prepend_header() to prepend value to header
    - MINOR: sample: add ARGC_OPT
    - MINOR: proxy: introduce http only options
    - MINOR: proxy/http_ext: introduce proxy forwarded option
    - REGTEST: add ifnone-forwardfor test
    - MINOR: proxy: move 'forwardfor' option to http_ext
    - MINOR: proxy: move 'originalto' option to http_ext
    - MINOR: http_ext: introduce http ext converters
    - MINOR: http_ext: add rfc7239_is_valid converter
    - MINOR: http_ext: add rfc7239_field converter
    - MINOR: http_ext: add rfc7239_n2nn converter
    - MINOR: http_ext: add rfc7239_n2np converter
    - REGTEST: add RFC7239 forwarded header tests
    - OPTIM: http_ext/7239: introduce c_mode to save some space
    - MINOR: http_ext/7239: warn the user when fetch is not available
    - MEDIUM: proxy/http_ext: implement dynamic http_ext
    - MINOR: cfgparse/http_ext: move post-parsing http_ext steps to http_ext
    - DOC: config: fix option spop-check proxy compatibility
    - BUG/MINOR: fcgi-app: prevent 'use-fcgi-app' in default section
    - DOC: config: 'http-send-name-header' option may be used in default section
    - BUG/MINOR: mux-h2: Fix possible null pointer deref on h2c in _h2_trace_header()
    - BUG/MINOR: http_ext/7239: ipv6 dumping relies on out of scope variables
    - BUG/MEDIUM: h3: do not crash if no buf space for trailers
    - OPTIM: h3: skip buf realign if no trailer to encode
    - MINOR: mux-quic/h3: define stream close callback
    - BUG/MEDIUM: h3: handle STOP_SENDING on control stream
    - BUG/MINOR: h3: reject RESET_STREAM received for control stream
    - MINOR: h3: add missing traces on closure
    - BUG/MEDIUM: ssl: wrong eviction from the session cache tree
    - BUG/MINOR: h3: fix crash due to h3 traces
    - BUG/MINOR: h3: fix crash due to h3 traces
    - BUG/MEDIUM: thread: consider secondary threads as idle+harmless during boot
    - BUG/MINOR: stats: use proper buffer size for http dump
    - BUILD: makefile: fix PCRE overriding specific lib path
    - MINOR: quic: remove fin from quic_stream frame type
    - MINOR: quic: ensure offset is properly set for STREAM frames
    - MINOR: quic: define new functions for frame alloc
    - MINOR: quic: refactor frame deallocation
    - MEDIUM: quic: implement a retransmit limit per frame
    - MINOR: quic: add config for retransmit limit
    - OPTIM: htx: inline the most common memcpy(8)
    - CLEANUP: quic: no need for atomics on packet refcnt
    - MINOR: stats: add by HTTP version cumulated number of sessions and requests
    - BUG/MINOR: quic: Possible stream truncations under heavy loss
    - BUG/MINOR: quic: Too big PTO during handshakes
    - MINOR: quic: Add a trace about variable states in qc_prep_fast_retrans()
    - BUG/MINOR: quic: Do not ignore coalesced packets in qc_prep_fast_retrans()
    - MINOR: quic: When probing Handshake packet number space, also probe the Initial one
    - BUG/MAJOR: quic: Possible crash when processing 1-RTT during 0-RTT session
    - MEDIUM: quic: Remove qc_conn_finalize() from the ClientHello TLS callbacks
    - BUG/MINOR: quic: Unchecked source connection ID
    - MEDIUM: listener: move the analysers mask to the bind_conf
    - MINOR: listener: move maxseg and tcp_ut to bind_conf
    - MINOR: listener: move maxaccept from listener to bind_conf
    - MINOR: listener: move the backlog setting from listener to bind_conf
    - MINOR: listener: move the maxconn parameter to the bind_conf
    - MINOR: listener: move the ->accept callback to the bind_conf
    - MINOR: listener: remove the useless ->default_target field
    - MINOR: listener: move the nice field to the bind_conf
    - MINOR: listener: move the NOLINGER option to the bind_conf
    - MINOR: listener: move the NOQUICKACK option to the bind_conf
    - MINOR: listener: move the DEF_ACCEPT option to the bind_conf
    - MINOR: listener: move TCP_FO to bind_conf
    - MINOR: listener: move the ACC_PROXY and ACC_CIP options to bind_conf
    - MINOR: listener: move LI_O_UNLIMITED and LI_O_NOSTOP to bind_conf
    - MINOR: listener: get rid of LI_O_TCP_L4_RULES and LI_O_TCP_L5_RULES
    - CLEANUP: listener: remove the now unused options field
    - MINOR: listener: remove the now useless LI_F_QUIC_LISTENER flag
    - CLEANUP: config: remove test for impossible case regarding bind thread mask
    - MINOR: thread: add a simple thread_set API
    - MEDIUM: listener/config: make the "thread" parser rely on thread_sets
    - CLEANUP: config: stop using bind_tgroup and bind_thread
    - CLEANUP: listener/thread: remove now unused bind_conf's bind_tgroup/bind_thread
    - CLEANUP: listener/config: remove the special case for shards==1
    - MEDIUM: config: restrict shards, not bind_conf to one group each
    - BUG/MEDIUM: quic: do not split STREAM frames if no space
    - BUILD: thread: fix build warnings with older gcc compilers

2 years agoBUILD: thread: fix build warnings with older gcc compilers
Willy Tarreau [Sat, 4 Feb 2023 09:49:01 +0000 (10:49 +0100)] 
BUILD: thread: fix build warnings with older gcc compilers

The "{ 0 }" form to initialize an empty structure triggers build warnings
on gcc 4.8, let's use the more common "{ }" instead.

2 years agoBUG/MEDIUM: quic: do not split STREAM frames if no space
Amaury Denoyelle [Fri, 3 Feb 2023 17:39:06 +0000 (18:39 +0100)] 
BUG/MEDIUM: quic: do not split STREAM frames if no space

When building STREAM frames in a packet buffer, if a frame is too large
it will be splitted in two. A shorten version will be used and the
original frame will be modified to represent the remaining space.

To ensure there is enough space to store the frame data length encoded
as a QUIC integer, we use the function max_available_room(). This
function can return 0 if there not only a small space left which is
insufficient for the frame header and the shorten data. Prior to this
patch, this wasn't check and an empty unneeded STREAM frame was built
and sent for nothing.

Change this by checking the value return by max_available_room(). If 0,
do not try to split this frame and continue to the next ones in the
packet.

On 2.6, this patch serves as an optimization which will prevent the building
of unneeded empty STREAM frames.

On 2.7, this behavior has the side-effect of triggering a BUG_ON()
statement on quic_build_stream_frame(). This BUG_ON() ensures that we do
not use quic_frame with OFF bit set if its offset is 0. This can happens
if the condition defined above is reproduced for a STREAM frame at
offset 0. An empty unneeded frame is built as descibed. The problem is
that the original frame is modified with its OFF bit set even if the
offset is still 0.

This must be backported up to 2.6.

2 years agoMEDIUM: config: restrict shards, not bind_conf to one group each
Willy Tarreau [Fri, 3 Feb 2023 14:52:07 +0000 (15:52 +0100)] 
MEDIUM: config: restrict shards, not bind_conf to one group each

Now that we're using thread_sets there's no need to restrict an entire
bind_conf to 1 group, the real concern being the FD, we can move that
restriction to the shard only. This means that as long as we have enough
shards and that they're properly aligned on group boundaries (i.e. shards
are an integer divider of the number of threads), we can support "bind"
lines spanning more than one group.

The check is still performed for shards to span more than one group,
and an error is emitted when this happens. But at least now it becomes
possible to have this:

    global
       nbthread 256

    frontend foo
       bind :1111 shards 4
       bind :2222 shards by-thread

2 years agoCLEANUP: listener/config: remove the special case for shards==1
Willy Tarreau [Fri, 3 Feb 2023 13:53:34 +0000 (14:53 +0100)] 
CLEANUP: listener/config: remove the special case for shards==1

In fact this case is already handled by the regular shards code, there
is no need to special-case it.

2 years agoCLEANUP: listener/thread: remove now unused bind_conf's bind_tgroup/bind_thread
Willy Tarreau [Thu, 2 Feb 2023 16:01:10 +0000 (17:01 +0100)] 
CLEANUP: listener/thread: remove now unused bind_conf's bind_tgroup/bind_thread

Not needed anymore since last commit, let's get rid of it.

2 years agoCLEANUP: config: stop using bind_tgroup and bind_thread
Willy Tarreau [Tue, 31 Jan 2023 18:37:54 +0000 (19:37 +0100)] 
CLEANUP: config: stop using bind_tgroup and bind_thread

Let's now retrieve the first thread group and its mask from the
thread_set so that we don't need these fields in the bind_conf anymore.
For now we're still limited to the first group (like before) but that
allows to get rid of these fields and to make sure that there's nothing
"special" being done there anymore.