]> git.ipfire.org Git - thirdparty/haproxy.git/log
thirdparty/haproxy.git
3 years agoBUG/MINOR: mux-h1: Save shutdown mode if the shutdown is delayed
Christopher Faulet [Wed, 27 Oct 2021 13:36:38 +0000 (15:36 +0200)] 
BUG/MINOR: mux-h1: Save shutdown mode if the shutdown is delayed

The connection shutdown may be delayed if there are pending outgoing
data. The action is performed once data are fully sent. In this case the
mode (dirty/clean) was lost and a clean shutdown was always performed. Now,
the mode is saved to be sure to perform the connection shutdown using the
right mode. To do so, H1C_F_ST_SILENT_SHUT flag is introduced.

This patch should be backported as far as 2.0.

3 years agoDOC: Typo fixed "it" should be "is"
Anubhav [Thu, 14 Oct 2021 16:58:25 +0000 (22:28 +0530)] 
DOC: Typo fixed "it" should be "is"

This patch was proposed in GitHub PR #1415.

Reviewed-by: Tim Duesterhus <tim@bastelstu.be>
3 years agoMINOR: halog: Add support for extracting captures using -hdr
Tim Duesterhus [Thu, 28 Oct 2021 15:24:02 +0000 (17:24 +0200)] 
MINOR: halog: Add support for extracting captures using -hdr

This patch adds support for extracting captured header fields to halog. A field
can be extracted by passing the `-hdr <block>:<field>` output filter.

Both `<block>` and `<field>` are 1-indexed.

`<block>` refers to the index of the brace-delimited list of headers. If both
request and response headers are captured, then request headers are referenced
by `<block> = 1`, response headers are `2`. If only one direction is captured,
there will only be a single block `1`.

`<field>` refers to a single field within the selected block.

The output will contain one line, possibly empty, per log line processed.
Passing a non-existent `<block>` or `<field>` will result in an empty line.

Example:

    capture request  header a len 50
    capture request  header b len 50
    capture request  header c len 50
    capture response header d len 50
    capture response header e len 50
    capture response header f len 50

`-srv 1:1` will extract request  header `a`
`-srv 1:2` will extract request  header `b`
`-srv 1:3` will extract request  header `c`
`-srv 2:3` will extract response header `f`

This resolves GitHub issue #1146.

3 years agoBUG/MINOR: halog: Add missing newlines in die() messages
Tim Duesterhus [Thu, 28 Oct 2021 15:06:23 +0000 (17:06 +0200)] 
BUG/MINOR: halog: Add missing newlines in die() messages

This newline is required to correctly print the usage.

3 years agoCLEANUP: halog: Use consistent indentation in help()
Tim Duesterhus [Thu, 28 Oct 2021 13:55:49 +0000 (15:55 +0200)] 
CLEANUP: halog: Use consistent indentation in help()

Consistently use 1 Tab per line.

3 years agoMINOR: halog: Rename -qry to -query
Tim Duesterhus [Thu, 28 Oct 2021 14:36:03 +0000 (16:36 +0200)] 
MINOR: halog: Rename -qry to -query

With the query flag moved into the correct help section, there is enough space
for two additional characters.

3 years agoDOC: halog: Move the `-qry` parameter into the correct section in help text
Tim Duesterhus [Thu, 28 Oct 2021 13:53:37 +0000 (15:53 +0200)] 
DOC: halog: Move the `-qry` parameter into the correct section in help text

This is not an output filter, but instead a modifier. Specifically "only one
may be used at a time" is not true.

see 24b8d693b202b01b649f64ed878d8f9dd1b242e4

3 years agoREGTESTS: lua: test httpclient with body streaming
William Lallemand [Thu, 28 Oct 2021 13:57:33 +0000 (15:57 +0200)] 
REGTESTS: lua: test httpclient with body streaming

Improve the httpclient reg-tests to test the streaming,

The regtest now sends a big payload to vtest, then receive a payload
from vtest and send it again.

3 years agoMINOR: httpclient/lua: handle the streaming into the lua applet
William Lallemand [Thu, 28 Oct 2021 13:41:38 +0000 (15:41 +0200)] 
MINOR: httpclient/lua: handle the streaming into the lua applet

With this feature the lua implementation of the httpclient is now able
to stream a payload larger than an haproxy buffer.

The hlua_httpclient_send() function is now split into:

hlua_httpclient_send() which initiate the httpclient and parse the lua
parameters

hlua_httpclient_snd_yield() which will send the request and be called
again to stream the request if the body is larger than an haproxy buffer

hlua_httpclient_rcv_yield() which will receive the response and store it
in the lua buffer.

3 years agoMINOR: httpclient: request streaming with a callback
William Lallemand [Thu, 28 Oct 2021 13:34:26 +0000 (15:34 +0200)] 
MINOR: httpclient: request streaming with a callback

This patch add a way to handle HTTP requests streaming using a
callback.

The end of the data must be specified by using the "end" parameter in
httpclient_req_xfer().

3 years agoMINOR: atomic: remove the memcpy() call and dependency on string.h
Willy Tarreau [Thu, 28 Oct 2021 07:41:29 +0000 (09:41 +0200)] 
MINOR: atomic: remove the memcpy() call and dependency on string.h

The memcpy() call in the aarch64 version of __ha_cas_dw() is sometimes
inlined and sometimes not, depending on the gcc version. It's only used
to copy two void*, so let's use direct assignment instead of memcpy().
It would also be possible to change the asm code to directly write there,
but it's not worth it.

With this change the code is 8kB smaller with gcc-5.4.

3 years agoBUILD: atomic: fix build on mac/arm64
David CARLIER [Sat, 23 Oct 2021 13:43:42 +0000 (14:43 +0100)] 
BUILD: atomic: fix build on mac/arm64

The inline assembly is invalid for this platform thus falling back
to the builtin instead.

3 years agoBUILD: atomic: prefer __atomic_compare_exchange_n() for __ha_cas_dw()
Willy Tarreau [Thu, 28 Oct 2021 06:53:33 +0000 (08:53 +0200)] 
BUILD: atomic: prefer __atomic_compare_exchange_n() for __ha_cas_dw()

__atomic_compare_exchange() is incorrectly documented in the gcc builtins
doc, it says the desired value is "type *desired" while in reality it is
"const type *desired" as expected since that value must in no way be
modified by the operation. However it seems that clang has implemented
it as documented, and reports build warnings when fed a const.

This is quite problematic because it means we have to betry the callers,
pretending we won't touch their constants but not knowing what the
compiler would do with them, and possibly hiding future bugs.

Instead of forcing a cast, let's just switch to the better
__atomic_compare_exchange_n() that takes a value instead of a pointer.
At least with this one there is no doubt about how the input will be
used.

It was verified that the output object code is the same both in clang
and gcc with this change.

3 years agoCLEANUP: hlua: Remove obsolete branch in `hlua_alloc()`
Tim Duesterhus [Sat, 23 Oct 2021 17:56:40 +0000 (19:56 +0200)] 
CLEANUP: hlua: Remove obsolete branch in `hlua_alloc()`

This branch is no longer required, because the `!nsize` case is handled for any
value of `ptr` now.

see 22586524e32f14c44239063088a38ccea8abc9b7
see a5efdff93c36f75345a2a18f18bffee9b602bc7b

3 years agoDEV: coccinelle: Add realloc_leak.cocci
Tim Duesterhus [Sat, 23 Oct 2021 17:53:35 +0000 (19:53 +0200)] 
DEV: coccinelle: Add realloc_leak.cocci

This coccinelle patch finds locations where the return value of `realloc()` is
assigned to the pointer passed to `realloc()`. This calls will leak memory if
`realloc()` returns `NULL`.

3 years agoCLEANUP: jwt: Remove the use of a trash buffer in jwt_jwsverify_rsa_ecdsa()
Tim Duesterhus [Mon, 18 Oct 2021 16:40:29 +0000 (18:40 +0200)] 
CLEANUP: jwt: Remove the use of a trash buffer in jwt_jwsverify_rsa_ecdsa()

`trash` was completely unused within this function.

3 years agoCLEANUP: jwt: Remove the use of a trash buffer in jwt_jwsverify_hmac()
Tim Duesterhus [Mon, 18 Oct 2021 16:40:28 +0000 (18:40 +0200)] 
CLEANUP: jwt: Remove the use of a trash buffer in jwt_jwsverify_hmac()

The OpenSSL documentation (https://www.openssl.org/docs/man1.1.0/man3/HMAC.html)
specifies:

> It places the result in md (which must have space for the output of the hash
> function, which is no more than EVP_MAX_MD_SIZE bytes). If md is NULL, the
> digest is placed in a static array. The size of the output is placed in
> md_len, unless it is NULL. Note: passing a NULL value for md to use the
> static array is not thread safe.

`EVP_MAX_MD_SIZE` appears to be defined as `64`, so let's simply use a stack
buffer to avoid the whole memory management.

3 years agoMINOR: halog: Add -qry parameter allowing to preserve the query string in -uX
Tim Duesterhus [Mon, 18 Oct 2021 10:12:02 +0000 (12:12 +0200)] 
MINOR: halog: Add -qry parameter allowing to preserve the query string in -uX

Our use-case for this is a dynamic application that performs routing based on
the query string. Without this option all URLs will just point to the central
entrypoint of this location, making the output completely useless.

3 years agoMINOR: protocols: replace protocol_by_family() with protocol_lookup()
Willy Tarreau [Wed, 27 Oct 2021 15:41:07 +0000 (17:41 +0200)] 
MINOR: protocols: replace protocol_by_family() with protocol_lookup()

At a few places we were still using protocol_by_family() instead of
the richer protocol_lookup(). The former is limited as it enforces
SOCK_STREAM and a stream protocol at the control layer. At least with
protocol_lookup() we don't have this limitationn. The values were still
set for now but later we can imagine making them configurable on the
fly.

3 years agoMINOR: protocols: make use of the protocol type to select the protocol
Willy Tarreau [Wed, 27 Oct 2021 15:28:55 +0000 (17:28 +0200)] 
MINOR: protocols: make use of the protocol type to select the protocol

Instead of using sock_type and ctrl_type to select a protocol, let's
make use of the new protocol type. For now they always match so there
is no change. This is applied to address parsing and to socket retrieval
from older processes.

3 years agoMINOR: protocols: add a new protocol type selector
Willy Tarreau [Wed, 27 Oct 2021 15:05:36 +0000 (17:05 +0200)] 
MINOR: protocols: add a new protocol type selector

The protocol selection is currently performed based on the family,
control type and socket type. But this is often not enough, as both
only provide DGRAM or STREAM, leaving few variants. Protocols like
SCTP for example might be indistinguishable from TCP here. Same goes
for TCP extensions like MPTCP.

This commit introduces a new enum proto_type that is placed in each
and every protocol definition, that will usually more or less match
the sock_type, but being an enum, will support additional values.

3 years agoDEBUG: protocol: yell loudly during registration of invalid sock_domain
Willy Tarreau [Wed, 27 Oct 2021 13:06:35 +0000 (15:06 +0200)] 
DEBUG: protocol: yell loudly during registration of invalid sock_domain

The test on the sock_domain is a bit useless because the protocols are
registered at boot time, and the test silently fails and returns no
error. Use a BUG_ON() instead to make sure to catch such bugs in the
code if any.

3 years agoBUILD: log: Fix compilation without SSL support
Christopher Faulet [Wed, 27 Oct 2021 09:58:05 +0000 (11:58 +0200)] 
BUILD: log: Fix compilation without SSL support

When compiled without SSL support, a variable is reported as not used by
GCC.

src/log.c: In function ‘sess_build_logline’:
src/log.c:2056:36: error: unused variable ‘conn’ [-Werror=unused-variable]
 2056 |                 struct connection *conn;
      |                                    ^~~~

This does not need to be backported.

3 years agoMINOR: stream: Use backend stream-interface dst address instead of target_addr
Christopher Faulet [Wed, 27 Oct 2021 07:34:56 +0000 (09:34 +0200)] 
MINOR: stream: Use backend stream-interface dst address instead of target_addr

target_addr field in the stream structure is removed. The backend
stream-interface destination address is now used.

3 years agoREGTESTS: Add script to test client src/dst manipulation at different levels
Christopher Faulet [Tue, 26 Oct 2021 16:12:23 +0000 (18:12 +0200)] 
REGTESTS: Add script to test client src/dst manipulation at different levels

This script tests various set-src and set-dst actions at different levels.

3 years agoMINOR: tcp-sample: Add samples to get original info about client connection
Christopher Faulet [Mon, 25 Oct 2021 14:58:50 +0000 (16:58 +0200)] 
MINOR: tcp-sample: Add samples to get original info about client connection

Because source and destination address of the client connection are now
updated at the appropriated level (connection, session or stream), original
info about the client connection are preserved.  src/src_port/src_is_local
and dst/dst_port/dst_is_local return current info about the client
connection. It is the info at the highest available level. Most of time, the
stream. Any tcp/http rules may alter this info.

To get original info, "fc_" prefix must be added. For instance
"fc_src". Here, only "tcp-request connection" rules may alter source and
destination address/port.

3 years agoDOC: config: Fix alphabetical order of fc_* samples
Christopher Faulet [Mon, 25 Oct 2021 14:18:15 +0000 (16:18 +0200)] 
DOC: config: Fix alphabetical order of fc_* samples

fc_* samples were not properly ordered. This patch may be backported as far
as 1.8.

3 years agoMINOR: tcp-act: Add set-src/set-src-port for "tcp-request content" rules
Christopher Faulet [Wed, 23 Jun 2021 10:07:21 +0000 (12:07 +0200)] 
MINOR: tcp-act: Add set-src/set-src-port for "tcp-request content" rules

This patch was reverted because it was inconsitent to change connection
addresses at stream level. Especially in HTTP because all requests was
affected by this change and not only the current one. In HTTP/2, it was
worse. Several streams was able to change the connection addresses at the
same time.

It is no longer an issue, thanks to recent changes. With multi-level client
source and destination addresses, it is possible to limit the change to the
current request. Thus this patch can be reintroduced.

If it possible to set source IP/Port from "tcp-request connection",
"tcp-request session" and "http-request" rules but not from "tcp-request
content" rules. There is no reason for this limitation and it may be a
problem for anyone wanting to call a lua fetch to dynamically set source
IP/Port from a TCP proxy. Indeed, to call a lua fetch, we must have a
stream. And there is no stream when "tcp-request connection/session" rules
are evaluated.

Thanks to this patch, "set-src" and "set-src-port" action are now supported
by "tcp_request content" rules.

This patch is related to the issue #1303.

3 years agoMEDIUM: tcp-act: Set addresses at the apprioriate level in set-(src/dst) actions
Christopher Faulet [Mon, 25 Oct 2021 06:26:34 +0000 (08:26 +0200)] 
MEDIUM: tcp-act: Set addresses at the apprioriate level in set-(src/dst) actions

When client source or destination addresses are changed via a tcp/http
action, we update addresses at the appropriate level. When "tcp-request
connection" rules are evaluated, we update addresses at the connection
level. When "tcp-request session" rules is evaluated, we update those at the
session level. And finally, when "tcp-request content" or "http-request"
rules are evaluated, we update the addresses at the stream level.

The same is performed when source or destination ports are changed.

Of course, for now, not all level are supported. But thanks to this patch,
it will be possible.

3 years agoMEDIUM: connection: Assign session addresses when NetScaler CIP proto is parsed
Christopher Faulet [Mon, 25 Oct 2021 06:23:22 +0000 (08:23 +0200)] 
MEDIUM: connection: Assign session addresses when NetScaler CIP proto is parsed

Just like for the PROXY protocol, when the NetScaler Client IP insertion
header is received, the retrieved client source and destination addresses
are set at the session level. This leaves those at the connection level
intact.

3 years agoMEDIUM: connection: Assign session addresses when PROXY line is received
Christopher Faulet [Mon, 25 Oct 2021 06:17:11 +0000 (08:17 +0200)] 
MEDIUM: connection: Assign session addresses when PROXY line is received

When PROXY protocol line is received, the retrieved client source and
destination addresses are set at the session level. This leaves those at the
connection level intact.

3 years agoMEDIUM: backend: Rely on addresses at stream level to init server connection
Christopher Faulet [Mon, 25 Oct 2021 06:13:25 +0000 (08:13 +0200)] 
MEDIUM: backend: Rely on addresses at stream level to init server connection

Client source and destination addresses at stream level are used to initiate
the connections to a server. For now, stream-interface addresses are never
set. So, thanks to the fallback mechanism, no changes are expected with this
patch. But its purpose is to rely on addresses at the appropriate level when
set instead of those at the connection level.

3 years agoMEDIUM: connection: Rely on addresses at stream level to make proxy line
Christopher Faulet [Mon, 25 Oct 2021 06:05:28 +0000 (08:05 +0200)] 
MEDIUM: connection: Rely on addresses at stream level to make proxy line

If the stream exists, the frontend stream-interface is used to get the
client source and destination addresses when the proxy line is built. For
now, stream-interface or session addresses are never set. So, thanks to the
fallback mechanism, no changes are expected with this patch. But its purpose
is to rely on addresses at the appropriate level when set instead of those
at the connection level.

3 years agoMEDIUM: tcp-sample: Rely on addresses at the appropriate level in tcp samples
Christopher Faulet [Mon, 25 Oct 2021 06:01:20 +0000 (08:01 +0200)] 
MEDIUM: tcp-sample: Rely on addresses at the appropriate level in tcp samples

In src, src-port, dst and dst-port sample fetches, the client source and
destination addresses are retrieved from the appropriate level. It means
that, if the stream exits, we use the frontend stream-interface to get the
client source and destination addresses. Otherwise, the session is used. For
now, stream-interface or session addresses are never set. So, thanks to the
fallback mechanism, no changes are expected with this patch. But its purpose
is to rely on addresses at the appropriate level when set instead of those
at the connection level.

3 years agoMINOR: mux-fcgi: Rely on client addresses at stream level to set default params
Christopher Faulet [Mon, 25 Oct 2021 05:56:51 +0000 (07:56 +0200)] 
MINOR: mux-fcgi: Rely on client addresses at stream level to set default params

Client source and destination addresses at stream level are now used to emit
SERVER_NAME/SERVER_PORT and REMOTE_ADDR/REMOTE_PORT parameters. For now,
stream-interface addresses are never set. So, thanks to the fallback
mechanism, no changes are expected with this patch. But its purpose is to
rely on addresses at the stream level, when set, instead of those at the
connection level.

3 years agoMINOR: http-fetch: Rely on addresses at stream level in HTTP sample fetches
Christopher Faulet [Mon, 25 Oct 2021 05:48:27 +0000 (07:48 +0200)] 
MINOR: http-fetch: Rely on addresses at stream level in HTTP sample fetches

Client source and destination addresses at stream level are now used to
compute base32+src and url32+src hashes. For now, stream-interface addresses
are never set. So, thanks to the fallback mechanism, no changes are expected
with this patch. But its purpose is to rely on addresses at the stream
level, when set, instead of those at the connection level.

3 years agoMINOR: http-ana: Rely on addresses at stream level to set xff and xot headers
Christopher Faulet [Mon, 25 Oct 2021 05:41:30 +0000 (07:41 +0200)] 
MINOR: http-ana: Rely on addresses at stream level to set xff and xot headers

Client source and destination addresses at stream level are now used to emit
X-Forwarded-For and X-Original-To headers. For now, stream-interface addresses
are never set. So, thanks to the fallback mechanism, no changes are expected
with this patch. But its purpose is to rely on addresses at the stream level,
when set, instead of those at the connection level.

3 years agoMINOR: session: Rely on client source address at session level to log error
Christopher Faulet [Fri, 22 Oct 2021 15:47:14 +0000 (17:47 +0200)] 
MINOR: session: Rely on client source address at session level to log error

When an embryonic session is killed, if no log format is defined for this
error, a generic error is emitted. When this happens, we now rely on the
session to get the client source address. For now, session addresses are
never set. So, thanks to the fallback mechanism, no changes are expected
with this patch. But its purpose is to rely on addresses at the session
level when set instead of those at the connection level.

3 years agoMINOR: log: Rely on client addresses at the appropriate level to log messages
Christopher Faulet [Fri, 22 Oct 2021 15:43:22 +0000 (17:43 +0200)] 
MINOR: log: Rely on client addresses at the appropriate level to log messages

When a log message is emitted, if the stream exits, we use the frontend
stream-interface to retrieve the client source and destination
addresses. Otherwise, the session is used. For now, stream-interface or
session addresses are never set. So, thanks to the fallback mechanism, no
changes are expected with this patch. But its purpose is to rely on
addresses at the appropriate level when set instead of those at the
connection level.

3 years agoMINOR: frontend: Rely on client src and dst addresses at stream level
Christopher Faulet [Fri, 22 Oct 2021 15:39:06 +0000 (17:39 +0200)] 
MINOR: frontend: Rely on client src and dst addresses at stream level

For now, stream-interface or session addresses are never set. So, thanks to
the fallback mechanism, no changes are expected with this patch. But its
purpose is to rely on the client addresses at the stream level, when set,
instead of those at the connection level. The addresses are retrieved from
the frontend stream-interface.

3 years agoMINOR: stream-int: Add src and dst addresses to the stream-interface
Christopher Faulet [Fri, 22 Oct 2021 15:25:58 +0000 (17:25 +0200)] 
MINOR: stream-int: Add src and dst addresses to the stream-interface

For now, these addresses are never set. But the idea is to be able to set, at
least first, the client source and destination addresses at the stream level
without updating the session or connection ones.

Of course, because these addresses are carried by the strream-interface, it
would be possible to set server source and destination addresses at this level
too.

Functions to fill these addresses have been added: si_get_src() and
si_get_dst(). If not already set, these functions relies on underlying
layers to fill stream-interface addresses. On the frontend side, the session
addresses are used if set, otherwise the client connection ones are used. On
the backend side, the server connection addresses are used.

And just like for sessions and conncetions, si_src() and si_dst() may be used to
get source and destination addresses or the stream-interface. And, if not set,
same mechanism as above is used.

3 years agoMINOR: session: Add src and dst addresses to the session
Christopher Faulet [Fri, 22 Oct 2021 13:41:57 +0000 (15:41 +0200)] 
MINOR: session: Add src and dst addresses to the session

For now, these addresses are never set. But the idea is to be able to set
client source and destination addresses at the session level without
updating the connection ones.

Functions to fill these addresses have been added: sess_get_src() and
sess_get_dst(). If not already set, these functions relies on
conn_get_src() and conn_get_dst() to fill session addresses.

And just like for conncetions, sess_src() and sess_dst() may be used to get
source and destination addresses. However, if not set, the corresponding
address from the underlying client connection is returned. When this
happens, the addresses is filled in the connection object.

3 years agoMINOR: connection: Add function to get src/dst without updating the connection
Christopher Faulet [Fri, 22 Oct 2021 14:33:28 +0000 (16:33 +0200)] 
MINOR: connection: Add function to get src/dst without updating the connection

conn_get_src() and conn_get_dst() functions are used to fill the source and
destination addresses of a connection. On success, ->src and ->dst
connection fields can be safely used.

For convenience, 2 new functions are added here: conn_src() and conn_dst().
These functions return the corresponding address, as a const and only if it
is already set. Otherwise NULL is returned.

3 years agoCLEANUP: lua: Use a const address to retrieve info about a connection
Christopher Faulet [Fri, 22 Oct 2021 13:36:08 +0000 (15:36 +0200)] 
CLEANUP: lua: Use a const address to retrieve info about a connection

hlua_socket_info() only extracts information about an address, there is no
reason to not use a const.

3 years agoCLEANUP: tools: Use const address for get_net_port() and get_host_port()
Christopher Faulet [Fri, 22 Oct 2021 13:32:48 +0000 (15:32 +0200)] 
CLEANUP: tools: Use const address for get_net_port() and get_host_port()

These functions only extract the port from an address. There is no reason to
not use a const address.

3 years agoCLEANUP: connection: No longer export make_proxy_line_v1/v2 functions
Christopher Faulet [Fri, 22 Oct 2021 12:33:59 +0000 (14:33 +0200)] 
CLEANUP: connection: No longer export make_proxy_line_v1/v2 functions

These functions are only used by the make_proxy_line() function. Thus, we
can turn them as static.

3 years agoBUG/MEDIUM: lua: fix invalid return types in hlua_http_msg_get_body
vishnu [Sun, 24 Oct 2021 01:16:24 +0000 (06:46 +0530)] 
BUG/MEDIUM: lua: fix invalid return types in hlua_http_msg_get_body

hlua_http_msg_get_body must return either a Lua string or nil. For some
HTTPMessage objects, HTX_BLK_EOT blocks are also present in the HTX buffer
along with HTX_BLK_DATA blocks. In such cases, _hlua_http_msg_dup will start
copying data into a luaL_Buffer until it encounters an HTX_BLK_EOT. But then
instead of pushing neither the luaL_Buffer nor `nil` to the Lua stack, the
function will return immediately. The end result will be that the caller of
the HTTPMessage.body() method from a Lua filter will see whatever object was
on top of the stack as return value. It may be either a userdata object if
HTTPMessage.body() was called with only two arguments, or the third argument
itself if called with three arguments. Hence HTTPMessage.body() would return
either nil, or HTTPMessage body as Lua string, or a userdata objects, or
number.

This fix ensure that HTTPMessage.body() will always return either a string
or nil.

Reviewed-by: Christopher Faulet <cfaulet@haproxy.com>
3 years agoCLEANUP: lua: Remove any ambiguities about lua txn execution context flags
Christopher Faulet [Mon, 25 Oct 2021 09:41:53 +0000 (11:41 +0200)] 
CLEANUP: lua: Remove any ambiguities about lua txn execution context flags

Flags used to set the execution context of a lua txn are used as an enum. It is
not uncommon but there are few flags otherwise. So to remove ambiguities, a
comment and a _NONE value are added to have a clear definition of supported
values.

This patch should fix the issue #1429. No backport needed.

3 years agoMINOR: httpclient/lua: return an error when it can't generate the request
William Lallemand [Tue, 26 Oct 2021 13:01:53 +0000 (15:01 +0200)] 
MINOR: httpclient/lua: return an error when it can't generate the request

Add a check during the httpclient request generation which yield an lua
error when the generation didn't work. The most common case is the lack
of space in the buffer, it can because of too much headers or a too big
body.

3 years agoMINOR: httpclient/lua: support more HTTP methods
William Lallemand [Tue, 26 Oct 2021 09:43:26 +0000 (11:43 +0200)] 
MINOR: httpclient/lua: support more HTTP methods

Add support for HEAD/PUT/POST/DELETE method with the lua httpclient.

This patch use the httpclient_req_gen() function with a different meth
parameter to implement this.

Also change the reg-test to support a POST request with a body.

3 years agoMINOR: httpclient: support payload within a buffer
William Lallemand [Mon, 25 Oct 2021 17:48:37 +0000 (19:48 +0200)] 
MINOR: httpclient: support payload within a buffer

httpclient_req_gen() takes a payload argument which can be use to put a
payload in the request. This payload can only fit a request buffer.

This payload can also be specified by the "body" named parameter within
the lua. httpclient.

It is also used within the CLI httpclient when specified as a CLI
payload with "<<".

3 years ago[RELEASE] Released version 2.5-dev11 v2.5-dev11
Willy Tarreau [Fri, 22 Oct 2021 17:40:44 +0000 (19:40 +0200)] 
[RELEASE] Released version 2.5-dev11

Released version 2.5-dev11 with the following main changes :
    - DEV: coccinelle: Add strcmp.cocci
    - CLEANUP: Apply strcmp.cocci
    - CI: Add `permissions` to GitHub Actions
    - CI: Clean up formatting in GitHub Action definitions
    - MINOR: add ::1 to predefined LOCALHOST acl
    - CLEANUP: assorted typo fixes in the code and comments
    - CLEANUP: Consistently `unsigned int` for bitfields
    - MEDIUM: resolvers: lower-case labels when converting from/to DNS names
    - MEDIUM: resolvers: replace bogus resolv_hostname_cmp() with memcmp()
    - MINOR: jwt: Empty the certificate tree during deinit
    - MINOR: jwt: jwt_verify returns negative values in case of error
    - MINOR: jwt: Do not rely on enum order anymore
    - BUG/MEDIUM: stream: Keep FLT_END analyzers if a stream detects a channel error
    - MINOR: httpclient/cli: access should be only done from expert mode
    - DOC: management: doc about the CLI httpclient
    - BUG/MEDIUM: tcpcheck: Properly catch early HTTP parsing errors
    - BUG/MAJOR: dns: tcp session can remain attached to a list after a free
    - BUG/MAJOR: dns: attempt to lock globaly for msg waiter list instead of use barrier
    - CLEANUP: dns: always detach the appctx from the dns session on release
    - DEBUG: dns: add a few more BUG_ON at sensitive places
    - BUG/MAJOR: resolvers: add other missing references during resolution removal
    - CLEANUP: resolvers: do not export resolv_purge_resolution_answer_records()
    - BUILD: resolvers: avoid a possible warning on null-deref
    - BUG/MEDIUM: resolvers: always check a valid item in query_list
    - CLEANUP: always initialize the answer_list
    - CLEANUP: resolvers: simplify resolv_link_resolution() regarding requesters
    - CLEANUP: resolvers: replace all LIST_DELETE with LIST_DEL_INIT
    - MEDIUM: resolvers: use a kill list to preserve the list consistency
    - MEDIUM: resolvers: remove the last occurrences of the "safe" argument
    - BUG/MEDIUM: checks: fix the starting thread for external checks
    - MEDIUM: resolvers: replace the answer_list with a (flat) tree
    - MEDIUM: resolvers: hash the records before inserting them into the tree
    - BUG/MAJOR: buf: fix varint API post- vs pre- increment
    - OPTIM: resolvers: move the eb32 node before the data in the answer_item
    - MINOR: list: add new macro LIST_INLIST_ATOMIC()
    - OPTIM: dns: use an atomic check for the list membership
    - BUG/MINOR: task: do not set TASK_F_USR1 for no reason
    - BUG/MINOR: mux-h2: do not prevent from sending a final GOAWAY frame
    - MINOR: connection: add a new CO_FL_WANT_DRAIN flag to force drain on close
    - MINOR: mux-h2: perform a full cycle shutdown+drain on close
    - CLEANUP: resolvers: get rid of single-iteration loop in resolv_get_ip_from_response()
    - MINOR: quic: Increase the size of handshake RX UDP datagrams
    - BUG/MEDIUM: lua: fix memory leaks with realloc() on non-glibc systems
    - MINOR: memprof: report the delta between alloc and free on realloc()
    - MINOR: memprof: add one pointer size to the size of allocations
    - BUILD: fix compilation on NetBSD
    - MINOR: backend: add traces for idle connections reuse
    - BUG/MINOR: backend: fix improper insert in avail tree for always reuse
    - MINOR: backend: improve perf with tcp proxies skipping idle conns
    - MINOR: connection: remove unneeded memset 0 for idle conns

3 years agoMINOR: connection: remove unneeded memset 0 for idle conns
Amaury Denoyelle [Wed, 20 Oct 2021 13:11:37 +0000 (15:11 +0200)] 
MINOR: connection: remove unneeded memset 0 for idle conns

Remove the zeroing of an idle connection node on remove from a tree.
This is not needed and should improve slightly the performance of idle
connection usage. Besides, it breaks the memory poisoning feature.

3 years agoMINOR: backend: improve perf with tcp proxies skipping idle conns
Amaury Denoyelle [Wed, 20 Oct 2021 13:04:03 +0000 (15:04 +0200)] 
MINOR: backend: improve perf with tcp proxies skipping idle conns

Skip the hash connection calcul when reuse must not be used in
connect_server() : this is the case for TCP proxies. This should result
in slightly better performance when using this use-case.

3 years agoBUG/MINOR: backend: fix improper insert in avail tree for always reuse
Amaury Denoyelle [Wed, 20 Oct 2021 13:22:20 +0000 (15:22 +0200)] 
BUG/MINOR: backend: fix improper insert in avail tree for always reuse

In connect_server(), if http-reuse always is set, the backend connection
is inserted into the available tree as soon as created. However, the
hash connection field is only set later at the end of the function.

This seems to have no impact as the hash connection field is always
position before a lookup. However, this is not a proper usage of ebmb
API. Fix this by setting the hash connection field before the insertion
into the avail tree.

This must be backported up to 2.4.

3 years agoMINOR: backend: add traces for idle connections reuse
Amaury Denoyelle [Wed, 20 Oct 2021 13:22:01 +0000 (15:22 +0200)] 
MINOR: backend: add traces for idle connections reuse

Add traces in connect_server() to debug idle connection reuse. These
are attached to stream trace module, as it's already in use in
backend.c with the macro TRACE_SOURCE.

3 years agoBUILD: fix compilation on NetBSD
Amaury Denoyelle [Thu, 21 Oct 2021 08:57:02 +0000 (10:57 +0200)] 
BUILD: fix compilation on NetBSD

Use include file <sys/time.h> to fix compilation error with timeval in
some files. This is as reported as 'man 7 system_data_types'. The build
error is reported on NetBSD 9.2.

This should be backported up to 2.2.

3 years agoMINOR: memprof: add one pointer size to the size of allocations
Willy Tarreau [Fri, 22 Oct 2021 14:33:53 +0000 (16:33 +0200)] 
MINOR: memprof: add one pointer size to the size of allocations

The current model causes an issue when trying to spot memory leaks,
because malloc(0) or realloc(0) do not count as allocations since we only
account for the application-usable size. This is the problem that made
issue #1406 not to appear as a leak.

What we're doing now is to account for one extra pointer (the one that
memory allocators usually place before the returned area), so that a
malloc(0) will properly account for 4 or 8 bytes. We don't need something
exact, we just need something non-zero so that a realloc(X) followed by a
realloc(0) without a free() gives a small non-zero result.

It was verified that the results are stable including in the presence
of lots of malloc/realloc/free as happens when stressing Lua.

It would make sense to backport this to 2.4 as it helps in bug reports.

3 years agoMINOR: memprof: report the delta between alloc and free on realloc()
Willy Tarreau [Fri, 22 Oct 2021 14:26:12 +0000 (16:26 +0200)] 
MINOR: memprof: report the delta between alloc and free on realloc()

realloc() calls are painful to analyse because they have two non-zero
columns and trying to spot a leaking one requires a bit of scripting.
Let's simply append the delta at the end of the line when alloc and
free are non-nul.

It would be useful to backport this to 2.4 to help with bug reports.

3 years agoBUG/MEDIUM: lua: fix memory leaks with realloc() on non-glibc systems
Willy Tarreau [Fri, 22 Oct 2021 14:00:02 +0000 (16:00 +0200)] 
BUG/MEDIUM: lua: fix memory leaks with realloc() on non-glibc systems

In issue #1406, Lev Petrushchak reported a nasty memory leak on Alpine
since haproxy 2.4 when using Lua, that memory profiling didn't detect.
After inspecting the code and Lua's code, it appeared that Lua's default
allocator does an explicit free() on size zero, while since 2.4 commit
d36c7fa5e ("MINOR: lua: simplify hlua_alloc() to only rely on realloc()"),
haproxy only calls realloc(ptr,0) that performs a free() on glibc but not
on other systems as it's not required by POSIX...

This patch reinstalls the explicit test for nsize==0 to call free().

Thanks to Lev for the very documented report, and to Tim for the links
to a musl thread on the same subject that confirms the diagnostic.

This must be backported to 2.4.

3 years agoMINOR: quic: Increase the size of handshake RX UDP datagrams
Frédéric Lécaille [Fri, 22 Oct 2021 13:04:27 +0000 (15:04 +0200)] 
MINOR: quic: Increase the size of handshake RX UDP datagrams

Some browsers may send Initial packets with sizes greater than 1252 bytes
(QUIC_INITIAL_IPV4_MTU). Let us increase this size limit up to 2048 bytes.
Also use this size for "max_udp_payload_size" transport parameter to limit
the size of the datagrams we want to receive.

3 years agoCLEANUP: resolvers: get rid of single-iteration loop in resolv_get_ip_from_response()
Willy Tarreau [Fri, 22 Oct 2021 06:34:14 +0000 (08:34 +0200)] 
CLEANUP: resolvers: get rid of single-iteration loop in resolv_get_ip_from_response()

In issue 1424 Coverity reports that the loop increment is unreachable,
which is true, the list_for_each_entry() was replaced with a for loop,
but it was already not needed and was instead used as a convenient
construct for a single iteration lookup. Let's get rid of all this
now and replace the loop with an "if" statement.

3 years agoMINOR: mux-h2: perform a full cycle shutdown+drain on close
Willy Tarreau [Thu, 21 Oct 2021 20:24:31 +0000 (22:24 +0200)] 
MINOR: mux-h2: perform a full cycle shutdown+drain on close

While in H1 we can usually close quickly, in H2 a client might be sending
window updates or anything while we're sending a GOAWAY and the pending
data in the socket buffers at the moment the close() is performed on the
socket results in the output data being lost and an RST being emitted.

One example where this happens easily is with h2spec, which randomly
reports connection resets when waiting for a GOAWAY while haproxy sends
it, as seen in issue #1422. With h2spec it's not window updates that are
causing this but the fact that h2spec has to upload the payload that
comes with invalid frames to accommodate various implementations, and
does that in two different segments. When haproxy aborts on the invalid
frame header, the payload was not yet received and causes an RST to
be sent.

Here we're dealing with this two ways:
  - we perform a shutdown(WR) on the connection to forcefully push pending
    data on a front connection after the xprt is shut and closed ;
  - we drain pending data
  - then we close

This totally solves the issue with h2spec, and the extra cost is very
low, especially if we consider that H2 connections are not set up and
torn down often. This issue was never observed with regular clients,
most likely because this pattern does not happen in regular traffic.

After more testing it could make sense to backport this, at least to
avoid reporting errors on h2spec tests.

3 years agoMINOR: connection: add a new CO_FL_WANT_DRAIN flag to force drain on close
Willy Tarreau [Thu, 21 Oct 2021 19:31:42 +0000 (21:31 +0200)] 
MINOR: connection: add a new CO_FL_WANT_DRAIN flag to force drain on close

Sometimes we'd like to do our best to drain pending data before closing
in order to save the peer from risking to receive an RST on close.

This adds a new connection flag CO_FL_WANT_DRAIN that is used to
trigger a call to conn_ctrl_drain() from conn_ctrl_close(), and the
sock_drain() function ignores fd_recv_ready() if this flag is set,
in order to catch latest data. It's not used for now.

3 years agoBUG/MINOR: mux-h2: do not prevent from sending a final GOAWAY frame
Willy Tarreau [Thu, 21 Oct 2021 15:30:06 +0000 (17:30 +0200)] 
BUG/MINOR: mux-h2: do not prevent from sending a final GOAWAY frame

Some checks were added by commit 9a3d3fcb5 ("BUG/MAJOR: mux-h2: Don't try
to send data if we know it is no longer possible") to make sure we don't
loop forever trying to send data that cannot leave. But one of the
conditions there is not correct, the one relying on H2_CS_ERROR2. Indeed,
this state indicates that the error code was serialized into the mux
buffer, and since the test is placed before trying to send the data to
the socket, if the connection states only contains a GOAWAY frame, it
may refrain from sending and may close without sending anything. It's
not dramatic, as GOAWAY reports connection errors in situations where
delivery is not even certain, but it's cleaner to make sure the error
is properly sent, and it avoids upsetting h2spec, as seen in github
issue #1422.

Given that the patch above was backported as far as 1.8, this patch will
also have to be backported that far.

Thanks to Ilya for reporting this one.

3 years agoBUG/MINOR: task: do not set TASK_F_USR1 for no reason
Willy Tarreau [Thu, 21 Oct 2021 14:17:29 +0000 (16:17 +0200)] 
BUG/MINOR: task: do not set TASK_F_USR1 for no reason

This applicationn specific flag was added in 2.4-dev by commit 6fa8bcdc7
("MINOR: task: add an application specific flag to the state: TASK_F_USR1")
to help preserve a the idle connections status across wakeup calls. While
the code to do this was OK for tasklets, it was wrong for tasks, as in an
effort not to lose it when setting the RUNNING flag (that tasklets don't
have), it ended up being inconditionally set. It just happens that for now
no regular tasks use it, only tasklets.

This fix makes sure we always atomically perform (state & flags | running)
there, using a CAS. It also does it for tasklets because it was possible
to lose some such flags if set by another thread, even though this should
not happen with current code. In order to make the code more readable (and
avoid the previous mistake of repeated flags in the bit field), a new
TASK_PERSISTENT aggregate was declared in task.h for this.

In practice the CAS is cheap here because task states are stable or
convergent so the loop will almost never be taken.

This should be backported to 2.4.

3 years agoOPTIM: dns: use an atomic check for the list membership
Willy Tarreau [Thu, 21 Oct 2021 12:33:38 +0000 (14:33 +0200)] 
OPTIM: dns: use an atomic check for the list membership

The crash that was fixed by commit 7045590d8 ("BUG/MAJOR: dns: attempt
to lock globaly for msg waiter list instead of use barrier") was now
completely analysed and confirmed to be partially a result of the
debugging code added to LIST_INLIST(), which was looking at both
pointers and their reciprocals, and that, if used in a concurrent
context, could perfectly return false if a neighbor was being added or
removed while the current one didn't change, allowing the LIST_APPEND
to fail.

As the LIST API was not designed to be used in a concurrent context,
we should not rely on LIST_INLIST() but on the newly introduced
LIST_INLIST_ATOMIC().

This patch simply reverts the commit above to switch to the new test,
saving a lock during potentially long operations. It was verified that
the check doesn't fail anymore.

It is unsure what the performance impact of the fix above could be in
some contexts. If any performance regression is observed, it could make
sense to backport this patch, along with the previous commit introducing
the LIST_INLIST_ATOMIC() macro.

3 years agoMINOR: list: add new macro LIST_INLIST_ATOMIC()
Willy Tarreau [Thu, 21 Oct 2021 12:06:01 +0000 (14:06 +0200)] 
MINOR: list: add new macro LIST_INLIST_ATOMIC()

This macro is similar to LIST_INLIST() except that it is guaranteed to
perform the test atomically, so that even if LIST_INLIST() is intrumented
with debugging code to perform extra consistency checks, it will not fail
when used in the context of barriers and atomic ops.

3 years agoOPTIM: resolvers: move the eb32 node before the data in the answer_item
Willy Tarreau [Thu, 21 Oct 2021 12:45:28 +0000 (14:45 +0200)] 
OPTIM: resolvers: move the eb32 node before the data in the answer_item

perf top shows that we spend a lot of time trying to read item->type in
the lookup loop, because the node is placed after the very long name,
so when the node is found, no data is in the cache yet. Let's simply
move the node upper in the struct. This results in the CPU usage of
resolv_validate_dns_response() to drop by 4 points.

3 years agoBUG/MAJOR: buf: fix varint API post- vs pre- increment
Willy Tarreau [Thu, 21 Oct 2021 13:05:34 +0000 (15:05 +0200)] 
BUG/MAJOR: buf: fix varint API post- vs pre- increment

A bogus test in b_get_varint(), b_put_varint(), b_peek_varint() shifts
the end of the buffer by one byte. Since the bug is the same in the read
and write functions, the buffer contents remain compatible, which explains
why this bug was not detected earlier. But if the buffer ends on an
aligned address or page, it can result in a one-byte overflow which will
typically cause a crash or an inconsistent behavior.

This API is only used by rings (e.g. for traces and boot messages) and
by DNS responses, so the probability to hit it is extremely low, but a
crash on boot was observed.

This must be backported to 2.2.

3 years agoMEDIUM: resolvers: hash the records before inserting them into the tree
Willy Tarreau [Thu, 21 Oct 2021 06:18:01 +0000 (08:18 +0200)] 
MEDIUM: resolvers: hash the records before inserting them into the tree

We're using an XXH32() on the record to insert it into or look it up from
the tree. This way we don't change the rest of the code, the comparisons
are still made on all fields and the next node is visited on mismatch. This
also allows to continue to use roundrobin between identical nodes.

Just doing this is sufficient to see the CPU usage go down from ~60-70% to
4% at ~2k DNS requests per second for farm with 300 servers. A larger
config with 12 backends of 2000 servers each shows ~8-9% CPU for 6-10000
DNS requests per second.

It would probably be possible to go further with multiple levels of indexing
but it's not worth it, and it's important to remember that tree nodes take
space (the struct answer_list went back from 576 to 600 bytes).

3 years agoMEDIUM: resolvers: replace the answer_list with a (flat) tree
Willy Tarreau [Thu, 21 Oct 2021 05:39:57 +0000 (07:39 +0200)] 
MEDIUM: resolvers: replace the answer_list with a (flat) tree

With SRV records, a huge amount of time is spent looking for records
by walking long lists. It is possible to reduce this by indexing values
in trees instead. However the whole code relies a lot on the list
ordering, and even implements some round-robin on it to distribute IP
addresses to servers.

This patch starts carefully by replacing the list with a an eb32 tree
that is still used like a list, with a constant key 0. Since ebtrees
preserve insertion order for duplicates, the tree walk visits the nodes
in the exact same order it did with the lists. This allows to implement
the required infrastructure without changing the behavior.

3 years agoBUG/MEDIUM: checks: fix the starting thread for external checks
Willy Tarreau [Wed, 20 Oct 2021 16:43:30 +0000 (18:43 +0200)] 
BUG/MEDIUM: checks: fix the starting thread for external checks

When cleaning up the code to remove most explicit task masks in commit
beeabf531 ("MINOR: task: provide 3 task_new_* wrappers to simplify the
API"), a mistake was done with the external checks where the call does
task_new_on(1) instead of task_new_on(0) due to the confusion with the
previous mask 1.

No backport is needed as that's only 2.5-dev.

3 years agoMEDIUM: resolvers: remove the last occurrences of the "safe" argument
Willy Tarreau [Wed, 20 Oct 2021 12:07:31 +0000 (14:07 +0200)] 
MEDIUM: resolvers: remove the last occurrences of the "safe" argument

This one was used to indicate whether the callee had to follow particularly
safe code path when removing resolutions. Since the code now uses a kill
list, this is not needed anymore.

3 years agoMEDIUM: resolvers: use a kill list to preserve the list consistency
Willy Tarreau [Mon, 18 Oct 2021 14:46:38 +0000 (16:46 +0200)] 
MEDIUM: resolvers: use a kill list to preserve the list consistency

When scanning resolution.curr it's possible to try to free some
resolutions which will themselves result in freeing other ones. If
one of these other ones is exactly the next one in the list, the list
walk visits deleted nodes and causes memory corruption, double-frees
and so on. The approach taken using the "safe" argument to some
functions seems to work but it's extremely brittle as it is required
to carefully check all call paths from process_ressolvers() and pass
the argument to 1 there to refrain from deleting entries, so the bug
is very likely to come back after some tiny changes to this code.

A variant was tried, checking at various places that the current task
corresponds to process_resolvers() but this is also quite brittle even
though a bit less.

This patch uses another approach which consists in carefully unlinking
elements from the list and deferring their removal by placing it in a
kill list instead of deleting them synchronously. The real benefit here
is that the complexity only has to be placed where the complications
are.

A thread-local list is fed with elements to be deleted before scanning
the resolutions, and it's flushed at the end by picking the first one
until the list is empty. This way we never dereference the next element
and do not care about its presence or not in the list. One function,
resolv_unlink_resolution(), is exported and used outside, so it had to
be modified to use this list as well. Internal code has to use
_resolv_unlink_resolution() instead.

3 years agoCLEANUP: resolvers: replace all LIST_DELETE with LIST_DEL_INIT
Willy Tarreau [Tue, 19 Oct 2021 20:01:36 +0000 (22:01 +0200)] 
CLEANUP: resolvers: replace all LIST_DELETE with LIST_DEL_INIT

The code as it is uses crossed lists between many elements, and at
many places the code relies on list iterators or emptiness checks,
which does not work with only LIST_DELETE. Further, it is quite
difficult to place debugging code and checks in the current situation,
and gdb is helpless.

This code replaces all LIST_DELETE calls with LIST_DEL_INIT so that
it becomes possible to trust the lists.

3 years agoCLEANUP: resolvers: simplify resolv_link_resolution() regarding requesters
Willy Tarreau [Tue, 19 Oct 2021 09:59:25 +0000 (11:59 +0200)] 
CLEANUP: resolvers: simplify resolv_link_resolution() regarding requesters

This function allocates requesters by hand for each and every type. This
is complex and error-prone, and it doesn't even initialize the list part,
leaving dangling pointers that complicate debugging.

This patch introduces a new function resolv_get_requester() that either
returns the current pointer if valid or tries to allocate a new one and
links it to its destination. Then it makes use of it in the function
above to clean it up quite a bit. This allows to remove complicated but
unneeded tests.

3 years agoCLEANUP: always initialize the answer_list
Willy Tarreau [Tue, 19 Oct 2021 09:29:21 +0000 (11:29 +0200)] 
CLEANUP: always initialize the answer_list

Similar to the previous patch, the answer's list was only initialized the
first time it was added to a list, leading to bogus outdated pointer to
appear when debugging code is added around it to watch it. Let's make
sure it's always initialized upon allocation.

3 years agoBUG/MEDIUM: resolvers: always check a valid item in query_list
Willy Tarreau [Tue, 19 Oct 2021 09:17:33 +0000 (11:17 +0200)] 
BUG/MEDIUM: resolvers: always check a valid item in query_list

The query_list is physically stored in the struct resolution itself,
so we have a list that contains a list to items stored in itself (and
there is a single item). But the list is first initialized in
resolv_validate_dns_response(), while it's scanned in
resolv_process_responses() later after calling the former. First,
this results in crashes as soon as the code is instrumented a little
bit for debugging, as elements from a previous incarnation can appear.

But in addition to this, the presence of an element is checked by
verifying that the return of LIST_NEXT() is not NULL, while it may
never be NULL even for an empty list, resulting in bugs or crashes
if the number of responses does not match the list's contents. This
is easily triggered by testing for the list non-emptiness outside of
the function.

Let's make sure the list is always correct, i.e. it's initialized to
an empty list when the structure is allocated, elements are checked by
first verifying the list is not empty, they are deleted once checked,
and in any case at end so that there are no dangling pointers.

This should be backported, but only as long as the patch fits without
modifications, as adaptations can be risky there given that bugs tend
to hide each other.

3 years agoBUILD: resolvers: avoid a possible warning on null-deref
Willy Tarreau [Wed, 20 Oct 2021 15:29:28 +0000 (17:29 +0200)] 
BUILD: resolvers: avoid a possible warning on null-deref

Depending on the code that precedes the loop, gcc may emit this warning:

  src/resolvers.c: In function 'resolv_process_responses':
  src/resolvers.c:1009:11: warning: potential null pointer dereference [-Wnull-dereference]
   1009 |  if (query->type != DNS_RTYPE_SRV && flags & DNS_FLAG_TRUNCATED) {
        |      ~~~~~^~~~~~

However after carefully checking, r_res->header.qdcount it exclusively 1
when reaching this place, which forces the for() loop to enter for at
least one iteration, and <query> to be set. Thus there's no code path
leading to a null deref. It's possibly just because the assignment is
too far and the compiler cannot figure that the condition is always OK.
Let's just mark it to please the compiler.

3 years agoCLEANUP: resolvers: do not export resolv_purge_resolution_answer_records()
Willy Tarreau [Tue, 19 Oct 2021 09:16:11 +0000 (11:16 +0200)] 
CLEANUP: resolvers: do not export resolv_purge_resolution_answer_records()

This code is dangerous enough that we certainly don't want external code
to ever approach it, let's not export unnecessary functions like this one.
It was made static and a comment was added about its purpose.

3 years agoBUG/MAJOR: resolvers: add other missing references during resolution removal
Willy Tarreau [Mon, 18 Oct 2021 14:49:14 +0000 (16:49 +0200)] 
BUG/MAJOR: resolvers: add other missing references during resolution removal

There is a fundamental design bug in the resolvers code which is that
a list of active resolutions is being walked to try to delete outdated
entries, and that the code responsible for removing them also removes
other elements, including the next one which will be visited by the
list iterator. This randomly causes a use-after-free condition leading
to crashes, infinite loops and various other issues such as random memory
corruption.

A first fix for the memory fix for this was brought by commit 0efc0993e
("BUG/MEDIUM: resolvers: Don't release resolution from a requester
callbacks"). While preparing for more fixes, some code was factored by
commit 11c6c3965 ("MINOR: resolvers: Clean server in a dedicated function
when removing a SRV item"), which inadvertently passed "0" as the "safe"
argument all the time, missing one case of removal protection, instead
of always using "safe". This patch reintroduces the correct argument.

This must be backported with all fixes above.

Cc: Christopher Faulet <cfaulet@haproxy.com>
3 years agoDEBUG: dns: add a few more BUG_ON at sensitive places
Willy Tarreau [Wed, 20 Oct 2021 09:02:13 +0000 (11:02 +0200)] 
DEBUG: dns: add a few more BUG_ON at sensitive places

A few places have been caught triggering late bugs recently, always cases
of use-after-free because a freed element was still found in one of the
lists. This patch adds a few checks for such elements in dns_session_free()
before the final pool_free() and dns_session_io_handler() before adding
elements to lists to make sure they remain consistent. They do not trigger
anymore now.

3 years agoCLEANUP: dns: always detach the appctx from the dns session on release
Willy Tarreau [Wed, 20 Oct 2021 12:38:43 +0000 (14:38 +0200)] 
CLEANUP: dns: always detach the appctx from the dns session on release

When dns_session_release() calls dns_session_free(), it was shown that
it might still be attached there:

  Program terminated with signal SIGSEGV, Segmentation fault.
  #0  0x00000000006437d7 in dns_session_free (ds=0x7f895439e810) at src/dns.c:768
  768             BUG_ON(!LIST_ISEMPTY(&ds->ring.waiters));
  [Current thread is 1 (Thread 0x7f895bbe2700 (LWP 31792))]
  (gdb) bt
  #0  0x00000000006437d7 in dns_session_free (ds=0x7f895439e810) at src/dns.c:768
  #1  0x0000000000643ab8 in dns_session_release (appctx=0x7f89545a4ff0) at src/dns.c:805
  #2  0x000000000062e35a in si_applet_release (si=0x7f89545a5550) at include/haproxy/stream_interface.h:236
  #3  0x000000000063150f in stream_int_shutw_applet (si=0x7f89545a5550) at src/stream_interface.c:1697
  #4  0x0000000000640ab8 in si_shutw (si=0x7f89545a5550) at include/haproxy/stream_interface.h:437
  #5  0x0000000000643103 in dns_session_io_handler (appctx=0x7f89545a4ff0) at src/dns.c:725
  #6  0x00000000006d776f in task_run_applet (t=0x7f89545a5100, context=0x7f89545a4ff0, state=81924) at src/applet.c:90
  #7  0x000000000068b82b in run_tasks_from_lists (budgets=0x7f895bbbf5c0) at src/task.c:611
  #8  0x000000000068c258 in process_runnable_tasks () at src/task.c:850
  #9  0x0000000000621e61 in run_poll_loop () at src/haproxy.c:2636
  #10 0x0000000000622328 in run_thread_poll_loop (data=0x8d7440 <ha_thread_info+64>) at src/haproxy.c:2807
  #11 0x00007f895c54a06b in start_thread () from /lib64/libpthread.so.0
  #12 0x00007f895bf3772f in clone () from /lib64/libc.so.6
  (gdb) p &ds->ring.waiters
  $1 = (struct list *) 0x7f895439e8a8
  (gdb) p ds->ring.waiters
  $2 = {
    n = 0x7f89545a5078,
    p = 0x7f89545a5078
  }
  (gdb) p ds->ring.waiters->n
  $3 = (struct list *) 0x7f89545a5078
  (gdb) p *ds->ring.waiters->n
  $4 = {
    n = 0x7f895439e8a8,
    p = 0x7f895439e8a8
  }

Let's always detach it before freeing so that it remains possible to
check the dns_session's ring before releasing it, and possibly catch
bugs.

3 years agoBUG/MAJOR: dns: attempt to lock globaly for msg waiter list instead of use barrier
Emeric Brun [Wed, 20 Oct 2021 08:49:53 +0000 (10:49 +0200)] 
BUG/MAJOR: dns: attempt to lock globaly for msg waiter list instead of use barrier

The barrier is insufficient here to protect the waiters list as we can
definitely catch situations where ds->waiter shows an inconsistency
whereby the element is not attached when entering the "if" block and
is already attached when attaching it later.

This patch uses a larger lock to maintain consistency. Without it the
code would crash in 30-180 minutes under heavy stress, always showing
the same problem (ds->waiter->n->p != &ds->waiter). Now it seems to
always resist, suggesting that this was indeed the problem.

This will have to be backported to 2.4.

3 years agoBUG/MAJOR: dns: tcp session can remain attached to a list after a free
Emeric Brun [Tue, 19 Oct 2021 13:40:10 +0000 (15:40 +0200)] 
BUG/MAJOR: dns: tcp session can remain attached to a list after a free

Using tcp, after a session release and free, the session can remain
attached to the list of sessions with a response message waiting for
a commit (ds->waiter). This results to a use after free of this
session.

Also, on some error path and after free, a session could remain attached
to the lists of available idle/free sessions (ds->list).

This patch ensure to remove the session from those external lists
before a free.

This patch should be backported to all version including
the dns over tcp (2.4)

3 years agoBUG/MEDIUM: tcpcheck: Properly catch early HTTP parsing errors
Christopher Faulet [Wed, 20 Oct 2021 11:53:38 +0000 (13:53 +0200)] 
BUG/MEDIUM: tcpcheck: Properly catch early HTTP parsing errors

When an HTTP response is parsed, early parsing errors are not properly
handled. When this error is reported by the multiplexer, nothing is copied
into the input buffer. The HTX message remains empty but the
HTX_FL_PARSING_ERROR flag is set. In addition CS_FL_EOI is set on the
conn-stream. This last flag must be handled to prevent subscription for
receive events. Otherwise, in the best case, a L7 timeout error is
reported. But a transient loop is also possible if a shutdown is received
because the multiplexer notifies the check of the event while the check
never handles it and waits for more data.

Now, if CS_FL_EOI flag is set on the conn-stream, expect rules are
evaluated. Any error must be handled there.

Thanks to @kazeburo for his valuable report.

This patch should fix the issue #1420. It must be backported at least to
2.4. On 2.3 and 2.2, there is no loop but the wrong error is reported (empty
response instead of invalid one). Thus it may also be backported as far as
2.2.

3 years agoDOC: management: doc about the CLI httpclient
William Lallemand [Tue, 19 Oct 2021 12:53:55 +0000 (14:53 +0200)] 
DOC: management: doc about the CLI httpclient

Add the doc about the CLI httpclient.

3 years agoMINOR: httpclient/cli: access should be only done from expert mode
William Lallemand [Tue, 19 Oct 2021 08:58:30 +0000 (10:58 +0200)] 
MINOR: httpclient/cli: access should be only done from expert mode

Only enable the usage of the CLI HTTP client in expert mode.

3 years agoBUG/MEDIUM: stream: Keep FLT_END analyzers if a stream detects a channel error
Christopher Faulet [Mon, 18 Oct 2021 13:06:20 +0000 (15:06 +0200)] 
BUG/MEDIUM: stream: Keep FLT_END analyzers if a stream detects a channel error

If a channel error (READ_ERRO|READ_TIMEOUT|WRITE_ERROR|WRITE_TIMEOUT) is
detected by the stream, in process_stream(), FLT_END analyers must be
preserved. It is important to be sure to ends filter analysis and be able to
release the stream.

First, filters may release some ressources when FLT_END analyzers are
called. Then, the CF_FL_ANALYZE flag is used to sync end of analysis for the
request and the response. If FLT_END analyzer is ignored on a channel, this
may block the other side and freeze the stream.

This patch must be backported to all stable versions

3 years agoMINOR: jwt: Do not rely on enum order anymore
Remi Tricot-Le Breton [Mon, 18 Oct 2021 13:14:48 +0000 (15:14 +0200)] 
MINOR: jwt: Do not rely on enum order anymore

Replace the test based on the enum value of the algorithm by an explicit
switch statement in case someone reorders it for some reason (while
still managing not to break the regtest).

3 years agoMINOR: jwt: jwt_verify returns negative values in case of error
Remi Tricot-Le Breton [Mon, 18 Oct 2021 13:14:49 +0000 (15:14 +0200)] 
MINOR: jwt: jwt_verify returns negative values in case of error

In order for all the error return values to be distributed on the same
side (instead of surrounding the success error code), the return values
for errors other than a simple verification failure are switched to
negative values. This way the result of the jwt_verify converter can be
compared strictly to 1 as well relative to 0 (any <= 0 return value is
an error).
The documentation was also modified to discourage conversion of the
return value into a boolean (which would definitely not work).

3 years agoMINOR: jwt: Empty the certificate tree during deinit
Remi Tricot-Le Breton [Mon, 18 Oct 2021 13:14:47 +0000 (15:14 +0200)] 
MINOR: jwt: Empty the certificate tree during deinit

The tree in which the JWT certificates are stored was not emptied. It is
now done during deinit.

3 years agoMEDIUM: resolvers: replace bogus resolv_hostname_cmp() with memcmp()
Willy Tarreau [Fri, 15 Oct 2021 06:53:44 +0000 (08:53 +0200)] 
MEDIUM: resolvers: replace bogus resolv_hostname_cmp() with memcmp()

resolv_hostname_cmp() is bogus, it is applied on labels and not plain
names, but doesn't make any distinction between length prefixes and
characters, so it compares the labels lengths via tolower() as well.
The only reason for which it doesn't break is because labels cannot
be larger than 63 bytes, and that none of the common encoding systems
have upper case letters in the lower 63 bytes, that could be turned
into a different value via tolower().

Now that all labels are stored in lower case, we don't need to burn
CPU cycles in tolower() at run time and can use memcmp() instead of
resolv_hostname_cmp(). This results in a ~22% lower CPU usage on large
farms using SRV records:

before:
  18.33%  haproxy                   [.] resolv_validate_dns_response
  10.58%  haproxy                   [.] process_resolvers
  10.28%  haproxy                   [.] resolv_hostname_cmp
   7.50%  libc-2.30.so              [.] tolower
  46.69%  total

after:
  24.73%  haproxy                     [.] resolv_validate_dns_response
   7.78%  libc-2.30.so                [.] __memcmp_avx2_movbe
   3.65%  haproxy                     [.] process_resolvers
  36.16%  total

3 years agoMEDIUM: resolvers: lower-case labels when converting from/to DNS names
Willy Tarreau [Fri, 15 Oct 2021 05:45:38 +0000 (07:45 +0200)] 
MEDIUM: resolvers: lower-case labels when converting from/to DNS names

The whole code relies on performing case-insensitive comparison on
lookups, which is extremely inefficient.

Let's make sure that all labels to be looked up or sent are first
converted to lower case. Doing so is also the opportunity to eliminate
an inefficient memcpy() in resolv_dn_label_to_str() that essentially
runs over a few unaligned bytes at once. As a side note, that call
was dangerous because it relied on a sign-extended size taken from a
string that had to be sanitized first.

This is tagged medium because while this is 100% safe, it may cause
visible changes on the wire at the packet level and trigger bugs in
test programs.

3 years agoCLEANUP: Consistently `unsigned int` for bitfields
Tim Duesterhus [Sat, 16 Oct 2021 16:24:18 +0000 (18:24 +0200)] 
CLEANUP: Consistently `unsigned int` for bitfields

see 6a0dd733906611dea958cf74b9f51bb16028ae20

Found using GitHub's CodeQL scan.

3 years agoCLEANUP: assorted typo fixes in the code and comments
Ilya Shipitsin [Fri, 15 Oct 2021 11:18:21 +0000 (16:18 +0500)] 
CLEANUP: assorted typo fixes in the code and comments

This is 27th iteration of typo fixes

3 years agoMINOR: add ::1 to predefined LOCALHOST acl
Björn Jacke [Fri, 15 Oct 2021 14:32:15 +0000 (16:32 +0200)] 
MINOR: add ::1 to predefined LOCALHOST acl

The "LOCALHOST" ACL currently matches only 127.0.0.1/8. This adds the
IPv6 "::1" address to the supported patterns.

3 years agoCI: Clean up formatting in GitHub Action definitions
Tim Duesterhus [Sat, 16 Oct 2021 16:10:27 +0000 (18:10 +0200)] 
CI: Clean up formatting in GitHub Action definitions

This patch cleans up the formatting within the .yml definition files for GitHub
Actions to ensure a consistent look across all actions.

3 years agoCI: Add `permissions` to GitHub Actions
Tim Duesterhus [Sat, 16 Oct 2021 16:10:26 +0000 (18:10 +0200)] 
CI: Add `permissions` to GitHub Actions

This change locks down the permissions of the access token in GitHub Actions to
only allow reading the repository contents and nothing else.

see https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token