Compare commits

...

162 Commits

Author SHA1 Message Date
Amaury Denoyelle
577fa44691 BUG/MINOR: quic: work around NEW_TOKEN parsing error on backend side
NEW_TOKEN frame is never emitted by a client, hence parsing was not
tested on frontend side.

On backend side, an issue can occur, as expected token length is static,
based on the token length used internally by haproxy. This is not
sufficient for most server implementation which uses larger token. This
causes a parsing error, which may cause skipping of following frames in
the same packet. This issue was detected using ngtcp2 as server.

As for now tokens are unused by haproxy, simply discard test on token
length during NEW_TOKEN frame parsing. The token itself is merely
skipped without being stored. This is sufficient for now to continue on
experimenting with QUIC backend implementation.

This does not need to be backported.
2025-06-12 17:47:15 +02:00
Amaury Denoyelle
830affc17d MINOR: server: reject QUIC servers without explicit SSL
Report an error during server configuration if QUIC is used by SSL is
not activiated via 'ssl' keyword. This is done in _srv_parse_finalize(),
which is both used by static and dynamic servers.

Note that contrary to listeners, an error is reported instead of a
warning, and SSL is not automatically activated if missing. This is
mainly due to the complex server configuration : _srv_parse_finalize()
is ideal to affect every servers, including dynamic entries. However, it
is executed after server SSL context allocation performed via
<prepare_srv> XPRT operation. A proper fix would be to move SSL ctx
alloc in _srv_parse_finalize(), but this may have unknown impact. Thus,
for now a simpler solution has been chosen.
2025-06-12 16:16:43 +02:00
Amaury Denoyelle
33cd96a5e9 BUG/MINOR: quic: prevent crash on startup with -dt
QUIC traces in ssl_quic_srv_new_ssl_ctx() are problematic as this
function is called early during startup. If activating traces via -dt
command-line argument, a crash occurs due to stderr sink not yet
available.

Thus, traces from ssl_quic_srv_new_ssl_ctx() are simply removed.

No backport needed.
2025-06-12 15:15:56 +02:00
Frederic Lecaille
5a0ae9e9be MINOR: quic-be: Avoid SSL context unreachable code without USE_QUIC_OPENSSL_COMPAT
This commit added a "err" C label reachable only with USE_QUIC_OPENSSL_COMPAT:

   MINOR: quic-be: Missing callbacks initializations (USE_QUIC_OPENSSL_COMPAT)

leading coverity to warn this:

*** CID 1611481:         Control flow issues  (UNREACHABLE)
/src/quic_ssl.c: 802             in ssl_quic_srv_new_ssl_ctx()
796     		goto err;
797     #endif
798
799      leave:
800     	TRACE_LEAVE(QUIC_EV_CONN_NEW);
801     	return ctx;
>>>     CID 1611481:         Control flow issues  (UNREACHABLE)
>>>     This code cannot be reached: "err:
SSL_CTX_free(ctx);".
802      err:
803     	SSL_CTX_free(ctx);
804     	ctx = NULL;
805     	TRACE_DEVEL("leaving on error", QUIC_EV_CONN_NEW);
806     	goto leave;
807     }

The less intrusive (without #ifdef) way to fix this it to add a "goto err"
statement from the code part which is reachable without USE_QUIC_OPENSSL_COMPAT.

Thank you to @chipitsine for having reported this issue in GH #3003.
2025-06-12 11:45:21 +02:00
Frederic Lecaille
869fb457ed BUG/MINOR: quic-be: CID double free upon qc_new_conn() failures
This issue may occur when qc_new_conn() fails after having allocated
and attached <conn_cid> to its tree. This is the case when compiling
haproxy against WolfSSL for an unknown reason at this time. In this
case the <conn_cid> is freed by pool_head_quic_connection_id(), then
freed again by quic_conn_release().

This bug arrived with this commit:

    MINOR: quic-be: QUIC connection allocation adaptation (qc_new_conn())

So, the aim of this patch is to free <conn_cid> only for QUIC backends
and if it is not attached to its tree. This is the case when <conn_id>
local variable passed with NULL value to qc_new_conn() is then intialized
to the same <conn_cid> value.
2025-06-12 11:45:21 +02:00
Frederic Lecaille
dc3fb3a731 CLEANUP: quic-be: Add comments about qc_new_conn() usage
This patch should have come with this last commit for the last qc_new_conn()
modifications for QUIC backends:

     MINOR: quic-be: get rid of ->li quic_conn member

qc_new_conn() must be passed NULL pointers for several variables as mentioned
by the comment. Some of these local variables are used to avoid too much
code modifications.
2025-06-12 11:45:21 +02:00
Amaury Denoyelle
603afd495b MINOR: hq-interop: encode request from HTX for backend side support
Implement transcoding of a HTX request into HTTP/0.9. This protocol is a
simplified version of HTTP. Request only supports GET method without any
header. As such, only a request line is written during snd_buf
operation.
2025-06-12 11:28:54 +02:00
Amaury Denoyelle
a286d5476b MINOR: hq-interop: decode response into HTX for backend side support
Implement transcoding of a HTTP/0.9 response into a HTX message.

HTTP/0.9 is a really simple substract of HTTP spec. The response does
not have any status line and is contains only the payload body. Response
is finished when the underlying connection/stream is closed.

A status line is generated to be compliant with HTX. This is performed
on the first invokation of rcv_buf for the current stream. Status code
is set to 200. Payload body if present is then copied using
htx_add_data().
2025-06-12 11:28:54 +02:00
Amaury Denoyelle
4031bf7432 MINOR: quic: wakeup backend MUX on handshake completed
This commit is the second and final step to initiate QUIC MUX on the
backend side. On handshake completion, MUX is woken up just after its
creation. This step is necessary to notify the stream layer, via the QCS
instance pre-initialized on MUX init, so that the transfer can be
resumed.

This mode of operation is similar to TCP stack when TLS+ALPN are used,
which forces MUX initialization to be delayed after handshake
completion.
2025-06-12 11:28:54 +02:00
Amaury Denoyelle
1efaca8a57 MINOR: mux-quic: instantiate first stream on backend side
Adjust qmux_init() to handle frontend and backend sides differently.
Most notably, on backend side, the first bidirectional stream is created
preemptively. This step is necessary as MUX layer will be woken up just
after handshake completion.
2025-06-12 11:28:54 +02:00
Amaury Denoyelle
f8d096c05f MINOR: mux-quic: set expect data only on frontend side
Stream data layer is notified that data is expected when FIN is
received, which marks the end of the HTTP request. This prepares data
layer to be able to handle the expected HTTP response.

Thus, this step is only relevant on frontend side. On backend side, FIN
marks the end of the HTTP response. No further content is expected, thus
expect data should not be set in this case.

Note that se_expect_data() invokation via qcs_attach_sc() is not
protected. This is because this function will only be called during
request headers parsing which is performed on the frontend side.
2025-06-12 11:28:54 +02:00
Amaury Denoyelle
e8775d51df MINOR: mux-quic: define flag for backend side
Mux connection is flagged with new QC_CF_IS_BACK if used on the backend
side. For now the only change is during traces, to be able to
differentiate frontend and backend usage.
2025-06-12 11:28:54 +02:00
Amaury Denoyelle
93b904702f MINOR: mux-quic: improve documentation for snd/rcv app-ops
Complete document for rcv_buf/snd_buf operations. In particular, return
value is now explicitely defined. For H3 layer, associated functions
documentation is also extended.
2025-06-12 11:28:54 +02:00
Amaury Denoyelle
e7f1db0348 MINOR: quic: mark ctrl layer as ready on quic_connect_server()
Use conn_ctrl_init() on the connection when quic_connect_server()
succeeds. This is necessary so that the connection is considered as
completely initialized. Without this, connect operation will be call
again if connection is reused.
2025-06-12 11:25:12 +02:00
Amaury Denoyelle
a0db93f3d8 MEDIUM: backend: delay MUX init with ALPN even if proto is forced
On backend side, multiplexer layer is initialized during
connect_server(). However, this step is not performed if ALPN is used,
as the negotiated protocol may be unknown. Multiplexer initialization is
delayed after TLS handshake completion.

There are still exceptions though that forces the MUX to be initialized
even if ALPN is used. One of them was if <mux_proto> server field was
already set at this stage, which is the case when an explicit proto is
selected on the server line configuration. Remove this condition so that
now MUX init is delayed with ALPN even if proto is forced.

The scope of this change should be minimal. In fact, the only impact
concerns server config with both proto and ALPN set, which is pretty
unlikely as it is contradictory.

The main objective of this patch is to prepare QUIC support on the
backend side. Indeed, QUIC proto will be forced on the server if a QUIC
address is used, similarly to bind configuration. However, we still want
to delay MUX initialization after QUIC handshake completion. This is
mandatory to know the selected application protocol, required during
QUIC MUX init.
2025-06-12 11:21:32 +02:00
Amaury Denoyelle
044ad3a602 BUG/MEDIUM: mux-quic: adjust wakeup behavior
Change wake callback behavior for QUIC MUX. This operation loops over
each QCS and notify their stream data layer on certain events via
internal helper qcc_wake_some_streams().

Previously, streams were notified only if an error occured on the
connection. Change this to notify streams data layer everytime wake
callback is used. This behavior is now identical to H2 MUX.

qcc_wake_some_streams() is also renamed to qcc_wake_streams(), as it
better reflect its true behavior.

This change should not have performance impact as wake mux ops should
not be called frequently. Note that qcc_wake_streams() can also be
called directly via qcc_io_process() to ensure a new error is correctly
propagated. As wake callback first uses qcc_io_process(), it will only
call qcc_wake_streams() if no error is present.

No known issue is associated with this commit. However, it could prevent
freezing transfer under certain condition. As such, it is considered as
a bug fix worthy of backporting.

This should be backported after a period of observation.
2025-06-12 11:12:49 +02:00
Christopher Faulet
2c3f3eaaed BUILD: hlua: Fix warnings about uninitialized variables (2)
It was still failing on Ubuntu-24.04 with GCC+ASAN. So, instead of
understand the code path the compiler followed to report uninitialized
variables, let's init them now.

No backport needed.
2025-06-12 10:49:54 +02:00
Aurelien DARRAGON
b5067a972c BUILD: listener: fix 'for' loop inline variable declaration
commit 16eb0fab3 ("MAJOR: counters: dispatch counters over thread groups")
introduced a build regression on some compilers:

  src/listener.c: In function 'listener_accept':
  src/listener.c:1095:3: error: 'for' loop initial declarations are only allowed in C99 mode
     for (int it = 0; it < global.nbtgroups; it++)
     ^
  src/listener.c:1095:3: note: use option -std=c99 or -std=gnu99 to compile your code
  src/listener.c:1101:4: error: 'for' loop initial declarations are only allowed in C99 mode
      for (int it = 0; it < global.nbtgroups; it++) {
      ^
  make: *** [src/listener.o] Error 1
  make: *** Waiting for unfinished jobs....

Let's fix that.
No backport needed
2025-06-12 08:46:36 +02:00
Christopher Faulet
01f011faeb BUILD: hlua: Fix warnings about uninitialized variables
In hlua_applet_tcp_recv_try() and hlua_applet_tcp_getline_yield(), GCC 14.2
reports warnings about 'blk2' variable that may be used uninitialized. It is
a bit strange because the code is pretty similar than before. But to make it
happy and to avoid bugs if the API change in future, 'blk2' is now used only
when its length is greater than 0.

No need to backport.
2025-06-12 08:46:36 +02:00
Christopher Faulet
8c573deb9f BUG/MINOR: hlua: Don't forget the return statement after a hlua_yieldk()
In hlua_applet_tcp_getline_yield(), the function may yield if there is no
data available. However we must take care to add a return statement just
after the call to hlua_yieldk(). I don't know the details of the LUA API,
but at least, this return statement fix a build error about uninitialized
variables that may be used.

It is a 3.3-specific issue. No backport needed.
2025-06-12 08:46:36 +02:00
Frederic Lecaille
bf6e576cfd MEDIUM: quic-be: initialize MUX on handshake completion
On backend side, MUX is instantiated after QUIC handshake completion.
This step is performed via qc_ssl_provide_quic_data(). First, connection
flags for handshake completion are resetted. Then, MUX is instantiated
via conn_create_mux() function.
2025-06-11 18:37:34 +02:00
Amaury Denoyelle
cdcecb9b65 MINOR: quic: define proper proto on QUIC servers
Force QUIC as <mux_proto> for server if a QUIC address is used. This is
similarly to what is already done for bind instances on the frontend
side. This step ensures that conn_create_mux() will select the proper
protocol.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
855fd63f90 MINOR: quic-be: Prevent the MUX to send/receive data
Such actions must be interrupted until the handshake completion.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
b9703cf711 MINOR: quic-be: get rid of ->li quic_conn member
Replace ->li quic_conn pointer to struct listener member by  ->target which is
an object type enum and adapt the code.
Use __objt_(listener|server)() where the object type is known. Typically
this is were the code which is specific to one connection type (frontend/backend).
Remove <server> parameter passed to qc_new_conn(). It is redundant with the
<target> parameter.
GSO is not supported at this time for QUIC backend. qc_prep_pkts() is modified
to prevent it from building more than an MTU. This has as consequence to prevent
qc_send_ppkts() to use GSO.
ssl_clienthello.c code is run only by listeners. This is why __objt_listener()
is used in place of ->li.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
f6ef3bbc8a MINOR: quic-be: SSL_get_peer_quic_transport_params() not defined by OpenSSL 3.5 QUIC API
Disable the code around SSL_get_peer_quic_transport_params() as this was done
for USE_QUIC_OPENSSL_COMPAT because SSL_get_peer_quic_transport_params() is not
defined by OpenSSL 3.5 QUIC API.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
034cf74437 MINOR: quic-be: Make the secret derivation works for QUIC backends (USE_QUIC_OPENSSL_COMPAT)
quic_tls_compat_keylog_callback() is the callback used by the QUIC OpenSSL
compatibility module to derive the TLS secrets from other secrets provided
by keylog. The <write> local variable to this function is initialized to denote
the direction (write to send, read to receive) the secret is supposed to be used
for. That said, as the QUIC cryptographic algorithms are symmetrical, the
direction is inversed between the peer: a secret which is used to write/send/cipher
data from a peer point of view is also the secret which is used to
read/receive/decipher data. This was confirmed by the fact that without this
patch, the TLS stack first provides the peer with Handshake to send/cipher
data. The client could not use such secret to decipher the Handshake packets
received from the server. This patch simply reverse the direction stored by
<write> variable to make the secrets derivation works for the QUIC client.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
d1cd0bb987 MINOR: quic-be: Missing callbacks initializations (USE_QUIC_OPENSSL_COMPAT)
quic_tls_compat_init() function is called from OpenSSL QUIC compatibility module
(USE_QUIC_OPENSSL_COMPAT) to initialize the keylog callback and the callback
which stores the QUIC transport parameters as a TLS extensions into the stack.
These callbacks must also be initialized for QUIC backends.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
fc90964b55 MINOR: quic-be: Store the remote transport parameters asap
This is done from TLS secrets derivation callback at Application level (the last
encryption level) calling SSL_get_peer_quic_transport_params() to have an access
to the TLS transport paremeters extension embedded into the Server Hello TLS message.
Then, quic_transport_params_store() is called to store a decoded version of
these transport parameters.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
8c2f2615f4 MINOR: quic-be: I/O handler switch adaptation
For connection to QUIC servers, this patch modifies the moment where the I/O
handler callback is switched to quic_conn_app_io_cb(). This is no more
done as for listener just after the handshake has completed but just after
it has been confirmed.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
f085a2f5bf MINOR: quic-be: Initial packet number space discarding.
Discard the Initial packet number space as soon as possible. This is done
during handshakes in quic_conn_io_cb() as soon as an Handshake packet could
be successfully sent.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
a62098bfb0 MINOR: quic-be: Add the conn object to the server SSL context
The initialization of <ssl_app_data_index> SSL user data index is required
to make all the SSL sessions to QUIC servers work as this is done for TCP
servers. The conn object notably retrieve for SSL callback which are
server specific (e.g. ssl_sess_new_srv_cb()).
2025-06-11 18:37:34 +02:00
Frederic Lecaille
e226a7cb79 MINOR: quic-be: Build post handshake frames
This action is not specific to listeners. A QUIC client also have to send
NEW_CONNECTION_ID frames.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
2d076178c6 MINOR: quic-be: Store asap the DCID
Store the peer connection ID (SCID) as the connection DCID as soon as an Initial
packet is received.
Stop comparing the packet to QUIC_PACKET_TYPE_0RTT is already match as
QUIC_PACKET_TYPE_INITIAL.
A QUIC server must not send too short datagram with ack-eliciting packets inside.
This cannot be done from quic_rx_pkt_parse() because one does not know if
there is ack-eliciting frame into the Initial packets. If the packet must be
dropped, this is after having parsed it!
2025-06-11 18:37:34 +02:00
Frederic Lecaille
b4a9b53515 MINOR: h3-be: Correctly retrieve h3 counters
This is done using qc_counters() function which supports also QUIC servers.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
e27b7b4889 MINOR: quic-be: Handshake packet number space discarding
This is done for QUIC clients (or haproxy QUIC servers) when the handshake is
confirmed.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
43d88a44f1 MINOR: quic-be: Datagrams and packet parsing support
Modify quic_dgram_parse() to stop passing it a listener as third parameter.
In place the object type address of the connection socket owner is passed
to support the haproxy servers with QUIC as transport protocol.
qc_owner_obj_type() is implemented to return this address.
qc_counters() is also implemented to return the QUIC specific counters of
the proxy of owner of the connection.
quic_rx_pkt_parse() called by quic_dgram_parse() is also modify to use
the object type address used by this latter as last parameter. It is
also modified to send Retry packet only from listeners. A QUIC client
(connection to haproxy QUIC servers) must drop the Initial packets with
non null token length. It is also not supposed to receive O-RTT packets
which are dropped.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
266b10b8a4 MINOR: quic-be: Do not redispatch the datagrams
The QUIC datagram redispatch is there to counter the race condition which
exists only for QUIC connections to listener where datagrams may arrive
on the wrong socket between the bind() and connect() calls.
Run this code part only for listeners.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
89d5a59933 MINOR: quic-be: add field for max_udp_payload_size into quic_conn
Add ->max_udp_payload_size new member to quic_conn struct.
Initialize it from qc_new_conn().
Adapt qc_snd_buf() to use it.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
f7c0f5ac1b MINOR: quic-be: xprt ->init() adapatations
Allocate a connection to connect to QUIC servers from qc_conn_init() which is the
->init() QUIC xprt callback.
Also initialize ->prepare_srv and ->destroy_srv callback as this done for TCP
servers.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
29fb1aee57 MINOR: quic-be: QUIC connection allocation adaptation (qc_new_conn())
For haproxy QUIC servers (or QUIC clients), the peer is considered as validated.
This is a property which is more specific to QUIC servers (haproxy QUIC listeners).
No <odcid> is used for the QUIC client connection. It is used only on the QUIC server side.
The <token_odcid> is also not used on the QUIC client side. It must be embedded into
the transport parameters only on the QUIC server side.
The quic_conn is created before the socket allocation. So, the local address is
zeroed.
Initilize the transport parameter with qc_srv_params_init().
Stop hardcoding the <server> parameter passed value to qc_new_isecs() to correctly
initialize the Initial secrets.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
9831f596ea MINOR: quic-be: ->connect() protocol callback adaptations
Modify quic_connect_server() which is the ->connect() callback for QUIC protocol:
    - add a BUG_ON() run when entering this funtion: the <fd> socket must equal -1
    - conn->handle is a union. conn->handle.qc is use for QUIC connection,
      conn->handle.fd must not be used to store the fd.
    - code alignment fix for setsockopt(fd, SOL_SOCKET, (SO_SNDBUF|SO_RCVBUF))
	  statements
    - remove the section of code which was duplicated from ->connect() TCP callback
    - fd_insert() the new socket file decriptor created to connect to the QUIC
      server with quic_conn_sock_fd_iocb() as callback for read event.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
52ec3430f2 MINOR: sock: Add protocol and socket types parameters to sock_create_server_socket()
This patch only adds <proto_type> new proto_type enum parameter and <sock_type>
socket type parameter to sock_create_server_socket() and adapts its callers.
This is to prepare the use of this function by QUIC servers/backends.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
9c84f64652 MINOR: quic-be: Add a function to initialize the QUIC client transport parameters
Implement qc_srv_params_init() to initialize the QUIC client transport parameters
in relation with connections to haproxy servers/backends.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
f49bbd36b9 MINOR: quic-be: SSL sessions initializations
Modify qc_alloc_ssl_sock_ctx() to pass the connection object as parameter. It is
NULL for a QUIC listener, not NULL for a QUIC server. This connection object is
set as value for ->conn quic_conn struct member. Initialise the SSL session object from
this function for QUIC servers.
qc_ssl_set_quic_transport_params() is also modified to pass the SSL object as parameter.
This is the unique parameter this function needs. <qc> parameter is used only for
the trace.
SSL_do_handshake() must be calle as soon as the SSL object is initialized for
the QUIC backend connection. This triggers the TLS CRYPTO data delivery.
tasklet_wakeup() is also called to send asap these CRYPTO data.
Modify the QUIC_EV_CONN_NEW event trace to dump the potential errors returned by
SSL_do_handshake().
2025-06-11 18:37:34 +02:00
Frederic Lecaille
1408d94bc4 MINOR: quic-be: ssl_sock contexts allocation and misc adaptations
Implement ssl_sock_new_ssl_ctx() to allocate a SSL server context as this is currently
done for TCP servers and also for QUIC servers depending on the <is_quic> boolean value
passed as new parameter. For QUIC servers, this function calls ssl_quic_srv_new_ssl_ctx()
which is specific to QUIC.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
7c76252d8a MINOR: quic-be: Correct the QUIC protocol lookup
From connect_server(), QUIC protocol could not be retreived by protocol_lookup()
because of the PROTO_TYPE_STREAM default passed as argument. In place to support
QUIC srv->addr_type.proto_type may be safely passed.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
1e45690656 MINOR: quic-be: Add a function for the TLS context allocations
Implement ssl_quic_srv_new_ssl_ctx() whose aim is to allocate a TLS context
for QUIC servers.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
a4e1296208 MINOR: quic-be: QUIC server xprt already set when preparing their CTXs
The QUIC servers xprts have already been set at server line parsing time.
This patch prevents the QUIC servers xprts to be reset to <ssl_sock> value which is
the value used for SSL/TCP connections.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
24fc44c44d MINOR: quic-be: QUIC backend XPRT and transport parameters init during parsing
Add ->quic_params new member to server struct.
Also set the ->xprt member of the server being initialized and initialize asap its
transport parameters from _srv_parse_init().
2025-06-11 18:37:34 +02:00
Frederic Lecaille
0e67687ca9 MINOR: quic-be: Call ->prepare_srv() callback at parsing time
This XPRT callback is called from check_config_validity() after the configuration
has been parsed to initialize all the SSL server contexts.

This patch implements the same thing for the QUIC servers.
2025-06-11 18:37:34 +02:00
Frederic Lecaille
5a711551a2 MINOR: quic-be: Version Information transport parameter check
Add a little check to verify that the version chosen by the server matches
with the client one. Initiliazes local transport parameters ->negotiated_version
value with this version if this is the case. If not, return 0;
2025-06-11 18:37:34 +02:00
Frederic Lecaille
990c9f95f7 MINOR: quic-be: Correct Version Information transp. param encoding
According to the RFC, a QUIC client must encode the QUIC version it supports
into the "Available Versions" of "Version Information" transport parameter
order by descending preference.

This is done defining <quic_version_2> and <quic_version_draft_29> new variables
pointers to the corresponding version of <quic_versions> array elements.
A client announces its available versions as follows: v1, v2, draft29.
2025-06-11 18:37:34 +02:00
Amaury Denoyelle
9c751a3cc1 MINOR: mux-quic-be: allow QUIC proto on backend side
Activate QUIC protocol support for MUX-QUIC on the backend side,
additionally to current frontend support. This change is mandatory to be
able to implement QUIC on the backend side.

Without this modification, it is impossible to activate explicitely QUIC
protocol on a server line, hence an error is reported :
  config : proxy 'xxxx' : MUX protocol 'quic' is not usable for server 'yyyy'
2025-06-11 18:37:34 +02:00
Amaury Denoyelle
f66b495f8e MINOR: server: mark QUIC support as experimental
Mark QUIC address support for servers as experimental on the backend
side. Previously, it was allowed but wouldn't function as expected. As
QUIC backend support requires several changes, it is better to declare
it as experimental first.
2025-06-11 18:37:33 +02:00
Amaury Denoyelle
bdd5e58179 MINOR: server: implement helper to identify QUIC servers
Define srv_is_quic() which can be used to quickly identified if a server
uses QUIC protocol.
2025-06-11 18:37:19 +02:00
Amaury Denoyelle
1ecf2e9bab BUG/MINOR: config/server: reject QUIC addresses
QUIC is not implemented on the backend side. To prevent any issue, it is
better to reject any server configured which uses it. This is done via
_srv_parse_init() which is used both for static and dynamic servers.

This should be backported up to all stable versions.
2025-06-11 18:37:17 +02:00
Christopher Faulet
b5525fe759 [RELEASE] Released version 3.3-dev1
Released version 3.3-dev1 with the following main changes :
    - BUILD: tools: properly define ha_dump_backtrace() to avoid a build warning
    - DOC: config: Fix a typo in 2.7 (Name format for maps and ACLs)
    - REGTESTS: Do not use REQUIRE_VERSION for HAProxy 2.5+ (5)
    - REGTESTS: Remove REQUIRE_VERSION=2.3 from all tests
    - REGTESTS: Remove REQUIRE_VERSION=2.4 from all tests
    - REGTESTS: Remove tests with REQUIRE_VERSION_BELOW=2.4
    - REGTESTS: Remove support for REQUIRE_VERSION and REQUIRE_VERSION_BELOW
    - MINOR: server: group postinit server tasks under _srv_postparse()
    - MINOR: stats: add stat_col flags
    - MINOR: stats: add ME_NEW_COMMON() helper
    - MINOR: proxy: collect per-capability stat in proxy_cond_disable()
    - MINOR: proxy: add a true list containing all proxies
    - MINOR: log: only run postcheck_log_backend() checks on backend
    - MEDIUM: proxy: use global proxy list for REGISTER_POST_PROXY_CHECK() hook
    - MEDIUM: server: automatically add server to proxy list in new_server()
    - MEDIUM: server: add and use srv_init() function
    - BUG/MAJOR: leastconn: Protect tree_elt with the lbprm lock
    - BUG/MEDIUM: check: Requeue healthchecks on I/O events to handle check timeout
    - CLEANUP: applet: Update comment for applet_put* functions
    - DEBUG: check: Add the healthcheck's expiration date in the trace messags
    - BUG/MINOR: mux-spop: Fix null-pointer deref on SPOP stream allocation failure
    - CLEANUP: sink: remove useless cleanup in sink_new_from_logger()
    - MAJOR: counters: add shared counters base infrastructure
    - MINOR: counters: add shared counters helpers to get and drop shared pointers
    - MINOR: counters: add common struct and flags to {fe,be}_counters_shared
    - MEDIUM: counters: manage shared counters using dedicated helpers
    - CLEANUP: counters: merge some common counters between {fe,be}_counters_shared
    - MINOR: counters: add local-only internal rates to compute some maxes
    - MAJOR: counters: dispatch counters over thread groups
    - BUG/MEDIUM: cli: Properly parse empty lines and avoid crashed
    - BUG/MINOR: config: emit warning for empty args only in discovery mode
    - BUG/MINOR: config: fix arg number reported on empty arg warning
    - BUG/MINOR: quic: Missing SSL session object freeing
    - MINOR: applet: Add API functions to manipulate input and output buffers
    - MINOR: applet: Add API functions to get data from the input buffer
    - CLEANUP: applet: Simplify a bit comments for applet_put* functions
    - MEDIUM: hlua: Update TCP applet functions to use the new applet API
    - BUG/MEDIUM: fd: Use the provided tgid in fd_insert() to get tgroup_info
    - BUG/MINIR: h1: Fix doc of 'accept-unsafe-...-request' about URI parsing
2025-06-11 14:31:33 +02:00
Christopher Faulet
b2f64af341 BUG/MINIR: h1: Fix doc of 'accept-unsafe-...-request' about URI parsing
The description of tests performed on the URI in H1 when
'accept-unsafe-violations-in-http-request' option is wrong. It states that
only characters below 32 and 127 are blocked when this option is set,
suggesting that otherwise, when it is not set, all invalid characters in the
URI, according to the RFC3986, are blocked.

But in fact, it is not true. By default all character below 32 and above 127
are blocked. And when 'accept-unsafe-violations-in-http-request' option is
set, characters above 127 (excluded) are accepted. But characters in
(33..126) are never checked, independently of this option.

This patch should fix the issue #2906. It should be backported as far as
3.0. For older versions, the docuementation could also be clarified because
this part is not really clear.

Note the request URI validation is still under discution because invalid
characters in (33.126) are never checked and some users request a stricter
parsing.
2025-06-10 19:17:56 +02:00
Olivier Houchard
6993981cd6 BUG/MEDIUM: fd: Use the provided tgid in fd_insert() to get tgroup_info
In fd_insert(), use the provided tgid to ghet the thread group info,
instead of using the one of the current thread, as we may call
fd_insert() from a thread of another thread group, that will happen at
least when binding the listeners. Otherwise we'd end up accessing the
thread mask containing enabled thread of the wrong thread group, which
can lead to crashes if we're binding on threads not present in the
thread group.
This should fix Github issue #2991.

This should be backported up to 2.8.
2025-06-10 15:10:56 +02:00
Christopher Faulet
9df380a152 MEDIUM: hlua: Update TCP applet functions to use the new applet API
The functions responsible to extract data from the applet input buffer or to
push data into the applet output buffer are now relying on the newly added
functions in the applet API. This simplifies a bit the code.
2025-06-10 08:16:10 +02:00
Christopher Faulet
18f9c71041 CLEANUP: applet: Simplify a bit comments for applet_put* functions
Instead of repeating which buffer is used depending on the API used by the
applet, a reference to applet_get_outbuf() was added.
2025-06-10 08:16:10 +02:00
Christopher Faulet
79445766a3 MINOR: applet: Add API functions to get data from the input buffer
There was already functions to pushed data from the applet to the stream by
inserting them in the right buffer, depending the applet was using or not
the legacy API. Here, functions to retreive data pushed to the applet by the
stream were added:

  * applet_getchar   : Gets one character

  * applet_getblk    : Copies a full block of data

  * applet_getword   : Copies one text block representing a word using a
                       custom separator as delimiter

  * applet_getline   : Copies one text line

  * applet_getblk_nc : Get one or two blocks of data

  * applet_getword_nc: Gets one or two blocks of text representing a word
                       using a custom separator as delimiter

  * applet_getline_nc: Gets one or two blocks of text representing a line
2025-06-10 08:16:10 +02:00
Christopher Faulet
0d8ecb1edc MINOR: applet: Add API functions to manipulate input and output buffers
In this patch, some functions were added to ease input and output buffers
manipulation, regardless the corresponding applet is using its own buffers
or it is relying on channels buffers. Following functions were added:

  * applet_get_inbuf  : Get the buffer containing data pushed to the applet
                        by the stream

  * applet_get_outbuf : Get the buffer containing data pushed by the applet
                        to the stream

  * applet_input_data : Return the amount of data in the input buffer

  * applet_skip_input : Skips <len> bytes from the input buffer

  * applet_reset_input: Skips all bytes from the input buffer

  * applet_output_room: Returns the amout of space available at the output
                        buffer

  * applet_need_room  : Indicates that the applet have more data to deliver
                        and it needs more room in the output buffer to do
			so
2025-06-10 08:16:10 +02:00
Frederic Lecaille
6b74633069 BUG/MINOR: quic: Missing SSL session object freeing
qc_alloc_ssl_sock_ctx() allocates an SSL_CTX object for each connection. It also
allocates an SSL object. When this function failed, it freed only the SSL_CTX object.
The correct way to free both of them is to call qc_free_ssl_sock_ctx().

Must be backported as far as 2.6.
2025-06-06 17:53:13 +02:00
Amaury Denoyelle
0cdf529720 BUG/MINOR: config: fix arg number reported on empty arg warning
If an empty argument is used in configuration, for example due to an
undefined environment variable, the rest of the line is not parsed. As
such, a warning is emitted to report this.

The warning was not totally correct as it reported the wrong argument
index. Fix this by this patch. Note that there is still an issue with
the "^" indicator, but this is not as easy to fix yet.

This is related to github issue #2995.

This should be backported up to 3.2.
2025-06-06 17:03:02 +02:00
Amaury Denoyelle
5f1fad1690 BUG/MINOR: config: emit warning for empty args only in discovery mode
Hide warning about empty argument outside of discovery mode. This is
necessary, else the message will be displayed twice, which hampers
haproxy output lisibility.

This should fix github isue #2995.

This should be backported up to 3.2.
2025-06-06 17:02:58 +02:00
Christopher Faulet
f5d41803d3 BUG/MEDIUM: cli: Properly parse empty lines and avoid crashed
Empty lines was not properly parsed and could lead to crashes because the
last argument was parsed outside of the cmdline buffer. Indeed, the last
argument is parsed to look for an eventual payload pattern. It is started
one character after the newline at the end of the command line. But it is
only valid for an non-empty command line.

So, now, this case is properly detected when we leave if an empty line is
detected.

This patch must be backported to 3.2.
2025-06-05 10:46:13 +02:00
Aurelien DARRAGON
16eb0fab31 MAJOR: counters: dispatch counters over thread groups
Most fe and be counters are good candidates for being shared between
processes. They are now grouped inside "shared" struct sub member under
be_counters and fe_counters.

Now they are properly identified, they would greatly benefit from being
shared over thread groups to reduce the cost of atomic operations when
updating them. For this, we take the current tgid into account so each
thread group only updates its own counters. For this to work, it is
mandatory that the "shared" member from {fe,be}_counters is initialized
AFTER global.nbtgroups is known, because each shared counter causes the stat
to be allocated lobal.nbtgroups times. When updating a counter without
concurrency, the first counter from the array may be updated.

To consult the shared counters (which requires aggregation of per-tgid
individual counters), some helper functions were added to counter.h to
ease code maintenance and avoid computing errors.
2025-06-05 09:59:38 +02:00
Aurelien DARRAGON
12c3ffbb48 MINOR: counters: add local-only internal rates to compute some maxes
cps_max (max new connections received per second), sps_max (max new
sessions per second) and http.rps_max (maximum new http requests per
second) all rely on shared counters (namely conn_per_sec, sess_per_sec and
http.req_per_sec). The problem is that shared counters are about to be
distributed over thread groups, and we cannot afford to compute the
total (for all thread groups) each time we update the max counters.

Instead, since such max counters (relying on shared counters) are a very
few exceptions, let's add internal (sess,conn,req) per sec freq counters
that are dedicated to cps_max, sps_max and http.rps_max computing.

Thanks to that, related *_max counters shouldn't be negatively impacted
by the thread-group distribution, yet they will not benefit from it
either. Related internal freq counters are prefixed with "_" to emphasize
the fact that they should not be used for other purpose (the shared ones,
which are about to be distributed over thread groups in upcoming commits
are still available and must be used instead). The internal ones could
eventually be removed at any time if we find another way to compute the
{cps,sps,http.rps)_max counters.
2025-06-05 09:59:31 +02:00
Aurelien DARRAGON
b72a8bb138 CLEANUP: counters: merge some common counters between {fe,be}_counters_shared
Now that we have a common struct between fe and be shared counters struct
let's perform some cleanup to merge duplicate members into the common
struct part. This will ease code maintenance.
2025-06-05 09:59:24 +02:00
Aurelien DARRAGON
b599138842 MEDIUM: counters: manage shared counters using dedicated helpers
proxies, listeners and server shared counters are now managed via helpers
added in one of the previous commits.

When guid is not set (ie: when not yet assigned), shared counters pointer
is allocated using calloc() (local memory) and a flag is set on the shared
counters struct to know how to manipulate (and free it). Else if guid is
set, then it means that the counters may be shared so while for now we
don't actually use a shared memory location the API is ready for that.

The way it works, for proxies and servers (for which guid is not known
during creation), we first call counters_{fe,be}_shared_get with guid not
set, which results in local pointer being retrieved (as if we just
manually called calloc() to retrieve a pointer). Later (during postparsing)
if guid is set we try to upgrade the pointer from local to shared.

Lastly, since the memory location for some objects (proxies and servers
counters) may change from creation to postparsing, let's update
counters->last_change member directly under counters_{fe,be}_shared_get()
so we don't miss it.

No change of behavior is expected, this is only preparation work.
2025-06-05 09:59:17 +02:00
Aurelien DARRAGON
c10ce1c85b MINOR: counters: add common struct and flags to {fe,be}_counters_shared
fe_counters_shared and be_counters_shared may share some common members
since they are quite similar, so we add a common struct part shared
between the two. struct counters_shared is added for convenience as
a generic pointer to manipulate common members from fe or be shared
counters pointer.

Also, the first common member is added: shared fe and be counters now
have a flags member.
2025-06-05 09:59:10 +02:00
Aurelien DARRAGON
aa53887398 MINOR: counters: add shared counters helpers to get and drop shared pointers
create include/haproxy/counters.h and src/counters.c files to anticipate
for further helpers as some counters specific tasks needs to be carried
out and since counters are shared between multiple object types (ie:
listener, proxy, server..) we need generic helpers.

Add some shared counters helper which are not yet used but will be updated
in upcoming commits.
2025-06-05 09:59:04 +02:00
Aurelien DARRAGON
a0dcab5c45 MAJOR: counters: add shared counters base infrastructure
Shareable counters are not tagged as shared counters and are dynamically
allocated in separate memory area as a prerequisite for being stored
in shared memory area. For now, GUID and threads groups are not taken into
account, this is only a first step.

also we ensure all counters are now manipulated using atomic operations,
namely, "last_change" counter is now read from and written to using atomic
ops.

Despite the numerous changes caused by the counters being moved away from
counters struct, no change of behavior should be expected.
2025-06-05 09:58:58 +02:00
Aurelien DARRAGON
89b04f2191 CLEANUP: sink: remove useless cleanup in sink_new_from_logger()
As reported by Ilya in GH #2994, some cleanup parts in
sink_new_from_logger() function are not used.

We can actually simplify the cleanup logic to remove dead code, let's
do that by renaming "error_final" label to "error" and only making use
of the "error" label, because sink_free() already takes care of proper
cleanup for all sink members.
2025-06-05 09:58:50 +02:00
Christopher Faulet
8c4bb8cab3 BUG/MINOR: mux-spop: Fix null-pointer deref on SPOP stream allocation failure
When we try to allocate a new SPOP stream, if an error is encountered,
spop_strm_destroy() is called to released the eventually allocated
stream. But, it must only be called if a stream was allocated. If the
reported error is an SPOP stream allocation failure, we must just leave to
avoid null-pointer dereference.

This patch should fix point 1 of the issue #2993. It must be backported as
far as 3.1.
2025-06-04 08:48:49 +02:00
Christopher Faulet
6786b05297 DEBUG: check: Add the healthcheck's expiration date in the trace messags
It could help to diagnose some issues about timeout processing. So let's add
it !
2025-06-03 15:06:12 +02:00
Christopher Faulet
8ee650a88b CLEANUP: applet: Update comment for applet_put* functions
These functions were copied from the channel API and modified to work with
applets using the new API or the legacy one. However, the comments were
updated accordingly. It is the purpose of this patch.
2025-06-03 15:03:30 +02:00
Christopher Faulet
7c788f0984 BUG/MEDIUM: check: Requeue healthchecks on I/O events to handle check timeout
When a healthchecks is processed, once the first wakeup passed to start the
check, and as long as the expiration timer is not reached, only I/O events
are able to wake it up. It is an issue when there is a check timeout
defined.  Especially if the connect timeout is high and the check timeout is
low. In that case, the healthcheck's task is never requeue to handle any
timeout update. When the connection is established, the check timeout is set
to replace the connect timeout. It is thus possible to report a success
while a timeout should be reported.

So, now, when an I/O event is handled, the healthcheck is requeue, except if
an success or an abort is reported.

Thanks to Thierry Fournier for report and the reproducer.

This patch must be backported to all stable versions.
2025-06-03 15:03:30 +02:00
Olivier Houchard
913b2d6c83 BUG/MAJOR: leastconn: Protect tree_elt with the lbprm lock
In fwlc_srv_reposition(), set the server's tree_elt while we still hold
the lbprm read lock. While it was protected from concurrent
fwlc_srv_reposition() calls by the server's lb_lock, it was not from
dequeuing/requeuing that could occur if the server gets down/up or its
weight is changed, and that would lead to inconsistencies, and the
watchdog killing the process because it is stuck in an infinite loop in
fwlc_get_next_server().

This hopefully fixes github issue #2990.

This should be backported to 3.2.
2025-06-03 04:42:47 +02:00
Aurelien DARRAGON
368d01361a MEDIUM: server: add and use srv_init() function
rename _srv_postparse() internal function to srv_init() function and group
srv_init_per_thr() plus idle conns list init inside it. This way we can
perform some simplifications as srv_init() performs multiple server
init steps after parsing.

SRV_F_CHECKED flag was added, it is automatically set when srv_init()
runs successfully. If the flag is already set and srv_init() is called
again, nothing is done. This permis to manually call srv_init() earlier
than the default POST_CHECK hook when needed without risking to do things
twice.
2025-06-02 17:51:33 +02:00
Aurelien DARRAGON
889ef6f67b MEDIUM: server: automatically add server to proxy list in new_server()
while new_server() takes the parent proxy as argument and even assigns
srv->proxy to the parent proxy, it didn't actually inserted the server
to the parent proxy server list on success.

The result is that sometimes we add the server to the list after
new_server() is called, and sometimes we don't.

This is really error-prone and because of that hooks such as
REGISTER_POST_SERVER_CHECK() which as run for all servers listed in
all proxies may not be relied upon for servers which are not actually
inserted in their parent proxy server list. Plus it feels very strange
to have a server that points to a proxy, but then the proxy doesn't know
about it because it cannot find it in its server list.

To prevent errors and make proxy->srv list reliable, we move the insertion
logic directly under new_server(). This requires to know if we are called
during parsing or during runtime to either insert or append the server to
the parent proxy list. For that we use PR_FL_CHECKED flag from the parent
proxy (if the flag is set, then the proxy was checked so we are past the
init phase, thus we assume we are called during runtime)

This implies that during startup if new_server() has to be cancelled on
error paths we need to call srv_detach() (which is now exposed in server.h)
before srv_drop().

The consequence of this commit is that REGISTER_POST_SERVER_CHECK() should
not run reliably on all servers created using new_server() (without having
to manually loop on global servers_list)
2025-06-02 17:51:30 +02:00
Aurelien DARRAGON
e262e4bbe4 MEDIUM: proxy: use global proxy list for REGISTER_POST_PROXY_CHECK() hook
REGISTER_POST_PROXY_CHECK() used to iterate over "main" proxies to run
registered callbacks. This means hidden proxies (and their servers) did
not get a chance to get post-checked and could cause issues if some post-
checks are expected to be executed on all proxies no matter their type.

Instead we now rely on the global proxies list. Another side effect is that
the REGISTER_POST_SERVER_CHECK() now runs as well for servers from proxies
that are not part of the main proxies list.
2025-06-02 17:51:27 +02:00
Aurelien DARRAGON
1f12e45b0a MINOR: log: only run postcheck_log_backend() checks on backend
postcheck_log_backend() checks are executed no matter if the proxy
actually has the backend capability while the checks actually depend
on this.

Let's fix that by adding an extra condition to ensure that the BE
capability is set.

This issue is not tagged as a bug because for now it remains impossible
to have a syslog proxy without BE capability in the main proxy list, but
this may change in the future.
2025-06-02 17:51:24 +02:00
Aurelien DARRAGON
943958c3ff MINOR: proxy: add a true list containing all proxies
We have global proxies_list pointer which is announced as the list of
"all existing proxies", but in fact it only represents regular proxies
declared on the config file through "listen, frontend or backend" keywords

It is ambiguous, and we currently don't have a straightforwrd method to
iterate over all proxies (either public or internal ones) within haproxy

Instead we still have to manually iterate over multiple lists (main
proxies, log-forward proxies, peer proxies..) which is error-prone.

In this patch we add a struct list member (8 bytes) inside struct proxy
in order to store every proxy (except default ones) within a global
"proxies" list which is actually representative for all proxies existing
under haproxy process, like we already have for servers.
2025-06-02 17:51:21 +02:00
Aurelien DARRAGON
6ccf770fe2 MINOR: proxy: collect per-capability stat in proxy_cond_disable()
proxy_cond_disable() collects and prints cumulated connections for be and
fe proxies no matter their type. With shared stats it may cause issues
because depending on the proxy capabilities only fe or be counters may
be allocated.

In this patch we add some checks to ensure we only try to read from
valid memory locations, else we rely on default values (0).
2025-06-02 17:51:17 +02:00
Aurelien DARRAGON
c7c017ec3c MINOR: stats: add ME_NEW_COMMON() helper
Split ME_NEW_* helper into COMMON part and specific part so it becomes
easier to add alternative helpers without code duplication.
2025-06-02 17:51:12 +02:00
Aurelien DARRAGON
d04843167c MINOR: stats: add stat_col flags
Add stat_col flags member to store .generic bit and prepare for upcoming
flags. No functional change expected.
2025-06-02 17:51:08 +02:00
Aurelien DARRAGON
f0b40b49b8 MINOR: server: group postinit server tasks under _srv_postparse()
init_srv_requeue() and init_srv_slowstart() functions are called after
initial server parsing via REGISTER_POST_SERVER_CHECK() hook, and they
are also manually called for dynamic server after the server is
initialized.

This may conflict with _srv_postparse() which is also registered via
REGISTER_POST_SERVER_CHECK() and called during dynamic server creation

To ensure functions don't conflict with each other, let's ensure they
are executed in proper order by calling init_srv_requeue and
init_srv_slowstart() from _srv_postparse() which now becomes the parent
function for server related postparsing stuff. No change of behavior is
expected.
2025-06-02 17:51:05 +02:00
Tim Duesterhus
8ee8b8a04d REGTESTS: Remove support for REQUIRE_VERSION and REQUIRE_VERSION_BELOW
This is no longer used since the migration to the native `haproxy -cc
'version_atleast(X)'` functionality.

see 8727614dc4046e91997ecce421bcb6a5537cac93
see 5efc48dcf1b133dd415c759e83b21d52dc303786
2025-06-02 17:37:11 +02:00
Tim Duesterhus
d8951ec70f REGTESTS: Remove tests with REQUIRE_VERSION_BELOW=2.4
HAProxy 2.4 is the lowest supported version, thus this never matches.

see 18cd4746e5aff9da78d16220b0412947ceba24f3
2025-06-02 17:37:07 +02:00
Tim Duesterhus
534b09f2a2 REGTESTS: Remove REQUIRE_VERSION=2.4 from all tests
HAProxy 2.4 is the lowest supported version, thus this always matches.

see 7aff1bf6b90caadfa95f6b43b526275191991d6f
2025-06-02 17:37:04 +02:00
Tim Duesterhus
239785fd27 REGTESTS: Remove REQUIRE_VERSION=2.3 from all tests
HAProxy 2.4 is the lowest supported version, thus this always matches.

see 7aff1bf6b90caadfa95f6b43b526275191991d6f
2025-06-02 17:37:00 +02:00
Tim Duesterhus
294c47a5ef REGTESTS: Do not use REQUIRE_VERSION for HAProxy 2.5+ (5)
Introduced in:

25bcdb1d9 BUG/MAJOR: h1: Be stricter on request target validation during message parsing

see also:

fbbbc33df REGTESTS: Do not use REQUIRE_VERSION for HAProxy 2.5+
2025-06-02 17:36:56 +02:00
Christopher Faulet
8e8cdf114b DOC: config: Fix a typo in 2.7 (Name format for maps and ACLs)
"identified" was used instead of "identifier". May be backported as far as
3.0
2025-06-02 09:19:38 +02:00
Willy Tarreau
b88164d9c0 BUILD: tools: properly define ha_dump_backtrace() to avoid a build warning
In resolve_sym_name() we declare a few symbols that we want to be able
to resolve. ha_dump_backtrace() was declared with a struct buffer instead
of a pointer to such a struct, which has no effect since we only want to
get the function's pointer, but produces a build warning with LTO, so
let's fix it.

This can be backported to 3.0.
2025-05-30 17:15:48 +02:00
Willy Tarreau
9f4cd435d3 [RELEASE] Released version 3.3-dev0
Released version 3.3-dev0 with the following main changes :
    - MINOR: version: mention that it's development again
2025-05-28 16:46:34 +02:00
Willy Tarreau
8809251ee0 MINOR: version: mention that it's development again
This essentially reverts a6458fd4269.
2025-05-28 16:46:15 +02:00
Willy Tarreau
e134140d28 [RELEASE] Released version 3.2.0
Released version 3.2.0 with the following main changes :
    - MINOR: promex: Add agent check status/code/duration metrics
    - MINOR: ssl: support strict-sni in ssl-default-bind-options
    - MINOR: ssl: also provide the "tls-tickets" bind option
    - MINOR: server: define CLI I/O handler for "add server"
    - MINOR: server: implement "add server help"
    - MINOR: server: use stress mode for "add server help"
    - BUG/MEDIUM: server: fix crash after duplicate GUID insertion
    - BUG/MEDIUM: server: fix potential null-deref after previous fix
    - MINOR: config: list recently added sections with -dKcfg
    - BUG/MAJOR: cache: Crash because of wrong cache entry deleted
    - DOC: configuration: fix the example in crt-store
    - DOC: config: clarify the wording around single/double quotes
    - DOC: config: clarify the legacy cookie and header captures
    - DOC: config: fix alphabetical ordering of layer 7 sample fetch functions
    - DOC: config: fix alphabetical ordering of layer 6 sample fetch functions
    - DOC: config: fix alphabetical ordering of layer 5 sample fetch functions
    - DOC: config: fix alphabetical ordering of layer 4 sample fetch functions
    - DOC: config: fix alphabetical ordering of internal sample fetch functions
    - BUG/MINOR: h3: Set HTX flags corresponding to the scheme found in the request
    - BUG/MEDIUM: h3: Declare absolute URI as normalized when a :authority is found
    - DOC: config: mention in bytes_in and bytes_out that they're read on input
    - DOC: config: clarify the basics of ACLs (call point, multi-valued etc)
    - REGTESTS: Make the script testing conditional set-var compatible with Vtest2
    - REGTESTS: Explicitly allow failing shell commands in some scripts
    - MINOR: listeners: Add support for a label on bind line
    - BUG/MEDIUM: cli/ring: Properly handle shutdown in "show event" I/O handler
    - BUG/MEDIUM: hlua: Properly detect shudowns for TCP applets based on the new API
    - BUG/MEDIUM: hlua: Fix getline() for TCP applets to work with applet's buffers
    - BUG/MEDIUM: hlua: Fix receive API for TCP applets to properly handle shutdowns
    - CI: vtest: Rely on VTest2 to run regression tests
    - CI: vtest: Fix the build script to properly work on MaOS
    - CI: combine AWS-LC and AWS-LC-FIPS by template
    - BUG/MEDIUM: httpclient: Throw an error if an lua httpclient instance is reused
    - DOC: hlua: Add a note to warn user about httpclient object reuse
    - DOC: hlua: fix a few typos in HTTPMessage.set_body_len() documentation
    - DEV: patchbot: prepare for new version 3.3-dev
    - MINOR: version: mention that it's 3.2 LTS now.
2025-05-28 16:35:14 +02:00
Willy Tarreau
a6458fd426 MINOR: version: mention that it's 3.2 LTS now.
The version will be maintained up to around Q2 2030. Let's
also update the INSTALL file to mention this.
2025-05-28 16:31:27 +02:00
Willy Tarreau
2502435eb3 DEV: patchbot: prepare for new version 3.3-dev
The bot will now load the prompt for the upcoming 3.2 version so we have
to rename the files and update their contents to match the current version.
2025-05-28 16:23:12 +02:00
Willy Tarreau
21ce685fcd DOC: hlua: fix a few typos in HTTPMessage.set_body_len() documentation
A few typos were noticed while gathering info for the 3.2 announce
messages, this fixes them, and will probably constitute the last
commit of this release. There's no need to backport it unless commit
94055a5e7 ("MEDIUM: hlua: Add function to change the body length of
an HTTP Message") is backported.
2025-05-27 19:33:49 +02:00
Christopher Faulet
cb7a2444d1 DOC: hlua: Add a note to warn user about httpclient object reuse
It is not supported to reuse an lua httpclient instance to process several
requests. A new object must be created for each request. Thanks to the
previous patch ("BUG/MEDIUM: httpclient: Throw an error if an lua httpclient
instance is reused"), an error is now reported if this happens. But it is
not obvious for users. So the lua-api docuementation was updated accordingly.

This patch is related to issue #2986. It should be backported with the
commit above.
2025-05-27 18:48:23 +02:00
Christopher Faulet
50fca6f0b7 BUG/MEDIUM: httpclient: Throw an error if an lua httpclient instance is reused
It is not expected/supported to reuse an httpclient instance to process
several requests. A new instance must be created for each request. However,
in lua, there is nothing to prevent a user to create an httpclient object
and use it in a loop to process requests.

That's unfortunate because this will apparently work, the requests will be
sent and a response will be received and processed. However internally some
ressources will be allocated and never released. When the next response is
processed, the ressources allocated for the previous one are definitively
lost.

In this patch we take care to check that the httpclient object was never
used when a request is sent from a lua script by checking
HTTPCLIENT_FS_STARTED flags. This flag is set when a httpclient applet is
spawned to process a request and never removed after that. In lua, the
httpclient applet is created when the request is sent. So, it is the right
place to do this test.

This patch should fix the issue #2986. It should be backported as far as
2.6.
2025-05-27 18:47:24 +02:00
Ilya Shipitsin
94ded5523f CI: combine AWS-LC and AWS-LC-FIPS by template
let's reduce code duplication by involving workflow templates
2025-05-27 15:06:58 +02:00
Christopher Faulet
508e074a32 CI: vtest: Fix the build script to properly work on MaOS
"config.h" header file is new in VTest2 and includes must be adapted to be
able to build VTest on MacOS. Let's add "-I." to make it work.
2025-05-27 14:48:53 +02:00
Christopher Faulet
6a18d28ba2 CI: vtest: Rely on VTest2 to run regression tests
VTest2 (https://github.com/vtest/VTest2) was released and is a remplacement
for VTest. VTest was archived. So let's use the new version now.

If this commit is backported, the 2 following commits must also be
backported:

 * 2808e3577 ("REGTESTS: Explicitly allow failing shell commands in some scripts")
 * 82c291124 ("REGTESTS: Make the script testing conditional set-var compatible with Vtest2")
2025-05-27 14:38:46 +02:00
Christopher Faulet
bc4c3c7969 BUG/MEDIUM: hlua: Fix receive API for TCP applets to properly handle shutdowns
An optional timeout was added to AppletTCP.receive() to interrupt calls after a
delay. It was mandatory to be able to implement interactive applets (like
trisdemo). However, this broke the API and it made impossible to differentiate
the shutdowns from the delays expirations. Indeed, in both cases, an empty
string was returned.

Because historically an empty string was used to notify a connection shutdown,
it should not be changed. So now, 'nil' value is returned when no data was
available before the delay expiration.

The new AppletTCP:try_receive() function was also affected. To fix it, instead
of stating there is no delay when a receive is tried, an expired delay is
set. Concretely TICK_ETERNITY was replaced by now_ms.

Finally, AppletTCP:getline() function is not concerned for now because there
is no way to interrupt it after some delay.

The documentation and trisdemo lua script were updated accordingly.

This patch depends on "BUG/MEDIUM: hlua: Properly detect shudowns for TCP
applets based on the new API". However, it is a 3.2-specific issue, so no
backport is needed.
2025-05-27 07:53:19 +02:00
Christopher Faulet
c0ecef71d7 BUG/MEDIUM: hlua: Fix getline() for TCP applets to work with applet's buffers
The commit e5e36ce09 ("BUG/MEDIUM: hlua/cli: Fix lua CLI commands to work
with applet's buffers") fixed the TCP applets API to work with applets using
its own buffers. Howver the getline() function was not updated. It could be
an issue for anyone registering a CLI commands reading lines.

This patch should be backported as far as 3.0.
2025-05-27 07:53:01 +02:00
Christopher Faulet
c64781c2c8 BUG/MEDIUM: hlua: Properly detect shudowns for TCP applets based on the new API
The internal function responsible to receive data for TCP applets with
internal buffers is buggy. Indeed, for these applets, the buffer API is used
to get data. So there is no tests on the SE to properly detect connection
shutdowns. So, it must be performed by hand after the call to b_getblk_nc().

This patch must be backported as far as 3.0.
2025-05-26 19:00:00 +02:00
Christopher Faulet
4d4da515f2 BUG/MEDIUM: cli/ring: Properly handle shutdown in "show event" I/O handler
The commit 03dc54d802 ("BUG/MINOR: ring: Fix I/O handler of "show event"
command to not rely on the SC") introduced a regression. By removing
dependencies on the SC, a test to detect client shutdowns was removed. So
now, the CLI applet is no longer released when the client shut the
connection during a "show event -w".

So of course, we should not use the SC to detect the shutdowns. But the SE
must be used insteead.

It is a 3.2-specific issue, so no backport needed.
2025-05-26 19:00:00 +02:00
Christopher Faulet
99e755d673 MINOR: listeners: Add support for a label on bind line
It is now possile to set a label on a bind line. All sockets attached to
this bind line inherits from this label. The idea is to be able to groud of
sockets. For now, there is no mechanism to create these groups, this must be
done by hand.
2025-05-26 19:00:00 +02:00
Christopher Faulet
2808e3577f REGTESTS: Explicitly allow failing shell commands in some scripts
Vtest2, that should replaced Vtest in few months, will reject any failing
commands in shell blocks. However, some scripts are executing some commands,
expecting an error to be able to parse the error output. So, now use "set
+e" in those scripts to explicitly state failing commads are expected.

It is just used for non-final commands. At the end, the shell block must
still report a success.
2025-05-26 19:00:00 +02:00
Christopher Faulet
82c2911248 REGTESTS: Make the script testing conditional set-var compatible with Vtest2
VTest2 will replaced VTest in few months. There is not so much change
expected. One of them is that a User-Agent header is added by default in all
requests, except if an custom one is already set or if "-nouseragent" option
is used. To still be compatible with VTest, it is not possible to use the
option to avoid the header addition. So, a custom user-agent is added in the
last test of "sample_fetches/cond_set_var.vtc" to be sure it will pass with
Vtest and Vtest2. It is mandatory because the request length is tested.
2025-05-26 19:00:00 +02:00
Willy Tarreau
5b937b7a97 DOC: config: clarify the basics of ACLs (call point, multi-valued etc)
This is essentially in order to address the concerns expressed in
issue #2226 where it is mentioned that the moment they are called is
not clear enough. Admittedly, re-reading the paragraph doesn't make
it obvious on a quick read that they behave like functions. This patch
adds an extra paragraph that makes the parallel with programming
languages' boolean functions and explains the fact that they can be
multi-valued. Hoping this is clearer now.
2025-05-26 16:25:22 +02:00
Willy Tarreau
ef9511be90 DOC: config: mention in bytes_in and bytes_out that they're read on input
Issue #2267 suggests that it's unclear what exactly the byte counts mean
(particularly when compression is involved). Let's clarify that the counts
are read on data input and that they also cover headers and a bit of
internal overhead.
2025-05-26 15:54:36 +02:00
Christopher Faulet
e70c23e517 BUG/MEDIUM: h3: Declare absolute URI as normalized when a :authority is found
Since commit 2c3d656f8 ("MEDIUM: h3: use absolute URI form with
:authority"), the absolute URI form is used when a ':authority'
pseudo-header is found. However, this URI was not declared as normalized
internally.  So, when the request is reformated to be sent to an h1 server,
the absolute-form is used instead of the origin-form. It is unexpected and
may be an issue for some servers that could reject the request.

So, now, we take care to set HTX_SL_F_HAS_AUTHORITY flag on the HTX message
when an authority was found and HTX_SL_F_NORMALIZED_URI flag is set for
"http" or "https" schemes.

No backport needed because the commit above must not be backported. It
should fix a regression reported on the 3.2-dev17 in issue #2977.

This commit depends on "BUG/MINOR: h3: Set HTX flags corresponding to the
scheme found in the request".
2025-05-26 11:47:23 +02:00
Christopher Faulet
da9792cca8 BUG/MINOR: h3: Set HTX flags corresponding to the scheme found in the request
When a ":scheme" pseudo-header is found in a h3 request, the
HTX_SL_F_HAS_SCHM flag must be set on the HTX message. And if the scheme is
'http' or 'https', the corresponding HTX flag must also be set. So,
respectively, HTX_SL_F_SCHM_HTTP or HTX_SL_F_SCHM_HTTPS.

It is mainly used to send the right ":scheme" pseudo-header value to H2
server on backend side.

This patch could be backported as far as 2.6.
2025-05-26 11:38:29 +02:00
Willy Tarreau
083708daf8 DOC: config: fix alphabetical ordering of internal sample fetch functions
Some misordering has been accumulating over time, making some of them
hard to spot. Also "uptime" was not indexed.
2025-05-26 09:36:23 +02:00
Willy Tarreau
52c2247d90 DOC: config: fix alphabetical ordering of layer 4 sample fetch functions
Some misordering has been accumulating over time, making some of them
hard to spot.
2025-05-26 09:33:17 +02:00
Willy Tarreau
770098f5e3 DOC: config: fix alphabetical ordering of layer 5 sample fetch functions
Some misordering has been accumulating over time, making some of them
hard to spot.
2025-05-26 09:26:11 +02:00
Willy Tarreau
5261e35b8f DOC: config: fix alphabetical ordering of layer 6 sample fetch functions
Some misordering has been accumulating over time, making some of them
hard to spot.
2025-05-26 09:26:11 +02:00
Willy Tarreau
e9248243e9 DOC: config: fix alphabetical ordering of layer 7 sample fetch functions
Some misordering has been accumulating over time, making some of them
hard to spot.
2025-05-26 09:26:11 +02:00
Willy Tarreau
38456f63a3 DOC: config: clarify the legacy cookie and header captures
As reported in issue #2195, cookie captures and header captures are no
longer the recommended way to proceed. Let's mention that this is the
legacy way and provide a few pointers to the recommended functions and
actions to use the modern methods.
2025-05-26 08:56:33 +02:00
Willy Tarreau
da8d6d1b2c DOC: config: clarify the wording around single/double quotes
As reported in issue #2327, the wording used in the section about quoting
can be read two ways due to the use of the two types of quotes to protect
each other quote. Better only use the quoting without mixing the two when
mentioning them.
2025-05-26 08:36:33 +02:00
William Lallemand
d607940915 DOC: configuration: fix the example in crt-store
Fix a bad example in the crt-store section. site1 does not use the "web"
crt-store but the global one.

Must be backported as far as 3.0 however the section was 3.12 in
previous version.
2025-05-25 16:55:08 +02:00
Remi Tricot-Le Breton
90441e9bfe BUG/MAJOR: cache: Crash because of wrong cache entry deleted
When "vary" is enabled, we can have multiple entries for a given primary
key in the cache tree. There is a limit to how many secondary entries
can be inserted for a given key. When we try to insert a new secondary
entry, if the limit is already reached, we can try to find expired
entries with the same primary key, and if the limit is still reached we
want to abort the current insertion and to remove the node that was just
inserted.

In commit "a29b073: MEDIUM: cache: Add refcount on cache_entry" though,
a regression was introduced. Instead of removing the entry just inserted
as the comments suggested, we removed the second to last entry and
returned NULL. We then reset the eb.key of the cache_entry in the caller
because we assumed that the entry was already removed from the tree.

This means that some entries with an empty key were wrongly kept in the
tree and the last secondary entry, which keeps the number of secondary
entries of a given key was removed.

This ended up causing some crashes later on when we tried to iterate
over the elements of this given key. The crash could occur in multiple
places, either when trying to retrieve an entry or to add some new ones.

This crash was raised in GitHub issue #2950.
The fix should be backported up to 3.0.
2025-05-23 22:38:54 +02:00
Willy Tarreau
84ffb3d0a9 MINOR: config: list recently added sections with -dKcfg
Newly added sections (crt-store, traces, acme) were not listed in
-dKcfg, let's add them. For now they have to be manually enumerated.
2025-05-23 10:49:33 +02:00
Willy Tarreau
28c7a22790 BUG/MEDIUM: server: fix potential null-deref after previous fix
A valid build warning was reported in the CI with latest commit b40ce97ecc
("BUG/MEDIUM: server: fix crash after duplicate GUID insertion"). Indeed,
if the first test in the function fails, we branch to the err label
with guid==NULL and will crash there. Let's just test guid before
dereferencing it for freeing.

This needs to be backported to 3.0 as well since the commit above was
meant to go there.
2025-05-22 18:09:12 +02:00
Amaury Denoyelle
b40ce97ecc BUG/MEDIUM: server: fix crash after duplicate GUID insertion
On "add server", if a GUID is defined, guid_insert() is used to add the
entry into the global GUID tree. If a similar entry already exists, GUID
insertion fails and the server creation is eventually aborted.

A crash could occur in this case because of an invalid memory access via
guid_remove(). The latter is caused via free_server() as the server
insertion is rejected. The invalid occurs on GUID key.

The issue occurs because of guid_insert(). The function properly
deallocates the GUID key on duplicate insertion, but it failed to reset
<guid.node.key> to NULL. This caused the invalid memory access on
guid_remove(). To fix this, ensure that key member is properly resetted
on guid_insert() error path.

This must be backported up to 3.0.
2025-05-22 17:59:37 +02:00
Amaury Denoyelle
5e088e3f8e MINOR: server: use stress mode for "add server help"
Implement stress mode on "add server help". This ensures that the
command is fully reentrant on full output buffer.

For testing, it requires compilation with USE_STRESS and global setting
"stress-level 1".
2025-05-22 17:40:05 +02:00
Amaury Denoyelle
4de5090976 MINOR: server: implement "add server help"
Implement "help" as a sub-command for "add server" CLI. The objective is
to list all the keywords that are supported for dynamic servers. CLI IO
handler and add_srv_ctx are used to support reentrancy on full output
buffer.

Now that this command is implemented, the outdated keyword list on "add
server" from management documentation can be removed.
2025-05-22 17:40:05 +02:00
Amaury Denoyelle
2570892c41 MINOR: server: define CLI I/O handler for "add server"
Extend "add server" to support an IO handler function named
cli_io_handler_add_server(). A context object is also defined whose
usage will depend on IO handler capabilities.

IO handler is skipped when "add server" is run in default mode, i.e. on
a dynamic server creation. Thus, currently IO handler is unneeded.
However, it will become useful to support sub-commands for "add server".

Note that return value of "add server" parser has been changed on server
creation success. Previously, it was used incorrectly to report if
server was inserted or not. In fact, parser return value is used by CLI
generic code to detect if command processing has been completed, or
should continue to the IO handler. Now, "add server" always returns 1 to
signal that CLI processing is completed. This is necessary to preserve
CLI output emitted by parser, even now that IO handler is defined for
the command. Previously, output was emitted in every situations due to
IO handler not defined. See below code snippet from cli.c for a better
overview :

  if (kw->parse && kw->parse(args, payload, appctx, kw->private) != 0) {
          ret = 1;
          goto fail;
  }

  /* kw->parse could set its own io_handler or io_release handler */
  if (!appctx->cli_ctx.io_handler) {
          ret = 1;
          goto fail;
  }

  appctx->st0 = CLI_ST_CALLBACK;
  ret = 1;
  goto end;
2025-05-22 17:40:05 +02:00
Willy Tarreau
1c0f2e62ad MINOR: ssl: also provide the "tls-tickets" bind option
Currently there is "no-tls-tickets" that is also supported in the
ssl-default-bind-options directive, but there's no way to re-enable
them on a specific "bind" line. This patch simply provides the option
to re-enable them. Note that the flag is inverted because tickets are
enabled by default and the no-tls-ticket option sets the flag to
disable them.
2025-05-22 15:31:54 +02:00
Willy Tarreau
3494775a1f MINOR: ssl: support strict-sni in ssl-default-bind-options
Several users already reported that it would be nice to support
strict-sni in ssl-default-bind-options. However, in order to support
it, we also need an option to disable it.

This patch moves the setting of the option from the strict_sni field
to a flag in the ssl_options field so that it can be inherited from
the default bind options, and adds a new "no-strict-sni" directive to
allow to disable it on a specific "bind" line.

The test file "del_ssl_crt-list.vtc" which already tests both options
was updated to make use of the default option and the no- variant to
confirm everything continues to work.
2025-05-22 15:31:54 +02:00
Christopher Faulet
7244f16ac4 MINOR: promex: Add agent check status/code/duration metrics
In the Prometheus exporter, the last health check status is already exposed,
with its code and duration in seconds. The server status is also exposed.
But the information about the agent check are not available. It is not
really handy because when a server status is changed because of the agent,
it is not obvious by looking to the Prometheus metrics. Indeed, the server
may reported as DOWN for instance, while the health check status still
reports a success. Being able to get the agent status in that case could be
valuable.

So now, the last agent check status is exposed, with its code and duration
in seconds. Following metrics can be grabbe now:

  * haproxy_server_agent_status
  * haproxy_server_agent_code
  * haproxy_server_agent_duration_seconds

Note that unlike the other metrics, no per-backend aggregated metric is
exposed.

This patch is related to issue #2983.
2025-05-22 09:50:10 +02:00
Willy Tarreau
0ac41ff97e [RELEASE] Released version 3.2-dev17
Released version 3.2-dev17 with the following main changes :
    - DOC: configuration: explicit multi-choice on bind shards option
    - BUG/MINOR: sink: detect and warn when using "send-proxy" options with ring servers
    - BUG/MEDIUM: peers: also limit the number of incoming updates
    - MEDIUM: hlua: Add function to change the body length of an HTTP Message
    - BUG/MEDIUM: stconn: Disable 0-copy forwarding for filters altering the payload
    - BUG/MINOR: h3: don't insert more than one Host header
    - BUG/MEDIUM: h1/h2/h3: reject forbidden chars in the Host header field
    - DOC: config: properly index "table and "stick-table" in their section
    - DOC: management: change reference to configuration manual
    - BUILD: debug: mark ha_crash_now() as attribute(noreturn)
    - IMPORT: slz: avoid multiple shifts on 64-bits
    - IMPORT: slz: support crc32c for lookup hash on sse4 but only if requested
    - IMPORT: slz: use a better hash for machines with a fast multiply
    - IMPORT: slz: fix header used for empty zlib message
    - IMPORT: slz: silence a build warning on non-x86 non-arm
    - BUG/MAJOR: leastconn: do not loop forever when facing saturated servers
    - BUG/MAJOR: queue: properly keep count of the queue length
    - BUG/MINOR: quic: fix crash on quic_conn alloc failure
    - BUG/MAJOR: leastconn: never reuse the node after dropping the lock
    - MINOR: acme: renewal notification over the dpapi sink
    - CLEANUP: quic: Useless BIO_METHOD initialization
    - MINOR: quic: Add useful error traces about qc_ssl_sess_init() failures
    - MINOR: quic: Allow the use of the new OpenSSL 3.5.0 QUIC TLS API (to be completed)
    - MINOR: quic: implement all remaining callbacks for OpenSSL 3.5 QUIC API
    - MINOR: quic: OpenSSL 3.5 internal QUIC custom extension for transport parameters reset
    - MINOR: quic: OpenSSL 3.5 trick to support 0-RTT
    - DOC: update INSTALL for QUIC with OpenSSL 3.5 usages
    - DOC: management: update 'acme status'
    - BUG/MEDIUM: wdt: always ignore the first watchdog wakeup
    - CLEANUP: wdt: clarify the comments on the common exit path
    - BUILD: ssl: avoid possible printf format warning in traces
    - BUILD: acme: fix build issue on 32-bit archs with 64-bit time_t
    - DOC: management: precise some of the fields of "show servers conn"
    - BUG/MEDIUM: mux-quic: fix BUG_ON() on rxbuf alloc error
    - DOC: watchdog: update the doc to reflect the recent changes
    - BUG/MEDIUM: acme: check if acme domains are configured
    - BUG/MINOR: acme: fix formatting issue in error and logs
    - EXAMPLES: lua: avoid screen refresh effect in "trisdemo"
    - CLEANUP: quic: remove unused cbuf module
    - MINOR: quic: move function to check stream type in utils
    - MINOR: quic: refactor handling of streams after MUX release
    - MINOR: quic: add some missing includes
    - MINOR: quic: adjust quic_conn-t.h include list
    - CLEANUP: cfgparse: alphabetically sort the global keywords
    - MINOR: glitches: add global setting "tune.glitches.kill.cpu-usage"
2025-05-21 15:56:06 +02:00
Willy Tarreau
a1577a89a0 MINOR: glitches: add global setting "tune.glitches.kill.cpu-usage"
It was mentioned during the development of glitches that it would be
nice to support not killing misbehaving connections below a certain
CPU usage so that poor implementations that routinely misbehave without
impact are not killed. This is now possible by setting a CPU usage
threshold under which we don't kill them via this parameter. It defaults
to zero so that we continue to kill them by default.
2025-05-21 15:47:42 +02:00
Willy Tarreau
eee57b4d3f CLEANUP: cfgparse: alphabetically sort the global keywords
The global keywords table was no longer sorted at all, let's fix it to
ease spotting the searched ones.
2025-05-21 15:47:42 +02:00
Amaury Denoyelle
00d90e8839 MINOR: quic: adjust quic_conn-t.h include list
Adjust include list in quic_conn-t.h. This file is included in many QUIC
source, so it is useful to keep as lightweight as possible. Note that
connection/QUIC MUX are transformed into forward declaration for better
layer separation.
2025-05-21 14:44:27 +02:00
Amaury Denoyelle
01e3b2119a MINOR: quic: add some missing includes
Insert some missing includes statement in QUIC source files. This was
detected after the next commit which adjust the include list used in
quic_conn-t.h file.
2025-05-21 14:44:27 +02:00
Amaury Denoyelle
f286288471 MINOR: quic: refactor handling of streams after MUX release
quic-conn layer has to handle itself STREAM frames after MUX release. If
the stream was already seen, it is probably only a retransmitted frame
which can be safely ignored. For other streams, an active closure may be
needed.

Thus it's necessary that quic-conn layer knows the highest stream ID
already handled by the MUX after its release. Previously, this was done
via <nb_streams> member array in quic-conn structure.

Refactor this by replacing <nb_streams> by two members called
<stream_max_uni>/<stream_max_bidi>. Indeed, it is unnecessary for
quic-conn layer to monitor locally opened uni streams, as the peer
cannot by definition emit a STREAM frame on it. Also, bidirectional
streams are always opened by the remote side.

Previously, <nb_streams> were set by quic-stream layer. Now,
<stream_max_uni>/<stream_max_bidi> members are only set one time, just
prior to QUIC MUX release. This is sufficient as quic-conn do not use
them if the MUX is available.

Note that previously, IDs were used relatively to their type, thus
incremented by 1, after shifting the original value. For simplification,
use the plain stream ID, which is incremented by 4.
2025-05-21 14:26:45 +02:00
Amaury Denoyelle
07d41a043c MINOR: quic: move function to check stream type in utils
Move general function to check if a stream is uni or bidirectional from
QUIC MUX to quic_utils module. This should prevent unnecessary include
of QUIC MUX header file in other sources.
2025-05-21 14:17:41 +02:00
Amaury Denoyelle
cf45bf1ad8 CLEANUP: quic: remove unused cbuf module
Cbuf are not used anymore. Remove the related source and header files,
as well as include statements in the rest of QUIC source files.
2025-05-21 14:16:37 +02:00
Baptiste Assmann
b437094853 EXAMPLES: lua: avoid screen refresh effect in "trisdemo"
In current version of the game, there is a "screen refresh" effect: the
screen is cleared before being re-drawn.
I moved the clear right after the connection is opened and removed it
from rendering time.
2025-05-21 12:00:53 +02:00
William Lallemand
8b121ab6f7 BUG/MINOR: acme: fix formatting issue in error and logs
Stop emitting \n in errmsg for intermediate error messages, this was
emitting multiline logs and was returning to a new line in the middle of
sentences.

We don't need to emit them in acme_start_task() since the errmsg is
ouput in a send_log which already contains a \n or on the CLI which
also emits it.
2025-05-21 11:41:28 +02:00
William Lallemand
156f4bd7a6 BUG/MEDIUM: acme: check if acme domains are configured
When starting the ACME task with a ckch_conf which does not contain the
domains, the ACME task would segfault because it will try to dereference
a NULL in this case.

The patch fix the issue by emitting a warning when no domains are
configured. It's not done at configuration parsing because it is not
easy to emit the warning because there are is no callback system which
give access to the whole ckch_conf once a line is parsed.

No backport needed.
2025-05-21 11:41:28 +02:00
Willy Tarreau
f5ed309449 DOC: watchdog: update the doc to reflect the recent changes
The watchdog was improved and fixed a few months ago, but the doc had
not been updated to reflect this. That's now done.
2025-05-21 11:34:55 +02:00
Amaury Denoyelle
e399daa67e BUG/MEDIUM: mux-quic: fix BUG_ON() on rxbuf alloc error
RX buffer allocation has been reworked in current dev tree. The
objective is to support multiple buffers per QCS to improve upload
throughput.

RX buffer allocation failure is handled simply : the whole connection is
closed. This is done via qcc_set_error(), with INTERNAL_ERROR as error
code. This function contains a BUG_ON() to ensure it is called only one
time per connection instance.

On RX buffer alloc failure, the aformentioned BUG_ON() crashes due to a
double invokation of qcc_set_error(). First by qcs_get_rxbuf(), and
immediately after it by qcc_recv(), which is the caller of the previous
one. This regression was introduced by the following commit.

  60f64449fbba7bb6e351e8343741bb3c960a2e6d
  MAJOR: mux-quic: support multiple QCS RX buffers

To fix this, simply remove qcc_set_error() invocation in
qcs_get_rxbuf(). On buffer alloc failture, qcc_recv() is responsible to
set the error.

This does not need to be backported.
2025-05-21 11:33:00 +02:00
Willy Tarreau
5c628d4e09 DOC: management: precise some of the fields of "show servers conn"
As reported in issue #2970, the output of "show servers conn" is not
clear. It was essentially meant as a debugging tool during some changes
to idle connections management, but if some users want to monitor or
graph them, more info is needed. The doc mentions the currently known
list of fields, and reminds that this output is not meant to be stable
over time, but as long as it does not change, it can provide some useful
metrics to some users.
2025-05-21 10:45:07 +02:00
Willy Tarreau
4b52d5e406 BUILD: acme: fix build issue on 32-bit archs with 64-bit time_t
The build failed on mips32 with a 64-bit time_t here:

  https://github.com/haproxy/haproxy/actions/runs/15150389164/job/42595310111

Let's just turn the "remain" variable used to show the remaining time
into a more portable ullong and use %llu for all format specifiers,
since long remains limited to 32-bit on 32-bit archs.

No backport needed.
2025-05-21 10:18:47 +02:00
Willy Tarreau
09d4c9519e BUILD: ssl: avoid possible printf format warning in traces
When building on MIPS-32 with gcc-9.5 and glibc-2.31, I got this:

  src/ssl_trace.c: In function 'ssl_trace':
  src/ssl_trace.c:118:42: warning: format '%ld' expects argument of type 'long int', but argument 3 has type 'ssize_t' {aka 'const int'} [-Wformat=]
    118 |     chunk_appendf(&trace_buf, " : size=%ld", *size);
        |                                        ~~^   ~~~~~
        |                                          |   |
        |                                          |   ssize_t {aka const int}
        |                                          long int
        |                                        %d

Let's just cast the type. No backport needed.
2025-05-21 10:01:14 +02:00
Willy Tarreau
3b2fb5cc15 CLEANUP: wdt: clarify the comments on the common exit path
The condition in which we reach the check for ha_panic() and
ha_stuck_warning() are not super clear, let's reformulate them.
2025-05-20 16:37:06 +02:00
Willy Tarreau
0a8bfb5b90 BUG/MEDIUM: wdt: always ignore the first watchdog wakeup
With commit a06c215f08 ("MEDIUM: wdt: always make the faulty thread
report its own warnings"), when the TH_FL_STUCK flag was flipped on,
we'd then go to the panic code instead of giving a second chance like
before the commit. This can trigger rare cases that only happen with
moderate loads like was addressed by commit 24ce001771 ("BUG/MEDIUM:
wdt: fix the stuck detection for warnings"). This is in fact due to
the loss of the common "goto update_and_leave" that used to serve
both the warning code and the flag setting for probation, and it's
apparently what hit Christian in issue #2980.

Let's make sure we exit naturally when turning the bit on for the
first time. Let's also update the confusing comment at the end of
the check that was left over by latest change.

Since the first commit was backported to 3.1, this commit should be
backported there as well.
2025-05-20 16:37:03 +02:00
William Lallemand
dcdf27af70 DOC: management: update 'acme status'
Update the 'acme status' section with the "Stopped" status and fix the
description.
2025-05-20 16:08:57 +02:00
Frederic Lecaille
bbe302087c DOC: update INSTALL for QUIC with OpenSSL 3.5 usages
Update the QUIC sections which mention the OpenSSL library use cases.
2025-05-20 15:00:06 +02:00
Frederic Lecaille
08eee0d9cf MINOR: quic: OpenSSL 3.5 trick to support 0-RTT
For an unidentified reason, SSL_do_hanshake() succeeds at its first call when 0-RTT
is enabled for the connection. This behavior looks very similar by the one encountered
by AWS-LC stack. That said, it was documented by AWS-LC. This issue leads the
connection to stop sending handshake packets after having release the handshake
encryption level. In fact, no handshake packets could even been sent leading
the handshake to always fail.

To fix this, this patch simulates a "handshake in progress" state waiting
for the application level read secret to be established by the TLS stack.
This may happen only after the QUIC listener has completed/confirmed the handshake
upon handshake CRYPTO data receipt from the peer.
2025-05-20 15:00:06 +02:00
Frederic Lecaille
849a3af14e MINOR: quic: OpenSSL 3.5 internal QUIC custom extension for transport parameters reset
A QUIC must sent its transport parameter using a TLS custom extention. This
extension is reset by SSL_set_SSL_CTX(). It can be restored calling
quic_ssl_set_tls_cbs() (which calls SSL_set_quic_tls_cbs()).
2025-05-20 15:00:06 +02:00
Frederic Lecaille
b3ac1a636c MINOR: quic: implement all remaining callbacks for OpenSSL 3.5 QUIC API
The quic_conn struct is modified for two reasons. The first one is to store
the encoded version of the local tranport parameter as this is done for
USE_QUIC_OPENSSL_COMPAT. Indeed, the local transport parameter "should remain
valid until after the parameters have been sent" as mentionned by
SSL_set_quic_tls_cbs(3) manual. In our case, the buffer is a static buffer
attached to the quic_conn object. qc_ssl_set_quic_transport_params() function
whose role is to call SSL_set_tls_quic_transport_params() (aliased by
SSL_set_quic_transport_params() to set these local tranport parameter into
the TLS stack from the buffer attached to the quic_conn struct.

The second quic_conn struct modification is the addition of the  new ->prot_level
(SSL protection level) member added to the quic_conn struct to store "the most
recent write encryption level set via the OSSL_FUNC_SSL_QUIC_TLS_yield_secret_fn
callback (if it has been called)" as mentionned by SSL_set_quic_tls_cbs(3) manual.

This patches finally implements the five remaining callacks to make the haproxy
QUIC implementation work.

OSSL_FUNC_SSL_QUIC_TLS_crypto_send_fn() (ha_quic_ossl_crypto_send) is easy to
implement. It calls ha_quic_add_handshake_data() after having converted
qc->prot_level TLS protection level value to the correct ssl_encryption_level_t
(boringSSL API/quictls) value.

OSSL_FUNC_SSL_QUIC_TLS_crypto_recv_rcd_fn() (ha_quic_ossl_crypto_recv_rcd())
provide the non-contiguous addresses to the TLS stack, without releasing
them.

OSSL_FUNC_SSL_QUIC_TLS_crypto_release_rcd_fn() (ha_quic_ossl_crypto_release_rcd())
release these non-contiguous buffer relying on the fact that the list of
encryption level (qc->qel_list) is correctly ordered by SSL protection level
secret establishements order (by the TLS stack).

OSSL_FUNC_SSL_QUIC_TLS_yield_secret_fn() (ha_quic_ossl_got_transport_params())
is a simple wrapping function over ha_quic_set_encryption_secrets() which is used
by boringSSL/quictls API.

OSSL_FUNC_SSL_QUIC_TLS_got_transport_params_fn() (ha_quic_ossl_got_transport_params())
role is to store the peer received transport parameters. It simply calls
quic_transport_params_store() and set them into the TLS stack calling
qc_ssl_set_quic_transport_params().

Also add some comments for all the OpenSSL 3.5 QUIC API callbacks.

This patch have no impact on the other use of QUIC API provided by the others TLS
stacks.
2025-05-20 15:00:06 +02:00
Frederic Lecaille
dc6a3c329a MINOR: quic: Allow the use of the new OpenSSL 3.5.0 QUIC TLS API (to be completed)
This patch allows the use of the new OpenSSL 3.5.0 QUIC TLS API when it is
available and detected at compilation time. The detection relies on the presence of the
OSSL_FUNC_SSL_QUIC_TLS_CRYPTO_SEND macro from openssl-compat.h. Indeed this
macro is defined by OpenSSL since 3.5.0 version. It is not defined by quictls.
This helps in distinguishing these two TLS stacks. When the detection succeeds,
HAVE_OPENSSL_QUIC is also defined by openssl-compat.h. Then, this is this new macro
which is used to detect the availability of the new OpenSSL 3.5.0 QUIC TLS API.

Note that this detection is done only if USE_QUIC_OPENSSL_COMPAT is not asked.
So, USE_QUIC_OPENSSL_COMPAT and HAVE_OPENSSL_QUIC are exclusive.

At the same location, from openssl-compat.h, ssl_encryption_level_t enum is
defined. This enum was defined by quictls and expansively used by the haproxy
QUIC implementation. SSL_set_quic_transport_params() is replaced by
SSL_set_quic_tls_transport_params. SSL_set_quic_early_data_enabled() (quictls) is also replaced
by SSL_set_quic_tls_early_data_enabled() (OpenSSL). SSL_quic_read_level() (quictls)
is not defined by OpenSSL. It is only used by the traces to log the current
TLS stack decryption level (read). A macro makes it return -1 which is an
usused values.

The most of the differences between quictls and OpenSSL QUI APIs are in quic_ssl.c
where some callbacks must be defined for these two APIs. This is why this
patch modifies quic_ssl.c to define an array of OSSL_DISPATCH structs: <ha_quic_dispatch>.
Each element of this arry defines a callback. So, this patch implements these
six callabcks:

  - ha_quic_ossl_crypto_send()
  - ha_quic_ossl_crypto_recv_rcd()
  - ha_quic_ossl_crypto_release_rcd()
  - ha_quic_ossl_yield_secret()
  - ha_quic_ossl_got_transport_params() and
  - ha_quic_ossl_alert().

But at this time, these implementations which must return an int return 0 interpreted
as a failure by the OpenSSL QUIC API, except for ha_quic_ossl_alert() which
is implemented the same was as for quictls. The five remaining functions above
will be implemented by the next patches to come.

ha_quic_set_encryption_secrets() and ha_quic_add_handshake_data() have been moved
to be defined for both quictls and OpenSSL QUIC API.

These callbacks are attached to the SSL objects (sessions) calling qc_ssl_set_cbs()
new function. This latter callback the correct function to attached the correct
callbacks to the SSL objects (defined by <ha_quic_method> for quictls, and
<ha_quic_dispatch> for OpenSSL).

The calls to SSL_provide_quic_data() and SSL_process_quic_post_handshake()
have been also disabled. These functions are not defined by OpenSSL QUIC API.
At this time, the functions which call them are still defined when HAVE_OPENSSL_QUIC
is defined.
2025-05-20 15:00:06 +02:00
Frederic Lecaille
894595b711 MINOR: quic: Add useful error traces about qc_ssl_sess_init() failures
There were no traces to diagnose qc_ssl_sess_init() failures from QUIC traces.
This patch add calls to TRACE_DEVEL() into qc_ssl_sess_init() and its caller
(qc_alloc_ssl_sock_ctx()). This was useful at least to diagnose SSL context
initialization failures when porting QUIC to the new OpenSSL 3.5 QUIC API.

Should be easily backported as far as 2.6.
2025-05-20 15:00:06 +02:00
Frederic Lecaille
a2822b1776 CLEANUP: quic: Useless BIO_METHOD initialization
This code is there from QUIC implementation start. It was supposed to
initialize <ha_quic_meth> as a BIO_METHOD static object. But this
BIO_METHOD is not used at all!

Should be backported as far as 2.6 to help integrate the next patches to come.
2025-05-20 15:00:06 +02:00
167 changed files with 4303 additions and 2622 deletions

View File

@ -5,97 +5,8 @@ on:
- cron: "0 0 * * 4"
workflow_dispatch:
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v4
- name: Install VTest
run: |
scripts/build-vtest.sh
- name: Determine latest AWS-LC release
id: get_aws_lc_release
run: |
result=$(cd .github && python3 -c "from matrix import determine_latest_aws_lc_fips; print(determine_latest_aws_lc_fips(''))")
echo $result
echo "result=$result" >> $GITHUB_OUTPUT
- name: Cache AWS-LC
id: cache_aws_lc
uses: actions/cache@v4
with:
path: '~/opt/'
key: ssl-${{ steps.get_aws_lc_release.outputs.result }}-Ubuntu-latest-gcc
- name: Install apt dependencies
run: |
sudo apt-get update -o Acquire::Languages=none -o Acquire::Translation=none
sudo apt-get --no-install-recommends -y install socat gdb jose
- name: Install AWS-LC
if: ${{ steps.cache_ssl.outputs.cache-hit != 'true' }}
run: env ${{ steps.get_aws_lc_release.outputs.result }} scripts/build-ssl.sh
- name: Compile HAProxy
run: |
make -j$(nproc) ERR=1 CC=gcc TARGET=linux-glibc \
USE_OPENSSL_AWSLC=1 USE_QUIC=1 \
SSL_LIB=${HOME}/opt/lib SSL_INC=${HOME}/opt/include \
DEBUG="-DDEBUG_POOL_INTEGRITY -DDEBUG_UNIT" \
ADDLIB="-Wl,-rpath,/usr/local/lib/ -Wl,-rpath,$HOME/opt/lib/"
sudo make install
- name: Show HAProxy version
id: show-version
run: |
ldd $(which haproxy)
haproxy -vv
echo "version=$(haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT
- name: Install problem matcher for VTest
run: echo "::add-matcher::.github/vtest.json"
- name: Run VTest for HAProxy
id: vtest
run: |
# This is required for macOS which does not actually allow to increase
# the '-n' soft limit to the hard limit, thus failing to run.
ulimit -n 65536
# allow to catch coredumps
ulimit -c unlimited
make reg-tests VTEST_PROGRAM=../vtest/vtest REGTESTS_TYPES=default,bug,devel
- name: Run Unit tests
id: unittests
run: |
make unit-tests
- name: Show VTest results
if: ${{ failure() && steps.vtest.outcome == 'failure' }}
run: |
for folder in ${TMPDIR:-/tmp}/haregtests-*/vtc.*; do
printf "::group::"
cat $folder/INFO
cat $folder/LOG
echo "::endgroup::"
done
exit 1
- name: Show coredumps
if: ${{ failure() && steps.vtest.outcome == 'failure' }}
run: |
failed=false
shopt -s nullglob
for file in /tmp/core.*; do
failed=true
printf "::group::"
gdb -ex 'thread apply all bt full' ./haproxy $file
echo "::endgroup::"
done
if [ "$failed" = true ]; then
exit 1;
fi
- name: Show Unit-Tests results
if: ${{ failure() && steps.unittests.outcome == 'failure' }}
run: |
for result in ${TMPDIR:-/tmp}/ha-unittests-*/results/res.*; do
printf "::group::"
cat $result
echo "::endgroup::"
done
exit 1
uses: ./.github/workflows/aws-lc-template.yml
with:
command: "from matrix import determine_latest_aws_lc_fips; print(determine_latest_aws_lc_fips(''))"

103
.github/workflows/aws-lc-template.yml vendored Normal file
View File

@ -0,0 +1,103 @@
name: AWS-LC template
on:
workflow_call:
inputs:
command:
required: true
type: string
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v4
- name: Install VTest
run: |
scripts/build-vtest.sh
- name: Determine latest AWS-LC release
id: get_aws_lc_release
run: |
result=$(cd .github && python3 -c "${{ inputs.command }}")
echo $result
echo "result=$result" >> $GITHUB_OUTPUT
- name: Cache AWS-LC
id: cache_aws_lc
uses: actions/cache@v4
with:
path: '~/opt/'
key: ssl-${{ steps.get_aws_lc_release.outputs.result }}-Ubuntu-latest-gcc
- name: Install apt dependencies
run: |
sudo apt-get update -o Acquire::Languages=none -o Acquire::Translation=none
sudo apt-get --no-install-recommends -y install socat gdb jose
- name: Install AWS-LC
if: ${{ steps.cache_ssl.outputs.cache-hit != 'true' }}
run: env ${{ steps.get_aws_lc_release.outputs.result }} scripts/build-ssl.sh
- name: Compile HAProxy
run: |
make -j$(nproc) ERR=1 CC=gcc TARGET=linux-glibc \
USE_OPENSSL_AWSLC=1 USE_QUIC=1 \
SSL_LIB=${HOME}/opt/lib SSL_INC=${HOME}/opt/include \
DEBUG="-DDEBUG_POOL_INTEGRITY -DDEBUG_UNIT" \
ADDLIB="-Wl,-rpath,/usr/local/lib/ -Wl,-rpath,$HOME/opt/lib/"
sudo make install
- name: Show HAProxy version
id: show-version
run: |
ldd $(which haproxy)
haproxy -vv
echo "version=$(haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT
- name: Install problem matcher for VTest
run: echo "::add-matcher::.github/vtest.json"
- name: Run VTest for HAProxy
id: vtest
run: |
# This is required for macOS which does not actually allow to increase
# the '-n' soft limit to the hard limit, thus failing to run.
ulimit -n 65536
# allow to catch coredumps
ulimit -c unlimited
make reg-tests VTEST_PROGRAM=../vtest/vtest REGTESTS_TYPES=default,bug,devel
- name: Run Unit tests
id: unittests
run: |
make unit-tests
- name: Show VTest results
if: ${{ failure() && steps.vtest.outcome == 'failure' }}
run: |
for folder in ${TMPDIR:-/tmp}/haregtests-*/vtc.*; do
printf "::group::"
cat $folder/INFO
cat $folder/LOG
echo "::endgroup::"
done
exit 1
- name: Show coredumps
if: ${{ failure() && steps.vtest.outcome == 'failure' }}
run: |
failed=false
shopt -s nullglob
for file in /tmp/core.*; do
failed=true
printf "::group::"
gdb -ex 'thread apply all bt full' ./haproxy $file
echo "::endgroup::"
done
if [ "$failed" = true ]; then
exit 1;
fi
- name: Show Unit-Tests results
if: ${{ failure() && steps.unittests.outcome == 'failure' }}
run: |
for result in ${TMPDIR:-/tmp}/ha-unittests-*/results/res.*; do
printf "::group::"
cat $result
echo "::endgroup::"
done
exit 1

View File

@ -5,97 +5,8 @@ on:
- cron: "0 0 * * 4"
workflow_dispatch:
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'haproxy' || github.event_name == 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v4
- name: Install VTest
run: |
scripts/build-vtest.sh
- name: Determine latest AWS-LC release
id: get_aws_lc_release
run: |
result=$(cd .github && python3 -c "from matrix import determine_latest_aws_lc; print(determine_latest_aws_lc(''))")
echo $result
echo "result=$result" >> $GITHUB_OUTPUT
- name: Cache AWS-LC
id: cache_aws_lc
uses: actions/cache@v4
with:
path: '~/opt/'
key: ssl-${{ steps.get_aws_lc_release.outputs.result }}-Ubuntu-latest-gcc
- name: Install apt dependencies
run: |
sudo apt-get update -o Acquire::Languages=none -o Acquire::Translation=none
sudo apt-get --no-install-recommends -y install socat gdb jose
- name: Install AWS-LC
if: ${{ steps.cache_ssl.outputs.cache-hit != 'true' }}
run: env ${{ steps.get_aws_lc_release.outputs.result }} scripts/build-ssl.sh
- name: Compile HAProxy
run: |
make -j$(nproc) ERR=1 CC=gcc TARGET=linux-glibc \
USE_OPENSSL_AWSLC=1 USE_QUIC=1 \
SSL_LIB=${HOME}/opt/lib SSL_INC=${HOME}/opt/include \
DEBUG="-DDEBUG_POOL_INTEGRITY -DDEBUG_UNIT" \
ADDLIB="-Wl,-rpath,/usr/local/lib/ -Wl,-rpath,$HOME/opt/lib/"
sudo make install
- name: Show HAProxy version
id: show-version
run: |
ldd $(which haproxy)
haproxy -vv
echo "version=$(haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT
- name: Install problem matcher for VTest
run: echo "::add-matcher::.github/vtest.json"
- name: Run VTest for HAProxy
id: vtest
run: |
# This is required for macOS which does not actually allow to increase
# the '-n' soft limit to the hard limit, thus failing to run.
ulimit -n 65536
# allow to catch coredumps
ulimit -c unlimited
make reg-tests VTEST_PROGRAM=../vtest/vtest REGTESTS_TYPES=default,bug,devel
- name: Run Unit tests
id: unittests
run: |
make unit-tests
- name: Show VTest results
if: ${{ failure() && steps.vtest.outcome == 'failure' }}
run: |
for folder in ${TMPDIR:-/tmp}/haregtests-*/vtc.*; do
printf "::group::"
cat $folder/INFO
cat $folder/LOG
echo "::endgroup::"
done
exit 1
- name: Show coredumps
if: ${{ failure() && steps.vtest.outcome == 'failure' }}
run: |
failed=false
shopt -s nullglob
for file in /tmp/core.*; do
failed=true
printf "::group::"
gdb -ex 'thread apply all bt full' ./haproxy $file
echo "::endgroup::"
done
if [ "$failed" = true ]; then
exit 1;
fi
- name: Show Unit-Tests results
if: ${{ failure() && steps.unittests.outcome == 'failure' }}
run: |
for result in ${TMPDIR:-/tmp}/ha-unittests-*/results/res.*; do
printf "::group::"
cat $result
echo "::endgroup::"
done
exit 1
uses: ./.github/workflows/aws-lc-template.yml
with:
command: "from matrix import determine_latest_aws_lc; print(determine_latest_aws_lc(''))"

130
CHANGELOG
View File

@ -1,6 +1,136 @@
ChangeLog :
===========
2025/06/11 : 3.3-dev1
- BUILD: tools: properly define ha_dump_backtrace() to avoid a build warning
- DOC: config: Fix a typo in 2.7 (Name format for maps and ACLs)
- REGTESTS: Do not use REQUIRE_VERSION for HAProxy 2.5+ (5)
- REGTESTS: Remove REQUIRE_VERSION=2.3 from all tests
- REGTESTS: Remove REQUIRE_VERSION=2.4 from all tests
- REGTESTS: Remove tests with REQUIRE_VERSION_BELOW=2.4
- REGTESTS: Remove support for REQUIRE_VERSION and REQUIRE_VERSION_BELOW
- MINOR: server: group postinit server tasks under _srv_postparse()
- MINOR: stats: add stat_col flags
- MINOR: stats: add ME_NEW_COMMON() helper
- MINOR: proxy: collect per-capability stat in proxy_cond_disable()
- MINOR: proxy: add a true list containing all proxies
- MINOR: log: only run postcheck_log_backend() checks on backend
- MEDIUM: proxy: use global proxy list for REGISTER_POST_PROXY_CHECK() hook
- MEDIUM: server: automatically add server to proxy list in new_server()
- MEDIUM: server: add and use srv_init() function
- BUG/MAJOR: leastconn: Protect tree_elt with the lbprm lock
- BUG/MEDIUM: check: Requeue healthchecks on I/O events to handle check timeout
- CLEANUP: applet: Update comment for applet_put* functions
- DEBUG: check: Add the healthcheck's expiration date in the trace messags
- BUG/MINOR: mux-spop: Fix null-pointer deref on SPOP stream allocation failure
- CLEANUP: sink: remove useless cleanup in sink_new_from_logger()
- MAJOR: counters: add shared counters base infrastructure
- MINOR: counters: add shared counters helpers to get and drop shared pointers
- MINOR: counters: add common struct and flags to {fe,be}_counters_shared
- MEDIUM: counters: manage shared counters using dedicated helpers
- CLEANUP: counters: merge some common counters between {fe,be}_counters_shared
- MINOR: counters: add local-only internal rates to compute some maxes
- MAJOR: counters: dispatch counters over thread groups
- BUG/MEDIUM: cli: Properly parse empty lines and avoid crashed
- BUG/MINOR: config: emit warning for empty args only in discovery mode
- BUG/MINOR: config: fix arg number reported on empty arg warning
- BUG/MINOR: quic: Missing SSL session object freeing
- MINOR: applet: Add API functions to manipulate input and output buffers
- MINOR: applet: Add API functions to get data from the input buffer
- CLEANUP: applet: Simplify a bit comments for applet_put* functions
- MEDIUM: hlua: Update TCP applet functions to use the new applet API
- BUG/MEDIUM: fd: Use the provided tgid in fd_insert() to get tgroup_info
- BUG/MINIR: h1: Fix doc of 'accept-unsafe-...-request' about URI parsing
2025/05/28 : 3.3-dev0
- MINOR: version: mention that it's development again
2025/05/28 : 3.2.0
- MINOR: promex: Add agent check status/code/duration metrics
- MINOR: ssl: support strict-sni in ssl-default-bind-options
- MINOR: ssl: also provide the "tls-tickets" bind option
- MINOR: server: define CLI I/O handler for "add server"
- MINOR: server: implement "add server help"
- MINOR: server: use stress mode for "add server help"
- BUG/MEDIUM: server: fix crash after duplicate GUID insertion
- BUG/MEDIUM: server: fix potential null-deref after previous fix
- MINOR: config: list recently added sections with -dKcfg
- BUG/MAJOR: cache: Crash because of wrong cache entry deleted
- DOC: configuration: fix the example in crt-store
- DOC: config: clarify the wording around single/double quotes
- DOC: config: clarify the legacy cookie and header captures
- DOC: config: fix alphabetical ordering of layer 7 sample fetch functions
- DOC: config: fix alphabetical ordering of layer 6 sample fetch functions
- DOC: config: fix alphabetical ordering of layer 5 sample fetch functions
- DOC: config: fix alphabetical ordering of layer 4 sample fetch functions
- DOC: config: fix alphabetical ordering of internal sample fetch functions
- BUG/MINOR: h3: Set HTX flags corresponding to the scheme found in the request
- BUG/MEDIUM: h3: Declare absolute URI as normalized when a :authority is found
- DOC: config: mention in bytes_in and bytes_out that they're read on input
- DOC: config: clarify the basics of ACLs (call point, multi-valued etc)
- REGTESTS: Make the script testing conditional set-var compatible with Vtest2
- REGTESTS: Explicitly allow failing shell commands in some scripts
- MINOR: listeners: Add support for a label on bind line
- BUG/MEDIUM: cli/ring: Properly handle shutdown in "show event" I/O handler
- BUG/MEDIUM: hlua: Properly detect shudowns for TCP applets based on the new API
- BUG/MEDIUM: hlua: Fix getline() for TCP applets to work with applet's buffers
- BUG/MEDIUM: hlua: Fix receive API for TCP applets to properly handle shutdowns
- CI: vtest: Rely on VTest2 to run regression tests
- CI: vtest: Fix the build script to properly work on MaOS
- CI: combine AWS-LC and AWS-LC-FIPS by template
- BUG/MEDIUM: httpclient: Throw an error if an lua httpclient instance is reused
- DOC: hlua: Add a note to warn user about httpclient object reuse
- DOC: hlua: fix a few typos in HTTPMessage.set_body_len() documentation
- DEV: patchbot: prepare for new version 3.3-dev
- MINOR: version: mention that it's 3.2 LTS now.
2025/05/21 : 3.2-dev17
- DOC: configuration: explicit multi-choice on bind shards option
- BUG/MINOR: sink: detect and warn when using "send-proxy" options with ring servers
- BUG/MEDIUM: peers: also limit the number of incoming updates
- MEDIUM: hlua: Add function to change the body length of an HTTP Message
- BUG/MEDIUM: stconn: Disable 0-copy forwarding for filters altering the payload
- BUG/MINOR: h3: don't insert more than one Host header
- BUG/MEDIUM: h1/h2/h3: reject forbidden chars in the Host header field
- DOC: config: properly index "table and "stick-table" in their section
- DOC: management: change reference to configuration manual
- BUILD: debug: mark ha_crash_now() as attribute(noreturn)
- IMPORT: slz: avoid multiple shifts on 64-bits
- IMPORT: slz: support crc32c for lookup hash on sse4 but only if requested
- IMPORT: slz: use a better hash for machines with a fast multiply
- IMPORT: slz: fix header used for empty zlib message
- IMPORT: slz: silence a build warning on non-x86 non-arm
- BUG/MAJOR: leastconn: do not loop forever when facing saturated servers
- BUG/MAJOR: queue: properly keep count of the queue length
- BUG/MINOR: quic: fix crash on quic_conn alloc failure
- BUG/MAJOR: leastconn: never reuse the node after dropping the lock
- MINOR: acme: renewal notification over the dpapi sink
- CLEANUP: quic: Useless BIO_METHOD initialization
- MINOR: quic: Add useful error traces about qc_ssl_sess_init() failures
- MINOR: quic: Allow the use of the new OpenSSL 3.5.0 QUIC TLS API (to be completed)
- MINOR: quic: implement all remaining callbacks for OpenSSL 3.5 QUIC API
- MINOR: quic: OpenSSL 3.5 internal QUIC custom extension for transport parameters reset
- MINOR: quic: OpenSSL 3.5 trick to support 0-RTT
- DOC: update INSTALL for QUIC with OpenSSL 3.5 usages
- DOC: management: update 'acme status'
- BUG/MEDIUM: wdt: always ignore the first watchdog wakeup
- CLEANUP: wdt: clarify the comments on the common exit path
- BUILD: ssl: avoid possible printf format warning in traces
- BUILD: acme: fix build issue on 32-bit archs with 64-bit time_t
- DOC: management: precise some of the fields of "show servers conn"
- BUG/MEDIUM: mux-quic: fix BUG_ON() on rxbuf alloc error
- DOC: watchdog: update the doc to reflect the recent changes
- BUG/MEDIUM: acme: check if acme domains are configured
- BUG/MINOR: acme: fix formatting issue in error and logs
- EXAMPLES: lua: avoid screen refresh effect in "trisdemo"
- CLEANUP: quic: remove unused cbuf module
- MINOR: quic: move function to check stream type in utils
- MINOR: quic: refactor handling of streams after MUX release
- MINOR: quic: add some missing includes
- MINOR: quic: adjust quic_conn-t.h include list
- CLEANUP: cfgparse: alphabetically sort the global keywords
- MINOR: glitches: add global setting "tune.glitches.kill.cpu-usage"
2025/05/14 : 3.2-dev16
- BUG/MEDIUM: mux-quic: fix crash on invalid fctl frame dereference
- DEBUG: pool: permit per-pool UAF configuration

33
INSTALL
View File

@ -237,7 +237,7 @@ to forcefully enable it using "USE_LIBCRYPT=1".
-----------------
For SSL/TLS, it is necessary to use a cryptography library. HAProxy currently
supports the OpenSSL library, and is known to build and work with branches
1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, and 3.0 to 3.4. It is recommended to use
1.0.0, 1.0.1, 1.0.2, 1.1.0, 1.1.1, and 3.0 to 3.5. It is recommended to use
at least OpenSSL 1.1.1 to have support for all SSL keywords and configuration
in HAProxy. OpenSSL follows a long-term support cycle similar to HAProxy's,
and each of the branches above receives its own fixes, without forcing you to
@ -259,10 +259,10 @@ reported to work as well. While there are some efforts from the community to
ensure they work well, OpenSSL remains the primary target and this means that
in case of conflicting choices, OpenSSL support will be favored over other
options. Note that QUIC is not fully supported when haproxy is built with
OpenSSL. In this case, QUICTLS is the preferred alternative. As of writing
this, the QuicTLS project follows OpenSSL very closely and provides update
simultaneously, but being a volunteer-driven project, its long-term future does
not look certain enough to convince operating systems to package it, so it
OpenSSL < 3.5 version. In this case, QUICTLS is the preferred alternative.
As of writing this, the QuicTLS project follows OpenSSL very closely and provides
update simultaneously, but being a volunteer-driven project, its long-term future
does not look certain enough to convince operating systems to package it, so it
needs to be build locally. See the section about QUIC in this document.
A fifth option is wolfSSL (https://github.com/wolfSSL/wolfssl). It is the only
@ -500,10 +500,11 @@ QUIC is the new transport layer protocol and is required for HTTP/3. This
protocol stack is currently supported as an experimental feature in haproxy on
the frontend side. In order to enable it, use "USE_QUIC=1 USE_OPENSSL=1".
Note that QUIC is not fully supported by the OpenSSL library. Indeed QUIC 0-RTT
cannot be supported by OpenSSL contrary to others libraries with full QUIC
support. The preferred option is to use QUICTLS. This is a fork of OpenSSL with
a QUIC-compatible API. Its repository is available at this location:
Note that QUIC is not always fully supported by the OpenSSL library depending on
its version. Indeed QUIC 0-RTT cannot be supported by OpenSSL for versions before
3.5 contrary to others libraries with full QUIC support. The preferred option is
to use QUICTLS. This is a fork of OpenSSL with a QUIC-compatible API. Its
repository is available at this location:
https://github.com/quictls/openssl
@ -531,14 +532,18 @@ way assuming that wolfSSL was installed in /opt/wolfssl-5.6.0 as shown in 4.5:
SSL_INC=/opt/wolfssl-5.6.0/include SSL_LIB=/opt/wolfssl-5.6.0/lib
LDFLAGS="-Wl,-rpath,/opt/wolfssl-5.6.0/lib"
As last resort, haproxy may be compiled against OpenSSL as follows:
As last resort, haproxy may be compiled against OpenSSL as follows from 3.5
version with 0-RTT support:
$ make TARGET=generic USE_OPENSSL=1 USE_QUIC=1
or as follows for all OpenSSL versions but without O-RTT support:
$ make TARGET=generic USE_OPENSSL=1 USE_QUIC=1 USE_QUIC_OPENSSL_COMPAT=1
Note that QUIC 0-RTT is not supported by haproxy QUIC stack when built against
OpenSSL. In addition to this compilation requirements, the QUIC listener
bindings must be explicitly enabled with a specific QUIC tuning parameter.
(see "limited-quic" global parameter of haproxy Configuration Manual).
In addition to this requirements, the QUIC listener bindings must be explicitly
enabled with a specific QUIC tuning parameter. (see "limited-quic" global
parameter of haproxy Configuration Manual).
5) How to build HAProxy

View File

@ -660,7 +660,7 @@ OPTIONS_OBJS += src/mux_quic.o src/h3.o src/quic_rx.o src/quic_tx.o \
src/quic_cc_nocc.o src/quic_cc.o src/quic_pacing.o \
src/h3_stats.o src/quic_stats.o src/qpack-enc.o \
src/qpack-tbl.o src/quic_cc_drs.o src/quic_fctl.o \
src/cbuf.o src/quic_enc.o
src/quic_enc.o
endif
ifneq ($(USE_QUIC_OPENSSL_COMPAT:0=),)
@ -984,7 +984,7 @@ OBJS += src/mux_h2.o src/mux_h1.o src/mux_fcgi.o src/log.o \
src/lb_fas.o src/clock.o src/sock_inet.o src/ev_select.o \
src/lb_map.o src/shctx.o src/mworker-prog.o src/hpack-dec.o \
src/arg.o src/signal.o src/fix.o src/dynbuf.o src/guid.o \
src/cfgparse-tcp.o src/lb_ss.o src/chunk.o \
src/cfgparse-tcp.o src/lb_ss.o src/chunk.o src/counters.o \
src/cfgparse-unix.o src/regex.o src/fcgi.o src/uri_auth.o \
src/eb64tree.o src/eb32tree.o src/eb32sctree.o src/lru.o \
src/limits.o src/ebimtree.o src/wdt.o src/hpack-tbl.o \

View File

@ -1,2 +1,2 @@
$Format:%ci$
2025/05/14
2025/06/11

View File

@ -1 +1 @@
3.2-dev16
3.3-dev1

View File

@ -389,6 +389,9 @@ listed below. Metrics from extra counters are not listed.
| haproxy_server_max_connect_time_seconds |
| haproxy_server_max_response_time_seconds |
| haproxy_server_max_total_time_seconds |
| haproxy_server_agent_status |
| haproxy_server_agent_code |
| haproxy_server_agent_duration_seconds |
| haproxy_server_internal_errors_total |
| haproxy_server_unsafe_idle_connections_current |
| haproxy_server_safe_idle_connections_current |

View File

@ -173,6 +173,8 @@ const struct ist promex_st_metric_desc[ST_I_PX_MAX] = {
[ST_I_PX_CTIME] = IST("Avg. connect time for last 1024 successful connections."),
[ST_I_PX_RTIME] = IST("Avg. response time for last 1024 successful connections."),
[ST_I_PX_TTIME] = IST("Avg. total time for last 1024 successful connections."),
[ST_I_PX_AGENT_STATUS] = IST("Status of last agent check, per state label value."),
[ST_I_PX_AGENT_DURATION] = IST("Total duration of the latest server agent check, in seconds."),
[ST_I_PX_QT_MAX] = IST("Maximum observed time spent in the queue"),
[ST_I_PX_CT_MAX] = IST("Maximum observed time spent waiting for a connection to complete"),
[ST_I_PX_RT_MAX] = IST("Maximum observed time spent waiting for a server response"),
@ -1342,6 +1344,7 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
secs = (double)sv->check.duration / 1000.0;
val = mkf_flt(FN_DURATION, secs);
break;
case ST_I_PX_REQ_TOT:
if (px->mode != PR_MODE_HTTP) {
sv = NULL;
@ -1364,6 +1367,36 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx)
labels[lb_idx+1].value = promex_hrsp_code[ctx->field_num - ST_I_PX_HRSP_1XX];
break;
case ST_I_PX_AGENT_STATUS:
if ((sv->agent.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) != CHK_ST_ENABLED)
goto next_sv;
for (; ctx->obj_state < HCHK_STATUS_SIZE; ctx->obj_state++) {
if (get_check_status_result(ctx->obj_state) < CHK_RES_FAILED)
continue;
val = mkf_u32(FO_STATUS, sv->agent.status == ctx->obj_state);
check_state = get_check_status_info(ctx->obj_state);
labels[lb_idx+1].name = ist("state");
labels[lb_idx+1].value = ist(check_state);
if (!promex_dump_ts(appctx, prefix, name, desc,
type,
&val, labels, &out, max))
goto full;
}
ctx->obj_state = 0;
goto next_sv;
case ST_I_PX_AGENT_CODE:
if ((sv->agent.state & (CHK_ST_ENABLED|CHK_ST_PAUSED)) != CHK_ST_ENABLED)
goto next_sv;
val = mkf_u32(FN_OUTPUT, (sv->agent.status < HCHK_STATUS_L57DATA) ? 0 : sv->agent.code);
break;
case ST_I_PX_AGENT_DURATION:
if (sv->agent.status < HCHK_STATUS_CHECKED)
goto next_sv;
secs = (double)sv->agent.duration / 1000.0;
val = mkf_flt(FN_DURATION, secs);
break;
default:
break;
}

View File

@ -0,0 +1,70 @@
BEGININPUT
BEGINCONTEXT
HAProxy's development cycle consists in one development branch, and multiple
maintenance branches.
All the development is made into the development branch exclusively. This
includes mostly new features, doc updates, cleanups and or course, fixes.
The maintenance branches, also called stable branches, never see any
development, and only receive ultra-safe fixes for bugs that affect them,
that are picked from the development branch.
Branches are numbered in 0.1 increments. Every 6 months, upon a new major
release, the development branch enters maintenance and a new development branch
is created with a new, higher version. The current development branch is
3.3-dev, and maintenance branches are 3.2 and below.
Fixes created in the development branch for issues that were introduced in an
earlier branch are applied in descending order to each and every version till
that branch that introduced the issue: 3.2 first, then 3.1, then 3.0, then 2.9
and so on. This operation is called "backporting". A fix for an issue is never
backported beyond the branch that introduced the issue. An important point is
that the project maintainers really aim at zero regression in maintenance
branches, so they're never willing to take any risk backporting patches that
are not deemed strictly necessary.
Fixes consist of patches managed using the Git version control tool and are
identified by a Git commit ID and a commit message. For this reason we
indistinctly talk about backporting fixes, commits, or patches; all mean the
same thing. When mentioning commit IDs, developers always use a short form
made of the first 8 characters only, and expect the AI assistant to do the
same.
It seldom happens that some fixes depend on changes that were brought by other
patches that were not in some branches and that will need to be backported as
well for the fix to work. In this case, such information is explicitly provided
in the commit message by the patch's author in natural language.
Developers are serious and always indicate if a patch needs to be backported.
Sometimes they omit the exact target branch, or they will say that the patch is
"needed" in some older branch, but it means the same. If a commit message
doesn't mention any backport instructions, it means that the commit does not
have to be backported. And patches that are not strictly bug fixes nor doc
improvements are normally not backported. For example, fixes for design
limitations, architectural improvements and performance optimizations are
considered too risky for a backport. Finally, all bug fixes are tagged as
"BUG" at the beginning of their subject line. Patches that are not tagged as
such are not bugs, and must never be backported unless their commit message
explicitly requests so.
ENDCONTEXT
A developer is reviewing the development branch, trying to spot which commits
need to be backported to maintenance branches. This person is already expert
on HAProxy and everything related to Git, patch management, and the risks
associated with backports, so he doesn't want to be told how to proceed nor to
review the contents of the patch.
The goal for this developer is to get some help from the AI assistant to save
some precious time on this tedious review work. In order to do a better job, he
needs an accurate summary of the information and instructions found in each
commit message. Specifically he needs to figure if the patch fixes a problem
affecting an older branch or not, if it needs to be backported, if so to which
branches, and if other patches need to be backported along with it.
The indented text block below after an "id" line and starting with a Subject line
is a commit message from the HAProxy development branch that describes a patch
applied to that branch, starting with its subject line, please read it carefully.

View File

@ -0,0 +1,29 @@
ENDINPUT
BEGININSTRUCTION
You are an AI assistant that follows instruction extremely well. Help as much
as you can, responding to a single question using a single response.
The developer wants to know if he needs to backport the patch above to fix
maintenance branches, for which branches, and what possible dependencies might
be mentioned in the commit message. Carefully study the commit message and its
backporting instructions if any (otherwise it should probably not be backported),
then provide a very concise and short summary that will help the developer decide
to backport it, or simply to skip it.
Start by explaining in one or two sentences what you recommend for this one and why.
Finally, based on your analysis, give your general conclusion as "Conclusion: X"
where X is a single word among:
- "yes", if you recommend to backport the patch right now either because
it explicitly states this or because it's a fix for a bug that affects
a maintenance branch (3.2 or lower);
- "wait", if this patch explicitly mentions that it must be backported, but
only after waiting some time.
- "no", if nothing clearly indicates a necessity to backport this patch (e.g.
lack of explicit backport instructions, or it's just an improvement);
- "uncertain" otherwise for cases not covered above
ENDINSTRUCTION
Explanation:

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@ falls back to CLOCK_REALTIME. The former is more accurate as it really counts
the time spent in the process, while the latter might also account for time
stuck on paging in etc.
Then wdt_ping() is called to arm the timer. t's set to trigger every
Then wdt_ping() is called to arm the timer. It's set to trigger every
<wdt_warn_blocked_traffic_ns> interval. It is also called by wdt_handler()
to reprogram a new wakeup after it has ticked.
@ -37,15 +37,18 @@ If the thread was not marked as stuck, it's verified that no progress was made
for at least one second, in which case the TH_FL_STUCK flag is set. The lack of
progress is measured by the distance between the thread's current cpu_time and
its prev_cpu_time. If the lack of progress is at least as large as the warning
threshold and no context switch happened since last call, ha_stuck_warning() is
called to emit a warning about that thread. In any case the context switch
counter for that thread is updated.
threshold, then the signal is bounced to the faulty thread if it's not the
current one. Since this bounce is based on the time spent without update, it
already doesn't happen often.
If the thread was already marked as stuck, then the thread is considered as
definitely stuck. Then ha_panic() is directly called if the thread is the
current one, otherwise ha_kill() is used to resend the signal directly to the
target thread, which will in turn go through this handler and handle the panic
itself.
Once on the faulty thread, two checks are performed:
1) if the thread was already marked as stuck, then the thread is considered
as definitely stuck, and ha_panic() is called. It will not return.
2) a check is made to verify if the scheduler is still ticking, by reading
and setting a variable that only the scheduler can clear when leaving a
task. If the scheduler didn't make any progress, ha_stuck_warning() is
called to emit a warning about that thread.
Most of the time there's no panic of course, and a wdt_ping() is performed
before leaving the handler to reprogram a check for that thread.
@ -61,12 +64,12 @@ set TAINTED_WARN_BLOCKED_TRAFFIC.
ha_panic() uses the current thread's trash buffer to produce the messages, as
we don't care about its contents since that thread will never return. However
ha_stuck_warning() instead uses a local 4kB buffer in the thread's stack.
ha_stuck_warning() instead uses a local 8kB buffer in the thread's stack.
ha_panic() will call ha_thread_dump_fill() for each thread, to complete the
buffer being filled with each thread's dump messages. ha_stuck_warning() only
calls the function for the current thread. In both cases the message is then
directly sent to fd #2 (stderr) and ha_thread_dump_one() is called to release
the dumped thread.
calls ha_thread_dump_one(), which works on the current thread. In both cases
the message is then directly sent to fd #2 (stderr) and ha_thread_dump_done()
is called to release the dumped thread.
Both print a few extra messages, but ha_panic() just ends by looping on abort()
until the process dies.
@ -110,13 +113,19 @@ ha_dump_backtrace() before returning.
ha_dump_backtrace() produces a backtrace into a local buffer (100 entries max),
then dumps the code bytes nearby the crashing instrution, dumps pointers and
tries to resolve function names, and sends all of that into the target buffer.
On some architectures (x86_64, arm64), it will also try to detect and decode
call instructions and resolve them to called functions.
3. Improvements
---------------
The symbols resolution is extremely expensive, particularly for the warnings
which should be fast. But we need it, it's just unfortunate that it strikes at
the wrong moment.
the wrong moment. At least ha_dump_backtrace() does disable signals while it's
resolving, in order to avoid unwanted re-entrance. In addition, the called
function resolve_sym_name() uses some locking and refrains from calling the
dladdr family of functions in a re-entrant way (in the worst case only well
known symbols will be resolved)..
In an ideal case, ha_dump_backtrace() would dump the pointers to a local array,
which would then later be resolved asynchronously in a tasklet. This can work

View File

@ -1,7 +1,7 @@
-----------------------
HAProxy Starter Guide
-----------------------
version 3.2
version 3.3
This document is an introduction to HAProxy for all those who don't know it, as

View File

@ -893,7 +893,9 @@ Core class
**context**: init, task, action
This function returns a new object of a *httpclient* class.
This function returns a new object of a *httpclient* class. An *httpclient*
object must be used to process one and only one request. It must never be
reused to process several requests.
:returns: A :ref:`httpclient_class` object.
@ -2581,7 +2583,9 @@ HTTPClient class
.. js:class:: HTTPClient
The httpclient class allows issue of outbound HTTP requests through a simple
API without the knowledge of HAProxy internals.
API without the knowledge of HAProxy internals. Any instance must be used to
process one and only one request. It must never be reused to process several
requests.
.. js:function:: HTTPClient.get(httpclient, request)
.. js:function:: HTTPClient.head(httpclient, request)
@ -3916,21 +3920,25 @@ AppletTCP class
*size* is missing, the function tries to read all the content of the stream
until the end. An optional timeout may be specified in milliseconds. In this
case the function will return no longer than this delay, with the amount of
available data (possibly none).
available data, or nil if there is no data. An empty string is returned if the
connection is closed.
:param class_AppletTCP applet: An :ref:`applettcp_class`
:param integer size: the required read size.
:returns: always return a string, the string can be empty if the connection is
closed.
:returns: return nil if the timeout has expired and no data was available but
can still be received. Otherwise, a string is returned, possibly an empty
string if the connection is closed.
.. js:function:: AppletTCP.try_receive(applet)
Reads available data from the TCP stream and returns immediately. Returns a
string containing read bytes that may possibly be empty if no bytes are
available at that time.
string containing read bytes or nil if no bytes are available at that time. An
empty string is returned if the connection is closed.
:param class_AppletTCP applet: An :ref:`applettcp_class`
:returns: always return a string, the string can be empty.
:returns: return nil if no data was available but can still be
received. Otherwise, a string is returned, possibly an empty string if the
connection is closed.
.. js:function:: AppletTCP.send(appletmsg)
@ -4617,10 +4625,10 @@ HTTPMessage class
added with the "chunked" value. In both cases, all existing "Content-Length"
and "Transfer-Encoding" headers are removed.
This fnuction should be used in the filter context to be able to alter the
payload of the HTTP message. The internal state fo the HTTP message is updated
This function should be used in the filter context to be able to alter the
payload of the HTTP message. The internal state of the HTTP message is updated
accordingly. :js:func:`HTTPMessage.add_header()` or
:js:func:`HTTPMessage.set_header()` functions must to be used in that case.
:js:func:`HTTPMessage.set_header()` functions must be used in that case.
:param class_httpmessage http_msg: The manipulated HTTP message.
:param type length: The new payload length to set. It can be an integer or

View File

@ -1,7 +1,7 @@
------------------------
HAProxy Management Guide
------------------------
version 3.2
version 3.3
This document describes how to start, stop, manage, and troubleshoot HAProxy,
@ -1662,10 +1662,10 @@ acme status
This command outputs, separated by a tab:
- The name of the certificate configured in haproxy
- The acme section used in the configuration
- The state of the acme task, either "Running" or "Scheduled"
- The state of the acme task, either "Running", "Scheduled" or "Stopped"
- The UTC expiration date of the certificate in ISO8601 format
- The relative expiration time (0d if expired)
- The UTC expiration date of the certificate in ISO8601 format
- The UTC scheduled date of the certificate in ISO8601 format
- The relative schedule time (0d if Running)
Example:
@ -1724,8 +1724,9 @@ add server <backend>/<server> [args]*
The <server> name must not be already used in the backend. A special
restriction is put on the backend which must used a dynamic load-balancing
algorithm. A subset of keywords from the server config file statement can be
used to configure the server behavior. Also note that no settings will be
reused from an hypothetical 'default-server' statement in the same backend.
used to configure the server behavior (see "add server help" to list them).
Also note that no settings will be reused from an hypothetical
'default-server' statement in the same backend.
Currently a dynamic server is statically initialized with the "none"
init-addr method. This means that no resolution will be undertaken if a FQDN
@ -1755,78 +1756,10 @@ add server <backend>/<server> [args]*
servers. Please refer to the "u-limit" global keyword documentation in this
case.
Here is the list of the currently supported keywords :
- agent-addr
- agent-check
- agent-inter
- agent-port
- agent-send
- allow-0rtt
- alpn
- addr
- backup
- ca-file
- check
- check-alpn
- check-proto
- check-send-proxy
- check-sni
- check-ssl
- check-via-socks4
- ciphers
- ciphersuites
- cookie
- crl-file
- crt
- disabled
- downinter
- error-limit
- fall
- fastinter
- force-sslv3/tlsv10/tlsv11/tlsv12/tlsv13
- id
- init-state
- inter
- maxconn
- maxqueue
- minconn
- no-ssl-reuse
- no-sslv3/tlsv10/tlsv11/tlsv12/tlsv13
- no-tls-tickets
- npn
- observe
- on-error
- on-marked-down
- on-marked-up
- pool-low-conn
- pool-max-conn
- pool-purge-delay
- port
- proto
- proxy-v2-options
- rise
- send-proxy
- send-proxy-v2
- send-proxy-v2-ssl
- send-proxy-v2-ssl-cn
- slowstart
- sni
- source
- ssl
- ssl-max-ver
- ssl-min-ver
- tfo
- tls-tickets
- track
- usesrc
- verify
- verifyhost
- weight
- ws
Their syntax is similar to the server line from the configuration file,
please refer to their individual documentation for details.
add server help
List the keywords supported for dynamic servers by the current haproxy
version. Keyword syntax is similar to the server line from the configuration
file, please refer to their individual documentation for details.
add ssl ca-file <cafile> <payload>
Add a new certificate to a ca-file. This command is useful when you reached
@ -3293,7 +3226,29 @@ show servers conn [<backend>]
The output consists in a header line showing the fields titles, then one
server per line with for each, the backend name and ID, server name and ID,
the address, port and a series or values. The number of fields varies
depending on thread count.
depending on thread count. The exact format of the output may vary slightly
across versions and depending on the number of threads. One needs to pay
attention to the header line to match columns when extracting output values,
and to the number of threads as the last columns are per-thread:
bkname/svname Backend name '/' server name
bkid/svid Backend ID '/' server ID
addr Server's IP address
port Server's port (or zero if none)
- Unused field, serves as a visual delimiter
purge_delay Interval between connection purges, in milliseconds
used_cur Number of connections currently in use
used_max Highest value of used_cur since the process started
need_est Floating estimate of total needed connections
unsafe_nb Number of idle connections considered as "unsafe"
safe_nb Number of idle connections considered as "safe"
idle_lim Configured maximum number of idle connections
idle_cur Total of the per-thread currently idle connections
idle_per_thr[NB] Idle conns per thread for each one of the NB threads
HAProxy will kill a portion of <idle_cur> every <purge_delay> when the total
of <idle_cur> + <used_cur> exceeds the estimate <need_est>. This estimate
varies based on connection activity.
Given the threaded nature of idle connections, it's important to understand
that some values may change once read, and that as such, consistency within a

View File

@ -112,7 +112,7 @@ local function rotate_piece(piece, piece_id, px, py, board)
end
function render(applet, board, piece, piece_id, px, py, score)
local output = clear_screen .. cursor_home
local output = cursor_home
output = output .. game_name .. " - Lines: " .. score .. "\r\n"
output = output .. "+" .. string.rep("-", board_width * 2) .. "+\r\n"
for y = 1, board_height do
@ -160,6 +160,7 @@ function handler(applet)
end
applet:send(cursor_hide)
applet:send(clear_screen)
-- fall the piece by one line every delay
local function fall_piece()
@ -214,7 +215,7 @@ function handler(applet)
local input = applet:receive(1, delay)
if input then
if input == "q" then
if input == "" or input == "q" then
game_over = true
elseif input == "\27" then
local a = applet:receive(1, delay)

View File

@ -282,6 +282,92 @@ static inline void applet_expect_data(struct appctx *appctx)
se_fl_clr(appctx->sedesc, SE_FL_EXP_NO_DATA);
}
/* Returns the buffer containing data pushed to the applet by the stream. For
* applets using its own buffers it is the appctx input buffer. For legacy
* applet, it is the output channel buffer.
*/
static inline struct buffer *applet_get_inbuf(struct appctx *appctx)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS)
return &appctx->inbuf;
else
return sc_ob(appctx_sc(appctx));
}
/* Returns the buffer containing data pushed by the applets to the stream. For
* applets using its own buffer it is the appctx output buffer. For legacy
* applet, it is the input channel buffer.
*/
static inline struct buffer *applet_get_outbuf(struct appctx *appctx)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS)
return &appctx->outbuf;
else
return sc_ib(appctx_sc(appctx));
}
/* Returns the amount of data in the input buffer (see applet_get_inbuf) */
static inline size_t applet_input_data(const struct appctx *appctx)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS)
return b_data(&appctx->inbuf);
else
return co_data(sc_oc(appctx_sc(appctx)));
}
/* Skips <len> bytes from the input buffer (see applet_get_inbuf).
*
* This is useful when data have been read directly from the buffer. It is
* illegal to call this function with <len> causing a wrapping at the end of the
* buffer. It's the caller's responsibility to ensure that <len> is never larger
* than available ouput data.
*/
static inline void applet_skip_input(struct appctx *appctx, size_t len)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS)
b_del(&appctx->inbuf, len);
else
co_skip(sc_oc(appctx_sc(appctx)), len);
}
/* Removes all bytes from the input buffer (see applet_get_inbuf).
*/
static inline void applet_reset_input(struct appctx *appctx)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS) {
b_reset(&appctx->inbuf);
applet_fl_clr(appctx, APPCTX_FL_INBLK_FULL);
}
else
co_skip(sc_oc(appctx_sc(appctx)), co_data(sc_oc(appctx_sc(appctx))));
}
/* Returns the amout of space available at the output buffer (see applet_get_outbuf).
*/
static inline size_t applet_output_room(const struct appctx *appctx)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS)
return b_room(&appctx->outbuf);
else
return channel_recv_max(sc_ic(appctx_sc(appctx)));
}
/*Indicates that the applet have more data to deliver and it needs more room in
* the output buffer to do so (see applet_get_outbuf).
*
* For applets using its own buffers, <room_needed> is not used and only
* <appctx> flags are updated. For legacy applets, the amount of free space
* required must be specified. In this last case, it is the caller
* responsibility to be sure <room_needed> is valid.
*/
static inline void applet_need_room(struct appctx *appctx, size_t room_needed)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS)
applet_have_more_data(appctx);
else
sc_need_room(appctx_sc(appctx), room_needed);
}
/* Should only be used via wrappers applet_putchk() / applet_putchk_stress(). */
static inline int _applet_putchk(struct appctx *appctx, struct buffer *chunk,
int stress)
@ -318,9 +404,10 @@ static inline int _applet_putchk(struct appctx *appctx, struct buffer *chunk,
return ret;
}
/* writes chunk <chunk> into the input channel of the stream attached to this
* appctx's endpoint, and marks the SC_FL_NEED_ROOM on a channel full error.
* See ci_putchk() for the list of return codes.
/* writes chunk <chunk> into the applet output buffer (see applet_get_outbuf).
*
* Returns the number of written bytes on success or -1 on error (lake of space,
* shutdown, invalid call...)
*/
static inline int applet_putchk(struct appctx *appctx, struct buffer *chunk)
{
@ -333,9 +420,10 @@ static inline int applet_putchk_stress(struct appctx *appctx, struct buffer *chu
return _applet_putchk(appctx, chunk, 1);
}
/* writes <len> chars from <blk> into the input channel of the stream attached
* to this appctx's endpoint, and marks the SC_FL_NEED_ROOM on a channel full
* error. See ci_putblk() for the list of return codes.
/* writes <len> chars from <blk> into the applet output buffer (see applet_get_outbuf).
*
* Returns the number of written bytes on success or -1 on error (lake of space,
* shutdown, invalid call...)
*/
static inline int applet_putblk(struct appctx *appctx, const char *blk, int len)
{
@ -367,10 +455,11 @@ static inline int applet_putblk(struct appctx *appctx, const char *blk, int len)
return ret;
}
/* writes chars from <str> up to the trailing zero (excluded) into the input
* channel of the stream attached to this appctx's endpoint, and marks the
* SC_FL_NEED_ROOM on a channel full error. See ci_putstr() for the list of
* return codes.
/* writes chars from <str> up to the trailing zero (excluded) into the applet
* output buffer (see applet_get_outbuf).
*
* Returns the number of written bytes on success or -1 on error (lake of space,
* shutdown, invalid call...)
*/
static inline int applet_putstr(struct appctx *appctx, const char *str)
{
@ -403,9 +492,10 @@ static inline int applet_putstr(struct appctx *appctx, const char *str)
return ret;
}
/* writes character <chr> into the input channel of the stream attached to this
* appctx's endpoint, and marks the SC_FL_NEED_ROOM on a channel full error.
* See ci_putchr() for the list of return codes.
/* writes character <chr> into the applet's output buffer (see applet_get_outbuf).
*
* Returns the number of written bytes on success or -1 on error (lake of space,
* shutdown, invalid call...)
*/
static inline int applet_putchr(struct appctx *appctx, char chr)
{
@ -438,6 +528,283 @@ static inline int applet_putchr(struct appctx *appctx, char chr)
return ret;
}
static inline int applet_may_get(const struct appctx *appctx, size_t len)
{
if (appctx->flags & APPCTX_FL_INOUT_BUFS) {
if (len > b_data(&appctx->inbuf)) {
if (se_fl_test(appctx->sedesc, SE_FL_SHW))
return -1;
return 0;
}
}
else {
const struct stconn *sc = appctx_sc(appctx);
if ((sc->flags & SC_FL_SHUT_DONE) || len > co_data(sc_oc(sc))) {
if (sc->flags & (SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED))
return -1;
return 0;
}
}
return 1;
}
/* Gets one char from the applet input buffer (see appet_get_inbuf),
*
* Return values :
* 1 : number of bytes read, equal to requested size.
* =0 : not enough data available. <c> is left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getchar(const struct appctx *appctx, char *c)
{
int ret;
ret = applet_may_get(appctx, 1);
if (ret <= 0)
return ret;
*c = ((appctx->flags & APPCTX_FL_INOUT_BUFS)
? *(b_head(&appctx->inbuf))
: *(co_head(sc_oc(appctx_sc(appctx)))));
return 1;
}
/* Copies one full block of data from the applet input buffer (see
* appet_get_inbuf).
*
* <len> bytes are capied, starting at the offset <offset>.
*
* Return values :
* >0 : number of bytes read, equal to requested size.
* =0 : not enough data available. <blk> is left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getblk(const struct appctx *appctx, char *blk, int len, int offset)
{
const struct buffer *buf;
int ret;
ret = applet_may_get(appctx, len+offset);
if (ret <= 0)
return ret;
buf = ((appctx->flags & APPCTX_FL_INOUT_BUFS)
? &appctx->inbuf
: sc_ob(appctx_sc(appctx)));
return b_getblk(buf, blk, len, offset);
}
/* Gets one text block representing a word from the applet input buffer (see
* appet_get_inbuf).
*
* The separator is waited for as long as some data can still be received and the
* destination is not full. Otherwise, the string may be returned as is, without
* the separator.
*
* Return values :
* >0 : number of bytes read. Includes the separator if present before len or end.
* =0 : no separator before end found. <str> is left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getword(const struct appctx *appctx, char *str, int len, char sep)
{
const struct buffer *buf;
char *p;
size_t input, max = len;
int ret = 0;
ret = applet_may_get(appctx, 1);
if (ret <= 0)
goto out;
if (appctx->flags & APPCTX_FL_INOUT_BUFS) {
buf = &appctx->inbuf;
input = b_data(buf);
}
else {
struct stconn *sc = appctx_sc(appctx);
buf = sc_ob(sc);
input = co_data(sc_oc(sc));
}
if (max > input) {
max = input;
str[max-1] = 0;
}
p = b_head(buf);
while (max) {
*str++ = *p;
ret++;
max--;
if (*p == sep)
goto out;
p = b_next(buf, p);
}
if (appctx->flags & APPCTX_FL_INOUT_BUFS) {
if (ret < len && (ret < input || b_room(buf)) &&
!se_fl_test(appctx->sedesc, SE_FL_SHW))
ret = 0;
}
else {
struct stconn *sc = appctx_sc(appctx);
if (ret < len && (ret < input || channel_may_recv(sc_oc(sc))) &&
!(sc->flags & (SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED)))
ret = 0;
}
out:
if (max)
*str = 0;
return ret;
}
/* Gets one text block representing a line from the applet input buffer (see
* appet_get_inbuf).
*
* The '\n' is waited for as long as some data can still be received and the
* destination is not full. Otherwise, the string may be returned as is, without
* the '\n'.
*
* Return values :
* >0 : number of bytes read. Includes the \n if present before len or end.
* =0 : no '\n' before end found. <str> is left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getline(const struct appctx *appctx, char *str, int len)
{
return applet_getword(appctx, str, len, '\n');
}
/* Gets one or two blocks of data at once from the applet input buffer (see appet_get_inbuf),
*
* Data are not copied.
*
* Return values :
* >0 : number of blocks filled (1 or 2). blk1 is always filled before blk2.
* =0 : not enough data available. <blk*> are left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getblk_nc(const struct appctx *appctx, const char **blk1, size_t *len1, const char **blk2, size_t *len2)
{
const struct buffer *buf;
size_t max;
int ret;
ret = applet_may_get(appctx, 1);
if (ret <= 0)
return ret;
if (appctx->flags & APPCTX_FL_INOUT_BUFS) {
buf = &appctx->inbuf;
max = b_data(buf);
}
else {
struct stconn *sc = appctx_sc(appctx);
buf = sc_ob(sc);
max = co_data(sc_oc(sc));
}
return b_getblk_nc(buf, blk1, len1, blk2, len2, 0, max);
}
/* Gets one or two blocks of text representing a word from the applet input
* buffer (see appet_get_inbuf).
*
* Data are not copied. The separator is waited for as long as some data can
* still be received and the destination is not full. Otherwise, the string may
* be returned as is, without the separator.
*
* Return values :
* >0 : number of bytes read. Includes the separator if present before len or end.
* =0 : no separator before end found. <str> is left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getword_nc(const struct appctx *appctx, const char **blk1, size_t *len1, const char **blk2, size_t *len2, char sep)
{
int ret;
size_t l;
ret = applet_getblk_nc(appctx, blk1, len1, blk2, len2);
if (unlikely(ret <= 0))
return ret;
for (l = 0; l < *len1 && (*blk1)[l] != sep; l++);
if (l < *len1 && (*blk1)[l] == sep) {
*len1 = l + 1;
return 1;
}
if (ret >= 2) {
for (l = 0; l < *len2 && (*blk2)[l] != sep; l++);
if (l < *len2 && (*blk2)[l] == sep) {
*len2 = l + 1;
return 2;
}
}
/* If we have found no LF and the buffer is full or the SC is shut, then
* the resulting string is made of the concatenation of the pending
* blocks (1 or 2).
*/
if (appctx->flags & APPCTX_FL_INOUT_BUFS) {
if (b_full(&appctx->inbuf) || se_fl_test(appctx->sedesc, SE_FL_SHW))
return ret;
}
else {
struct stconn *sc = appctx_sc(appctx);
if (!channel_may_recv(sc_oc(sc)) || sc->flags & (SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED))
return ret;
}
/* No LF yet and not shut yet */
return 0;
}
/* Gets one or two blocks of text representing a line from the applet input
* buffer (see appet_get_inbuf).
*
* Data are not copied. The '\n' is waited for as long as some data can still be
* received and the destination is not full. Otherwise, the string may be
* returned as is, without the '\n'.
*
* Return values :
* >0 : number of bytes read. Includes the \n if present before len or end.
* =0 : no '\n' before end found. <str> is left undefined.
* <0 : no more bytes readable because output is shut.
*
* The status of the corresponding buffer is not changed. The caller must call
* applet_skip_input() to update it.
*/
static inline int applet_getline_nc(const struct appctx *appctx, const char **blk1, size_t *len1, const char **blk2, size_t *len2)
{
return applet_getword_nc(appctx, blk1, len1, blk2, len2, '\n');
}
#endif /* _HAPROXY_APPLET_H */
/*

View File

@ -86,7 +86,7 @@ static inline int be_usable_srv(struct proxy *be)
/* set the time of last session on the backend */
static inline void be_set_sess_last(struct proxy *be)
{
be->be_counters.last_sess = ns_to_sec(now_ns);
HA_ATOMIC_STORE(&be->be_counters.shared->tg[tgid - 1]->last_sess, ns_to_sec(now_ns));
}
/* This function returns non-zero if the designated server will be

View File

@ -1,46 +0,0 @@
/*
* include/haprox/cbuf-t.h
* This file contains definition for circular buffers.
*
* Copyright 2021 HAProxy Technologies, Frederic Lecaille <flecaille@haproxy.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _HAPROXY_CBUF_T_H
#define _HAPROXY_CBUF_T_H
#ifdef USE_QUIC
#ifndef USE_OPENSSL
#error "Must define USE_OPENSSL"
#endif
#endif
#include <stddef.h>
#include <haproxy/list-t.h>
extern struct pool_head *pool_head_cbuf;
struct cbuf {
/* buffer */
unsigned char *buf;
/* buffer size */
size_t sz;
/* Writer index */
size_t wr;
/* Reader index */
size_t rd;
};
#endif /* _HAPROXY_CBUF_T_H */

View File

@ -1,136 +0,0 @@
/*
* include/haprox/cbuf.h
* This file contains definitions and prototypes for circular buffers.
* Inspired from Linux circular buffers (include/linux/circ_buf.h).
*
* Copyright 2021 HAProxy Technologies, Frederic Lecaille <flecaille@haproxy.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _HAPROXY_CBUF_H
#define _HAPROXY_CBUF_H
#ifdef USE_QUIC
#ifndef USE_OPENSSL
#error "Must define USE_OPENSSL"
#endif
#endif
#include <haproxy/atomic.h>
#include <haproxy/list.h>
#include <haproxy/cbuf-t.h>
struct cbuf *cbuf_new(unsigned char *buf, size_t sz);
void cbuf_free(struct cbuf *cbuf);
/* Amount of data between <rd> and <wr> */
#define CBUF_DATA(wr, rd, size) (((wr) - (rd)) & ((size) - 1))
/* Return the writer position in <cbuf>.
* To be used only by the writer!
*/
static inline unsigned char *cb_wr(struct cbuf *cbuf)
{
return cbuf->buf + cbuf->wr;
}
/* Reset the reader index.
* To be used by a reader!
*/
static inline void cb_rd_reset(struct cbuf *cbuf)
{
cbuf->rd = 0;
}
/* Reset the writer index.
* To be used by a writer!
*/
static inline void cb_wr_reset(struct cbuf *cbuf)
{
cbuf->wr = 0;
}
/* Increase <cbuf> circular buffer data by <count>.
* To be used by a writer!
*/
static inline void cb_add(struct cbuf *cbuf, size_t count)
{
cbuf->wr = (cbuf->wr + count) & (cbuf->sz - 1);
}
/* Return the reader position in <cbuf>.
* To be used only by the reader!
*/
static inline unsigned char *cb_rd(struct cbuf *cbuf)
{
return cbuf->buf + cbuf->rd;
}
/* Skip <count> byte in <cbuf> circular buffer.
* To be used by a reader!
*/
static inline void cb_del(struct cbuf *cbuf, size_t count)
{
cbuf->rd = (cbuf->rd + count) & (cbuf->sz - 1);
}
/* Return the amount of data left in <cbuf>.
* To be used only by the writer!
*/
static inline size_t cb_data(struct cbuf *cbuf)
{
size_t rd;
rd = HA_ATOMIC_LOAD(&cbuf->rd);
return CBUF_DATA(cbuf->wr, rd, cbuf->sz);
}
/* Return the amount of room left in <cbuf> minus 1 to distinguish
* the case where the buffer is full from the case where is is empty
* To be used only by the write!
*/
static inline size_t cb_room(struct cbuf *cbuf)
{
size_t rd;
rd = HA_ATOMIC_LOAD(&cbuf->rd);
return CBUF_DATA(rd, cbuf->wr + 1, cbuf->sz);
}
/* Return the amount of contiguous data left in <cbuf>.
* To be used only by the reader!
*/
static inline size_t cb_contig_data(struct cbuf *cbuf)
{
size_t end, n;
end = cbuf->sz - cbuf->rd;
n = (HA_ATOMIC_LOAD(&cbuf->wr) + end) & (cbuf->sz - 1);
return n < end ? n : end;
}
/* Return the amount of contiguous space left in <cbuf>.
* To be used only by the writer!
*/
static inline size_t cb_contig_space(struct cbuf *cbuf)
{
size_t end, n;
end = cbuf->sz - 1 - cbuf->wr;
n = (HA_ATOMIC_LOAD(&cbuf->rd) + end) & (cbuf->sz - 1);
return n <= end ? n : end + 1;
}
#endif /* _HAPROXY_CBUF_H */

View File

@ -25,108 +25,144 @@
#include <haproxy/freq_ctr-t.h>
#define COUNTERS_SHARED_F_NONE 0x0000
#define COUNTERS_SHARED_F_LOCAL 0x0001 // shared counter struct is actually process-local
// common to fe_counters_shared and be_counters_shared
#define COUNTERS_SHARED \
struct { \
uint16_t flags; /* COUNTERS_SHARED_F flags */\
};
#define COUNTERS_SHARED_TG \
struct { \
unsigned long last_change; /* last time, when the state was changed */\
long long srv_aborts; /* aborted responses during DATA phase caused by the server */\
long long cli_aborts; /* aborted responses during DATA phase caused by the client */\
long long internal_errors; /* internal processing errors */\
long long failed_rewrites; /* failed rewrites (warning) */\
long long bytes_out; /* number of bytes transferred from the server to the client */\
long long bytes_in; /* number of bytes transferred from the client to the server */\
long long denied_resp; /* blocked responses because of security concerns */\
long long denied_req; /* blocked requests because of security concerns */\
long long cum_sess; /* cumulated number of accepted connections */\
/* compression counters, index 0 for requests, 1 for responses */\
long long comp_in[2]; /* input bytes fed to the compressor */\
long long comp_out[2]; /* output bytes emitted by the compressor */\
long long comp_byp[2]; /* input bytes that bypassed the compressor (cpu/ram/bw limitation) */\
struct freq_ctr sess_per_sec; /* sessions per second on this server */\
}
// for convenience (generic pointer)
struct counters_shared {
COUNTERS_SHARED;
struct {
COUNTERS_SHARED_TG;
} *tg[MAX_TGROUPS];
};
/* counters used by listeners and frontends */
struct fe_counters {
unsigned int conn_max; /* max # of active sessions */
long long cum_conn; /* cumulated number of received connections */
long long cum_sess; /* cumulated number of accepted connections */
long long cum_sess_ver[3]; /* cumulated number of h1/h2/h3 sessions */
struct fe_counters_shared_tg {
COUNTERS_SHARED_TG;
unsigned int cps_max; /* maximum of new connections received per second */
unsigned int sps_max; /* maximum of new connections accepted per second (sessions) */
long long bytes_in; /* number of bytes transferred from the client to the server */
long long bytes_out; /* number of bytes transferred from the server to the client */
/* compression counters, index 0 for requests, 1 for responses */
long long comp_in[2]; /* input bytes fed to the compressor */
long long comp_out[2]; /* output bytes emitted by the compressor */
long long comp_byp[2]; /* input bytes that bypassed the compressor (cpu/ram/bw limitation) */
long long denied_req; /* blocked requests because of security concerns */
long long denied_resp; /* blocked responses because of security concerns */
long long failed_req; /* failed requests (eg: invalid or timeout) */
long long denied_conn; /* denied connection requests (tcp-req-conn rules) */
long long denied_sess; /* denied session requests (tcp-req-sess rules) */
long long failed_rewrites; /* failed rewrites (warning) */
long long internal_errors; /* internal processing errors */
long long cli_aborts; /* aborted responses during DATA phase caused by the client */
long long srv_aborts; /* aborted responses during DATA phase caused by the server */
long long denied_conn; /* denied connection requests (tcp-req-conn rules) */
long long intercepted_req; /* number of monitoring or stats requests intercepted by the frontend */
long long cum_conn; /* cumulated number of received connections */
struct freq_ctr conn_per_sec; /* received connections per second on the frontend */
struct freq_ctr req_per_sec; /* HTTP requests per second on the frontend */
long long cum_sess_ver[3]; /* cumulated number of h1/h2/h3 sessions */
union {
struct {
long long cum_req[4]; /* cumulated number of processed other/h1/h2/h3 requests */
long long comp_rsp; /* number of compressed responses */
unsigned int rps_max; /* maximum of new HTTP requests second observed */
long long rsp[6]; /* http response codes */
long long cache_lookups;/* cache lookups */
long long cache_hits; /* cache hits */
long long cache_lookups;/* cache lookups */
long long comp_rsp; /* number of compressed responses */
long long rsp[6]; /* http response codes */
} http;
} p; /* protocol-specific stats */
struct freq_ctr sess_per_sec; /* sessions per second on this server */
struct freq_ctr req_per_sec; /* HTTP requests per second on the frontend */
struct freq_ctr conn_per_sec; /* received connections per second on the frontend */
long long failed_req; /* failed requests (eg: invalid or timeout) */
};
unsigned long last_change; /* last time, when the state was changed */
struct fe_counters_shared {
COUNTERS_SHARED;
struct fe_counters_shared_tg *tg[MAX_TGROUPS];
};
struct fe_counters {
struct fe_counters_shared *shared; /* shared counters */
unsigned int conn_max; /* max # of active sessions */
unsigned int cps_max; /* maximum of new connections received per second */
unsigned int sps_max; /* maximum of new connections accepted per second (sessions) */
struct freq_ctr _sess_per_sec; /* sessions per second on this frontend, used to compute sps_max (internal use only) */
struct freq_ctr _conn_per_sec; /* connections per second on this frontend, used to compute cps_max (internal use only) */
union {
struct {
unsigned int rps_max; /* maximum of new HTTP requests second observed */
struct freq_ctr _req_per_sec; /* HTTP requests per second on the frontend, only used to compute rps_max */
} http;
} p; /* protocol-specific stats */
};
struct be_counters_shared_tg {
COUNTERS_SHARED_TG;
long long cum_lbconn; /* cumulated number of sessions processed by load balancing (BE only) */
long long connect; /* number of connection establishment attempts */
long long reuse; /* number of connection reuses */
unsigned long last_sess; /* last session time */
long long failed_checks, failed_hana; /* failed health checks and health analyses for servers */
long long down_trans; /* up->down transitions */
union {
struct {
long long cum_req; /* cumulated number of processed HTTP requests */
long long cache_hits; /* cache hits */
long long cache_lookups;/* cache lookups */
long long comp_rsp; /* number of compressed responses */
long long rsp[6]; /* http response codes */
} http;
} p; /* protocol-specific stats */
long long redispatches; /* retried and redispatched connections (BE only) */
long long retries; /* retried and redispatched connections (BE only) */
long long failed_resp; /* failed responses (BE only) */
long long failed_conns; /* failed connect() attempts (BE only) */
};
struct be_counters_shared {
COUNTERS_SHARED;
struct be_counters_shared_tg *tg[MAX_TGROUPS];
};
/* counters used by servers and backends */
struct be_counters {
struct be_counters_shared *shared; /* shared counters */
unsigned int conn_max; /* max # of active sessions */
long long cum_sess; /* cumulated number of accepted connections */
long long cum_lbconn; /* cumulated number of sessions processed by load balancing (BE only) */
unsigned int cps_max; /* maximum of new connections received per second */
unsigned int sps_max; /* maximum of new connections accepted per second (sessions) */
unsigned int nbpend_max; /* max number of pending connections with no server assigned yet */
unsigned int cur_sess_max; /* max number of currently active sessions */
long long bytes_in; /* number of bytes transferred from the client to the server */
long long bytes_out; /* number of bytes transferred from the server to the client */
/* compression counters, index 0 for requests, 1 for responses */
long long comp_in[2]; /* input bytes fed to the compressor */
long long comp_out[2]; /* output bytes emitted by the compressor */
long long comp_byp[2]; /* input bytes that bypassed the compressor (cpu/ram/bw limitation) */
long long denied_req; /* blocked requests because of security concerns */
long long denied_resp; /* blocked responses because of security concerns */
long long connect; /* number of connection establishment attempts */
long long reuse; /* number of connection reuses */
long long failed_conns; /* failed connect() attempts (BE only) */
long long failed_resp; /* failed responses (BE only) */
long long cli_aborts; /* aborted responses during DATA phase caused by the client */
long long srv_aborts; /* aborted responses during DATA phase caused by the server */
long long retries; /* retried and redispatched connections (BE only) */
long long redispatches; /* retried and redispatched connections (BE only) */
long long failed_rewrites; /* failed rewrites (warning) */
long long internal_errors; /* internal processing errors */
long long failed_checks, failed_hana; /* failed health checks and health analyses for servers */
long long down_trans; /* up->down transitions */
struct freq_ctr _sess_per_sec; /* sessions per second on this frontend, used to compute sps_max (internal use only) */
unsigned int q_time, c_time, d_time, t_time; /* sums of conn_time, queue_time, data_time, total_time */
unsigned int qtime_max, ctime_max, dtime_max, ttime_max; /* maximum of conn_time, queue_time, data_time, total_time observed */
union {
struct {
long long cum_req; /* cumulated number of processed HTTP requests */
long long comp_rsp; /* number of compressed responses */
unsigned int rps_max; /* maximum of new HTTP requests second observed */
long long rsp[6]; /* http response codes */
long long cache_lookups;/* cache lookups */
long long cache_hits; /* cache hits */
} http;
} p; /* protocol-specific stats */
struct freq_ctr sess_per_sec; /* sessions per second on this server */
unsigned long last_sess; /* last session time */
unsigned long last_change; /* last time, when the state was changed */
};
#endif /* _HAPROXY_COUNTERS_T_H */

102
include/haproxy/counters.h Normal file
View File

@ -0,0 +1,102 @@
/*
* include/haproxy/counters.h
* objects counters management
*
* Copyright 2025 HAProxy Technologies
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _HAPROXY_COUNTERS_H
# define _HAPROXY_COUNTERS_H
#include <stddef.h>
#include <haproxy/counters-t.h>
#include <haproxy/guid-t.h>
struct fe_counters_shared *counters_fe_shared_get(const struct guid_node *guid);
struct be_counters_shared *counters_be_shared_get(const struct guid_node *guid);
void counters_fe_shared_drop(struct fe_counters_shared *counters);
void counters_be_shared_drop(struct be_counters_shared *counters);
/* time oriented helper: get last time (relative to current time) on a given
* <scounter> array, for <elem> member (one member per thread group) which is
* assumed to be unsigned long type.
*
* wrapping is handled by taking the lowest diff between now and last counter.
* But since wrapping is expected once every ~136 years (starting 01/01/1970),
* perhaps it's not worth the extra CPU cost.. let's see.
*/
#define COUNTERS_SHARED_LAST_OFFSET(scounters, type, offset) \
({ \
unsigned long last = HA_ATOMIC_LOAD((type *)((char *)scounters[0] + offset));\
unsigned long now_seconds = ns_to_sec(now_ns); \
int it; \
\
for (it = 1; it < global.nbtgroups; it++) { \
unsigned long cur = HA_ATOMIC_LOAD((type *)((char *)scounters[it] + offset));\
if ((now_seconds - cur) < (now_seconds - last)) \
last = cur; \
} \
last; \
})
#define COUNTERS_SHARED_LAST(scounters, elem) \
({ \
int offset = offsetof(typeof(**scounters), elem); \
unsigned long last = COUNTERS_SHARED_LAST_OFFSET(scounters, typeof(scounters[0]->elem), offset); \
\
last; \
})
/* generic unsigned integer addition for all <elem> members from
* <scounters> array (one member per thread group)
* <rfunc> is function taking pointer as parameter to read from the memory
* location pointed to scounters[it].elem
*/
#define COUNTERS_SHARED_TOTAL_OFFSET(scounters, type, offset, rfunc) \
({ \
uint64_t __ret = 0; \
int it; \
\
for (it = 0; it < global.nbtgroups; it++) \
__ret += rfunc((type *)((char *)scounters[it] + offset)); \
__ret; \
})
#define COUNTERS_SHARED_TOTAL(scounters, elem, rfunc) \
({ \
int offset = offsetof(typeof(**scounters), elem); \
uint64_t __ret = COUNTERS_SHARED_TOTAL_OFFSET(scounters, typeof(scounters[0]->elem), offset, rfunc);\
\
__ret; \
})
/* same as COUNTERS_SHARED_TOTAL but with <rfunc> taking 2 extras arguments:
* <arg1> and <arg2>
*/
#define COUNTERS_SHARED_TOTAL_ARG2(scounters, elem, rfunc, arg1, arg2) \
({ \
uint64_t __ret = 0; \
int it; \
\
for (it = 0; it < global.nbtgroups; it++) \
__ret += rfunc(&scounters[it]->elem, arg1, arg2); \
__ret; \
})
#endif /* _HAPROXY_COUNTERS_H */

View File

@ -499,6 +499,7 @@ static inline long fd_clr_running(int fd)
static inline void fd_insert(int fd, void *owner, void (*iocb)(int fd), int tgid, unsigned long thread_mask)
{
extern void sock_conn_iocb(int);
struct tgroup_info *tginfo = &ha_tgroup_info[tgid - 1];
int newstate;
/* conn_fd_handler should support edge-triggered FDs */
@ -528,7 +529,7 @@ static inline void fd_insert(int fd, void *owner, void (*iocb)(int fd), int tgid
BUG_ON(fdtab[fd].state != 0);
BUG_ON(tgid < 1 || tgid > MAX_TGROUPS);
thread_mask &= tg->threads_enabled;
thread_mask &= tginfo->threads_enabled;
BUG_ON(thread_mask == 0);
fd_claim_tgid(fd, tgid);

View File

@ -197,6 +197,7 @@ struct global {
int pattern_cache; /* max number of entries in the pattern cache. */
int sslcachesize; /* SSL cache size in session, defaults to 20000 */
int comp_maxlevel; /* max HTTP compression level */
uint glitch_kill_maxidle; /* have glitches kill only below this level of idle */
int pool_low_ratio; /* max ratio of FDs used before we stop using new idle connections */
int pool_high_ratio; /* max ratio of FDs used before we start killing idle connections when creating new connections */
int pool_low_count; /* max number of opened fd before we stop using new idle connections */

View File

@ -121,6 +121,7 @@ enum li_status {
#define BC_SSL_O_NONE 0x0000
#define BC_SSL_O_NO_TLS_TICKETS 0x0100 /* disable session resumption tickets */
#define BC_SSL_O_PREF_CLIE_CIPH 0x0200 /* prefer client ciphers */
#define BC_SSL_O_STRICT_SNI 0x0400 /* refuse negotiation if sni doesn't match a certificate */
#endif
struct tls_version_filter {
@ -169,7 +170,6 @@ struct bind_conf {
unsigned long long ca_ignerr_bitfield[IGNERR_BF_SIZE]; /* ignored verify errors in handshake if depth > 0 */
unsigned long long crt_ignerr_bitfield[IGNERR_BF_SIZE]; /* ignored verify errors in handshake if depth == 0 */
void *initial_ctx; /* SSL context for initial negotiation */
int strict_sni; /* refuse negotiation if sni doesn't match a certificate */
int ssl_options; /* ssl options */
struct eb_root sni_ctx; /* sni_ctx tree of all known certs full-names sorted by name */
struct eb_root sni_w_ctx; /* sni_ctx tree of all known certs wildcards sorted by name */
@ -244,7 +244,7 @@ struct listener {
struct fe_counters *counters; /* statistics counters */
struct mt_list wait_queue; /* link element to make the listener wait for something (LI_LIMITED) */
char *name; /* listener's name */
char *label; /* listener's label */
unsigned int thr_conn[MAX_THREADS_PER_GROUP]; /* number of connections per thread for the group */
struct list by_fe; /* chaining in frontend's list of listeners */

View File

@ -28,9 +28,6 @@ enum qcs_type {
QCS_SRV_BIDI,
QCS_CLT_UNI,
QCS_SRV_UNI,
/* Must be the last one */
QCS_MAX_TYPES
};
enum qcc_app_st {
@ -205,7 +202,7 @@ struct qcc_app_ops {
/* Initialize <qcs> stream app context or leave it to NULL if rejected. */
int (*attach)(struct qcs *qcs, void *conn_ctx);
/* Convert received HTTP payload to HTX. */
/* Convert received HTTP payload to HTX. Returns amount of decoded bytes from <b> or a negative error code. */
ssize_t (*rcv_buf)(struct qcs *qcs, struct buffer *b, int fin);
/* Convert HTX to HTTP payload for sending. */
@ -235,7 +232,7 @@ struct qcc_app_ops {
#define QC_CF_ERRL 0x00000001 /* fatal error detected locally, connection should be closed soon */
#define QC_CF_ERRL_DONE 0x00000002 /* local error properly handled, connection can be released */
/* unused 0x00000004 */
#define QC_CF_IS_BACK 0x00000004 /* backend side */
#define QC_CF_CONN_FULL 0x00000008 /* no stream buffers available on connection */
/* unused 0x00000010 */
#define QC_CF_ERR_CONN 0x00000020 /* fatal error reported by transport layer */

View File

@ -51,15 +51,7 @@ static inline int qmux_stream_rx_bufsz(void)
return global.tune.bufsize - NCB_RESERVED_SZ;
}
/* Bit shift to get the stream sub ID for internal use which is obtained
* shifting the stream IDs by this value, knowing that the
* QCS_ID_TYPE_SHIFT less significant bits identify the stream ID
* types (client initiated bidirectional, server initiated bidirectional,
* client initiated unidirectional, server initiated bidirectional).
* Note that there is no reference to such stream sub IDs in the RFC.
*/
#define QCS_ID_TYPE_MASK 0x3
#define QCS_ID_TYPE_SHIFT 2
/* The less significant bit of a stream ID is set for a server initiated stream */
#define QCS_ID_SRV_INTIATOR_BIT 0x1
/* This bit is set for unidirectional streams */
@ -82,16 +74,6 @@ static inline int quic_stream_is_remote(struct qcc *qcc, uint64_t id)
return !quic_stream_is_local(qcc, id);
}
static inline int quic_stream_is_uni(uint64_t id)
{
return id & QCS_ID_DIR_BIT;
}
static inline int quic_stream_is_bidi(uint64_t id)
{
return !quic_stream_is_uni(id);
}
static inline char *qcs_st_to_str(enum qcs_state st)
{
switch (st) {

View File

@ -46,7 +46,25 @@
#ifdef USE_QUIC_OPENSSL_COMPAT
#include <haproxy/quic_openssl_compat.h>
#else
#if defined(OSSL_FUNC_SSL_QUIC_TLS_CRYPTO_SEND)
/* This macro is defined by the new OpenSSL 3.5.0 QUIC TLS API and it is not
* defined by quictls.
*/
#define HAVE_OPENSSL_QUIC
#define SSL_set_quic_transport_params SSL_set_quic_tls_transport_params
#define SSL_set_quic_early_data_enabled SSL_set_quic_tls_early_data_enabled
#define SSL_quic_read_level(arg) -1
enum ssl_encryption_level_t {
ssl_encryption_initial = 0,
ssl_encryption_early_data,
ssl_encryption_handshake,
ssl_encryption_application
};
#endif
#endif /* USE_QUIC_OPENSSL_COMPAT */
#if defined(OPENSSL_IS_AWSLC)
#define OPENSSL_NO_DH

View File

@ -311,6 +311,10 @@ struct proxy {
char flags; /* bit field PR_FL_* */
enum pr_mode mode; /* mode = PR_MODE_TCP, PR_MODE_HTTP, ... */
char cap; /* supported capabilities (PR_CAP_*) */
/* 4-bytes hole */
struct list global_list; /* list member for global proxy list */
unsigned int maxconn; /* max # of active streams on the frontend */
int options; /* PR_O_REDISP, PR_O_TRANSP, ... */

View File

@ -33,6 +33,7 @@
#include <haproxy/thread.h>
extern struct proxy *proxies_list;
extern struct list proxies;
extern struct eb_root used_proxy_id; /* list of proxy IDs in use */
extern unsigned int error_snapshot_id; /* global ID assigned to each error then incremented */
extern struct eb_root proxy_by_name; /* tree of proxies sorted by name */
@ -135,22 +136,24 @@ static inline void proxy_reset_timeouts(struct proxy *proxy)
/* increase the number of cumulated connections received on the designated frontend */
static inline void proxy_inc_fe_conn_ctr(struct listener *l, struct proxy *fe)
{
_HA_ATOMIC_INC(&fe->fe_counters.cum_conn);
_HA_ATOMIC_INC(&fe->fe_counters.shared->tg[tgid - 1]->cum_conn);
if (l && l->counters)
_HA_ATOMIC_INC(&l->counters->cum_conn);
_HA_ATOMIC_INC(&l->counters->shared->tg[tgid - 1]->cum_conn);
update_freq_ctr(&fe->fe_counters.shared->tg[tgid - 1]->conn_per_sec, 1);
HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.cps_max,
update_freq_ctr(&fe->fe_counters.conn_per_sec, 1));
update_freq_ctr(&fe->fe_counters._conn_per_sec, 1));
}
/* increase the number of cumulated connections accepted by the designated frontend */
static inline void proxy_inc_fe_sess_ctr(struct listener *l, struct proxy *fe)
{
_HA_ATOMIC_INC(&fe->fe_counters.cum_sess);
_HA_ATOMIC_INC(&fe->fe_counters.shared->tg[tgid - 1]->cum_sess);
if (l && l->counters)
_HA_ATOMIC_INC(&l->counters->cum_sess);
_HA_ATOMIC_INC(&l->counters->shared->tg[tgid - 1]->cum_sess);
update_freq_ctr(&fe->fe_counters.shared->tg[tgid - 1]->sess_per_sec, 1);
HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.sps_max,
update_freq_ctr(&fe->fe_counters.sess_per_sec, 1));
update_freq_ctr(&fe->fe_counters._sess_per_sec, 1));
}
/* increase the number of cumulated HTTP sessions on the designated frontend.
@ -160,20 +163,21 @@ static inline void proxy_inc_fe_cum_sess_ver_ctr(struct listener *l, struct prox
unsigned int http_ver)
{
if (http_ver == 0 ||
http_ver > sizeof(fe->fe_counters.cum_sess_ver) / sizeof(*fe->fe_counters.cum_sess_ver))
http_ver > sizeof(fe->fe_counters.shared->tg[tgid - 1]->cum_sess_ver) / sizeof(*fe->fe_counters.shared->tg[tgid - 1]->cum_sess_ver))
return;
_HA_ATOMIC_INC(&fe->fe_counters.cum_sess_ver[http_ver - 1]);
_HA_ATOMIC_INC(&fe->fe_counters.shared->tg[tgid - 1]->cum_sess_ver[http_ver - 1]);
if (l && l->counters)
_HA_ATOMIC_INC(&l->counters->cum_sess_ver[http_ver - 1]);
_HA_ATOMIC_INC(&l->counters->shared->tg[tgid - 1]->cum_sess_ver[http_ver - 1]);
}
/* increase the number of cumulated streams on the designated backend */
static inline void proxy_inc_be_ctr(struct proxy *be)
{
_HA_ATOMIC_INC(&be->be_counters.cum_sess);
_HA_ATOMIC_INC(&be->be_counters.shared->tg[tgid - 1]->cum_sess);
update_freq_ctr(&be->be_counters.shared->tg[tgid - 1]->sess_per_sec, 1);
HA_ATOMIC_UPDATE_MAX(&be->be_counters.sps_max,
update_freq_ctr(&be->be_counters.sess_per_sec, 1));
update_freq_ctr(&be->be_counters._sess_per_sec, 1));
}
/* increase the number of cumulated requests on the designated frontend.
@ -183,14 +187,15 @@ static inline void proxy_inc_be_ctr(struct proxy *be)
static inline void proxy_inc_fe_req_ctr(struct listener *l, struct proxy *fe,
unsigned int http_ver)
{
if (http_ver >= sizeof(fe->fe_counters.p.http.cum_req) / sizeof(*fe->fe_counters.p.http.cum_req))
if (http_ver >= sizeof(fe->fe_counters.shared->tg[tgid - 1]->p.http.cum_req) / sizeof(*fe->fe_counters.shared->tg[tgid - 1]->p.http.cum_req))
return;
_HA_ATOMIC_INC(&fe->fe_counters.p.http.cum_req[http_ver]);
_HA_ATOMIC_INC(&fe->fe_counters.shared->tg[tgid - 1]->p.http.cum_req[http_ver]);
if (l && l->counters)
_HA_ATOMIC_INC(&l->counters->p.http.cum_req[http_ver]);
_HA_ATOMIC_INC(&l->counters->shared->tg[tgid - 1]->p.http.cum_req[http_ver]);
update_freq_ctr(&fe->fe_counters.shared->tg[tgid - 1]->req_per_sec, 1);
HA_ATOMIC_UPDATE_MAX(&fe->fe_counters.p.http.rps_max,
update_freq_ctr(&fe->fe_counters.req_per_sec, 1));
update_freq_ctr(&fe->fe_counters.p.http._req_per_sec, 1));
}
/* Returns non-zero if the proxy is configured to retry a request if we got that status, 0 otherwise */

View File

@ -28,22 +28,22 @@
#include <sys/socket.h>
#include <haproxy/cbuf-t.h>
#include <haproxy/list.h>
#include <haproxy/show_flags-t.h>
#include <import/ebtree-t.h>
#include <haproxy/api-t.h>
#include <haproxy/buf-t.h>
#include <haproxy/listener-t.h>
#include <haproxy/openssl-compat.h>
#include <haproxy/mux_quic-t.h>
#include <haproxy/quic_cid-t.h>
#include <haproxy/quic_cc-t.h>
#include <haproxy/quic_loss-t.h>
#include <haproxy/quic_frame-t.h>
#include <haproxy/quic_openssl_compat-t.h>
#include <haproxy/quic_stats-t.h>
#include <haproxy/quic_tls-t.h>
#include <haproxy/quic_tp-t.h>
#include <haproxy/task.h>
#include <import/ebtree-t.h>
#include <haproxy/show_flags-t.h>
#include <haproxy/ssl_sock-t.h>
#include <haproxy/task-t.h>
typedef unsigned long long ull;
@ -228,6 +228,9 @@ struct quic_version {
extern const struct quic_version quic_versions[];
extern const size_t quic_versions_nb;
extern const struct quic_version *preferred_version;
extern const struct quic_version *quic_version_draft_29;
extern const struct quic_version *quic_version_1;
extern const struct quic_version *quic_version_2;
/* unused: 0x01 */
/* Flag the packet number space as requiring an ACK frame to be sent. */
@ -279,6 +282,10 @@ struct quic_conn_cntrs {
long long streams_blocked_uni; /* total number of times STREAMS_BLOCKED_UNI frame was received */
};
struct connection;
struct qcc;
struct qcc_app_ops;
#define QUIC_CONN_COMMON \
struct { \
/* Connection owned socket FD. */ \
@ -301,6 +308,7 @@ struct quic_conn_cntrs {
/* Number of received bytes. */ \
uint64_t rx; \
} bytes; \
size_t max_udp_payload; \
/* First DCID used by client on its Initial packet. */ \
struct quic_cid odcid; \
/* DCID of our endpoint - not updated when a new DCID is used */ \
@ -311,7 +319,7 @@ struct quic_conn_cntrs {
* with a connection \
*/ \
struct eb_root *cids; \
struct listener *li; /* only valid for frontend connections */ \
enum obj_type *target; \
/* Idle timer task */ \
struct task *idle_timer_task; \
unsigned int idle_expire; \
@ -334,7 +342,10 @@ struct quic_conn {
int tps_tls_ext;
int state;
enum qc_mux_state mux_state; /* status of the connection/mux layer */
#ifdef USE_QUIC_OPENSSL_COMPAT
#ifdef HAVE_OPENSSL_QUIC
uint32_t prot_level;
#endif
#if defined(USE_QUIC_OPENSSL_COMPAT) || defined(HAVE_OPENSSL_QUIC)
unsigned char enc_params[QUIC_TP_MAX_ENCLEN]; /* encoded QUIC transport parameters */
size_t enc_params_len;
#endif
@ -383,10 +394,10 @@ struct quic_conn {
/* RX buffer */
struct buffer buf;
struct list pkt_list;
struct {
/* Number of open or closed streams */
uint64_t nb_streams;
} strms[QCS_MAX_TYPES];
/* first unhandled streams ID, set by MUX after release */
uint64_t stream_max_uni;
uint64_t stream_max_bidi;
} rx;
struct {
struct quic_tls_kp prv_rx;
@ -449,6 +460,7 @@ struct quic_conn_closed {
#define QUIC_FL_CONN_HPKTNS_DCD (1U << 16) /* Handshake packet number space discarded */
#define QUIC_FL_CONN_PEER_VALIDATED_ADDR (1U << 17) /* Peer address is considered as validated for this connection. */
#define QUIC_FL_CONN_NO_TOKEN_RCVD (1U << 18) /* Client dit not send any token */
#define QUIC_FL_CONN_SCID_RECEIVED (1U << 19) /* (client only: first Initial received. */
/* gap here */
#define QUIC_FL_CONN_TO_KILL (1U << 24) /* Unusable connection, to be killed */
#define QUIC_FL_CONN_TX_TP_RECEIVED (1U << 25) /* Peer transport parameters have been received (used for the transmitting part) */

View File

@ -69,7 +69,8 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
struct quic_connection_id *conn_id,
struct sockaddr_storage *local_addr,
struct sockaddr_storage *peer_addr,
int server, int token, void *owner);
int token, void *owner,
struct connection *conn);
int quic_build_post_handshake_frames(struct quic_conn *qc);
const struct quic_version *qc_supported_version(uint32_t version);
int quic_peer_validated_addr(struct quic_conn *qc);
@ -163,6 +164,22 @@ static inline void quic_free_ncbuf(struct ncbuf *ncbuf)
*ncbuf = NCBUF_NULL;
}
/* Return the address of the QUIC counters attached to the proxy of
* the owner of the connection whose object type address is <o> for
* listener and servers, or NULL for others object type.
*/
static inline void *qc_counters(enum obj_type *o, const struct stats_module *m)
{
struct proxy *p;
struct listener *l = objt_listener(o);
struct server *s = objt_server(o);
p = l ? l->bind_conf->frontend :
s ? s->proxy : NULL;
return p ? EXTRA_COUNTERS_GET(p->extra_counters_fe, m) : NULL;
}
void chunk_frm_appendf(struct buffer *buf, const struct quic_frame *frm);
void quic_set_connection_close(struct quic_conn *qc, const struct quic_err err);
void quic_set_tls_alert(struct quic_conn *qc, int alert);

View File

@ -26,7 +26,7 @@
#include <haproxy/quic_rx-t.h>
int quic_dgram_parse(struct quic_dgram *dgram, struct quic_conn *from_qc,
struct listener *li);
enum obj_type *obj_type);
int qc_treat_rx_pkts(struct quic_conn *qc);
int qc_parse_hd_form(struct quic_rx_packet *pkt,
unsigned char **pos, const unsigned char *end);

View File

@ -31,7 +31,9 @@
#include <haproxy/api.h>
#include <haproxy/connection-t.h>
#include <haproxy/fd-t.h>
#include <haproxy/listener-t.h>
#include <haproxy/obj_type.h>
#include <haproxy/quic_conn-t.h>
#include <haproxy/quic_sock-t.h>
@ -77,7 +79,8 @@ static inline char qc_test_fd(struct quic_conn *qc)
*/
static inline int qc_fd(struct quic_conn *qc)
{
return qc_test_fd(qc) ? qc->fd : qc->li->rx.fd;
/* TODO: check this: For backends, qc->fd is always initialized */
return qc_test_fd(qc) ? qc->fd : __objt_listener(qc->target)->rx.fd;
}
/* Try to increment <l> handshake current counter. If listener limit is

View File

@ -34,8 +34,10 @@
#include <haproxy/ssl_sock-t.h>
int ssl_quic_initial_ctx(struct bind_conf *bind_conf);
int qc_alloc_ssl_sock_ctx(struct quic_conn *qc);
SSL_CTX *ssl_quic_srv_new_ssl_ctx(void);
int qc_alloc_ssl_sock_ctx(struct quic_conn *qc, struct connection *conn);
int qc_ssl_provide_all_quic_data(struct quic_conn *qc, struct ssl_sock_ctx *ctx);
int quic_ssl_set_tls_cbs(SSL *ssl);
static inline void qc_free_ssl_sock_ctx(struct ssl_sock_ctx **ctx)
{

View File

@ -291,6 +291,29 @@ static inline struct quic_enc_level **ssl_to_qel_addr(struct quic_conn *qc,
}
}
#ifdef HAVE_OPENSSL_QUIC
/* Simple helper function which translate an OpenSSL SSL protection level
* to a quictls SSL encryption. This way the code which use the OpenSSL QUIC API
* may use the code which uses the quictls API.
*/
static inline enum ssl_encryption_level_t ssl_prot_level_to_enc_level(struct quic_conn *qc,
uint32_t prot_level)
{
switch (prot_level) {
case OSSL_RECORD_PROTECTION_LEVEL_NONE:
return ssl_encryption_initial;
case OSSL_RECORD_PROTECTION_LEVEL_EARLY:
return ssl_encryption_early_data;
case OSSL_RECORD_PROTECTION_LEVEL_HANDSHAKE:
return ssl_encryption_handshake;
case OSSL_RECORD_PROTECTION_LEVEL_APPLICATION:
return ssl_encryption_application;
default:
return -1;
}
}
#endif
/* Return the address of the QUIC TLS encryption level associated to <level> internal
* encryption level and attached to <qc> QUIC connection if succeeded, or
* NULL if failed.

View File

@ -26,6 +26,9 @@ int qc_lstnr_params_init(struct quic_conn *qc,
const unsigned char *dcid, size_t dcidlen,
const unsigned char *scid, size_t scidlen,
const struct quic_cid *token_odcid);
void qc_srv_params_init(struct quic_conn *qc,
const struct quic_transport_params *srv_params,
const unsigned char *scid, size_t scidlen);
/* Dump <cid> transport parameter connection ID value if present (non null length).
* Used only for debugging purposes.

View File

@ -99,5 +99,6 @@ struct quic_rx_crypto_frm {
#define QUIC_EV_CONN_KP (1ULL << 50)
#define QUIC_EV_CONN_SSL_COMPAT (1ULL << 51)
#define QUIC_EV_CONN_BIND_TID (1ULL << 52)
#define QUIC_EV_CONN_RELEASE_RCD (1ULL << 53)
#endif /* _HAPROXY_QUIC_TRACE_T_H */

View File

@ -23,6 +23,7 @@
#include <haproxy/buf-t.h>
#include <haproxy/list-t.h>
#include <haproxy/pool.h>
#include <haproxy/quic_conn-t.h>
#include <haproxy/quic_tls-t.h>
#include <haproxy/quic_pacing-t.h>

View File

@ -8,6 +8,16 @@
#include <haproxy/buf-t.h>
#include <haproxy/chunk.h>
static inline int quic_stream_is_uni(uint64_t id)
{
return id & QCS_ID_DIR_BIT;
}
static inline int quic_stream_is_bidi(uint64_t id)
{
return !quic_stream_is_uni(id);
}
static inline void bdata_ctr_init(struct bdata_ctr *ctr)
{
ctr->tot = 0;

View File

@ -171,6 +171,7 @@ enum srv_init_state {
#define SRV_F_DEFSRV_USE_SSL 0x4000 /* default-server uses SSL */
#define SRV_F_DELETED 0x8000 /* srv is deleted but not yet purged */
#define SRV_F_STRICT_MAXCONN 0x10000 /* maxconn is to be strictly enforced, as a limit of outbound connections */
#define SRV_F_CHECKED 0x20000 /* set once server was postparsed */
/* configured server options for send-proxy (server->pp_opts) */
#define SRV_PP_V1 0x0001 /* proxy protocol version 1 */
@ -477,6 +478,9 @@ struct server {
char *alpn_str; /* ALPN protocol string */
int alpn_len; /* ALPN protocol string length */
} ssl_ctx;
#ifdef USE_QUIC
struct quic_transport_params quic_params; /* QUIC transport parameters */
#endif
struct resolv_srvrq *srvrq; /* Pointer representing the DNS SRV requeest, if any */
struct list srv_rec_item; /* to attach server to a srv record item */
struct list ip_rec_item; /* to attach server to a A or AAAA record item */

View File

@ -73,7 +73,7 @@ struct server *new_server(struct proxy *proxy);
void srv_take(struct server *srv);
struct server *srv_drop(struct server *srv);
void srv_free_params(struct server *srv);
int srv_init_per_thr(struct server *srv);
int srv_init(struct server *srv);
void srv_set_ssl(struct server *s, int use_ssl);
const char *srv_adm_st_chg_cause(enum srv_adm_st_chg_cause cause);
const char *srv_op_st_chg_cause(enum srv_op_st_chg_cause cause);
@ -181,15 +181,16 @@ const struct mux_ops *srv_get_ws_proto(struct server *srv);
/* increase the number of cumulated streams on the designated server */
static inline void srv_inc_sess_ctr(struct server *s)
{
_HA_ATOMIC_INC(&s->counters.cum_sess);
_HA_ATOMIC_INC(&s->counters.shared->tg[tgid - 1]->cum_sess);
update_freq_ctr(&s->counters.shared->tg[tgid - 1]->sess_per_sec, 1);
HA_ATOMIC_UPDATE_MAX(&s->counters.sps_max,
update_freq_ctr(&s->counters.sess_per_sec, 1));
update_freq_ctr(&s->counters._sess_per_sec, 1));
}
/* set the time of last session on the designated server */
static inline void srv_set_sess_last(struct server *s)
{
s->counters.last_sess = ns_to_sec(now_ns);
HA_ATOMIC_STORE(&s->counters.shared->tg[tgid - 1]->last_sess, ns_to_sec(now_ns));
}
/* returns the current server throttle rate between 0 and 100% */
@ -319,6 +320,39 @@ static inline int srv_is_transparent(const struct server *srv)
(srv->flags & SRV_F_MAPPORTS);
}
/* Detach server from proxy list. It is supported to call this
* even if the server is not yet in the list
* Must be called under thread isolation or when it is safe to assume
* that the parent proxy doesn't is not skimming through the server list
*/
static inline void srv_detach(struct server *srv)
{
struct proxy *px = srv->proxy;
if (px->srv == srv)
px->srv = srv->next;
else {
struct server *prev;
for (prev = px->srv; prev && prev->next != srv; prev = prev->next)
;
BUG_ON(!prev);
prev->next = srv->next;
}
}
static inline int srv_is_quic(const struct server *srv)
{
#ifdef USE_QUIC
return srv->addr_type.proto_type == PROTO_TYPE_DGRAM &&
srv->addr_type.xprt_type == PROTO_TYPE_STREAM;
#else
return 0;
#endif
}
#endif /* _HAPROXY_SERVER_H */
/*

View File

@ -28,9 +28,11 @@
#include <haproxy/api.h>
#include <haproxy/connection-t.h>
#include <haproxy/listener-t.h>
#include <haproxy/protocol-t.h>
#include <haproxy/sock-t.h>
int sock_create_server_socket(struct connection *conn, struct proxy *be, int *stream_err);
int sock_create_server_socket(struct connection *conn, struct proxy *be,
enum proto_type proto_type, int sock_type, int *stream_err);
void sock_enable(struct receiver *rx);
void sock_disable(struct receiver *rx);
void sock_unbind(struct receiver *rx);

View File

@ -62,7 +62,7 @@ struct ckch_inst *ckch_inst_new();
int ckch_inst_new_load_store(const char *path, struct ckch_store *ckchs, struct bind_conf *bind_conf,
struct ssl_bind_conf *ssl_conf, char **sni_filter, int fcount, int is_default, struct ckch_inst **ckchi, char **err);
int ckch_inst_new_load_srv_store(const char *path, struct ckch_store *ckchs,
struct ckch_inst **ckchi, char **err);
struct ckch_inst **ckchi, char **err, int is_quic);
int ckch_inst_rebuild(struct ckch_store *ckch_store, struct ckch_inst *ckchi,
struct ckch_inst **new_inst, char **err);

View File

@ -342,6 +342,11 @@ enum stat_idx_info {
ST_I_INF_MAX
};
/* Flags for stat_col.flags */
#define STAT_COL_FL_NONE 0x00
#define STAT_COL_FL_GENERIC 0x01 /* stat is generic if set */
#define STAT_COL_FL_SHARED 0x02 /* stat may be shared between co-processes if set */
/* Represent an exposed statistic. */
struct stat_col {
const char *name; /* short name, used notably in CSV headers */
@ -350,8 +355,8 @@ struct stat_col {
uint32_t type; /* combination of field_nature and field_format */
uint8_t cap; /* mask of stats_domain_px_cap to restrain metrics to an object types subset */
uint8_t generic; /* bit set if generic */
/* 2 bytes hole */
/* 1 byte hole */
uint16_t flags; /* STAT_COL_FL_* flags */
/* used only for generic metrics */
struct {

View File

@ -79,7 +79,7 @@ int stats_emit_field_tags(struct buffer *out, const struct field *f,
/* Returns true if <col> is fully defined, false if only used as name-desc. */
static inline int stcol_is_generic(const struct stat_col *col)
{
return col->generic;
return col->flags & STAT_COL_FL_GENERIC;
}
static inline enum field_format stcol_format(const struct stat_col *col)

View File

@ -362,8 +362,8 @@ static inline void stream_choose_redispatch(struct stream *s)
s->scb->state = SC_ST_REQ;
} else {
if (objt_server(s->target))
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.retries);
_HA_ATOMIC_INC(&s->be->be_counters.retries);
_HA_ATOMIC_INC(&__objt_server(s->target)->counters.shared->tg[tgid - 1]->retries);
_HA_ATOMIC_INC(&s->be->be_counters.shared->tg[tgid - 1]->retries);
s->scb->state = SC_ST_ASS;
}

View File

@ -33,7 +33,7 @@
#ifdef CONFIG_PRODUCT_BRANCH
#define PRODUCT_BRANCH CONFIG_PRODUCT_BRANCH
#else
#define PRODUCT_BRANCH "3.2"
#define PRODUCT_BRANCH "3.3"
#endif
#ifdef CONFIG_PRODUCT_STATUS

View File

@ -14,7 +14,7 @@ See also: doc/regression-testing.txt
* vtest compilation *
$ git clone https://github.com/vtest/VTest
$ git clone https://github.com/vtest/VTest2
$ cd VTest

View File

@ -1,6 +1,5 @@
vtest "Test for balance URI"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.3
server s1 {
rxreq

View File

@ -2,8 +2,6 @@ varnishtest "Caching rules test"
# A response will not be cached unless it has an explicit age (Cache-Control max-age of s-maxage, Expires) or a validator (Last-Modified, or ETag)
# A response will not be cached either if it has an Age header that is either invalid (should be an integer) or greater than its max age.
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -1,7 +1,5 @@
varnishtest "Expires support"
#REQUIRE_VERSION=2.3
feature ignore_unknown_macro
server s1 {

View File

@ -1,7 +1,5 @@
varnishtest "If-Modified-Since support"
#REQUIRE_VERSION=2.3
feature ignore_unknown_macro
server s1 {

View File

@ -1,7 +1,5 @@
varnishtest "If-None-Match support"
#REQUIRE_VERSION=2.3
feature ignore_unknown_macro
server s1 {

View File

@ -1,7 +1,5 @@
varnishtest "A successful unsafe method (POST for instance) on a cached entry must disable it."
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -1,7 +1,5 @@
varnishtest "Vary support"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -1,7 +1,5 @@
varnishtest "Check the Accept-Encoding processing implemented in the Vary mechanism"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -6,7 +6,6 @@ feature ignore_unknown_macro
# The first health-checks passed tests are checked for all these servers
# thanks to syslog messages.
#REQUIRE_VERSION=2.4
#EXCLUDE_TARGETS=freebsd
#REGTEST_TYPE=slow

View File

@ -1,7 +1,6 @@
varnishtest "Health-checks"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
#EXCLUDE_TARGETS=freebsd,osx,generic
#REGTEST_TYPE=slow

View File

@ -1,7 +1,6 @@
varnishtest "Health-check test"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
#EXCLUDE_TARGETS=freebsd
#REGTEST_TYPE=slow

View File

@ -1,6 +1,5 @@
varnishtest "Health-checks: http-check send test"
#REGTEST_TYPE=slow
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
# This script tests HTTP health-checks and more particularly the "http-check

View File

@ -5,8 +5,6 @@ feature cmd "$HAPROXY_PROGRAM -cc 'feature(TPROXY)'"
# as private and should only be reused for requests of the same session.
# This is similar to the http-reuse never mode
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
haproxy h1 -conf {

View File

@ -1,5 +1,4 @@
varnishtest "Test the http-reuse with special connection parameters"
#REQUIRE_VERSION=2.4
#REQUIRE_OPTIONS=OPENSSL
feature ignore_unknown_macro

View File

@ -4,8 +4,6 @@ varnishtest "Test the proper interaction between http-reuse and dispatch mode"
# reused for requests of the same session
# This is similar to the http-reuse never mode
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
haproxy h1 -conf {

View File

@ -1,7 +1,5 @@
varnishtest "Check that the TLVs are properly validated"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
# We need one HAProxy for each test, because apparently the connection by

View File

@ -1,7 +1,5 @@
varnishtest "Test connection upgrades from TCP to HTTP"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -1,5 +1,4 @@
varnishtest "fix converters Test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro

View File

@ -1,5 +1,4 @@
varnishtest "iif converter Test"
#REQUIRE_VERSION=2.3
feature ignore_unknown_macro

View File

@ -1,5 +1,4 @@
varnishtest "JSON Query converters Test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro

View File

@ -1,5 +1,4 @@
varnishtest "mqtt converters Test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
@ -235,4 +234,4 @@ client c3_31_1 -connect ${h1_fe1_sock} {
# Valid MQTT 3.1 CONNECT packet (id: test_sub - username: test - passwd: passwd)
sendhex "102400064d514973647003c200000008746573745f7375620004746573740006706173737764"
recv 4
} -run
} -run

View File

@ -1,7 +1,5 @@
varnishtest "url_enc converter test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -1,6 +1,5 @@
varnishtest "Filtering test with several filters and random forwarding (via trace filter)"
#REQUIRE_VERSION=2.4
#REQUIRE_OPTION=ZLIB|SLZ
#REGTEST_TYPE=slow

View File

@ -2,7 +2,7 @@ varnishtest "HTTP request tests: H1 request target parsing"
feature ignore_unknown_macro
#REQUIRE_VERSION=3.0
feature cmd "$HAPROXY_PROGRAM -cc 'version_atleast(3.0-dev0)'"
haproxy h1 -conf {
global

View File

@ -1,8 +1,6 @@
varnishtest "A test to be sure payload is skipped for bodyless responses"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
server s1 {
rxreq
txresp \

View File

@ -5,8 +5,6 @@ feature cmd "$HAPROXY_PROGRAM $HAPROXY_ARGS -cc 'enabled(FAST-FORWARD)'"
feature cmd "$HAPROXY_PROGRAM $HAPROXY_ARGS -cc 'enabled(SPLICE)'"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
server s1 {
rxreq
txresp \

View File

@ -1,61 +0,0 @@
varnishtest "cannot add the HTX EOM block because the buffer is full"
feature ignore_unknown_macro
#REQUIRE_VERSION_BELOW=2.4
#REGTEST_TYPE=devel
# This test checks that an HTTP message is properly processed when we failed to
# add the HTX EOM block in an HTX message during the parsing because the buffer
# is full. Some space must be released in the buffer to make it possible. This
# requires an extra pass in the H1 multiplexer. Here, we must be sure the mux is
# called while there is no more incoming data.
server s1 {
rxreq
expect req.bodylen == 15200
txresp -bodylen 15220
} -start
syslog S -level info {
recv
expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"GET / HTTP/1\\.1\""
} -start
haproxy h1 -conf {
global
tune.bufsize 16384
tune.maxrewrite 1024
defaults
mode http
timeout client "${HAPROXY_TEST_TIMEOUT-5s}"
timeout server "${HAPROXY_TEST_TIMEOUT-5s}"
timeout connect "${HAPROXY_TEST_TIMEOUT-5s}"
backend be1
tcp-response inspect-delay 100ms
tcp-response content accept if { res.len gt 15272 }
tcp-response content reject
http-response deny if { internal.htx.has_eom -m bool } or { internal.htx.free_data gt 1024 }
server srv1 ${s1_addr}:${s1_port}
frontend fe1
option httplog
option http-buffer-request
log ${S_addr}:${S_port} local0 debug err
bind "fd@${fe1}"
http-request deny if ! { req.body_len eq 15200 } or { internal.htx.has_eom -m bool } or { internal.htx.free_data gt 1024 }
use_backend be1
} -start
haproxy h1 -cli {
send "trace h1 sink stderr; trace h1 level developer; trace h1 verbosity complete; trace h1 start now"
}
client c1 -connect ${h1_fe1_sock} {
txreq -bodylen 15200
rxresp
expect resp.status == 200
expect resp.bodylen == 15220
} -run

View File

@ -1,7 +1,6 @@
varnishtest "A test for the wait-for-body HTTP action"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
#REGTEST_TYPE=slow
server s1 {

View File

@ -8,8 +8,6 @@ varnishtest "h1/h2 support for protocol upgrade test"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
# http/1.1 server
server srv_h1 {
rxreq

View File

@ -12,8 +12,6 @@ varnishtest "WebSocket test"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
# valid websocket server
server s1 {
rxreq

View File

@ -1,5 +1,4 @@
varnishtest "Test IPv4/IPv6 except param for the forwardfor and originalto options"
#REQUIRE_VERSION=2.4
# This config tests the except parameter for the HTTP forwardfor and originalto
# options.

View File

@ -1,5 +1,4 @@
varnishtest "normalize-uri tests"
#REQUIRE_VERSION=2.4
# This reg-test tests the http-request normalize-uri action.

View File

@ -2,8 +2,6 @@ varnishtest "http-request set-timeout test"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
server srv_h1 -repeat 9 {
rxreq
txresp

View File

@ -1,8 +1,6 @@
varnishtest "Verify logging of relative/absolute URI path"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
server s1 {
rxreq
txresp -hdr "Connection: close"

View File

@ -49,6 +49,7 @@ client c1 -connect ${h1_frt_sock} -repeat 100 {
syslog Slog -wait
shell {
set +e
ss -pt | grep CLOSE-WAIT.*haproxy.*pid=${h1_pid}
exit $((!$?))
}

View File

@ -1,6 +1,5 @@
varnishtest "Lua: txn:get_priv() scope"
#REQUIRE_OPTIONS=LUA,OPENSSL
#REQUIRE_VERSION=2.4
#REGTEST_TYPE=bug
feature ignore_unknown_macro

View File

@ -355,8 +355,8 @@ client c9 -connect ${h1_mainfe_sock} {
} -run
client c10 -connect ${h1_mainfe_sock} {
txreq -url "/converter" -hdr "X-Cust: foobar"
txreq -url "/converter" -hdr "User-Agent: c10" -hdr "X-Cust: foobar"
rxresp
expect resp.status == 200
expect resp.http.x-var == "proc.req_len=35 sess.x_cust=foobar"
expect resp.http.x-var == "proc.req_len=52 sess.x_cust=foobar"
} -run

View File

@ -1,7 +1,5 @@
varnishtest "Hash validity test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
server s1 {

View File

@ -1,7 +1,5 @@
varnishtest "ub64dec sample fetche Test"
#REQUIRE_VERSION=2.4
feature ignore_unknown_macro
haproxy h1 -conf {

View File

@ -2,8 +2,6 @@ varnishtest "Add server via cli"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
server s1 {
rxreq
txresp

View File

@ -5,8 +5,6 @@ varnishtest "Delete server via cli"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
# static server
server s1 -repeat 3 {
rxreq

View File

@ -3,7 +3,6 @@ varnishtest "Set server ssl via CLI"
feature ignore_unknown_macro
# for "set server <srv> ssl"
#REQUIRE_VERSION=2.4
#REGTEST_TYPE=devel
#REQUIRE_OPTIONS=OPENSSL

View File

@ -26,6 +26,7 @@ haproxy h1 -conf {
tune.ssl.capture-buffer-size 1
crt-base ${testdir}
stats socket "${tmpdir}/h1/stats" level admin
ssl-default-bind-options strict-sni
defaults
mode http
@ -47,13 +48,14 @@ haproxy h1 -conf {
server s3 "${tmpdir}/first-ssl.sock" ssl verify none sni str(record2.bug940.domain.tld)
listen first-ssl-fe
# note: strict-sni is enforced from ssl-default-bind-options above
mode http
bind "${tmpdir}/first-ssl.sock" ssl strict-sni crt-list ${testdir}/simple.crt-list
bind "${tmpdir}/first-ssl.sock" ssl crt-list ${testdir}/simple.crt-list
server s1 ${s1_addr}:${s1_port}
listen second-ssl-fe
mode http
bind "${tmpdir}/second-ssl.sock" ssl crt-list ${testdir}/localhost.crt-list
bind "${tmpdir}/second-ssl.sock" ssl no-strict-sni crt-list ${testdir}/localhost.crt-list
server s1 ${s1_addr}:${s1_port}
} -start

View File

@ -6,7 +6,6 @@ varnishtest "Delete server via cli and update certificates"
feature ignore_unknown_macro
#REQUIRE_VERSION=2.4
#REQUIRE_OPTIONS=OPENSSL
feature cmd "command -v socat"

View File

@ -47,6 +47,7 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 1"
@ -77,6 +78,7 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 2"
@ -107,6 +109,7 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 3"
@ -138,6 +141,7 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 4"
@ -169,6 +173,7 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 5"
@ -200,6 +205,7 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 6"
@ -232,6 +238,7 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 7"
@ -263,6 +270,7 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 8"
@ -295,6 +303,7 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 9"
@ -327,6 +336,7 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 10"
@ -359,6 +369,7 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 11"
@ -391,6 +402,7 @@ listen ssl-lst
server s1 127.0.0.1:80
EOF
set +e
haproxy_output="$($HAPROXY_PROGRAM -f ${tmpdir}/ocsp_compat_check.cfg -c 2>&1)"
haproxy_ret=$?
echo "==== test 12"

View File

@ -15,7 +15,6 @@
# This should be backported to 1.8
#REGTEST_TYPE=bug
#REQUIRE_VERSION=2.4
varnishtest "stick-tables: Test expirations when used with table_*"

View File

@ -6,8 +6,6 @@ feature ignore_unknown_macro
# do the job they are supposed to do.
# If we remove one of the "stick on" rule, this script fails.
#REQUIRE_VERSION=2.4
server s_not_used_1 {}
server s_not_used_2 {}
server s_not_used_3 {}

View File

@ -2,7 +2,7 @@
set -eux
curl -fsSL https://github.com/wlallemand/VTest/archive/refs/heads/haproxy-sd_notify.tar.gz -o VTest.tar.gz
curl -fsSL https://github.com/vtest/VTest2/archive/main.tar.gz -o VTest.tar.gz
mkdir ../vtest
tar xvf VTest.tar.gz -C ../vtest --strip-components=1
# Special flags due to: https://github.com/vtest/VTest/issues/12
@ -24,7 +24,7 @@ set -e
# temporarily detect Apple Silicon (it's using /opt/homebrew instead of /usr/local)
#
if test -f /opt/homebrew/include/pcre2.h; then
make -j${CPUS} FLAGS="-O2 -s -Wall" INCS="-Isrc -Ilib -I/usr/local/include -I/opt/homebrew/include -pthread"
make -j${CPUS} FLAGS="-O2 -s -Wall" INCS="-I. -Isrc -Ilib -I/usr/local/include -I/opt/homebrew/include -pthread"
else
make -j${CPUS} FLAGS="-O2 -s -Wall"
fi

View File

@ -52,10 +52,6 @@ _help()
#REQUIRE_SERVICE=prometheus-exporter
#REQUIRE_SERVICES=prometheus-exporter,foo
# To define a range of versions that a test can run with:
#REQUIRE_VERSION=0.0
#REQUIRE_VERSION_BELOW=99.9
Configure environment variables to set the haproxy and vtest binaries to use
setenv HAPROXY_PROGRAM /usr/local/sbin/haproxy
setenv VTEST_PROGRAM /usr/local/bin/vtest
@ -124,15 +120,13 @@ _findtests() {
set -- $(grep '^#[0-9A-Z_]*=' "$i")
IFS="$OLDIFS"
require_version=""; require_version_below=""; require_options="";
require_options="";
require_services=""; exclude_targets=""; regtest_type=""
requiredoption=""; requiredservice=""; excludedtarget="";
while [ $# -gt 0 ]; do
v="$1"; v="${v#*=}"
case "$1" in
"#REQUIRE_VERSION="*) require_version="$v" ;;
"#REQUIRE_VERSION_BELOW="*) require_version_below="$v" ;;
"#REQUIRE_OPTIONS="*) require_options="$v" ;;
"#REQUIRE_SERVICES="*) require_services="$v" ;;
"#EXCLUDE_TARGETS="*) exclude_targets="$v" ;;
@ -171,21 +165,6 @@ _findtests() {
IFS=","; set -- $require_services; IFS=$OLDIFS; require_services="$*"
IFS=","; set -- $exclude_targets; IFS=$OLDIFS; exclude_targets="$*"
if [ -n "$require_version" ]; then
if [ $(_version "$HAPROXY_VERSION") -lt $(_version "$require_version") ]; then
echo " Skip $i because option haproxy is version: $HAPROXY_VERSION"
echo " REASON: this test requires at least version: $require_version"
skiptest=1
fi
fi
if [ -n "$require_version_below" ]; then
if [ $(_version "$HAPROXY_VERSION") -ge $(_version "$require_version_below") ]; then
echo " Skip $i because option haproxy is version: $HAPROXY_VERSION"
echo " REASON: this test requires a version below: $require_version_below"
skiptest=1
fi
fi
for excludedtarget in $exclude_targets; do
if [ "$excludedtarget" = "$TARGET" ]; then
echo " Skip $i because haproxy is compiled for the excluded target $TARGET"

Some files were not shown because too many files have changed in this diff Show More