Commit Graph

13949 Commits

Author SHA1 Message Date
Willy Tarreau
4596fe20d9 CLEANUP: conn_stream: tree-wide rename to stconn (stream connector)
This renames the "struct conn_stream" to "struct stconn" and updates
the descriptions in all comments (and the rare help descriptions) to
"stream connector" or "connector". This touches a lot of files but
the change is minimal. The local variables were not even renamed, so
there's still a lot of "cs" everywhere.
2022-05-27 19:33:34 +02:00
Willy Tarreau
3a3f480d15 CLEANUP: conn_stream: rename cs_app_* to sc_app_*
Let's start to introduce the stream connector at the app_ops level.
This is entirely self-contained into conn_stream.c. The functions
were also updated to reflect the new name, and the comments were
updated.
2022-05-27 19:33:34 +02:00
Willy Tarreau
798465b02c CLEANUP: conn_stream: rename the conn_stream's endp to sedesc
Just like for the appctx, this is a pointer to a stream endpoint descriptor,
so let's make this explicit and not confuse it with the full endpoint. There
are very few changes thanks to the preliminary refactoring of the flags
manipulation.
2022-05-27 19:33:34 +02:00
Willy Tarreau
d869e13ed8 CLEANUP: applet: rename the sedesc pointer from "endp" to "sedesc"
Now at least it makes it obvious that it's the stream endpoint descriptor
and not an endpoint. There were few changes thanks to the previous refactor
of the flags.
2022-05-27 19:33:34 +02:00
Willy Tarreau
ea59b0201c CLEANUP: conn_stream: rename cs_endpoint to sedesc (stream endpoint descriptor)
After some discussion we found that the cs_endpoint was precisely the
descriptor for a stream endpoint, hence the naturally coming name,
stream endpoint constructor.

This patch renames only the type everywhere and the new/init/free functions
to remain consistent with it. Future patches will address field names and
argument names in various code areas.
2022-05-27 19:33:34 +02:00
Willy Tarreau
65d0597b2b CLEANUP: conn_stream: rename the cs_endpoint's target to "se"
That's the "stream endpoint" pointer. Let's change it now while it's
not much spread. The function __cs_endp_target() wasn't yet renamed
because that will change more globally soon.
2022-05-27 19:33:34 +02:00
Willy Tarreau
b605c4213f CLEANUP: conn_stream: rename the stream endpoint flags CS_EP_* to SE_FL_*
Let's now use the new flag names for the stream endpoint.
2022-05-27 19:33:34 +02:00
Willy Tarreau
d56377c5eb CLEANUP: conn_stream: apply endp_flags.cocci tree-wide
This changes all main uses of endp->flags to the se_fl_*() equivalent
by applying coccinelle script endp_flags.cocci. The se_fl_*() functions
themselves were manually excluded from the change, of course.

Note: 144 locations were touched, manually reviewed and found to be OK.

The script was applied with all includes:

  spatch --in-place --recursive-includes -I include --sp-file $script $files
2022-05-27 19:33:34 +02:00
Willy Tarreau
0cfcc40812 CLEANUP: conn_stream: apply cs_endp_flags.cocci tree-wide
This changes all main uses of cs->endp->flags to the sc_ep_*() equivalent
by applying coccinelle script cs_endp_flags.cocci.

Note: 143 locations were touched, manually reviewed and found to be OK,
except a single one that was adjusted in cs_reset_endp() where the flags
are read and filtered to be used as-is and not as a boolean, hence was
replaced with sc_ep_get() & $FLAGS.

The script was applied with all includes:

  spatch --in-place --recursive-includes -I include --sp-file $script $files
2022-05-27 19:33:34 +02:00
Willy Tarreau
24d15b1891 CLEANUP: conn_stream: rename the cs_endpoint's context to "conn"
This one is exclusively used by the connection, regardless its generic
name "ctx" is rather confusing. Let's make it a struct connection* and
call it "conn". This way there's no doubt about what it is and there's
no way it will be used by accident by being taken for something else.
2022-05-27 19:33:34 +02:00
Willy Tarreau
5fec7a1f98 CLEANUP: conn_stream: remove unneeded exclusion of RX_WAIT_EP from RXBLK_ANY
This test in cs_update_rx() was introduced in 1.9 by commit b26a6f970
("MEDIUM: stream-int: make use of si_rx_chan_{rdy,blk} to control the
stream-int from the channel"), but by then already it was not needed
because the RX_WAIT_EP flag has never been part of RXBLK_ANY so there's
no point doing "flags & RXBLK_ANY & ~RX_WAIT_EP", that part is already
complicated enough like this.
2022-05-27 19:33:34 +02:00
Thayne McCombs
6a0d217628 BUG/MEDIUM: sample: Fix adjusting size in word converter
Adjust the size of the sample buffer before we change the "area"
pointer. Otherwise, we end up not changing the size, because the area
pointer is already the same as "start" before we compute the difference
between the two.

This is similar to the change in b28430591d
but for the word converter instead of field.
2022-05-27 19:33:34 +02:00
William Lallemand
d8c195a326 BUG/MINOR: ssl/lua: use correctly cert_ext in CertCache.set()
Fix a typo that lead to using the wrong pointer when loading a
certificate, which lead to always using the pem loader for every
parameeter.

Use the cert_ext->load() ptr instead of cert_exts->load() which was the
first element of the cert_exts[] array.

Enhance the error message with the field name.

Should fix issue #1716
2022-05-26 19:36:07 +02:00
Willy Tarreau
8e5b9589b3 CLEANUP: init: address another coverity warning about a possible multiply overflow
Commit 2cb3be76b ("CLEANUP: init: address a coverity warning about
possible multiply overflow") was incomplete, two other locations were
present. This should address issue #1585.
2022-05-26 08:55:05 +02:00
Amaury Denoyelle
8c6176b8db MINOR: h3: refactor SETTINGS parsing/error reporting
Bring some improvment to h3_parse_settings_frm() function. The first one
is the parsing which now manipulates a buffer instead of a plain char*.
This is more to unify with other parsing functions rather than dealing
with data wrapping : it's unlikely to happen as SETTINGS is only
received as the first frame on the control STREAM.

Various errors are now properly reported as connection error :
* on incomplete frame payload
* on a duplicated settings in the same frame
* on reserved settings receive
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
849b24f15b MINOR: h3: abort read on unknown uni stream
As specified by HTTP/3 draft, an unknown unidirectional stream can be
aborted. To do this, use a new flag QC_SF_READ_ABORTED. When the MUX
detects this flag, QCS instance is automatically freed.

Previously, such streams were instead automatically drained. By aborting
them, we economize some useless memcpy instruction. On future data
reception, QCS instance is not found in the tree and considered as
already closed. The frame payload is thus deleted without copying it.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
9cc475182c CLEANUP: h3: remove h3 uni tasklet
Remove all unnecessary bits of code for H3 unidirectional streams. Most
notable, an individual tasklet is not require anymore for each stream.
This is useless since the merge of RX/TX uni streams handling with
bidirectional streams code.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
f8db5aaf78 MEDIUM: quic: refactor uni streams RX
The whole QUIC stack is impacted by this change :
* at quic-conn level, a single function is now used to handle uni and
  bidirectional streams. It uses qcc_recv() function from MUX.
* at MUX level, qc_recv() io-handler function does not skip uni streams
* most changes are conducted at app layer. Most notably, all received
  data is handle by decode_qcs operation.

Now that decode_qcs is the single app read function, the H3 layer can be
simplified. Uni streams parsing was extracted from h3_attach_ruqs() to
h3_decode_qcs().

h3_decode_qcs() is able to deal with all HTTP/3 frame types. It first
check if the frame is valid for the H3 stream type. Most notably,
SETTINGS parsing was moved from h3_control_recv() into h3_decode_qcs().

This commit has some major benefits besides removing duplicated code.
Mainly, QUIC flow control is now enforced for uni streams as with bidi
streams. Also, an unknown frame received on control stream does not set
an error : it is now silently ignored as required by the specification.

Some cleaning in H3 code is already done with this patch :
h3_control_recv() and h3_attach_ruqs() are removed as they are now
unused. A final patch should clean up the unneeded remaining bit.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
fc99a6933e MINOR: h3: define non-h3 generic parsing function
Define a new function h3_parse_uni_stream_no_h3(). It can be used to
handle the payload of streams which does not convey H3 frames. This is
mainly useful for QPACK encoder/decoder streams. It can also be used for
a stream of unknown type which should be drain without parsing it.

This patch is useful to extract code in a dedicated function. It will be
simple to reuse it in h3_decode_qcs() when uni-streams reception is
unify with bidirectional streams, without using dedicated stream tasklet.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
302ecd490b MINOR: h3: check if frame is valid for stream type
Define a new function h3_is_frame_valid(). It returns if a frame is
valid or not depending on the stream which received it.

For the moment, it is used in h3_decode_qcs() which only deals with
bidirectional streams. Soon, uni streams will use the same function,
rendering the frame type check useful.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
3555064e87 MINOR: h3: refactor uni streams initialization
Define a new function h3_init_uni_stream(). This can be used to read the
stream type of an unidirectional stream. There is no functional change
with previous code.

This patch will be useful to unify reception for uni streams with
bidirectional ones.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
3236a8e85c MINOR: h3: define stream type
Define a new enum h3s_t. This is used to differentiate between the
different stream types used in a HTTP/3 connection, including the QPACK
encoder/decoder streams.

For the moment, only bidirectional streams is positioned. This patch
will be useful to unify reception of uni streams with bidirectional
ones.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
6b92394973 MINOR: h3/qpack: use qcs as type in decode callbacks
Replace h3_uqs type by qcs in stream callbacks. This change is done in
the context of unification between bidi and uni-streams. h3_uqs type
will be unneeded when this is achieved.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
c6195d77b4 BUG/MINOR: mux-quic: refactor uni streams TX/send H3 SETTINGS
Remove the unneeded skip over unidirectional streams in qc_send(). This
unify sending for both uni and bidi streams.

In fact, the only local unidirectional streams in use for the moment is
the H3 Control stream responsible of SETTINGS emission. The frame was
already properly generated in qcs.tx.buf, but not send due to stream
skip in qc_send(). Now, there is no need to ignore uni streams so remove
this condition.

This fixes the emission of H3 settings which is now properly emitted.

Uni and bidi streams use the same set of funtcions for sending. One of
the most notable gain is that flow-control is now enforced for uni
streams.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
6754d7e2ed MINOR: mux-quic: emit STREAM_STATE_ERROR in qcc_recv
Emit STREAM_STATE_ERROR connection error in two cases :
* if receiving data for send-only stream
* if receiving data on a locally initiated stream not open yet

For the moment the first case cannot be encoutered as uni streams
reception does not use qcc_recv(). However, this will be soon
implemented with the unification between bidi and uni streams.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
80097cc824 MINOR: h3: reject too big frames
The whole frame payload must have been received to demux a H3 frames,
except for H3 DATA which can be fragmented into multiple HTX blocks.

If the frame is bigger than the buffer and is not a DATA frame, a
connection error is reported with error H3_EXCESSIVE_LOAD.

This should be completed in the future with the H3 settings to limit the
size of uncompressed header section.

This code is more generic : it can handle every H3 frames. This is done
in order to be able to use h3_decode_qcs() to demux both uni and bidir
streams.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
5c4373a47b MINOR: mux-quic: disable read on CONNECTION_CLOSE emission
Similar to sending, read operations are disabled when a CONNECTION_CLOSE
frame has been emitted.

Most notably, this prevents unneeded loop demuxing when the H3 layer has
issue an error and cannot process the buffer payload anymore.

Note that read is not prevented for unidirectional streams for the
moment. This will supported soon with the unification of bidir and uni
streams treatment.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
f9e190e49a MINOR: quic: support CONNECTION_CLOSE_APP emission
Complete quic-conn API for error reporting. A new parameter <app> is
defined in the function quic_set_connection_close(). This will transform
the frame into a CONNECTION_CLOSE_APP type.

This type of frame will be generated by the applicative layer, h3 or
hq-interop for the moment. A new function qcc_emit_cc_app() is exported
by the MUX layer for them.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
65df3add33 MINOR: h3: refactor h3_control_send()
The only change is that the H3_CF_SETTINGS_SENT flag if-condition is
replaced by a BUG_ON statement. This may help to catch multiple calls on
h3_control_send() instead of silently ignore them.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
160507d0ba BUG/MINOR: h3: prevent overflow when parsing SETTINGS
h3_parse_settings_frm() read one byte after the frame payload. Fix the
parsing code. In most cases, this has no impact as we are inside an
allocated buffer but it could cause a segfault depending on the buffer
alignment.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
081479df92 CLEANUP: h3: rename uni stream type constants
Cosmetic fix which reduce the name of unidirectional stream constants.
No impact on the code.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
8d1ecac5d9 CLEANUP: h3: rename struct h3 -> h3c
struct h3 represents the whole HTTP/3 connection. A new type h3s was
recently introduced to represent a single HTTP/3 stream. To facilitate
the analogy with other haproxy code, most notable in MUX, rename h3 type
to h3c.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
0ffd6e7e64 MINOR: mux-quic: adjust return value of decode_qcs
Use 0 for success of decode_qcs operation else non-zero. This is to
follow the same model which is in use in most of the function in MUX/H3
code.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
e1cad8bc03 MINOR: mux-quic: add traces in qc_recv()
Just add traces in qc_recv() similarly to qc_send() function.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
1c25b18e17 MINOR: mux-quic: delay cs_endpoint allocation
Do not allocate cs_endpoint for every QCS instances in qcs_new().
Instead, this is delayed to qc_attach_cs() function.

In effect, with H3 as app protocol, cs_endpoint will be allocated on
HEADERS parsing. Thus, no cs_endpoint is allocated for H3 unidirectional
streams which do not convey any HTTP data.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
93fba32430 MINOR: mux-quic: do not alloc quic_stream_desc for uni remote stream
qc_stream_desc type is required for sending. Thus, it is not required
for an unidirectional remote stream where only receive will be
performed.
2022-05-25 15:41:25 +02:00
Amaury Denoyelle
c7dd9d6867 MINOR: h3: mark ncbuf as const on h3_b_dup
h3_b_dup() is used to obtains a ncbuf representation into a struct
buffer. ncbuf can thus be marked as a const parameter. This will allows
function which already manipulates a const ncbuf to use it.
2022-05-25 15:41:25 +02:00
Emeric Brun
ca82578fe8 BUG/MEDIUM: peers: prevent unitialized multiple listeners on peers section
The previous fix:
BUG/MEDIUM: peers: fix segfault using multiple bind on peers

Prevents to declare multiple listeners on a peers sections but if
peers protocol is extended to support this we could raise the bug
again.

Indeed, after allocating a new listener and adding it to a list the
code mistakenly re-configure the first element of the list instead
of the new added one, and the last one remains finally uninitialized.
The previous fix assure there is no more than one listener in this
list but this could be changed in futur.

This patch patch assures we configure and initialize the newly added
listener instead of the first one in the list.

This patch could be backported until version 2.0 to complete
BUG/MEDIUM: peers: fix segfault using multiple bind on peers
2022-05-25 15:10:08 +02:00
Emeric Brun
49f6f4b1a7 BUG/MEDIUM: peers: fix segfault using multiple bind on peers sections
If multiple "bind" lines were present on the "peers" section, multiple
listeners were added to a list but the code mistakenly initialize
the first member and this first listener was re-configured instead of
the newly created one. The last one remains uninitialized causing a null
dereference a soon a connection is received.

In addition, the 'peers' sections and protocol are not currently designed to
handle multiple listeners.

This patch check if there is already a listener configured on the 'peers'
section when we want to create a new one. This is rising an error if
a listener is already present showing the file and line in the error
message.

To keep the file and line number of the previous listener available
for the error message, the 'bind_conf_uniq_alloc' function was modified
to keep the file/line data the struct 'bind_conf' was firstly
allocated (previously it was updated each time the 'bind_conf' was
reused).

This patch should be backported until version 2.0
2022-05-25 15:10:08 +02:00
Christopher Faulet
4315d17d3f BUG/MEDIUM: resolvers: Don't defer resolutions release in deinit function
resolvers_deinit() function is called on error, during post-parsing stage,
or on deinit, when HAProxy is stopped. It releases all entities: resolvers,
resolutions and SRV requests. There is no reason to defer the resolutions
release by moving them in the death_row list because this function is
terminal. And it is in fact a bug. Resolutions must not be released at the
end of the function because resolvers were already freed. However some
resolutions may still be attached to a reolver. Thus, when we try to remove
it from the resolver's tree, in resolv_reset_resolution(), this resolver was
already released.

So now, resolution are immediately released. It means there is no more
reason to track this function. calls to
enter_resolver_code()/leave_resolver_code() have been removed.

This patch should fix the issue #1680 and may be related to #1485. It must
be backported as far as 2.2.
2022-05-24 18:11:59 +02:00
Willy Tarreau
1ba30167a0 MEDIUM: h1: enlarge the scope of accepted version chars with accept-invalid-http-request
We used to support both RTSP and HTTP protocol version names with and
without accept-invalid-http-request, but since this is based on the
characters themselves, any protocol made of chars {0-9/.HPRST} was
possible and not others. Now that such non-standard protocols are
restricted to accept-invalid-http-request, there's no reason for not
allowing other letters. With this patch, characters {0-9./A-Z} are
permitted when the option is set.
2022-05-24 15:38:54 +02:00
Tim Duesterhus
8f4116ea65 BUG/MEDIUM: http: Properly reject non-HTTP/1.x protocols
This patch hardens the verification of the HTTP/1.x version line
(i.e. the first line within an HTTP/1.x request) to verify that
the protocol name within the version actually reads "HTTP".

Previously protocols that superficially resembled the wire-format
of HTTP/1.x and having a 4-letter acronym as the protocol name, such
as RTSP would pass this check.

This patch fixes GitHub issue #540, it must be backported to all
supported versions. The legacy, non-HTX parser is affected as well,
a fix must be created for it as well.

Note that such protocols can still be used when option
accept-invalid-http-request is set.
2022-05-24 15:38:05 +02:00
Willy Tarreau
2cb3be76bf CLEANUP: init: address a coverity warning about possible multiply overflow
In issue #1585 Coverity suspects a risk of multiply overflow when
calculating the SSL cache size, though in practice the cache is
limited to 2^32 anyway thus it cannot really happen. Nevertheless,
casting the operation should be sufficient to avoid marking it as a
false positive.
2022-05-24 07:46:00 +02:00
Amaury Denoyelle
019a182ebf Revert "MINOR: mux-quic: activate qmux traces on stdout via macro"
This reverts commit 251eadfce5.

This patch is similar to the previous revert for QUIC-MUX traces.
2022-05-23 11:06:42 +02:00
Amaury Denoyelle
2208d57ce7 Revert "MINOR: quic: activate QUIC traces at compilation"
This reverts commit 118b2cbf84.

This patch was useful mainly for the docker image of QUIC interop to
have traces on stdout.

A better solution has been found by integrating this patch directly in
the qns repository which is used to build the docker image. Thus, this
hack is not require anymore in the main repository.
2022-05-23 11:06:42 +02:00
Amaury Denoyelle
d0c62328af BUG/MEDIUM: mux-quic: adjust buggy proxy closing support
The wake handler detects if the frontend is closed. This can happen if
the proxy has been disabled individually or even on process soft-stop.
Before this patch, in this condition QCS instances were freed before
being detached from the cs_endpoint. This clearly violates the haproxy
connection architecture and cause a BUG_ON statement crash in cs_free().

To handle this properly, cs_endpoint is notified by setting RD_SH|WR_SH
on connection flags. The cs_endpoint will thus use the detach operation
which allows the QCS instance to be freed.

This code allows the soft-stop process to complete as soon as possible.
However, the client is not notified about the connection closing. It
should be done by emitting a H3 GOAWAY + CONNECTION_CLOSE. Sadly, this
is impossible at this stage because the listener sockets are closed so
the quic-conn cannot use it to emit new frames. At this stage the client
will most probably detect connection closing on its idle timeout
expiration.

Thus, to completely support proxy closing/soft-stop, important
architecture changes are required in QUIC socket management. This is
also linked with the reload feature.
2022-05-23 11:05:52 +02:00
Tim Duesterhus
22535a56a7 CLEANUP: tools: Crash if inet_ntop fails due to ENOSPC in sa2str
This is impossible, because we pass a destination buffer that is appropriately
sized to hold an IPv6 address.

This is related to GitHub issue #1599.
2022-05-23 09:39:32 +02:00
Tim Duesterhus
162f0875ad BUG/MEDIUM: tools: Fix inet_ntop usage in sa2str
The given size must be the size of the destination buffer, not the size of the
(binary) address representation.

This fixes GitHub issue #1599.

The bug was introduced in 92149f9a82 which is in
2.4+. The fix must be backported there.
2022-05-23 08:45:31 +02:00
Tim Duesterhus
147eeb2ef3 CLEANUP: tools: Clean up non-QUIC error message handling in str2sa_range()
If QUIC support is enabled both branches of the ternary conditional are
identical, upsetting Coverity. Move the full conditional into the non-QUIC
preprocessor branch to make the code more clear.

This resolves GitHub issue #1710.
2022-05-23 08:45:31 +02:00
Frédéric Lécaille
07968dcea3 BUG/MINOR: quic: Missing <conn_opening> stats counter decrementation
When we receive a CONNECTION_CLOSE frame, we should decrement this counter
if the handshake state was not successful and if we have not received
a TLS alert from the TLS stack.
2022-05-20 20:57:31 +02:00
Frédéric Lécaille
ad9895d133 BUG/MINOR: quic: Fixe a typo in qc_idle_timer_task()
The & operator was confused with | operator :-(
2022-05-20 20:57:31 +02:00
Willy Tarreau
287f32fd01 MINOR: listener: automatically enable SSL if a QUIC transport is found
When a bind line is configured without the "ssl" keyword, a warning is
emitted and a crash happens at runtime:

   bind quic4@:4449 crt rsa+dh2048.pem alpn h3 allow-0rtt

   [WARNING]  (17867) : config : Proxy 'decrypt': A certificate was specified but SSL was not enabled on bind 'quic4@:4449' at [quic-mini.cfg:24] (use 'ssl').

Let's automatically turn SSL on when QUIC is detected, as it doesn't
exist without SSL anyway. It solves the runtime issue, and also makes
sure it is not possible to accidentally configure a quic listener with
no certificate since the error is detected via the SSL checks.

A warning is emitted in this case, to encourage the user to fix the
configuration so that it remains reviewable.
2022-05-20 18:41:55 +02:00
Willy Tarreau
730cc02c26 MINOR: listener: automatically select a QUIC mux with a QUIC transport
When no mux protocol is configured on a bind line with "proto", and the
transport layer is QUIC, right now mux_h1 is being used, leading to a
crash.

Now when the transport layer of the bind line is already known as being
QUIC, let's automatically try to configure the QUIC mux, so that users
do not have to enter "proto quic" all the time while it's the only
supported option. this means that the following line now works:

    bind quic4@:4449 ssl crt rsa+dh2048.pem alpn h3 allow-0rtt
2022-05-20 18:41:55 +02:00
Willy Tarreau
cac619b4d2 MINOR: config: detect and report mux and transport incompatibilities
Till now, placing "proto h1" or "proto h2" on a "quic" bind or placing
"proto quic" on a TCP line would parse fine but would crash when traffic
arrived. The reason is that there's a strong binding between the QUIC
mux and QUIC transport and that they're not expected to be called with
other types at all.

Now that we have the mux's type and we know the type of the protocol used
on the bind conf, we can perform such checks. This now returns:

  [ALERT]    (16978) : config : frontend 'decrypt' : stream-based MUX protocol 'h2' is incompatible with framed transport of 'bind quic4@:4448' at [quic-mini.cfg:27].
  [ALERT]    (16978) : config : frontend 'decrypt' : frame-based MUX protocol 'quic' is incompatible with stream transport of 'bind :4448' at [quic-mini.cfg:29].

This config tightening is only tagged MINOR since while such a config,
despite not reporting error, cannot work at all so even if it breaks
experimental configs, they were just waiting for a single connection
to crash.
2022-05-20 18:41:55 +02:00
Willy Tarreau
b5821e12ce MINOR: connection: add flag MX_FL_FRAMED to mark muxes relying on framed xprt
In order to be able to check compatibility between muxes and transport
layers, we'll need a new flag to tag muxes that work on framed transport
layers like QUIC. Only QUIC has this flag now.
2022-05-20 18:41:55 +02:00
Willy Tarreau
2071a99dfe MINOR: listener/ssl: set the SSL xprt layer only once the whole config is known
We used to preset XPRT_SSL on bind_conf->xprt when parsing the "ssl"
keyword, which required to be careful about what QUIC could have set
before, and which makes it impossible to consider the whole line to
set all options.

Now that we have the BC_O_USE_SSL option on the bind_conf, it becomes
easier to set XPRT_SSL only once the bind_conf's args are parsed.
2022-05-20 18:41:55 +02:00
Willy Tarreau
78d0dcd519 MINOR: listener: set the QUIC xprt layer immediately after parsing the args
It used to be set when parsing the listeners' addresses but this comes
with some difficulties in that other places have to be careful not to
replace it (e.g. the "ssl" keyword parser).

Now we know what protocols a bind_conf line relies on, we can set it
after having parsed the whole line.
2022-05-20 18:41:55 +02:00
Willy Tarreau
64306ccd97 MINOR: listener: detect stream vs dgram conflict during parsing
Now that we have a function to parse all bind keywords, and that we
know what types of sock-level and xprt-level protocols a bind_conf
is using, it's easier to centralize the check for stream vs dgram
conflict by putting it directly at the end of the args parser. This
way it also works for peers, provides better precision in the report,
and will also allow to validate transport layers. The check was even
extended to detect inconsistencies between xprt layer (which were not
covered before). It can even detect that there are two incompatible
"bind" lines in a single peers section.
2022-05-20 18:41:55 +02:00
Willy Tarreau
91b780a455 CLEANUP: listener: store stream vs dgram at the bind_conf level
Let's collect the set of xprt-level and sock-level dgram/stream protocols
seen on a bind line and store that in the bind_conf itself while they're
being parsed. This will make it much easier to detect incompatibilities
later than the current approch which consists in scanning all listeners
in post-parsing.
2022-05-20 18:41:55 +02:00
Willy Tarreau
787e92a4fb CLEANUP: listener: replace bind_conf->quic_force_retry with BC_O_QUIC_FORCE_RETRY
It was only set and used once, let's replace it now and take it out of
the ifdef.
2022-05-20 18:41:51 +02:00
Willy Tarreau
1ea6e6a17f CLEANUP: listener: replace bind_conf->generate_cers with BC_O_GENERATE_CERTS
The new flag will now replace this boolean variable.
2022-05-20 18:39:43 +02:00
Willy Tarreau
11ba404c6b CLEANUP: listener: replace all uses of bind_conf->is_ssl with BC_O_USE_SSL
The new flag will now replace this boolean variable that was only set and
tested.
2022-05-20 18:39:43 +02:00
Willy Tarreau
55f0f7bb54 MINOR: config: use the new bind_parse_args_list() to parse a "bind" line
This now makes sure that both the peers' "bind" line and the regular one
will use the exact same parser with the exact same behavior. Note that
the parser applies after the address and that it could be factored
further, since the peers one still does quite a bit of duplicated work.
2022-05-20 18:39:43 +02:00
Willy Tarreau
3882d2a96c MINOR: listener: provide a function to process all of a bind_conf's arguments
The "bind" parsing code was duplicated for the peers section and as a
result it wasn't kept updated, resulting in slightly different error
behavior (e.g. errors were not freed, warnings were emitted as alerts)
Let's first unify it into a new dedicated function that properly reports
and frees the error.
2022-05-20 18:39:43 +02:00
Willy Tarreau
91b47263f7 MINOR: protocol: replace ctrl_type with xprt_type and clarify it
There's been some great confusion between proto_type, ctrl_type and
sock_type. It turns out that ctrl_type was improperly chosen because
it's not the control layer that is of this or that type, but the
transport layer, and it turns out that the transport layer doesn't
(normally) denaturate the underlying control layer, except for QUIC
which turns dgrams to streams. The fact that the SOCK_{DGRAM|STREAM}
set of values was used added to the confusion.

Let's replace it with xprt_type which reuses the later introduced
PROTO_TYPE_* values, and update the comments to explain which one
works at what level.
2022-05-20 18:39:43 +02:00
Willy Tarreau
3d7b4684fe CLEANUP: config: provide cleare hints about unsupported QUIC addresses
We now detect that QUIC was likely requested, and if it's not compiled
it, we clearly mention it.
2022-05-20 18:39:43 +02:00
Willy Tarreau
2b049b8166 CLEANUP: config: improve address parser error report for unmatched protocols
Just trying "quic4@:4433" with USE_QUIC not set rsults in such a cryptic
error:

   [ALERT]    (14610) : config : parsing [quic-mini.cfg:44] : 'bind' : unsupported protocol family 2 for address 'quic4@:4433'

Let's at least add the stream and datagram statuses to indicate what was
being looked for:

   [ALERT]    (15252) : config : parsing [quic-mini.cfg:44] : 'bind' : unsupported stream protocol for datagram family 2 address 'quic4@:4433'

Still not very pretty but gives a little bit more info.
2022-05-20 18:39:43 +02:00
Willy Tarreau
0d04410ebe BUG/MINOR: peers: fix error reporting of "bind" lines
In case the str2listener() parser reports a generic error with no message
when parsing the argument of a "bind" statement in a "peers" section, the
reported error indicates an invalid address on the empty arg. This has
existed since 2.0 with commit 355b2033e ("MINOR: cfgparse: SSL/TLS binding
in "peers" sections."), so this must be backported till 2.0.
2022-05-20 18:39:43 +02:00
Amaury Denoyelle
cc3d7166f4 MINOR: mux-quic: close connection on error if different data at offset
As specified by the RFC reception of different STREAM data for the same
offset should be treated with a CONNECTION_CLOSE with error
PROTOCOL_VIOLATION.

Use ncbuf API to detect this case : if add operation fails with
NCB_RET_DATA_REJ with add mode NCB_ADD_COMPARE.
2022-05-20 17:56:00 +02:00
Amaury Denoyelle
209404bff1 MINOR: mux-quic: emit STREAM_LIMIT_ERROR
Send a CONNECTION_CLOSE on reception of a STREAM frame for a STREAM id
exceeding the maximum value enforced. Only implemented for bidirectional
streams for the moment.
2022-05-20 17:52:07 +02:00
Amaury Denoyelle
d46b0f52ae MINOR: mux-quic: emit FLOW_CONTROL_ERROR
Send a CONNECTION_CLOSE if the peer emits more data than authorized by
our flow-control. This is implemented for both stream and connection
level.

Fields have been added in qcc/qcs structures to differentiate received
offsets for limit enforcing with consumed offsets for sending of
MAX_DATA/MAX_STREAM_DATA frames.
2022-05-20 17:47:09 +02:00
Amaury Denoyelle
9fab9fd7e5 MINOR: quic/mux-quic: define CONNECTION_CLOSE send API
Define an API to easily set a CONNECTION_CLOSE. This will mainly be
useful for the MUX when an error is detected which require to close the
whole connection.

On the MUX side, a new flag is added when a CONNECTION_CLOSE has been
prepared. This will disable add future send operations.
2022-05-20 17:26:56 +02:00
Frédéric Lécaille
dfd1301035 MINOR: quic: Dynamic Retry implementation
We rely on <conn_opening> stats counter and tune.quic.retry_threshold
setting to dynamically start sending Retry packets. We continue to send such packets
when "quic-force-retry" setting is set. The difference is when we receive tokens.
We check them regardless of this setting because the Retry could have been
dynamically started. We must also send Retry packets when we receive Initial
packets without token if the dynamic Retry threshold was reached but only for connection
which are not currently opening or in others words for Initial packets without
connection already instantiated. Indeed, we must not send Retry packets for all
Initial packets without token. For instance a client may have already sent an
Initial packet without receiving Retry packet because the Retry feature was not
started, then the Retry starts on exeeding the threshold value due to others
connections, then finally our client decide to send another Initial packet
(to ACK Initial CRYPTO data for instance). It does this without token. So, for
this already existing connection we must not send a Retry packet.
2022-05-20 17:11:13 +02:00
Frédéric Lécaille
9286210aa8 MINOR: quic: Add tune.quic.retry-threshold keyword
This QUIC specific keyword may be used to set the theshold, in number of
connection openings, beyond which QUIC Retry feature will be automatically
enabled. Its default value is 100.
2022-05-20 17:11:13 +02:00
Frédéric Lécaille
cbd59c7ab6 MINOR: quic: QUIC stats counters handling
First commit to handle the QUIC stats counters. There is nothing special to say
except perhaps for ->conn_openings which is a gauge to count the number of
connection openings. It is incremented after having instantiated a quic_conn
struct, then decremented when the handshake was successful (handshake completed
state) or failed or when the connection timed out without reaching the handshake
completed state.
2022-05-20 17:11:13 +02:00
Frédéric Lécaille
3fd92f69e0 BUG/MINOR: quic: Fix potential memory leak during QUIC connection allocations
Move the code which finalizes the QUIC connections initialisations after
having called qc_new_conn() into this function to benefit from its
error handling to release the memory allocated for QUIC connections
the initialization of which could not be finalized.
2022-05-20 17:11:13 +02:00
Frédéric Lécaille
a89659a752 MINOR: quic: Attach proxy QUIC stats counters to the QUIC connection
Make usage of EXTRA_COUNTERS_GET() do to so from qc_new_conn().
2022-05-20 17:11:13 +02:00
Frédéric Lécaille
a58cafeb89 MINOR: quic_stats: Add a new stats module for QUIC
This is a very minimalist frontend only stats module with only one gauge for the
QUIC establishing connections count.
2022-05-20 17:11:13 +02:00
Frédéric Lécaille
6492e66e41 MINOR: quic: Move quic_lstnr_dgram_dispatch() out of xprt_quic.c
Remove this function from xprt_quic.c which for now implements only
"by thread attached to a connection" code.
2022-05-20 16:57:12 +02:00
Frédéric Lécaille
ad20a56971 MINOR: cfgparse: Update for "cluster-secret" keyword for QUIC Retry
The QUIC Retry feature is disabled if no "cluster-secret" setting was set.
2022-05-20 16:57:12 +02:00
Frédéric Lécaille
3f3ff47998 MINOR: quic: Retry implementation
Here is the format of a token:
        - format (1 byte)
        - ODCID (from 9 up 21 bytes)
        - creation timestamp (4 bytes)
        - salt (16 bytes)

A format byte is required to distinguish the Retry token from others sent in
NEW_TOKEN frames.

The Retry token is ciphered after having derived a strong secret from the cluster secret
and generated the AEAD AAD, as well as a 16 bytes long salt. This salt is
added to the token. Obviously it is not ciphered. The format byte is not
ciphered too.

The AAD are built by quic_generate_retry_token_aad() which concatenates the version,
the client SCID and the IP address and port. We had to implement quic_saddr_cpy()
to copy the IP address and port to the AAD buffer. Only the Retry SCID is generated
on our side to build a Retry packet, the others fields come from the first packet
received by the client. It must reuse this Retry SCID in response to our Retry packet.
So, we have not to store it on our side. Everything is offloaded to the client (stateless).
quic_generate_retry_token() must be used to generate a Retry packet. It calls
quic_pkt_encrypt() to cipher the token.

quic_generate_retry_check() must be used to check the validity of a Retry token.
It is able to decipher a token which arrives into an Initial packet in response
to a Retry packet. It calls parse_retry_token() after having deciphered the token
to store the ODCID into a local quic_cid struct variable. Finally this ODCID may
be stored into the transport parameter thanks to qc_lstnr_params_init().
The Retry token lifetime is 10 seconds. This lifetime is also checked by
quic_generate_retry_check(). If quic_generate_retry_check() fails, the received
packet is dropped without anymore packet processing at this time.
2022-05-20 16:57:12 +02:00
Frédéric Lécaille
55367c8679 MINOR: quic_tls: Add quic_tls_decrypt2() implementation
This function does exactly the same thing as quic_tls_decrypt(), except that
it does reuse its input buffer as output buffer. This is needed
to decrypt the Retry token without modifying the packet buffer which
contains this token. Indeed, this would prevent us from decryption
the packet itself as the token belong to the AEAD AAD for the packet.
2022-05-20 16:57:12 +02:00
Frédéric Lécaille
a9c5d8da58 MINOR: quic_tls: Add quic_tls_derive_retry_token_secret()
This function must be used to derive strong secrets from a non pseudo-random
secret (cluster-secret setting in our case) and an IV. First it call
quic_hkdf_extract_and_expand() to do that for a temporary strong secret (tmpkey)
then two calls to quic_hkdf_expand() reusing this strong temporary secret
to derive the final strong secret and IV.
2022-05-20 16:57:12 +02:00
Willy Tarreau
8ec9c81ac4 BUG/MINOR: cfgparse: abort earlier in case of allocation error
In issue #1563, Coverity reported a very interesting issue about a
possible UAF in the config parser if the config file ends in with a
very large line followed by an empty one and the large one causes an
allocation failure.

The issue essentially is that we try to go on with the next line in case
of allocation error, while there's no point doing so. If we failed to
allocate memory to read one config line, the same may happen on the next
one, and blatantly dropping it while trying to parse what follows it. In
the best case, subsequent errors will be incorrect due to this prior error
(e.g. a large ACL definition with many patterns, followed by a reference of
this ACL).

Let's just immediately abort in such a condition where there's no recovery
possible.

This may be backported to all versions once the issue is confirmed to be
addressed.

Thanks to Ilya for the report.
2022-05-20 09:20:12 +02:00
Amaury Denoyelle
3dde0d86dd MINOR: quic: detect EBADF on sendto()
EBADF can be encountered during process termination after fd listener
has been reset to -1.
2022-05-19 11:58:32 +02:00
Amaury Denoyelle
ad5df386d9 MINOR: quic: abort on unlisted errno on sendto()
If an unlisted errno is reported, abort the process. If a crash is
reported on this condition, we must determine if the error code is a
bug, should interrupt emission on the fd or if we can retry the syscall.
2022-05-19 10:18:18 +02:00
Amaury Denoyelle
8fa666650f BUG/MINOR: quic: break for error on sendto
If sendto returns an error, we should not retry the call and break from
the sending loop. An exception is made for EINTR which allows to retry
immediately the syscall.

This bug caused an infinite loop reproduced when the process is in the
closing state by SIGUSR1 but there is still QUIC data emission left.
2022-05-19 10:18:18 +02:00
Christopher Faulet
c95eaefbfd MEDIUM: check: Use the CS to handle subscriptions for read/write events
Instead of using the health-check to subscribe to read/write events, we now
rely on the conn-stream. Indeed, on the server side, the conn-stream's
endpoint is a multiplexer. Thus it seems appropriate to handle subscriptions
for read/write events the same way than for the streams. Of course, the I/O
callback function is not the same. We use srv_chk_io_cb() instead of
cs_conn_io_cb().
2022-05-19 10:12:38 +02:00
Christopher Faulet
361417f9b4 REORG: check: Rename and export I/O callback function
event_srv_chk_io() function is renamed srv_chk_io_cb() to be consistant with
the I/O callback function of connections. In addition, this function is
exported. It will be required to use the conn-stream's subscriptions.
2022-05-19 10:12:38 +02:00
Christopher Faulet
08c8f8e20d MEDIUM: check: No longer shutdown the connection in .wake callback function
The connection is already closed by the health-check itself. Thus there is
now reason to duplicate this part in the .wake callback function. It is
enough to wake the health-check and wait.
2022-05-19 10:12:38 +02:00
Christopher Faulet
6d781f612a BUG/MINOR: check: Reinit the buffer wait list at the end of a check
The buffer wait list is used to deal with buffer allocation failure. But at
the end of health-check, it must be reinitialized. There is no reason to
reason to get a buffer between two health-check runs. And in fact, the
associated flags, CHK_ST_IN_ALLOC and CHK_ST_OUT_ALLOC, are already cleared
at the end of a health-check.

This patch must be backported as far as 2.2. On the 2.2, MT_LIST_ADDED and
MT_LIST_DEL must be used instead of LIST_INLIST and LIST_DEL_INIT.
2022-05-19 10:12:38 +02:00
Christopher Faulet
dfe32c7e15 BUG/MEDIUM: config: Reset outline buffer size on realloc error in readcfgfile()
When the line parsing failed because outline buffer must be reallocated, if
my_realloc2() call fails, the buffer size must be reset. Indeed, in this case
the current line is skipped, a fatal error is reported and we jump to the next
line. At this stage the outline buffer is NULL. If the buffer size is not reset,
the next call to parse_line() crashes because we try to write in the buffer. We
fail to detect the outline buffer is too small to copy any character.

To fix the issue, outlinesize variable must be set to 0 when outline allocation
failed.

This patch should fix the issue #1563. It must be backported as far as 2.2.
2022-05-19 10:12:38 +02:00
Amaury Denoyelle
8b87b15c22 MINOR: mux-quic: free RX buf if empty
Release the QCS RX buffer if emptied afer qcs_consume(). This improves
memory usage and avoids a QCS to keep an allocated buffer, particularly
when no data is received anymore. Buffer is automatically reallocated if
needed via qc_get_ncbuf().
2022-05-18 16:25:07 +02:00
Amaury Denoyelle
7313f5ee7e BUG/MINOR: mux-quic: support nul buffer with qc_free_ncbuf()
qc_free_ncbuf() may now be used with a NCBUF_NULL buffer as parameter.
This is useful when using this function on a QCS with no allocated
buffer. This case was not reproduced for the moment, but it will soon
become more present as buffers will be released if emptied.

Also a call to offer_buffers() is added to conform with the dynamic
buffer management of haproxy.
2022-05-18 16:25:07 +02:00
Amaury Denoyelle
c830e1e904 MINOR: mux-quic: implement MAX_DATA emission
This commit is similar to the previous one but deals with MAX_DATA for
connection-level data flow control. It uses the same function
qcc_consume_qcs() to update flow control level and generate a MAX_DATA
frame if needed.
2022-05-18 16:25:07 +02:00
Amaury Denoyelle
a977355aa1 MINOR: mux-quic: implement MAX_STREAM_DATA emission
Send MAX_STREAM_DATA frames when at least half of the allocated
flow-control has been demuxed, frame and cleared. This is necessary to
support QUIC STREAM with received data greater than a buffer.

Transcoders must use the new function qcc_consume_qcs() to empty the QCS
buffer. This will allow to monitor current flow-control level and
generate a MAX_STREAM_DATA frame if required. This frame will be emitted
via qc_io_cb().
2022-05-18 16:25:07 +02:00
Amaury Denoyelle
c985cb167d MINOR: mux-quic: reorganize flow-control frames emission
Adjust the mechanism for MAX_STREAMS_BIDI emission. When a bidirectional
stream is removed, current flow-control level is checked. If needed, a
MAX_STREAMS_BIDI frame is generated and inserted in a new list in the
QCS instance. The new frames will be emitted at the start of qc_send().

This has no impact on the current MAX_STREAMS_BIDI behavior. However,
this mechanism is more flexible and will allow to implement quickly
MAX_STREAM_DATA/MAX_DATA emission.
2022-05-18 15:52:44 +02:00
Amaury Denoyelle
3a0864067a MINOR: mux-quic: remove qcc_decode_qcs() call in XPRT
Slightly change the interface for qcc_recv() between MUX and XPRT. The
MUX is now responsible to call qcc_decode_qcs(). This is cleaner as now
the XPRT does not have to deal with an extra QCS parameter and the MUX
will call qcc_decode_qcs() only if really needed.

This change is possible since there is no extra buffering for
out-of-order STREAM frames and the XPRT does not have to handle buffered
frames.
2022-05-18 15:50:57 +02:00
Amaury Denoyelle
37c2e4a65a MEDIUM: mux-quic: implement recv on io-cb
Previously, qc_io_cb() of mux-quic only dealt with TX. Add support for
RX in it. This is done through a new function qc_recv(qcc). It loops
over all QCS instances and call qcc_decode_qcs(qcs).

This has no impact from the quic-conn layer as qcc_decode_qcs(qcs) is
called directly. However, this allows to have a resume point when demux
is blocked on the upper layer HTX full buffer.

Note that for the moment, only RX for bidirectional streams is managed
in qc_io_cb(). Unidirectional streams use their own mechanism for both
TX/RX. It should be unified in the near future in a refactoring.
2022-05-18 15:43:22 +02:00
Amaury Denoyelle
73d6ffe832 MINOR: h3: flag demux as full on HTX full
Flag QCS if HTX buffer is full on demux. This will block all future
operations on QCS demux and should limit unnecessary decode_qcs() calls.
The flag is cleared on rcv_buf operation called by conn-stream.
2022-05-18 15:38:01 +02:00
Amaury Denoyelle
b5454d42df MINOR: h3: do not wait a complete frame for demuxing
Previously, H3 demuxer refused to proceed the payload if the frame was
not entirely received and the QCS buffer is not full. This code was
duplicated from the H2 demuxer.

In H2, this is a justified optimization as only one frame at a time can
be demuxed. However, this is not the case in H3 with interleaved frames
in the lower layer QUIC STREAM frames.

This condition is now removed. H3 demuxer will proceed payload as soon
as possible. An exception is kept for HEADERS frame as the code is not
able to deal with partial HEADERS.

With this change, H3 demuxer should consume less memory. To ensure that
we never received a HEADER bigger than the RX buffer, we should use the
H3 SETTINGS_MAX_FIELD_SECTION_SIZE.
2022-05-18 15:31:46 +02:00
Amaury Denoyelle
ca21c768b9 MINOR: ncbuf: refactor ncb_advance()
First adjusted some typos in comments inside the function. Second,
change the naming of some variable to reduce confusion.

A special case has been inserted when advance is done inside a GAP block
and this block is the last of the buffer. In this case, the whole buffer
will be emptied, equivalent to a ncb_init() operation.
2022-05-18 15:30:13 +02:00
Amaury Denoyelle
f6dbdc1444 BUG/MINOR: ncbuf: fix ncb_is_empty()
ncb_is_empty() was plainly incorrect as it directly dereferences the
memory to read offset blocks instead of ncb_read_off(). The result is
undefined.

Also, BUG_ON() statement is wrong when the buffer starts with a data
block. In this case, ncb_head() is not the first gap offset but instead
just random data. The calculated sum in BUG_ON() statement has thus no
meaning and may cause an abort. Adjust this by reorganizing the whole
function. Only the first data block size is read. If and only if not
nul, the first gap size is then checked.

ncb_is_full() has been rewritten to share the same model as
ncb_is_empty().
2022-05-18 15:23:29 +02:00
Amaury Denoyelle
80d0572a31 BUG/MEDIUM: quic: fix Rx buffering
The quic-conn manages a buffer to store received QUIC packets. When the
buffer wraps, the gap is filled until the end with junk and packets can
be inserted at the start of the buffer.

On the other end, deletion is implemented via quic_rx_pkts_del().
Packets are removed one by one if their refcount is nul. If junk is
found, the buffer is emptied until its wrap.

This seems to work in most cases but a bug was found in a particular
case : on insertion if buffer gap is not at the end of the buffer. In
this case, the gap was filled, which is useless as now the buffer is
full and the packet cannot be inserted. Worst, on deletion, when junk is
removed there is a risk to removed new packets. This can happens in the
following case :
1. buffer contig space is too small, junk is inserted in the middle of
   it
2. on quic_rx_pkts_del() invocation, a packet is removed, but not the
   next one because its refcount is still positive. When a new packet is
   received, it will be stored after the junk.
3. on next quic_rx_pkts_del(), when junk is removed, all contig data is
   cleared, with newer packets data too.

This will cause a transfer between a client and haproxy to be stalled.
This can be reproduced with big enough POST requests. I triggered it
with ngtcp2 and 10M of posted data.

Hopefully, the solution of this bug is simple. If contig space is not
big enough to store a packet, but the space is not at the end of the
buffer, no junk is inserted and the packet is dropped as we cannot
buffered it. This ensures that junk is only present at the end of the
buffer and when removed no packets data is purged with it.
2022-05-18 15:02:14 +02:00
Christopher Faulet
f229e1894c CLEANUP: httpclient: Remove useless test on ss_dst in httpclient_applet_init()
In httpclient_applet_init() function, ss_dst variable is always defined
before the call to sockaddr_alloc(). There is no reason to test it.

This patch should fix the issue #1706.
2022-05-18 09:29:33 +02:00
Christopher Faulet
9e3c8d5512 CLEANUP: peers: Remove unreachable code in peer_session_create()
An error label is now unreachable in peer_session_create().

This patch should fix the issue #1704.
2022-05-18 09:04:53 +02:00
Christopher Faulet
fa463afa8f BUG/MINOR: spoe: Fix error handling in spoe_init_appctx()
labels used in goto statement was not called in the right order. Thus if
there is an error during the appctx startup, it is possible to leak a task.

This patch should fix the issue #1703. No backport needed.
2022-05-18 09:04:53 +02:00
Tim Duesterhus
7ad27d41b4 CLEANUP: http_ana: Make use of the return value of stream_generate_unique_id()
Even if `unique_id` and `s->unique_id` are identical it is a bit odd to
`isttest()` `unique_id` and then use `s->unique_id` in the call to `http_add_header()`.

This "issue" was introduced in a17e66289c,
because before that commit the function returned the length of the ID, as it
was not an ist.
2022-05-18 07:19:01 +02:00
Remi Tricot-Le Breton
ccc0355c41 MINOR: ssl: Add 'ssl-provider-path' global option
When loading providers with 'ssl-provider' global options, this
ssl-provider-path option can be used to set the search path that is to
be used by openssl. It behaves the same way as the OPENSSL_MODULES
environment variable.
2022-05-17 18:09:17 +02:00
Christopher Faulet
bc684acae7 CLEANUP: proxy: Remove dead code when parsing "http-restrict-req-hdr-names" option
negation or default modifiers are not supported for this option. However,
this was already tested earlier in cfg_parse_listen() function. Thus, when
"http-restrict-req-hdr-names" option is parsed, the keyword modifier is
always equal to KWM_STD. It is useless to test it again at this place.

This patch should solve the issue #1702.
2022-05-17 16:13:22 +02:00
Christopher Faulet
2d9cc85b74 MINOR: conn-stream/applet: Stop setting appctx as the endpoint context
The appctx is already the endpoint target. It is confusing to also use it to
set the endpoint context. So, never set the endpoint ctx when an appctx is
created or attached to an existing conn-stream.
2022-05-17 16:13:22 +02:00
Maciej Zdeb
34e4085f8a MEDIUM: peers: Balance applets across threads
When creating a new applet for peer outgoing connection, we check
the load on each thread. Threads with least applet count are
preferred.

With this solution we avoid a situation when many outgoing
connections run on the same thread causing significant load on
single CPU core.
2022-05-17 16:13:22 +02:00
Maciej Zdeb
d01be2ab13 MINOR: peers: Track number of applets run by thread
Maintain number of peers applets run on all threads. It will be used
in next patch for least loaded thread selection.
2022-05-17 16:13:22 +02:00
Christopher Faulet
d9c1d33fa1 MEDIUM: applet: Add support for async appctx startup on a thread subset
It is now possible to start an appctx on a thread subset. Some controls were
added here and there. It is forbidden to start a backend appctx on another
thread than the local one. If a frontend appctx is started on another thread
or a thread subset, the applet .init callback function must be defined. This
callback function is responsible to finalize the appctx startup. It can be
performed synchornously. In this case, the appctx is started on the local
thread. It is not really useful but it is valid. Or it can be performed
asynchronously. In this case, .init callback function is called when the
appctx is woken up for the first time. When this happens, the appctx
affinity is set to the current thread to be able to start the session and
the stream.
2022-05-17 16:13:22 +02:00
Christopher Faulet
6095d57701 MINOR: applet: Add API to start applet on a thread subset
In the same way than for the tasks, the applets api was changed to be able
to start a new appctx on a thread subset. For now the feature is
disabled. Only appctx_new_here() is working. But it will be possible to
start an appctx on a specific thread or a subset via a mask.
2022-05-17 16:13:22 +02:00
Christopher Faulet
6712dc680c MEDIUM: peers: Refactor peer appctx creation
A .init callback function is defined for the peer_applet applet. This
function finishes the appctx startup by calling appctx_finalize_startup()
and its handles the stream customization.
2022-05-17 16:13:22 +02:00
Christopher Faulet
387e79727c MINOR: peers: Add a ref to peers section in the peer structure
This change is required to handle asynchrone init of the appctx. It is now
possible to directly get the peers section associated to a peer.
2022-05-17 16:13:22 +02:00
Christopher Faulet
aee57fc277 MEDIUM: sink: Refactor sink forwarder appctx creation
A .init callback function is defined for the sink_forward_applet applet.
This function finishes the appctx startup by calling
appctx_finalize_startup() and its handles the stream customization.
2022-05-17 16:13:22 +02:00
Christopher Faulet
2ae25ea24b MINOR: sink: Add a ref to sink in the sink_forward_target structure
This change is required to be able to refactor the init stage of appctx. It
is now possible to directly get the sink from a forward target.
2022-05-17 16:13:22 +02:00
Christopher Faulet
b1e0836ecf MEDIUM: httpclient: Refactor http-client appctx creation
A .init callback function is defined for the httpclient_applet applet. This
function finishes the appctx startup by calling appctx_finalize_startup()
and its handles the stream customization.
2022-05-17 16:13:22 +02:00
Christopher Faulet
5f35a3e2ec MEDIUM: lua: Refactor cosocket appctx creation
A .init callback function is defined for the update_applet applet. This
function finishes the appctx startup by calling appctx_finalize_startup()
and its handles the stream customization.
2022-05-17 16:13:22 +02:00
Christopher Faulet
69ebc3093a MEDIUM: spoe: Refactor SPOE appctx creation
A .init callback function is defined for the spoe_applet applet. This
function finishes the spoe_appctx initialization. It also finishes the
appctx startup by calling appctx_finalize_startup() and its handles the
stream customization.
2022-05-17 16:13:22 +02:00
Christopher Faulet
9223851a80 MEDIUM: dns: Refactor dns appctx creation
A .init callback function is defined for the dns_session_applet applet. This
function finishes the appctx startup by calling appctx_finalize_startup()
and its handles the stream customization.
2022-05-17 16:13:21 +02:00
Christopher Faulet
d0c4ec04b8 MINOR: applet: Add function to release appctx on error during init stage
appctx_free_on_early_error() must be used to release a freshly created
frontend appctx if an error occurred during the init stage. It takes care to
release the stream instead of the appctx if it exists. For a backend appctx,
it just calls appctx_free().
2022-05-17 16:13:21 +02:00
Christopher Faulet
8718c95c0a MINOR: applet: Add a function to finalize frontend appctx startup
appctx_finalize_startup() may be used to finalize the frontend appctx
startup. It is responsible to create the appctx's session and the frontend
conn-stream. On error, it is the caller responsibility to release the
appctx. However, the session is released if it was created. On success, if
an error is encountered in the caller function, the stream must be released
instead of the appctx.

This function should ease the init stage when new appctx is created.
2022-05-17 16:13:21 +02:00
Christopher Faulet
16c0d9cda0 MINOR: applet: Add appctx_init() helper fnuction
It is just a helper function that call the .init applet callback function,
if it exists. This will simplify a bit the init stage when a new applet is
started. For now, this callback function is only used when a new service is
started.
2022-05-17 16:13:21 +02:00
Christopher Faulet
ab5d1dceed MINOR: stream: Export stream_free()
The stream_free() function is now public. It is mandatory to properly handle
errors when a new applet is started.
2022-05-17 16:13:21 +02:00
Christopher Faulet
c9929380a4 MINOR: applet: Change return value for .init callback function
0 is now returned on success and -1 on error.
2022-05-17 16:13:21 +02:00
Christopher Faulet
92202da2da MINOR: applet: Let the frontend appctx release the session
The session created for frontend applets is now totally owns by the
corresponding appctx. It means the appctx is now responsible to release
it. This removes the hack in stream_free() about frontend applets to be sure
to release the session.
2022-05-17 16:13:21 +02:00
Christopher Faulet
ac57bb527a MINOR: applet: Prepare appctx to own the session on frontend side
Applets were moved at the same level than multiplexers. Thus, gradually,
applets code is changed to be less dependent from the stream. With this
commit, the frontend appctx are ready to own the session. It means a
frontend appctx will be responsible to release the session.
2022-05-17 16:13:21 +02:00
Remi Tricot-Le Breton
9bf3a1f67e BUG/MINOR: ssl: Fix crash when no private key is found in pem
If no private key can be found in a bind line's certificate and
ssl-load-extra-files is set to none we end up trying to call
X509_check_private_key with a NULL key, which crashes.

This fix should be backported to all stable branches.
2022-05-17 15:51:41 +02:00
David Carlier
7198c700bc MINOR: tools: add get_exec_path implementation for solaris based systems.
We can use getexecname() which fetches AT_SUN_EXECNAME from the auxiliary
vectors.
2022-05-17 11:44:21 +02:00
Tim Duesterhus
9b6becb312 CLEANUP: Remove unused function hlua_get_top_error_string
This function has no prototype defined in a header and is not used in hlua.c
either, thus it can be safely removed. Found with -Wmissing-prototypes.
2022-05-17 11:40:33 +02:00
Tim Duesterhus
6eded62f6a CLEANUP: Add missing header to hlua_fcn.c
Found with -Wmissing-prototypes:

    src/hlua_fcn.c:53:5: fatal error: no previous prototype for function 'hlua_checkboolean' [-Wmissing-prototypes]
    int hlua_checkboolean(lua_State *L, int index)
        ^
    src/hlua_fcn.c:53:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
    int hlua_checkboolean(lua_State *L, int index)
    ^
    static
    1 error generated.
2022-05-17 11:40:33 +02:00
Tim Duesterhus
2a0688aa89 CLEANUP: Add missing header to ssl_utils.c
Found with -Wmissing-prototypes:

    src/ssl_utils.c:22:5: fatal error: no previous prototype for function 'cert_get_pkey_algo' [-Wmissing-prototypes]
    int cert_get_pkey_algo(X509 *crt, struct buffer *out)
        ^
    src/ssl_utils.c:22:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
    int cert_get_pkey_algo(X509 *crt, struct buffer *out)
    ^
    static
    1 error generated.
2022-05-17 11:40:33 +02:00
Remi Tricot-Le Breton
1746a388c5 MINOR: ssl: Add 'ssl-provider' global option
When HAProxy is linked to an OpenSSLv3 library, this option can be used
to load a provider during init. You can specify multiple ssl-provider
options, which will be loaded in the order they appear. This does not
prevent OpenSSL from parsing its own configuration file in which some
other providers might be specified.
A linked list of the providers loaded from the configuration file is
kept so that all those providers can be unloaded during cleanup. The
providers loaded directly by OpenSSL will be freed by OpenSSL.
2022-05-17 10:56:05 +02:00
Remi Tricot-Le Breton
e80976526c MINOR: ssl: Add 'ssl-propquery' global option
This option can be used to define a default property query used when
fetching algorithms in OpenSSL providers. It follows the format
described in https://www.openssl.org/docs/man3.0/man7/property.html.
It is only available when haproxy is built with SSL support and linked
to OpenSSLv3 libraries.
2022-05-17 10:56:05 +02:00
Remi Tricot-Le Breton
5194446b76 MEDIUM: ssl: Delay random generator initialization after config parsing
The random generator initialization needs to be performed before the
chroot but it is not needed before. If we want to add provider
configuration option to the configuration file, they need to be
processed before any call to a crypto-related OpenSSL function.
We can then delay the initialization until after the configuration file
is parsed and processed.
2022-05-17 10:55:59 +02:00
Christopher Faulet
18c13d3bd8 MEDIUM: http-ana: Add a proxy option to restrict chars in request header names
The "http-restrict-req-hdr-names" option can now be set to restrict allowed
characters in the request header names to the "[a-zA-Z0-9-]" charset.

Idea of this option is to not send header names with non-alphanumeric or
hyphen character. It is especially important for FastCGI application because
all those characters are converted to underscore. For instance,
"X-Forwarded-For" and "X_Forwarded_For" are both converted to
"HTTP_X_FORWARDED_FOR". So, header names can be mixed up by FastCGI
applications. And some HAProxy rules may be bypassed by mangling header
names. In addition, some non-HTTP compliant servers may incorrectly handle
requests when header names contain characters ouside the "[a-zA-Z0-9-]"
charset.

When this option is set, the policy must be specify:

  * preserve: It disables the filtering. It is the default mode for HTTP
              proxies with no FastCGI application configured.

  * delete: It removes request headers with a name containing a character
            outside the "[a-zA-Z0-9-]" charset. It is the default mode for
            HTTP backends with a configured FastCGI application.

  * reject: It rejects the request with a 403-Forbidden response if it
            contains a header name with a character outside the
            "[a-zA-Z0-9-]" charset.

The option is evaluated per-proxy and after http-request rules evaluation.

This patch may be backported to avoid any secuirty issue with FastCGI
application (so as far as 2.2).
2022-05-16 16:00:26 +02:00
Amaury Denoyelle
f46393ac44 MINOR: ncbuf: fix warnings for testing build
Using -Wall reveals several warning when building ncbuf testing API. One
of them was about the signedness mismatch. The other one was with an
incorrect print format.
2022-05-16 11:32:33 +02:00
Amaury Denoyelle
48fbad45e2 BUG/MEDIUM: ncbuf: fix null buffer usage
ncbuf public API functions were not ready to deal with a NCBUF_NULL as
parameter. Strenghten these functions by handling it properly.

Most of the functions will consider the buffer as empty and silently
returns. The only exception is ncb_init(buf) which cannot be called
with a NCBUF_NULL. This seems legitimate to consider this as a bug and
not silently failed in this case.
2022-05-16 11:28:41 +02:00
Amaury Denoyelle
45fce8fcb5 CLEANUP: quic: remove unused quic_rx_strm_frm
quic_rx_strm_frm type was used to buffered STREAM frames received out of
order. Now the MUX is able to deal directly with these frames and
buffered it inside its ncbuf.
2022-05-13 17:29:52 +02:00
Amaury Denoyelle
00f87bbaa3 CLEANUP: mux-quic: remove unused fields for Rx
Rx has been simplified since the conversion of buffer to a ncbuf. The
old buffer can now be removed. The frms tree is also removed. It was
used previously to stored out-of-order received STREAM frames. Now the
MUX is able to buffer them directly into the ncbuf.
2022-05-13 17:29:52 +02:00
Amaury Denoyelle
3db98e9d13 MEDIUM: mux-quic/h3/qpack: use ncbuf for uni streams
This commit is the equivalent for uni-streams of previous commit
  MEDIUM: mux-quic/h3/hq-interop: use ncbuf for bidir streams

All unidirectional streams data is now handle in MUX Rx ncbuf. The
obsolete buffer is not unused and will be cleared in the following
patches.
2022-05-13 17:29:49 +02:00
Amaury Denoyelle
1290f1ebfb MEDIUM: mux-quic/h3/hq-interop: use ncbuf for bidir streams
Add a ncbuf for data reception on qcs. Thanks to this, the MUX is able
to buffered all received frame directly into the buffer. Flow control
parameters will be used to ensure there is never an overflow.

This change will simplify Rx path with the future deletion of acked
frames tree previously used for frames out of order.
2022-05-13 17:28:46 +02:00
Amaury Denoyelle
b5ca943ff9 BUG/MINOR: ncbuf: fix coverity warning on uninit sz_data
Coverity reports that data block generated by ncb_blk_first() has
sz_data field uninitialized. This has no real impact as it has no sense
for data block. Set to 0 to hide the warning.

This should fix github issue #1695.
2022-05-13 17:06:24 +02:00
Willy Tarreau
26f221bd55 MINOR: config: make sure never to mix dgram and stream protocols on a bind line
It is absolutely not possible to use the same "bind" line to listen to
both quic and tcp for example, because no single transport layer would
fit both modes and we'll need the type to choose one then to choose a
mux. Let's make sure this does not happen. This may be relaxed in the
future if we manage to instantiate transport layers on the fly, but the
SSL vs quic part might be tricky to handle.
2022-05-13 17:00:09 +02:00
Willy Tarreau
8d31ab0438 MINOR: tools: improve error message accuracy in str2sa_range
The error message when mixing stream and dgram protocols in an
address speaks about sockets while it ought to speak about addresses,
let's fix this as in some contexts it can be a bit confusing.
2022-05-13 16:50:00 +02:00
Willy Tarreau
df94313e0e BUG/MEDIUM: mux-quic: fix a thinko in the latest cs/endpoint cleanup
Fred & Amaury found that I messed up with qc_detach() in commit 4201ab791
("CLEANUP: muxes: make mux->attach/detach take a conn_stream endpoint"),
causing a segv in this case with endp->cs == NULL being passed to
__cs_mux(). It obviously ought to have been endp->target like in other
muxes.

No backport needed.
2022-05-13 16:34:40 +02:00
Willy Tarreau
973cf90714 MINOR: ext-check: indicate the transport and protocol of a server
Valerio Pachera explained [1] that external checks would benefit from
having a variable indicating if SSL is being used or not on the server
being checked, and the discussion derived to also indicating the protocol
in use.

This patch adds two environment variables for external checks:
  - HAPROXY_SERVER_SSL: equals "0" when SSL is not used, "1" when it is
  - HAPROXY_SERVER_PROTO: contains one of the following words to describe
    the protocol used with this server:
      - "cli": the haproxy CLI. Normally not seen
      - "syslog": this is a syslog TCP server
      - "peers": this is a peers TCP server
      - "h1": this is an HTTP/1.x server
      - "h2": this is an HTTP/2 server
      - "tcp": this is any other TCP server

The patch is very simple, and may be backported to recent versions if
needed. This closes github issue #1692.

[1] https://www.mail-archive.com/haproxy@formilux.org/msg42233.html
2022-05-13 16:06:29 +02:00