7020 Commits

Author SHA1 Message Date
Willy Tarreau
1057beecda REORG: ssl: move ssl_sock_is_ssl() to connection.h and rename it
This one doesn't use anything from an SSL context, it only checks the
type of the transport layer of a connection, thus it belongs to
connection.h. This is particularly visible due to all the ifdefs
around it in various call places.
2021-10-07 01:36:51 +02:00
Willy Tarreau
340ef2502e CLEANUP: servers: do not include openssl-compat
This is exactly the same as for listeners, servers only include
openssl-compat to provide the SSL_CTX type to use as two pointers to
contexts, and to detect if NPN, ALPN, and cipher suites are supported,
and save up to 5 pointers in the ssl_ctx struct if not supported. This
is pointless, as these ones have all been supported for about a decade,
and including this file comes with a long dependency chain that impacts
lots of other files. The ctx was made a void*.

Now the build time was significantly reduced, from 9.2 to 8.1 seconds,
thanks to opensslconf.h being included "only" 456 times instead of 2424
previously!

The total number of lines of code compiled was reduced by 15%.
2021-10-07 01:36:51 +02:00
Willy Tarreau
b0d8194684 CLEANUP: listeners: do not include openssl-compat
Listeners only include openssl-compat to provide the SSL_CTX type to
use as two pointers to contexts, and to detect if NPN, ALPN, and cipher
suites are supported, and save up to 5 pointers in the ssl_bind_conf
struct if not supported. This is pointless, as these ones have all been
supported for about a decade, and including this file comes with a long
dependency chain that impacts lots of other files. The initial_ctx and
default_ctx can perfectly remain void* instead of SSL_CTX*.
2021-10-07 01:36:51 +02:00
Willy Tarreau
dbf78025a0 REORG: listener: move bind_conf_alloc() and listener_state_str() to listener.c
These functions have no reason for being inlined, and they require some
includes with long dependencies. Let's move them to listener.c and trim
unused includes in listener.h.
2021-10-07 01:36:51 +02:00
Willy Tarreau
fd1c17ff46 CLEANUP: remove some unneeded includes from applet-t.h
This file includes streams, proxies, Lua just for some definitions of
structures for which we only have a pointer. Let's drop this. That's
responsible for 0.2% of all the lines of code.
2021-10-07 01:36:51 +02:00
Willy Tarreau
407ef893e7 REORG: thread: uninline the lock-debugging code
The lock-debugging code in thread.h has no reason to be inlined. the
functions are quite fat and perform a lot of operations so there's no
saving keeping them inlined. Worse, most of them are in fact not
inlined, resulting in a significantly bigger executable.

This patch moves all this part from thread.h to thread.c. The functions
are still exported in thread.h of course. This results in ~166kB less
code:

     text    data     bss     dec     hex filename
  3165938   99424  897376 4162738  3f84b2 haproxy-before
  2991987   99424  897376 3988787  3cdd33 haproxy-after

In addition the build time with thread debugging enabled has shrunk
from 19.2 to 17.7s thanks to much less code to be parsed in thread.h
that is included virtually everywhere.
2021-10-07 01:36:51 +02:00
Willy Tarreau
f14d19024b REORG: pools: uninline the UAF allocator and force-inline the rest
pool-os.h relies on a number of includes solely because the
pool_alloc_area() function was inlined, and this only because we want
the normal version to be inlined so that we can track the calling
places for the memory profiler. It's worth noting that it already
does not work at -O0, and that when UAF is enabled we don't care a
dime about profiling.

This patch does two things at once:
  - force-inline the functions so that pool_alloc_area() is still
    inlined at -O0 to help track malloc() users ;

  - uninline the UAF version of these (that rely on mmap/munmap)
    and move them to pools.c so that we can remove all unneeded
    includes.

Doing so reduces by ~270kB or 0.15% the total build size.
2021-10-07 01:36:51 +02:00
Willy Tarreau
690fa145ef CLEANUP: pools: pools-t.h doesn't need to include thread-t.h
This is probably a leftover from an older version to access MAX_THREADS.
2021-10-07 01:36:51 +02:00
Willy Tarreau
1a2134138a BUILD: compat: fix -Wundef on SO_REUSEADDR
If USE_NETFILTER is set and not SO_REUSEPORT, we evaluate SO_REUSEADDR,
let's fix that to check that it's defined.
2021-10-07 01:36:51 +02:00
Willy Tarreau
fa17d9f92c BUILD: connection: connection.h needs list.h and server.h
It manipulates lists and calls srv_add_conn().
2021-10-07 01:36:51 +02:00
Willy Tarreau
337f23a112 BUILD: compiler: add the container_of() and container_of_safe() macros
These ones are called from a few places in the code and are only provided
by ebtree.h, which is not normal given that some callers do not even use
ebtree.
2021-10-07 01:36:51 +02:00
Willy Tarreau
ab46ac8343 BUILD: http_ana: need to include proxy-t to get redirect_rule
The struct was only defined inside function arguments there and
inherited from other files.
2021-10-07 01:36:51 +02:00
Willy Tarreau
d2d968a9bf BUILD: resolvers: define missing types in resolvers.h
proxy, server, stream_interface and list were used but not defined. Let's
define them as well as act_rule and drop action-t.h.
2021-10-07 01:36:51 +02:00
Willy Tarreau
59be17a29a BUILD: stats: define several missing structures in stats.h
channel, stream_interface, appctx, buffer, proxy and htx ones are used
in function arguments and most of them are not defined but were inherited
from intermediary inclues. Let's define them here and drop the unneeded
includes.
2021-10-07 01:36:51 +02:00
Willy Tarreau
b70596df0a BUILD: action: add the relevant structures for function arguments
Some structures are inherited via intermediary includes (e.g. dns_counters
comes from a long path). Let's define the missing ones and includes vars-t
that is needed in the structure.
2021-10-07 01:36:51 +02:00
Willy Tarreau
168e8de1d0 MINOR: sample: provide a generic var-to-sample conversion function
We're using variable-to-sample conversion at least 4 times in the code,
two of which are bogus. Let's introduce a generic conversion function
that performs the required checks.
2021-10-07 01:36:51 +02:00
Willy Tarreau
4034e2cb58 CLEANUP: sample: uninline sample_conv_var2smp_str()
There's no reason to limit this one to this file, it could be used in
other contexts.
2021-10-07 01:36:51 +02:00
Willy Tarreau
d9be599529 CLEANUP: sample: rename sample_conv_var2smp() to *_sint
This one only handles integers, contrary to its sibling with the suffix
_str that only handles strings. Let's rename it and uninline it since it
may well be used from outside.
2021-10-07 01:36:51 +02:00
Willy Tarreau
80527bcb9d CLEANUP: server: always include the storage for SSL settings
The SSL stuff in struct server takes less than 3% of it and requires
lots of annoying ifdefs in the code just to take care of the cases
where the field is absent. Let's get rid of this and stop including
openssl-compat from server.c to detect NPN and ALPN capabilities.

This reduces the total LoC by another 0.4%.
2021-10-07 01:36:51 +02:00
William Lallemand
2a879001b5 MINOR: httpclient: destroy checks if a client was started but not stopped
During httpclient_destroy, add a condition in the BUG_ON which checks
that the client was started before it has ended. A httpclient structure
could have been created without being started.
2021-10-06 15:15:03 +02:00
William Lallemand
b8b1370307 MINOR: httpclient: test if started during stop_and_destroy()
If the httpclient was never started, it is safe to destroy completely
the httpclient.
2021-10-06 15:15:03 +02:00
William Lallemand
ecb83e13eb MINOR: httpclient: stop_and_destroy() ask the applet to autokill
httpclient_stop_and_destroy() tries to destroy the httpclient structure
if the client was stopped.

In the case the client wasn't stopped, it ask the client to stop itself
and to destroy the httpclient structure itself during the release of the
applet.
2021-10-06 15:15:03 +02:00
Willy Tarreau
1cdb531ec8 REORG: sched: move the stolen CPU time detection to sched_entering_poll()
That's where that code initially was but it had been moved to
activity_count_runtime() for pure reasons of dependency loops. These
ones are no longer true so we can move that code back to the scheduler
and keep it where the information are updated and checked.
2021-10-01 18:37:51 +02:00
Willy Tarreau
6dfab112e1 REORG: sched: move idle time calculation from time.h to task.h
time.h is a horrible place to put activity calculation, it's a
historical mistake because the functions were there. We already have
most of the parts in sched.{c,h} and these ones make an exception in
the middle, forcing time.h to include some thread stuff and to access
the before/after_poll and idle_pct values.

Let's move these 3 functions to task.h with the other ones. They were
prefixed with "sched_" instead of the historical "tv_" which already
made no sense anymore.
2021-10-01 18:37:51 +02:00
Willy Tarreau
6136989a22 MINOR: time: uninline report_idle() and move it to task.c
I don't know why I inlined this one, this makes no sense given that it's
only used for stats, and it starts a circular dependency on tinfo.h which
can be problematic in the future. In addition, all the stuff related to
idle time calculation should be with the rest of the scheduler, which
currently is in task.{c,h}, so let's move it there.
2021-10-01 18:37:50 +02:00
Willy Tarreau
beeabf5314 MINOR: task: provide 3 task_new_* wrappers to simplify the API
We'll need to improve the API to pass other arguments in the future, so
let's start to adapt better to the current use cases. task_new() is used:
  - 18 times as task_new(tid_bit)
  - 18 times as task_new(MAX_THREADS_MASK)
  - 2 times with a single bit (in a loop)
  - 1 in the debug code that uses a mask

This patch provides 3 new functions to achieve this:
  - task_new_here()     to create a task on the calling thread
  - task_new_anywhere() to create a task to be run anywhere
  - task_new_on()       to create a task to run on a specific thread

The change is trivial and will allow us to later concentrate the
required adaptations to these 3 functions only. It's still possible
to call task_new() if needed but a comment was added to encourage the
use of the new ones instead. The debug code was not changed and still
uses it.
2021-10-01 18:36:29 +02:00
Willy Tarreau
6a2a912cb8 CLEANUP: tasks: remove the long-unused work_lists
Work lists were a mechanism introduced in 1.8 to asynchronously delegate
some work to be performed on another thread via a dedicated task.
The only user was the listeners, to deal with the queue. Nowadays
the tasklets have made this much more convenient, and have replaced
work_lists in the listeners. It seems there will be no valid use case
of work lists anymore, so better get rid of them entirely and keep the
scheduler code cleaner.
2021-10-01 18:30:14 +02:00
Willy Tarreau
7a9699916a MINOR: tasks: catch TICK_ETERNITY with BUG_ON() in __task_queue()
__task_queue() must absolutely not be called with TICK_ETERNITY or it
will place a never-expiring node upfront in the timers queue, preventing
any timer from expiring until the process is restarted. Code was found
to cause this using "task_schedule(task, now_ms)" which does this one
millisecond every 49.7 days, so let's add a condition against this. It
must never trigger since any process susceptible to trigger it would
already accumulate tasks until it dies.

An extra test was added in wake_expired_tasks() to detect tasks whose
timeout would have been changed after being queued.

An improvement over this could be in the future to use a non-scalar
type (union/struct) for expiration dates so as to avoid the risk of
using them directly like this. But now_ms is already such a valid
time and this specific construct would still not be caught.

This could even be backported to stable versions to help detect other
occurrences if any.
2021-09-30 17:09:39 +02:00
Remi Tricot-Le Breton
1fe0fad88b MINOR: ssl: Rename ssl_bc_hsk_err to ssl_bc_err
The ssl_bc_hsk_err sample fetch will need to raise more errors than only
handshake related ones hence its renaming to a more generic ssl_bc_err.
This patch is required because some handshake failures that should have
been caught by this fetch (verify error on the server side for instance)
were missed. This is caused by a change in TLS1.3 in which the
'Finished' state on the client is reached before its certificate is sent
(and verified) on the server side (see the "Protocol Overview" part of
RFC 8446).
This means that the SSL_do_handshake call is finished long before the
server can verify and potentially reject the client certificate.

The ssl_bc_hsk_err will then need to be expanded to catch other types of
errors.

This change is also applied to the frontend fetches (ssl_fc_hsk_err
becomes ssl_fc_err) and to their string counterparts.
2021-09-30 11:04:35 +02:00
Remi Tricot-Le Breton
61944f7a73 MINOR: ssl: Set connection error code in case of SSL read or write fatal failure
In case of a connection error happening after the SSL handshake is
completed, the error code stored in the connection structure would not
always be set, hence having some connection failures being described as
successful in the fc_conn_err or bc_conn_err sample fetches.
The most common case in which it could happen is when the SSL server
rejects the client's certificate. The SSL_do_handshake call on the
client side would be sucessful because the client effectively sent its
client hello and certificate information to the server, but the next
call to SSL_read on the client side would raise an SSL_ERROR_SSL code
(through the SSL_get_error function) which is decribed in OpenSSL
documentation as a non-recoverable and fatal SSL error.
This patch ensures that in such a case, the connection's error code is
set to a special CO_ERR_SSL_FATAL value.
2021-09-30 11:04:35 +02:00
Willy Tarreau
8de6dc9926 REORG: pools: move default settings to defaults.h
There's no reason CONFIG_HAP_POOLS and its opposite are located into
pools-t.h, it forces those that depend on them to inlcude the file.
Other similar options are normally dealt with in defaults.h, which is
part of the default API, so let's do that.
2021-09-28 19:31:16 +02:00
Christopher Faulet
545fbba273 MINOR: h1: Change T-E header parsing to fail if chunked encoding is found twice
According to the RFC7230, "chunked" encoding must not be applied more than
once to a message body. To handle this case, h1_parse_xfer_enc_header() is
now responsible to fail when a parsing error is found. It also fails if the
"chunked" encoding is not the last one for a request.

To help the parsing, two H1 parser flags have been added: H1_MF_TE_CHUNKED
and H1_MF_TE_OTHER. These flags are set, respectively, when "chunked"
encoding and any other encoding are found. H1_MF_CHNK flag is used when
"chunked" encoding is the last one.
2021-09-28 16:21:25 +02:00
Christopher Faulet
92cafb39e7 MINOR: http: Add 422-Unprocessable-Content error message
The last HTTP/1.1 draft adds the 422 status code in the list of client
errors. It normalizes the WebDav specific one (422-Unprocessable-Entity).
2021-09-28 16:21:25 +02:00
William Lallemand
3956c4ead2 MINOR: httpclient/lua: httpclient:get() API in lua
This commit provides an hlua_httpclient object which is a bridge between
the httpclient and the lua API.

The HTTPClient is callable in lua this way:

    local httpclient = core.httpclient()
    local response = httpclient:get("http://127.0.0.1:9000/?s=9999")
    core.Debug("Status: ".. res.status .. ", Reason : " .. res.reason .. ", Len:" .. string.len(res.body) .. "\n")

The resulting response object will provide a "status" field which
contains the status code, a "reason" string which contains the reason
string, and a "body" field which contains the response body.

The implementation uses the httpclient callback to wake up the lua task
which yield each time it pushes some data. The httpclient works in the
same thread as the lua task.
2021-09-24 14:29:36 +02:00
William Lallemand
1123dde6dd MINOR: httpclient: httpclient_ended() returns 1 if the client ended
httpclient_ended() returns 1 if there is no more data to collect,
because the client received everything or the connection ended.
2021-09-24 14:21:26 +02:00
William Lallemand
518878e007 MINOR: httpclient: httpclient_data() returns the available data
httpclient_data() returns the available data in the httpclient.
2021-09-24 14:21:26 +02:00
Christopher Faulet
564e39c4c6 MINOR: stream-int: Notify mux when the buffer is not stuck when calling rcv_buf
The transient flag CO_RFL_BUF_NOT_STUCK should now be set when the mux's
rcv_buf() function is called, in si_cs_recv(), to be sure the mux is able to
perform some optimisation during data copy. This flag is set when we are
sure the channel buffer is not stuck. Concretely, it happens when there are
data scheduled to be sent.

It is not a fix and this flag is not used for now. But it makes sense to have
this info to be sure to be able to do some optimisations if necessary.

This patch is related to the issue #1362. It may be backported to 2.4 to
ease future backports.
2021-09-23 16:25:47 +02:00
Christopher Faulet
361fbcc14a MINOR: htx: Add a function to know if the free space wraps
the htx_space_wraps() function may now be used to know if the free space of
an HTX message wraps. It does the same as b_space_wraps().
2021-09-23 16:19:36 +02:00
Christopher Faulet
4697c92c9d MINOR: htx: Add an HTX flag to know when a message is fragmented
HTX_FL_FRAGMENTED flag is now set on an HTX message when it is
fragmented. It happens when an HTX block is removed in the middle of the
message and flagged as unused. HTX_FL_FRAGMENTED flag is removed when all
data are removed from the message or when the message is defragmented.

Note that some optimisations are still possible because the flag can be
avoided in other situations. For instance when the last header of a bodyless
message is removed.
2021-09-23 16:19:36 +02:00
Christopher Faulet
7833596ff4 BUG/MEDIUM: stream: Stop waiting for more data if SI is blocked on RXBLK_ROOM
If the stream-interface is waiting for more buffer room to store incoming
data, it is important at the stream level to stop to wait for more data to
continue. Thanks to the previous patch ("BUG/MEDIUM: stream-int: Notify
stream that the mux wants more room to xfer data"), the stream is woken up
when this happens. In this patch, we take care to interrupt the
corresponding tcp-content ruleset or to stop waiting for the HTTP message
payload.

To ease detection of the state, si_rx_blocked_room() helper function has
been added. It returns non-zero if the stream interface's Rx path is blocked
because of lack of room in the input buffer.

This patch is part of a series related to the issue #1362. It should be
backported as ar as 2.0, probably with some adaptations. So be careful
during backports.
2021-09-23 16:18:07 +02:00
Christopher Faulet
df99408e0d BUG/MEDIUM: stream-int: Notify stream that the mux wants more room to xfer data
When the mux failed to transfer data to the upper layer because of a lack of
room, it is important to wake the stream up to let it handle this
event. Otherwise, if the stream is waiting for more data, both the stream
and the mux reamin blocked waiting for each other.

When this happens, the mux set the CS_FL_WANT_ROOM flag on the
conn-stream. Thus, in si_cs_recv() we are able to detect this event. Today,
the stream-interface is blocked. But, it is not enough to wake the stream
up. To fix the bug, CF_READ_PARTIAL flag is extended to also handle cases
where a read exception occurred. This flag should idealy be renamed. But for
now, it is good enough. By setting this flag, we are sure the stream will be
woken up.

This patch is part of a series related to the issue #1362. It should be
backported as far as 2.0, probably with some adaptations. So be careful
during backports.
2021-09-23 16:16:57 +02:00
Christopher Faulet
46e058dda5 BUG/MEDIUM: mux-h1: Adjust conditions to ask more space in the channel buffer
When a message is parsed and copied into the channel buffer, in
h1_process_demux(), more space is requested if some pending data remain
after the parsing while the channel buffer is not empty. To do so,
CS_FL_WANT_ROOM flag is set. It means the H1 parser needs more space in the
channel buffer to continue. In the stream-interface, when this flag is set,
the SI is considered as blocked on the RX path. It is only unblocked when
some data are sent.

However, it is not accurrate because the parsing may be stopped because
there is not enough data to continue. For instance in the middle of a chunk
size. In this case, some data may have been already copied but the parser is
blocked because it must receive more data to continue. If the calling SI is
blocked on RX at this stage when the stream is waiting for the payload
(because http-buffer-request is set for instance), the stream remains stuck
infinitely.

To fix the bug, we must request more space to the app layer only when it is
not possible to copied more data. Actually, this happens when data remain in
the input buffer while the H1 parser is in states MSG_DATA or MSG_TUNNEL, or
when we are unable to copy headers or trailers into a non-empty buffer.

The first condition is quite easy to handle. The second one requires an API
refactoring. h1_parse_msg_hdrs() and h1_parse_msg_tlrs() fnuctions have been
updated. Now it is possible to know when we need more space in the buffer to
copy headers or trailers (-2 is returned). In the H1 mux, a new H1S flag
(H1S_F_RX_CONGESTED) is used to track this state inside h1_process_demux().

This patch is part of a series related to the issue #1362. It should be
backported as far as 2.0, probably with some adaptations. So be careful
during backports.
2021-09-23 16:13:17 +02:00
Frédéric Lécaille
ebc3fc1509 CLEANUP: quic: Remove useless inline functions
We want to track the packet reference counting more easily, so without
inline functions.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
513b4f290a MINOR: quic: Implement quic_conn_subscribe()
We implement ->subscribe() xprt callback which should be used only by the mux.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
153194f47a MINOR: mux_quic: Export the mux related flags
These flags should be available from the xprt which must be able to
wake up the mux when blocked.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
c7c8764145 MINOR: quic: Wrong packet number space selection in quic_loss_pktns()
Ensure the tick is set for a packet number space loss time before
selecting it.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
d7d549c9b0 MINOR: quic: Wrong packet loss detection due to wrong pktns order
During the packet loss detection we must treat the paquet number
in this order Initial -> Handshake -> O1RTT. This was not the case
due to the chosen order to implement the array of packet number space
which was there before the packet loss detection implementation.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
682bb38c34 MINOR: quic_tls: Client/serveur state reordering
This is to ensure that expressions which compare the current
state with others are not polluted by the "handshake failed"
special state.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
eb6dfab889 MINOR: quic: Add a typedef for unsigned long long
As we manipulate very uint64_t variables which must be cast to
unsigned long long to be printed, let's add this useful type definition.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
785d3bdedc MINOR: quic: Make use of buffer structs to handle STREAM frames
The STREAM data to send coming from the upper layer must be stored until
having being acked by the peer. To do so, we store them in buffer structs,
one by stream (see qcs.tx.buf). Each time a STREAM is built by quic_push_frame(),
its offset must match the offset of the first byte added to the buffer (modulo
the size of the buffer) by the frame. As they are not always acknowledged in
order, they may be stored in eb_trees ordered by their offset to be sure
to sequentially delete the STREAM data from their buffer, in the order they
have been added to it.
2021-09-23 15:27:25 +02:00