]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
3 years agoMEDIUM: servers: make the server deletion code run under full thread isolation
Willy Tarreau [Wed, 4 Aug 2021 12:42:37 +0000 (14:42 +0200)] 
MEDIUM: servers: make the server deletion code run under full thread isolation

In 2.4, runtime server deletion was brought by commit e558043e1 ("MINOR:
server: implement delete server cli command"). A comment remained in the
code about a theoretical race between the thread_isolate() call and another
thread being in the process of allocating memory before accessing the
server via a reference that was grabbed before the memory allocation,
since the thread_harmless_now()/thread_harmless_end() pair around mmap()
may have the effect of allowing cli_parse_delete_server() to proceed.

Now that the full thread isolation is available, let's update the code
to rely on this. Now it is guaranteed that competing threads will either
be in the poller or queued in front of thread_isolate_full().

This may be backported to 2.4 if any report of breakage suggests the bug
really exists, in which case the two following patches will also be
needed:
  MINOR: threads: make thread_release() not wait for other ones to complete
  MEDIUM: threads: add a stronger thread_isolate_full() call

3 years agoMEDIUM: threads: add a stronger thread_isolate_full() call
Willy Tarreau [Wed, 4 Aug 2021 09:44:17 +0000 (11:44 +0200)] 
MEDIUM: threads: add a stronger thread_isolate_full() call

The current principle of running under isolation was made to access
sensitive data while being certain that no other thread was using them
in parallel, without necessarily having to place locks everywhere. The
main use case are "show sess" and "show fd" which run over long chains
of pointers.

The thread_isolate() call relies on the "harmless" bit that indicates
for a given thread that it's not currently doing such sensitive things,
which is advertised using thread_harmless_now() and which ends usings
thread_harmless_end(), which also waits for possibly concurrent threads
to complete their work if they took this opportunity for starting
something tricky.

As some system calls were notoriously slow (e.g. mmap()), a bunch of
thread_harmless_now() / thread_harmless_end() were placed around them
to let waiting threads do their work while such other threads were not
able to modify memory contents.

But this is not sufficient for performing memory modifications. One such
example is the server deletion code. By modifying memory, it not only
requires that other threads are not playing with it, but are not either
in the process of touching it. The fact that a pool_alloc() or pool_free()
on some structure may call thread_harmless_now() and let another thread
start to release the same object's memory is not acceptable.

This patch introduces the concept of "idle threads". Threads entering
the polling loop are idle, as well as those that are waiting for all
others to become idle via the new function thread_isolate_full(). Once
thread_isolate_full() is granted, the thread is not idle anymore, and
it is released using thread_release() just like regular isolation. Its
users have to keep in mind that across this call nothing is granted as
another thread might have performed shared memory modifications. But
such users are extremely rare and are actually expecting this from their
peers as well.

Note that that in case of backport, this patch depends on previous patch:
  MINOR: threads: make thread_release() not wait for other ones to complete

3 years agoMINOR: threads: make thread_release() not wait for other ones to complete
Willy Tarreau [Wed, 4 Aug 2021 09:22:07 +0000 (11:22 +0200)] 
MINOR: threads: make thread_release() not wait for other ones to complete

The original intent of making thread_release() wait for other requesters to
proceed was more of a fairness trade, guaranteeing that a thread that was
granted an access to the CPU would be in turn giving back once its job is
done. But this is counter-productive as it forces such threads to spin
instead of going back to the poller, and it prevents us from implementing
multiple levels of guarantees, as a thread_release() call could spin
waiting for another requester to pass while that requester expects
stronger guarantees than the current thread may be able to offer.

Let's just remove that wait period and let the thread go back to the
poller, a-la "race to idle".

While in theory it could possibly slightly increase the perceived
latency of concurrent slow operations like "show fd" or "show sess",
it is not the case at all in tests, probably because the time needed
to reach the poller remains extremely low anyway.

3 years agoCLEANUP: thread: fix fantaisist indentation of thread_harmless_till_end()
Willy Tarreau [Wed, 4 Aug 2021 08:33:57 +0000 (10:33 +0200)] 
CLEANUP: thread: fix fantaisist indentation of thread_harmless_till_end()

Probably due to a copy-paste, there were two indent levels in this function
since its introduction in 1.9 by commit 60b639ccb ("MEDIUM: hathreads:
implement a more flexible rendez-vous point"). Let's fix this.

3 years agoBUG/MINOR: server: fix race on error path of 'add server' CLI if track
Amaury Denoyelle [Wed, 28 Jul 2021 08:06:52 +0000 (10:06 +0200)] 
BUG/MINOR: server: fix race on error path of 'add server' CLI if track

If an error occurs during a dynamic server creation with tracking, it
must be removed from the tracked list. This operation is not thread-safe
and thus must be conducted under the thread isolation.

Track support for dynamic servers has been introduced in this release.
This does not need to be backported.

3 years agoMINOR: stats: shows proxy in a stopped state
William Lallemand [Tue, 3 Aug 2021 11:18:11 +0000 (13:18 +0200)] 
MINOR: stats: shows proxy in a stopped state

Previous patch b5c0d65 ("MINOR: proxy: disabled takes a stopping and a
disabled state") allows us to set 2 states for a stopped or a disabled
proxy. With this patch we are now able to show the stats of all proxies
when the process is in a stopping states, not only when there is some
activity on a proxy.

This patch should fix issue #1307.

3 years agoMINOR: proxy: disabled takes a stopping and a disabled state
William Lallemand [Tue, 3 Aug 2021 09:58:03 +0000 (11:58 +0200)] 
MINOR: proxy: disabled takes a stopping and a disabled state

This patch splits the disabled state of a proxy into a PR_DISABLED and a
PR_STOPPED state.

The first one is set when the proxy is disabled in the configuration
file, and the second one is set upon a stop_proxy().

3 years agoMINOR: doc: rename conn_status in `option httsplog`
William Lallemand [Mon, 2 Aug 2021 08:57:49 +0000 (10:57 +0200)] 
MINOR: doc: rename conn_status in `option httsplog`

Rename the conn_status field by the real name of the sample fetch in the
`option httpslog` documentation.

3 years agoMINOR: log: rename 'dontloglegacyconnerr' to 'log-error-via-logformat'
William Lallemand [Mon, 2 Aug 2021 08:25:30 +0000 (10:25 +0200)] 
MINOR: log: rename 'dontloglegacyconnerr' to 'log-error-via-logformat'

Rename the 'dontloglegacyconnerr' option to 'log-error-via-logformat'
which is much more self-explanatory and readable.

Note: only legacy keywords don't use hyphens, it is recommended to
separate words with them in new keywords.

3 years ago[RELEASE] Released version 2.5-dev3 v2.5-dev3
Willy Tarreau [Sun, 1 Aug 2021 16:19:51 +0000 (18:19 +0200)] 
[RELEASE] Released version 2.5-dev3

Released version 2.5-dev3 with the following main changes :
    - BUG/MINOR: arg: free all args on make_arg_list()'s error path
    - BUG/MINOR: cfgcond: revisit the condition freeing mechanism to avoid a leak
    - MEDIUM: proxy: remove long-broken 'option http_proxy'
    - CLEANUP: http_ana: Remove now unused label from http_process_request()
    - MINOR: deinit: always deinit the init_mutex on failed initialization
    - BUG/MEDIUM: cfgcond: limit recursion level in the condition expression parser
    - BUG/MEDIUM: mworker: do not register an exit handler if exit is expected
    - BUG/MINOR: mworker: do not export HAPROXY_MWORKER_REEXEC across programs
    - BUILD/MINOR: memprof fix macOs build.
    - BUG/MEDIUM: ssl_sample: fix segfault for srv samples on invalid request
    - BUG/MINOR: stats: Add missing agent stats on servers
    - BUG/MINOR: check: fix the condition to validate a port-less server
    - BUILD: threads: fix pthread_mutex_unlock when !USE_THREAD
    - BUG/MINOR: resolvers: Use a null-terminated string to lookup in servers tree
    - MINOR: ssl: use __objt_* variant when retrieving counters
    - BUG/MINOR: systemd: must check the configuration using -Ws
    - BUG/MINOR: mux-h1: Obey dontlognull option for empty requests
    - BUG/MINOR: mux-h2: Obey dontlognull option during the preface
    - BUG/MINOR: mux-h1: Be sure to swap H1C to splice mode when rcv_pipe() is called
    - BUG/MEDIUM: mux-h2: Handle remaining read0 cases on partial frames
    - MINOR: proxy: rename PR_CAP_LUA to PR_CAP_INT
    - MINOR: mworker: the mworker CLI proxy is internal
    - MINOR: stats: don't output internal proxies (PR_CAP_INT)
    - CLEANUP: mworker: use the proxy helper functions in mworker_cli_proxy_create()
    - CLEANUP: mworker: PR_CAP already initialized with alloc_new_proxy()
    - BUG/MINOR: connection: Add missing error labels to conn_err_code_str
    - MINOR: connection: Add a connection error code sample fetch
    - MINOR: ssl: Enable error fetches in case of handshake error
    - MINOR: ssl: Add new ssl_fc_hsk_err sample fetch
    - MINOR: ssl: Define a default https log format
    - MEDIUM: connection: Add option to disable legacy error log
    - REGTESTS: ssl: Add tests for the connection and SSL error fetches
    - REGTESTS: ssl: ssl_errors.vtc does not work with old openssl version
    - BUG/MEDIUM: connection: close a rare race between idle conn close and takeover
    - BUG/MEDIUM: pollers: clear the sleeping bit after waking up, not before
    - BUG/MINOR: select: fix excess number of dead/skip reported
    - BUG/MINOR: poll: fix abnormally high skip_fd counter
    - BUG/MINOR: pollers: always program an update for migrated FDs
    - BUG/MINOR: fd: protect fd state harder against a concurrent takeover
    - DOC: internals: document the FD takeover process
    - MINOR: fd: update flags only once in fd_update_events()
    - MINOR: poll/epoll: move detection of RDHUP support earlier
    - REORG: fd: uninline fd_update_events()
    - MEDIUM: fd: rely more on fd_update_events() to detect changes
    - BUG/MINOR: freq_ctr: use stricter barriers between updates and readings
    - MEDIUM: atomic: simplify the atomic load/store/exchange operations
    - MEDIUM: atomic: relax the load/store barriers on x86_64
    - BUILD: opentracing: fixed build when using pkg-config utility

3 years agoBUILD: opentracing: fixed build when using pkg-config utility
Miroslav Zagorac [Thu, 29 Jul 2021 09:10:08 +0000 (11:10 +0200)] 
BUILD: opentracing: fixed build when using pkg-config utility

In case the OpenTracing C Wrapper library was installed as part of the
system (ie in a directory that pkg-config considers part of the system),
HAProxy building was not possible because in that case pkg-config did
not set the value of the OT_CFLAGS variable in the addon Makefile.

This resolves GitHub issue #1323.

3 years agoMEDIUM: atomic: relax the load/store barriers on x86_64
Willy Tarreau [Thu, 15 Jul 2021 14:02:47 +0000 (16:02 +0200)] 
MEDIUM: atomic: relax the load/store barriers on x86_64

The x86-tso model makes the load and store barriers unneeded for our
usage as long as they perform at least a compiler barrier: the CPU
will respect store ordering and store vs load ordering. It's thus
safe to remove the lfence and sfence which are normally needed only
to communicate with external devices. Let's keep the mfence though,
to make sure that reads of same memory location after writes report
the value from memory and not the one snooped from the write buffer
for too long.

An in-depth review of all use cases tends to indicate that this is
okay in the rest of the code. Some parts could be cleaned up to
use atomic stores and atomic loads instead of explicit barriers
though.

Doing this reliably increases the overall performance by about 2-2.5%
on a 8c-16t Xeon thanks to less frequent flushes (it's likely that the
biggest gain is in the MT lists which use them a lot, and that this
results in less cache line flushes).

3 years agoMEDIUM: atomic: simplify the atomic load/store/exchange operations
Willy Tarreau [Thu, 15 Jul 2021 12:48:21 +0000 (14:48 +0200)] 
MEDIUM: atomic: simplify the atomic load/store/exchange operations

The atomic_load/atomic_store/atomic_xchg operations were all forced to
__ATOMIC_SEQ_CST, which results in explicit store or even full barriers
even on x86-tso while we do not need them: we're not communicating with
external devices for example and are only interested in respecting the
proper ordering of loads and stores between each other.

These ones being rarely used, the emitted code on x86 remains almost the
same (barring a handful of locations). However they will allow to place
correct barriers at other places where atomics are accessed a bit lightly.

The patch is marked medium because we can never rule out the risk of some
bugs on more relaxed platforms due to the rest of the code.

3 years agoBUG/MINOR: freq_ctr: use stricter barriers between updates and readings
Willy Tarreau [Thu, 15 Jul 2021 13:45:44 +0000 (15:45 +0200)] 
BUG/MINOR: freq_ctr: use stricter barriers between updates and readings

update_freq_ctr_period() was using relaxed atomics without using barriers,
which usually works fine on x86 but not everywhere else. In addition, some
values were read without being enclosed by barriers, allowing the compiler
to possibly prefetch them a bit earlier. Finally, freq_ctr_total() was also
reading these without enough barriers. Let's make explicit use of atomic
loads and atomic stores to get rid of this situation. This required to
slightly rearrange the freq_ctr_total() loop, which could possibly slightly
improve performance under extreme contention by avoiding to reread all
fields.

A backport may be done to 2.4 if a problem is encountered, but last tests
on arm64 with LSE didn't show any issue so this can possibly stay as-is.

3 years agoMEDIUM: fd: rely more on fd_update_events() to detect changes
Willy Tarreau [Thu, 29 Jul 2021 14:57:19 +0000 (16:57 +0200)] 
MEDIUM: fd: rely more on fd_update_events() to detect changes

This function already performs a number of checks prior to calling the
IOCB, and detects the change of thread (FD migration). Half of the
controls are still in each poller, and these pollers also maintain
activity counters for various cases.

Note that the unreliable test on thread_mask was removed so that only
the one performed by fd_set_running() is now used, since this one is
reliable.

Let's centralize all that fd-specific logic into the function and make
it return a status among:

  FD_UPDT_DONE,        // update done, nothing else to be done
  FD_UPDT_DEAD,        // FD was already dead, ignore it
  FD_UPDT_CLOSED,      // FD was closed
  FD_UPDT_MIGRATED,    // FD was migrated, ignore it now

Some pollers already used to call it last and have nothing to do after
it, regardless of the result. epoll has to delete the FD in case a
migration is detected. Overall this removes more code than it adds.

3 years agoREORG: fd: uninline fd_update_events()
Willy Tarreau [Thu, 29 Jul 2021 14:53:46 +0000 (16:53 +0200)] 
REORG: fd: uninline fd_update_events()

This function has become a monster (80 lines and 2/3 of a kB), it doesn't
benefit from being static nor inline anymore, let's move it to fd.c.

3 years agoMINOR: poll/epoll: move detection of RDHUP support earlier
Willy Tarreau [Thu, 29 Jul 2021 14:19:24 +0000 (16:19 +0200)] 
MINOR: poll/epoll: move detection of RDHUP support earlier

Let's move the detection of support for RDHUP earlier and out of the
FD update chain, as it complicates its simplification.

3 years agoMINOR: fd: update flags only once in fd_update_events()
Willy Tarreau [Thu, 29 Jul 2021 06:04:00 +0000 (08:04 +0200)] 
MINOR: fd: update flags only once in fd_update_events()

Since 2.4 with commit f50906519 ("MEDIUM: fd: merge fdtab[].ev and state
for FD_EV_* and FD_POLL_* into state") we can merge all flag updates at
once in fd_update_events(). Previously this was performed in 1 to 3 steps,
setting the polling state, then setting READY_R if in/err/hup, and setting
READY_W if out/err. But since the commit above, all flags are stored
together in the same structure field that is being updated with the new
flags, thus we can simply update the flags altogether and avoid multiple
atomic operations. This even removes the need for atomic ops for FDs that
are not shared.

3 years agoDOC: internals: document the FD takeover process
Willy Tarreau [Fri, 30 Jul 2021 15:40:07 +0000 (17:40 +0200)] 
DOC: internals: document the FD takeover process

This explains the traps to avoid and the sequence that leads to
consistent use of an FD known by multiple threads at once. This
was co-authored with Olivier.

3 years agoBUG/MINOR: fd: protect fd state harder against a concurrent takeover
Willy Tarreau [Wed, 28 Jul 2021 15:20:53 +0000 (17:20 +0200)] 
BUG/MINOR: fd: protect fd state harder against a concurrent takeover

There's a theoretical race (that we failed to trigger) in function
fd_update_events(), which could strike on idle connections. The "locked"
variable will most often be 0 as the FD is bound to the current thread
only. Another thread could take it over once "locked" is set, change
the thread and running masks. Then the first thread updates the FD's
state non-atomically and possibly overwrites what the other thread was
preparing. It still looks like the FD's state will ultimately converge
though.

The solution against this is to set the running flag earlier so that a
takeover() attempt cannot succeed, or that the fd_set_running() attempt
fails, indicating that nothing needs to be done on this FD.

While this is sufficient for a simple fix to be backported, it leaves
the FD actively polled in the calling thread, this will trigger a second
wakeup which will notice the absence of tid_bit in the thread_mask,
getting rid of it.

A more elaborate solution would consist in calling fd_set_running()
directly from the pollers before calling fd_update_events(), getting
rid of the thread_mask test and letting the caller eliminate that FD
from its list if needed.

Interestingly, this code also proves to be suboptimal in that it sets
the FD state twice instead of calculating the new state at once and
always using a CAS to set it. This is a leftover of a simplification
that went into 2.4 and which should be explored in a future patch.

This may be backported as far as 2.2.

3 years agoBUG/MINOR: pollers: always program an update for migrated FDs
Willy Tarreau [Fri, 30 Jul 2021 12:18:49 +0000 (14:18 +0200)] 
BUG/MINOR: pollers: always program an update for migrated FDs

If an MT-aware poller reports that a file descriptor was migrated, it
must stop reporting it. The simplest way to do this is to program an
update if not done yet. This will automatically mark the FD for update
on next round. Otherwise there's a risk that some events are reported
a bit too often and cause extra CPU usage with these pollers. Note
that epoll is currently OK regarding this. Select does not need this
because it uses a single shared events table, so in case of migration
no FD change is expected.

This should be backported as far as 2.2.

3 years agoBUG/MINOR: poll: fix abnormally high skip_fd counter
Willy Tarreau [Fri, 30 Jul 2021 12:04:28 +0000 (14:04 +0200)] 
BUG/MINOR: poll: fix abnormally high skip_fd counter

The skip_fd counter that is incremented when a migrated FD is reported
was abnormally high in with poll. The reason is that it was accounted
for before preparing the polled events instead of being measured from
the reported events.

This mistake was done when the counters were introduced in 1.9 with
commit d80cb4ee1 ("MINOR: global: add some global activity counters to
help debugging"). It may be backported as far as 2.0.

3 years agoBUG/MINOR: select: fix excess number of dead/skip reported
Willy Tarreau [Fri, 30 Jul 2021 11:55:36 +0000 (13:55 +0200)] 
BUG/MINOR: select: fix excess number of dead/skip reported

In 1.8, commit ab62f5195 ("MINOR: polling: Use fd_update_events to update
events seen for a fd") updated the pollers to rely on fd_update_events(),
but the modification delayed the test of presence of the FD in the report,
resulting in owner/thread_mask and possibly event updates being performed
for each FD appearing in a block of 32 FDs around an active one. This
caused the request rate to be ~3 times lower with select() than poll()
under 6 threads.

This can be backported as far as 1.8.

3 years agoBUG/MEDIUM: pollers: clear the sleeping bit after waking up, not before
Willy Tarreau [Fri, 30 Jul 2021 08:57:09 +0000 (10:57 +0200)] 
BUG/MEDIUM: pollers: clear the sleeping bit after waking up, not before

A bug was introduced in 2.1-dev2 by commit 305d5ab46 ("MAJOR: fd: Get
rid of the fd cache."). Pollers "poll" and "evport" had the sleeping
bit accidentally removed before the syscall instead of after. This
results in them not being woken up by inter-thread wakeups, which is
particularly visible with the multi-queue accept() and with queues.

As a work-around, when these pollers are used, "nbthread 1" should
be used.

The fact that it has remained broken for 2 years is a great indication
that threads are definitely not enabled outside of epoll and kqueue,
hence why this patch is only tagged medium.

This must be backported as far as 2.2.

3 years agoBUG/MEDIUM: connection: close a rare race between idle conn close and takeover
Willy Tarreau [Wed, 28 Jul 2021 13:27:37 +0000 (15:27 +0200)] 
BUG/MEDIUM: connection: close a rare race between idle conn close and takeover

The takeover of idle conns between threads is particularly tricky, for
two reasons:
  - there's no way to atomically synchronize kernel-side polling with
    userspace activity, so late events will always be reported for some
    FDs just migrated ;

  - upon error, an FD may be immediately reassigned to whatever other
    thread since it's process-wide.

The current model uses the FD's thread_mask to figure if an FD still
ought to be reported or not, and a per-thread idle connection queue
from which eligible connections are atomically added/picked. I/Os
coming from the bottom for such a connection must remove it from the
list so that it's not elected. Same for timeout tasks and iocbs. And
these last ones check their context under the idle_conn lock to judge
if they're still allowed to run.

One rare case was omitted: the wake() callback. This one is rare, it
may serve to notify about finalized connect() calls that are not being
polled, as well as unhandled shutdowns and errors. This callback was
not protected till now because it wasn't seen as sensitive, but there
exists a particular case where it may be called without protectoin in
parallel to a takeover. This happens in the following sequence:

  - thread T1 wants to establish an outgoing connection
  - the connect() call returns EINPROGRESS
  - the poller adds it using epoll_ctl()
  - epoll_wait() reports it, connect() is done. The connection is
    not being marked as actively polled anymore but is still known
    from the poller.
  - the request is sent over that connection using send(), which
    queues to system buffers while data are being delivered
  - the scheduler switches to other tasks
  - the request is physically sent
  - the server responds
  - the stream is notified that send() succeeded, and makes progress,
    trying to recv() from that connection
  - the recv() succeeds, the response is delivered
  - the poller doesn't need to be touched (still no active polling)
  - the scheduler switches to other tasks
  - the server closes the connection
  - the poller on T1 is notified of the SHUTR and starts to call mux->wake()
  - another thread T2 takes over the connection
  - T2 continues to run inside wake() and releases the connection
  - T2 is just dereferencing it.
  - BAM.

The most logical solution here is to surround the call to wake() with an
atomic removal/insert of the connection from/into the idle conns lists.
This way, wake() is guaranteed to run alone. Any other poller reporting
the FD will not have its tid_bit in the thread_mask si will not bother
it. Another thread trying a takeover will not find this connection. A
task or tasklet being woken up late will either be on the same thread,
or be called on another one with a NULL context since it will be the
consequence of previous successful takeover, and will be ignored. Note
that the extra cost of a lock and tree access here have a low overhead
which is totally amortized given that these ones roughly happen 1-2
times per connection at best.

While it was possible to crash the process after 10-100k req using H2
and a hand-refined configuration achieving perfect synchronism between
a long (20+) chain of proxies and a short timeout (1ms), now with that
fix this never happens even after 10M requests.

Many thanks to Olivier for proposing this solution and explaining why
it works.

This should be backported as far as 2.2 (when inter-thread takeover was
introduced). The code in older versions will be found in conn_fd_handler().
A workaround consists in disabling inter-thread pool sharing using:

    tune.idle-pool.shared off

3 years agoREGTESTS: ssl: ssl_errors.vtc does not work with old openssl version
William Lallemand [Thu, 29 Jul 2021 14:00:24 +0000 (16:00 +0200)] 
REGTESTS: ssl: ssl_errors.vtc does not work with old openssl version

Disable the new ssl_errors.vtc reg-tests because in does not work
correctly on the CI since it requires a version of OpenSSL which is
compatible with TLSv1.3 and the ciphersuites keyword.

3 years agoREGTESTS: ssl: Add tests for the connection and SSL error fetches
Remi Tricot-Le Breton [Thu, 29 Jul 2021 07:45:54 +0000 (09:45 +0200)] 
REGTESTS: ssl: Add tests for the connection and SSL error fetches

This reg-test checks that the connection and SSL sample fetches related
to errors are functioning properly. It also tests the proper behaviour
of the default HTTPS log format and of the log-legacy-conn-error option
which enables or disables the output of a special error message in case
of connection failure (otherwise a line following the configured
log-format is output).

3 years agoMEDIUM: connection: Add option to disable legacy error log
Remi Tricot-Le Breton [Thu, 29 Jul 2021 07:45:53 +0000 (09:45 +0200)] 
MEDIUM: connection: Add option to disable legacy error log

In case of connection failure, a dedicated error message is output,
following the format described in section "Error log format" of the
documentation. These messages cannot be configured through a log-format
option.
This patch adds a new option, "dontloglegacyconnerr", that disables
those error logs when set, and "replaces" them by a regular log line
that follows the configured log-format (thanks to a call to sess_log in
session_kill_embryonic).
The new fc_conn_err sample fetch allows to add the legacy error log
information into a regular log format.
This new option is unset by default so the logging logic will remain the
same until this new option is used.

3 years agoMINOR: ssl: Define a default https log format
Remi Tricot-Le Breton [Thu, 29 Jul 2021 07:45:52 +0000 (09:45 +0200)] 
MINOR: ssl: Define a default https log format

This patch adds a new httpslog option and a new HTTP over SSL log-format
that expands the default HTTP format and adds SSL specific information.

3 years agoMINOR: ssl: Add new ssl_fc_hsk_err sample fetch
Remi Tricot-Le Breton [Thu, 29 Jul 2021 07:45:51 +0000 (09:45 +0200)] 
MINOR: ssl: Add new ssl_fc_hsk_err sample fetch

This new sample fetch along the ssl_fc_hsk_err_str fetch contain the
last SSL error of the error stack that occurred during the SSL
handshake (from the frontend's perspective). The errors happening during
the client's certificate verification will still be given by the
ssl_c_err and ssl_c_ca_err fetches. This new fetch will only hold errors
retrieved by the OpenSSL ERR_get_error function.

3 years agoMINOR: ssl: Enable error fetches in case of handshake error
Remi Tricot-Le Breton [Thu, 29 Jul 2021 07:45:50 +0000 (09:45 +0200)] 
MINOR: ssl: Enable error fetches in case of handshake error

The ssl_c_err, ssl_c_ca_err and ssl_c_ca_err_depth sample fetches values
were not recoverable when the connection failed because of the test
"conn->flags & CO_FL_WAIT_XPRT" (which required the connection to be
established). They could then not be used in a log-format since whenever
they would have sent a non-null value, the value fetching was disabled.
This patch ensures that all these values can be fetched in case of
connection failure.

3 years agoMINOR: connection: Add a connection error code sample fetch
Remi Tricot-Le Breton [Thu, 29 Jul 2021 07:45:49 +0000 (09:45 +0200)] 
MINOR: connection: Add a connection error code sample fetch

The fc_conn_err and fc_conn_err_str sample fetches give information
about the problem that made the connection fail. This information would
previously only have been given by the error log messages meaning that
thanks to these fetches, the error log can now be included in a custom
log format. The log strings were all found in the conn_err_code_str
function.

3 years agoBUG/MINOR: connection: Add missing error labels to conn_err_code_str
Remi Tricot-Le Breton [Thu, 29 Jul 2021 07:45:48 +0000 (09:45 +0200)] 
BUG/MINOR: connection: Add missing error labels to conn_err_code_str

The CO_ER_SSL_EARLY_FAILED and CO_ER_CIP_TIMEOUT connection error codes
were missing in the conn_err_code_str switch which converts the error
codes into string.

This patch can be backported on all stable branches.

3 years agoCLEANUP: mworker: PR_CAP already initialized with alloc_new_proxy()
William Lallemand [Thu, 29 Jul 2021 13:35:48 +0000 (15:35 +0200)] 
CLEANUP: mworker: PR_CAP already initialized with alloc_new_proxy()

Remove the PR_CAP initialization in mworker_cli_proxy_create() which is
already done in alloc_new_proxy().

3 years agoCLEANUP: mworker: use the proxy helper functions in mworker_cli_proxy_create()
William Lallemand [Thu, 29 Jul 2021 13:13:22 +0000 (15:13 +0200)] 
CLEANUP: mworker: use the proxy helper functions in mworker_cli_proxy_create()

Cleanup the mworker_cli_proxy_create() function by removing the
allocation and init of the proxy which is done manually, and replace it
by alloc_new_proxy(). Do the same with the free_proxy() function.

This patch also move the insertion at the end of the function.

3 years agoMINOR: stats: don't output internal proxies (PR_CAP_INT)
William Lallemand [Wed, 28 Jul 2021 15:45:18 +0000 (17:45 +0200)] 
MINOR: stats: don't output internal proxies (PR_CAP_INT)

Disable the output of the statistics of internal proxies (PR_CAP_INT),
wo we don't rely only on the px->uuid > 0. This will allow to hide more
cleanly the internal proxies in the stats.

3 years agoMINOR: mworker: the mworker CLI proxy is internal
William Lallemand [Wed, 28 Jul 2021 15:40:56 +0000 (17:40 +0200)] 
MINOR: mworker: the mworker CLI proxy is internal

Sets the mworker CLI proxy as a internal one (PR_CAP_INT) so we could
exlude it from stats and other tests.

3 years agoMINOR: proxy: rename PR_CAP_LUA to PR_CAP_INT
William Lallemand [Wed, 28 Jul 2021 13:48:16 +0000 (15:48 +0200)] 
MINOR: proxy: rename PR_CAP_LUA to PR_CAP_INT

This patch renames the proxy capability "LUA" to "INT" so it could be
used for any internal proxy.

Every proxy that are not user defined should use this flag.

3 years agoBUG/MEDIUM: mux-h2: Handle remaining read0 cases on partial frames
Christopher Faulet [Mon, 26 Jul 2021 10:06:53 +0000 (12:06 +0200)] 
BUG/MEDIUM: mux-h2: Handle remaining read0 cases on partial frames

This part was fixed several times since commit aade4edc1 ("BUG/MEDIUM:
mux-h2: Don't handle pending read0 too early on streams") and there are
still some cases where a read0 event may be ignored because a partial frame
inhibits the event.

Here, we must take care to set H2_CF_END_REACHED flag if a read0 was
received while a partial frame header is received or if the padding length
is missing.

To ease partial frame detection, H2_CF_DEM_SHORT_READ flag is introduced. It
is systematically removed when some data are received and is set when a
partial frame is found or when dbuf buffer is empty. At the end of the
demux, if the connection must be closed ASAP or if data are missing to move
forward, we may acknowledge the pending read0 event, if any. For now,
H2_CF_DEM_SHORT_READ is not part of H2_CF_DEM_BLOCK_ANY mask.

This patch should fix the issue #1328. It must be backported as far as 2.0.

3 years agoBUG/MINOR: mux-h1: Be sure to swap H1C to splice mode when rcv_pipe() is called
Christopher Faulet [Mon, 26 Jul 2021 08:49:39 +0000 (10:49 +0200)] 
BUG/MINOR: mux-h1: Be sure to swap H1C to splice mode when rcv_pipe() is called

The splicing does not work anymore because the H1 connection is not swap to
splice mode when rcv_pipe() callback function is called. It is important to
set H1C_F_WANT_SPLICE flag to inhibit data receipt via the buffer
API. Otherwise, because there are always data in the buffer, it is not
possible to use the kernel splicing.

This bug was introduced by the commit 2b861bf72 ("MINOR: mux-h1: clean up
conditions to enabled and disabled splicing").

The patch must be backported to 2.4.

3 years agoBUG/MINOR: mux-h2: Obey dontlognull option during the preface
Christopher Faulet [Mon, 26 Jul 2021 08:18:35 +0000 (10:18 +0200)] 
BUG/MINOR: mux-h2: Obey dontlognull option during the preface

If a connection is closed during the preface while no data are received, if
the dontlognull option is set, no log message must be emitted. However, this
will still be handled as a protocol error. Only the log is omitted.

This patch should fix the issue #1336 for H2 sessions. It must be backported
to 2.4 and 2.3 at least, and probably as far as 2.0.

3 years agoBUG/MINOR: mux-h1: Obey dontlognull option for empty requests
Christopher Faulet [Mon, 26 Jul 2021 07:42:49 +0000 (09:42 +0200)] 
BUG/MINOR: mux-h1: Obey dontlognull option for empty requests

If a H1 connection is closed while no data are received, if the dontlognull
option is set, no log message must be emitted. Because the H1 multiplexer
handles early errors, it must take care to obey this option. It is true for
400-Bad-Request, 408-Request-Time-out and 501-Not-Implemented
responses. 500-Internal-Server-Error responses are still logged.

This patch should fix the issue #1336 for H1 sessions. It must be backported
to 2.4.

3 years agoBUG/MINOR: systemd: must check the configuration using -Ws
William Lallemand [Mon, 26 Jul 2021 09:03:54 +0000 (11:03 +0200)] 
BUG/MINOR: systemd: must check the configuration using -Ws

When doing a reload with a configuration which requires the
master-worker mode, the configuration check will fail because the check
is not done with -W/-Ws.

Example:
wla@kikyo:~/haproxy$ ./haproxy -Ws -c -f haproxy.cfg
Configuration file is valid
wla@kikyo:~/haproxy$ ./haproxy -c -f haproxy.cfg
[NOTICE]   (13153) : haproxy version is 2.5-dev2-4567b3-16
[NOTICE]   (13153) : path to executable is ./haproxy
[ALERT]    (13153) : config : Can't use a 'program' section without master worker mode.
[ALERT]    (13153) : config : Fatal errors found in configuration.

This patch fixes the issue by adding -Ws on the check command line.

Must be backported in all stable branches. (The file was previously in
contrib/systemd/haproxy.service.in).

3 years agoMINOR: ssl: use __objt_* variant when retrieving counters
Amaury Denoyelle [Mon, 26 Jul 2021 07:59:06 +0000 (09:59 +0200)] 
MINOR: ssl: use __objt_* variant when retrieving counters

Use non-checked function to retrieve listener/server via obj_type. This
is done as a previous obj_type function ensure that the type is well
known and the instance is not NULL.

Incidentally, this should prevent the coverity report from the #1335
github issue which warns about a possible NULL dereference.

3 years agoBUG/MINOR: resolvers: Use a null-terminated string to lookup in servers tree
Christopher Faulet [Thu, 22 Jul 2021 12:29:26 +0000 (14:29 +0200)] 
BUG/MINOR: resolvers: Use a null-terminated string to lookup in servers tree

When we evaluate a DNS response item, it may be necessary to look for a
server with a hostname matching the item target into the named servers
tree. To do so, the item target is transformed to a lowercase string. It
must be a null-terminated string. Thus we must explicitly set the trailing
'\0' character.

For a specific resolution, the named servers tree contains all servers using
this resolution with a hostname loaded from a state file. Because of this
bug, same entry may be duplicated because we are unable to find the right
server, assigning this way the item to a free server slot.

This patch should fix the issue #1333. It must be backported as far as 2.2.

3 years agoBUILD: threads: fix pthread_mutex_unlock when !USE_THREAD
Willy Tarreau [Thu, 22 Jul 2021 12:42:32 +0000 (14:42 +0200)] 
BUILD: threads: fix pthread_mutex_unlock when !USE_THREAD

Commit 048368ef6 ("MINOR: deinit: always deinit the init_mutex on
failed initialization") added the missing unlock but forgot to
condition it on USE_THREAD, resulting in a build failure. No
backport is needed.

This addresses oss-fuzz issue 36426.

3 years agoBUG/MINOR: check: fix the condition to validate a port-less server
Willy Tarreau [Thu, 22 Jul 2021 09:06:41 +0000 (11:06 +0200)] 
BUG/MINOR: check: fix the condition to validate a port-less server

A config like the below fails to validate because of a bogus test:

  backend b1
      tcp-check connect port 1234
      option tcp-check
      server s1 1.2.3.4 check

[ALERT] (18887) : config : config: proxy 'b1': server 's1' has neither
                  service port nor check port, and a tcp_check rule
                  'connect' with no port information.

A || instead of a && only validates the connect rule when both the
address *and* the port are set. A work around is to set the rule like
this:

      tcp-check connect addr 0:1234 port 1234

This needs to be backported as far as 2.2 (2.0 is OK).

3 years agoBUG/MINOR: stats: Add missing agent stats on servers
Christopher Faulet [Thu, 22 Jul 2021 06:04:38 +0000 (08:04 +0200)] 
BUG/MINOR: stats: Add missing agent stats on servers

Agent stats were lost during the stats refactoring performed in the 2.4 to
simplify the Prometheus exporter. stats_fill_sv_stats() function must fill
ST_F_AGENT_* and ST_F_LAST_AGT stats.

This patch should fix the issue #1331. It must be backported to 2.4.

3 years agoBUG/MEDIUM: ssl_sample: fix segfault for srv samples on invalid request
Amaury Denoyelle [Wed, 21 Jul 2021 09:50:12 +0000 (11:50 +0200)] 
BUG/MEDIUM: ssl_sample: fix segfault for srv samples on invalid request

Some ssl samples cause a segfault when the stream is not instantiated,
for example during an invalid HTTP request. A new check is added to
prevent the stream dereferencing if NULL.

This is the list of the affected samples :
- ssl_s_chain_der
- ssl_s_der
- ssl_s_i_dn
- ssl_s_key_alg
- ssl_s_notafter
- ssl_s_notbefore
- ssl_s_s_dn
- ssl_s_serial
- ssl_s_sha1
- ssl_s_sig_alg
- ssl_s_version

This bug can be reproduced easily by using one of these samples in a
log-format string. Emit an invalid HTTP request with an HTTP client to
trigger the crash.

This bug has been reported in redmine issue 3913.

This must be backported up to 2.2.

3 years agoBUILD/MINOR: memprof fix macOs build.
David CARLIER [Tue, 20 Jul 2021 19:37:45 +0000 (20:37 +0100)] 
BUILD/MINOR: memprof fix macOs build.

this platform has a similar malloc_usable_size too.

3 years agoBUG/MINOR: mworker: do not export HAPROXY_MWORKER_REEXEC across programs
Willy Tarreau [Wed, 21 Jul 2021 08:17:02 +0000 (10:17 +0200)] 
BUG/MINOR: mworker: do not export HAPROXY_MWORKER_REEXEC across programs

This undocumented variable is only for internal use, and its sole
presence affects the process' behavior, as shown in bug #1324. It must
not be exported to workers, external checks, nor programs. Let's unset
it before forking programs and workers.

This should be backported as far as 1.8. The worker code might differ
a bit before 2.5 due to the recent removal of multi-process support.

3 years agoBUG/MEDIUM: mworker: do not register an exit handler if exit is expected
Willy Tarreau [Wed, 21 Jul 2021 08:01:36 +0000 (10:01 +0200)] 
BUG/MEDIUM: mworker: do not register an exit handler if exit is expected

The master-worker code registers an exit handler to deal with configuration
issues during reload, leading to a restart of the master process in wait
mode. But it shouldn't do that when it's expected that the program stops
during config parsing or condition checks, as the reload operation is
unexpectedly called and results in abnormal behavior and even crashes:

  $ HAPROXY_MWORKER_REEXEC=1  ./haproxy -W -c -f /dev/null
  Configuration file is valid
  [NOTICE]   (18418) : haproxy version is 2.5-dev2-ee2420-6
  [NOTICE]   (18418) : path to executable is ./haproxy
  [WARNING]  (18418) : config : Reexecuting Master process in waitpid mode
  Segmentation fault

  $ HAPROXY_MWORKER_REEXEC=1 ./haproxy -W -cc 1
  [NOTICE]   (18412) : haproxy version is 2.5-dev2-ee2420-6
  [NOTICE]   (18412) : path to executable is ./haproxy
  [WARNING]  (18412) : config : Reexecuting Master process in waitpid mode
  [WARNING]  (18412) : config : Reexecuting Master process

Note that the presence of this variable happens by accident when haproxy
is called from within its own programs (see issue #1324), but this should
be the object of a separate fix.

This patch fixes this by preventing the atexit registration in such
situations. This should be backported as far as 1.8. MODE_CHECK_CONDITION
has to be dropped for versions prior to 2.5.

3 years agoBUG/MEDIUM: cfgcond: limit recursion level in the condition expression parser
Willy Tarreau [Tue, 20 Jul 2021 15:58:34 +0000 (17:58 +0200)] 
BUG/MEDIUM: cfgcond: limit recursion level in the condition expression parser

Oss-fuzz reports in issue 36328 that we can recurse too far by passing
extremely deep expressions to the ".if" parser. I thought we were still
limited to the 1024 chars per line, that would be highly sufficient, but
we don't have any limit now :-/

Let's just pass a maximum recursion counter to the recursive parsers.
It's decremented for each call and the expression fails if it reaches
zero. On the most complex paths it can add 3 levels per parenthesis,
so with a limit of 1024, that's roughly 343 nested sub-expressions that
are supported in the worst case. That's more than sufficient, for just
a few kB of RAM.

No backport is needed.

3 years agoMINOR: deinit: always deinit the init_mutex on failed initialization
jenny-cheung [Sun, 18 Jul 2021 08:40:57 +0000 (16:40 +0800)] 
MINOR: deinit: always deinit the init_mutex on failed initialization

The init_mutex was not unlocked in case an error is encountered during
a thread initialization, and the polling loop was aborted during startup.
In practise it does not have any observable effect since an explicit
exit() is placed there, but it could confuse some debugging tools or
some static analysers, so let's release it as expected.

This addresses issue #1326.

3 years agoCLEANUP: http_ana: Remove now unused label from http_process_request()
Christopher Faulet [Mon, 19 Jul 2021 08:32:16 +0000 (10:32 +0200)] 
CLEANUP: http_ana: Remove now unused label from http_process_request()

Since last change on HTTP analysers (252412316 "MEDIUM: proxy: remove
long-broken 'option http_proxy'"), http_process_request() may only return
internal errors on failures. Thus the label used to handle bad requests may
be removed.

This patch should fix the issue #1330.

3 years agoMEDIUM: proxy: remove long-broken 'option http_proxy'
Willy Tarreau [Sun, 18 Jul 2021 17:18:56 +0000 (19:18 +0200)] 
MEDIUM: proxy: remove long-broken 'option http_proxy'

This option had always been broken in HTX, which means that the first
breakage appeared in 1.9, that it was broken by default in 2.0 and that
no workaround existed starting with 2.1. The way this option works is
praticularly unfit to the rest of the configuration and to the internal
architecture. It had some uses when it was introduced 14 years ago but
nowadays it's possible to do much better and more reliable using a
set of "http-request set-dst" and "http-request set-uri" rules, which
additionally are compatible with DNS resolution (via do-resolve) and
are not exclusive to normal load balancing. The "option-http_proxy"
example config file was updated to reflect this.

The option is still parsed so that an error message gives hints about
what to look for.

3 years agoBUG/MINOR: cfgcond: revisit the condition freeing mechanism to avoid a leak
Willy Tarreau [Sat, 17 Jul 2021 16:46:30 +0000 (18:46 +0200)] 
BUG/MINOR: cfgcond: revisit the condition freeing mechanism to avoid a leak

The cfg_free_cond_{term,and,expr}() functions used to take a pointer to
the pointer to be freed in order to replace it with a NULL once done.
But this doesn't cope well with freeing lists as it would require
recursion which the current code tried to avoid.

Let's just change the API to free the area and let the caller set the NULL.

This leak was reported by oss-fuzz (issue 36265).

3 years agoBUG/MINOR: arg: free all args on make_arg_list()'s error path
Willy Tarreau [Sat, 17 Jul 2021 16:36:43 +0000 (18:36 +0200)] 
BUG/MINOR: arg: free all args on make_arg_list()'s error path

While we do free the array containing the arguments, we do not free
allocated ones. Most of them are unresolved, but strings are allocated
and have to be freed as well. Note that for the sake of not breaking
the args resolution list that might have been set, we still refrain
from doing this if a resolution was already programmed, but for most
common cases (including the ones that can be found in config conditions
and at run time) we're safe.

This may be backported to stable branches, but it relies on the new
free_args() function that was introduced by commit ab213a5b6 ("MINOR:
arg: add a free_args() function to free an args array"), and which is
likely safe to backport as well.

This leak was reported by oss-fuzz (issue 36265).

3 years ago[RELEASE] Released version 2.5-dev2 v2.5-dev2
Willy Tarreau [Sat, 17 Jul 2021 10:35:11 +0000 (12:35 +0200)] 
[RELEASE] Released version 2.5-dev2

Released version 2.5-dev2 with the following main changes :
    - BUILD/MEDIUM: tcp: set-mark support for OpenBSD
    - DOC: config: use CREATE USER for mysql-check
    - BUG/MINOR: stick-table: fix several printf sign errors dumping tables
    - BUG/MINOR: peers: fix data_type bit computation more than 32 data_types
    - MINOR: stick-table: make skttable_data_cast to use only std types
    - MEDIUM: stick-table: handle arrays of standard types into stick-tables
    - MEDIUM: peers: handle arrays of std types in peers protocol
    - DOC: stick-table: add missing documentation about gpt0 stored type
    - MEDIUM: stick-table: add the new array of gpt data_type
    - MEDIUM: stick-table: make the use of 'gpt' excluding the use of 'gpt0'
    - MEDIUM: stick-table: add the new arrays of gpc and gpc_rate
    - MEDIUM: stick-table: make the use of 'gpc' excluding the use of 'gpc0/1''
    - BUG/MEDIUM: sock: make sure to never miss early connection failures
    - BUG/MINOR: cli: fix server name output in "show fd"
    - Revert "MINOR: tcp-act: Add set-src/set-src-port for "tcp-request content" rules"
    - MEDIUM: stats: include disabled proxies that hold active sessions to stats
    - BUILD: stick-table: shut up invalid "uninitialized" warning in gcc 8.3
    - MINOR: http: implement http_get_scheme
    - MEDIUM: http: implement scheme-based normalization
    - MEDIUM: h1-htx: apply scheme-based normalization on h1 requests
    - MEDIUM: h2: apply scheme-based normalization on h2 requests
    - REGTESTS: add http scheme-based normalization test
    - BUILD: http_htx: fix ci compilation error with isdigit for Windows
    - MINOR: http: implement http uri parser
    - MINOR: http: use http uri parser for scheme
    - MINOR: http: use http uri parser for authority
    - REORG: http_ana: split conditions for monitor-uri in wait for request
    - MINOR: http: use http uri parser for path
    - BUG/MEDIUM: http_ana: fix crash for http_proxy mode during uri rewrite
    - MINOR: mux_h2: define config to disable h2 websocket support
    - CLEANUP: applet: remove unused thread_mask
    - BUG/MINOR: ssl: Default-server configuration ignored by server
    - BUILD: add detection of missing important CFLAGS
    - BUILD: lua: silence a build warning with TCC
    - MINOR: srv: extract tracking server config function
    - MINOR: srv: do not allow to track a dynamic server
    - MEDIUM: server: support track keyword for dynamic servers
    - REGTESTS: test track support for dynamic servers
    - MINOR: init: verify that there is a single word on "-cc"
    - MINOR: init: make -cc support environment variables expansion
    - MINOR: arg: add a free_args() function to free an args array
    - CLEANUP: config: use free_args() to release args array in cfg_eval_condition()
    - CLEANUP: hlua: use free_args() to release args arrays
    - REORG: config: move the condition preprocessing code to its own file
    - MINOR: cfgcond: start to split the condition parser to introduce terms
    - MEDIUM: cfgcond: report invalid trailing chars after expressions
    - MINOR: cfgcond: remerge all arguments into a single line
    - MINOR: cfgcond: support negating conditional expressions
    - MINOR: cfgcond: make the conditional term parser automatically allocate nodes
    - MINOR: cfgcond: insert an expression between the condition and the term
    - MINOR: cfgcond: support terms made of parenthesis around expressions
    - REGTEST: make check_condition.vtc fail as soon as possible
    - REGTESTS: add more complex check conditions to check_conditions.vtc
    - BUG/MEDIUM: init: restore behavior of command-line "-m" for memory limitation

3 years agoBUG/MEDIUM: init: restore behavior of command-line "-m" for memory limitation
Willy Tarreau [Sat, 17 Jul 2021 10:31:08 +0000 (12:31 +0200)] 
BUG/MEDIUM: init: restore behavior of command-line "-m" for memory limitation

The removal for the shared inter-process cache in commit 6fd0450b4
("CLEANUP: shctx: remove the different inter-process locking techniques")
accidentally removed the enforcement of rlimit_memmax_all which
corresponds to what is passed to the command-line "-m" argument.
Let's restore it.

Thanks to @nafets227 for spotting this. This fixes github issue #1319.

3 years agoREGTESTS: add more complex check conditions to check_conditions.vtc
Willy Tarreau [Sat, 17 Jul 2021 08:43:33 +0000 (10:43 +0200)] 
REGTESTS: add more complex check conditions to check_conditions.vtc

Now that we support logic expressions, variables and parenthesis, let's
add a few more tests to check_conditions.vtc. The tests are conditionned
by the version being at least 2.5-dev2 so that it will not cause failures
during a possible later bisect session or if backported.

The test verifies that exported variables are seen, that operators precedence
works as expected, that parenthesis work at least through two levels, that an
empty condition is false while a negative number is true, and that extraneous
chars in an expression, or unfinished strings are properly caught.

3 years agoREGTEST: make check_condition.vtc fail as soon as possible
Willy Tarreau [Sat, 17 Jul 2021 08:54:46 +0000 (10:54 +0200)] 
REGTEST: make check_condition.vtc fail as soon as possible

The test consists in a sequence of shell commands, but the shell is not
necessarily started with strict errors enabled, so only the last command
provides the verdict. Let's add "set -e" to make it fail on the first
test that fails.

3 years agoMINOR: cfgcond: support terms made of parenthesis around expressions
Willy Tarreau [Fri, 16 Jul 2021 12:56:59 +0000 (14:56 +0200)] 
MINOR: cfgcond: support terms made of parenthesis around expressions

Now it's possible to form a term using parenthesis around an expression.
This will soon allow to build more complex expressions. For now they're
still pretty limited but parenthesis do work.

3 years agoMINOR: cfgcond: insert an expression between the condition and the term
Willy Tarreau [Fri, 16 Jul 2021 12:46:09 +0000 (14:46 +0200)] 
MINOR: cfgcond: insert an expression between the condition and the term

Now evaluating a condition will rely on an expression (or an empty string),
and this expression will support ORing a sub-expression with another
optional expression. The sub-expressions ANDs a term with another optional
sub-expression. With this alone precedence between && and || is respected,
and the following expression:

     A && B && C || D || E && F || G

will naturally evaluate as:

     (A && B && C) || D || (E && F) || G

3 years agoMINOR: cfgcond: make the conditional term parser automatically allocate nodes
Willy Tarreau [Fri, 16 Jul 2021 12:27:20 +0000 (14:27 +0200)] 
MINOR: cfgcond: make the conditional term parser automatically allocate nodes

It's not convenient to let the caller be responsible for node allocation,
better have the leaf function do that and implement the accompanying free
call. Now only a pointer is needed instead of a struct, and the leaf
function makes sure to leave the situation in a consistent way.

3 years agoMINOR: cfgcond: support negating conditional expressions
Willy Tarreau [Fri, 16 Jul 2021 11:56:54 +0000 (13:56 +0200)] 
MINOR: cfgcond: support negating conditional expressions

Now preceeding a config condition term with "!" will simply negate it.
Example:

   .if !feature(OPENSSL)
       .alert "SSL support is mandatory"
   .endif

3 years agoMINOR: cfgcond: remerge all arguments into a single line
Willy Tarreau [Fri, 16 Jul 2021 14:38:58 +0000 (16:38 +0200)] 
MINOR: cfgcond: remerge all arguments into a single line

Till now we were dealing with single-word expressions but in order to
extend the configuration condition language a bit more, we'll need to
support slightly more complex expressions involving operators, and we
must absolutely support spaces around them to keep them readable.

As all arguments are pointers to the same line with spaces replaced by
zeroes, we can trivially rebuild the whole line before calling the
condition evaluator, and remove the test for extraneous argument. This
is what this patch does.

3 years agoMEDIUM: cfgcond: report invalid trailing chars after expressions
Willy Tarreau [Fri, 16 Jul 2021 14:18:03 +0000 (16:18 +0200)] 
MEDIUM: cfgcond: report invalid trailing chars after expressions

Random characters placed after a configuration predicate currently do
not report an error. This is a problem because extra parenthesis,
commas or even other random left-over chars may accidently appear there.
Let's now report an error when this happens.

This is marked MEDIUM because it may break otherwise working configs
which are faulty.

3 years agoMINOR: cfgcond: start to split the condition parser to introduce terms
Willy Tarreau [Fri, 16 Jul 2021 10:12:00 +0000 (12:12 +0200)] 
MINOR: cfgcond: start to split the condition parser to introduce terms

The purpose is to build a descendent parser that will split conditions
into expressions made of terms. There are two phases, a parsing phase
and an evaluation phase. Strictly speaking it's not required to cut
that in two right now, but it's likely that in the future we won't want
certain predicates to be evaluated during the parsing (e.g. file system
checks or execution of some external commands).

The cfg_eval_condition() function is now much simpler, it just tries to
parse a single term, and if OK evaluates it, then returns the result.
Errors are unchanged and may still be reported during parsing or
evaluation.

It's worth noting that some invalid expressions such as streq(a,b)zzz
continue to parse correctly for now (what remains after the parenthesis
is simply ignored as not necessary).

3 years agoREORG: config: move the condition preprocessing code to its own file
Willy Tarreau [Fri, 16 Jul 2021 13:39:28 +0000 (15:39 +0200)] 
REORG: config: move the condition preprocessing code to its own file

The .if/.else/.endif and condition evaluation code is quite dirty and
was dumped into cfgparse.c because it was easy. But it should be tidied
quite a bit as it will need to evolve.

Let's move all that to cfgcond.{c,h}.

3 years agoCLEANUP: hlua: use free_args() to release args arrays
Willy Tarreau [Fri, 16 Jul 2021 08:26:56 +0000 (10:26 +0200)] 
CLEANUP: hlua: use free_args() to release args arrays

Argument arrays used in hlua_lua2arg_check() as well as in the functions
used to call sample fetches and converters were manually released, let's
use the cleaner and more reliable free_args() instead. The prototype of
hlua_lua2arg_check() was amended to mention that the function relies on
the final ARGT_STOP, which is already the case, and the pointless test
for this was removed.

3 years agoCLEANUP: config: use free_args() to release args array in cfg_eval_condition()
Willy Tarreau [Fri, 16 Jul 2021 08:26:09 +0000 (10:26 +0200)] 
CLEANUP: config: use free_args() to release args array in cfg_eval_condition()

Doing so is cleaner than open-coding it and will support future extensions.

3 years agoMINOR: arg: add a free_args() function to free an args array
Willy Tarreau [Fri, 16 Jul 2021 08:13:00 +0000 (10:13 +0200)] 
MINOR: arg: add a free_args() function to free an args array

make_arg_list() can create an array of arguments, some of which remain
to be resolved, but all users had to deal with their own roll back on
error. Let's add a free_args() function to release all the array's
elements and let the caller deal with the array itself (sometimes it's
allocated in the stack).

3 years agoMINOR: init: make -cc support environment variables expansion
Willy Tarreau [Fri, 16 Jul 2021 17:14:54 +0000 (19:14 +0200)] 
MINOR: init: make -cc support environment variables expansion

I found myself a few times testing some conditoin examples from the doc
against command line's "-cc" to see that they didn't work with environment
variables expansion. Not being documented as being on purpose it looks like
a miss, so let's add PARSE_OPT_ENV and PARSE_OPT_WORD_EXPAND to be able to
test for example -cc "streq(${WITH_SSL},yes)" to help debug expressions.

3 years agoMINOR: init: verify that there is a single word on "-cc"
Willy Tarreau [Fri, 16 Jul 2021 14:36:05 +0000 (16:36 +0200)] 
MINOR: init: verify that there is a single word on "-cc"

This adds the exact same restriction as commit 5546c8bdc ("MINOR:
cfgparse: Fail when encountering extra arguments in macro") but for
the "-cc" command line argument, for the sake of consistency.

3 years agoREGTESTS: test track support for dynamic servers
Amaury Denoyelle [Thu, 15 Jul 2021 09:23:17 +0000 (11:23 +0200)] 
REGTESTS: test track support for dynamic servers

Create a regtest for the 'track' keyword support by dynamic servers.

First checks are executed to ensure that tracking cannot be activated on
non-check server or dynamic servers.

Then, 3 scenarii are written to ensure that the deletion of a dynamic
server with track is properly handled and other servers in the track
chain are properly maintained.

3 years agoMEDIUM: server: support track keyword for dynamic servers
Amaury Denoyelle [Tue, 13 Jul 2021 08:36:03 +0000 (10:36 +0200)] 
MEDIUM: server: support track keyword for dynamic servers

Allow the usage of the 'track' keyword for dynamic servers. On server
deletion, the server is properly removed from the tracking chain to
prevents NULL pointer dereferencing.

3 years agoMINOR: srv: do not allow to track a dynamic server
Amaury Denoyelle [Tue, 13 Jul 2021 08:35:50 +0000 (10:35 +0200)] 
MINOR: srv: do not allow to track a dynamic server

Prevents the use of the "track" keyword for a dynamic server. This
simplifies the deletion of a dynamic server, without having to worry
about servers which might tracked it.

A BUG_ON is present in the dynamic server delete function to validate
this assertion.

3 years agoMINOR: srv: extract tracking server config function
Amaury Denoyelle [Tue, 13 Jul 2021 08:35:23 +0000 (10:35 +0200)] 
MINOR: srv: extract tracking server config function

Extract the post-config tracking setup in a dedicated function
srv_apply_track. This will be useful to implement track support for
dynamic servers.

4 years agoBUILD: lua: silence a build warning with TCC
Willy Tarreau [Wed, 14 Jul 2021 17:41:25 +0000 (19:41 +0200)] 
BUILD: lua: silence a build warning with TCC

TCC doesn't have the equivalent of __builtin_unreachable() and complains
that hlua_panic_ljmp() may return no value. Let's add a return 0 there.
All compilers that know that longjmp() doesn't return will see no change
and tcc will be happy.

4 years agoBUILD: add detection of missing important CFLAGS
Willy Tarreau [Wed, 14 Jul 2021 15:54:01 +0000 (17:54 +0200)] 
BUILD: add detection of missing important CFLAGS

Modern compilers love to break existing code, and some options detected
at build time (such as -fwrapv) are absolutely critical otherwise some
bad code can be generated.

Given that some users rely on packages that force CFLAGS without being
aware of this and can be hit by runtime bugs, we have to help packagers
figure that they need to be careful about their build options.

The test here consists in detecting correct wrapping of signed integers.
Some of the old code relies on it, and modern compilers recently decided
to break it. It's normally addressed using -fwrapv which users will
rarely enforce in their own flags. Thus it is a good indicator of missing
critical CFLAGS, and it happens to be very easy to detect at run time.
Note that the test uses argc in order to have a variable. While gcc
ignores wrapping even for constants, clang only ignores it for variables.
The way the code is constructed doesn't result in code being emitted for
optimized builds thanks to value range propagation.

This should address GitHub issue #1315, and should be backported to all
stable versions. It may result in instantly breaking binaries that seemed
to work fine (typically the ones suddenly showing a busy loop after a few
weeks of uptime), and require packagers to fix their flags. The vast
majority of distro packages are fine and will not be affected though.

4 years agoBUG/MINOR: ssl: Default-server configuration ignored by server
Remi Tricot-Le Breton [Tue, 13 Jul 2021 16:28:22 +0000 (18:28 +0200)] 
BUG/MINOR: ssl: Default-server configuration ignored by server

When a default-server line specified a client certificate to use, the
frontend would not take it into account and create an empty SSL context,
which would raise an error on the backend side ("peer did not return a
certificate").

This bug was introduced by d817dc733eacfd7cf5bb0bbc6128f44644db078e in
which the SSL contexts are created earlier than before (during the
default-server line parsing) without setting it in the corresponding
server structures. It then made the server create an empty SSL context
in ssl_sock_prepare_srv_ctx because it thought it needed one.

It was raised on redmine, in Bug #3906.

It can be backported to 2.4.

4 years agoCLEANUP: applet: remove unused thread_mask
Willy Tarreau [Tue, 13 Jul 2021 16:01:46 +0000 (18:01 +0200)] 
CLEANUP: applet: remove unused thread_mask

Since 1.9 with commit 673867c35 ("MAJOR: applets: Use tasks, instead
of rolling our own scheduler.") the thread_mask field of the appctx
became unused, but the code hadn't been cleaned for this. The appctx
has its own task and the task's thread_mask is the one to be displayed.

It's worth noting that all calls to appctx_new() pass tid_bit as the
thread_mask. This makes sense, and it could be convenient to decide
that this becomes the norm and to simplify the API.

4 years agoMINOR: mux_h2: define config to disable h2 websocket support
Amaury Denoyelle [Fri, 9 Jul 2021 15:14:30 +0000 (17:14 +0200)] 
MINOR: mux_h2: define config to disable h2 websocket support

Define a new global config statement named
"h2-workaround-bogus-websocket-clients".

This statement will disable the automatic announce of h2 websocket
support as specified in the RFC8441. This can be use to overcome clients
which fail to implement the relatively fresh RFC8441. Clients will in
his case automatically downgrade to http/1.1 for the websocket tunnel
if the haproxy configuration allows it.

This feature is relatively simple and can be backported up to 2.4, which
saw the introduction of h2 websocket support.

4 years agoBUG/MEDIUM: http_ana: fix crash for http_proxy mode during uri rewrite
Amaury Denoyelle [Thu, 8 Jul 2021 15:27:01 +0000 (17:27 +0200)] 
BUG/MEDIUM: http_ana: fix crash for http_proxy mode during uri rewrite

Fix the wrong usage of http_uri_parser which is defined with an
uninitialized uri. This causes a crash which happens when forwarding a
request to a backend configured in plain proxy ('option http_proxy').

This has been reported through a clang warning on the CI.

This bug has been introduced by the refactoring of URI parser API.
  c453f9547e14c563f7bdf03d68979a5083c0372b
  MINOR: http: use http uri parser for path
This does not need to be backported.

WARNING: although this patch fix the crash, the 'option http_proxy'
seems to be non buggy, possibly since quite a few stable versions.
Indeed, the URI rewriting is not functional : the path is written on the
beginning of the URI but the rest of the URI is not and this garbage is
passed to the server which does not understand the request.

4 years agoMINOR: http: use http uri parser for path
Amaury Denoyelle [Tue, 6 Jul 2021 09:40:12 +0000 (11:40 +0200)] 
MINOR: http: use http uri parser for path

Replace http_get_path by the http_uri_parser API. The new functions is
renamed http_parse_path. Replace duplicated code for scheme and
authority parsing by invocations to http_parse_scheme/authority.

If no scheme is found for an URI detected as an absolute-uri/authority,
consider it to be an authority format : no path will be found. For an
absolute-uri or absolute-path, use the remaining of the string as the
path. A new http_uri_parser state is declared to mark the path parsing
as done.

4 years agoREORG: http_ana: split conditions for monitor-uri in wait for request
Amaury Denoyelle [Tue, 6 Jul 2021 09:23:10 +0000 (11:23 +0200)] 
REORG: http_ana: split conditions for monitor-uri in wait for request

Split in two the condition which check if the monitor-uri is set for the
current request. This will allow to easily use the http_uri_parser type
for http_get_path.

4 years agoMINOR: http: use http uri parser for authority
Amaury Denoyelle [Tue, 6 Jul 2021 09:02:22 +0000 (11:02 +0200)] 
MINOR: http: use http uri parser for authority

Replace http_get_authority by the http_uri_parser API.

The new function is renamed http_parse_authority. Replace duplicated
scheme parsing code by http_parse_scheme invocation. A new
http_uri_parser state is declared to mark the authority parsing as done.

4 years agoMINOR: http: use http uri parser for scheme
Amaury Denoyelle [Tue, 6 Jul 2021 08:52:58 +0000 (10:52 +0200)] 
MINOR: http: use http uri parser for scheme

Replace http_get_scheme by the http_uri_parser API. The new function is
renamed http_parse_scheme. A new http_uri_parser state is declared to
mark the scheme parsing as completed.

4 years agoMINOR: http: implement http uri parser
Amaury Denoyelle [Tue, 6 Jul 2021 08:48:44 +0000 (10:48 +0200)] 
MINOR: http: implement http uri parser

Implement a http uri parser type. This type will be used as a context to
parse the various elements of an uri.

The goal of this serie of patches is to factorize duplicated code
between the http_get_scheme/authority/path functions. A simple parsing
API is designed to be able to extract once each element of an HTTP URI
in order. The functions will be renamed in the following patches to
reflect the API change with the prefix http_parse_*.

For the parser API, the http_uri_parser type must first be
initialized before usage. It will register the URI to parse and detect
its format according to the rfc 7230.

4 years agoBUILD: http_htx: fix ci compilation error with isdigit for Windows
Amaury Denoyelle [Wed, 7 Jul 2021 15:17:39 +0000 (17:17 +0200)] 
BUILD: http_htx: fix ci compilation error with isdigit for Windows

The warning is encountered on platforms for which char type is signed by
default.

cf the following links
https://stackoverflow.com/questions/10186219/array-subscript-has-type-char

This must be backported up to 2.4.

4 years agoREGTESTS: add http scheme-based normalization test
Amaury Denoyelle [Wed, 7 Jul 2021 08:49:29 +0000 (10:49 +0200)] 
REGTESTS: add http scheme-based normalization test

This test ensure that http scheme-based normalization is properly
applied on target URL and host header. It uses h2 clients as it is not
possible to specify an absolute url for h1 vtc clients.

4 years agoMEDIUM: h2: apply scheme-based normalization on h2 requests
Amaury Denoyelle [Wed, 7 Jul 2021 08:49:28 +0000 (10:49 +0200)] 
MEDIUM: h2: apply scheme-based normalization on h2 requests

Apply the rfc 3986 scheme-based normalization on h2 requests. This
process will be executed for most of requests because scheme and
authority are present on every h2 requests, except CONNECT. However, the
normalization will only be applied on requests with defaults http port
(http/80 or https/443) explicitly specified which most http clients
avoid.

This change is notably useful for http2 websockets with Firefox which
explicitly specify the 443 default port on Extended CONNECT. In this
case, users can be trapped if they are using host routing without
removing the port. With the scheme-based normalization, the default port
will be removed.

To backport this change, it is required to backport first the following
commits:
* MINOR: http: implement http_get_scheme
* MEDIUM: http: implement scheme-based normalization

4 years agoMEDIUM: h1-htx: apply scheme-based normalization on h1 requests
Amaury Denoyelle [Wed, 7 Jul 2021 08:49:27 +0000 (10:49 +0200)] 
MEDIUM: h1-htx: apply scheme-based normalization on h1 requests

Apply the rfc 3986 scheme-based normalization on h1 requests. It is
executed only for requests which uses absolute-form target URI, which is
not the standard case.

4 years agoMEDIUM: http: implement scheme-based normalization
Amaury Denoyelle [Wed, 7 Jul 2021 08:49:26 +0000 (10:49 +0200)] 
MEDIUM: http: implement scheme-based normalization

Implement the scheme-based uri normalization as described in rfc3986
6.3.2. Its purpose is to remove the port of an uri if the default one is
used according to the uri scheme : 80/http and 443/https. All other
ports are not touched.

This method uses an htx message as an input. It requires that the target
URI is in absolute-form with a http/https scheme. This represents most
of h2 requests except CONNECT. On the contrary, most of h1 requests
won't be elligible as origin-form is the standard case.

The normalization is first applied on the target URL of the start line.
Then, it is conducted on every Host headers present, assuming that they
are equivalent to the target URL.

This change will be notably useful to not confuse users who are
accustomed to use the host for routing without specifying default ports.
This problem was recently encountered with Firefox which specify the 443
default port for http2 websocket Extended CONNECT.

4 years agoMINOR: http: implement http_get_scheme
Amaury Denoyelle [Wed, 7 Jul 2021 08:49:25 +0000 (10:49 +0200)] 
MINOR: http: implement http_get_scheme

This method can be used to retrieve the scheme part of an uri, with the
suffix '://'. It will be useful to implement scheme-based normalization.

4 years agoBUILD: stick-table: shut up invalid "uninitialized" warning in gcc 8.3
Willy Tarreau [Tue, 6 Jul 2021 16:51:12 +0000 (18:51 +0200)] 
BUILD: stick-table: shut up invalid "uninitialized" warning in gcc 8.3

gcc 8.3.0 spews a bunch of:

  src/stick_table.c: In function 'action_inc_gpc0':
  include/haproxy/freq_ctr.h:66:12: warning: 'period' may be used uninitialized in this function [-Wmaybe-uninitialized]
    curr_tick += period;
            ^~
  src/stick_table.c:2241:15: note: 'period' was declared here
    unsigned int period;
               ^~~~~~
but they're incorrect because all accesses are guarded by the exact same
condition (ptr1 not being null), it's just the compiler being overzealous
about the uninitialized detection that seems to be stronger than its
ability to follow its own optimizations. This code path is not critical,
let's just pre-initialize the period to zero.

No backport is needed.

4 years agoMEDIUM: stats: include disabled proxies that hold active sessions to stats
Marno Krahmer [Thu, 24 Jun 2021 14:51:08 +0000 (16:51 +0200)] 
MEDIUM: stats: include disabled proxies that hold active sessions to stats

After reloading HAProxy, the old process may still hold active sessions.
Currently there is no way to gather information, how many sessions such
a process still holds. This patch will not exclude disabled proxies from
stats output when they hold at least one active session. This will allow
sending `!@<PID> show stat` through a master socket to the disabled
process and have it returning its stats data.

4 years agoRevert "MINOR: tcp-act: Add set-src/set-src-port for "tcp-request content" rules"
Christopher Faulet [Tue, 6 Jul 2021 09:25:36 +0000 (11:25 +0200)] 
Revert "MINOR: tcp-act: Add set-src/set-src-port for "tcp-request content" rules"

This reverts commit 19bbbe05629ea947dd60d5b96d96f0066b047b97.

For now, set-src/set-src-port actions are directly performed on the client
connection. Using these actions at the stream level is really a problem with
HTTP connection (See #90) because all requests are affected by this change
and not only the current request. And it is worse with the H2, because
several requests can set their source address into the same connection at
the same time.

It is already an issue when these actions are called from "http-request"
rules. It is safer to wait a bit before adding the support to "tcp-request
content" rules. The solution is to be able to set src/dst address on the
stream and not on the connection when the action if performed from the L7
level..

Reverting the above commit means the issue #1303 is no longer fixed.

This patch must be backported in all branches containing the above commit
(as far as 2.0 for now).

4 years agoBUG/MINOR: cli: fix server name output in "show fd"
Willy Tarreau [Tue, 6 Jul 2021 09:41:10 +0000 (11:41 +0200)] 
BUG/MINOR: cli: fix server name output in "show fd"

A server name was displayed as <srv>/<proxy> instead of the reverse.
It only confuses diagnostics. This was introduced by commit 7a4a0ac71
("MINOR: cli: add a new "show fd" command") so this fix can be backport
down to 1.8.