Commit Graph

12588 Commits

Author SHA1 Message Date
Willy Tarreau
b4e34766a3 REORG: thread/sched: move the last dynamic thread_info to thread_ctx
The last 3 fields were 3 list heads that are per-thread, and which are:
  - the pool's LRU head
  - the buffer_wq
  - the streams list head

Moving them into thread_ctx completes the removal of dynamic elements
from the struct thread_info. Now all these dynamic elements are packed
together at a single place for a thread.
2021-10-08 17:22:26 +02:00
Willy Tarreau
a0b99536c8 REORG: thread/sched: move the thread_info flags to the thread_ctx
The TI_FL_STUCK flag is manipulated by the watchdog and scheduler
and describes the apparent life/death of a thread so it changes
all the time and it makes sense to move it to the thread's context
for an active thread.
2021-10-08 17:22:26 +02:00
Willy Tarreau
45c38e22bf REORG: thread/clock: move the clock parts of thread_info to thread_ctx
The "thread_info" name was initially chosen to store all info about
threads but since we now have a separate per-thread context, there is
no point keeping some of its elements in the thread_info struct.

As such, this patch moves prev_cpu_time, prev_mono_time and idle_pct to
thread_ctx, into the thread context, with the scheduler parts. Instead
of accessing them via "ti->" we now access them via "th_ctx->", which
makes more sense as they're totally dynamic, and will be required for
future evolutions. There's no room problem for now, the structure still
has 84 bytes available at the end.
2021-10-08 17:22:26 +02:00
Willy Tarreau
1a9c922b53 REORG: thread/sched: move the task_per_thread stuff to thread_ctx
The scheduler contains a lot of stuff that is thread-local and not
exclusively tied to the scheduler. Other parts (namely thread_info)
contain similar thread-local context that ought to be merged with
it but that is even less related to the scheduler. However moving
more data into this structure isn't possible since task.h is high
level and cannot be included everywhere (e.g. activity) without
causing include loops.

In the end, it appears that the task_per_thread represents most of
the per-thread context defined with generic types and should simply
move to tinfo.h so that everyone can use them.

The struct was renamed to thread_ctx and the variable "sched" was
renamed to "th_ctx". "sched" used to be initialized manually from
run_thread_poll_loop(), now it's initialized by ha_set_tid() just
like ti, tid, tid_bit.

The memset() in init_task() was removed in favor of a bss initialization
of the array, so that other subsystems can put their stuff in this array.

Since the tasklet array has TL_CLASSES elements, the TL_* definitions
was moved there as well, but it's not a problem.

The vast majority of the change in this patch is caused by the
renaming of the structures.
2021-10-08 17:22:26 +02:00
Willy Tarreau
6414e4423c CLEANUP: wdt: do not remap SI_TKILL to SI_LWP, test the values directly
We used to remap SI_TKILL to SI_LWP when SI_TKILL was not available
(e.g. FreeBSD) but that's ugly and since we need this only in a single
switch/case block in wdt.c it's even simpler and cleaner to perform the
two tests there, so let's do this.
2021-10-08 17:22:26 +02:00
Willy Tarreau
b474f43816 MINOR: wdt: move wd_timer to wdt.c
The watchdog timer had no more reason for being shared with the struct
thread_info since the watchdog is the only user now. Let's remove it
from the struct and move it to a static array in wdt.c. This removes
some ifdefs and the need for the ugly mapping to empty_t that might be
subject to a cast to a long when compared to TIMER_INVALID. Now timer_t
is not known outside of wdt.c and clock.c anymore.
2021-10-08 17:22:26 +02:00
Willy Tarreau
2169498941 MINOR: clock: move the clock_ids to clock.c
This removes the knowledge of clockid_t from anywhere but clock.c, thus
eliminating a source of includes burden. The unused clock_id field was
removed from thread_info, and the definition setting of clockid_t was
removed from compat.h. The most visible change is that the function
now_cpu_time_thread() now takes the thread number instead of a tinfo
pointer.
2021-10-08 17:22:26 +02:00
Willy Tarreau
6cb0c391e7 REORG: clock/wdt: move wdt timer initialization to clock.c
The code that deals with timer creation for the WDT was moved to clock.c
and is called with the few relevant arguments. This removes the need for
awareness of clock_id from wdt.c and as such saves us from having to
share it outside. The timer_t is also known only from both ends but not
from the public API so that we don't have to create a fake timer_t
anymore on systems which do not support it (e.g. macos).
2021-10-08 17:22:26 +02:00
Willy Tarreau
44c58da52f REORG: clock: move the clock_id initialization to clock.c
This was previously open-coded in run_thread_poll_loop(). Now that
we have clock.c dedicated to such stuff, let's move the code there
so that we don't need to keep such ifdefs nor to depend on the
clock_id.
2021-10-08 17:22:26 +02:00
Willy Tarreau
2c6a998727 CLEANUP: clock: stop exporting before_poll and after_poll
We don't need to export them anymore so let's make them static.
2021-10-08 17:22:26 +02:00
Willy Tarreau
20adfde9c8 MINOR: activity: get the run_time from the clock updates
Instead of fiddling with before_poll and after_poll in
activity_count_runtime(), the function is now called by
clock_entering_poll() which passes it the number of microseconds
spent working. This allows to remove all calls to
activity_count_runtime() from the pollers.
2021-10-08 17:22:26 +02:00
Willy Tarreau
f9d5e1079c REORG: clock: move the updates of cpu/mono time to clock.c
The entering_poll/leaving_poll/measure_idle functions that were hard
to classify and used to move to various locations have now been placed
into clock.c since it's precisely about time-keeping. The functions
were renamed to clock_*. The samp_time and idle_time values are now
static since there is no reason for them to be read from outside.
2021-10-08 17:22:26 +02:00
Willy Tarreau
5554264f31 REORG: time: move time-keeping code and variables to clock.c
There is currently a problem related to time keeping. We're mixing
the functions to perform calculations with the os-dependent code
needed to retrieve and adjust the local time.

This patch extracts from time.{c,h} the parts that are solely dedicated
to time keeping. These are the "now" or "before_poll" variables for
example, as well as the various now_*() functions that make use of
gettimeofday() and clock_gettime() to retrieve the current time.

The "tv_*" functions moved there were also more appropriately renamed
to "clock_*".

Other parts used to compute stolen time are in other files, they will
have to be picked next.
2021-10-08 17:22:26 +02:00
Willy Tarreau
28345c6652 BUILD: init: avoid a build warning on FreeBSD with USE_PROCCTL
It was brought by a variable declared after some statements in commit
21185970c ("MINOR: proc: setting the process to produce a core dump on
FreeBSD."). It's worth noting that some versions of clang seem to ignore
-Wdeclaration-after-statement by default. No backport is needed.
2021-10-08 17:21:48 +02:00
Amaury Denoyelle
eb01f597eb BUG/MINOR: quic: fix includes for compilation
Fix missing includes in quic code following the general recent include
reorganization. This fixes the compilation error with QUIC enabled.
2021-10-08 15:59:02 +02:00
Amaury Denoyelle
769e9ffd94 CLEANUP: mux-quic: remove unused code
Remove unused code in mux-quic. This is mostly code related to the
backend side. This code is untested for the moment, its removal will
simplify the code maintenance.
2021-10-08 15:48:00 +02:00
Amaury Denoyelle
9c8c4fa3a2 MINOR: qpack: fix memory leak on huffman decoding
Remove an unneeded strdup invocation during QPACK huffman decoding. A
temporary storage buffer is passed by the function and exists after
decoding so no need to duplicate memory here.
2021-10-08 15:45:57 +02:00
Amaury Denoyelle
3a590c7ff2 MINOR: qpack: support non-indexed http status code encoding
If a HTTP status code is not present in the QPACK static table, encode
it with a literal field line with name reference.
2021-10-08 15:30:18 +02:00
Amaury Denoyelle
fccffe08b3 MINOR: qpack: do not encode invalid http status code
Ensure that the HTTP status code is valid before encoding with QPACK. An
error is return if this is not the case.
2021-10-08 15:28:35 +02:00
Christopher Faulet
485da0b053 BUG/MEDIUM: mux_h2: Handle others remaining read0 cases on partial frames
We've found others places where the read0 is ignored because of an
incomplete frame parsing. This time, it happens during parsing of
CONTINUATION frames.

When frames are parsed, incomplete frames are properly handled and
H2_CF_DEM_SHORT_READ flag is set. It is also true for HEADERS
frames. However, for CONTINUATION frames, there is an exception. Besides
parsing the current frame, we try to peek header of the next one to merge
payload of both frames, the current one and the next one. Idea is to create
a sole HEADERS frame before parsing the payload. However, in this case, it
is possible to have an incomplete frame too, not the current one but the
next one. From the demux point of view, the current frame is complete. We
must go to the internal function h2c_decode_headers() to detect an
incomplete frame. And this case was not identified and fixed when
H2_CF_DEM_SHORT_READ flag was introduced in the commit b5f7b5296
("BUG/MEDIUM: mux-h2: Handle remaining read0 cases on partial frames")

This bug was reported in a comment of the issue #1362. The patch must be
backported as far as 2.0.
2021-10-08 09:17:27 +02:00
Amaury Denoyelle
2af1985af8 BUG/MAJOR: quic: remove qc from receiver cids tree on free
Remove the quic_conn from the receiver connection_ids tree on
quic_conn_free. This fixes a crash due to dangling references in the
tree after a quic connection release.

This operation must be conducted under the listener lock. For this
reason, the quic_conn now contains a reference to its attached listener.
2021-10-07 17:35:25 +02:00
Amaury Denoyelle
d595f108db MINOR: mux-quic: release connection if no more bidir streams
Use the count of bidirectional streams to call qc_release in qc_detach.
We cannot inspect the by_id tree because uni-streams are never removed
from it. This allows the connection to be properly freed.
2021-10-07 17:35:25 +02:00
Amaury Denoyelle
336f6fd964 BUG/MAJOR: xprt-quic: do not queue qc timer if not set
Do not queue the pto/loss-detection timer if set to TICK_ETERNITY. This
usage is invalid with the scheduler and cause a BUG_ON trigger.
2021-10-07 17:35:25 +02:00
Amaury Denoyelle
139814a67a BUG/MEDIUM: mux-quic: reinsert all streams in by_id tree
It is required that all qcs streams are in the by_id tree for the xprt
to function correctly. Without this, some ACKs are not properly emitted
by xprt.

Note that this change breaks the free of the connection because the
condition eb_is_empty in qc_detach is always true. This will be fixed in
a following patch.
2021-10-07 17:35:25 +02:00
Frédéric Lécaille
75dd2b7987 MINOR: quic: Fix SSL error issues (do not use ssl_bio_and_sess_init())
It seems it was a bad idea to use the same function as for TCP ssl sockets
to initialize the SSL session objects for QUIC with ssl_bio_and_sess_init().
Indeed, this had as very bad side effects to generate SSL errors due
to the fact that such BIOs initialized for QUIC could not finally be controlled
via the BIO_ctrl*() API, especially BIO_ctrl() function used by very much other
internal OpenSSL functions (BIO_push(), BIO_pop() etc).
Others OpenSSL base QUIC implementation do not use at all BIOs to configure
QUIC connections. So, we decided to proceed the same way as ngtcp2 for instance:
only initialize an SSL object and call SSL_set_quic_method() to set its
underlying method. Note that calling this function silently disable this option:
SSL_OP_ENABLE_MIDDLEBOX_COMPAT.
We implement qc_ssl_sess_init() to initialize SSL sessions for QUIC connections
to do so with a retry in case of allocation failure as this is done by
ssl_bio_and_sess_init(). We also modify the code part for haproxy servers.
2021-10-07 17:35:25 +02:00
Frédéric Lécaille
7c881bdab8 MINOR: quic: BUG_ON() SSL errors.
As this QUIC implementation is still experimental, let's BUG_ON()
very important SSL handshake errors.
Also dump the SSL errors before BUG_ON().
2021-10-07 17:35:25 +02:00
Frédéric Lécaille
6f0fadb5a7 MINOR: quic: Add a function to dump SSL stack errors
This has been very helpful to fix SSL related issues.
2021-10-07 17:35:25 +02:00
Frédéric Lécaille
57e6e9eef8 MINOR: quic: Distinguish packet and SSL read enc. level in traces
This is only to distinguish the encryption level of packet traces from
the TLS stack current read encryption level.
2021-10-07 17:35:25 +02:00
Willy Tarreau
1b4a714266 MINOR: pools: report the amount used by thread caches in "show pools"
The "show pools" command provides some "allocated" and "used" estimates
on the pools objects, but this applies to the shared pool and the "used"
includes what is currently assigned to thread-local caches. It's possible
to know how much each thread uses, so let's dump the total size allocated
by thread caches as an estimate. It's only done when pools are enabled,
which explains why the patch adds quite a lot of ifdefs.
2021-10-07 17:30:06 +02:00
Willy Tarreau
aa992761d8 CLEANUP: thread: uninline ha_tkill/ha_tkillall/ha_cpu_relax()
These ones are rarely used or only to waste CPU cycles waiting, and are
the last ones requiring system includes in thread.h. Let's uninline them
and move them to thread.c.
2021-10-07 01:41:15 +02:00
Willy Tarreau
5e03dfaaf6 MINOR: thread: use a dedicated static pthread_t array in thread.c
This removes the thread identifiers from struct thread_info and moves
them only in static array in thread.c since it's now the only file that
needs to touch it. It's also the only file that needs to include
pthread.h, beyond haproxy.c which needs it to start the poll loop. As
a result, much less system includes are needed and the LoC reduced by
around 3%.
2021-10-07 01:41:15 +02:00
Willy Tarreau
4eeb88363c REORG: thread: move ha_get_pthread_id() to thread.c
It's the last function which directly accesses the pthread_t, let's move
it to thread.c and leave a static inline for non-thread.
2021-10-07 01:41:14 +02:00
Willy Tarreau
d10385ac4b REORG: thread: move the thread init/affinity/stop to thread.c
haproxy.c still has to deal with pthread-specific low-level stuff that
is OS-dependent. We should not have to deal with this there, and we do
not need to access pthread anywhere else.

Let's move these 3 functions to thread.c and keep empty inline ones for
when threads are disabled.
2021-10-07 01:41:14 +02:00
Willy Tarreau
19b18ad552 CLENAUP: wdt: use ha_tkill() instead of accessing pthread directly
Instead of calling pthread_kill() directly on the pthread_t let's
call ha_tkill() which does the same by itself. This will help isolate
pthread_t.
2021-10-07 01:41:14 +02:00
Willy Tarreau
b63888c67c REORG: fd: uninline compute_poll_timeout()
It's not needed to inline it at all (one call per loop) and it introduces
dependencies, let's move it to fd.c.

Removing the few remaining includes that came with it further reduced
by ~0.2% the LoC and the build time is now below 6s.
2021-10-07 01:41:14 +02:00
Willy Tarreau
d8b325c748 REORG: task: uninline the loop time measurement code
It's pointless to inline this, it's called exactly once per poll loop,
and it depends on time.h which is quite deep. Let's move that to task.c
along with sched_report_idle().
2021-10-07 01:41:14 +02:00
Willy Tarreau
8de90c71b3 REORG: connection: uninline the rest of the alloc/free stuff
The remaining large functions are those allocating/initializing and
occasionally freeing connections, conn_streams and sockaddr. Let's
move them to connection.c. In fact, cs_free() is the only one-liner
but let's move it along with the other ones since a call will be
small compared to the rest of the work done there.
2021-10-07 01:41:14 +02:00
Willy Tarreau
aac777f169 REORG: connection: move the largest inlines from connection.h to connection.c
The following inlined functions are particularly large (and probably not
inlined at all by the compiler), and together represent roughly half of
the file, while they're used at most once per connection. They were moved
to connection.c.

  conn_upgrade_mux_fe, conn_install_mux_fe, conn_install_mux_be,
  conn_install_mux_chk, conn_delete_from_tree, conn_init, conn_new,
  conn_free
2021-10-07 01:41:14 +02:00
Willy Tarreau
260f324c19 REORG: server: uninline the idle conns management functions
The following functions are quite heavy and have no reason to be kept
inlined:

   srv_release_conn, srv_lookup_conn, srv_lookup_conn_next,
   srv_add_to_idle_list

They were moved to server.c. It's worth noting that they're a bit
at the edge between server and connection and that maybe we could
create an idle-conn file for these in the near future.
2021-10-07 01:41:14 +02:00
Willy Tarreau
930428c0bf REORG: connection: uninline conn_notify_mux() and conn_delete_from_tree()
The former is far too huge to be inlined and the second is the only
one requiring an ebmb tree through all includes, let's move them to
connection.c.
2021-10-07 01:41:14 +02:00
Willy Tarreau
e5983ffb3a REORG: connection: move the hash-related stuff to connection.c
We do not really need to have them inlined, and having xxhash.h included
by connection.h results in this 4700-lines file being processed 101 times
over the whole project, which accounts for 13.5% of the total size!
Additionally, half of the functions are only needed from connection.c.
Let's move the functions there and get rid of the painful include.

The build time is now down to 6.2s just due to this.
2021-10-07 01:41:14 +02:00
Willy Tarreau
fd21c6c6fd MINOR: connection: use uint64_t for the hashes
The hash type stored everywhere is XXH64_hash_t, which annoyingly forces
everyone to include the huge xxhash file. We know it's an uint64_t because
that's its purpose and the type is only made to abstract it on machines
where uint64_t is not availble. Let's switch the type to uint64_t
everywhere and avoid including xxhash from the type file.
2021-10-07 01:41:14 +02:00
Willy Tarreau
a26be37e20 REORG: acitvity: uninline sched_activity_entry()
This one is expensive in code size because it comes with xxhash.h at a
low level of dependency that's inherited at plenty of places, and for
a function does doesn't benefit from inlining and could possibly even
benefit from not being inline given that it's large and called from the
scheduler.

Moving it to activity.c reduces the LoC by 1.2% and the binary size by
~1kB.
2021-10-07 01:41:14 +02:00
Willy Tarreau
e0650224b8 REORG: activity: uninline activity_count_runtime()
This function has no reason for being inlined, it's called from non
critical places (once in pollers), is quite large and comes with
dependencies (time and freq_ctr). Let's move it to acitvity.c. That's
another 0.4% less LoC to build.
2021-10-07 01:41:14 +02:00
Willy Tarreau
9310f481ce CLEANUP: tree-wide: remove unneeded include time.h in ~20 files
20 files used to have haproxy/time.h included only for now_ms, and two
were missing it for other things but used to inherit from it via other
files.
2021-10-07 01:41:14 +02:00
Willy Tarreau
078c2573c2 REORG: sched: moved samp_time and idle_time to task.c as well
The idle time calculation stuff was moved to task.h by commit 6dfab112e
("REORG: sched: move idle time calculation from time.h to task.h") but
these two variables that are only maintained by task.{c,h} were still
left in time.{c,h}. They have to move as well.
2021-10-07 01:41:14 +02:00
Willy Tarreau
99ea188c0e REORG: sample: move the crypto samples to ssl_sample.c
These ones require openssl and are only built when it's enabled. There's
no point keeping them in sample.c when ssl_sample.c already deals with this
and the required includes. This also allows to remove openssl-compat.h
from sample.c and to further reduce the number of inclusions of openssl
includes, and the build time is now down to under 8 seconds.
2021-10-07 01:41:14 +02:00
Willy Tarreau
82531f6730 REORG: ssl-sock: move the sslconns/totalsslconns counters to global
These two counters were the only ones not in the global struct, while
the SSL freq counters or the req counts are already in it, this forces
stats.c to include ssl_sock just to know about them. Let's move them
over there with their friends. This reduces from 408 to 384 the number
of includes of opensslconf.h.
2021-10-07 01:41:14 +02:00
Willy Tarreau
a8a72c68d5 CLEANUP: ssl/server: move ssl_sock_set_srv() to srv_set_ssl() in server.c
This one has nothing to do with ssl_sock as it manipulates the struct
server only. Let's move it to server.c and remove unneeded dependencies
on ssl_sock.h. This further reduces by 10% the number of includes of
opensslconf.h and by 0.5% the number of compiled lines.
2021-10-07 01:41:06 +02:00
Willy Tarreau
d2ae3858e9 CLEANUP: mux_fcgi: remove dependency on ssl_sock
It's not needed anymore (used to be needed for ssl_sock_is_ssl()).
2021-10-07 01:36:51 +02:00
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
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
dced3ebb4a MINOR: thread/debug: replace nsec_now() with now_mono_time()
The two functions do exactly the same except that the second one
is already provided by time.h and still defined if not available.
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
5d9ddc5442 BUILD: tree-wide: add several missing activity.h
A number of files currently access activity counters but rely on their
definitions to be inherited from other files (task.c, backend.c hlua.c,
sock.c, pool.c, stats.c, fd.c).
2021-10-07 01:36:51 +02:00
Willy Tarreau
410e2590e9 BUILD: mworker: mworker-prog needs time.h for the 'now' variable
It wasn't included and it used to get them through other includes.
2021-10-07 01:36:51 +02:00
Willy Tarreau
6cd007d078 BUILD: tcp_sample: include missing errors.h and session-t.h
Both are used without being defined as they were inherited from other
files.
2021-10-07 01:36:51 +02:00
Willy Tarreau
0d1dd0e894 BUILD: cfgparse-ssl: add missing errors.h
ha_warning(), ha_alert() and friends are in errors.h and it used
to be inherited via other files.
2021-10-07 01:36:51 +02:00
Willy Tarreau
b7fc4c4e9f BUILD: tree-wide: add missing http_ana.h from many places
At least 6 files make use of s->txn without including http_ana which
defines it. They used to get it from other includes.
2021-10-07 01:36:51 +02:00
Willy Tarreau
63617dbec6 BUILD: idleconns: include missing ebmbtree.h at several places
backend.c, all muxes, backend.c started manipulating ebmb_nodes with
the introduction of idle conns but the types were inherited through
other includes. Let's add ebmbtree.h there.
2021-10-07 01:36:51 +02:00
Willy Tarreau
74f2456c42 BUILD: ssl_ckch: include ebpttree.h in ssl_ckch.c
It's used but is only found through other includes.
2021-10-07 01:36:51 +02:00
Willy Tarreau
8db34cc974 BUILD: peers: need to include eb{32/mb/pt}tree.h
peers.c uses them all and used to only find them through other includes.
2021-10-07 01:36:51 +02:00
Willy Tarreau
b555eb1176 BUILD: vars: need to include xxhash
It's needed for XXH3(), and it used to get it through other includes.
2021-10-07 01:36:51 +02:00
Willy Tarreau
0ce6dc0107 BUILD: http_rules: requires http_ana-t.h for REDIRECT_*
It used to inherit it through other includes.
2021-10-07 01:36:51 +02:00
Willy Tarreau
286631a1a0 BUILD: sample: include openssl-compat
It's needed for EVP_*.
2021-10-07 01:36:51 +02:00
Willy Tarreau
1df20428f1 BUILD: httpclient: include missing ssl_sock-t
It's needed for SSL_SOCK_VERIFY_NONE.
2021-10-07 01:36:51 +02:00
Willy Tarreau
27539409fd BUILD: hlua: needs to include stream-t.h
It uses the SF_ERR_* error codes and currently gets them via
intermediary includes.
2021-10-07 01:36:51 +02:00
Willy Tarreau
397ad4135a BUILD: extcheck: needs to include stream-t.h
It uses the SF_ERR_* error codes and currently gets them via
intermediary includes.
2021-10-07 01:36:51 +02:00
Willy Tarreau
2476ff102f BUG/MEDIUM: sample: properly verify that variables cast to sample
The various variable-to-sample converters allow to turn a variable to
a sample of type string, sint or binary, but both the string one used
by strcmp() and the binary one used by secure_memcmp() are missing a
pointer check on the ability to the cast, making them crash if a
variable of type addr is used with strcmp(), or if an addr or bool is
used with secure_memcmp().

Let's rely on the new sample_conv_var2smp() function to run the proper
checks.

This will need to be backported to all supported version. It relies on
previous commits:

  CLEANUP: server: always include the storage for SSL settings
  CLEANUP: sample: rename sample_conv_var2smp() to *_sint
  CLEANUP: sample: uninline sample_conv_var2smp_str()
  MINOR: sample: provide a generic var-to-sample conversion function

For backports it's probably easier to check the sample_casts[] pointer
before calling it in sample_conv_strcmp() and sample_conv_secure_memcmp().
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
746e6f3f8e MINOR: httpclient/lua: supports headers via named arguments
Migrate the httpclient:get() method to named arguments so we can
specify optional arguments.

This allows to pass headers as an optional argument as an array.

The () in the method call must be replaced by {}:

	local res = httpclient:get{url="http://127.0.0.1:9000/?s=99",
	            headers= {["X-foo"]  = { "salt" }, ["X-bar"] = {"pepper" }}}
2021-10-06 15:21:02 +02:00
William Lallemand
ef574b2101 BUG/MINOR: httpclient/lua: does not process headers when failed
Do not try to process the header list when it is NULL. This case can
arrive when the request failed and did not return a response.
2021-10-06 15:15:03 +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
4d60184887 BUG/MEDIUM: httpclient/lua: crash because of b_xfer and get_trash_chunk()
When using the lua httpclient, haproxy could crash because a b_xfer is
done in httpclient_xfer, which will do a zero-copy swap of the data in
the buffers. The ptr will then be free() by the pool.

However this can't work with a trash buffer, because the area was not
allocated from the pool buffer, so the pool is not suppose to free it
because it does not know this ptr, using -DDEBUG_MEMORY_POOLS will
result with a crash during the free.

Fix the problem by using b_force_xfer() instead of b_xfer which copy
the data instead. The problem still exist with the trash however, and
the trash API must be reworked.
2021-10-06 15:15:03 +02:00
William Lallemand
f77f1de802 MINOR: httpclient/lua: implement garbage collection
Implement the garbage collector of the lua httpclient.

This patch declares the __gc method of the httpclient object which only
does a httpclient_stop_and_destroy().
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
William Lallemand
739f90a6ef MINOR: httpclient: set HTTPCLIENT_F_ENDED only in release
Only set the HTTPCLIENT_F_ENDED flag in httpclient_applet_release()
function so we are sure that the appctx is not used anymore once the
flag is set.
2021-10-06 15:15:03 +02:00
William Lallemand
03f5a1c77d MINOR: httpclient: destroy() must free the headers and the ists
httpclient_destroy() must free all the ist in the httpclient structure,
the URL in the request, the vsn and reason in the response.

It also must free the list of headers of the response.
2021-10-06 15:15:03 +02:00
Christopher Faulet
d34758849e BUG/MEDIUM: http-ana: Clear request analyzers when applying redirect rule
A bug was introduced by the commit 2d5650082 ("BUG/MEDIUM: http-ana: Reset
channels analysers when returning an error").

The request analyzers must be cleared when a redirect rule is applied. It is
not a problem if the redirect rule is inside an http-request ruleset because
the analyzer takes care to clear it. However, when it comes from a redirect
ruleset (via the "redirect ..."  directive), because of the above commit,
the request analyzers are no longer cleared. It means some HTTP request
analyzers may be called while the request channel was already flushed. It is
totally unexpected and may lead to crash.

Thanks to Yves Lafon for reporting the problem.

This patch must be backported everywhere the above commit was backported.
2021-10-04 14:32:02 +02:00
Christopher Faulet
d28b2b2352 BUG/MEDIUM: filters: Fix a typo when a filter is attached blocking the release
When a filter is attached to a stream, the wrong FLT_END analyzer is added
on the request channel. AN_REQ_FLT_END must be added instead of
AN_RES_FLT_END. Because of this bug, the stream may hang on the filter
release stage.

It seems to be ok for HTTP filters (cache & compression) in HTTP mode. But
when enabled on a TCP proxy, the stream is blocked until the client or the
server timeout expire because data forwarding is blocked. The stream is then
prematurely aborted.

This bug was introduced by commit 26eb5ea35 ("BUG/MINOR: filters: Always set
FLT_END analyser when CF_FLT_ANALYZE flag is set"). The patch must be
backported in all stable versions.
2021-10-04 08:28:44 +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
Christopher Faulet
cb59e0bc3c BUG/MINOR: tcp-rules: Stop content rules eval on read error and end-of-input
For now, tcp-request and tcp-response content rules evaluation is
interrupted before the inspect-delay when the channel's buffer is full, the
RX path is blocked or when a shutdown for reads was received. To sum up, the
evaluation is interrupted when no more input data are expected. However, it
is not exhaustive. It also happens when end of input is reached (CF_EOI flag
set) or when a read error occurred (CF_READ_ERROR flag set).

Note that, AFAIK, it is only a problem on HAProy 2.3 and prior when a H1 to
H2 upgrade is performed. On newer versions, it works as expected because the
stream is not created at this stage.

This patch must be backported as far as 2.0.
2021-09-30 16:37:29 +02:00
Christopher Faulet
eaba25dd97 BUG/MINOR: tcpcheck: Don't use arg list for default proxies during parsing
During tcp/http check rules parsing, when a sample fetch or a log-format
string is parsed, the proxy's argument list used to track unresolved
argument is no longer passed for default proxies. It means it is no longer
possible to rely on sample fetches depending on the execution context (for
instance 'nbsrv').

It is important to avoid HAProxy crashes because these arguments are
resolved during the configuration validity check. But, default proxies are
not evaluated during this stage. Thus, these arguments remain unresolved.

It will probably be possible to relax this rule. But to ease backports, it
is forbidden for now.

This patch must be backported as far as 2.2. It depends on the commit
"MINOR: arg: Be able to forbid unresolved args when building an argument
list".  It must be adapted for the 2.3 because PR_CAP_DEF capability was
introduced in the 2.4. A solution may be to test The proxy's id agains NULL.
2021-09-30 16:37:05 +02:00
Christopher Faulet
35926a16ac MINOR: arg: Be able to forbid unresolved args when building an argument list
In make_arg_list() function, unresolved dependencies are pushed in an
argument list to be resolved later, during the configuration validity
check. It is now possible to forbid such unresolved dependencies by omitting
<al> parameter (setting it to NULL). It is usefull when the parsing context
is not the same than the running context or when the parsing context is lost
after the startup stage. For instance, an argument may be defined in
defaults section during parsing and executed in a frontend/backend section.
2021-09-30 16:37:05 +02:00
Willy Tarreau
e3957f83e0 BUG/MAJOR: lua: use task_wakeup() to properly run a task once
The Lua tasks registered vi core.register_task() use a dangerous
task_schedule(task, now_ms) to start them, that will most of the
time work by accident, except when the time wraps every 49.7 days,
if now_ms is 0, because it's not valid to queue a task with an
expiration date set to TICK_ETERNITY, as it will fail all wakeup
checks and prevent all subsequent timers from being seen as expired.
The only solution in this case is to restart the process.

Fortunately for the vast majority of users it is extremely unlikely
to ever be met (only one millisecond every 49.7 days is at risk), but
this can be systematic for a process dealing with 1000 req/s, hence
the major tag.

The bug was introduced in 1.6-dev with commit 24f335340 ("MEDIUM: lua:
add coroutine as tasks."), so the fix must be backported to all stable
branches.
2021-09-30 16:26:51 +02:00
Willy Tarreau
12c02701d3 BUG/MEDIUM: lua: fix wakeup condition from sleep()
A time comparison was wrong in hlua_sleep_yield(), making the sleep()
code do nothing for periods of 24 days every 49 days. An arithmetic
comparison was performed on now_ms instead of using tick_is_expired().

This bug was added in 1.6-dev by commit 5b8608f1e ("MINOR: lua: core:
add sleep functions") so the fix should be backported to all stable
versions.
2021-09-30 16:26:51 +02:00
Remi Tricot-Le Breton
9543d5ad5b MINOR: ssl: Store the last SSL error code in case of read or write failure
In case of error while calling a SSL_read or SSL_write, the
SSL_get_error function is called in order to know more about the error
that happened. If the error code is SSL_ERROR_SSL or SSL_ERROR_SYSCALL,
the error queue might contain more information on the error. This error
code was not used until now. But we now need to store it in order for
backend error fetches to catch all handshake related errors.

The change was required because the previous backend fetch would not
have raised anything if the client's certificate was rejected by the
server (and the connection interrupted). This happens because starting
from TLS1.3, the 'Finished' state on the client is reached before its
certificate is sent to the server (see the "Protocol Overview" part of
RFC 8446). The only place where we can detect that the server rejected the
certificate is after the first SSL_read call after the SSL_do_handshake
function.

This patch then adds an extra ERR_peek_error after the SSL_read and
SSL_write calls in ssl_sock_to_buf and ssl_sock_from_buf. This means
that it could set an error code in the SSL context a long time after the
handshake is over, hence the change in the error fetches.
2021-09-30 11:04:35 +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
Christopher Faulet
da3adebd06 BUG/MEDIUM: mux-h1/mux-fcgi: Reject messages with unknown transfer encoding
HAproxy only handles "chunked" encoding internally. Because it is a gateway,
we stated it was not a problem if unknown encodings were applied on a
message because it is the recipient responsibility to accept the message or
not. And indeed, it is not a problem if both the client and the server
connections are using H1. However, Transfer-Encoding headers are dropped
from H2 messages. It is not a problem for chunk-encoded payload because
dechunking is performed during H1 parsing. But, for any other encodings, the
xferred H2 message is invalid.

It is also a problem for internal payload manipulations (lua,
filters...). Because the TE request headers are now sanitiezd, unsupported
encoding should not be used by servers. Thus it is only a problem for the
request messages. For this reason, such messages are now rejected. And if a
server decides to use an unknown encoding, the response will also be
rejected.

Note that it is pretty uncommon to use other encoding than "chunked" on the
request payload. So it is not necessary to backport it.

This patch should fix the issue #1301. No backport is needed.
2021-09-28 16:39:47 +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
Christopher Faulet
f56e8465f0 BUG/MINOR: mux-h1/mux-fcgi: Sanitize TE header to only send "trailers"
Only chunk-encoded response payloads are supported by HAProxy. All other
transfer encodings are not supported and will be an issue if the HTTP
compression is enabled. So be sure only "trailers" is send in TE request
headers.

The patch is related to the issue #1301. It must be backported to all stable
versions. Be carefull for 2.0 and lower because the HTTP legacy must also be
fixed.
2021-09-28 16:21:25 +02:00
Christopher Faulet
631c7e8665 MEDIUM: h1: Force close mode for invalid uses of T-E header
Transfer-Encoding header is not supported in HTTP/1.0. However, softwares
dealing with HTTP/1.0 and HTTP/1.1 messages may accept it and transfer
it. When a Content-Length header is also provided, it must be
ignored. Unfortunately, this may lead to vulnerabilities (request smuggling
or response splitting) if an intermediary is only implementing
HTTP/1.0. Because it may ignore Transfer-Encoding header and only handle
Content-Length one.

To avoid any security issues, when Transfer-Encoding and Content-Length
headers are found in a message, the close mode is forced. The same is
performed for HTTP/1.0 message with a Transfer-Encoding header only. This
change is conform to what it is described in the last HTTP/1.1 draft. See
also httpwg/http-core#879.

Note that Content-Length header is also removed from any incoming messages
if a Transfer-Encoding header is found. However it is not true (not yet) for
responses generated by HAProxy.
2021-09-28 16:21:25 +02:00
Christopher Faulet
e136bd12a3 MEDIUM: mux-h1: Reject HTTP/1.0 GET/HEAD/DELETE requests with a payload
This kind of requests is now forbidden and rejected with a
413-Payload-Too-Large error.

It is unexpected to have a payload for GET/HEAD/DELETE requests. It is
explicitly allowed in HTTP/1.1 even if some servers may reject such
requests. However, HTTP/1.0 is not clear on this point and some old servers
don't expect any payload and never look for body length (via Content-Length
or Transfer-Encoding headers).

It means that some intermediaries may properly handle the payload for
HTTP/1.0 GET/HEAD/DELETE requests, while some others may totally ignore
it. That may lead to security issues because a request smuggling attack is
possible.

To prevent any issue, those requests are now rejected.

See also httpwg/http-core#904
2021-09-28 16:21:11 +02:00
Christopher Faulet
b3230f76e8 MINOR: mux-h1: Be able to set custom status code on parsing error
When a parsing error is triggered, the status code may be customized by
setting H1C .errcode field. By default a 400-Bad-Request is returned. The
function h1_handle_bad_req() has been renamed to h1_handle_parsing_error()
to be more generic.
2021-09-28 16:18:17 +02:00
Christopher Faulet
36e46aa28c MINOR: mux-h1: Set error code if possible when MUX_EXIT_STATUS is returned
In h1_ctl(), if output parameter is provided when MUX_EXIT_STATUS is
returned, it is used to set the error code. In addition, any client errors
(4xx), except for 408 ones, are handled as invalid errors
(MUX_ES_INVALID_ERR). This way, it will be possible to customize the parsing
error code for request messages.
2021-09-28 16:17:59 +02:00
Christopher Faulet
a015b3ec8b MINOR: log: Try to get the status code when MUX_EXIT_STATUS is retrieved
The mux .ctl callback can provide some information about the mux to the
caller if the third parameter is provided. Thus, when MUX_EXIT_STATUS is
retrieved, a pointer on the status is now passed. The mux may fill it. It
will be pretty handy to provide custom error code from h1 mux instead of
default ones (400/408/500/501).
2021-09-28 13:52:25 +02:00
Willy Tarreau
2d5d4e0c3e MINOR: init: extract the setup and end of threads to their own functions
The startup code was still ugly with tons of unreadable nested ifdefs.
Let's just have one function to set up the extra threads and another one
to wait for their completion. The ifdefs are isolated into their own
functions now and are more readable, just like the end of main(), which
now uses the same statements to start thread 0 with and without threads.
2021-09-28 11:44:31 +02:00
Willy Tarreau
fb641d7af0 MEDIUM: init: de-uglify the per-thread affinity setting
Till now the threads startup was quite messy:
  - we would start all threads but one
  - then we would change all threads' CPU affinities
  - then we would manually start the poll loop for the current thread

Let's change this by moving the CPU affinity setting code to a function
set_thread_cpu_affinity() that does this job for the current thread only,
and that is called during the thread's initialization in the polling loop.

It takes care of not doing this for the master, and will result in all
threads to be properly bound earlier and with cleaner code. It also
removes some ugly nested ifdefs.
2021-09-28 11:42:19 +02:00
Willy Tarreau
2a30f4d87e CLEANUP: init: remove useless test against MAX_THREADS in affinity loop
The test i < MAX_THREADS is pointless since the loop boundary is bound
to global.nbthread which is already not greater.
2021-09-28 09:56:44 +02:00
Willy Tarreau
51ec03a61d MINOR: config: use a standard parser for the "nbthread" keyword
Probably because of some copy-paste from "nbproc", "nbthread" used to
be parsed in cfgparse instead of using a registered parser. Let's fix
this to clean up the code base now.
2021-09-27 09:47:40 +02:00
William Lallemand
614e68337d BUG/MEDIUM: httpclient: replace ist0 by istptr
ASAN reported a buffer overflow in the httpclient. This overflow is the
consequence of ist0() which is incorrect here.

Replace all occurences of ist0() by istptr() which is more appropried
here since all ist in the httpclient were created from strings.
2021-09-26 18:19:55 +02:00
William Lallemand
4a4e663771 Revert "head-truc"
This reverts commit fe67e091859b07dca4622981a8d98a0b64de3cab.

Revert a development/test patch which was accidentely introduced.
2021-09-24 19:19:37 +02:00
William Lallemand
7d21836bc6 head-truc 2021-09-24 19:05:41 +02:00
Tim Duesterhus
eaf16fcb53 CLEANUP: slz: Mark reset_refs as static
This function has no prototype and is not used outside of slz.c.
2021-09-24 15:07:50 +02:00
William Lallemand
79416cbd7a BUG/MINOR: httpclient/lua: return an error on argument check
src/hlua.c:7074:6: error: variable 'url_str' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized]
        if (lua_type(L, -1) == LUA_TSTRING)
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/hlua.c:7079:36: note: uninitialized use occurs here
        hlua_hc->hc->req.url = istdup(ist(url_str));
                                          ^~~~~~~

Return an error on the stack if the argument is not a string.
2021-09-24 14:57:15 +02:00
William Lallemand
d7df73a114 MINOR: httpclient/lua: implement the headers in the response object
Provide a new field "headers" in the response of the HTTPClient, which
contains all headers of the response.

This field is a multi-dimensionnal table which could be represented this
way in lua:

    headers = {
       ["content-type"] = { "text/html" },
       ["cache-control"] = { "no-cache" }
    }
2021-09-24 14:29:36 +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
Thierry Fournier
b6b1cdeae4 CLEANUP: stats: Fix some alignment mistakes
This patch fix some broken alignements. Code is not modified
The command `git show -w` whows nothing.
2021-09-24 08:52:45 +02:00
Thierry Fournier
e9ed63e548 MINOR: stats: Enable dark mode on stat web page
According with the W3 CSS specification, media queries 5 allow
the browser to enable some CSS when dark mode is enabled. This
patch defines dark mode CSS for the stats page.

https://www.w3.org/TR/mediaqueries-5/#prefers-color-scheme
2021-09-24 08:27:40 +02:00
Dragan Dosen
9a006f9641 BUG/MINOR: http-ana: increment internal_errors counter on response error
A bug was introduced in the commit cff0f739e5 ("MINOR: counters: Review
conditions to increment counters from analysers"). The internal_errors
counter for the target server was incremented twice. The counter for the
session listener needs to be incremented instead.

This must be backported everywhere the commit cff0f739e5 is.
2021-09-23 16:25:47 +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
2bc364c191 BUG/MEDIUM: stream-int: Defrag HTX message in si_cs_recv() if necessary
The stream interface is now responsible for defragmenting the HTX message of
the input channel if necessary, before calling the mux's .rcv_buf()
function. The defrag is performed if the underlying buffer contains only
input data while the HTX message free space is not contiguous.

The defrag is important here to be sure the mux and the app layer have the
same criteria to decide if a buffer is full or not. Otherwise, the app layer
may wait for more data because the buffer is not full while the mux is
blocked because it needs more space to proceed.

This patch depends on following commits:

  * MINOR: htx: Add an HTX flag to know when a message is fragmented
  * MINOR: htx: Add a function to know if the free space wraps

This patch is related to the issue #1362. It may be backported as far as 2.0
after some observation period (not sure it is required or not).
2021-09-23 16:25:16 +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
68a14db573 MINOR: stream-int: Set CO_RFL transient/persistent flags apart in si_cs_rcv()
In si_cs_recv(), some CO_RFL flags are set when the mux's .rcv_buf()
function is called. Some are persitent inside si_cs_recv() scope, some
others must be computed at each call to rcv_buf(). This patch takes care of
distinguishing them.

Among others, CO_RFL_KEEP_RECV is a persistent flag while CO_RFL_BUF_WET is
transient.
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
Christopher Faulet
216d3352b1 BUG/MINOR: h1-htx: Fix a typo when request parser is reset
In h1_postparse_req_hdrs(), if we need more space to copy headers, the request
parser is reset. However, because of a typo, it was reset as a response parser
instead of a request one. h1m_init_req() must be called.

This patch must be backported as far as 2.2.
2021-09-23 16:10:36 +02:00
Amaury Denoyelle
cde911231e MINOR: quic: fix qcc subs initialization 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
cd28b27581 MEDIUM: quic: implement mux release/conn free 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
414cac5f9d MINOR: quic: define close handler 2021-09-23 15:27:25 +02:00
Frédéric Lécaille
865b07855e MINOR: quic: Crash upon too big packets receipt
This bug came with this commit:
    ("MINOR: quic: RX packets memory leak")
Too big packets were freed twice.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
3230bcfdc4 MINOR: quic: Possible endless loop in qc_treat_rx_pkts()
Ensure we do not endlessly treat always the same encryption level
in qc_treat_rx_pkts().
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
310d1bd08f MINOR: quic: RX packets memory leak
Missing RX packet reference counter decrementation at the lowest level.
This leaded the memory reserved for RX packets to never be released.
2021-09-23 15:27:25 +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
8526f14acd MINOR: quic: Wake up the xprt from mux
We wake up the xprt as soon as STREAM frames have been pushed to
the TX mux buffer (->tx.buf).
We also make the mux subscribe() to the xprt layer if some data
remain in its ring buffer after having try to transfer them to the
xprt layer (TX mux buffer for the stream full).
Also do not consider a buffer in the ring if not allocated (see b_size(buf))
condition in the for(;;) loop.
Make a call to qc_process_mux() if possible when entering qc_send() to
fill the mux with data from streams in the send or flow control lists.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
1d40240f25 MINOR: quic: Implement qc_process_mux()
At this time, we only add calls to qc_resume_each_sending_qcs()
which handle the flow control and send lists.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
d2ba0967b7 MINOR: quic: Stream FIN bit fix in qcs_push_frame()
The FIN of a STREAM frame to be built must be set if there is no more
at all data in the ring buffer.
Do not do anything if there is nothing to transfer the ->tx.buf mux
buffer via b_force_xfer() (without zero copy)
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
1c482c665b MINOR: quic: Wake up the mux upon ACK receipt
When ACK have been received by the xprt, it must wake up the
mux if this latter has subscribed to SEND events. This is the
role of qcs_try_to_consume() to detect such a situation. This
is the function which consumes the buffer filled by the mux.
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
acd43a597c MINOR: quic: Add useful trace about pktns discarding
It is important to know if the packet number spaces used during the
handshakes have really been discarding. If not, this may have a
significant impact on the packet loss detection.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
8c27de7d20 MINOR: quic: Initial packet number spaced not discarded
There were cases where the Initial packet number space was not discarded.
This leaded the packet loss detection to continue to take it into
considuration during the connection lifetime. Some Application level
packets could not be retransmitted.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
2cb130c980 MINOR: quic: Constantness fixes for frame builders/parsers.
This is to ensure we do not modify important static variables:
the QUIC frame builders and parsers.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
dc2593e460 MINOR: quic: Wrong packet flags settings during frame building
We flag the packet as being ack-eliciting when building the frame.
But a wrong variable was used to to so.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
156a59b7c9 MINOR: quic: Confusion between TX/RX for the frame builders
QUIC_FL_TX_PACKET_ACK_ELICITING was replaced by QUIC_FL_RX_PACKET_ACK_ELICITING
by this commit due to a copy and paste:
   e5b47b637 ("MINOR: quic: Add a mask for TX frame builders and their authorized packet types")
Furthermore the flags for the PADDING frame builder was not initialized.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
578a7898f2 MINOR: mux_quic: move qc_process() code to qc_send()
qc_process is supposed to be run for each I/O handler event, not
only for "send" events.
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
Frédéric Lécaille
b9c06fbe52 MINOR: quic_sock: Do not flag QUIC connections as being set
This is to let conn_get_src() or conn_get_src() set the source
or destination addresses for the connection.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
48fc74af64 MINOR: quic: Missing active_connection_id_limit default value
The peer transport parameter values were not initialized with
the default ones (when absent), especially the
"active_connection_id_limit" parameter with 2 as default value
when absent from received remote transport parameters. This
had as side effect to send too much NEW_CONNECTION_ID frames.
This was the case for curl which does not announce any
"active_connection_id_limit" parameter.
Also rename ->idle_timeout to ->max_idle_timeout to reflect the RFC9000.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
d4d6aa7b5c MINOR: quic: Attach the QUIC connection to a thread.
Compute a thread ID from a QUIC CID and attach the I/O handler to this
thread.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
2fc76cffaf MINOR: quic: Make QUIC-TLS support at least two initial salts
These salts are used to derive initial secrets to decrypt the first Initial packet.
We support draft-29 and v1 QUIC version initial salts.
Add parameters to our QUIC-TLS API functions used to derive these secret for
these salts.
Make our xprt_quic use the correct initial salt upon QUIC version field found in
the first paquet. Useful to support connections with curl which use draft-29
QUIC version.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
2766e78f3b MINOR: quic: Shorten some handshakes
Move the "ACK required" bit from the packet number space to the connection level.
Force the "ACK required" option when acknowlegding Handshake or Initial packet.
A client may send three packets with a different encryption level for each. So,
this patch modifies qc_treat_rx_pkts() to consider two encryption level passed
as parameters, in place of only one.
Make qc_conn_io_cb() restart its process after the handshake has succeeded
so that to process any Application level packets which have already been received
in the same datagram as the last CRYPTO frames in Handshake packets.
2021-09-23 15:27:25 +02:00
Amaury Denoyelle
42bb8aac65 MINOR: h3/mux: detect fin on last h3 frame of the stream 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
8e2a998b17 MINOR: h3: send htx data 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
15b096180d MINOR: h3: encode htx headers to QPACK 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
e0930fcb07 MINOR: qpack: encode headers functions 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
4652a59255 MINOR: qpack: create qpack-enc module 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
26dfd90eb0 MINOR: h3: define snd_buf callback and divert mux ops 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
7b1d3d6d3d MINOR: mux-quic: send SETTINGS on uni stream 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
f52151d83e MEDIUM: mux-quic: implement ring buffer on stream tx 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
990435561b MINOR: h3: allocate stream on headers 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
b49fa1aa6d MINOR: h3: parse headers to htx 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
fd7cdc3e70 MINOR: qpack: generate headers list on decoder
TMP -> non-free strdup
TMP -> currently only support indexed field line or literal field line
with name reference
2021-09-23 15:27:25 +02:00
Amaury Denoyelle
484317e5e8 MINOR: qpack: fix wrong comment 2021-09-23 15:27:25 +02:00
Amaury Denoyelle
3394939475 MINOR: h3: change default settings
In particular, advertise a 0-length dynamic table for QPACK.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
a5b1b894c6 MINOR: quic: Prepare STREAM frames to fill QUIC packets
We must take as most as possible data from STREAM frames to be encapsulated
in QUIC packets, almost as this is done for CRYPTO frames whose fields are
variable length fields. The difference is that STREAM frames are only accepted
for short packets without any "Length" field. So it is sufficient to call
max_available_room() for that in place of max_stream_data_size() as this
is done for CRYPTO data.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
e16f0bd1e3 MINOR: h3: Send h3 settings asap
As it is possible to send Application level packets during the handshake,
let's send the h3 settings asaps.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
4bade77bf9 MINOR: quic: Prepare Application level packet asap.
It is possible the TLS stack stack provides us with 1-RTT TX secrets
at the same time as Handshake secrets are provided. Thanks to this
simple patch we can build Application level packets during the handshake.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
f798096412 MINOR: quic: Post handshake packet building improvements
Make qc_prep_hdshk_pkts() and qui_conn_io_cb() handle the case
where we enter them with QUIC_HS_ST_COMPLETE or QUIC_HS_ST_CONFIRMED
as connection state with QUIC_TLS_ENC_LEVEL_APP and QUIC_TLS_ENC_LEVEL_NONE
to consider to prepare packets.
quic_get_tls_enc_levels() is modified to return QUIC_TLS_ENC_LEVEL_APP
and QUIC_TLS_ENC_LEVEL_NONE as levels to consider when coalescing
packets in the same datagram.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
754f99e995 MINOR: quic: Missing case when discarding HANDSHAKE secrets
With very few packets received by the listener, it is possible
that its state may move from QUIC_HS_ST_SERVER_INITIAL to
QUIC_HS_ST_COMPLETE without transition to QUIC_HS_ST_SERVER_HANDSHAKE state.
This latter state is not mandatory.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
67f47d0125 MINOR: quic: Wrong flags handling for acks
Fixes several concurrent accesses issue regarding QUIC_FL_PKTNS_ACK_RECEIVED and
QUIC_FL_PKTNS_ACK_REQUIRED flags.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
d067088695 MINOR: quic: Coalesce Application level packets with Handshake packets.
This simple enable use to coalesce Application level packet with
Handshake ones at the end of the handshake. This is highly useful
if we do want to send a short Handshake packet followed by Application
level ones.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
eed7a7d73b MINOR: quic: Atomically get/set the connection state
As ->state quic_conn struct member field is shared between threads
we must atomically get and set its value.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
4436cb6606 MINOR: quic: Evaluate the packet lengths in advance
We must evaluate the packet lenghts in advance to be sure we do not
consume a packet number for nothing. The packet building must always
succeeds. This is the role of qc_eval_pkt() implemented by this patch
called before calling qc_do_build_pkt() which was previously modified to
always succeed.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
82b8652ac6 MINOR: quic: Missing acks encoded size updates.
There were cases where the encoded size of acks was not updated leading
to ACK frames building too big compared to the expected size. At this
time, this makes the code "BUG_ON()".
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
8b19a9f162 MINOR: quic: Make use of the last cbuf API when initializing TX ring buffers
Initialize the circular buffer internal buffer from a specific pool for TX ring
buffers named "pool_head_quic_tx_ring".
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
dbe25afbe6 MINOR: quic: Add a pool for TX ring buffer internal buffer
We want to allocate the internal buffer of TX ring buffer from a pool.
This patch add "quic_tx_ring_pool" to do so.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
a2e954a817 MINOR: quic: Make circular buffer internal buffers be variable-sized.
For now on thanks to this simple patch we can use circular buffers with
a variable-sized internal buffer.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
9445abc013 MINOR: quic: Rename functions which do not build only Handshake packets
Rename qc_build_hdshk_pkt() to qc_build_pkt() and qc_do_build_hdshk_pkt()
to qc_do_build_pkt().
Update their comments consequently.
Make qc_do_build_hdshk_pkt() BUG_ON() when it does not manage to build
a packet. This is a bug!
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
5d00b2d7b1 MINOR: quic: Remove Application level related functions
Remove the functions which were specific to the Application level.
This is the same function which build any packet for any encryption
level: quic_prep_hdshk_pkts() directly called from the quic_conn_io_cb().
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
f252adb368 MINOR: quic: qc_do_build_hdshk_pkt() does not need to pass a copy of CRYPTO frame
There is no need to pass a copy of CRYPTO frames to qc_build_frm() from
qc_do_build_hdshk_pkt(). Furthermore, after the previous modifications,
qc_do_build_hdshk_pkt() do not build only CRYPTO frame from ->pktns.tx.frms
MT_LIST but any type of frame.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
a7348f6f85 MINOR: quic: Make qc_build_hdshk_pkt() atomically consume a packet number
Atomically increase the "next packet variable" before building a new packet.
Make the code bug on a packet building failure. This should never happen
if we do not want to consume a packet number for nothing. There are remaining
modifications to come to ensure this is the case.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
91ae7aa7ec MINOR: quic: quic_conn_io_cb() task rework
Modify this task which is called at least each a packet is received by a listener
so that to make it behave almost as qc_do_hdshk(). This latter is no more useful
and removed.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
0ac3851f14 MINOR: quic: Modify qc_build_cfrms() to support any frame
This function was responsible of building CRYPTO frames to fill as much as
possible a packet passed as argument. This patch makes it support any frame
except STREAM frames whose lengths are highly variable.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
59b07c737b MINOR: quic: Atomically handle packet number space ->largest_acked_pn variable
Protect this variable (largest acked packet number) from any concurrent access.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
e1aa0d347a MINOR: quic: Modify qc_do_build_hdshk_pkt() to accept any packet type
With this patch qc_do_build_hdshk_pkt() is also able to build Application level
packet type. Its name should be consequently renamed (to come).
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
0e50e1b0b5 MINOR: quic: Add the packet type to quic_tx_packet struct
This is required to build packets from the same function.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
522c65ce39 MINOR: quic: Store post handshake frame in ->pktns.tx.frms MT_LIST
We want to treat all the frames to be built the same way as frames
built during handshake (CRYPTO frames). So, let't store them at the same
place which is an MT_LIST.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
546186b1cf MINOR: quic: Add the QUIC connection state to traces
This connection variable was missing. It is useful to debug issues.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
f5821dc7b7 MINOR: quic: Add a mask for TX frame builders and their authorized packet types
As this has been done for RX frame parsers, we add a mask for each TX frame
builder to denote the packet types which are authorized to embed such frames.
Each time a TX frame builder is called, we check that its mask matches the
packet type the frame is built for.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
0ad0458a56 MINOR: quic: Replace quic_tx_frm struct by quic_frame struct
These structures are similar. quic_tx_frm was there to try to reduce the
size of such objects which embed a union for all the QUIC frames.
Furtheremore this patch fixes the issue where quic_tx_frm objects were freed
from the pool for quic_frame.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
c88df07bdd MINOR: quic: Make ->tx.frms quic_pktns struct member be thread safe
Replace this member which is a list struct by an mt_list struct.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
120ea6f169 MINOR: quic: Make qc_treat_rx_pkts() be thread safe.
Make quic_rx_packet_ref(inc|dec)() functions be thread safe.
Make use of ->rx.crypto.frms_rwlock RW lock when manipulating RX frames
from qc_treat_rx_crypto_frms().
Modify atomically several variables attached to RX part of quic_enc_level struct.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
98cdeb2f0c MINOR: quic: Rename ->rx.rwlock of quic_enc_level struct to ->rx.pkts_rwlock
As there are at two RW lock in this structure, let's the name of this lock
be more explicit.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
9054d1b564 MINOR: quic: Missing encryption level rx.crypto member initialization and lock.
->rx.crypto member of quic_enc_level struct was not initialized as
this was done for all other members of this structure. This patch
fixes this.
Also adds a RW lock for the frame of this member.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
01abc4612b MINOR: quic: Unitialized mux context upon Client Hello message receipt.
If we let the connection packet handler task (quic_conn_io_cb) process the first
client Initial packet which contain the TLS Client Hello message before the mux
context is initialized, quic_mux_transport_params_update() makes haproxy crash.
->start xprt callback already wakes up this task and is called after all the
connection contexts are initialized. So, this patch do not wakes up quic_conn_io_cb()
if the mux context is not initialized (this was already the case for the connection
context (conn_ctx)).
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
0eb60c5b4d MINOR: quic: Add TX packets at the very last time to their tree.
If we add TX packets to their trees before sending them, they may
be detected as lost before being sent. This may make haproxy crash
when it retreives the prepared packets from TX ring buffers, dereferencing
them after they have been freed.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
c8d3f873e8 MINOR: quic: Remove old TX buffer implementation
We use only ring buffers (struct qring) to prepare and send QUIC datagrams.
We can safely remove the old buffering implementation which was not thread safe.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
98ad56a049 MINOR: quic_tls: Make use of the QUIC V1 salt.
This salt is used to derive the Initial secrets.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
c5b0c93c26 MINOR: quic: Make use of TX ring buffers to send QUIC packets
We modify the functions responsible of building packets to put these latters
in ring buffers (qc_build_hdshk_pkt() during the handshake step, and
qc_build_phdshk_apkt() during the post-handshake step). These functions
remove a ring buffer from its list to build as much as possible datagrams.
Eache datagram is prepended of two field: the datagram length and the
first packet in the datagram. We chain the packets belonging to the same datagram
in a singly linked list to reach them from the first one: indeed we must
modify some members of each packet when we really send them from send_ppkts().
This function is also modified to retrieved the datagram from ring buffers.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
6b19764e3c MINOR: quic: Initialize pointers to TX ring buffer list
We initialize the pointer to the listener TX ring buffer list.
Note that this is not done for QUIC clients  as we do not fully support them:
we only have to allocate the list and attach it to server struct I guess.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
48f8e1925b MINOR: proto_quic: Allocate TX ring buffers for listeners
We allocate an array of QUIC ring buffer, one by thread, and arranges them in a
MT_LIST. Everything is allocated or nothing: we do not want to usse an incomplete
array of ring buffers to ensure that each thread may safely acquire one of these
buffers.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
ed9119f39e BUG/MINOR: quic: Too much reduced computed space to build handshake packets
Before this patch we reserved 16 bytes (QUIC_TLS_TAG_LEN) before building the
handshake packet to be sure to be able to add the tag which comes with the
the packet encryption, decreasing the end offset of the building buffer by 16 bytes.
But this tag length was taken into an account when calling qc_build_frms() which
computes and build crypto frames for the remaining available room thanks to <*len>
parameter which is the length of the already present bytes in the building buffer
before adding CRYPTO frames. This leaded us to waste the 16 last bytes of the buffer
which were not used.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
82d1daa268 MINOR: quic: Add the QUIC v1 initial salt.
See initial_salt value for QUIC-TLS RFC 9001 at
https://www.rfc-editor.org/rfc/rfc9001.html#name-initial-secrets
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
4b1fddcfcf MINOR: quic: Prefer x25519 as ECDH preferred parametes.
This make at least our listeners answer to ngtcp2 clients without
HelloRetryRequest message. It seems the server choses the first
group in the group list ordered by preference and set by
SSL_CTX_set1_curves_list() which match the client ones.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
c6bc185c18 MINOR: quic: Add a ring buffer implementation for QUIC
This implementation is inspired from Linux kernel circular buffer implementation
(see include/linux/circ-buf.h). Such buffers may be used at the same time both
by writer and reader (lock-free).
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
f3d078d22e MINOR: quic: Make qc_lstnr_pkt_rcv() be thread safe.
Modify the I/O dgram handler principal function used to parse QUIC packets
be thread safe. Its role is at least to create new incoming connections
add to two trees protected by the same RW lock. The packets are for now on
fully parsed before possibly creating new connections.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
01ab6618fe MINOR: quic: Move conn_prepare() to ->accept_conn() callback
The xprt context must be initialized before receiving further packets from
the I/O dgram handler.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
6de7287cc7 MINOR: quic: Connection allocations rework
Allocate everything needed for a connection (struct quic_conn) from the same
function.
Rename qc_new_conn_init() to qc_new_conn() to reflect these modifications.
Insert these connection objects in their tree after returning from this function.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
7fd59789f2 MINOR: quic: Do not wakeup the xprt task on ACK receipt
This is an old statement which was there before implemeting the PTO and
packet loss detection. There is no reason to keep for now on.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
2e7ffc9d31 MINOR: quic: Add useful traces for I/O dgram handler
This traces have already help in diagnosing multithreading issues.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
a11d0e26d4 MINOR: quic: Replace the RX unprotected packet list by a thread safety one.
This list is shared between the I/O dgram handler and the task responsible
for processing the QUIC packets inside.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
c28aba2a8d MINOR: quic: Replace the RX list of packet by a thread safety one.
This list is shared between the I/O dgram handler and the task responsible
for processing the QUIC packets.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
1eaec33cb5 MINOR: quic: Replace quic_conn_ctx struct by ssl_sock_ctx struct
Some SSL call may be called with pointer to ssl_sock_ctx struct as parameter
which does not match the quic_conn_ctx struct type (see ssl_sock_infocb()).
I am not sure we have to keep such callbacks for QUIC but we must ensure
the SSL and QUIC xprts use the same data structure as context.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
a5fe49f44a MINOR: quic: Move the connection state
Move the connection state from quic_conn_ctx struct to quic_conn struct which
is the structure which is used to store the QUIC connection part information.
This structure is initialized by the I/O dgram handler for each new connection
to QUIC listeners. This is needed for the multithread support so that to not
to have to depend on the connection context potentially initialized by another
thread.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
9fccace8b0 MINOR: quic: Add a lock for RX packets
We must protect from concurrent the tree which stores the QUIC packets received
by the dgram I/O handler, these packets being also parsed by the xprt task.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
654c691731 MINOR: quic: Do not stop the packet parsing too early in qc_treat_rx_packets()
Continue to parse the packets even if we will not be able to acknowledge them.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
6fe21b0dec BUG/MINOR: quic: Wrong RX packet reference counter usage
No need to call free_quic_rx_packet() after calling quic_rx_packet_eb64_delete()
as this latter already calls quic_rx_packet_refdec() also called by
free_quic_rx_packet().
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
c4b93ea57d CLEAUNUP: quic: Usage of a useless variable in qc_treat_rx_pkts()
The usage of a <drop> variable is unnecessary here.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
8ba4276d13 BUG/MINOR: quic: Missing cases treatement when updating ACK ranges
Let's say that we have to insert a range R between to others A and B
with A->first <= R->first <= B->first. We have to remove the ranges
which are overlapsed by R during. This was correctly done when
the intersection between A and R was not empty, but not when the
intersection between R and B was not empty. If this latter case
after having inserting a new range R we set <new> variable as the
node to consider to check the overlaping between R and its following
ranges.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
c825eba5f9 MINOR: quic: Remove a useless variable in quic_update_ack_ranges_list()
This very minor modification is there to ease the readibilyt of this function.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
d3f4dd8014 MINOR: quic: Useless test in quic_update_ack_ranges_list()
At this place, the condition "le_ar->first.key <= ar->first" is true because
<le_ar> is the ack-range just below <ar> ack range.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
9ef64cd078 MINOR: quic: quic_update_ack_ranges_list() code factorization
Very minor modification to avoid repeating the same code section in this function
when allocation new ack range.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
baea284c3c BUG/MINOR: quic: Wrong memory free in quic_update_ack_ranges_list()
Wrong call to free() in place of pool_free() for an object allocated from a pool
memory.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
1a5e88c86a MINOR: quic: Remove header protection also for Initial packets
Make qc_try_rm_hp() be able to remove the header protection of Initial packets
which are the first incoming packets of a connection without context.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
497fa78ad8 MINOR: quic: Derive the initial secrets asap
Make depends qc_new_isecs() only on quic_conn struct initialization only (no more
dependency on connection struct initialization) to be able to run it as soon as
the quic_conn struct is initialized (from the I/O handler) before running ->accept()
quic proto callback.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
d24c2ecb16 MINOR: quic: Remove header protection for conn with context
We remove the header protection of packet only for connection with already
initialized context. This latter keep traces of the connection state.
Furthermore, we enqueue the first Initial packet for a new connection
after having completely parsed the packet so that to not start the accept
process for nothing.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
3d77fa754d MINOR: quic: QUIC conn initialization from I/O handler
Move the QUIC conn (struct quic_conn) initialization from quic_sock_accept_conn()
to qc_lstnr_pkt_rcv() as this is done for the server part.
Move the timer initialization to ->start xprt callback to ensure the connection
context is done : it is initialized by the ->accept callback which may be run
by another thread than the one for the I/O handler which also run ->start.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
de935f34e5 BUG/MINOR: quic: Do not check the acception of a new conn from I/O handler.
As the ->conn member of quic_conn struct is reset to NULL value by the ->accept
callback potentially run by another thread, this check is irrelevant.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
ecb5872012 MINOR: quic: Initialize the session before starting the xprt.
We must ensure the session and the mux are initialized before starting the xprt.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
1e1aad4ff4 MINOR: quic: Move an SSL func call from QUIC I/O handler to the xprt init.
Move the call to SSL_set_quic_transport_params() from the listener I/O dgram
handler to the ->init() callback of the xprt (qc_conn_init()) which initializes
its context where is stored the SSL context itself, needed by
SSL_set_quic_transport_params(). Furthermore this is already what is done for the
server counterpart of ->init() QUIC xprt callback. As the ->init() may be run
by another thread than the one for the I/O handler, the xprt context could
not be potentially already initialized before calling SSL_set_quic_transport_params()
from the I/O handler.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
785c9c998a MINOR: quic: Replace max_packet_size by max_udp_payload size.
The name the maximum packet size transport parameter was ambiguous and replaced
by maximum UDP payload size. Our code would be also ambiguous if it does not
reflect this change.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
0faf8078a8 MINOR: quic: Update the streams transport parameters.
Set the streams transport parameters which could not be initialized because they
were not available during initializations. Indeed, the streams transport parameters
are provided by the peer during the handshake.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
e8139f3b37 BUG/MINOR: quic: Wrong ->accept() error handling
Really signal the caller that ->accept() has failed if the session could not
be initialized because conn_complete_session() has failed. This is the case
if the mux could not be initialized too.
When it fails an ->accept() must returns -1 in case of resource shortage.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
422a39cf2c MINOR: quic: Add callbacks for (un)scribing to QUIC xprt.
Add these callbacks so that the QUIC mux may (un)scribe to the read/write xprt
events.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
fbe3b77c4e MINOR: quic: Disable the action of ->rcv_buf() xprt callback
Deactivate the action of this callback at this time. I am not sure
we will keep it for QUIC as it does not really make sense for QUIC:
the QUIC packet are already recvfrom()'ed by the low level I/O handler
used for all the connections.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
27faba7240 MINOR: quic_sock: Finalize the QUIC connections.
Add a call to conn_connection_complete() so that to install the mux any
QUIC connection.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
b4672fb6f0 MINOR: qpack: Add QPACK compression.
Implement QPACK used for HTTP header compression by h3.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
ccac11f35a MINOR: h3: Add HTTP/3 definitions.
Add all the definitions for HTTP/3 implementation.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
dfbae766b2 MINOR: mux_quic: Add QUIC mux layer.
This file has been derived from mux_h2.c removing all h2 parts. At
QUIC mux layer, there must not be any reference to http. This will be the
responsability of the application layer (h3) to open streams handled by the mux.
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
5aa4143d6c MINOR: quic: Move transport parmaters to anynomous struct.
We move ->params transport parameters to ->rx.params. They are the
transport parameters which will be sent to the peer, and used for
the endpoint flow control. So, they will be used to received packets
from the peer (RX part).
Also move ->rx_tps transport parameters to ->tx.params. They are the
transport parameter which are sent by the peer, and used to respect
its flow control limits. So, they will be used when sending packets
to the peer (TX part).
2021-09-23 15:27:25 +02:00
Frédéric Lécaille
577fe48890 BUG/MINOR: quic: Possible NULL pointer dereferencing when dumping streams.
This bug may occur when displaying streams traces. It came with this commit:
242fb1b63 ("MINOR: quic: Drop packets with STREAM frames with wrong direction.").
2021-09-23 15:27:25 +02:00
Willy Tarreau
6f97b4ef33 BUG/MEDIUM: leastconn: fix rare possibility of divide by zero
An optimization was brought in commit 5064ab6a9 ("OPTIM: lb-leastconn:
do not unlink the server if it did not change") to avoid locking the
server just to discover it did not move. However a mistake was made
because the operation involves a divide with a value that is read
outside of its usual lock, which makes it possible to be zero at the
exact moment we watch it if another thread takes the server down under
the lbprm lock, resulting in a divide by zero.

Therefore we must check that the value is not null there.

This must be backported to 2.4.
2021-09-22 07:24:02 +02:00
Willy Tarreau
c8cac04bd5 MEDIUM: listener: deprecate "process" in favor of "thread" on bind lines
The "process" directive on "bind" lines becomes quite confusing considering
that the only allowed value is 1 for the process, and that threads are
optional and come after the mandatory "1/".

Let's introduce a new "thread" directive to directly configure thread
numbers, and mark "process" as deprecated. Now "process" will emit a
warning and will suggest how to be replaced with "thread" instead.
The doc was updated accordingly (mostly a copy-paste of the previous
description which was already up to date).

This is marked as MEDIUM as it will impact users having "zero-warning"
and "process" specified.
2021-09-21 14:35:42 +02:00
Amaury Denoyelle
cd8a6f28c6 MINOR: server: enable slowstart for dynamic server
Enable the 'slowstart' keyword for dynamic servers. The slowstart task
is allocated in 'add server' handler if slowstart is used.

As the server is created in disabled state, there is no need to start
the task. The slowstart task will be automatically started on the first
'enable server' invocation.
2021-09-21 14:00:32 +02:00
Amaury Denoyelle
29d1ac1330 REORG: server: move slowstart init outside of checks
'slowstart' can be used without check on a server, with the CLI handlers
'enable/disable server'. Move the code to initialize and start the
slowstart task outside of check.c.

This change will also be reused to enable slowstart for dynamic servers.
2021-09-21 14:00:32 +02:00
Amaury Denoyelle
725f8d29ff MINOR: server: enable more check related keywords for dynamic servers
Allow to use the check related keywords defined in server.c. These
keywords can be enabled now that checks have been implemented for
dynamic servers.

Here is the list of the new keywords supported :
- error-limit
- observe
- on-error
- on-marked-down
- on-marked-up
2021-09-21 14:00:32 +02:00
Amaury Denoyelle
79b90e8cd4 MINOR: server: enable more keywords for ssl checks for dynamic servers
Allow to configure ssl support for dynamic server checks independently
of the ssl server configuration. This is done via the keyword
"check-ssl". Also enable to configure the sni/alpn used for the check
via "check-sni/alpn".
2021-09-21 14:00:07 +02:00
Amaury Denoyelle
b621552ca3 BUG/MINOR: server: alloc dynamic srv ssl ctx if proxy uses ssl chk rule
The ssl context is not initialized for a dynamic server, even if there
is a tcpcheck rule which uses ssl on the related backed. This will cause
the check initialization to failed with the message :
  "Out of memory when initializing an SSL connection"

This can be reproduced by having the following config in the backend :
  option tcp-check
  tcp-check connect ssl
and create a dynamic server with check activated and a ca-file.

Fix this by calling the prepare_srv xprt callback when the proxy options
PR_O_TCPCKH_SSL is set.

Check support for dynamic servers has been merged in the current branch.
No backport needed.
2021-09-21 13:56:03 +02:00
Amaury Denoyelle
0f456d5029 BUG/MINOR: server: allow 'enable health' only if check configured
Test that checks have been configured on the server before enabling via
the 'enable health' CLI. This mirrors the 'enable agent' command.

Without this, a user can use the command on the server without checks.
This leaves the server in an undefined state. Notably, the stat page
reports the server in check transition.

This condition was left on the following reorg commit.
  2c04eda8b5
  REORG: cli: move "{enable|disable} health" to server.c

This should be backported up to 1.8.
2021-09-21 11:50:22 +02:00
Tim Duesterhus
4f065262e9 CLEANUP: Remove unreachable break from parse_time_err()
The `return` already leaves the function.
2021-09-20 18:37:32 +02:00
Tim Duesterhus
75e2f8dcdd CLEANUP: Include check.h in flt_spoe.c
This is required for the prototype of spoe_prepare_healthcheck_request().
2021-09-20 18:37:32 +02:00
William Lallemand
79a3478c24 MINOR: httpclient: add the EOH when no headers where provided
httpclient_req_gen() now adds the end of headers block when no header
was provided, which avoid adding it manually.
2021-09-20 16:24:54 +02:00
Dragan Dosen
a8018eb470 BUG/MINOR: flt-trace: fix an infinite loop when random-parsing is set
The issue is introduced with the commit c41d8bd65 ("CLEANUP: flt-trace:
Remove unused random-parsing option").

This must be backported everywhere the above commit is.
2021-09-20 16:06:58 +02:00
Tim Duesterhus
ec4a8754da CLEANUP: Apply xalloc_size.cocci
This fixes a few locations with a hardcoded type within `sizeof()`.
2021-09-17 17:22:05 +02:00
Tim Duesterhus
16554245e2 CLEANUP: Apply bug_on.cocci
The changes look safe to me, even if `DEBUG_STRICT` is not enabled.
2021-09-17 17:22:05 +02:00
Tim Duesterhus
b113b5ca24 CLEANUP: Apply ist.cocci
This cleans up ist handling.
2021-09-17 17:22:05 +02:00
Willy Tarreau
e61244631a MINOR: applet: remove the thread mask from appctx_new()
appctx_new() is exclusively called with tid_bit and it only uses the
mask to pass it to the accompanying task. There is no point requiring
the caller to know about a mask there, nor is there any point in
creating an applet outside of the context of its own thread anyway.
Let's drop this and pass tid_bit to task_new() directly.
2021-09-17 16:08:34 +02:00
Willy Tarreau
87063a7da1 BUILD: fd: remove unused variable totlen in fd_write_frag_line()
Ilya reports in GH #1392 that clang 13 complains about totlen being
calculated and not used in fd_write_frag_line(), which is true. It's
a leftover of some older code.
2021-09-17 12:00:27 +02:00
Willy Tarreau
b5d1141305 BUILD: proto_uxst: do not set unused flag
Similarly to previous patch for sockpair, UNIX sockets set the
CONNECT_HAS_DATA flag without using it later, we can drop it.
2021-09-17 11:59:15 +02:00
Willy Tarreau
0ce77ac204 BUILD: sockpair: do not set unused flag
Ilya reports in GH #1392 that clang 13 complains about a flag being added
to the "flags" parameter without being used later. That's generic code
that was shared from TCP but we can indeed drop this flag since it's used
for TFO which we don't have in socketpairs.
2021-09-17 11:56:25 +02:00
Willy Tarreau
f2dda52e78 BUG/MINOR: cli/payload: do not search for args inside payload
The CLI's payload parser is over-complicated and as such contains more
bugs than needed. One of them is that it uses strstr() to find the
ending tag, ignoring spaces before it, while the argument locator
creates a new arg on each space, without checking if the end of the
word appears past the previously found end. This results in "<<" being
considered as the start of a new argument if preceeded by more than
one space, and the payload being damaged with a \0 inserted at the
first space or tab.

Let's make an easily backportable fix for now. This fix makes sure that
the trailing zero from the first line is properly kept after '<<' and
that the end tag is looked for only as an isolated argument and nothing
else. This also gets rid of the unsuitable strstr() call and now makes
sure that strcspn() will not return elements that are found in the
payload.

For the long term the loop must be rewritten to get rid of those
unsuitable strcspn() and strstr() calls which work past each other, and
the cli_parse_request() function should be split into a tokenizer and
an executor that are used from the caller instead of letting the caller
play games with what it finds there.

This should be backported wherever CLI payload is supported, i.e. 2.0+.
2021-09-17 11:50:09 +02:00
Amaury Denoyelle
4837293ca0 BUG/MINOR: connection: prevent null deref on mux cleanup task allocation
Move the code to allocate/free the mux cleanup task outside of the polling
loop. A new thread_alloc/free handler is registered for this in
connection.c.

This has the benefit to clean up the polling loop code. And as another
benefit, if the task allocation fails, the handler can report an error
to exit the haproxy process. This prevents a potential null pointer
dereferencing.

This should fix the github issue #1389.

This must be backported up to 2.4.
2021-09-16 17:45:52 +02:00
Christopher Faulet
8a0e5f822b BUG/MINOR: tcpcheck: Improve LDAP response parsing to fix LDAP check
When the LDAP response is parsed, the message length is not properly
decoded. While it works for LDAP servers encoding it on 1 byte, it does not
work for those using a multi-bytes encoding. Among others, Active Directory
servers seems to encode messages or elements length on 4 bytes.

In this patch, we only handle length of BindResponse messages encoded on 1,
2 or 4 bytes. In theory, it may be encoded on any bytes number less than 127
bytes. But it is useless to make this part too complex. It should be ok this
way.

This patch should fix the issue #1390. It should be backported to all stable
versions. While it should be easy to backport it as far as 2.2, the patch
will have to be totally rewritten for lower versions.
2021-09-16 17:24:50 +02:00
Willy Tarreau
c2afb860f2 MINOR: pools: use mallinfo2() when available instead of mallinfo()
Ilya reported in issue #1391 a build warning on Fedora about mallinfo()
being deprecated in favor of mallinfo2() since glibc-2.33. Let's add
support for it. This should be backported where the following commit is
also backported: 157e39303 ("MINOR: pools: automatically disable
malloc_trim() with external allocators").
2021-09-16 09:20:16 +02:00
Christopher Faulet
ab7389dc3c BUG/MAJOR: mux-h1: Don't eval input data if an error was reported
If an error was already reported on the H1 connection, pending input data
must not be (re)evaluated in h1_process(). Otherwise an unexpected internal
error will be reported, in addition of the first one. And on some
conditions, this may generate an infinite loop because the mux tries to send
an internal error but it fails to do so thus it loops to retry.

This patch should fix the issue #1356. It must be backported to 2.4.
2021-09-16 08:31:46 +02:00
Christopher Faulet
51324b8720 CLEANUP: acl: Remove unused variable when releasing an acl expression
The "unresolved" variable is unused since commit 9fa0df5 ("BUG/MINOR: acl:
Fix freeing of expr->smp in prune_acl_expr").

This patch should fix the issue #1359.
2021-09-16 08:31:46 +02:00
Willy Tarreau
845b560f6a MINOR: pools: report it when malloc_trim() is enabled
Since we can detect it at runtime now, it could help to have it mentioned
in haproxy -vv.
2021-09-15 10:41:24 +02:00
Willy Tarreau
157e393039 MINOR: pools: automatically disable malloc_trim() with external allocators
Pierre Cheynier reported some occasional crashes in malloc_trim() on a
recent glibc when running with jemalloc(). While in theory there should
not be any link between the two, it remains plausible that something
allocated early with one is tentatively freed with the other and that
attempts to trim end up badly. There's no point calling the glibc specific
malloc_trim() with external allocators anyway. However these ones are often
enabled at link time or even at run time with LD_PRELOAD, so we cannot rely
on build options for this.

This patch implements runtime detection for the allocator in use by checking
with mallinfo() that a malloc() call is properly accounted for in glibc's
malloc. It only enables malloc_trim() in this case, and ignores it for
other cases. It's fine to proceed like this because mallinfo() is provided
by a wider range of glibcs than malloc_trim().

This could be backported to 2.4 and 2.3. If so, it will also need previous
patch "CLEANUP: pools: factor all malloc_trim() calls into trim_all_pools()".
2021-09-15 10:40:39 +02:00
Willy Tarreau
ea3323f62c CLEANUP: pools: factor all malloc_trim() calls into trim_all_pools()
The code was slightly cleaned up by removing repeated occurrences of ifdefs
and moving that into a single trim_all_pools() function.
2021-09-15 10:38:21 +02:00
Willy Tarreau
c5d0fc9b9f BUILD: sample: fix format warning on 32-bit archs in sample_conv_be2dec_check()
The sizeof() was printed as a long but it's just an unsigned on some
32-bit platforms, hence the format warning. No backport is needed, as
this arrived in 2.5 with commit  40ca09c7b ("MINOR: sample: Add be2dec
converter").
2021-09-15 10:32:12 +02:00
Tim Duesterhus
2281738256 BUG/MEDIUM lua: Add missing call to RESET_SAFE_LJMP in hlua_filter_new()
In one case before exiting leaving the function the panic handler was not
reset.

Introduced in 69c581a092, which is 2.5+.
No backport required.
2021-09-12 08:21:07 +02:00
Tim Duesterhus
d5fc8fcb86 CLEANUP: Add haproxy/xxhash.h to avoid modifying import/xxhash.h
This solves setting XXH_INLINE_ALL in a cleaner way, because the imported
header is not modified, easing future updates.

see 6f7cc11e6d
2021-09-11 19:58:45 +02:00
Christopher Faulet
949b6ca961 BUG/MINOR: filters: Set right FLT_END analyser depending on channel
A bug was introduced by the commit 26eb5ea35 ("BUG/MINOR: filters: Always
set FLT_END analyser when CF_FLT_ANALYZE flag is set"). Depending on the
channel evaluated, the rigth FLT_END analyser must be set. AN_REQ_FLT_END
for the request channel and AN_RES_FLT_END for the response one.

Ths patch must be backported everywhere the above commit was backported.
2021-09-10 10:35:53 +02:00
Christopher Faulet
2d56500826 BUG/MEDIUM: http-ana: Reset channels analysers when returning an error
When an error is returned to the client, via a call to
http_reply_and_close(), the request channel is flushed and shut down and
HTTP analysis on both direction is finished. So it is safer to centralize
reset of channels analysers at this place. It is especially important when a
filter is attached to the stream when a client abort is detected. Because,
otherwise, the stream remains blocked because request analysers are not
reset.

This bug was hidden for a while. But since the fix 6fcd2d328 ("BUG/MINOR:
stream: Don't release a stream if FLT_END is still registered"), it is
possible to trigger it.

This patch must be backported everywhere the above commit was backported.
2021-09-10 10:35:53 +02:00
Christopher Faulet
883d83e83c BUG/MEDIUM: stream-int: Don't block SI on a channel policy if EOI is reached
If the end of input is reported by the mux on the conn-stream during a
receive, we leave without evaluating the channel policies. It is especially
important to be able to catch client aborts during server connection
establishment. Indeed, in this case, without this patch, the
stream-interface remains blocked and read events are not forwarded to the
stream. It means it is not possible to detect client aborts.

Thanks to this fix, the abortonclose option should fixed for HAProxy 2.3 and
lower. On 2.4 and 2.5, it seems to work because the stream is created after
the request parsing.

Note that a previous fix of abortonclose option was reverted. This one
should be the right way to fix it. It must carefully be backported as far as
2.0. A observation period on the 2.3 is probably a good idea.
2021-09-10 10:35:53 +02:00
Christopher Faulet
0fa8007102 CLEANUP: mux-h1: Remove condition rejecting upgrade requests with payload
Now, "Upgrade:" header is removed from such requests. Thus, the condition to
reject them is now useless and can be removed. Code to handle unimplemented
features is now unused but is preserved for future uses.

This patch may be backported to 2.4.
2021-09-10 10:35:53 +02:00
Christopher Faulet
52a5ec2d18 BUG/MEDIUM: mux-h1: Remove "Upgrade:" header for requests with payload
Instead of returning a 501-Not-implemented error when "Ugrade:" header is
found for a request with a payload, the header is removed. This way, the
upgrade is disabled and the request is still sent to the server. It is
required because some frameworks seem to try to perform H2 upgrade on every
requests, including POST ones.

The h2 mux was slightly fixed to convert Upgrade requests to extended
connect ones only if the rigth HTX flag is set.

This patch should fix the issue #1381. It must be backported to 2.4.
2021-09-10 09:17:51 +02:00
Willy Tarreau
55f8a830dc OPTIM: vars: do not keep variables usage stats if no limit is set
The sole purpose of the variable's usage accounting is to enforce
limits at the session or process level, but very commonly these are not
set, yet the bookkeeping (especially at the process level) is extremely
expensive.

Let's simply disable it when the limits are not set. This further
increases the performance of 12 variables on 16-thread from 1.06M
to 1.24M req/s.
2021-09-08 15:53:07 +02:00
Willy Tarreau
3b78f2aa5d OPTIM: vars: remove internal bookkeeping for vars_global_size
Right now we have a per-process max variable size and a per-scope one,
with the proc scope covering all others. As such, the per-process global
one is always exactly equal to the per-proc-scope one. And bookkeeping
on these process-wide variables is extremely expensive (up to 38% CPU
seen in var_accounting_diff() just for them).

Let's kill vars_global_size and only rely on the proc one. Doing this
increased the request rate from 770k to 1.06M in a config having only
12 variables on a 16-thread machine.
2021-09-08 15:45:05 +02:00
Willy Tarreau
dc72fbb8e8 MINOR: vars: centralize the lock/unlock into static inlines
The goal it to simplify the variables locking in order to later
simplify it.
2021-09-08 15:19:57 +02:00
Willy Tarreau
3f120d2a58 CLEANUP: vars: remove the now unused var_names array
This was the table of all variable names known to the haproxy process.
It's not used anymore.
2021-09-08 15:09:22 +02:00
Willy Tarreau
3a4bedccc6 MEDIUM: vars: replace the global name index with a hash
The global table of known variables names can only grow and was designed
for static names that are registered at boot. Nowadays it's possible to
set dynamic variable names from Lua or from the CLI, which causes a real
problem that was partially addressed in 2.2 with commit 4e172c93f
("MEDIUM: lua: Add `ifexist` parameter to `set_var`"). Please see github
issue #624 for more context.

This patch simplifies all this by removing the need for a central
registry of known names, and storing 64-bit hashes instead. This is
highly sufficient given the low number of variables in each context.
The hash is calculated using XXH64() which is bijective over the 64-bit
space thus is guaranteed collision-free for 1..8 chars. Above that the
risk remains around 1/2^64 per extra 8 chars so in practice this is
highly sufficient for our usage. A random seed is used at boot to seed
the hash so that it's not attackable from Lua for example.

There's one particular nit though. The "ifexist" hack mentioned above
is now limited to variables of scope "proc" only, and will only match
variables that were already created or declared, but will now verify
the scope as well. This may affect some bogus Lua scripts and SPOE
agents which used to accidentally work because a similarly named
variable used to exist in a different scope. These ones may need to be
fixed to comply with the doc.

Now we can sum up the situation as this one:
  - ephemeral variables (scopes sess, txn, req, res) will always be
    usable, regardless of any prior declaration. This effectively
    addresses the most problematic change from the commit above that
    in order to work well could have required some script auditing ;

  - process-wide variables (scope proc) that are mentioned in the
    configuration, referenced in a "register-var-names" SPOE directive,
    or created via "set-var" in the global section or the CLI, are
    permanent and will always accept to be set, with or without the
    "ifexist" restriction (SPOE uses this internally as well).

  - process-wide variables (scope proc) that are only created via a
    set-var() tcp/http action, via Lua's set_var() calls, or via an
    SPOE with the "force-set-var" directive), will not be permanent
    but will always accept to be replaced once they are created, even
    if "ifexist" is present

  - process-wide variables (scope proc) that do not exist will only
    support being created via the set-var() tcp/http action, Lua's
    set_var() calls without "ifexist", or an SPOE declared with
    "force-set-var".

This means that non-proc variables do not care about "ifexist" nor
prior declaration, and that using "ifexist" should most often be
reliable in Lua and that SPOE should most often work without any
prior declaration. It may be doable to turn "ifexist" to 1 by default
in Lua to further ease the transition. Note: regtests were adjusted.

Cc: Tim Dsterhus <tim@bastelstu.be>
2021-09-08 15:06:11 +02:00
Willy Tarreau
2c897d9d1b MINOR: vars: preset a random seed to hash variables names
Variables names will be hashed, but for this we need a random seed.
The XXH3() algorithms is bijective over the whole 64-bit space, which
is great as it guarantees no collision for 1..8 byte names. But above
that even if the risk is extremely faint, it theoretically exists and
since variables may be set from Lua we'd rather do our best to limit
the risk of controlled collision, hence the random seed.
2021-09-08 15:06:11 +02:00
Willy Tarreau
df8eeb1619 MEDIUM: vars: pre-create parsed SCOPE_PROC variables as permanent ones
All variables whose names are parsed by the config parser, the
command-line parser or the SPOE's register-var-names parser are
now preset as permanent. This will guarantee that these variables
will exist through out all the process' life, and that it will be
possible to implement the "ifexist" feature by looking them up.

This was marked medium because pre-setting a variable with an empty
value may always have side effects, even though none was spotted at
this stage.
2021-09-08 15:06:11 +02:00
Willy Tarreau
c1c88f4809 MEDIUM: vars: make var_clear() only reset VF_PERMANENT variables
We certainly do not want that a permanent variable (one that is listed
in the configuration) be erased by accident by an "unset-var" action.
Let's make sure these ones are only reset to an empty sample, like at
the moment of their initial registration. One trick is that the same
function is used to purge the memory at the end and to delete, so we
need to add an extra "force" argument to make the choice.
2021-09-08 15:06:11 +02:00
Willy Tarreau
3dc6dc3178 MINOR: vars: store flags into variables and add VF_PERMANENT
In order to continue to honor the ifexist Lua option and prevent rogue
SPOA agents from creating too many variables, we'll need to keep the
ability to mark certain proc.* variables as permanent when they're
known from the config file.

Let's add a flag there for this. It's added to the variable when the
variable is created with this flag set by the caller.

Another approach could have been to use a distinct list or distinct
scope but that sounds complicated and bug-prone.
2021-09-08 14:06:34 +02:00
Willy Tarreau
63c30667d7 MINOR: vars: support storing empty sample data with a variable
Storing an unset sample (SMP_T_ANY == 0) will be used to only reserve
the variable's space but associate no value. We need to slightly adjust
var_to_smp() for this so that it considers a value-less variable as non
existent and falls back to the default value.
2021-09-08 13:59:43 +02:00
Willy Tarreau
4994b57728 MINOR: vars: add a VF_CREATEONLY flag for creation
Passing this flag to var_set() will result in the variable to only be
created if it did not exist, otherwise nothing is done (it's not even
updated). This will be used for pre-registering names.
2021-09-08 11:47:30 +02:00
Willy Tarreau
7978c5c422 MEDIUM: vars: make the ifexist variant of set-var only apply to the proc scope
When setting variables, there are currently two variants, one which will
always create the variable, and another one, "ifexist", which will only
create or update a variable if a similarly named variable in any scope
already existed before.

The goal was to limit the risk of injecting random names in the proc
scope, but it was achieved by making use of the somewhat limited name
indexing model, which explains the scope-agnostic restriction.

With this change, we're moving the check downwards in the chain, at the
variable level, and only variables under the scope "proc" will be subject
to the restriction. A new set of VF_* flags was added to adjust how
variables are set, and VF_UPDATEONLY is used to mention this restriction.

In this exact state of affairs, this is not completely exact, as if a
similar name was not known in any scope, the variable will continue to
be rejected like before, but this will change soon.
2021-09-08 11:47:06 +02:00
Willy Tarreau
f1cb0ebe3e REORG: vars: remerge sample_store{,_stream}() into var_set()
The names for these two functions are totally misleading, they have
nothing to do with samples, they're purely dedicated to variables. The
former is only used by the second one and makes no sense by itself, so
it cannot even get a meaningful name. Let's remerge them into a single
one called "var_set()" which, as its name tries to imply, sets a variable
to a given value.
2021-09-08 11:10:16 +02:00
Willy Tarreau
d378eb82d9 CLEANUP: vars: rename sample_clear_stream() to var_unset()
This name was quite misleading, as it has nothing to do with samples nor
streams. This function's sole purpose is to unset a variable, so let's
call it "var_unset()" and document it a little bit.
2021-09-08 11:10:16 +02:00
Willy Tarreau
b7bfcb3ff3 MINOR: vars: rename vars_init() to vars_init_head()
The vars_init() name is particularly confusing as it does not initialize
the variables code but the head of a list of variables passed in
arguments. And we'll soon need to have proper initialization code, so
let's rename it now.
2021-09-08 11:10:16 +02:00
Willy Tarreau
10080716bf MINOR: proxy: add a global "grace" directive to postpone soft-stop
In ticket #1348 some users expressed some concerns regarding the removal
of the "grace" directive from the proxies. Their use case very closely
mimmicks the original intent of the grace keyword, which is, let haproxy
accept traffic for some time when stopping, while indicating an external
LB that it's stopping.

This is implemented here by starting a task whose expiration triggers
the soft-stop for real. The global "stopping" variable is immediately
set however. For example, this below will be sufficient to instantly
notify an external check on port 9999 that the service is going down,
while other services remain active for 10s:

    global
      grace 10s

    frontend ext-check
      bind :9999
      monitor-uri /ext-check
      monitor fail if { stopping }
2021-09-07 17:34:29 +02:00
Christopher Faulet
b7308f00cb Revert "BUG/MINOR: stream-int: Don't block reads in si_update_rx() if chn may receive"
This reverts commit e0dec4b7b2.

At first glance, channel_is_empty() was used on purpose in si_update_rx(),
because of the HTX ("b3e0de46c" MEDIUM: stream-int: Rely only on
SI_FL_WAIT_ROOM to stop data receipt). It is not pretty clear for now why
channel_may_recv() sould not be used here but this change introduce a
possible infinite loop with the stats applet. So, it is safer to revert the
patch, waiting for a better understanding of the probelm.

This means the abortonclose option will be broken again on the 2.3 and lower
versions.

This patch should fix the issue #1360. It must be backported as far as 2.0.
2021-09-07 14:31:02 +02:00
Willy Tarreau
3d5f19e04d CLEANUP: htx: remove comments about "must be < 256 MB"
Since commit "BUG/MINOR: config: reject configs using HTTP with bufsize
>= 256 MB" we are now sure that it's not possible anymore to have an HTX
block of a size 256 MB or more, even after concatenation thanks to the
tests for len >= htx_free_data_space(). Let's remove these now obsolete
comments.

A BUG_ON() was added in htx_add_blk() to track any such exception if
the conditions would change later, to complete the one that is performed
on the start address that must remain within the buffer.
2021-09-03 16:15:29 +02:00
Willy Tarreau
32b51cdf30 BUG/MINOR: config: reject configs using HTTP with bufsize >= 256 MB
As seen in commit 5ef965606 ("BUG/MINOR: lua: use strlcpy2() not
strncpy() to copy sample keywords"), configs with large values of
tune.bufsize were not practically usable since Lua was introduced,
regardless of the machine's available memory.

In addition, HTX encoding already limits block sizes to 256 MB, thus
it is not technically possible to use that large a buffer size when
HTTP is in use. This is absurdly high anyway, and for example Lua
initialization would take around one minute on a 4 GHz CPU. Better
prevent such a config from starting than having to deal with bug
reports that make no sense.

The check is only enforced if at least one HTX proxy was found, as
there is no techincal reason to block it for configs that are solely
based on raw TCP, and it could still be imagined that some such might
exist with single connections (e.g. a log forwarder that buffers to
cover for the storage I/O latencies).

This should be backported to all HTX-enabled versions (2.0 and above).
2021-09-03 16:15:29 +02:00
Willy Tarreau
54496a6a5b MINOR: vars: make the vars() sample fetch function support a default value
It is quite common to see in configurations constructions like the
following one:

    http-request set-var(txn.bodylen) 0
    http-request set-var(txn.bodylen) req.hdr(content-length)
    ...
    http-request set-header orig-len %[var(txn.bodylen)]

The set-var() rules are almost always duplicated when manipulating
integers or any other value that is mandatory along operations. This is
a problem because it makes the configurations complicated to maintain
and slower than needed. And it becomes even more complicated when several
conditions may set the same variable because the risk of forgetting to
initialize it or to accidentally reset it is high.

This patch extends the var() sample fetch function to take an optional
argument which contains a default value to be returned if the variable
was not set. This way it becomes much simpler to use the variable, just
set it where needed, and read it with a fall back to the default value:

    http-request set-var(txn.bodylen) req.hdr(content-length)
    ...
    http-request set-header orig-len %[var(txn.bodylen,0)]

The default value is always passed as a string, thus it will experience
a cast to the output type. It doesn't seem userful to complicate the
configuration to pass an explicit type at this point.

The vars.vtc regtest was updated accordingly.
2021-09-03 12:08:54 +02:00
Willy Tarreau
e352b9dac7 MINOR: vars: make vars_get_by_* support an optional default value
In preparation for support default values when fetching variables, we
need to update the internal API to pass an extra argument to functions
vars_get_by_{name,desc} to provide an optional default value. This
patch does this and always passes NULL in this argument. var_to_smp()
was extended to fall back to this value when available.
2021-09-03 12:08:54 +02:00
Willy Tarreau
be7e00d134 CLEANUP: vars: factor out common code from vars_get_by_{desc,name}
The two functions vars_get_by_name() and vars_get_by_scope() perform
almost the same operations except that they differ from the way the
name and scope are retrieved. The second part in common is more
complex and involves locking, so better factor this one out into a
new function.

There is no other change than refactoring.
2021-09-03 11:43:35 +02:00
Willy Tarreau
e93bff4107 MEDIUM: vars: also support format strings in CLI's "set var" command
Most often "set var" on the CLI is used to set a string, and using only
expressions is not always convenient, particularly when trying to
concatenate variables sur as host names and paths.

Now the "set var" command supports an optional keyword before the value
to indicate its type. "expr" takes an expression just like before this
patch, and "fmt" a format string, making it work like the "set-var-fmt"
actions.

The VTC was updated to include a test on the format string.
2021-09-03 11:01:48 +02:00
Willy Tarreau
753d4db5f3 MINOR: vars: add a "set-var-fmt" directive to the global section
Just like the set-var-fmt action for tcp/http rules, the set-var-fmt
directive in global sections allows to pre-set process-wide variables
using a format string instead of a sample expression. This is often
more convenient when it is required to concatenate multiple fields,
or when emitting just one word.
2021-09-03 11:01:48 +02:00
Willy Tarreau
20b7a0f9ed MINOR: log: make log-format expressions completely usable outside of req/resp
The log-format strings are usable at plenty of places, but the expressions
using %[] were restricted to request or response context and nothing else.
This prevents from using them from the config context or the CLI, let's
relax this.
2021-09-03 11:01:48 +02:00
Willy Tarreau
9c20433aca CLEANUP: vars: name the temporary proxy "CFG" instead of "CLI" for global vars
We're using a dummy temporary proxy when creating global variables in
the configuration file, it was copied from the CLI's code and was
mistakenly called "CLI", better name it "CFG". It should not appear
anywhere except maybe when debugging cores.
2021-09-03 11:01:48 +02:00
Willy Tarreau
c767eebf1f BUG/MINOR: vars: do not talk about global section in CLI errors for set-var
When attempting to set a variable does not start with the "proc" scope on
the CLI, we used to emit "only proc is permitted in the global section"
which obviously is a leftover from the initial code.

This may be backported to 2.4.
2021-09-03 11:01:12 +02:00
Willy Tarreau
1402fef58a BUG/MINOR: vars: truncate the variable name in error reports about scope.
When a variable starts with the wrong scope, it is named without stripping
the extra characters that follow it, which usually are closing parenthesis.
Let's make sure we only report what is expected.

This may be backported to 2.4.
2021-09-03 11:01:12 +02:00
Willy Tarreau
c77bad2467 BUG/MEDIUM: vars: run over the correct list in release_store_rules()
In commit 9a621ae76 ("MEDIUM: vars: add a new "set-var-fmt" action")
we introduced the support for format strings in variables with the
ability to release them on exit, except that it's the wrong list that
was being scanned for the rule (http vs vars), resulting in random
crashes during deinit.

This was a recent commit in 2.5-dev, no backport is needed.
2021-09-03 11:01:12 +02:00
Willy Tarreau
9a621ae76d MEDIUM: vars: add a new "set-var-fmt" action
The set-var() action is convenient because it preserves the input type
but it's a pain to deal with when trying to concatenate values. The
most recurring example is when it's needed to build a variable composed
of the source address and the source port. Usually it ends up like this:

    tcp-request session set-var(sess.port) src_port
    tcp-request session set-var(sess.addr) src,concat(":",sess.port)

This is even worse when trying to aggregate multiple fields from stick-table
data for example. Due to this a lot of users instead abuse headers from HTTP
rules:

    http-request set-header(x-addr) %[src]:%[src_port]

But this requires some careful cleanups to make sure they won't leak, and
it's significantly more expensive to deal with. And generally speaking it's
not clean. Plus it must be performed for each and every request, which is
expensive for this common case of ip+port that doesn't change for the whole
session.

This patch addresses this limitation by implementing a new "set-var-fmt"
action which performs the same work as "set-var" but takes a format string
in argument instead of an expression. This way it becomes pretty simple to
just write:

    tcp-request session set-var-fmt(sess.addr) %[src]:%[src_port]

It is usable in all rulesets that already support the "set-var" action.
It is not yet implemented for the global "set-var" directive (which already
takes a string) and the CLI's "set var" command, which would definitely
benefit from it but currently uses its own parser and engine, thus it
must be reworked.

The doc and regtests were updated.
2021-09-02 21:22:22 +02:00
Willy Tarreau
54b96d9955 BUG/MINOR: vars: properly set the argument parsing context in the expression
When the expression called in "set-var" uses argments that require late
resolution, the context must be set. At the moment, any unknown argument
is misleadingly reported as "ACL":

    frontend f
        bind :8080
        mode http
        http-request set-var(proc.a) be_conn(foo)

   parsing [b1.cfg:4]: unable to find backend 'foo' referenced in arg 1 \
   of ACL keyword 'be_conn' in proxy 'f'.

Once the context is properly set, it now says the truth:

   parsing [b1.cfg:8]: unable to find backend 'foo' referenced in arg 1 \
   of sample fetch keyword 'be_conn' in http-request expression in proxy 'f'.

This may be backported but is not really important. If so, the preceeding
patches "BUG/MINOR: vars: improve accuracy of the rules used to check
expression validity" and "MINOR: sample: add missing ARGC_ entries" must
be backported as well.
2021-09-02 20:34:30 +02:00
Willy Tarreau
57467b8356 MINOR: sample: add missing ARGC_ entries
For a long time we couldn't have arguments in expressions used in
tcp-request, tcp-response etc rules. But now due to the variables
it's possible, and their context in case of failure to resolve an
argument (e.g. backend name not found) is not properly reported
because there is no arg context values in ARGC_* to report them.

Let's add a number of missing ones for tcp-request {connection,
session,content}, tcp-response content, tcp-check, the config
parser (for "set-var" in the global section) and the CLI parser
(for "set-var" on the CLI).
2021-09-02 19:43:20 +02:00
Willy Tarreau
843096d72a BUG/MINOR: vars: improve accuracy of the rules used to check expression validity
The set-var() expression naturally checks whether expressions are valid
in the context of the rule, but it fails to differentiate frontends from
backends. As such for tcp-content and http-request rules, it will only
accept frontend-compatible sample-fetches, excluding those declared with
SMP_UES_BKEND (a few such as be_id, be_name). For the response it accepts
the backend-compatible expressions only, though it seems that there are
no sample-fetch function that are valid only in the frontend's content,
so that should not cause any problem.

Note that while allowing valid configs to be used, the fix might also
uncover some incorrect configurations where some expressions currently
return nothing (e.g. something depending on frontend declared in a
backend), and which could be rejected, but there does not seem to be
any such keyword. Thus while it should be backported, better not backport
it too far (2.4 and possibly 2.3 only).
2021-09-02 19:23:43 +02:00
Willy Tarreau
2819210a83 BUG/MINOR: vars: fix set-var/unset-var exclusivity in the keyword parser
The parser checks first for "set-var" then "unset-var" from the updated
offset instead of testing it only when the other one fails, so it
validates this rule as "unset-var":

    http-request set-varunset-var(proc.a)

This should be backported everywhere relevant, though it's mostly harmless
as it's unlikely that some users are purposely writing this in their conf!
2021-09-02 18:46:22 +02:00
Willy Tarreau
bc1223be79 MINOR: http-rules: add a new "ignore-empty" option to redirects.
Sometimes it is convenient to remap large sets of URIs to new ones (e.g.
after a site migration for example). This can be achieved using
"http-request redirect" combined with maps, but one difficulty there is
that non-matching entries will return an empty response. In order to
avoid this, duplicating the operation as an ACL condition ending in
"-m found" is possible but it becomes complex and error-prone while it's
known that an empty URL is not valid in a location header.

This patch addresses this by improving the redirect rules to be able to
simply ignore the rule and skip to the next one if the result of the
evaluation of the "location" expression is empty. However in order not
to break existing setups, it requires a new "ignore-empty" keyword.

There used to be an ACT_FLAG_FINAL on redirect rules that's used during
the parsing to emit a warning if followed by another rule, so here we
only set it if the option is not there. The http_apply_redirect_rule()
function now returns a 3rd value to mention that it did nothing and
that this was not an error, so that callers can just ignore the rule.
The regular "redirect" rules were not modified however since this does
not apply there.

The map_redirect VTC was completed with such a test and updated to 2.5
and an example was added into the documentation.
2021-09-02 17:06:18 +02:00
Remi Tricot-Le Breton
942c167229 MINOR: connection: Add a connection error code sample fetch for backend side
The bc_conn_err and bc_conn_err_str sample fetches give the status of
the connection on the backend side. The error codes and error messages
are the same than the ones that can be raised by the fc_conn_err fetch.
2021-09-01 22:55:54 +02:00
Remi Tricot-Le Breton
163cdeba37 MINOR: ssl: Add new ssl_bc_hsk_err sample fetch
This new sample fetch along the ssl_bc_hsk_err_str fetch contain the
last SSL error of the error stack that occurred during the SSL
handshake (from the backend's perspective).
2021-09-01 22:55:39 +02:00
Willy Tarreau
87154e3010 BUG/MAJOR: queue: better protect a pendconn being picked from the proxy
The locking in the dequeuing process was significantly improved by commit
49667c14b ("MEDIUM: queue: take the proxy lock only during the px queue
accesses") in that it tries hard to limit the time during which the
proxy's queue lock is held to the strict minimum. Unfortunately it's not
enough anymore, because we take up the task and manipulate a few pendconn
elements after releasing the proxy's lock (while we're under the server's
lock) but the task will not necessarily hold the server lock since it may
not have successfully found one (e.g. timeout in the backend queue). As
such, stream_free() calling pendconn_free() may release the pendconn
immediately after the proxy's lock is released while the other thread
currently proceeding with the dequeuing tries to wake up the owner's
task and dies in task_wakeup().

One solution consists in releasing le proxy's lock later. But tests have
shown that we'd have to sacrifice a significant share of the performance
gained with the patch above (roughly a 20% loss).

This patch takes another approach. It adds a "del_lock" to each pendconn
struct, that allows to keep it referenced while the proxy's lock is being
released. It's mostly a serialization lock like a refcount, just to maintain
the pendconn alive till the task_wakeup() call is complete. This way we can
continue to release the proxy's lock early while keeping this one. It had
to be added to the few points where we're about to free a pendconn, namely
in pendconn_dequeue() and pendconn_unlink(). This way we continue to
release the proxy's lock very early and there is no performance degradation.

This lock may only be held under the queue's lock to prevent lock
inversion.

No backport is needed since the patch above was merged in 2.5-dev only.
2021-08-31 18:37:13 +02:00
Remi Tricot-Le Breton
fe21fe76bd MINOR: log: Add new "error-log-format" option
This option can be used to define a specific log format that will be
used in case of error, timeout, connection failure on a frontend... It
will be used for any log line concerned by the log-separate-errors
option. It will also replace the format of specific error messages
decribed in section 8.2.6.
If no "error-log-format" is defined, the legacy error messages are still
emitted and the other error logs keep using the regular log-format.
2021-08-31 12:13:08 +02:00
Remi Tricot-Le Breton
3d6350e108 MINOR: log: Remove log-error-via-logformat option
This option will be replaced by a "error-log-format" that enables to use
a dedicated log-format for connection error messages instead of the
regular log-format (in which most of the fields would be invalid in such
a case).
The "log-error-via-logformat" mechanism will then be replaced by a test
on the presence of such an error log format or not. If a format is
defined, it is used for connection error messages, otherwise the legacy
error log format is used.
2021-08-31 12:13:06 +02:00
Willy Tarreau
7b2108cad1 BUILD: tools: properly guard __GLIBC__ with defined()
The test on the glibc versions based on #if (__GLIBC > 2 ...) fails to
build under -Wundef, let's prepend defined(__GLIBC__) first.
2021-08-30 10:16:30 +02:00
Willy Tarreau
b131049eb5 BUILD: ssl: fix two remaining occurrences of #if USE_OPENSSL
One was in backend.c and the other one in hlua.c. No other candidate
was found with "git grep '^#if\s*USE'". It's worth noting that 3
other such tests exist for SSL_OP_NO_{SSLv3,TLSv1_1,TLSv1_2} but
that these ones are properly set to 0 in openssl-compat.h when not
defined.
2021-08-30 09:39:24 +02:00
Tim Duesterhus
18795d48a9 BUG/MINOR: tools: Fix loop condition in dump_text()
The condition should first check whether `bsize` is reached, before
dereferencing the offset. Even if this always works fine, due to the
string being null-terminated, this certainly looks odd.

Found using GitHub's CodeQL scan.

This bug traces back to at least 97c2ae13bc
(1.7.0+) and this patch should be backported accordingly.
2021-08-30 06:14:50 +02:00
Tim Duesterhus
1f269c12dc BUG/MINOR threads: Use get_(local|gm)time instead of (local|gm)time
Using localtime / gmtime is not thread-safe, whereas the `get_*` wrappers are.

Found using GitHub's CodeQL scan.

The use in sample_conv_ltime() can be traced back to at least
fac9ccfb70 (first appearing in 1.6-dev3), so all
supported branches with thread support are affected.
2021-08-30 06:14:32 +02:00
Willy Tarreau
fc89c3fd2b IMPORT: slz: silence a build warning with -Wundef
The test on FIND_OPTIMAL_MATCH for the experimental code can yield a
build warning when using -Wundef, let's turn it into a regular ifdef.

This is slz upstream commit 05630ae8f22b71022803809eb1e7deb707bb30fb
2021-08-28 12:47:57 +02:00
Willy Tarreau
e15615c1ff BUILD: activity: use #ifdef not #if on USE_MEMORY_PROFILING
This avoids most build warnings with -Wundef, and all other USE_* flags
are tested this way, let's do it there as well. See gh issue #1369.
2021-08-28 12:04:25 +02:00
Willy Tarreau
fe456c581f MINOR: time: add report_idle() to report process-wide idle time
Before threads were introduced in 1.8, idle_pct used to be a global
variable indicating the overall process idle time. Threads made it
thread-local, meaning that its reporting in the stats made little
sense, though this was not easy to spot. In 2.0, the idle_pct variable
moved to the struct thread_info via commit 81036f273 ("MINOR: time:
move the cpu, mono, and idle time to thread_info"). It made it more
obvious that the idle_pct was per thread, and also allowed to more
accurately measure it. But no more effort was made in that direction.

This patch introduces a new report_idle() function that accurately
averages the per-thread idle time over all running threads (i.e. it
should remain valid even if some threads are paused or stopped), and
makes use of it in the stats / "show info" reports.

Sending traffic over only two connections of an 8-thread process
would previously show this erratic CPU usage pattern:

  $ while :; do socat /tmp/sock1 - <<< "show info"|grep ^Idle;sleep 0.1;done
  Idle_pct: 30
  Idle_pct: 35
  Idle_pct: 100
  Idle_pct: 100
  Idle_pct: 100
  Idle_pct: 100
  Idle_pct: 100
  Idle_pct: 100
  Idle_pct: 35
  Idle_pct: 33
  Idle_pct: 100
  Idle_pct: 100
  Idle_pct: 100
  Idle_pct: 100
  Idle_pct: 100
  Idle_pct: 100

Now it shows this more accurate measurement:

  $ while :; do socat /tmp/sock1 - <<< "show info"|grep ^Idle;sleep 0.1;done
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83
  Idle_pct: 83

This is not technically a bug but this lack of precision definitely affects
some users who rely on the idle_pct measurement. This should at least be
backported to 2.4, and might be to some older releases depending on users
demand.
2021-08-28 11:18:10 +02:00
Marcin Deranek
310a260e4a MEDIUM: config: Deprecate tune.ssl.capture-cipherlist-size
Deprecate tune.ssl.capture-cipherlist-size in favor of
tune.ssl.capture-buffer-size which better describes the purpose of the
setting.
2021-08-26 19:52:04 +02:00
Marcin Deranek
da0264a968 MINOR: sample: Add be2hex converter
Add be2hex converter to convert big-endian binary data into hex string
with optional string separators.
2021-08-26 19:48:34 +02:00
Marcin Deranek
40ca09c7bb MINOR: sample: Add be2dec converter
Add be2dec converter which allows to build JA3 compatible TLS
fingerprints by converting big-endian binary data into string
separated unsigned integers eg.

http-request set-header X-SSL-JA3 %[ssl_fc_protocol_hello_id],\
    %[ssl_fc_cipherlist_bin(1),be2dec(-,2)],\
    %[ssl_fc_extlist_bin(1),be2dec(-,2)],\
    %[ssl_fc_eclist_bin(1),be2dec(-,2)],\
    %[ssl_fc_ecformats_bin,be2dec(-,1)]
2021-08-26 19:48:34 +02:00
Marcin Deranek
959a48c116 MINOR: sample: Expose SSL captures using new fetchers
To be able to provide JA3 compatible TLS Fingerprints we need to expose
all Client Hello captured data using fetchers. Patch provides new
and modifies existing fetchers to add ability to filter out GREASE values:
- ssl_fc_cipherlist_*
- ssl_fc_ecformats_bin
- ssl_fc_eclist_bin
- ssl_fc_extlist_bin
- ssl_fc_protocol_hello_id
2021-08-26 19:48:34 +02:00
Marcin Deranek
769fd2e447 MEDIUM: ssl: Capture more info from Client Hello
When we set tune.ssl.capture-cipherlist-size to a non-zero value
we are able to capture cipherlist supported by the client. To be able to
provide JA3 compatible TLS fingerprinting we need to capture more
information from Client Hello message:
- SSL Version
- SSL Extensions
- Elliptic Curves
- Elliptic Curve Point Formats
This patch allows HAProxy to capture such information and store it for
later use.
2021-08-26 19:48:33 +02:00
Willy Tarreau
5ef965606b BUG/MINOR: lua: use strlcpy2() not strncpy() to copy sample keywords
The lua initialization code which creates the Lua mapping of all converters
and sample fetch keywords makes use of strncpy(), and as such can take ages
to start with large values of tune.bufsize because it spends its time zeroing
gigabytes of memory for nothing. A test performed with an extreme value of
16 MB takes roughly 4 seconds, so it's possible that some users with huge
1 MB buffers (e.g. for payload analysis) notice a small startup latency.
However this does not affect config checks since the Lua stack is not yet
started. Let's replace this with strlcpy2().

This should be backported to all supported versions.
2021-08-26 16:57:48 +02:00
Amaury Denoyelle
dd56520cdf BUG/MINOR: resolvers: mark servers with name-resolution as non purgeable
When a server is configured with name-resolution, resolvers objects are
created with reference to this server. Thus the server is marked as non
purgeable to prevent its removal at runtime.

This does not need to be backport.
2021-08-26 15:53:17 +02:00
William Lallemand
a39e6266d1 BUG/MINOR: proxy: don't dump servers of internal proxies
Patch 211c967 ("MINOR: httpclient: add the server to the proxy") broke
the reg-tests that do a "show servers state".

Indeed the servers of the proxies flagged with PR_CAP_INT are dumped in
the output of this CLI command.

This patch fixes the issue par ignoring the PR_CA_INT proxies in the
dump.
2021-08-25 18:15:31 +02:00
Dragan Dosen
61aa4428c1 BUG/MINOR: base64: base64urldec() ignores padding in output size check
Without this fix, the decode function would proceed even when the output
buffer is not large enough, because the padding was not considered. For
example, it would not fail with the input length of 23 and the output
buffer size of 15, even the actual decoded output size is 17.

This patch should be backported to all stable branches that have a
base64urldec() function available.
2021-08-25 16:14:14 +02:00
Amaury Denoyelle
14c3c5c121 MEDIUM: server: allow to remove servers at runtime except non purgeable
Relax the condition on "delete server" CLI handler to be able to remove
all servers, even non dynamic, except if they are flagged as non
purgeable.

This change is necessary to extend the use cases for dynamic servers
with reload. It's expected that each dynamic server created via the CLI
is manually commited in the haproxy configuration by the user. Dynamic
servers will be present on reload only if they are present in the
configuration file. This means that non-dynamic servers must be allowed
to be removable at runtime.

The dynamic servers removal reg-test has been updated and renamed to
reflect its purpose. A new test is present to check that non-purgeable
servers cannot be removed.
2021-08-25 15:53:54 +02:00
Amaury Denoyelle
86f3707d14 MINOR: server: mark servers referenced by LUA script as non purgeable
Each server that is retrieved by a LUA script is marked as non
purgeable. Note that for this to work, the script must have been
executed already once.
2021-08-25 15:53:54 +02:00
Amaury Denoyelle
0626961ad3 MINOR: server: mark referenced servers as non purgeable
Mark servers that are referenced by configuration elements as non
purgeable. This includes the following list :
- tracked servers
- servers referenced in a use-server rule
- servers referenced in a sample fetch
2021-08-25 15:53:54 +02:00
Amaury Denoyelle
bc2ebfa5a4 MEDIUM: server: extend refcount for all servers
In a future patch, it will be possible to remove at runtime every
servers, both static and dynamic. This requires to extend the server
refcount for all instances.

First, refcount manipulation functions have been renamed to better
express the API usage.

* srv_refcount_use -> srv_take
The refcount is always initialize to 1 on the server creation in
new_server. It's also incremented for each check/agent configured on a
server instance.

* free_server -> srv_drop
This decrements the refcount and if null, the server is freed, so code
calling it must not use the server reference after it. As a bonus, this
function now returns the next server instance. This is useful when
calling on the server loop without having to save the next pointer
before each invocation.

In these functions, remove the checks that prevent refcount on
non-dynamic servers. Each reference to "dynamic" in variable/function
naming have been eliminated as well.
2021-08-25 15:53:54 +02:00
Amaury Denoyelle
0a8d05d31c BUG/MINOR: stats: use refcount to protect dynamic server on dump
A dynamic server may be deleted at runtime at the same moment when the
stats applet is pointing to it. Use the server refcount to prevent
deletion in this case.

This should be backported up to 2.4, with an observability period of 2
weeks. Note that it requires the dynamic server refcounting feature
which has been implemented on 2.5; the following commits are required :

- MINOR: server: implement a refcount for dynamic servers
- BUG/MINOR: server: do not use refcount in free_server in stopping mode
- MINOR: server: return the next srv instance on free_server
2021-08-25 15:53:43 +02:00
Amaury Denoyelle
f5c1e12e44 MINOR: server: return the next srv instance on free_server
As a convenience, return the next server instance from servers list on
free_server.

This is particularily useful when using this function on the servers
list without having to save of the next pointer before calling it.
2021-08-25 15:29:19 +02:00
devnexen@gmail.com
21185970c1 MINOR: proc: setting the process to produce a core dump on FreeBSD.
using the procctl api to set the current process as traceable, thus being able to produce a core dump as well.

making it as compile option if not wished or using freebsd prior to 11.x (last no EOL release).
2021-08-25 05:14:27 +02:00
Ilya Shipitsin
ff0f278860 CLEANUP: assorted typo fixes in the code and comments
This is 26th iteration of typo fixes
2021-08-25 05:13:31 +02:00
William Lallemand
957ab13d7b BUILD: httpclient: fix build without OpenSSL
Add some defines around the ssl server so we can build without OpenSSL.
2021-08-24 18:33:28 +02:00
William Lallemand
4463b17fe3 BUG/MINOR: httpclient: fix Host header
THe http_update_update_host function takes an URL and extract the domain
to use as a host header. However it only update an existing host header
and does not create one.

This patch add an empty host header so the function can update it.
2021-08-24 17:53:03 +02:00
William Lallemand
211c9679c8 MINOR: httpclient: add the server to the proxy
Add the raw and ssl server to the proxy list so they can be freed during
the deinit() of HAProxy. As a side effect the 2 servers need to have a
different ID so the SSL one was renamed "<HTTPSCLIENT>".
2021-08-24 17:18:13 +02:00
William Lallemand
cfcbe9ebd9 MINOR: httpclient: set verify none on the https server
There is currently no way to specify the CA to verify from the
httpclient API. Sets the verify to none so we can still do https
request.
2021-08-24 17:15:58 +02:00