Commit Graph

9436 Commits

Author SHA1 Message Date
Christopher Faulet
fee726ffa7 MINOR: http-ana: Remove the unused function http_reset_txn()
Since the legacy HTTP mode was removed, the stream is always released at the end
of each HTTP transaction and a new is created to handle the next request for
keep-alive connections. So the HTTP transaction is no longer reset and the
function http_reset_txn() can be removed.
2019-11-07 15:32:52 +01:00
Christopher Faulet
5939925a38 BUG/MEDIUM: stream: Be sure to release allocated captures for TCP streams
All TCP and HTTP captures are stored in 2 arrays, one for the request and
another for the response. In HAPRoxy 1.5, these arrays are part of the HTTP
transaction and thus are released during its cleanup. Because in this version,
the transaction is part of the stream (in 1.5, streams are still called
sessions), the cleanup is always performed, for HTTP and TCP streams.

In HAProxy 1.6, the HTTP transaction was moved out from the stream and is now
dynamically allocated only when required (becaues of an HTTP proxy or an HTTP
sample fetch). In addition, still in 1.6, the captures arrays were moved from
the HTTP transaction to the stream. This way, it is still possible to capture
elements from TCP rules for a full TCP stream. Unfortunately, the release is
still exclusively performed during the HTTP transaction cleanup. Thus, for a TCP
stream where the HTTP transaction is not required, the TCP captures, if any, are
never released.

Now, all captures are released when the stream is freed. This fixes the memory
leak for TCP streams. For streams with an HTTP transaction, the captures are now
released when the transaction is reset and not systematically during its
cleanup.

This patch must be backported as fas as 1.6.
2019-11-07 15:32:52 +01:00
Christopher Faulet
eea8fc737b MEDIUM: stream/trace: Register a new trace source with its events
Runtime traces are now supported for the streams, only if compiled with
debug. process_stream() is covered as well as TCP/HTTP analyzers and filters.

In traces, the first argument is always a stream. So it is easy to get the info
about the channels and the stream-interfaces. The second argument, when defined,
is always a HTTP transaction. And the third one is an HTTP message. The trace
message is adapted to report HTTP info when possible.
2019-11-06 10:14:32 +01:00
Christopher Faulet
a3ed271ed4 MINOR: flt_trace: Rename macros to print trace messages
Names of these macros may enter in conflict with the macros of the runtime
tracing mechanism. So the prefix "FLT_" has been added to avoid any ambiguities.
2019-11-06 10:14:32 +01:00
Christopher Faulet
276c1e0533 BUG/MEDIUM: stream: Be sure to support splicing at the mux level to enable it
Despite the addition of the mux layer, no change have been made on how to enable
the TCP splicing on process_stream(). We still check if transport layer on both
sides support the splicing, but we don't check the muxes support. So it is
possible to start to splice data with an unencrypted H2 connection on a side and
an H1 connection on the other. This leads to a freeze of the stream until a
client or server timeout is reached.

This patch fixed a part of the issue #356. It must be backported as far as 1.8.
2019-11-06 10:14:32 +01:00
Christopher Faulet
9fa40c46df BUG/MEDIUM: mux-h1: Disable splicing for chunked messages
The mux H1 announces the support of the TCP splicing. It only works for payload
data. It works for messages with an explicit content-length or for tunnelled
data. For chunked messages, the mux H1 should normally not try to xfer more than
the current chunk through the pipe. Unfortunately, this works on the read side
but the send is completely bogus. During the output formatting, the announced
size of chunks does not handle the size that will be spliced. Because there is
no formatting when spliced data are sent, the produced message is malformed and
rejected by the peer.

For now, because it is quick and simple, the TCP splicing is disabled for
chunked messages. I will try to enable it again in a proper way. I don't know
for now if it will be backportable in previous versions. This will depend on the
amount of changes required to handle it.

This patch fixes a part of the issue #356. It must be backported to 2.0 and 1.9.
2019-11-06 10:14:27 +01:00
Frédéric Lécaille
b6f759b43d MINOR: peers: Add "log" directive to "peers" section.
This patch is easy to review: let's call parse_logsrv() function to parse
"log" directive as this is already for other sections for proxies.
This enable us to log incoming TCP connections for the listeners for "peers"
sections.

Update the documentation for "peers" section.
2019-11-06 04:49:56 +01:00
William Lallemand
21724f0807 MINOR: ssl/cli: replace the default_ctx during 'commit ssl cert'
If the SSL_CTX of a previous instance (ckch_inst) was used as a
default_ctx, replace the default_ctx of the bind_conf by the first
SSL_CTX inserted in the SNI tree.

Use the RWLOCK of the sni tree to handle the change of the default_ctx.
2019-11-04 18:16:53 +01:00
William Lallemand
3246d9466a BUG/MINOR: ssl/cli: fix an error when a file is not found
When trying to update a certificate <file>.{rsa,ecdsa,dsa}, but this one
does not exist and if <file> was used as a regular file in the
configuration, the error was ambiguous. Correct it so we can return a
certificate not found error.
2019-11-04 14:11:41 +01:00
William Lallemand
37031b85ca BUG/MINOR: ssl/cli: unable to update a certificate without bundle extension
Commit bc6ca7c ("MINOR: ssl/cli: rework 'set ssl cert' as 'set/commit'")
broke the ability to commit a unique certificate which does not use a
bundle extension .{rsa,ecdsa,dsa}.
2019-11-04 14:11:41 +01:00
William Lallemand
8a7fdf036b BUG/MEDIUM: ssl/cli: don't alloc path when cert not found
When doing an 'ssl set cert' with a certificate which does not exist in
configuration, the appctx->ctx.ssl.old_ckchs->path was duplicated while
app->ctx.ssl.old_ckchs was NULL, resulting in a NULL dereference.

Move the code so the 'not referenced' error is done before this.
2019-11-04 11:22:33 +01:00
vkill
1dfd16536f MINOR: backend: Add srv_name sample fetche
The sample fetche can get srv_name without foreach
`core.backends["bk"].servers`.

Then we can get Server class quickly via
`core.backends[txn.f:be_name()].servers[txn.f:srv_name()]`.

Issue#342
2019-11-01 05:40:24 +01:00
Emmanuel Hocdet
40f2f1e341 BUG/MEDIUM: ssl/cli: fix dot research in cli_parse_set_cert
During a 'set ssl cert', the result of the strrchr was wrongly tested
and can lead to a segfault when the certificate path did not contained a
dot.
2019-10-31 17:32:06 +01:00
Emmanuel Hocdet
eaad5cc2d8 MINOR: ssl: BoringSSL ocsp_response does not need issuer
HAproxy can fail when issuer is not found, it must not with BoringSSL.
2019-10-31 17:24:16 +01:00
Emmanuel Hocdet
83cbd3c89f BUG/MINOR: ssl: double free on error for ckch->{key,cert}
On last error in ssl_sock_load_pem_into_ckch, key/cert are released
and ckch->{key,cert} are released in ssl_sock_free_cert_key_and_chain_contents.
2019-10-31 16:56:51 +01:00
Emmanuel Hocdet
ed17f47c71 BUG/MINOR: ssl: ckch->chain must be initialized
It's a regression from 96a9c973 "MINOR: ssl: split
ssl_sock_load_crt_file_into_ckch()".
2019-10-31 16:53:28 +01:00
Emmanuel Hocdet
f6ac4fa745 BUG/MINOR: ssl: segfault in cli_parse_set_cert with old openssl/boringssl
Fix 541a534 ("BUG/MINOR: ssl/cli: fix build of SCTL and OCSP") was not
enough.

[wla: It will probably be better later to put the #ifdef in the
functions so they can return an error if they are not implemented]
2019-10-31 16:21:06 +01:00
Willy Tarreau
1eb3b4828e BUG/MINOR: stats: properly check the path and not the whole URI
Since we now have full URIs with h2, stats may fail to work over H2
so we must carefully only check the path there if the stats URI was
passed with a path only. This way it remains possible to intercept
proxy requests to report stats on explicit domains but it continues
to work as expected on origin requests.

No backport needed.
2019-10-31 15:52:14 +01:00
Willy Tarreau
cab2295ae7 BUG/MEDIUM: mux-h2: immediately report connection errors on streams
In case a stream tries to send on a connection error, we must report the
error so that the stream interface keeps the data available and may safely
retry on another connection. Till now this would happen only before the
connection was established, not in case of a failed handshake or an early
GOAWAY for example.

This should be backported to 2.0 and 1.9.
2019-10-31 15:48:18 +01:00
Willy Tarreau
4481e26e5d BUG/MEDIUM: mux-h2: immediately remove a failed connection from the idle list
If a connection faces an error or a timeout, it must be removed from its
idle list ASAP. We certainly don't want to risk sending new streams on
it.

This should be backported to 2.0 (replacing MT_LIST_DEL with LIST_DEL_LOCKED)
and 1.9 (there's no lock there, the idle lists are per-thread and per-server
however a LIST_DEL_INIT will be needed).
2019-10-31 15:39:27 +01:00
Willy Tarreau
c61966f9b4 BUG/MEDIUM: mux-h2: report no available stream on a connection having errors
If an H2 mux has met an error, we must not report available streams
anymore, or it risks to accumulate new streams while not being able
to process them.

This should be backported to 2.0 and 1.9.
2019-10-31 15:10:03 +01:00
William Lallemand
33cc76f918 BUG/MINOR: ssl/cli: check trash allocation in cli_io_handler_commit_cert()
Possible NULL pointer dereference found by coverity.

Fix #350 #340.
2019-10-31 11:48:01 +01:00
Damien Claisse
ae6f125c7b MINOR: sample: add us/ms support to date/http_date
It can be sometimes interesting to have a timestamp with a
resolution of less than a second.
It is currently painful to obtain this, because concatenation
of date and date_us lead to a shorter timestamp during first
100ms of a second, which is not parseable and needs ugly ACLs
in configuration to prepend 0s when needed.
To improve this, add an optional <unit> parameter to date sample
to report an integer with desired unit.
Also support this unit in http_date converter to report
a date string with sub-second precision.
2019-10-31 08:47:31 +01:00
Joao Morais
e1583751b6 BUG/MINOR: config: Update cookie domain warn to RFC6265
The domain option of the cookie keyword allows to define which domain or
domains should use the the cookie value of a cookie-based server
affinity. If the domain does not start with a dot, the user agent should
only use the cookie on hosts that matches the provided domains. If the
configured domain starts with a dot, the user agent can use the cookie
with any host ending with the configured domain.

haproxy config parser helps the admin warning about a potentially buggy
config: defining a domain without an embedded dot which does not start
with a dot, which is forbidden by the RFC.

The current condition to issue the warning implements RFC2109. This
change updates the implementation to RFC6265 which allows domain without
a leading dot.

Should be backported to all supported versions. The feature exists at least
since 1.5.
2019-10-31 06:06:52 +01:00
William Lallemand
beea2a476e CLEANUP: ssl/cli: remove leftovers of bundle/certs (it < 2)
Remove the leftovers of the certificate + bundle updating in 'ssl set
cert' and 'commit ssl cert'.

* Remove the it variable in appctx.ctx.ssl.
* Stop doing everything twice.
* Indent
2019-10-30 17:52:34 +01:00
William Lallemand
bc6ca7ccaa MINOR: ssl/cli: rework 'set ssl cert' as 'set/commit'
This patch splits the 'set ssl cert' CLI command into 2 commands.

The previous way of updating the certificate on the CLI was limited with
the bundles. It was only able to apply one of the tree part of the
certificate during an update, which mean that we needed 3 updates to
update a full 3 certs bundle.

It was also not possible to apply atomically several part of a
certificate with the ability to rollback on error. (For example applying
a .pem, then a .ocsp, then a .sctl)

The command 'set ssl cert' will now duplicate the certificate (or
bundle) and update it in a temporary transaction..

The second command 'commit ssl cert' will commit all the changes made
during the transaction for the certificate.

This commit breaks the ability to update a certificate which was used as
a unique file and as a bundle in the HAProxy configuration. This way of
using the certificates wasn't making any sense.

Example:

	// For a bundle:

	$ echo -e "set ssl cert localhost.pem.rsa <<\n$(cat kikyo.pem.rsa)\n" | socat /tmp/sock1 -
	Transaction created for certificate localhost.pem!

	$ echo -e "set ssl cert localhost.pem.dsa <<\n$(cat kikyo.pem.dsa)\n" | socat /tmp/sock1 -
	Transaction updated for certificate localhost.pem!

	$ echo -e "set ssl cert localhost.pem.ecdsa <<\n$(cat kikyo.pem.ecdsa)\n" | socat /tmp/sock1 -
	Transaction updated for certificate localhost.pem!

	$ echo "commit ssl cert localhost.pem" | socat /tmp/sock1 -
	Committing localhost.pem.
	Success!
2019-10-30 17:01:07 +01:00
William Dauchy
0fec3ab7bf MINOR: init: always fail when setrlimit fails
this patch introduces a strict-limits parameter which enforces the
setrlimit setting instead of a warning. This option can be forcingly
disable with the "no" keyword.
The general aim of this patch is to avoid bad surprises on a production
environment where you change the maxconn for example, a new fd limit is
calculated, but cannot be set because of sysfs setting. In that case you
might want to have an explicit failure to be aware of it before seeing
your traffic going down. During a global rollout it is also useful to
explictly fail as most progressive rollout would simply check the
general health check of the process.

As discussed, plan to use the strict by default mode starting from v2.3.

Signed-off-by: William Dauchy <w.dauchy@criteo.com>
2019-10-29 17:42:27 +01:00
William Dauchy
ec73098171 MINOR: config: allow no set-dumpable config option
in global config parsing, we currently expect to have a possible no
keyword (KWN_NO), but we never allow it in config parsing.
another patch could have been to simply remove the code handling a
possible KWN_NO.
take this opportunity to update documentation of set-dumpable.

Signed-off-by: William Dauchy <w.dauchy@criteo.com>
2019-10-29 17:42:27 +01:00
Olivier Houchard
e8f5f5d8b2 BUG/MEDIUM: servers: Only set SF_SRV_REUSED if the connection if fully ready.
In connect_server(), if we're reusing a connection, only use SF_SRV_REUSED
if the connection is fully ready. We may be using a multiplexed connection
created by another stream that is not yet ready, and may fail.
If we set SF_SRV_REUSED, process_stream() will then not wait for the timeout
to expire, and retry to connect immediately.

This should be backported to 1.9 and 2.0.
This commit depends on 55234e33708c5a584fb9efea81d71ac47235d518.
2019-10-29 14:15:20 +01:00
Olivier Houchard
9b8e11e691 MINOR: mux: Add a new method to get informations about a mux.
Add a new method, ctl(), to muxes. It uses a "enum mux_ctl_type" to
let it know which information we're asking for, and can output it either
directly by returning the expected value, or by using an optional argument.
"output" argument.
Right now, the only known mux_ctl_type is MUX_STATUS, that will return 0 if
the mux is not ready, or MUX_STATUS_READY if the mux is ready.

We probably want to backport this to 1.9 and 2.0.
2019-10-29 14:15:20 +01:00
Willy Tarreau
20020ae804 MINOR: chunk: add chunk_istcat() to concatenate an ist after a chunk
We previously relied on chunk_cat(dst, b_fromist(src)) for this but it
is not reliable as the allocated buffer is inside the expression and
may be on a temporary stack. While it's possible to allocate stack space
for a struct and return a pointer to it, it's not possible to initialize
it form a temporary variable to prevent arguments from being evaluated
multiple times. Since this is only used to append an ist after a chunk,
let's instead have a chunk_istcat() function to perform exactly this
from a native ist.

The only call place (URI computation in the cache) was updated.
2019-10-29 13:09:14 +01:00
Willy Tarreau
0580052bb6 BUILD/MINOR: ssl: shut up a build warning about format truncation
Actually gcc believes it has detected a possible truncation but it
cannot since the output string is necessarily at least one char
shorter than what it expects. However addressing it is easy and
removes the need for an intermediate copy so let's do it.
2019-10-29 10:50:22 +01:00
Willy Tarreau
4fd6d671b2 BUG/MINOR: spoe: fix off-by-one length in UUID format string
The per-thread UUID string produced by generate_pseudo_uuid() could be
off by one character due to too small of size limit in snprintf(). In
practice the UUID remains large enough to avoid any collision though.

This should be backported to 2.0 and 1.9.
2019-10-29 10:33:13 +01:00
Willy Tarreau
e112c8a64b BUILD/MINOR: tools: shut up the format truncation warning in get_gmt_offset()
The gcc warning about format truncation in get_gmt_offset() is annoying
since we always call it with a valid time thus it cannot fail. However
it's true that nothing guarantees that future code reuses this function
incorrectly in the future, so better enforce the modulus on one day and
shut the warning.
2019-10-29 10:19:34 +01:00
William Lallemand
430413e285 MINOR: ssl/cli: rework the 'set ssl cert' IO handler
Rework the 'set ssl cert' IO handler so it is clearer.
Use its own SETCERT_ST_* states insted of the STAT_ST ones.

Use an inner loop in SETCERT_ST_GEN and SETCERT_ST_INSERT to do the work
for both the certificate and the bundle.

The io_release() is now called only when the CKCH spinlock is taken so
we can unlock during a release without any condition.
2019-10-28 14:57:37 +01:00
William Lallemand
1212db417b BUG/MINOR: ssl/cli: cleanup on cli_parse_set_cert error
Since commit 90b098c ("BUG/MINOR: cli: don't call the kw->io_release if
kw->parse failed"), the io_release() callback is not called anymore when
the parse() failed. Call it directly on the error path of the
cli_parse_set_cert() function.
2019-10-28 14:57:37 +01:00
Christopher Faulet
04400bc787 BUG/MAJOR: stream-int: Don't receive data from mux until SI_ST_EST is reached
This bug is pretty pernicious and have serious consequences : In 2.1, an
infinite loop in process_stream() because the backend stream-interface remains
in the ready state (SI_ST_RDY). In 2.0, a call in loop to process_stream()
because the stream-interface remains blocked in the connect state
(SI_ST_CON). In both cases, it happens after a connection retry attempt. In 1.9,
it seems to not happen. But it may be just by chance or just because it is
harder to get right conditions to trigger the bug. However, reading the code,
the bug seems to exist too.

Here is how the bug happens in 2.1. When we try to establish a new connection to
a server, the corresponding stream-interface is first set to the connect state
(SI_ST_CON). When the underlying connection is known to be connected (the flag
CO_FL_CONNECTED set), the stream-interface is switched to the ready state
(SI_ST_RDY). It is a transient state between the connect state (SI_ST_CON) and
the established state (SI_ST_EST). It must be handled on the next call to
process_stream(), which is responsible to operate the transition. During all
this time, errors can occur. A connection error or a client abort. The transient
state SI_ST_RDY was introduced to let a chance to process_stream() to catch
these errors before considering the connection as fully established.
Unfortunatly, if a read0 is catched in states SI_ST_CON or SI_ST_RDY, it is
possible to have a shutdown without transition to SI_ST_DIS (in fact, here,
SI_ST_CON is swichted to SI_ST_RDY). This happens if the request was fully
received and analyzed. In this case, the flag SI_FL_NOHALF is set on the backend
stream-interface. If an error is also reported during the connect, the behavior
is undefined because an error is returned to the client and a connection retry
is performed. So on the next connection attempt to the server, if another error
is reported, a client abort is detected. But the shutdown for writes was already
done. So the transition to the state SI_ST_DIS is impossible. We stay in the
state SI_ST_RDY. Because it is a transient state, we loop in process_stream() to
perform the transition.

It is hard to understand how the bug happens reading the code and even harder to
explain. But there is a trivial way to hit the bug by sending h2 requests to a
server only speaking h1. For instance, with the following config :

  listen tst
    bind *:80
    server www 127.0.0.1:8000 proto h2 # in reality, it is a HTTP/1.1 server

It is a configuration error, but it is an easy way to observe the bug. Note it
may happen with a valid configuration.

So, after a careful analyzis, it appears that si_cs_recv() should never be
called for a not fully established stream-interface. This way the connection
retries will be performed before reporting an error to the client. Thus, if a
shutdown is performed because a read0 is handled, the stream-interface is
inconditionnaly set to the transient state SI_ST_DIS.

This patch must be backported to 2.0 and 1.9. However on these versions, this
patch reveals a design flaw about connections and a bad way to perform the
connection retries. We are working on it.
2019-10-26 08:24:45 +02:00
Christopher Faulet
69fe5cea21 BUG/MINOR: mux-h2: Don't pretend mux buffers aren't full anymore if nothing sent
In h2_send(), when something is sent, we remove the flags
(H2_CF_MUX_MFULL|H2_CF_DEM_MROOM) on the h2 connection. This way, we are able to
wake up all streams waiting to send data. Unfortunatly, these flags are
unconditionally removed, even when nothing was sent. So if the h2c is blocked
because the mux buffers are full and we are unable to send anything, all streams
in the send_list are woken up for nothing. Now, we only remove these flags if at
least a send succeeds.

This patch must be backport to 2.0.
2019-10-26 08:24:45 +02:00
William Lallemand
90b098c921 BUG/MINOR: cli: don't call the kw->io_release if kw->parse failed
The io_release() callback of the cli_kw is supposed to be used to clean
what an io_handler() has made. It is called once the work in the IO
handler is finished, or when the connection was aborted by the client.

This patch fixes a bug where the io_release callback was called even
when the parse() callback failed. Which means that the io_release() could
called even if the io_handler() was not called.

Should be backported in every versions that have a cli_kw->release().
(as far as 1.7)
2019-10-25 22:00:49 +02:00
Willy Tarreau
b2fee0406d BUG/MEDIUM: debug: address a possible null pointer dereference in "debug dev stream"
As reported in issue #343, there is one case where a NULL stream can
still be dereferenced, when getting &s->txn->flags. Let's protect all
assignments to stay on the safe side for future additions.

No backport is needed.
2019-10-25 10:10:07 +02:00
Willy Tarreau
9b013701f1 MINOR: stats/debug: maintain a counter of debug commands issued
Debug commands will usually mark the fate of the process. We'd rather
have them counted and visible in a core or in stats output than trying
to guess how a flag combination could happen. The counter is only
incremented when the command is about to be issued however, so that
failed attempts are ignored.
2019-10-24 18:38:00 +02:00
Willy Tarreau
b24ab22ac0 MINOR: debug: make most debug CLI commands accessible in expert mode
Instead of relying on DEBUG_DEV for most debugging commands, which is
limiting, let's condition them to expert mode. Only one ("debug dev exec")
remains conditionned to DEBUG_DEV because it can have a security implication
on the system. The commands are not listed unless "expert-mode on" was first
entered on the CLI :

 > expert-mode on
 > help
   debug dev close <fd>        : close this file descriptor
   debug dev delay [ms]        : sleep this long
   debug dev exec  [cmd] ...   : show this command's output
   debug dev exit  [code]      : immediately exit the process
   debug dev hex   <addr> [len]: dump a memory area
   debug dev log   [msg] ...   : send this msg to global logs
   debug dev loop  [ms]        : loop this long
   debug dev panic             : immediately trigger a panic
   debug dev stream ...        : show/manipulate stream flags
   debug dev tkill [thr] [sig] : send signal to thread

 > debug dev stream
 Usage: debug dev stream { <obj> <op> <value> | wake }*
      <obj>   = {strm | strm.f | sif.f | sif.s | sif.x | sib.f | sib.s | sib.x |
                 txn.f | req.f | req.r | req.w | res.f | res.r | res.w}
      <op>    = {'' (show) | '=' (assign) | '^' (xor) | '+' (or) | '-' (andnot)}
      <value> = 'now' | 64-bit dec/hex integer (0x prefix supported)
      'wake' wakes the stream asssigned to 'strm' (default: current)
2019-10-24 18:38:00 +02:00
Willy Tarreau
abb9f9b057 MINOR: cli: add an expert mode to hide dangerous commands
Some commands like the debug ones are not enabled by default but can be
useful on some production environments. In order to avoid the temptation
of using them incorrectly, let's introduce an "expert" mode for a CLI
connection, which allows some commands to appear and be used. It is
enabled by command "expert-mode on" which is not listed by default.
2019-10-24 18:38:00 +02:00
Willy Tarreau
2b5520da47 MINOR: cli/debug: validate addresses using may_access() in "debug dev stream"
This function adds some control by verifying that the target address is
really readable. It will not protect against writing to wrong places,
but will at least protect against a large number of mistakes such as
incorrectly copy-pasted addresses.
2019-10-24 18:38:00 +02:00
Willy Tarreau
68680bb14e MINOR: debug: add a new "debug dev stream" command
This new "debug dev stream" command allows to manipulate flags, timeouts,
states for streams, channels and stream interfaces, as well as waking a
stream up. These may be used to help reproduce certain bugs during
development. The operations are performed to the stream assigned by
"strm" which defaults to the CLI's stream. This stream pointer can be
chosen from one of those reported in "show sess". Example:

  socat - /tmp/sock1 <<< "debug dev stream strm=0x1555b80 req.f=-1 req.r=now wake"
2019-10-24 10:43:04 +02:00
William Dauchy
b705b4d7d3 MINOR: tcp: avoid confusion in time parsing init
We never enter val_fc_time_value when an associated fetcher such as `fc_rtt` is
called without argument.  meaning `type == ARGT_STOP` will never be true and so
the default `data.sint = TIME_UNIT_MS` will never be set.  remove this part to
avoid thinking default data.sint is set to ms while reading the code.

Signed-off-by: William Dauchy <w.dauchy@criteo.com>

[Cf: This patch may safely backported as far as 1.7. But no matter if not.]
2019-10-24 10:25:00 +02:00
William Lallemand
f29cdefccd BUG/MINOR: ssl/cli: out of bounds when built without ocsp/sctl
Commit 541a534 ("BUG/MINOR: ssl/cli: fix build of SCTL and OCSP")
introduced a bug in which we iterate outside the array durint a 'set ssl
cert' if we didn't built with the ocsp or sctl.
2019-10-23 15:05:00 +02:00
William Lallemand
541a534c9f BUG/MINOR: ssl/cli: fix build of SCTL and OCSP
Fix the build issue of SCTL and OCSP for boring/libressl introduced by
44b3532 ("MINOR: ssl/cli: update ocsp/issuer/sctl file from the CLI")
2019-10-23 14:47:16 +02:00
William Lallemand
8f840d7e55 MEDIUM: cli/ssl: handle the creation of SSL_CTX in an IO handler
To avoid affecting too much the traffic during a certificate update,
create the SNIs in a IO handler which yield every 10 ckch instances.

This way haproxy continues to respond even if we tries to update a
certificate which have 50 000 instances.
2019-10-23 11:54:51 +02:00
William Lallemand
0c3b7d9e1c MINOR: ssl/cli: assignate a new ckch_store
When updating a certificate from the CLI, it is not possible to revert
some of the changes if part of the certicate update failed. We now
creates a copy of the ckch_store for the changes so we can revert back
if something goes wrong.

Even if the ckch_store was affected before this change, it wasn't
affecting the SSL_CTXs used for the traffic. It was only a problem if we
try to update a certificate after we failed to do it the first time.

The new ckch_store is also linked to the new sni_ctxs so it's easy to
insert the sni_ctxs before removing the old ones.
2019-10-23 11:54:51 +02:00
William Lallemand
8c1cddef6d MINOR: ssl: new functions duplicate and free a ckch_store
ckchs_dup() alloc a new ckch_store and copy the content of its source.

ckchs_free() frees a ckch_store and its content.
2019-10-23 11:54:51 +02:00
William Lallemand
8d0f893222 MINOR: ssl: copy a ckch from src to dst
ssl_sock_copy_cert_key_and_chain() copy the content of a
<src> cert_key_and_chain to a <dst>.

It applies a refcount increasing on every SSL structures (X509, DH,
privte key..) and allocate new buffers for the other fields.
2019-10-23 11:54:51 +02:00
William Lallemand
455af50fac MINOR: ssl: update ssl_sock_free_cert_key_and_chain_contents
The struct cert_key_and_chain now contains the DH, the sctl and the
ocsp_response. Free them.
2019-10-23 11:54:51 +02:00
William Lallemand
44b3532250 MINOR: ssl/cli: update ocsp/issuer/sctl file from the CLI
It is now possible to update new parts of a CKCH from the CLI.

Currently you will be able to update a PEM (by default), a OCSP response
in base64, an issuer file, and a SCTL file.

Each update will creates a new CKCH and new sni_ctx structure so we will
need a "commit" command later to apply several changes and create the
sni_ctx only once.
2019-10-23 11:54:51 +02:00
William Lallemand
849eed6b25 BUG/MINOR: ssl/cli: fix looking up for a bundle
If we want a bundle but we didn't find a bundle, we shouldn't try to
apply the changes.
2019-10-23 11:54:51 +02:00
William Lallemand
96a9c97369 MINOR: ssl: split ssl_sock_load_crt_file_into_ckch()
Split the ssl_sock_load_crt_file_into_ckch() in two functions:

- ssl_sock_load_files_into_ckch() which is dedicated to opening every
files related to a filename during the configuration parsing (PEM, sctl,
ocsp, issuer etc)

- ssl_sock_load_pem_into_ckch() which is dedicated to opening a PEM,
either in a file or a buffer
2019-10-23 11:54:51 +02:00
William Lallemand
f9568fcd79 MINOR: ssl: load issuer from file or from buffer
ssl_sock_load_issuer_file_into_ckch() is a new function which is able to
load an issuer from a buffer or from a file to a CKCH.

Use this function directly in ssl_sock_load_crt_file_into_ckch()
2019-10-23 11:54:51 +02:00
William Lallemand
0dfae6c315 MINOR: ssl: load sctl from buf OR from a file
The ssl_sock_load_sctl_from_file() function was modified to
fill directly a struct cert_key_and_chain.

The function prototype was normalized in order to be used with the CLI
payload parser.

This function either read  text from a buffer or read a file on the
filesystem.

It fills the ocsp_response buffer of the struct cert_key_and_chain.
2019-10-23 11:54:51 +02:00
William Lallemand
3b5f360744 MINOR: ssl: OCSP functions can load from file or buffer
The ssl_sock_load_ocsp_response_from_file() function was modified to
fill directly a struct cert_key_and_chain.

The function prototype was normalized in order to be used with the CLI
payload parser.

This function either read a base64 from a buffer or read a binary file
on the filesystem.

It fills the ocsp_response buffer of the struct cert_key_and_chain.
2019-10-23 11:54:51 +02:00
William Lallemand
02010478e9 CLEANUP: ssl: fix SNI/CKCH lock labels
The CKCH and the SNI locks originally used the same label, we split them
but we forgot to change some of them.
2019-10-23 11:54:51 +02:00
William Lallemand
34779c34fc CLEANUP: ssl: remove old TODO commentary
Remove an old commentary above ckch_inst_new_load_multi_store().
This function doe not do filesystem syscalls anymore.
2019-10-23 11:54:51 +02:00
Willy Tarreau
9364a5fda3 BUG/MINOR: mux-h2: do not emit logs on backend connections
The logs were added to the H2 mux so that we can report logs in case
of errors that prevent a stream from being created, but as a side effect
these logs are emitted twice for backend connections: once by the H2 mux
itself and another time by the upper layer stream. It can even happen
more with connection retries.

This patch makes sure we do not emit logs for backend connections.

It should be backported to 2.0 and 1.9.
2019-10-23 11:12:22 +02:00
Willy Tarreau
403bfbb130 BUG/MEDIUM: pattern: make the pattern LRU cache thread-local and lockless
As reported in issue #335, a lot of contention happens on the PATLRU lock
when performing expensive regex lookups. This is absurd since the purpose
of the LRU cache was to have a fast cache for expressions, thus the cache
must not be shared between threads and must remain lockless.

This commit makes the LRU cache thread-local and gets rid of the PATLRU
lock. A test with 7 threads on 4 cores climbed from 67kH/s to 369kH/s,
or a scalability factor of 5.5.

Given the huge performance difference and the regression caused to
users migrating from processes to threads, this should be backported at
least to 2.0.

Thanks to Brian Diekelman for his detailed report about this regression.
2019-10-23 07:27:25 +02:00
Willy Tarreau
28c63c15f5 BUG/MINOR: stick-table: fix an incorrect 32 to 64 bit key conversion
As reported in issue #331, the code used to cast a 32-bit to a 64-bit
stick-table key is wrong. It only copies the 32 lower bits in place on
little endian machines or overwrites the 32 higher ones on big endian
machines. It ought to simply remove the wrong cast dereference.

This bug was introduced when changing stick table keys to samples in
1.6-dev4 by commit bc8c404449 ("MAJOR: stick-tables: use sample types
in place of dedicated types") so it the fix must be backported as far
as 1.6.
2019-10-23 06:24:58 +02:00
Emeric Brun
eb46965bbb BUG/MINOR: ssl: fix memcpy overlap without consequences.
A trick is used to set SESSION_ID, and SESSION_ID_CONTEXT lengths
to 0 and avoid ASN1 encoding of these values.

There is no specific function to set the length of those parameters
to 0 so we fake this calling these function to a different value
with the same buffer but a length to zero.

But those functions don't seem to check the length of zero before
performing a memcpy of length zero but with src and dst buf on the
same pointer, causing valgrind to bark.

So the code was re-work to pass them different pointers even
if buffer content is un-used.

In a second time, reseting value, a memcpy overlap
happened on the SESSION_ID_CONTEXT. It was re-worked and this is
now reset using the constant global value SHCTX_APPNAME which is a
different pointer with the same content.

This patch should be backported in every version since ssl
support was added to haproxy if we want valgrind to shut up.
This is tracked in github issue #56.
2019-10-22 18:57:45 +02:00
Baptiste Assmann
25e6fc2030 BUG/MINOR: dns: allow srv record weight set to 0
Processing of SRV record weight was inaccurate and when a SRV record's
weight was set to 0, HAProxy enforced it to '1'.
This patch aims at fixing this without breaking compability with
previous behavior.

Backport status: 1.8 to 2.0
2019-10-22 13:44:12 +02:00
Vedran Furac
5d48627aba BUG/MINOR: server: check return value of fopen() in apply_server_state()
fopen() can return NULL when state file is missing. This patch adds a
check of fopen() return value so we can skip processing in such case.

No backport needed.
2019-10-21 16:00:24 +02:00
Tim Duesterhus
4381d26edc BUG/MINOR: sample: Make the field converter compatible with -m found
Previously an expression like:

    path,field(2,/) -m found

always returned `true`.

Bug exists since the `field` converter exists. That is:
f399b0debf

The fix should be backported to 1.6+.
2019-10-21 15:49:42 +02:00
William Lallemand
d1d1e22945 BUG/MINOR: cache: alloc shctx after check config
When running haproxy -c, the cache parser is trying to allocate the size
of the cache. This can be a problem in an environment where the RAM is
limited.

This patch moves the cache allocation in the post_check callback which
is not executed during a -c.

This patch may be backported at least to 2.0 and 1.9. In 1.9, the callbacks
registration mechanism is not the same. So the patch will have to be adapted. No
need to backport it to 1.8, the code is probably too different.
2019-10-21 15:05:46 +02:00
Christopher Faulet
a9fa88a1ea BUG/MINOR: stick-table: Never exceed (MAX_SESS_STKCTR-1) when fetching a stkctr
When a stick counter is fetched, it is important that the requested counter does
not exceed (MAX_SESS_STKCTR -1). Actually, there is no bug with a default build
because, by construction, MAX_SESS_STKCTR is defined to 3 and we know that we
never exceed the max value. scN_* sample fetches are numbered from 0 to 2. For
other sample fetches, the value is tested.

But there is a bug if MAX_SESS_STKCTR is set to a lower value. For instance
1. In this case the counters sc1_* and sc2_* may be undefined.

This patch fixes the issue #330. It must be backported as far as 1.7.
2019-10-21 11:17:04 +02:00
Christopher Faulet
e566f3db11 BUG/MINOR: ssl: Fix fd leak on error path when a TLS ticket keys file is parsed
When an error occurred in the function bind_parse_tls_ticket_keys(), during the
configuration parsing, the opened file is not always closed. To fix the bug, all
errors are catched at the same place, where all ressources are released.

This patch fixes the bug #325. It must be backported as far as 1.7.
2019-10-21 10:04:51 +02:00
William Lallemand
f7f488d8e9 BUG/MINOR: mworker/cli: reload fail with inherited FD
When using the master CLI with 'fd@', during a reload, the master CLI
proxy is stopped. Unfortunately if this is an inherited FD it is closed
too, and the master CLI won't be able to bind again during the
re-execution. It lead the master to fallback in waitpid mode.

This patch forbids the inherited FDs in the master's listeners to be
closed during a proxy_stop().

This patch is mandatory to use the -W option in VTest versions that contain the
-mcli feature.
(86e65f1024)

Should be backported as far as 1.9.
2019-10-18 21:45:42 +02:00
Emeric Brun
a9363eb6a5 BUG/MEDIUM: ssl: 'tune.ssl.default-dh-param' value ignored with openssl > 1.1.1
If openssl 1.1.1 is used, c2aae74f0 commit mistakenly enables DH automatic
feature from openssl instead of ECDH automatic feature. There is no impact for
the ECDH one because the feature is always enabled for that version. But doing
this, the 'tune.ssl.default-dh-param' was completely ignored for DH parameters.

This patch fix the bug calling 'SSL_CTX_set_ecdh_auto' instead of
'SSL_CTX_set_dh_auto'.

Currently some users may use a 2048 DH bits parameter, thinking they're using a
1024 bits one. Doing this, they may experience performance issue on light hardware.

This patch warns the user if haproxy fails to configure the given DH parameter.
In this case and if openssl version is > 1.1.0, haproxy will let openssl to
automatically choose a default DH parameter. For other openssl versions, the DH
ciphers won't be usable.

A commonly case of failure is due to the security level of openssl.cnf
which could refuse a 1024 bits DH parameter for a 2048 bits key:

 $ cat /etc/ssl/openssl.cnf
 ...

 [system_default_sect]
 MinProtocol = TLSv1
 CipherString = DEFAULT@SECLEVEL=2

This should be backport into any branch containing the commit c2aae74f0.
It requires all or part of the previous CLEANUP series.

This addresses github issue #324.
2019-10-18 15:18:52 +02:00
Emeric Brun
0655c9b222 CLEANUP: bind: handle warning label on bind keywords parsing.
All bind keyword parsing message were show as alerts.

With this patch if the message is flagged only with ERR_WARN and
not ERR_ALERT it will show a label [WARNING] and not [ALERT].
2019-10-18 15:18:52 +02:00
Emeric Brun
7a88336cf8 CLEANUP: ssl: make ssl_sock_load_dh_params handle errcode/warn
ssl_sock_load_dh_params used to return >0 or -1 to indicate success
or failure. Make it return a set of ERR_* instead so that its callers
can transparently report its status. Given that its callers only used
to know about ERR_ALERT | ERR_FATAL, this is the only code returned
for now. An error message was added in the case of failure and the
comment was updated.
2019-10-18 15:18:52 +02:00
Emeric Brun
a96b582d0e CLEANUP: ssl: make ssl_sock_put_ckch_into_ctx handle errcode/warn
ssl_sock_put_ckch_into_ctx used to return 0 or >0 to indicate success
or failure. Make it return a set of ERR_* instead so that its callers
can transparently report its status. Given that its callers only used
to know about ERR_ALERT | ERR_FATAL, this is the only code returned
for now. And a comment was updated.
2019-10-18 15:18:52 +02:00
Emeric Brun
054563de13 CLEANUP: ssl: make ckch_inst_new_load_(multi_)store handle errcode/warn
ckch_inst_new_load_store() and ckch_inst_new_load_multi_store used to
return 0 or >0 to indicate success or failure. Make it return a set of
ERR_* instead so that its callers can transparently report its status.
Given that its callers only used to know about ERR_ALERT | ERR_FATAL,
his is the only code returned for now. And the comment was updated.
2019-10-18 15:18:52 +02:00
Emeric Brun
f69ed1d21c CLEANUP: ssl: make cli_parse_set_cert handle errcode and warnings.
cli_parse_set_cert was re-work to show errors and warnings depending
of ERR_* bitfield value.
2019-10-18 15:18:52 +02:00
Willy Tarreau
8c5414a546 CLEANUP: ssl: make ssl_sock_load_ckchs() return a set of ERR_*
ssl_sock_load_ckchs() used to return 0 or >0 to indicate success or
failure even though this was not documented. Make it return a set of
ERR_* instead so that its callers can transparently report its status.
Given that its callers only used to know about ERR_ALERT | ERR_FATAL,
this is the only code returned for now. And a comment was added.
2019-10-18 15:18:52 +02:00
Willy Tarreau
bbc91965bf CLEANUP: ssl: make ssl_sock_load_cert*() return real error codes
These functions were returning only 0 or 1 to mention success or error,
and made it impossible to return a warning. Let's make them return error
codes from ERR_* and map all errors to ERR_ALERT|ERR_FATAL for now since
this is the only code that was set on non-zero return value.

In addition some missing comments were added or adjusted around the
functions' return values.
2019-10-18 15:18:52 +02:00
Olivier Houchard
2ed389dc6e BUG/MEDIUM: mux_pt: Only call the wake emthod if nobody subscribed to receive.
In mux_pt_io_cb(), instead of always calling the wake method, only do so
if nobody subscribed for receive. If we have a subscription, just wake the
associated tasklet up.

This should be backported to 1.9 and 2.0.
2019-10-18 14:18:29 +02:00
Olivier Houchard
ea510fc5e7 BUG/MEDIUM: mux_pt: Don't destroy the connection if we have a stream attached.
There's a small window where the mux_pt tasklet may be woken up, and thus
mux_pt_io_cb() get scheduled, and then the connection is attached to a new
stream. If this happen, don't do anything, and just let the stream know
by calling its wake method. If the connection had an error, the stream should
take care of destroying it by calling the detach method.

This should be backported to 2.0 and 1.9.
2019-10-18 14:07:22 +02:00
Olivier Houchard
9dce2c53a8 Revert e8826ded5f.
This reverts commit "BUG/MEDIUM: mux_pt: Make sure we don't have a
conn_stream before freeing.".
mux_pt_io_cb() is only used if we have no associated stream, so we will
never have a cs, so there's no need to check that, and we of course have to
destroy the mux in mux_pt_detach() if we have no associated session, or if
there's an error on the connection.

This should be backported to 2.0 and 1.9.
2019-10-18 11:24:04 +02:00
Willy Tarreau
bbb5f1d6d2 BUG/MAJOR: idle conns: schedule the cleanup task on the correct threads
The idle cleanup tasks' masks are wrong for threads 32 to 64, which
causes the wrong thread to wake up and clean the connections that it
does not own, with a risk of crash or infinite loop depending on
concurrent accesses. For thread 32, any thread between 32 and 64 will
be woken up, but for threads 33 to 64, in fact threads 1 to 32 will
run the task instead.

This issue only affects deployments enabling more than 32 threads. While
is it not common in 1.9 where this has to be explicit, and can easily be
dealt with by lowering the number of threads, it can be more common in
2.0 since by default the thread count is determined based on the number
of available processors, hence the MAJOR tag which is mostly relevant
to 2.x.

The problem was first introduced into 1.9-dev9 by commit 0c18a6fe3
("MEDIUM: servers: Add a way to keep idle connections alive.") and was
later moved to cfgparse.c by commit 980855bd9 ("BUG/MEDIUM: server:
initialize the orphaned conns lists and tasks at the end").

This patch needs to be backported as far as 1.9, with care as 1.9 is
slightly different there (uses idle_task[] instead of idle_conn_cleanup[]
like in 2.x).
2019-10-18 09:04:02 +02:00
Olivier Houchard
e8826ded5f BUG/MEDIUM: mux_pt: Make sure we don't have a conn_stream before freeing.
On error, make sure we don't have a conn_stream before freeing the connection
and the associated mux context. Otherwise a stream will still reference
the connection, and attempt to use it.
If we still have a conn_stream, it will properly be free'd when the detach
method is called, anyway.

This should be backported to 2.0 and 1.9.
2019-10-17 18:02:57 +02:00
Christopher Faulet
ba0c53ef71 BUG/MINOR: tcp: Don't alter counters returned by tcp info fetchers
There are 2 kinds of tcp info fetchers. Those returning a time value (fc_rtt and
fc_rttval) and those returning a counter (fc_unacked, fc_sacked, fc_retrans,
fc_fackets, fc_lost, fc_reordering). Because of a bug, the counters were handled
as time values, and by default, were divided by 1000 (because of an invalid
conversion from us to ms). To work around this bug and have the right value, the
argument "us" had to be specified.

So now, tcp info fetchers returning a counter don't support any argument
anymore. To not break old configurations, if an argument is provided, it is
ignored and a warning is emitted during the configuration parsing.

In addition, parameter validiation is now performed during the configuration
parsing.

This patch must be backported as far as 1.7.
2019-10-17 15:20:06 +02:00
William Lallemand
5fdb5b36e1 BUG/MINOR: mworker/ssl: close openssl FDs unconditionally
Patch 56996da ("BUG/MINOR: mworker/ssl: close OpenSSL FDs on reload")
fixes a issue where the /dev/random FD was leaked by OpenSSL upon a
reload in master worker mode. Indeed the FD was not flagged with
CLOEXEC.

The fix was checking if ssl_used_frontend or ssl_used_backend were set
to close the FD. This is wrong, indeed the lua init code creates an SSL
server without increasing the backend value, so the deinit is never
done when you don't use SSL in your configuration.

To reproduce the problem you just need to build haproxy with openssl and
lua with an openssl which does not use the getrandom() syscall.  No
openssl nor lua configuration are required for haproxy.

This patch must be backported as far as 1.8.

Fix issue #314.
2019-10-17 11:36:22 +02:00
Willy Tarreau
ccc61d87ae BUG/MINOR: cache: also cache absolute URIs
The recent changes to address URI issues mixed with the recent fix to
stop caching absolute URIs have caused the cache not to cache H2 requests
anymore since these ones come with a scheme and authority. Let's unbreak
this by using absolute URIs all the time, now that we keep host and
authority in sync. So what is done now is that if we have an authority,
we take the whole URI as it is as the cache key. This covers H2 and H1
absolute requests. If no authority is present (most H1 origin requests),
then we prepend "https://" and the Host header. The reason for https://
is that most of the time we don't care about the scheme, but since about
all H2 clients use this scheme, at least we can share the cache between
H1 and H2.

No backport is needed since the breakage only affects 2.1-dev.
2019-10-17 10:40:47 +02:00
David Carlier
5e4c8e2a67 BUILD/MEDIUM: threads: enable cpu_affinity on osx
Enable it but on a per thread basis only using Darwin native API.
2019-10-17 07:20:58 +02:00
David Carlier
a92c5cec2d BUILD/MEDIUM: threads: rename thread_info struct to ha_thread_info
On Darwin, the thread_info name exists as a standard function thus
we need to rename our array to ha_thread_info to fix this conflict.
2019-10-17 07:15:17 +02:00
Christopher Faulet
04f8919a78 MINOR: mux-h1: Force close mode for proxy responses with an unfinished request
When a response generated by HAProxy is handled by the mux H1, if the
corresponding request has not fully been received, the close mode is
forced. Thus, the client is notified the connection will certainly be closed
abruptly, without waiting the end of the request.
2019-10-16 10:03:12 +02:00
Christopher Faulet
065118166c MINOR: htx: Add a flag on HTX to known when a response was generated by HAProxy
The flag HTX_FL_PROXY_RESP is now set on responses generated by HAProxy,
excluding responses returned by applets and services. It is an informative flag
set by the applicative layer.
2019-10-16 10:03:12 +02:00
Christopher Faulet
0d4ce93fcf BUG/MINOR: http-htx: Properly set htx flags on error files to support keep-alive
When an error file was loaded, the flag HTX_SL_F_XFER_LEN was never set on the
HTX start line because of a bug. During the headers parsing, the flag
H1_MF_XFER_LEN is never set on the h1m. But it was the condition to set
HTX_SL_F_XFER_LEN on the HTX start-line. Instead, we must only rely on the flags
H1_MF_CLEN or H1_MF_CHNK.

Because of this bug, it was impossible to keep a connection alive for a response
generated by HAProxy. Now the flag HTX_SL_F_XFER_LEN is set when an error file
have a content length (chunked responses are unsupported at this stage) and the
connection may be kept alive if there is no connection header specified to
explicitly close it.

This patch must be backported to 2.0 and 1.9.
2019-10-16 10:03:12 +02:00
Willy Tarreau
abefa34c34 MINOR: version: make the version strings variables, not constants
It currently is not possible to figure the exact haproxy version from a
core file for the sole reason that the version is stored into a const
string and as such ends up in the .text section that is not part of a
core file. By turning them into variables we move them to the data
section and they appear in core files. In order to help finding them,
we just prepend an extra variable in front of them and we're able to
immediately spot the version strings from a core file:

  $ strings core | fgrep -A2 'HAProxy version'
  HAProxy version follows
  2.1-dev2-e0f48a-88
  2019/10/15

(These are haproxy_version and haproxy_date respectively). This may be
backported to 2.0 since this part is not support to impact anything but
the developer's time spent debugging.
2019-10-16 09:56:57 +02:00
William Lallemand
e0f48ae976 BUG/MINOR: ssl: can't load ocsp files
246c024 ("MINOR: ssl: load the ocsp in/from the ckch") broke the loading
of OCSP files. The function ssl_sock_load_ocsp_response_from_file() was
not returning 0 upon success which lead to an error after the .ocsp was
read.
2019-10-15 13:50:20 +02:00
William Lallemand
786188f6bf BUG/MINOR: ssl: fix error messages for OCSP loading
The error messages for OCSP in ssl_sock_load_crt_file_into_ckch() add a
double extension to the filename, that can be confusing. The messages
reference a .issuer.issuer file.
2019-10-15 13:50:20 +02:00
Miroslav Zagorac
f0eb3739ac BUG/MINOR: WURFL: fix send_log() function arguments
If the user agent data contains text that has special characters that
are used to format the output from the vfprintf() function, haproxy
crashes.  String "%s %s %s" may be used as an example.

% curl -A "%s %s %s" localhost:10080/index.html
curl: (52) Empty reply from server

haproxy log:
00000000:WURFL-test.clireq[00c7:ffffffff]: GET /index.html HTTP/1.1
00000000:WURFL-test.clihdr[00c7:ffffffff]: host: localhost:10080
00000000:WURFL-test.clihdr[00c7:ffffffff]: user-agent: %s %s %s
00000000:WURFL-test.clihdr[00c7:ffffffff]: accept: */*
segmentation fault (core dumped)

gdb 'where' output:
#0  strlen () at ../sysdeps/x86_64/strlen.S:106
#1  0x00007f7c014a8da8 in _IO_vfprintf_internal (s=s@entry=0x7ffc808fe750, format=<optimized out>,
    format@entry=0x7ffc808fe9c0 "WURFL: retrieve header request returns [%s %s %s]\n",
    ap=ap@entry=0x7ffc808fe8b8) at vfprintf.c:1637
#2  0x00007f7c014cfe89 in _IO_vsnprintf (
    string=0x55cb772c34e0 "WURFL: retrieve header request returns [(null) %s %s %s  B,w\313U",
    maxlen=<optimized out>,
    format=format@entry=0x7ffc808fe9c0 "WURFL: retrieve header request returns [%s %s %s]\n",
    args=args@entry=0x7ffc808fe8b8) at vsnprintf.c:114
#3  0x000055cb758f898f in send_log (p=p@entry=0x0, level=level@entry=5,
    format=format@entry=0x7ffc808fe9c0 "WURFL: retrieve header request returns [%s %s %s]\n")
    at src/log.c:1477
#4  0x000055cb75845e0b in ha_wurfl_log (
    message=message@entry=0x55cb75989460 "WURFL: retrieve header request returns [%s]\n") at src/wurfl.c:47
#5  0x000055cb7584614a in ha_wurfl_retrieve_header (header_name=<optimized out>, wh=0x7ffc808fec70)
    at src/wurfl.c:763

In case WURFL (actually HAProxy) is not compiled with debug option
enabled (-DWURFL_DEBUG), this bug does not come to light.

This patch could be backported in every version supporting
the ScientiaMobile's WURFL. (as far as 1.7)
2019-10-15 10:47:31 +02:00
Christopher Faulet
531b83e039 MINOR: h1: Reject requests if the authority does not match the header host
As stated in the RCF7230#5.4, a client must send a field-value for the header
host that is identical to the authority if the target URI includes one. So, now,
by default, if the authority, when provided, does not match the value of the
header host, an error is triggered. To mitigate this behavior, it is possible to
set the option "accept-invalid-http-request". In that case, an http error is
captured without interrupting the request parsing.
2019-10-14 22:28:50 +02:00
Christopher Faulet
497ab4f519 MINOR: h1: Reject requests with different occurrences of the header host
There is no reason for a client to send several headers host. It even may be
considered as a bug. However, it is totally invalid to have different values for
those. So now, in such case, an error is triggered during the request
parsing. In addition, when several headers host are found with the same value,
only the first instance is kept and others are skipped.
2019-10-14 22:28:50 +02:00
Christopher Faulet
486498c630 BUG/MINOR: mux-h1: Capture ignored parsing errors
When the option "accept-invalid-http-request" is enabled, some parsing errors
are ignored. But the position of the error is reported. In legacy HTTP mode,
such errors were captured. So, we now do the same in the H1 multiplexer.

If required, this patch may be backported to 2.0 and 1.9.
2019-10-14 22:28:50 +02:00
Christopher Faulet
53a899b946 CLEANUP: h1-htx: Move htx-to-h1 formatting functions from htx.c to h1_htx.c
The functions "htx_*_to_h1()" have been renamed into "h1_format_htx_*()" and
moved in the file h1_htx.c. It is the right place for such functions.
2019-10-14 22:28:50 +02:00
Christopher Faulet
d9233f091a MINOR: mux-h1: Xfer as much payload data as possible during output processing
When an outgoing HTX message is formatted to a raw message, DATA blocks may be
splitted to not tranfser more data than expected. But if the buffer is almost
full, the formatting is interrupted, leaving some unused free space in the
buffer, because data are too large to be copied in one time.

Now, we transfer as much data as possible. When the message is chunked, we also
count the size used to encode the data.
2019-10-14 22:28:44 +02:00
Christopher Faulet
a61aa544b4 BUG/MINOR: mux-h1: Mark the output buffer as full when the xfer is interrupted
When an outgoing HTX message is formatted to a raw message, if we fail to copy
data of an HTX block into the output buffer, we mark it as full. Before it was
only done calling the function buf_room_for_htx_data(). But this function is
designed to optimize input processing.

This patch must be backported to 2.0 and 1.9.
2019-10-14 22:09:33 +02:00
Christopher Faulet
e0f8dc576f BUG/MEDIUM: htx: Catch chunk_memcat() failures when HTX data are formatted to h1
In functions htx_*_to_h1(), most of time several calls to chunk_memcat() are
chained. The expected size is always compared to available room in the buffer to
be sure the full copy will succeed. But it is a bit risky because it relies on
the fact the function chunk_memcat() evaluates the available room in the buffer
in a same way than htx ones. And, unfortunately, it does not. A bug in
chunk_memcat() will always leave a byte unused in the buffer. So, for instance,
when a chunk is copied in an almost full buffer, the last CRLF may be skipped.

To fix the issue, we now rely on the result of chunk_memcat() only.

This patch must be backported to 2.0 and 1.9.
2019-10-14 16:42:46 +02:00
William Lallemand
4a66013069 BUG/MINOR: ssl: fix OCSP build with BoringSSL
246c024 broke the build of the OCSP code with BoringSSL.

Rework it a little so it could load the OCSP buffer of the ckch.

Issue #322.
2019-10-14 15:07:44 +02:00
William Lallemand
104a7a6c14 BUILD: ssl: wrong #ifdef for SSL engines code
The SSL engines code was written below the OCSP #ifdef, which means you
can't build the engines code if the OCSP is deactived in the SSL lib.

Could be backported in every version since 1.8.
2019-10-14 15:07:44 +02:00
William Lallemand
963b2e70ba BUG/MINOR: ssl: fix build without multi-cert bundles
Commit 150bfa8 broke the build with ssl libs that does not support
multi certificate bundles.

Issue #322.
2019-10-14 11:41:18 +02:00
William Lallemand
e15029bea9 BUG/MEDIUM: ssl: NULL dereference in ssl_sock_load_cert_sni()
A NULL dereference can occur when inserting SNIs. In the case of
checking for duplicates, if there is already several sni_ctx with the
same key.

Fix issue #321.
2019-10-14 10:57:16 +02:00
William Lallemand
246c0246d3 MINOR: ssl: load the ocsp in/from the ckch
Don't try to load the files containing the issuer and the OCSP response
each time we generate a SSL_CTX.

The .ocsp and the .issuer are now loaded in the struct
cert_key_and_chain only once and then loaded from this structure when
creating a SSL_CTX.
2019-10-11 17:32:03 +02:00
William Lallemand
a17f4116d5 MINOR: ssl: load the sctl in/from the ckch
Don't try to load the file containing the sctl each time we generate a
SSL_CTX.

The .sctl is now loaded in the struct cert_key_and_chain only once and
then loaded from this structure when creating a SSL_CTX.

Note that this now make possible the use of sctl with multi-cert
bundles.
2019-10-11 17:32:03 +02:00
William Lallemand
150bfa84e3 MEDIUM: ssl/cli: 'set ssl cert' updates a certificate from the CLI
$ echo -e "set ssl cert certificate.pem <<\n$(cat certificate2.pem)\n" | \
    socat stdio /var/run/haproxy.stat
    Certificate updated!

The operation is locked at the ckch level with a HA_SPINLOCK_T which
prevents the ckch architecture (ckch_store, ckch_inst..) to be modified
at the same time. So you can't do a certificate update at the same time
from multiple CLI connections.

SNI trees are also locked with a HA_RWLOCK_T so reading operations are
locked only during a certificate update.

Bundles are supported but you need to update each file (.rsa|ecdsa|.dsa)
independently. If a file is used in the configuration as a bundle AND
as a unique certificate, both will be updated.

Bundles, directories and crt-list are supported, however filters in
crt-list are currently unsupported.

The code tries to allocate every SNIs and certificate instances first,
so it can rollback the operation if that was unsuccessful.

If you have too much instances of the certificate (at least 20000 in my
tests on my laptop), the function can take too much time and be killed
by the watchdog. This will be fixed later. Also with too much
certificates it's possible that socat exits before the end of the
generation without displaying a message, consider changing the socat
timeout in this case (-t2 for example).

The size of the certificate is currently limited by the maximum size of
a payload, that must fit in a buffer.
2019-10-11 17:32:03 +02:00
William Lallemand
f11365b26a MINOR: ssl: ssl_sock_load_crt_file_into_ckch() is filling from a BIO
The function ssl_sock_load_crt_file_into_ckch() is now able to fill a
ckch using a BIO in input.
2019-10-11 17:32:03 +02:00
William Lallemand
614ca0d370 MEDIUM: ssl: ssl_sock_load_ckchs() alloc a ckch_inst
The ssl_sock_load_{multi}_ckchs() function were renamed and modified:

- allocate a ckch_inst and loads the sni in it
- return a ckch_inst or NULL
- the sni_ctx are not added anymore in the sni trees from there
- renamed in ckch_inst_new_load_{multi}_store()
- new ssl_sock_load_ckchs() function calls
ckch_inst_new_load_{multi}_store() and add the sni_ctx to the sni trees.
2019-10-11 17:32:03 +02:00
William Lallemand
0c6d12fb66 MINOR: ssl: ssl_sock_load_multi_ckchs() can properly fail
ssl_sock_load_multi_ckchs() is now able to fail without polluting the
bind_conf trees and leaking memory.

It is a prerequisite to load certificate on-the-fly with the CLI.

The insertion of the sni_ctxs in the trees are done once everything has
been allocated correctly.
2019-10-11 17:32:03 +02:00
William Lallemand
d919937991 MINOR: ssl: ssl_sock_load_ckchn() can properly fail
ssl_sock_load_ckchn() is now able to fail without polluting the
bind_conf trees and leaking memory.

It is a prerequisite to load certificate on-the-fly with the CLI.

The insertion of the sni_ctxs in the trees are done once everything has
been allocated correctly.
2019-10-11 17:32:03 +02:00
William Lallemand
1d29c7438e MEDIUM: ssl: split ssl_sock_add_cert_sni()
In order to allow the creation of sni_ctx in runtime, we need to split
the function to allow rollback.

We need to be able to allocate all sni_ctxs required before inserting
them in case we need to rollback if we didn't succeed the allocation.

The function was splitted in 2 parts.

The first one ckch_inst_add_cert_sni() allocates a struct sni_ctx, fill
it with the right data and insert it in the ckch_inst's list of sni_ctx.

The second will take every sni_ctx in the ckch_inst and insert them in
the bind_conf's sni tree.
2019-10-11 17:32:03 +02:00
William Lallemand
9117de9e37 MEDIUM: ssl: introduce the ckch instance structure
struct ckch_inst represents an instance of a certificate (ckch_node)
used in a bind_conf. Every sni_ctx created for 1 ckch_node in a
bind_conf are linked in this structure.

This patch allocate the ckch_inst for each bind_conf and inserts the
sni_ctx in its linked list.
2019-10-11 17:32:03 +02:00
William Lallemand
28a8fce485 BUG/MINOR: ssl: abort on sni_keytypes allocation failure
The ssl_sock_populate_sni_keytypes_hplr() function does not return an
error upon an allocation failure.

The process would probably crash during the configuration parsing if the
allocation fail since it tries to copy some data in the allocated
memory.

This patch could be backported as far as 1.5.
2019-10-11 17:32:02 +02:00
William Lallemand
8ed5b96587 BUG/MINOR: ssl: free the sni_keytype nodes
This patch frees the sni_keytype nodes once the sni_ctxs have been
allocated in ssl_sock_load_multi_ckchn();

Could be backported in every version using the multi-cert SSL bundles.
2019-10-11 17:32:02 +02:00
William Lallemand
fe49bb3d0c BUG/MINOR: ssl: abort on sni allocation failure
The ssl_sock_add_cert_sni() function never return an error when a
sni_ctx allocation fail. It silently ignores the problem and continues
to try to allocate other snis.

It is unlikely that a sni allocation will succeed after one failure and
start a configuration without all the snis. But to avoid any problem we
return a -1 upon an sni allocation error and stop the configuration
parsing.

This patch must be backported in every version supporting the crt-list
sni filters. (as far as 1.5)
2019-10-11 17:32:02 +02:00
William Lallemand
4b989f2fac MINOR: ssl: initialize the sni_keytypes_map as EB_ROOT
The sni_keytypes_map was initialized to {0}, it's better to initialize
it explicitly to EB_ROOT
2019-10-11 17:32:02 +02:00
William Lallemand
f6adbe9f28 REORG: ssl: move structures to ssl_sock.h 2019-10-11 17:32:02 +02:00
William Lallemand
e3af8fbad3 REORG: ssl: rename ckch_node to ckch_store
A ckch_store is a storage which contains a pointer to one or several
cert_key_and_chain structures.

This patch renames ckch_node to ckch_store, and ckch_n, ckchn to ckchs.
2019-10-11 17:32:02 +02:00
William Lallemand
eed4bf234e MINOR: ssl: crt-list do ckchn_lookup 2019-10-11 17:32:02 +02:00
Willy Tarreau
572d9f5847 MINOR: mux-h2: also support emitting CONTINUATION on trailers
Trailers were forgotten by commit cb985a4da6 ("MEDIUM: mux-h2: support
emitting CONTINUATION frames after HEADERS"), this one just fixes this
miss.
2019-10-11 17:00:04 +02:00
Olivier Houchard
5a3671d8b1 MINOR: h2: Document traps to be avoided on multithread.
Document a few traps to avoid if we ever attempt to allow the upper layer
of the mux h2 to be run by multiple threads.
2019-10-11 16:37:41 +02:00
Olivier Houchard
06910464dd MEDIUM: task: Split the tasklet list into two lists.
As using an mt_list for the tasklet list is costly, instead use a regular list,
but add an mt_list for tasklet woken up by other threads, to be run on the
current thread. At the beginning of process_runnable_tasks(), we just take
the new list, and merge it into the task_list.
This should give us performances comparable to before we started using a
mt_list, but allow us to use tasklet_wakeup() from other threads.
2019-10-11 16:37:41 +02:00
Willy Tarreau
6d4897eec0 BUILD: stats: fix missing '=' sign in array declaration
I introduced this mistake when adding the description for the stats
metrics, it's even amazing it built and worked at all! This was
reported by Travis CI on non-GNU platforms :

src/stats.c:92:39: warning: use of GNU 'missing =' extension in designator [-Wgnu-designator]
    [INF_NAME]               { .name = "Name",                        .desc = "Product name" },
                             ^
                             =
No backport is needed.
2019-10-11 16:39:00 +02:00
Willy Tarreau
19920d6fc9 BUG/MEDIUM: applet: always check a fast running applet's activity before killing
In issue #277 is reported a strange problem related to a fast-spinning
applet which seems to show valid progress being made. It's uncertain how
this can happen, maybe some very specific timing patterns manage to place
just a few bytes in each buffer and result in the peers applet being called
a lot. But it appears possible to artificially cross the spinning threshold
by asking for monster stats page (500 MB) and limiting the send() size to
1 MSS (1460 bytes), causing the stats page to be called for very small
blocks which most often do not leave enough room to place a new chunk.

The idea developed in this patch consists in not crashing for an applet
which reaches a very high call rate if it shows some indication of
progress. Detecting progress on applets is not trivial but in our case
we know that they must at least not claim to wait for a buffer allocation
if this buffer is present, wait for room if the buffer is empty, ask for
more data without polling if such data are still present, nor leave with
an empty input buffer without having written anything nor read anything
from the other side while a shutw is pending.

Doing so doesn't affect normal behaviors nor abuses of our existing
applets and does at least protect against an applet performing an
early return without processing events, or one causing an endless
loop by asking for impossible conditions.

This must be backported to 2.0.
2019-10-11 16:05:57 +02:00
Willy Tarreau
d89331ecb5 MINOR: stats: fill all the descriptions for "show info" and "show stat"
Now "show info desc", "show info typed desc" and "show stat typed desc"
will report (hopefully) accurate descriptions of each field. These ones
were verified in the code. When some metrics are specific to the process
or the thread, they are indicated. Sometimes a config option is known
for a setting and it is reported as well. The purpose mainly is to help
sysadmins in field more easily sort out issues vs non-issues. In part
inspired by this very informative talk :

    https://kernel-recipes.org/en/2019/metrics-are-money/

Example:

  $ socat - /var/run/haproxy.sock <<< "show info desc"
  Name: HAProxy:"Product name"
  Version: 2.1-dev2-991035-31:"Product version"
  Release_date: 2019/10/09:"Date of latest source code update"
  Nbthread: 1:"Number of started threads (global.nbthread)"
  Nbproc: 1:"Number of started worker processes (global.nbproc)"
  Process_num: 1:"Relative process number (1..Nbproc)"
  Pid: 11975:"This worker process identifier for the system"
  Uptime: 0d 0h00m10s:"How long ago this worker process was started (days+hours+minutes+seconds)"
  Uptime_sec: 10:"How long ago this worker process was started (seconds)"
  Memmax_MB: 0:"Worker process's hard limit on memory usage in MB (-m on command line)"
  PoolAlloc_MB: 0:"Amount of memory allocated in pools (in MB)"
  PoolUsed_MB: 0:"Amount of pool memory currently used (in MB)"
  PoolFailed: 0:"Number of failed pool allocations since this worker was started"
  Ulimit-n: 300000:"Hard limit on the number of per-process file descriptors"
  Maxsock: 300000:"Hard limit on the number of per-process sockets"
  Maxconn: 149982:"Hard limit on the number of per-process connections (configured or imposed by Ulimit-n)"
  Hard_maxconn: 149982:"Hard limit on the number of per-process connections (imposed by Memmax_MB or Ulimit-n)"
  CurrConns: 0:"Current number of connections on this worker process"
  CumConns: 1:"Total number of connections on this worker process since started"
  CumReq: 1:"Total number of requests on this worker process since started"
  MaxSslConns: 0:"Hard limit on the number of per-process SSL endpoints (front+back), 0=unlimited"
  CurrSslConns: 0:"Current number of SSL endpoints on this worker process (front+back)"
  CumSslConns: 0:"Total number of SSL endpoints on this worker process since started (front+back)"
  Maxpipes: 0:"Hard limit on the number of pipes for splicing, 0=unlimited"
  PipesUsed: 0:"Current number of pipes in use in this worker process"
  PipesFree: 0:"Current number of allocated and available pipes in this worker process"
  ConnRate: 0:"Number of front connections created on this worker process over the last second"
  ConnRateLimit: 0:"Hard limit for ConnRate (global.maxconnrate)"
  MaxConnRate: 0:"Highest ConnRate reached on this worker process since started (in connections per second)"
  SessRate: 0:"Number of sessions created on this worker process over the last second"
  SessRateLimit: 0:"Hard limit for SessRate (global.maxsessrate)"
  MaxSessRate: 0:"Highest SessRate reached on this worker process since started (in sessions per second)"
  SslRate: 0:"Number of SSL connections created on this worker process over the last second"
  SslRateLimit: 0:"Hard limit for SslRate (global.maxsslrate)"
  MaxSslRate: 0:"Highest SslRate reached on this worker process since started (in connections per second)"
  SslFrontendKeyRate: 0:"Number of SSL keys created on frontends in this worker process over the last second"
  SslFrontendMaxKeyRate: 0:"Highest SslFrontendKeyRate reached on this worker process since started (in SSL keys per second)"
  SslFrontendSessionReuse_pct: 0:"Percent of frontend SSL connections which did not require a new key"
  SslBackendKeyRate: 0:"Number of SSL keys created on backends in this worker process over the last second"
  SslBackendMaxKeyRate: 0:"Highest SslBackendKeyRate reached on this worker process since started (in SSL keys per second)"
  SslCacheLookups: 0:"Total number of SSL session ID lookups in the SSL session cache on this worker since started"
  SslCacheMisses: 0:"Total number of SSL session ID lookups that didn't find a session in the SSL session cache on this worker since started"
  CompressBpsIn: 0:"Number of bytes submitted to HTTP compression in this worker process over the last second"
  CompressBpsOut: 0:"Number of bytes out of HTTP compression in this worker process over the last second"
  CompressBpsRateLim: 0:"Limit of CompressBpsOut beyond which HTTP compression is automatically disabled"
  Tasks: 10:"Total number of tasks in the current worker process (active + sleeping)"
  Run_queue: 1:"Total number of active tasks+tasklets in the current worker process"
  Idle_pct: 100:"Percentage of last second spent waiting in the current worker thread"
  node: wtap.local:"Node name (global.node)"
  Stopping: 0:"1 if the worker process is currently stopping, otherwise zero"
  Jobs: 14:"Current number of active jobs on the current worker process (frontend connections, master connections, listeners)"
  Unstoppable Jobs: 0:"Current number of unstoppable jobs on the current worker process (master connections)"
  Listeners: 13:"Current number of active listeners on the current worker process"
  ActivePeers: 0:"Current number of verified active peers connections on the current worker process"
  ConnectedPeers: 0:"Current number of peers having passed the connection step on the current worker process"
  DroppedLogs: 0:"Total number of dropped logs for current worker process since started"
  BusyPolling: 0:"1 if busy-polling is currently in use on the worker process, otherwise zero (config.busy-polling)"
  FailedResolutions: 0:"Total number of failed DNS resolutions in current worker process since started"
  TotalBytesOut: 0:"Total number of bytes emitted by current worker process since started"
  BytesOutRate: 0:"Number of bytes emitted by current worker process over the last second"
2019-10-10 11:30:07 +02:00
Willy Tarreau
6b19b142e8 MINOR: stats: make "show stat" and "show info"
Now "show info" supports "desc" after the default and "typed" formats,
and "show stat" supports this after the typed format. In both cases
this appends the description for the represented metric between double
quotes. The same could be done for JSON output but would possibly require
to update the schema first.
2019-10-10 11:30:07 +02:00
Willy Tarreau
eaa55370c3 MINOR: stats: prepare to add a description with each stat/info field
Several times some users have expressed the non-intuitive aspect of some
of our stat/info metrics and suggested to add some help. This patch
replaces the char* arrays with an array of name_desc so that we now have
some reserved room to store a description with each stat or info field.
These descriptions are currently empty and not reported yet.
2019-10-10 11:30:07 +02:00
Willy Tarreau
2f39738750 MINOR: stats: support the "desc" output format modifier for info and stat
Now "show info" and "show stat" can parse "desc" as an output format
modifier that will be passed down the chain to add some descriptions
to the fields depending on the format in use. For now it is not
exploited.
2019-10-10 11:30:07 +02:00
Willy Tarreau
43241ffb6c MINOR: stats: uniformize the calling convention of the dump functions
Some functions used to take flags + appctx with flags==appctx.flags,
others neither, others just one of them. Some functions used to have
the flags before the object being dumped (server) while others had
it after (listener). This patch aims at cleaning this up a little bit
by following this principle:
  - low-level functions which do not need the appctx take flags only
  - medium-level functions which already use the appctx for other
    reasons do not keep the flags
  - top-level functions which already have the stream-int don't need
    the flags nor the appctx.
2019-10-10 11:30:07 +02:00
Willy Tarreau
b0ce3ad9ff MINOR: stats: make stats_dump_fields_json() directly take flags
It used to take an inverted flag for STAT_STARTED, let's make it take
the raw flags instead.
2019-10-10 11:30:07 +02:00
Willy Tarreau
ab02b3f345 MINOR: stats: get rid of the STAT_SHOWADMIN flag
This flag is used to decide to show the check box in front of a proxy
on the HTML stat page. It is always equal to STAT_ADMIN except when the
proxy has no backend capability (i.e. a pure frontend) or has no server,
in which case it's only used to avoid leaving an empty column at the
beginning of the table. Not only this is pretty useless, but it also
causes the columns not to align well when mixing multiple proxies with
or without servers.

Let's simply always use STAT_ADMIN and get rid of this flag.
2019-10-10 11:30:07 +02:00
Willy Tarreau
578d6e4360 MINOR: stats: set the appctx flags when initializing the applet only
When "show stat" is emitted on the CLI, we need to set the relevant
flags on the appctx. We must not re-adjust them while dumping a proxy.
2019-10-10 11:30:07 +02:00
Willy Tarreau
676c29e3ae MINOR: stats: always merge the uri_auth flags into the appctx flags
Now we only use the appctx flags everywhere in the code, and the uri_auth
flags are read only by the HTTP analyser which presets the appctx ones.
This will allow to simplify access to the flags everywhere.
2019-10-10 11:30:07 +02:00
Willy Tarreau
708c41602b MINOR: stats: replace the ST_* uri_auth flags with STAT_*
We used to rely on some config flags defined in uri_auth.h set during
parsing, and another set of STAT_* flags defined in stats.h set at run
time, with a somewhat gray area between the two sets. This is confusing
in the stats code as both are called "flags" in various functions and
it's quite hard to know which one describes what.

This patch cleans this up by replacing all ST_* by a newly assigned
value from the STAT_* set so that we can now use unified flags to
describe both the configuration and the current state. There is no
functional change at all.
2019-10-10 11:30:07 +02:00
Willy Tarreau
ee4f5f83d3 MINOR: stats: get rid of the ST_CONVDONE flag
This flag was added in 1.4-rc1 by commit 329f74d463 ("[BUG] uri_auth: do
not attemp to convert uri_auth -> http-request more than once") to
address the case where two proxies inherit the stats settings from
the defaults instance, and the first one compiles the expression while
the second one uses it. In this case since they use the exact same
uri_auth pointer, only the first one should compile and the second one
must not fail the check. This was addressed by adding an ST_CONVDONE
flag indicating that the expression conversion was completed and didn't
need to be done again. But this is a hack and it becomes cumbersome in
the middle of the other flags which are all relevant to the stats
applet. Let's instead fix it by checking if we're dealing with an
alias of the defaults instance and refrain from compiling this twice.
This allows us to remove the ST_CONVDONE flag.

A typical config requiring this check is :

   defaults
        mode http
        stats auth foo:bar

   listen l1
        bind :8080

   listen l2
        bind :8181

Without this (or previous) check it would cmoplain when checking l2's
validity since the rule was already built.
2019-10-10 11:30:07 +02:00
Willy Tarreau
6103836315 MINOR: stats: mention in the help message support for "json" and "typed"
Both "show info" and "show stat" support the "typed" output format and
the "json" output format. I just never can remind them, which is an
indication that some help is missing.
2019-10-10 11:30:07 +02:00
Willy Tarreau
30ee1efe67 MEDIUM: h2: use the normalized URI encoding for absolute form requests
H2 strongly recommends that clients exclusively use the absolute form
for requests, which contains a scheme, an authority and a path, instead
of the old format involving the Host header and a path. Thus there is
no way to distinguish between a request intended for a proxy and an
origin request, and as such proxied requests are lost.

This patch makes sure to keep the encoding of all absolute form requests
so that the URI is kept end-to-end. If the scheme is http or https, there
is an uncertainty so the request is tagged as a normalized URI so that
the other end (H1) can decide to emit it in origin form as this is by far
the most commonly expected one, and it's certain that quite a number of
H1 setups are not ready to cope with absolute URIs.

There is a direct visible impact of this change, which is that the uri
sample fetch will now return absolute URIs (as they really come on the
wire) whenever these are used. It also means that default http logs will
report absolute URIs.

If a situation is once met where a client uses H2 to join an H1 proxy
with haproxy in the middle, then it will be trivial to add an option to
ask the H1 output to use absolute encoding for such requests.

Later we may be able to consider that the normalized URI is the default
output format and stop sending them in origin form unless an option is
set.

Now chaining multiple instances keeps the semantics as far as possible
along the whole chain :

 1) H1 to H1
  H1:"GET /"       --> H1:"GET /"       # log: /
  H1:"GET http://" --> H1:"GET http://" # log: http://
  H1:"GET ftp://"  --> H1:"GET ftp://"  # log: ftp://

 2) H2 to H1
  H2:"GET /"       --> H1:"GET /"       # log: /
  H2:"GET http://" --> H1:"GET /"       # log: http://
  H2:"GET ftp://"  --> H1:"GET ftp://"  # log: ftp://

 3) H1 to H2 to H2 to H1
  H1:"GET /"       --> H2:"GET /"       --> H2:"GET /"       --> H1:"GET /"
  H1:"GET http://" --> H2:"GET http://" --> H2:"GET http://" --> H1:"GET /"
  H1:"GET ftp://"  --> H2:"GET ftp://"  --> H2:"GET ftp://"  --> H1:"GET ftp://"

Thus there is zero loss on H1->H1, H1->H2 nor H2->H2, and H2->H1 is
normalized in origin format if ambiguous.
2019-10-09 11:10:19 +02:00
Willy Tarreau
b8ce8905cf MEDIUM: mux-h2: do not map Host to :authority on output
Instead of mapping the Host header field to :authority, we now act
differently if the request is in origin form or in absolute form.
If it's absolute, we extract the scheme and the authority from the
request, fix the path if it's empty, and drop the Host header.
Otherwise we take the scheme from the http/https flags in the HTX
layer, make the URI be the path only, and emit the Host header,
as indicated in RFC7540#8.1.2.3. This allows to distinguish between
absolute and origin requests for H1 to H2 conversions.
2019-10-09 11:10:19 +02:00
Willy Tarreau
1440fe8b4b MINOR: h2: report in the HTX flags when the request has an authority
The other side will need to know when to emit an authority or not. We
need to pass this information in the HTX flags.
2019-10-09 11:10:19 +02:00
Willy Tarreau
92919f7fd5 MEDIUM: h2: make the request parser rebuild a complete URI
Till now we've been producing path components of the URI and using the
:authority header only to be placed into the host part. But this practice
is not correct, as if we're used to convey H1 proxy requests over H2 then
over H1, the absolute URI is presented as a path on output, which is not
valid. In addition the scheme on output is not updated from the absolute
URI either.

Now the request parser will continue to deliver origin-form for request
received using the http/https schemes, but will use the absolute-form
when dealing with other schemes, by concatenating the scheme, the authority
and the path if it's not '*'.
2019-10-09 11:10:19 +02:00
Christopher Faulet
92916d343c MINOR: h1-htx: Only use the path of a normalized URI to format a request line
When a request start-line is converted to its raw representation, if its URI is
normalized, only the path part is used. Most of H2 clients send requests using
the absolute form (:scheme + :authority + :path), regardless the request is sent
to a proxy or not. But, when the request is relayed to an H1 origin server, it
is unusual to send it using the absolute form. And, even if the servers must
support this form, some old servers may reject it. So, for such requests, we
only get the path of the absolute URI. Most of time, it will be the right
choice. However, an option will probably by added to customize this behavior.
2019-10-09 11:10:16 +02:00
Christopher Faulet
d7b7a1ce50 MEDIUM: http-htx: Keep the Host header and the request start-line synchronized
In HTTP, the request authority, if any, and the Host header must be identical
(excluding any userinfo subcomponent and its "@" delimiter). So now, during the
request analysis, when the Host header is updated, the start-line is also
updated. The authority of an absolute URI is changed accordingly. Symmetrically,
if the URI is changed, if it contains an authority, then then Host header is
also changed. In this latter case, the flags of the start-line are also updated
to reflect the changes on the URI.
2019-10-09 11:05:31 +02:00
Christopher Faulet
fe451fb9ef MINOR: h1-htx: Set the flag HTX_SL_F_HAS_AUTHORITY during the request parsing
When an h1 request is received and parsed, this flag is set if it is a CONNECT
request or if an absolute URI is detected.
2019-10-09 11:05:31 +02:00
Christopher Faulet
16fdc55f79 MINOR: http: Add a function to get the authority into a URI
The function http_get_authority() may be used to parse a URI and looks for the
authority, between the scheme and the path. An option may be used to skip the
user info (part before the '@'). Most of time, the user info will be ignored.
2019-10-09 11:05:31 +02:00
Willy Tarreau
2be362c937 MINOR: h2: clarify the rules for how to convert an H2 request to HTX
The H2 request parsing is not trivial given that we have multiple
possible syntaxes. Mainly we can have :authority or not, and when
a CONNECT method is seen, :scheme and :path are missing. This mostly
updates the functions' comments and header index assignments to make
them less confusing. Functionally there is no change.
2019-10-09 11:05:31 +02:00
Christopher Faulet
08618a733d BUG/MINOR: mux-h1/mux-fcgi/trace: Fix position of the 4th arg in some traces
In these muxes, when an integer value is provided in a trace, it must be the 4th
argument. The 3rd one, if defined, is always an HTX message. Unfortunately, some
traces are buggy and the 4th argument is erroneously passed in 3rd position.

No backport needed.
2019-10-08 16:28:30 +02:00
Willy Tarreau
cb985a4da6 MEDIUM: mux-h2: support emitting CONTINUATION frames after HEADERS
There are some reports of users not being able to pass "enterprise"
traffic through haproxy when using H2 because it doesn't emit CONTINUATION
frames and as such is limited to headers no longer than the negociated
max-frame-size which usually is 16 kB.

This patch implements support form emitting CONTINUATION when a HEADERS
frame cannot fit within a limit of mfs. It does this by first filling a
buffer-wise frame, then truncating it starting from the tail to append
CONTINUATION frames. This makes sure that we can truncate on any byte
without being forced to stop on a header boundary, and ensures that the
common case (no fragmentation) doesn't add any extra cost. By moving
the tail first we make sure that each byte is moved only once, thus the
performance impact remains negligible.

This addresses github issue #249.
2019-10-07 18:18:32 +02:00
Willy Tarreau
22c6107dba BUG/MEDIUM: cache: make sure not to cache requests with absolute-uri
If a request contains an absolute URI and gets its Host header field
rewritten, or just the request's URI without touching the Host header
field, it can lead to different Host and authority parts. The cache
will always concatenate the Host and the path while a server behind
would instead ignore the Host and use the authority found in the URI,
leading to incorrect content possibly being cached.

Let's simply refrain from caching absolute requests for now, which
also matches what the comment at the top of the function says. Later
we can improve this by having a special handling of the authority.

This should be backported as far as 1.8.
2019-10-07 14:21:30 +02:00
Christopher Faulet
5c0f859c27 MINOR: mux-fcgi/trace: Register a new trace source with its events
As for the mux h1 and h2, traces are now supported in the mux fcgi. All parts of
the multiplexer is covered by these traces. Events are splitted by categories
(fconn, fstrm, stream, rx, tx and rsp) for a total of ~40 different events with
5 verboisty levels.

In traces, the first argument is always a connection. So it is easy to get the
fconn (conn->ctx). The second argument is always a fstrm. The third one is an
HTX message. Depending on the context it is the request or the response. In all
cases it is owned by a channel. Finally, the fourth argument is an integer
value. Its meaning depends on the calling context.
2019-10-04 16:12:02 +02:00
Christopher Faulet
660f6f34d7 MINOR: mux-h1: Try to wakeup the stream on output buffer allocation
When the output buffer allocation failed, we block stream processing. When
finally a buffer is available and we succed to allocate the output buffer, it
seems fair to wake up the stream.
2019-10-04 16:12:02 +02:00
Christopher Faulet
7a991a9b83 BUG/MINOR: mux-h1: Adjust header case when chunked encoding is add to a message
When an outgoing h1 message is formatted, if it is considered as chunked but the
corresponding header is missing, we add it. And as all other h1 headers, if
configured so, the case of this header must be adjusted.

No backport needed.
2019-10-04 16:12:02 +02:00
Christopher Faulet
5cef2a6d84 BUG/MINOR: mux-h1: Adjust header case when the server name is add to a request
As all other h1 headers, if configured so, the case of this header must be adjusted.

No backport needed.
2019-10-04 16:12:02 +02:00
Christopher Faulet
67d580994e MINOR: http: Remove headers matching the name of http-send-name-header option
It is not explicitly stated in the documentation, but some users rely on this
behavior. When the server name is inserted in a request, headers with the same
name are first removed.

This patch is not tagged as a bug, because it is not explicitly documented. We
choose to keep the same implicit behavior to not break existing
configuration. Because this option is used very little, it is not a big deal.
2019-10-04 16:12:02 +02:00
Christopher Faulet
dabcc8eb47 MINOR: proxy: Store http-send-name-header in lower case
All HTTP header names are now handled in lower case. So this one is now stored
in lower case. It will simplify some processing in HTTP muxes.
2019-10-04 16:12:02 +02:00
Christopher Faulet
6b81df7276 MINOR: mux-h1/trace: register a new trace source with its events
As for the mux h2, traces are now supported in the mux h1. All parts of the
multiplexer is covered by these traces. Events are splitted by categories (h1c,
h1s, stream, rx and tx) for a total of ~30 different events with 5 verboisty
levels.

In traces, the first argument is always a connection. So it is easy to get the
h1c (conn->ctx). The second argument is always a h1s. The third one is an HTX
message. Depending on the context it is the request or the response. In all
cases it is owned by a channel. Finally, the fourth argument is an integer
value. Its meaning depends on the calling context.
2019-10-04 16:11:57 +02:00
Christopher Faulet
af542635f7 MINOR: h1-htx: Update h1_copy_msg_data() to ease the traces in the mux-h1
This function now uses the address of the pointer to the htx message where the
copy must be performed. This way, when a zero-copy is performed, there is no
need to refresh the caller's htx message. It is a bit easier to do that way,
especially to add traces in the mux-h1.
2019-10-04 15:46:59 +02:00
Christopher Faulet
f81ef0344e BUG/MINOR: mux-h2/trace: Fix traces on h2c initialization
When a new H2 connection is initialized, the connection context is not changed
before the end. So, traces emitted during this initialization are buggy, except
the last one when no error occurred, because the connection context is not an
h2c.

To fix the bug, the connection context is saved and set as soon as possible. So,
the connection can always safely be used in all traces, except for the very
first one. And on error, the connection context is restored.

No need to backport.
2019-10-04 15:46:59 +02:00
Frédéric Lécaille
5a4fe5a35d BUG/MINOR: peers: crash on reload without local peer.
When we configure a "peers" section without local peer, this makes haproxy
old process crash on reload.

Such a configuration file allows to reproduce this issue:

  global
    stats socket /tmp/sock1 mode 666 level admin
    stats timeout 10s

  peers peers
    peer localhost 127.0.0.1:1024

This bug was introduced by this commit:
  "MINOR: cfgparse: Make "peer" lines be parsed as "server" lines"

This commit introduced a new condition to detect a "peers" section without
local peer. This is a "peers" section with a frontend struct which has no ->id
initialized member. Such a "peers" section must be removed.

This patch adds this new condition to remove such peers sections without local
peer as this was always done before.

Must be backported to 2.0.
2019-10-04 10:21:04 +02:00
Olivier Houchard
07308677dd BUG/MEDIUM: tasks: Don't forget to decrement tasks_run_queue.
When executing tasks, don't forget to decrement tasks_run_queue once we
popped one task from the task_list. tasks_run_queue used to be decremented
by __tasklet_remove_from_tasklet_list(), but we now call MT_LIST_POP().
2019-10-03 14:55:40 +02:00
Willy Tarreau
c2ea47fb18 BUG/MEDIUM: mux-h2: do not enforce timeout on long connections
Alexandre Derumier reported issue #308 in which the client timeout will
strike on an H2 mux when it's shorter than the server's response time.
What happens in practice is that there is no activity on the connection
and there's no data pending on output so we can expire it. But this does
not take into account the possibility that some streams are in fact
waiting for the data layer above. So what we do now is that we enforce
the timeout when:
  - there are no more streams
  - some data are pending in the output buffer
  - some streams are blocked on the connection's flow control
  - some streams are blocked on their own flow control
  - some streams are in the send/sending list

In all other cases the connection will not timeout as it means that some
streams are actively used by the data layer.

This fix must be backported to 2.0, 1.9 and probably 1.8 as well. It
depends on the new "blocked_list" field introduced by "MINOR: mux-h2:
add a per-connection list of blocked streams". It would be nice to
also backport "ebtree: make eb_is_empty() and eb_is_dup() take a const"
to avoid a build warning.
2019-10-02 15:27:03 +02:00
Willy Tarreau
9edf6dbecc MINOR: mux-h2: add a per-connection list of blocked streams
Currently the H2 mux doesn't have a list of all the streams blocking on
the H2 side. It only knows about those trying to send or waiting for a
connection window update. It is problematic to enforce timeouts because
we never know if a stream has to live as long as the data layer wants or
has to be timed out becase it's waiting for a stream window update. This
patch adds a new list, "blocked_list", to store streams blocking on
stream flow control, or later, dependencies. Streams blocked on sfctl
are now added there. It doesn't modify the rest of the logic.
2019-10-02 14:16:14 +02:00
Willy Tarreau
35fb846333 MINOR: mux-h2/trace: missing conn pointer in demux full message
One trace was missing the connection's pointer, reporting "demux buffer full"
without indicating for what connection it was.
2019-10-02 14:16:14 +02:00
Willy Tarreau
6905d18495 Revert "MINOR: cache: allow caching of OPTIONS request"
This reverts commit 1263540fe8.

As discussed in issues #214 and #251, this is not the correct way to
cache CORS responses, since it relies on hacking the cache to cache
the OPTIONS method which is explicitly non-cacheable and for which
we cannot rely on any standard caching semantics (cache headers etc
are not expected there). Let's roll this back for now and keep that
for a more reliable and flexible CORS-specific solution later.
2019-10-01 17:59:17 +02:00
Baptiste Assmann
4c52e4b560 BUG/MINOR: action: do-resolve does not yield on requests with body
@davidmogar reported a github issue (#227) about problems with
do-resolve action when the request contains a body.
The variable was never populated in such case, despite tcpdump shows a
valid DNS response coming back.

The do-resolve action is a task in HAProxy and so it's waken by the
scheduler each time the scheduler think such task may have some work to
do.
When a simple HTTP request is sent, then the task is called, it sends
the DNS request, then the scheduler will wake up the task again later
once the DNS response is there.
Now, when the client send a PUT or a POST request (or any other type)
with a BODY, then the do-resolve action if first waken up once the
headers are processed. It sends the DNS request. Then, when the bytes
for the body are processed by HAProxy AND the DNS response has not yet
been received, then the action simply terminates and cleans up all the
data associated to this resolution...

This patch detect such behavior and if the action is now waken up while
a DNS resolution is in RUNNING state, then the action will tell the
scheduler to wake it up again later.

Backport status: 2.0 and above
2019-10-01 15:50:50 +02:00
William Lallemand
1633e39d91 BUILD: ssl: fix a warning when built with openssl < 1.0.2
src/ssl_sock.c:2928:12: warning: ‘ssl_sock_is_ckch_valid’ defined but not used [-Wunused-function]
 static int ssl_sock_is_ckch_valid(struct cert_key_and_chain *ckch)

This function is only used with openssl >= 1.0.2, this patch adds a
condition to build the function.
2019-09-30 13:40:53 +02:00
Tim Duesterhus
9fe7c6376a BUG/MEDIUM: lua: Store stick tables into the sample's t field
This patch fixes issue #306.

This bug was introduced in the stick table refactoring in
1b8e68e89a.

This fix must be backported to 2.0.
2019-09-30 04:11:36 +02:00
Tim Duesterhus
2e89dec513 CLEANUP: lua: Get rid of obsolete (size_t *) cast in hlua_lua2(smp|arg)
This was required for the `chunk` API (`data` was an int), but is not
required with the `buffer` API.
2019-09-30 04:11:36 +02:00
Tim Duesterhus
29d2e8aa9a BUG/MINOR: lua: Properly initialize the buffer's fields for string samples in hlua_lua2(smp|arg)
`size` is used in conditional jumps and valgrind complains:

==24145== Conditional jump or move depends on uninitialised value(s)
==24145==    at 0x4B3028: smp_is_safe (sample.h:98)
==24145==    by 0x4B3028: smp_make_safe (sample.h:125)
==24145==    by 0x4B3028: smp_to_stkey (stick_table.c:936)
==24145==    by 0x4B3F2A: sample_conv_in_table (stick_table.c:1113)
==24145==    by 0x420AD4: hlua_run_sample_conv (hlua.c:3418)
==24145==    by 0x54A308F: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0)
==24145==    by 0x54AFEFC: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0)
==24145==    by 0x54A29F1: ??? (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0)
==24145==    by 0x54A3523: lua_resume (in /usr/lib/x86_64-linux-gnu/liblua5.3.so.0.0.0)
==24145==    by 0x426433: hlua_ctx_resume (hlua.c:1097)
==24145==    by 0x42D7F6: hlua_action (hlua.c:6218)
==24145==    by 0x43A414: http_req_get_intercept_rule (http_ana.c:3044)
==24145==    by 0x43D946: http_process_req_common (http_ana.c:500)
==24145==    by 0x457892: process_stream (stream.c:2084)

Found while investigating issue #306.

A variant of this issue exists since 55da165301,
which was using the old `chunk` API instead of the `buffer` API thus this patch
must be backported to HAProxy 1.6 and higher.
2019-09-30 04:11:36 +02:00
Christopher Faulet
52c91bb72c BUG/MINOR: stats: Add a missing break in a switch statement
A break is missing in the switch statement in the function
stats_emit_json_data_field(). This bug was introduced in the commit 88a0db28a
("MINOR: stats: Add the support of float fields in stats").

This patch fixes the issue #302 and #303. It must be backported to 2.0.
2019-09-28 10:41:09 +02:00
Willy Tarreau
fc41e25c2e BUG/MEDIUM: fcgi: fix missing list tail in sample fetch registration
Ilya reported in bug #300 that ASAN found a read overflow during startup
in the fcgi code due to a missing empty element at the end of the list
of sample fetches. The effect is that will randomly either work or crash
on startup.

No backport is needed, this is solely for 2.1-dev.
2019-09-27 22:48:27 +02:00
Christopher Faulet
88a0db28ae MINOR: stats: Add the support of float fields in stats
It is now possible to format stats counters as floats. But the stats applet does
not use it.

This patch is required by the Prometheus exporter to send the time averages in
seconds. If the promex change is backported, this patch must be backported
first.
2019-09-27 08:49:09 +02:00
Christopher Faulet
d72665b425 CLEANUP: http-ana: Remove the unused function http_send_name_header()
Because the HTTP multiplexers are now responsible to handle the option
"http-send-name-header", the function http_send_name_header() can be removed.
2019-09-27 08:48:53 +02:00
Christopher Faulet
72ba6cd8c0 MINOR: http: Add server name header from HTTP multiplexers
the option "http-send-name-header" is an eyesore. It was responsible of several
bugs because it is handled after the message analysis. With the HTX
representation, the situation is cleaner because no rewind on forwarded data is
required. But it remains ugly.

With recent changes in HAProxy, we have the opportunity to make it fairly
better. The message formatting in now done in the HTTP multiplexers. So it seems
to be the right place to handle this option. Now, the server name is added by
the HTTP multiplexers (h1, h2 and fcgi).
2019-09-27 08:48:21 +02:00
Christopher Faulet
b1bb1afa47 MINOR: spoe: Support the async mode with several threads
A different engine-id is now generated for each thread. So, it is possible to
enable the async mode with several threads.

This patch may be backported to older versions.
2019-09-26 16:51:02 +02:00
Christopher Faulet
09bd9aa412 MINOR: spoe: Improve generation of the engine-id
Use the same algo than the sample fetch uuid(). This one was added recently. So
it is better to use the same way to generate UUIDs.

This patch may be backported to older versions.
2019-09-26 16:51:02 +02:00
Kevin Zhu
d87b1a56d5 BUG/MEDIUM: spoe: Use a different engine-id per process
SPOE engine-id is the same for all processes when nbproc is more than 1. So, in
async mode, an agent receiving a NOTIFY frame from a process may send the ACK to
another process. It is abviously wrong. A different engine-id must be generated
for each process.

This patch must be backported to 2.0, 1.9 and 1.8.
2019-09-26 16:51:02 +02:00
Christopher Faulet
eec96b5381 BUG/MINOR: mux-h1: Do h2 upgrade only on the first request
When a request is received, if the h2 preface is matched, an implicit upgrade
from h1 to h2 is performed. This must only be done for the first request on a
connection. But a test was missing to unsure it is really the first request.

This patch must be backported to 2.0.
2019-09-26 16:51:02 +02:00
Christopher Faulet
5112a603d9 BUG/MAJOR: mux_h2: Don't consume more payload than received for skipped frames
When a frame is received for a unknown or already closed stream, it must be
skipped. This also happens when a stream error is reported. But we must be sure
to only skip received data. In the loop in h2_process_demux(), when such frames
are handled, all the frame lenght is systematically skipped. If the frame
payload is partially received, it leaves the demux buffer in an undefined
state. Because of this bug, all sort of errors may be observed, like crash or
intermittent freeze.

This patch must be backported to 2.0, 1.9 and 1.8.
2019-09-26 16:51:02 +02:00
Christopher Faulet
ea7a7781a9 BUG/MINOR: mux-h2: Use the dummy error when decoding headers for a closed stream
Since the commit 6884aa3e ("BUG/MAJOR: mux-h2: Handle HEADERS frames received
after a RST_STREAM frame"), HEADERS frames received for an unknown or already
closed stream are decoded. Once decoded, an error is reported for the
stream. But because it is a dummy stream (h2_closed_stream), its state cannot be
changed. So instead, we must return the dummy error stream (h2_error_stream).

This patch must be backported to 2.0 and 1.9.
2019-09-26 16:51:02 +02:00
Christopher Faulet
b2d930ebe6 BUG/MINOR: mux-h2: Fix missing braces because of traces in h2_detach()
Braces was missing aroung a "if" statement in the function h2_detach(), leaving
an unconditional return.

No backport needed.
2019-09-26 16:51:02 +02:00
William Lallemand
13ed9faecd BUG/MINOR: mux-fcgi: silence a gcc warning about null dereference
Silence an impossible warning that gcc reports about a NULL dereference.
2019-09-26 11:07:39 +02:00
Willy Tarreau
4c08f12dd8 BUG/MEDIUM: mux-h2: don't reject valid frames on closed streams
Consecutive to commit 6884aa3eb0 ("BUG/MAJOR: mux-h2: Handle HEADERS frames
received after a RST_STREAM frame") some valid frames on closed streams
(RST_STREAM, PRIORITY, WINDOW_UPDATE) were now rejected. It turns out that
the previous condition was in fact intentional to catch only sensitive
frames, which was indeed a mistake since these ones needed to be decoded
to keep HPACK synchronized. But we must absolutely accept WINDOW_UPDATES
or we risk to stall some transfers. And RST/PRIO definitely are valid.

Let's adjust the condition to reflect that and update the comment to
explain the reason for this unobvious condition.

This must be backported to 2.0 and 1.9 after the commit above is brought
there.
2019-09-26 08:47:15 +02:00
Willy Tarreau
f8340e38bf MINOR: sink: change ring buffer "buf0"'s format to "timed"
This way we now always have the events date which were really missing,
especially when used with traces :

<0>2019-09-26T07:57:25.183845 [00|h2|1|mux_h2.c:3024] receiving H2 HEADERS frame : h2c=0x1ddcad0(B,FRP) h2s=0x1dde9e0(3,HCL)
<0>2019-09-26T07:57:25.183845 [00|h2|4|mux_h2.c:2505] h2c_bck_handle_headers(): entering : h2c=0x1ddcad0(B,FRP) h2s=0x1dde9>
<0>2019-09-26T07:57:25.183846 [00|h2|4|mux_h2.c:4096] h2c_decode_headers(): entering : h2c=0x1ddcad0(B,FRP)
<0>2019-09-26T07:57:25.183847 [00|h2|4|mux_h2.c:4298] h2c_decode_headers(): leaving : h2c=0x1ddcad0(B,FRH)
<0>2019-09-26T07:57:25.183848 [00|h2|0|mux_h2.c:2559] rcvd H2 response : h2c=0x1ddcad0(B,FRH) : [3] H2 RES: HTTP/2.0 200
<0>2019-09-26T07:57:25.183849 [00|h2|4|mux_h2.c:2560] h2c_bck_handle_headers(): leaving : h2c=0x1ddcad0(B,FRH) h2s=0x1dde9e>
<0>2019-09-26T07:57:25.183849 [00|h2|4|mux_h2.c:2866] h2_process_demux(): no more Rx data : h2c=0x1ddcad0(B,FRH)
<0>2019-09-26T07:57:25.183849 [00|h2|4|mux_h2.c:3123] h2_process_demux(): notifying stream before switching SID : h2c=0x1dd>
<0>2019-09-26T07:57:25.183850 [00|h2|4|mux_h2.c:1014] h2s_notify_recv(): in : h2c=0x1ddcad0(B,FRH) h2s=0x1dde9e0(3,HCL)
<0>2019-09-26T07:57:25.183850 [00|h2|4|mux_h2.c:3135] h2_process_demux(): leaving : h2c=0x1ddcad0(B,FRH)
<0>2019-09-26T07:57:25.183851 [00|h2|4|mux_h2.c:3319] h2_send(): entering : h2c=0x1ddcad0(B,FRH)
<0>2019-09-26T07:57:25.183851 [00|h2|4|mux_h2.c:3145] h2_process_mux(): entering : h2c=0x1ddcad0(B,FRH)
<0>2019-09-26T07:57:25.183851 [00|h2|4|mux_h2.c:3234] h2_process_mux(): leaving : h2c=0x1ddcad0(B,FRH)
<0>2019-09-26T07:57:25.183852 [00|h2|4|mux_h2.c:3428] h2_send(): leaving with everything sent : h2c=0x1ddcad0(B,FRH)
<0>2019-09-26T07:57:25.183852 [00|h2|4|mux_h2.c:3319] h2_send(): entering : h2c=0x1ddcad0(B,FRH)

It looks like some format options could finally be separate from the sink,
or maybe enforced. For example we could imagine making the date optional
or its resolution configurable within a same buffer.

Similarly, maybe trace events would like to always emit the date even
on stdout, while traffic logs would prefer not to emit the date in the
ring buffer given that there's already one in the message.
2019-09-26 08:13:38 +02:00
Willy Tarreau
53ba9d9bcf MINOR: sink: finally implement support for SINK_FMT_{TIMED,ISO}
These formats add the date with a resolution of the microsecond before the
message fields.
2019-09-26 08:13:38 +02:00
Willy Tarreau
93acfa2263 MINOR: time: add timeofday_as_iso_us() to return instant time as ISO
We often need ISO time + microseconds in traces and ring buffers, thus
function does this by calling gettimeofday() and keeping a cached value
of the part representing the tv_sec value, and only rewrites the microsecond
part. The cache is per-thread so it's lockless and safe to use as-is.
Some tests already show that it's easy to see 3-4 events in a single
microsecond, thus it's likely that the nanosecond version will have to
be implemented as well. But certain comments on the net suggest that
some parsers are having trouble beyond microsecond, thus for now let's
stick to the microsecond only.
2019-09-26 08:13:38 +02:00
Krisztian Kovacs
710d987cd6 BUG/MEDIUM: namespace: close open namespaces during soft shutdown
When doing a soft shutdown, we won't be making new connections anymore so
there's no point in keeping the namespace file descriptors open anymore.

Keeping these open effectively makes it impossible to properly clean up
namespaces which are no longer used in the new configuration until all
previously opened connections are closed in the old worker process.

This change introduces a cleanup function that is called during soft shutdown
that closes all namespace file descriptors by iterating over the namespace
ebtree.
2019-09-25 23:33:52 +02:00
Willy Tarreau
cec60056e4 BUG/MINOR: mux-h2: do not wake up blocked streams before the mux is ready
In h2_send() we used to scan pending streams and wake them up when it's
possible to send, without considering the connection's state. Thus caused
some excess failed calls to h2_snd_buf() during the preface on backend
connections :

[01|h2|4|mux_h2.c:3562] h2_wake(): entering : h2c=0x7f1430032ed0(B,PRF)
[01|h2|4|mux_h2.c:3475] h2_process(): entering : h2c=0x7f1430032ed0(B,PRF)
[01|h2|4|mux_h2.c:3326] h2_send(): entering : h2c=0x7f1430032ed0(B,PRF)
[01|h2|4|mux_h2.c:3152] h2_process_mux(): entering : h2c=0x7f1430032ed0(B,PRF)
[01|h2|4|mux_h2.c:1508] h2c_bck_send_preface(): entering : h2c=0x7f1430032ed0(B,PRF)
[01|h2|4|mux_h2.c:1379] h2c_send_settings(): entering : h2c=0x7f1430032ed0(B,PRF)
[01|h2|4|mux_h2.c:1464] h2c_send_settings(): leaving : h2c=0x7f1430032ed0(B,PRF)
[01|h2|4|mux_h2.c:1543] h2c_bck_send_preface(): leaving : h2c=0x7f1430032ed0(B,PRF)
[01|h2|4|mux_h2.c:3241] h2_process_mux(): leaving : h2c=0x7f1430032ed0(B,STG)
[01|h2|3|mux_h2.c:3384] sent data : h2c=0x7f1430032ed0(B,STG)
  >>> streams woken up here
[01|h2|4|mux_h2.c:3428] h2_send(): waking up pending stream : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:3435] h2_send(): leaving with everything sent : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:3326] h2_send(): entering : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:3152] h2_process_mux(): entering : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:3241] h2_process_mux(): leaving : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:3435] h2_send(): leaving with everything sent : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:3552] h2_process(): leaving : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:3564] h2_wake(): leaving
  >>> I/O callback was already scheduled and called despite having nothing left to do
[01|h2|4|mux_h2.c:3454] h2_io_cb(): entering : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:3326] h2_send(): entering : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:3152] h2_process_mux(): entering : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:3241] h2_process_mux(): leaving : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:3435] h2_send(): leaving with everything sent : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:3463] h2_io_cb(): leaving
  >>> stream tries and fails again here!
[01|h2|4|mux_h2.c:5568] h2_snd_buf(): entering : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:5587] h2_snd_buf(): connection not ready, leaving : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:5398] h2_subscribe(): entering : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:5408] h2_subscribe(): subscribe(send) : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:5422] h2_subscribe(): leaving : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:5475] h2_rcv_buf(): entering : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:5535] h2_rcv_buf(): leaving : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:5398] h2_subscribe(): entering : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:5400] h2_subscribe(): subscribe(recv) : h2c=0x7f1430032ed0(B,STG)
[01|h2|4|mux_h2.c:5422] h2_subscribe(): leaving : h2c=0x7f1430032ed0(B,STG)

This can happen when sending the preface, the settings, and the settings
ACK. Let's simply condition the wake up on st0 >= FRAME_H as is done at
other places.
2019-09-25 08:34:15 +02:00
Willy Tarreau
73db434f7f MINOR: h2/trace: report the frame type when known
In state match error cases, we don't know what frame type was received
because we don't reach the frame parsers. Let's add the demuxed frame
type and flags in the trace when it's known. For this we make sure to
always reset h2c->dsi when switching back to FRAME_H. Only one location
was missing. The state transitions were not always clear (sometimes
reported before, sometimes after), these were clarified by being
reported only before switching.
2019-09-25 08:34:15 +02:00
Willy Tarreau
2d22144559 MINOR: h2/trace: indicate 'F' or 'B' to locate the side of an h2c in traces
It was difficult in traces showing h2-to-h2 communications to figure the
connection side solely based on the pointer. With this patch we prepend
'F' or 'B' before the state to make this more explicit:

[06|h2|4|mux_h2.c:5487] h2_rcv_buf(): entering : h2c=0x7f6acc026440(F,FRH) h2s=0x7f6acc021720(1,CLO)
[06|h2|4|mux_h2.c:5547] h2_rcv_buf(): leaving : h2c=0x7f6acc026440(F,FRH) h2s=0x7f6acc021720(1,CLO)
[06|h2|4|mux_h2.c:4040] h2_shutw(): entering : h2c=0x7f6acc026440(F,FRH) h2s=0x7f6acc021720(1,CLO)
2019-09-25 07:30:59 +02:00
Olivier Houchard
bba1a263c5 BUG/MEDIUM: tasklets: Make sure we're waking the target thread if it sleeps.
Now that we can wake tasklet for other threads, make sure that if the thread
is sleeping, we wake it up, or the tasklet won't be executed until it's
done sleeping.
That also means that, before going to sleep, and after we put our bit
in sleeping_thread_mask, we have to check that nobody added a tasklet for
us, just checking for global_tasks_mask isn't enough anymore.
2019-09-24 14:58:45 +02:00
Christopher Faulet
c45791aa52 BUG/MINOR: mux-fcgi: Use a literal string as format in app_log()
This avoid any crashes if stderr messages contain format specifiers.

This patch partially fixes the issue #295. No backport needed.
2019-09-24 14:30:49 +02:00
Christopher Faulet
82c798a082 CLEANUP: mux-fcgi: Remove the unused function fcgi_strm_id()
This patch partially fixes the issue #295.
2019-09-24 14:11:01 +02:00
Willy Tarreau
d022e9c98b MINOR: task: introduce a thread-local "sched" variable for local scheduler stuff
The aim is to rassemble all scheduler information related to the current
thread. It simply points to task_per_thread[tid] without having to perform
the operation at each time. We save around 1.2 kB of code on performance
sensitive paths and increase the request rate by almost 1%.
2019-09-24 11:23:30 +02:00
Willy Tarreau
d66d75656e MINOR: task: split the tasklet vs task code in process_runnable_tasks()
There are a number of tests there which are enforced on tasklets while
they will never apply (various handlers, destroyed task or not, arguments,
results, ...). Instead let's have a single TASK_IS_TASKLET() test and call
the tasklet processing function directly, skipping all the rest.

It now appears visible that the only unneeded code is the update to
curr_task that is never used for tasklets, except for opportunistic
reporting in the debug handler, which can only catch si_cs_io_cb,
which in practice doesn't appear in any report so the extra cost
incurred there is pointless.

This change alone removes 700 bytes of code, mostly in
process_runnable_tasks() and increases the performance by about
1%.
2019-09-24 11:23:30 +02:00
Willy Tarreau
4c1e1ad6a8 CLEANUP: task: cache the task_per_thread pointer
In process_runnable_tasks() we perform a lot of dereferences to
task_per_thread[tid] but tid is thread_local and the compiler cannot
know that it doesn't change so this results in making lots of thread
local accesses and array dereferences. By just keeping a copy pointer
of this, we let the compiler optimize the code. Just doing this has
reduced process_runnable_tasks() by 124 bytes in the fast path. Doing
the same in wake_expired_tasks() results in 16 extra bytes saved.
2019-09-24 11:23:30 +02:00
Willy Tarreau
9b48c629f2 CLEANUP: task: remove impossible test
In process_runnable_task(), after the task's process() function returns,
we used to check if the return is not NULL and is not a tasklet, to update
profiling measurements. This is useless since only tasks can return non-null
here. Let's remove this useless test.
2019-09-24 11:23:30 +02:00
Willy Tarreau
0f0393fc0d BUG/MEDIUM: checks: make sure the connection is ready before trying to recv
As identified in issue #278, the backport of commit c594039225 ("BUG/MINOR:
checks: do not uselessly poll for reads before the connection is up")
introduced a regression in 2.0 when default checks are enabled (not
"option tcp-check"), but it did not affect 2.1.

What happens is that in 2.0 and earlier we have the fd cache which makes
a speculative call to the I/O functions after an attempt to connect, and
the __event_srv_chk_r() function was absolutely not designed to be called
while a connection attempt is still pending. Thus what happens is that the
test for success/failure expects the verdict to be final before waking up
the check task, and since the connection is not yet validated, it fails.
It will usually work over the loopback depending on scheduling, which is
why it doesn't fail in reg tests.

In 2.1 after the failed connect(), we subscribe to polling and usually come
back with a validated connection, so the function is not expected to be
called before it completes, except if it happens as a side effect of some
spurious wake calls, which should not have any effect on such a check.

The other check types are not impacted by this issue because they all
check for a minimum data length in the buffer, and wait for more data
until they are satisfied.

This patch fixes the issue by explicitly checking that the connection
is established before trying to read or to give a verdict. This way the
function becomes safe to call regardless of the connection status (even
if it's still totally ugly).

This fix must be backported to 2.0.
2019-09-24 10:59:55 +02:00
Christopher Faulet
e55a5a4171 BUG/MEDIUM: stream-int: Process connection/CS errors during synchronous sends
If an error occurred on the connection or the conn-stream, no syncrhonous send
is performed. If the error was not already processed and there is no more I/O,
it will never be processed and the stream will never be notified of this
error. This may block the stream until a timeout is reached or infinitly if
there is no timeout.

Concretly, this bug can be triggered time to time with h2spec, running the test
"http2/5.1.1/2".

This patch depends on the commit 328ed220a "BUG/MINOR: stream-int: Process
connection/CS errors first in si_cs_send()". Both must be backported to 2.0 and
probably to 1.9. In 1.9, the code is totally different, so this patch would have
to be adapted.
2019-09-24 10:04:19 +02:00
Christopher Faulet
328ed220a8 BUG/MINOR: stream-int: Process connection/CS errors first in si_cs_send()
Errors on the connections or the conn-stream must always be processed in
si_cs_send(), even if the stream-interface is already subscribed on
sending. This patch does not fix any concrete bug per-se. But it is required by
the following one to handle those errors during synchronous sends.

This patch must be backported with the following one to 2.0 and probably to 1.9
too, but with caution because the code is really different.
2019-09-24 10:04:05 +02:00
Willy Tarreau
2bd65a781e OPTIM: listeners: use tasklets for the multi-queue rings
Now that we can wake up a remote thread's tasklet, it's way more
interesting to use a tasklet than a task in the accept queue, as it
will avoid passing through all the scheduler. Just doing this increases
the accept rate by about 4%, overall recovering the slight loss
introduced by the tasklet change. In addition it makes sure that
even a heavily loaded scheduler (e.g. many very fast checks) will
not delay a connection accept.
2019-09-24 06:57:32 +02:00
Krisztián Kovács (kkovacs)
538aa7168f BUG/MEDIUM: namespace: fix fd leak in master-worker mode
When namespaces are used in the configuration, the respective namespace handles
are opened during config parsing and stored in an ebtree for lookup later.

Unfortunately, when the master process re-execs itself these file descriptors
were not closed, effectively leaking the fds and preventing destruction of
namespaces no longer present in the configuration.

This change fixes this issue by opening the namespace file handles as
close-on-exec, making sure that they will be closed during re-exec.
2019-09-23 19:08:39 +02:00
Emmanuel Hocdet
7ceb96be72 BUG/MINOR: build: fix event ports (Solaris)
Patch 6b308985 "MEDIUM: fd: do not use the FD_POLL_* flags in the
pollers anymore" break ev_evports.c build. Restore variable name
to fix it.
2019-09-23 19:08:39 +02:00
Olivier Houchard
ff1e9f39b9 MEDIUM: tasklets: Make the tasklet list a struct mt_list.
Change the tasklet code so that the tasklet list is now a mt_list.
That means that tasklet now do have an associated tid, for the thread it
is expected to run on, and any thread can now call tasklet_wakeup() for
that tasklet.
One can change the associated tid with tasklet_set_tid().
2019-09-23 18:16:08 +02:00
Olivier Houchard
859dc80f94 MEDIUM: list: Separate "locked" list from regular list.
Instead of using the same type for regular linked lists and "autolocked"
linked lists, use a separate type, "struct mt_list", for the autolocked one,
and introduce a set of macros, similar to the LIST_* macros, with the
MT_ prefix.
When we use the same entry for both regular list and autolocked list, as
is done for the "list" field in struct connection, we know have to explicitely
cast it to struct mt_list when using MT_ macros.
2019-09-23 18:16:08 +02:00
Willy Tarreau
6dd4ac890b BUG/MEDIUM: check/threads: make external checks run exclusively on thread 1
See GH issues #141 for all the context. In short, registered signal
handlers are not inherited by other threads during startup, which is
normally not a problem, except that we need that the same thread as
the one doing the fork() cleans up the old process using waitpid()
once its death is reported via SIGCHLD, as happens in external checks.

The only simple solution to this at the moment is to make sure that
external checks are exclusively run on the first thread, the one
which registered the signal handlers on startup. It will be far more
than enough anyway given that external checks must not require to be
load balanced on multiple threads! A more complex solution could be
designed over the long term to let each thread deal with all signals
but it sounds overkill.

This must be backported as far as 1.8.
2019-09-23 18:14:37 +02:00
Christopher Faulet
6884aa3eb0 BUG/MAJOR: mux-h2: Handle HEADERS frames received after a RST_STREAM frame
As stated in the RFC7540#5.1, an endpoint that receives any frame other than
PRIORITY after receiving a RST_STREAM MUST treat that as a stream error of type
STREAM_CLOSED. However, frames carrying compression state must still be
processed before being dropped to keep the HPACK decoder synchronized. This had
to be the purpose of the commit 8d9ac3ed8b ("BUG/MEDIUM: mux-h2: do not abort
HEADERS frame before decoding them"). But, the test on the frame type was
inverted.

This bug is major because desynchronizing the HPACK decoder leads to mixup
indexed headers in messages. From the time an HEADERS frame is received and
ignored for a closed stream, wrong headers may be sent to the following streams.

This patch may fix several bugs reported on github (#116, #290, #292). It must
be backported to 2.0 and 1.9.
2019-09-23 15:28:23 +02:00
Christopher Faulet
0ce57b05de BUG/MINOR: mux-fcgi: Don't compare the filter name in its parsing callback
The function parse_fcgi_flt() is called when the keyword "fcgi-app" is found on
a filter line. We don't need to compare it again in the function.

This patch fixes the issue #284. No backport needed.
2019-09-18 11:20:55 +02:00
Christopher Faulet
d432b3e5c8 CLEANUP: fcgi-app: Remove useless test on fcgi_conf pointer
fcgi_conf was already tested after allocation. No need to test it again.
This patch fixes the isssue #285.
2019-09-18 11:20:55 +02:00
Christopher Faulet
a99db937c5 BUG/MINOR: mux-fcgi: Be sure to have a connection to unsubcribe
When the mux is released, It must own the connection to unsubcribe.
This patch fixes the issue #283. No backport needed.
2019-09-18 11:20:55 +02:00
Christopher Faulet
21d849f52f BUG/MINOR: mux-h2: Be sure to have a connection to unsubcribe
When the mux is released, It must own the connection to unsubcribe.
This patch must be backported to 2.0.
2019-09-18 11:20:55 +02:00
Christopher Faulet
d66700a91c BUG/MINOR: build: Fix compilation of mux_fcgi.c when compiled without SSL
The function ssl_sock_is_ssl is only available when HAProxy is compile with the
SSL support.

This patch fixes the issue #279. No need to backport.
2019-09-17 13:50:20 +02:00
Christopher Faulet
99eff65f4f MEDIUM: mux-fcgi: Add the FCGI multiplexer
This multiplexer is only available on the backend side. It may handle
multiplexed connections if the FCGI application supports it. A FCGI application
must be configured on the backend to be used. If not redefined during the
request processing by the FCGI filter, this mux handles all mandatory
parameters.

There is a limitation on the way the requests are processed. The parameters must
be encoded into a uniq PARAMS record. It means, once encoded, all HTTP headers
and FCGI parameters must small enough to be store in a buffer. Otherwise, an
internal processing error is returned.
2019-09-17 10:18:54 +02:00
Christopher Faulet
78fbb9f991 MEDIUM: fcgi-app: Add FCGI application and filter
The FCGI application handles all the configuration parameters used to format
requests sent to an application. The configuration of an application is grouped
in a dedicated section (fcgi-app <name>) and referenced in a backend to be used
(use-fcgi-app <name>). To be valid, a FCGI application must at least define a
document root. But it is also possible to set the default index, a regex to
split the script name and the path-info from the request URI, parameters to set
or unset...  In addition, this patch also adds a FCGI filter, responsible for
all processing on a stream.
2019-09-17 10:18:54 +02:00
Christopher Faulet
63bbf284a1 MINOR: fcgi: Add code related to FCGI protocol
This code is independant and is only responsible to encode and decode part of
the FCGI protocol.
2019-09-17 10:18:54 +02:00
Christopher Faulet
86d144c74b MINOR: muxes/htx: Ignore pseudo header during message formatting
When an HTX message is formatted to an H1 or H2 message, pseudo-headers (with
header names starting by a colon (':')) are now ignored. In fact, for now, only
H2 messages have such headers, and the H2 mux already skips them when it creates
the HTX message. But in the futur, it may be useful to keep these headers in the
HTX message to help the message analysis or to do some processing during the
HTTP formatting. It would also be a good idea to have scopes for pseudo-headers
(:h1-, :h2-, :fcgi-...) to limit their usage to a specific mux.
2019-09-17 10:18:54 +02:00
Christopher Faulet
cc3124cf44 MINOR: h1-htx: Use the same function to copy message payload in all cases
This function will try to do a zero-copy transfer. Otherwise, it adds a data
block. The same is used for messages with a content-length, chunked messages and
messages with unknown body length.
2019-09-17 10:18:54 +02:00
Christopher Faulet
4f0f88a9d0 MEDIUM: mux-h1/h1-htx: move HTX convertion of H1 messages in dedicated file
To avoid code duplication in the futur mux FCGI, functions parsing H1 messages
and converting them into HTX have been moved in the file h1_htx.c. Some
specific parts remain in the mux H1. But most of the parsing is now generic.
2019-09-17 10:18:54 +02:00
Christopher Faulet
341fac1eb2 MINOR: http: Add function to parse value of the header Status
It will be used by the mux FCGI to get the status a response.
2019-09-17 10:18:54 +02:00
Christopher Faulet
5c6fefc8eb MINOR: log: Provide a function to emit a log for an application
Application is a generic term here. It is a modules which handle its own log
server list, with no dependency on a proxy. Such applications can now call the
function app_log() to log messages, passing a log server list and a tag as
parameters. Internally, the function __send_log() has been adapted accordingly.
2019-09-17 10:18:54 +02:00
Christopher Faulet
a406356255 MINOR: http_fetch: Add sample fetches to get auth method/user/pass
Now, following sample fetches may be used to get information about
authentication:

 * http_auth_type : returns the auth method as supplied in Authorization header
 * http_auth_user : returns the auth user as supplied in Authorization header
 * http_auth_pass : returns the auth pass as supplied in Authorization header

Only Basic authentication is supported.
2019-09-17 10:18:54 +02:00
Christopher Faulet
c16929658f MINOR: config: Support per-proxy and per-server post-check functions callbacks
Most of times, when a keyword is added in proxy section or on the server line,
we need to have a post-parser callback to check the config validity for the
proxy or the server which uses this keyword.

It is possible to register a global post-parser callback. But all these
callbacks need to loop on the proxies and servers to do their job. It is neither
handy nor efficient. Instead, it is now possible to register per-proxy and
per-server post-check callbacks.
2019-09-17 10:18:54 +02:00
Christopher Faulet
3ea5cbe6a4 MINOR: config: Support per-proxy and per-server deinit functions callbacks
Most of times, when any allocation is done during configuration parsing because
of a new keyword in proxy section or on the server line, we must add a call in
the deinit() function to release allocated ressources. It is now possible to
register a post-deinit callback because, at this stage, the proxies and the
servers are already releases.

Now, it is possible to register deinit callbacks per-proxy or per-server. These
callbacks will be called for each proxy and server before releasing them.
2019-09-17 10:18:54 +02:00
Christopher Faulet
e3d2a877fb MINOR: http-ana: Remove err_state field from http_msg
This field is not used anymore. In addition, the state HTTP_MSG_ERROR is now
only used when an error occurred during the body forward.
2019-09-17 10:18:54 +02:00
Christopher Faulet
b9a92f308a MINOR: http-ana: Handle HTX errors first during message analysis
When an error occurred in a mux, most of time, an error is also reported on the
conn-stream, leading to an error (read and/or write) on the channel. When a
parsing or a processing error is reported for the HTX message, it is better to
handle it first.
2019-09-17 10:18:54 +02:00
Christopher Faulet
69b482180c MINOR: mux-h1: Report a processing error during output processing
During output processing, It is unexpected to have a malformed HTX
message. Instead of reporting a parsing error, we now report a processing error.
2019-09-17 10:18:54 +02:00
Christopher Faulet
4e9a83349a BUG/MEDIUM: stick-table: Properly handle "show table" with a data type argument
Since the commit 1b8e68e8 ("MEDIUM: stick-table: Stop handling stick-tables as
proxies."), the target field into the table context of the CLI applet was not
anymore a pointer to a proxy. It was replaced by a pointer to a stktable. But,
some parts of the code was not updated accordingly. the function
table_prepare_data_request() still tries to cast it to a pointer to a proxy. The
result is totally undefined. With a bit of luck, when the "show table" command
is used with a data type, we failed to find a table and the error "Data type not
stored in this table" is returned. But crashes may also be experienced.

This patch fixes the issue #262. It must be backported to 2.0.
2019-09-13 15:46:46 +02:00
Adis Nezirovic
a46b142e88 BUG/MINOR: Missing stat_field_names (since f21d17bb)
Recently Lua code which uses Proxy class (get_stats method) stopped
working ("table index is nil from [C] method 'get_stats'")
It probably affects other codepaths too.

This should be backported do 2.0 and 1.9.
2019-09-13 12:40:50 +02:00
Christopher Faulet
1dbc4676c6 BUG/MINOR: backend: Fix a possible null pointer dereference
In the function connect_server(), when we are not able to reuse a connection and
too many FDs are opened, the variable srv must be defined to kill an idle
connection.

This patch fixes the issue #257. It must be backported to 2.0
2019-09-13 10:08:44 +02:00
Christopher Faulet
361935aa1e BUG/MINOR: acl: Fix memory leaks when an ACL expression is parsed
This only happens during the configuration parsing. First leak is the string
representing the last converter parsed, if any. The second one is on the error
path, when the allocation of the ACL expression failed. In this case, the sample
was not released.

This patch fixes the issue #256. It must be backported to all stable versions.
2019-09-13 10:08:44 +02:00
Christopher Faulet
3e395632bf CLEANUP: mux-h2: Remove unused flag H2_SF_DATA_CHNK
Since the legacy HTTP mode has been removed, this flag is not necessary
anymore. Removing this flag, a test on the HTX message at the end of the
function h2c_decode_headers() has also been removed fixing the github
issue #244.

No backport needed.
2019-09-13 10:08:28 +02:00
Luca Schimweg
8a694b859c MINOR: sample: Add UUID-fetch
Adds the fetch uuid(int). It returns a UUID following the format of
version 4 in the RFC4122 standard.

New feature, but could be backported.
2019-09-13 04:43:33 +02:00
Christopher Faulet
e058f7359f BUG/MINOR: filters: Properly set the HTTP status code on analysis error
When a filter returns an error during the HTTP analysis, an error must be
returned if the status code is not already set. On the request path, an error
400 is returned. On the response path, an error 502 is returned. The status is
considered as unset if its value is not strictly positive.

If needed, this patch may be backported to all versions having filters (as far
as 1.7). Because nobody have never report any bug, the backport to 2.0 is
probably enough.
2019-09-10 10:29:54 +02:00
Christopher Faulet
6338a08c34 MINOR: stats: Add JSON export from the stats page
It is now possible to export stats using the JSON format from the HTTP stats
page. Like for the CSV export, to export stats in JSON, you must add the option
";json" on the stats URL. It is also possible to dump the JSON schema with the
option ";json-schema". Corresponding Links have been added on the HTML page.

This patch fixes the issue #263.
2019-09-10 10:29:54 +02:00
Christopher Faulet
82004145d4 BUG/MINOR: ssl: always check for ssl connection before getting its XPRT context
In several SSL functions, the XPRT context is retrieved before any check on the
connection. In the function ssl_sock_is_ssl(), a test suggests the connection
may be null. So, it is safer to test the ssl connection before retrieving its
XPRT context. It removes any ambiguities and prevents possible null pointer
dereferences.

This patch fixes the issue #265. It must be backported to 2.0.
2019-09-10 10:29:54 +02:00
Christopher Faulet
ad6c2eac28 BUG/MINOR: listener: Fix a possible null pointer dereference
It seems to be possible to have no frontend for a listener. A test was missing
before dereferencing it at the end of the function listener_accept().

This patch fixes the issue #264. It must be backported to 2.0 and 1.9.
2019-09-10 10:29:54 +02:00
David Carlier
6c00eba63b BUILD/MINOR: auth: enabling for osx
macOS supports this but as part of libc.
Little typo fix while here.
2019-09-08 12:20:13 +02:00
Willy Tarreau
f21d17bbe8 MINOR: stats: report the number of idle connections for each server
This adds two extra fields to the stats, one for the current number of idle
connections and one for the configured limit. A tooltip link now appears on
the HTML page to show these values in front of the active connection values.

This should be backported to 2.0 and 1.9 as it's the only way to monitor
the idle connections behaviour.
2019-09-08 09:30:50 +02:00
Willy Tarreau
6b3089856f MEDIUM: fd: do not use the FD_POLL_* flags in the pollers anymore
As mentioned in previous commit, these flags do not map well to
modern poller capabilities. Let's use the FD_EV_*_{R,W} flags instead.
This first patch only performs a 1-to-1 mapping making sure that the
previously reported flags are still reported identically while using
the closest possible semantics in the pollers.

It's worth noting that kqueue will now support improvements such as
returning distinctions between shut and errors on each direction,
though this is not exploited for now.
2019-09-06 19:09:56 +02:00
Willy Tarreau
ccf3f6d1d6 MEDIUM: connection: enable reading only once the connection is confirmed
In order to address the absurd polling sequence described in issue #253,
let's make sure we disable receiving on a connection until it's established.
Previously with bottom-top I/Os, we were almost certain that a connection
was ready when the first I/O was confirmed. Now we can enter various
functions, including process_stream(), which will attempt to read
something, will fail, and will then subscribe. But we don't want them
to try to receive if we know the connection didn't complete. The first
prerequisite for this is to mark the connection as not ready for receiving
until it's validated. But we don't want to mark it as not ready for sending
because we know that attempting I/Os later is extremely likely to work
without polling.

Once the connection is confirmed we re-enable recv readiness. In order
for this event to be taken into account, the call to tcp_connect_probe()
was moved earlier, between the attempt to send() and the attempt to recv().
This way if tcp_connect_probe() enables reading, we have a chance to
immediately fall back to this and read the possibly pending data.

Now the trace looks like the following. It's far from being perfect
but we've already saved one recvfrom() and one epollctl():

 epoll_wait(3, [], 200, 0) = 0
 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 7
 fcntl(7, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
 setsockopt(7, SOL_TCP, TCP_NODELAY, [1], 4) = 0
 connect(7, {sa_family=AF_INET, sin_port=htons(8000), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
 epoll_ctl(3, EPOLL_CTL_ADD, 7, {EPOLLIN|EPOLLOUT|EPOLLRDHUP, {u32=7, u64=7}}) = 0
 epoll_wait(3, [{EPOLLOUT, {u32=7, u64=7}}], 200, 1000) = 1
 connect(7, {sa_family=AF_INET, sin_port=htons(8000), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
 getsockopt(7, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
 sendto(7, "OPTIONS / HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 22
 epoll_ctl(3, EPOLL_CTL_MOD, 7, {EPOLLIN|EPOLLRDHUP, {u32=7, u64=7}}) = 0
 epoll_wait(3, [{EPOLLIN|EPOLLRDHUP, {u32=7, u64=7}}], 200, 1000) = 1
 getsockopt(7, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
 getsockopt(7, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
 recvfrom(7, "HTTP/1.0 200\r\nContent-length: 0\r\nX-req: size=22, time=0 ms\r\nX-rsp: id=dummy, code=200, cache=1, size=0, time=0 ms (0 real)\r\n\r\n", 16384, 0, NULL, NULL) = 126
 close(7)                = 0
2019-09-06 17:50:36 +02:00
Emeric Brun
5762a0db0a BUG/MAJOR: ssl: ssl_sock was not fully initialized.
'ssl_sock' wasn't fully initialized so a new session can inherit some
flags from an old one.

This causes some fetches, related to client's certificate presence or
its verify status and errors, returning erroneous values.

This issue could generate other unexpected behaviors because a new
session could also inherit other flags such as SSL_SOCK_ST_FL_16K_WBFSIZE,
SSL_SOCK_SEND_UNLIMITED, or SSL_SOCK_RECV_HEARTBEAT from an old session.

This must be backported to 2.0 but it's useless for previous.
2019-09-06 17:33:33 +02:00
Willy Tarreau
ed5ac9c786 BUG/MINOR: lb/leastconn: ignore the server weights for empty servers
As discussed in issue #178, the change brought around 1.9-dev11 by commit
1eb6c55808 ("MINOR: lb: make the leastconn algorithm more accurate")
causes some harm in the situation it tried to improve. By always applying
the server's weight even for no connection, we end up always picking the
same servers for the first connections, so under a low load, if servers
only have either 0 or 1 connections, in practice the same servers will
always be picked.

This patch partially restores the original behaviour but still keeping
the spirit of the aforementioned patch. Now what is done is that servers
with no connections will always be picked first, regardless of their
weight, so they will effectively follow round-robin. Only servers with
one connection or more will see an accurate weight applied.

This patch was developed and tested by @malsumis and @jaroslawr who
reported the initial issue. It should be backported to 2.0 and 1.9.
2019-09-06 17:13:44 +02:00
Christopher Faulet
cac5c094d1 BUG/MINOR: mux-h1: Fix a UAF in cfg_h1_headers_case_adjust_postparser()
When an error occurs in the post-parser callback which checks configuration
validity of the option outgoing-headers-case-adjust-file, the error message is
freed too early, before being used.

No backport needed. It fixes the github issue #258.
2019-09-06 08:59:23 +02:00
Willy Tarreau
c594039225 BUG/MINOR: checks: do not uselessly poll for reads before the connection is up
It's pointless to start to perform a recv() call on a connection that is
not yet established. The only purpose used to be to subscribe but that
causes many extra syscalls when we know we can do it later.

This patch only attempts a read if the connection is established or if
there is no write planed, since we want to be certain to be called. And
in wake_srv_chk() we continue to attempt to read if the reader was not
subscribed, so as to perform the first read attempt. In case a first
result is provided, __event_srv_chk_r() will not do anything anyway so
this is totally harmless in this case.

This fix requires that commit "BUG/MINOR: checks: make __event_chk_srv_r()
report success before closing" is applied before, otherwise it will break
some checks (notably SSL) by doing them again after the connection is shut
down. This completes the fixes on the checks described in issue #253 by
roughly cutting the number of syscalls in half. It must be backported to
2.0.
2019-09-06 08:13:15 +02:00
Willy Tarreau
4c1a2b30a3 BUG/MINOR: checks: make __event_chk_srv_r() report success before closing
On a plain TCP check, this function will do nothing except shutting the
connection down and will not even update the status. This prevents it
from being called again, which is the reason why we attempt to do it
once too early. Let's first fix this function to make it report success
on plain TCP checks before closing, as it does for all other ones.

This must be backported to 2.0. It should be safe to backport to older
versions but it doesn't seem it would fix anything there.
2019-09-06 08:13:15 +02:00
Willy Tarreau
cc705a6b61 BUG/MINOR: checks: start sending the request right after connect()
Since the change of I/O direction, we must not wait for an empty connect
callback before sending the request, we must attempt to send it as soon
as possible so that we don't uselessly poll. This is what this patch
does. This reduces the total check duration by a complete poll loop
compared to what is described in issue #253.

This must be backported to 2.0.
2019-09-06 08:13:15 +02:00
Willy Tarreau
5909380c05 BUG/MINOR: checks: stop polling for write when we have nothing left to send
Since the change of I/O direction, we perform the connect() call and
the send() call together from the top. But the send call must at least
disable polling for writes once it does not have anything left to send.

This bug is partially responsible for the waste of resources described
in issue #253.

This must be backported to 2.0.
2019-09-06 08:13:15 +02:00
Willy Tarreau
dbe3060e81 MINOR: fd: make updt_fd_polling() a normal function
It's called from many places, better use a real function than an inline.
2019-09-05 09:31:18 +02:00
Willy Tarreau
5bee3e2f47 MEDIUM: fd: remove the FD_EV_POLLED status bit
Since commit 7ac0e35f2 in 1.9-dev1 ("MAJOR: fd: compute the new fd polling
state out of the fd lock") we've started to update the FD POLLED bit a
bit more aggressively. Lately with the removal of the FD cache, this bit
is always equal to the ACTIVE bit. There's no point continuing to watch
it and update it anymore, all it does is create confusion and complicate
the code. One interesting side effect is that it now becomes visible that
all fd_*_{send,recv}() operations systematically call updt_fd_polling(),
except fd_cant_recv()/fd_cant_send() which never saw it change.
2019-09-05 09:31:18 +02:00
Christopher Faulet
51bb185618 BUG/MINOR: mux-h1: Fix a possible null pointer dereference in h1_subscribe()
This patch fixes the github issue #243. No backport needed.
2019-09-04 10:30:11 +02:00
Christopher Faulet
b066747107 BUG/MEDIUM: cache: Don't cache objects if the size of headers is too big
HTTP responses with headers than impinge upon the reserve must not be
cached. Otherwise, there is no warranty to have enough space to add the header
"Age" when such cached responses are delivered.

This patch must be backported to 2.0 and 1.9. For these versions, the same must
be done for the legacy HTTP mode.
2019-09-04 10:30:11 +02:00
Christopher Faulet
15a4ce870a BUG/MEDIUM: cache: Properly copy headers splitted on several shctx blocks
In the cache, huge HTTP headers will use several shctx blocks. When a response
is returned from the cache, these headers must be properly copied in the
corresponding HTX message by updating the pointer where to copied a header
part.

This patch must be backported to 2.0 and 1.9.
2019-09-04 10:30:11 +02:00
Christopher Faulet
f1ef7f641d BUG/MINOR: mux-h1: Be sure to update the count before adding EOM after trailers
Otherwise, an EOM may be added in a full buffer.

This patch must be backported to 2.0.
2019-09-04 10:30:11 +02:00
Christopher Faulet
6b32192cfb BUG/MINOR: mux-h1: Don't stop anymore input processing when the max is reached
The loop is now stopped only when nothing else is consumed from the input buffer
or if a parsing error is encountered. This will let a chance to detect cases
when we fail to add the EOM.

For instance, when the max is reached after the headers parsing and all the
message is received. In this case, we may have the flag H1S_F_REOS set without
the flag H1S_F_APPEND_EOM and no pending input data, leading to an error because
we think it is an abort.

This patch must be backported to 2.0. This bug does not affect 1.9.
2019-09-04 10:30:11 +02:00
Christopher Faulet
8427d0d6f8 BUG/MINOR: mux-h1: Fix size evaluation of HTX messages after headers parsing
The block size of the start-line was not counted.

This patch must be backported to 2.0.
2019-09-04 10:30:11 +02:00
Christopher Faulet
84f06533e1 BUG/MINOR: h1: Properly reset h1m when parsing is restarted
Otherwise some processing may be performed twice. For instance, if the header
"Content-Length" is parsed on the first pass, when the parsing is restarted, we
skip it because we think another header with the same value was already seen. In
fact, it is currently the only existing bug that can be encountered. But it is
safer to reset all the h1m on restart to avoid any future bugs.

This patch must be backported to 2.0 and 1.9
2019-09-04 10:30:11 +02:00
Christopher Faulet
3499f62b59 BUG/MINOR: http-ana: Reset response flags when 1xx messages are handled
Otherwise, the following final response could inherit of some of these
flags. For instance, because informational responses have no body, the flag
HTTP_MSGF_BODYLESS is set for 1xx messages. If it is not reset, this flag will
be kept for the final response.

One of visible effect of this bug concerns the HTTP compression. When the final
response is preceded by an 1xx message, the compression is not performed. This
was reported in github issue #229.

This patch must be backported to 2.0 and 1.9. Note that the file http_ana.c does
not exist for these branches, the patch must be applied on proto_htx.c instead.
2019-09-04 10:29:55 +02:00
Jerome Magnin
78891c7e71 BUILD: connection: silence gcc warning with extra parentheses
Commit 8a4ffa0a ("MINOR: send-proxy-v2: sends authority TLV according
to TLV received") is missing parentheses around a variable assignment
used as condition in an if statement, and gcc isn't happy about it.
2019-09-02 16:59:32 +02:00
Frédéric Lécaille
9c3a0ceeac BUG/MEDIUM: peers: local peer socket not bound.
This bug came with 015e4d7 commit: "MINOR: stick-tables: Add peers process
binding computing" where the "stick" rules cases were missing when computing
the peer local listener process binding. At parsing time we store in the
stick-table struct ->proxies_list the proxies which refer to this stick-table.
The process binding is computed after having parsed the entire configuration file
with this simple loop in cfgparse.c:

     /* compute the required process bindings for the peers from <stktables_list>
      * for all the stick-tables, the ones coming with "peers" sections included.
      */
     for (t = stktables_list; t; t = t->next) {
             struct proxy *p;

             for (p = t->proxies_list; p; p = p->next_stkt_ref) {
                     if (t->peers.p && t->peers.p->peers_fe) {
                             t->peers.p->peers_fe->bind_proc |= p->bind_proc;
                     }
             }
     }

Note that if this process binding is not correctly initialized, the child forked
by the master-worker stops the peer local listener. Should be also the case
when daemonizing haproxy.

Must be backported to 2.0.
2019-09-02 14:39:38 +02:00
Emmanuel Hocdet
8a4ffa0aab MINOR: send-proxy-v2: sends authority TLV according to TLV received
Since patch "7185b789", the authority TLV in a PROXYv2 header from a
client connection is stored. Authority TLV sends in PROXYv2 should be
taken into account to allow chaining PROXYv2 without droping it.
2019-08-31 12:28:33 +02:00
Willy Tarreau
c046d167e4 MEDIUM: log: add support for logging to a ring buffer
Now by prefixing a log server with "ring@<name>" it's possible to send
the logs to a ring buffer. One nice thing is that it allows multiple
sessions to consult the logs in real time in parallel over the CLI, and
without requiring file system access. At the moment, ring0 is created as
a default sink for tracing purposes and is available. No option is
provided to create new rings though this is trivial to add to the global
section.
2019-08-30 15:24:59 +02:00
Willy Tarreau
f3dc30f6de MINOR: log: add a target type instead of hacking the address family
Instead of detecting an AF_UNSPEC address family for a log server and
to deduce a file descriptor, let's create a target type field and
explicitly mention that the socket is of type FD.
2019-08-30 15:07:25 +02:00
Willy Tarreau
d52a7f8c8d MEDIUM: log: use the new generic fd_write_frag_line() function
When logging to a file descriptor, we'd rather use the unified
fd_write_frag_line() which uses the FD's lock than perform the
writev() ourselves and use a per-server lock, because if several
loggers point to the same output (e.g. stdout) they are still
not locked and their logs may interleave. The function above
instead relies on the fd's lock so this is safer and will even
protect against concurrent accesses from other areas (e.g traces).
The function also deals with the FD's non-blocking mode so we do
not have to keep specific code for this anymore in the logs.
2019-08-30 15:07:25 +02:00
Willy Tarreau
7e9776ad7b MINOR: fd/log/sink: make the non-blocking initialization depend on the initialized bit
Logs and sinks were resorting to dirty hacks to initialize an FD to
non-blocking mode. Now we have a bit for this in the fd tab so we can
do it on the fly on first use of the file descriptor. Previously it was
set per log server by writing value 1 to the port, or during a sink
initialization regardless of the usage of the fd.
2019-08-30 15:07:25 +02:00
Willy Tarreau
76913d3ef4 CLEANUP: fd: remove leftovers of the fdcache
The "cache" entry was still present in the fdtab struct and it was
reported in "show sess". Removing it broke the cache-line alignment
on 64-bit machines which is important for threads, so it was fixed
by adding an attribute(aligned()) when threads are in use. Doing it
only in this case allows 32-bit thread-less platforms to see the
struct fit into 32 bytes.
2019-08-30 15:07:25 +02:00
Willy Tarreau
30362908d8 BUG/MINOR: ring: b_peek_varint() returns a uint64_t, not a size_t
The difference matters when building on 32-bit architectures and a
warning was rightfully emitted.

No backport is needed.
2019-08-30 15:07:25 +02:00
Willy Tarreau
e7bbbca781 BUG/MEDIUM: mux-h2/trace: fix missing braces added with traces
Ilya reported in issue #242 that h2c_handle_priority() was having
unreachable code...  Obviously, I missed the braces around the "if",
leaving an unconditional return.

No backport is needed.
2019-08-30 15:03:58 +02:00
Willy Tarreau
fe1c908744 BUG/MEDIUM: mux-h2/trace: do not dereference h2c->conn after failed idle
In h2_detach(), if session_check_idle_conn() returns <0 we must not
dereference it since it has been freed.

No backport is needed.
2019-08-30 15:00:42 +02:00
Willy Tarreau
1d181e489c MEDIUM: ring: implement a wait mode for watchers
Now it is possible for a reader to subscribe and wait for new events
sent to a ring buffer. When new events are written to a ring buffer,
the applets that are subscribed are woken up to display new events.
For now we only support this with the CLI applet called by "show events"
since the I/O handler is indeed a CLI I/O handler. But it's not
complicated to add other mechanisms to consume events and forward them
to external log servers for example. The wait mode is enabled by adding
"-w" after "show events <sink>". An extra "-n" was added to directly
seek to new events only.
2019-08-30 11:58:58 +02:00
Willy Tarreau
70b1e50feb MINOR: mux-h2/trace: report the connection pointer and state before FRAME_H
Initially we didn't report anything before FRAME_H but at least the
connection's pointer and its state are desirable.
2019-08-30 11:58:58 +02:00
Willy Tarreau
300decc8d9 MINOR: cli: extend the CLI context with a list and two offsets
Some CLI parsers are currently abusing the CLI context types such as
pointers to stuff longs into them by lack of room. But the context is
80 bytes while cli is only 48, thus there's some room left. This patch
adds a list element and two size_t usable as various offsets. The list
element is initialized.
2019-08-30 11:58:58 +02:00
Willy Tarreau
13696ffba2 BUG/MINOR: ring: fix the way watchers are counted
There are two problems with the way we count watchers on a ring:
  - the test for >=255 was accidently kept to 1 used during QA
  - if the producer deletes all data up to the reader's position
    and the reader is called, cannot write, and is called again,
    it will have a zero offset, causing it to initialize itself
    multiple times and each time adding a new refcount.

Let's change this and instead use ~0 as the initial offset as it's
not possible to have it as a valid one. We now store it into the
CLI context's size_t o0 instead of casting it to a void*.

No backport needed.
2019-08-30 11:58:58 +02:00
Willy Tarreau
99282ddb2c MINOR: trace: extend default event names to 12 chars
With "tx_settings" the 10-chars limit was already passed, thus it sounds
reasonable to push this slightly.
2019-08-30 07:39:59 +02:00
Willy Tarreau
8795194f79 CLEANUP: mux-h2/trace: lower-case event names
I wanted to do it before pushing and forgot. It's easier to type lower-
case event names and more consistent with the "none" and "any" keywords.
2019-08-30 07:39:59 +02:00
Willy Tarreau
8fecec2839 CLEANUP: mux-h2/trace: reformat the "received" messages for better alignment
user-level traces are more readable when visually aligned. This is easily
done by writing "rcvd" instead of "received" to align with "sent" :

  $ socat - /tmp/sock1 <<< "show events buf0"
  [00|h2|0|mux_h2.c:2465] rcvd H2 request  : [1] H2 REQ: GET /?s=10k HTTP/2.0
  [00|h2|0|mux_h2.c:4563] sent H2 response : [1] H2 RES: HTTP/1.1 200
2019-08-30 07:39:59 +02:00
Willy Tarreau
c067a3ac8f MINOR: mux-h2/trace: report h2s->id before h2c->dsi for the stream ID
h2c->dsi is only for demuxing, and needed while decoding a new request.
But if we already have a valid stream ID (e.g. response or outgoing
request), we should use it instead. This avoids seeing [0] in front of
the responses at user level.
2019-08-30 07:39:59 +02:00
Willy Tarreau
17104d46be MINOR: mux-h2/trace: always report the h2c/h2s state and flags
There's no limitation to just "state" trace level anymore, we're
expected to always show these internal states at verbosity levels
above "clean".
2019-08-30 07:39:59 +02:00
Willy Tarreau
94f1dcf119 MINOR: mux-h2/trace: only decode the start-line at verbosity other than "minimal"
This is as documented in "trace h2 verbosity", level "minimal" only
features flags and doesn't perform any decoding at all, "simple" does,
just like "clean" which is the default for end uesrs.
2019-08-30 07:39:59 +02:00
Willy Tarreau
f7dd5191cd MINOR: mux-h2/trace: add a new verbosity level "clean"
The "clean" output will be suitable for user and proto-level output
where the internal stuff (state, pointers, etc) is not desired but
just the basic protocol elements.
2019-08-30 07:38:42 +02:00
Willy Tarreau
ab2ec45403 MINOR: mux-h2: add functions to convert an h2c/h2s state to a string
We need this all the time in traces, let's have it now. For the sake
of compact outputs, the strings are all 3-chars long. The "show fd"
output was improved to make use of this.
2019-08-30 07:10:46 +02:00
Willy Tarreau
7838a79bac MEDIUM: mux-h2/trace: add lots of traces all over the code
All functions of the h2 data path were updated to receive one or multiple
TRACE() calls, at least one pair of TRACE_ENTER()/TRACE_LEAVE(), and those
manipulating protocol elements have been improved to report frame types,
special state transitions or detected errors. Even with careful tests, no
performance impact was measured when traces are disabled.

They are not completely exploited yet, the callback function tries to
dump a lot about them, but still doesn't provide buffer dumps, nor does
it indicate the stream or connection error codes.

The first argument is always set to the connection when known. The second
argument is set to the h2s when known, sometimes a 3rd argument is set to
a buffer, generally the rxbuf or htx, and occasionally the 4th argument
points to an integer (number of bytes read/sent, error code).

Retrieving a 10kB object produces roughly 240 lines when at developer
level, 35 lines at data level, 27 at state level, and 10 at proto level
and 2 at user level.

For now the headers are not dumped, but the start line are emitted in
each direction at user level.

The patch is marked medium because it touches lots of places, though
it takes care not to change the execution path.
2019-08-29 18:22:12 +02:00
Willy Tarreau
db3cfff200 MINOR: mux-h2/trace: add the default decoding callback
The new function h2_trace() is called when relevant by the trace subsystem
in order to provide extra information about the trace being produced. It
can for example display the connection pointer, the stream pointer, etc.
It is declared in the trace source as the default callback as we expect
it to be versatile enough to enrich most traces.

In addition, for requests and responses, if we have a buffer and we can
decode it as an HTX buffer, we can extract user-friendly information from
the start line.
2019-08-29 18:19:11 +02:00
Willy Tarreau
12ae212837 MINOR: mux-h2/trace: register a new trace source with its events
For now the traces are not used. Supported events are categorized by
where the activity comes from (h2c, h2s, stream, etc), a direction
(send/recv/wake), and a list of possibilities for each of them (frame
types, errors, shut, ...). This results in ~50 different events that
try to cover a lot of possibilities when it's needed to filter on
something specific. Special events like protocol error are handled.
A few aggregate events like "rx_frame" or "tx_frame" are planed to
cover all frame types at once by being placed all the time with any
of the other ones.

We also state that the first argument is always the connection. This way
the trace subsystem will be able to safely retrieve some useful info, and
we'll still be able to get the h2c from there (conn->ctx) in a pretty
print function. The second argument will always be an h2s, and in order
to propose it for tracking, we add its description. We also define 4
verbosity levels, which seems more than enough.
2019-08-29 17:14:35 +02:00
Willy Tarreau
370a694879 MINOR: trace: change the detail_level to per-source verbosity
The detail level initially based on syslog levels is not used, while
something related is missing, trace verbosity, to indicate whether or
not we want to call the decoding callback and what level of decoding
we want (raw captures etc). Let's change the field to "verbosity" for
this. A verbosity of zero means that the decoding callback is not
called, and all other levels are handled by this callback and are
source-specific. The source is now prompted to list the levels that
are proposed to the user. When the source doesn't define anything,
"quiet" and "default" are available.
2019-08-29 17:11:25 +02:00
Willy Tarreau
052ad360cd MINOR: trace: also report the trace level in the output
It's very convenient to know the trace level in the output, at least to
grep/grep -v on it. The main usage is to filter/filter out the developer
traces at level DEVEL. For this we now add the numeric level (0 to 4) just
after the source name in the brackets. The output now looks like this :

  [00|h2|4|mux_h2.c:3174] h2_send(): entering : h2c=0x27d75a0 st=2
   -, -, | ------------,  --------,  -------------------> message
    |  | |             |          '-> function name
    |  | |             '-> source file location
    |  | '-> trace level (4=dev)
    |  '-> trace source
    '-> thread number
2019-08-29 17:11:25 +02:00
Willy Tarreau
09fb0df6fd MINOR: trace: prepend the function name for developer level traces
Working on adding traces to mux-h2 revealed that the function names are
manually copied a lot in developer traces. The reason is that they are
not preprocessor macros and as such cannot be concatenated. Let's
slightly adjust the trace() function call to take a function name just
after the file:line argument. This argument is only added for the
TRACE_DEVEL and 3 new TRACE_ENTER, TRACE_LEAVE, and TRACE_POINT macros
and left NULL for others. This way the function name is only reported
for traces aimed at the developers. The pretty-print callback was also
extended to benefit from this. This will also significantly shrink the
data segment as the "entering" and "leaving" strings will now be merged.

One technical point worth mentioning is that the function name is *not*
passed as an ist to the inline function because it's not considered as
a builtin constant by the compiler, and would lead to strlen() being
run on it from all call places before calling the inline function. Thus
instead we pass the const char * (that the compiler knows where to find)
and it's the __trace() function that converts it to an ist for internal
consumption and for the pretty-print callback. Doing this avoids losing
5-10% peak performance.
2019-08-29 17:09:13 +02:00
Willy Tarreau
2ea549bc43 MINOR: trace: change the "payload" level to "data" and move it
The "payload" trace level was ambigous because its initial purpose was
to be able to dump received data. But it doesn't make sense to force to
report data transfers just to be able to report state changes. For
example, all snd_buf()/rcv_buf() operations coming from the application
layer should be tagged at this level. So here we move this payload level
above the state transitions and rename it to avoid the ambiguity making
one think it's only about request/response payload. Now it clearly is
about any data transfer and is thus just below the developer level. The
help messages on the CLI and the doc were slightly reworded to help
remove this ambiguity.
2019-08-29 10:46:11 +02:00
Geoff Simmons
7185b789f9 MINOR: connection: add the fc_pp_authority fetch -- authority TLV, from PROXYv2
Save the authority TLV in a PROXYv2 header from the client connection,
if present, and make it available as fc_pp_authority.

The fetch can be used, for example, to set the SNI for a backend TLS
connection.
2019-08-28 17:16:20 +02:00
Willy Tarreau
a9f5b96e02 MINOR: trace: show thread number and source name in the trace
Traces were missing the thread number and the source name, which was
really annoying. Now the thread number is emitted on two digits inside
the square brackets, followed by the source name then the line location,
each delimited with a vertical bar, such as below :

  [00|h2|mux_h2.c:2651] Notifying stream about SID change : h2c=0x7f3284581ae0 st=3 h2s=0x7f3284297f00 id=523 st=4
  [00|h2|mux_h2.c:2708] receiving H2 HEADERS frame : h2c=0x7f3284581ae0 st=3 dsi=525 (st=0)
  [02|h2|mux_h2.c:2194] Received H2 request : h2c=0x7f328d3d1ae0 st=2 : [525] H2 REQ: GET / HTTP/2.0
  [02|h2|mux_h2.c:2561] Expecting H2 frame header : h2c=0x7f328d3d1ae0 st=2
2019-08-28 10:10:50 +02:00
Willy Tarreau
b3f7a72c27 MINOR: trace: extend the source location to 13 chars
With 4-digit line numbers, this allows to emit up to 6 chars of file
name before extension, instead of 3 previously.
2019-08-28 10:10:50 +02:00
Willy Tarreau
3da0026d25 MINOR: trace: support a default callback for the source
It becomes apparent that most traces will use a single trace pretty
print callback, so let's allow the trace source to declare a default
one so that it can be omitted from trace calls, and will be used if
no other one is specified.
2019-08-28 07:06:23 +02:00
Willy Tarreau
8f24023ba0 MINOR: sink: now report the number of dropped events on output
The principle is that when emitting a message, if some dropped events
were logged, we first attempt to report this counter before going
further. This is done under an exclusive lock while all logs are
produced under a shared lock. This ensures that the dropped line is
accurately reported and doesn't accidently arrive after a later
event.
2019-08-27 17:14:19 +02:00
Willy Tarreau
9f830d7408 MINOR: sink: implement "show events" to show supported sinks and dump the rings
The new "show events" CLI keyword lists supported event sinks. When
passed a buffer-type sink it completely dumps it.

no drops at all during attachment even at 8 millon evts/s.
still missing the attachment limit though.
2019-08-27 17:14:19 +02:00
Willy Tarreau
4ed23ca0e7 MINOR: sink: add support for ring buffers
This now provides sink_new_buf() which allocates a ring buffer. One such
ring ("buf0") of 1 MB is created already, and may be used by sink_write().
The sink's creation should probably be moved somewhere else later.
2019-08-27 17:14:19 +02:00
Willy Tarreau
072931cdcb MINOR: ring: add a generic CLI io_handler to dump a ring buffer
The three functions (attach, IO handler, and release) are meant to be
called by any CLI command which requires to dump the contents of a ring
buffer. We do not implement anything generic to dump any ring buffer on
the CLI since it's meant to be used by other functionalities above.
However these functions deal with locking and everything so it's trivial
to embed them in other code.
2019-08-27 17:14:19 +02:00
Willy Tarreau
be97853c2f MINOR: ring: add a ring_write() function
This function tries to write to the ring buffer, possibly removing enough
old messages to make room for the new one. It takes two arrays of fragments
on input to ease the insertion of prefixes by the caller. It atomically
writes the message, possibly truncating it if desired, and returns the
operation's status.
2019-08-27 17:14:19 +02:00
Willy Tarreau
172945fbad MINOR: ring: add a new mechanism for retrieving/storing ring data in buffers
Our circular buffers are well suited for being used as ring buffers for
not-so-structured data. The machanism here consists in making room in a
buffer before inserting a new record which is prefixed by its size, and
looking up next record based on the previous one's offset and size. We
can have up to 255 consumers watching for data (dump in progress, tail)
which guarantee that entrees are not recycled while they're being dumped.
The complete representation is described in the header file. For now only
ring_new(), ring_resize() and ring_free() are created.
2019-08-27 17:14:19 +02:00
Willy Tarreau
a1426de5aa MINOR: sink: now call the generic fd write function
Let's not mess up with fd-specific code, locking nor message formating
here, and use the new generic function instead. This substantially
simplifies the sink_write() code and makes it more agnostic to the
output representation and storage.
2019-08-27 17:14:19 +02:00
Willy Tarreau
931d8b79a8 MINOR: fd: add fd_write_frag_line() to send a fragmented line to an fd
Currently both logs and event sinks may use a file descriptor to
atomically emit some output contents. The two may use the same FD though
nothing is done to make sure they use the same lock. Also there is quite
some redundancy between the two. Better make a specific function to send
a fragmented message to a file descriptor which will take care of the
locking via the fd's lock. The function is also able to truncate a
message and to enforce addition of a trailing LF when building the
output message.
2019-08-27 17:14:19 +02:00
Willy Tarreau
4d589e719b MINOR: tools: add a function varint_bytes() to report the size of a varint
It will sometimes be useful to encode varints to know the output size in
advance. Two versions are provided, one inline using a switch/case construct
which will be trivial for use with constants (and will be very fast albeit
huge) and one function iterating on the number which is 5 times smaller,
for use with variables.
2019-08-27 17:14:19 +02:00
Willy Tarreau
799e9ed62b MINOR: sink: set the fd-type sinks to non-blocking
Just like we used to do for the logs, we must disable blocking on FD
output except if it's a terminal.
2019-08-27 17:14:18 +02:00
Nenad Merdanovic
177adc9e57 MINOR: backend: Add srv_queue converter
The converter can be useful to look up a server queue from a dynamic value.

It takes an input value of type string, either a server name or
<backend>/<server> format and returns the number of queued sessions
on that server. Can be used in places where we want to look up
queued sessions from a dynamic name, like a cookie value (e.g.
req.cook(SRVID),srv_queue) and then make a decision to break
persistence or direct a request elsewhere.

Signed-off-by: Nenad Merdanovic <nmerdan@haproxy.com>
2019-08-27 04:32:06 +02:00
Jerome Magnin
2dd26ca9ff BUG/MEDIUM: url32 does not take the path part into account in the returned hash.
The url32 sample fetch does not take the path part of the URL into
account. This is because in smp_fetch_url32() we erroneously modify
path.len and path.ptr before testing their value and building the
path based part of the hash.

This fixes issue #235

This must be backported as far as 1.9, when HTX was introduced.
2019-08-26 13:28:13 +02:00
Willy Tarreau
6ee9f8df3b BUG/MEDIUM: listener/threads: fix an AB/BA locking issue in delete_listener()
The delete_listener() function takes the listener's lock before taking
the proto_lock, which is contrary to what other functions do, possibly
causing an AB/BA deadlock. In practice the two only places where both
are taken are during protocol_enable_all() and delete_listener(), the
former being used during startup and the latter during stop. In practice
during reload floods, it is technically possible for a thread to be
initializing the listeners while another one is stopping. While this
is too hard to trigger on 2.0 and above due to the synchronization of
all threads during startup, it's reasonably easy to do in 1.9 by having
hundreds of listeners, starting 64 threads and flooding them with reloads
like this :

   $ while usleep 50000; do killall -USR2 haproxy; done

Usually in less than a minute, all threads will be deadlocked. The fix
consists in always taking the proto_lock before the listener lock. It
seems to be the only place where these two locks were reversed. This
fix needs to be backported to 2.0, 1.9, and 1.8.
2019-08-26 11:07:09 +02:00
Willy Tarreau
e0d86e2c1c BUG/MINOR: mworker: disable SIGPROF on re-exec
If haproxy is built with profiling enabled with -pg, it is possible to
see the master quit during a reload while it's re-executing itself with
error code 155 (signal 27) saying "Profile timer expired)". This happens
if the SIGPROF signal is delivered during the execve() call while the
handler was already unregistered. The issue itself is not directly inside
haproxy but it's easy to address. This patch disables this signal before
calling execvp() during a master reload. A simple test for this consists
in running this little script with haproxy started in master-worker mode :

     $ while usleep 50000; do killall -USR2 haproxy; done

This fix should be backported to all versions using the master-worker
model.
2019-08-26 10:44:48 +02:00
Willy Tarreau
0bb5a5c4b5 BUG/MEDIUM: mux-h1: do not report errors on transfers ending on buffer full
If a receipt ends with the HTX buffer full and everything is completed except
appending the HTX EOM block, we end up detecting an error because the H1
parser did not switch to H1_MSG_DONE yet while all conditions for an end of
stream and end of buffer are met. This can be detected by retrieving 31532
or 31533 chunk-encoded bytes over H1 and seeing haproxy log "SD--" at the
end of a successful transfer.

Ideally the EOM part should be totally independent on the H1 message state
since the block was really parsed and finished. So we should switch to a
last state requiring to send only EOM. However this needs a few risky
changes. This patch aims for simplicity and backport safety, thus it only
adds a flag to the H1 stream indicating that an EOM is still needed, and
excludes this condition from the ones used to detect end of processing. A
cleaner approach needs to be studied, either by adding a state before DONE
or by setting DONE once the various blocks are parsed and before trying to
send EOM.

This fix must be backported to 2.0. The issue does not seem to affect 1.9
though it is not yet known why, probably that it is related to the different
encoding of trailers which always leaves a bit of room to let EOM be stored.
2019-08-23 09:37:30 +02:00
Willy Tarreau
347f464d4e BUG/MEDIUM: mux-h1: do not truncate trailing 0CRLF on buffer boundary
The H1 message parser calls the various message block parsers with an
offset indicating where in the buffer to start from, and only consumes
the data at the end of the parsing. The headers and trailers parsers
have a condition detecting if a headers or trailers block is too large
to fit into the buffer. This is detected by an incomplete block while
the buffer is full. Unfortunately it doesn't take into account the fact
that the block may be parsed after other blocks that are still present
in the buffer, resulting in aborting some transfers early as reported
in issue #231. This typically happens if a trailers block is incomplete
at the end of a buffer full of data, which typically happens with data
sizes multiple of the buffer size minus less than the trailers block
size. It also happens with the CRLF that follows the 0-sized chunk of
any transfer-encoded contents is itself on such a boundary since this
CRLF is technically part of the trailers block. This can be reproduced
by asking a server to retrieve exactly 31532 or 31533 bytes of static
data using chunked encoding with curl, which reports:

   transfer closed with outstanding read data remaining

This issue was revealed in 2.0 and does not affect 1.9 because in 1.9
the trailers block was processed at once as part of the data block
processing, and would simply give up and wait for the rest of the data
to arrive.

It's interesting to note that the headers block parsing is also affected
by this issue but in practice it has a much more limited impact since a
headers block is normally only parsed at the beginning of a buffer. The
only case where it seems to matter is when dealing with a response buffer
full of 100-continue header blocks followed by a regular header block,
which will then be rejected for the same reason.

This fix must be backported to 2.0 and partially to 1.9 (the headers
block part).
2019-08-23 08:11:36 +02:00
Willy Tarreau
d8b99edeed MINOR: trace: retrieve useful pointers and enforce lock-on
Now we try to find frontend, listener, backend, server, connection,
session, stream, from the presented argument of type connection,
stream or session. Various combinations and bounces allow to
retrieve most of them almost all the time. The extraction is
performed early so that we'll be able to apply filters later.

The lock-on is set if it was not there while the trace is running and
a valid pointer is available. If it was already set and doesn't match,
no trace is produced.
2019-08-22 20:21:00 +02:00
Willy Tarreau
60e4c9f8db MINOR: trace: parse the "lock" argument to trace
When no criterion is provided, it carefully enumerates all available
ones, including those provided by the source itself. Otherwise it sets
the new criterion and resets the lockon pointer.
2019-08-22 20:21:00 +02:00
Willy Tarreau
beadb5c823 MINOR: trace: make sure to always stop the locking when stopping or pausing
When we stop or pause a trace (either on a matching event or by hand),
we must also stop the lock-on feature so that we don't follow any
further activity on this pointer even if it is recycled. For now this
is not exploited.
2019-08-22 20:21:00 +02:00
Willy Tarreau
bfd14fc6eb MINOR: trace: implement a call to a decode function
The trace() call will support an optional decoding callback and 4
arguments that this function is supposed to know how to use to provide
extra information. The output remains unchanged when the function is
NULL. Otherwise, the message is pre-filled into the thread-local
trace_buf, and the function is called with all arguments so that it
completes the buffer in a readable form depending on the expected
level of detail.
2019-08-22 20:21:00 +02:00
Willy Tarreau
5da408818b MINOR: trace: make trace() now also take a level in argument
This new "level" argument will allow the trace sources to label the
traces for different purposes, and filter out some of them if they
are not relevant to the current target. Right now we have 5 different
levels:
  - USER : the least verbose one, only a few functional information
  - PAYLOAD: like user but also displays some payload-related information
  - PROTO: focuses on the protocol's framing
  - STATE: also indicate state internal transitions or non-transitions
  - DEVELOPER: adds extra info about branches taken in the code (break
    points, return points)
2019-08-22 20:21:00 +02:00
Willy Tarreau
419bd49f0b MINOR: trace: add the file name and line number in the prefix
We now pass an extra argument "where" to the trace() call, which
is supposed to be an ist made of the concatenation of the filename
and the line number. We only keep the last 10 chars from this string
since the end of file names is most often easy to recognize. This
gives developers useful information at very low cost.
2019-08-22 20:21:00 +02:00
Willy Tarreau
4c2ae48375 MINOR: trace: implement a very basic trace() function
For now it remains quite basic. It performs a few state checks, calls
the source's sink if defined, and performs the transitions between
RUNNING, STOPPED and WAITING when the configured events match.
2019-08-22 20:21:00 +02:00
Willy Tarreau
85b157570b MINOR: trace/cli: add "show trace" to report trace state and statistics
The new "show trace" CLI command lists available trace sources and
indicates their status, their sink, and number of dropped packets.
When "show trace <source>" is used, the list of known events is
also listed with their status per action (report/start/stop/pause).
2019-08-22 20:21:00 +02:00
Willy Tarreau
aaaf411406 MINOR: trace/cli: parse the "level" argument to configure the trace verbosity
The "level" keyword allows to indicate the expected level of verbosity
in the traces, among "user" (least verbose, just synthetic info) to
"developer" (very detailed, including function entry/leaving). It's only
displayed and set but not used yet.
2019-08-22 20:21:00 +02:00
Willy Tarreau
864e880f6c MINOR: trace/cli: register the "trace" CLI keyword to list the sources
For now it lists the sources if one is not provided, and checks
for the source's existence. It lists the events if not provided,
checks for their existence if provided, and adjusts reported
events/start/stop/pause events, and performs state transitions.
It lists sinks and adjusts them as well. Filters, lock, and
level are not implemented yet.
2019-08-22 20:21:00 +02:00
Willy Tarreau
88ebd4050e MINOR: trace: add allocation of buffer-sized trace buffers
This will be needed so that we can implement protocol decoders which will
have to emit their contents into such a buffer.
2019-08-22 20:21:00 +02:00
Willy Tarreau
4151c753fc MINOR: trace: start to create a new trace subsystem
The principle of this subsystem will be to support taking live traces
at various places in the code with conditional triggers, filters, and
ability to lock on some elements. The traces will support typed events
and will be sent into sinks made of ring buffers, file descriptors or
remote servers.
2019-08-22 20:21:00 +02:00
Willy Tarreau
973e662fe8 MINOR: sink: add a support for file descriptors
This is the most basic type of sink. It pre-registers "stdout" and
"stderr", and is able to use writev() on them. The writev() operation
is locked to avoid mixing outputs. It's likely that the registration
should move somewhere else to take into account the fact that stdout
and stderr are still opened or are closed.
2019-08-22 20:21:00 +02:00
Willy Tarreau
67b5a161b4 MINOR: sink: create definitions a minimal code for event sinks
The principle will be to be able to dispatch events to various destinations
called "sinks". This is already done in part in logs where log servers can
be either a UDP socket or a file descriptor. This will be needed with the
new trace subsystem where we may also want to add ring buffers. And it turns
out that all such destinations make sense at all places. Logs may need to be
sent to a TCP server via a ring buffer, or consulted from the CLI. Trace
events may need to be sent to stdout/stderr as well as to remote log servers.

This patch creates a new structure "sink" aiming at addressing these similar
needs. The goal is to merge together what is common to all of them, such as
the output format, the dropped events count, etc, and also keep separately
the target identification (network address, file descriptor). Provisions
were made to have a "waiter" on the sink. For a TCP log server it will be
the task to wake up after writing to the log buffer. For a ring buffer, it
could be the list of watchers on the CLI running a "tail" operation and
waiting for new events. A lock was also placed in the struct since many
operations will require some locking, including the FD ones. The output
formats covers those in use by logs and two extra ones prepending the ISO
time in front of the message (convenient for stdio/buffer).

For now only the generic infrastructure is present, no type-specific
output is implemented. There's the sink_write() function which prepares
and formats a message to be sent, trying hard to avoid copies and only
using pointer manipulation, where the type-specific code just has to be
added. Dropped messages are already counted (for now 100% drop). The
message is put into an iovec array as it will be trivial to use with
file descriptors and sockets.
2019-08-22 20:21:00 +02:00
Willy Tarreau
9eebd8a978 REORG: trace: rename trace.c to calltrace.c and mention it's not thread-safe
The function call tracing code is a quite old and was never ported to
support threads. It's not even sure whether it still works well, but
at least its presence creates confusion for future work so let's rename
it to calltrace.c and add a comment about its lack of thread-safety.
2019-08-22 20:21:00 +02:00
Olivier Houchard
02bac85bee BUG/MEDIUM: h1: Always try to receive more in h1_rcv_buf().
In h1_rcv_buf(), wake the h1c tasklet as long as we're not done reading the
request/response, and the h1c is not already subscribed for receiving. Now
that we no longer subscribe in h1_recv() if we managed to read data, we
rely on h1_rcv_buf() calling us again, but h1_process_input() may have
returned 0 if we only received part of the request, so we have to wake
the tasklet to be sure to get more data again.
2019-08-22 18:35:42 +02:00
Willy Tarreau
78a7cb648c MEDIUM: debug: make the thread dump code show Lua backtraces
When we dump a thread's state (show thread, panic) we don't know if
anything is happening in Lua, which can be problematic especially when
calling external functions. With this patch, the thread dump code can
now detect if we're running in a global Lua task (hlua_process_task),
or in a TCP or HTTP Lua service (task_run_applet and applet.fct ==
hlua_applet_tcp_fct or http_applet_http_fct), or a fetch/converter
from an analyser (s->hlua != NULL). In such situations, it's able to
append a formatted Lua backtrace of the Lua execution path with
function names, file names and line numbers.

Note that a shorter alternative could be to call "luaL_where(hlua->T,0)"
which only prints the current location, but it's not necessarily sufficient
for complex code.
2019-08-21 14:32:09 +02:00
Willy Tarreau
60409db0b1 MINOR: lua: export applet and task handlers
The current functions are seen outside from the debugging code and are
convenient to export so that we can improve the thread dump output :

  void hlua_applet_tcp_fct(struct appctx *ctx);
  void hlua_applet_http_fct(struct appctx *ctx);
  struct task *hlua_process_task(struct task *task, void *context, unsigned short state);

Of course they are only available when USE_LUA is defined.
2019-08-21 14:32:09 +02:00
Willy Tarreau
a2c9911ace MINOR: tools: add append_prefixed_str()
This is somewhat related to indent_msg() except that this one places a
known prefix at the beginning of each line, allows to replace the EOL
character, and not to insert a prefix on the first line if not desired.
It works with a normal output buffer/chunk so it doesn't need to allocate
anything nor to modify the input string. It is suitable for use in multi-
line backtraces.
2019-08-21 14:32:09 +02:00
Willy Tarreau
a512b02f67 MINOR: debug: indicate the applet name when the task is task_run_applet()
This allows to figure what applet is currently being executed (and likely
hung).
2019-08-21 14:32:09 +02:00
Olivier Houchard
ea32b0fa50 BUG/MEDIUM: mux_pt: Don't call unsubscribe if we did not subscribe.
In mux_pt_attach(), don't inconditionally call unsubscribe, and only do so
if we were subscribed. The idea was that at this point we would always be
subscribed, as for the mux_pt attach would only be called after at least one
request, after which the mux_pt would have subscribed, but this is wrong.
We can also be called if for some reason the connection failed before the
xprt was created. And with no xprt, attempting to call unsubscribe will
probably lead to a crash.

This should be backported to 2.0.
2019-08-16 16:11:56 +02:00
Christopher Faulet
bd9e842866 BUG/MINOR: stats: Wait the body before processing POST requests
The stats applet waits to have a full body to process POST requests. Because
when it is waiting for the end of a request it does not produce anything, the
applet may be blocked. The client side is blocked because the stats applet does
not consume anything and the applet is waiting because all the body is not
received. Registering the analyzer AN_REQ_HTTP_BODY when a POST request is sent
for the stats applet solves the issue.

This patch must be backported to 2.0.
2019-08-15 22:26:50 +02:00
Christopher Faulet
81921b1371 BUG/MEDIUM: lua: Fix test on the direction to set the channel exp timeout
This bug was introduced by the commit bfab2ddd ("MINOR: hlua: Add a flag on the
lua txn to know in which context it can be used"). The wrong test was done. So
the timeout was always set on the response channel. It may lead to an infinite
loop.

This patch must be backported everywhere the commit bfab2ddd is. For now, at
least to 2.0, 1.9 and 1.8.
2019-08-14 23:29:18 +02:00
Lukas Tribus
579e3e3dd5 BUG/MINOR: lua: fix setting netfilter mark
In the REORG of commit 1a18b5414 ("REORG: connection: centralize the
conn_set_{tos,mark,quickack} functions") a bug was introduced by
calling conn_set_tos instead of conn_set_mark.

This was reported in issue #212

This should be backported to 1.9 and 2.0.
2019-08-12 07:41:31 +02:00
Olivier Houchard
59dd06d659 BUG/MEDIUM: proxy: Don't use cs_destroy() when freeing the conn_stream.
When we upgrade the mux from TCP to H2/HTX, don't use cs_destroy() to free
the conn_stream, use cs_free() instead. Using cs_destroy() would call the
mux detach method, and at that point of time the mux would be the H2 mux,
which knows nothing about that conn_stream, so bad things would happen.
This should eventually make upgrade from TCP to H2/HTX work, and fix
the github issue #196.

This should be backported to 2.0.
2019-08-09 18:01:15 +02:00
Olivier Houchard
71b20c26be BUG/MEDIUM: proxy: Don't forget the SF_HTX flag when upgrading TCP=>H1+HTX.
In stream_end_backend(), if we're upgrading from TCP to H1/HTX, as we don't
destroy the stream, we have to add the SF_HTX flag on the stream, or bad
things will happen.
This was broken when attempting to fix github issue #196.

This should be backported to 2.0.
2019-08-09 17:50:05 +02:00
Willy Tarreau
9d00869323 CLEANUP: cli: replace all occurrences of manual handling of return messages
There were 221 places where a status message or an error message were built
to be returned on the CLI. All of them were replaced to use cli_err(),
cli_msg(), cli_dynerr() or cli_dynmsg() depending on what was expected.
This removed a lot of duplicated code because most of the times, 4 lines
are replaced by a single, safer one.
2019-08-09 11:26:10 +02:00
Willy Tarreau
d50c7feaa1 MINOR: cli: add two new states to print messages on the CLI
Right now we used to have extremely inconsistent states to report output,
one is CLI_ST_PRINT which prints constant message cli->msg with the
assigned severity, and CLI_ST_PRINT_FREE which prints dynamically
allocated cli->err with severity LOG_ERR, and nothing in between,
eventhough it's useful to be able to report dynamically allocated
messages as well as constant error messages.

This patch adds two extra states, which are not particularly well named
given the constraints imposed by existing ones. One is CLI_ST_PRINT_ERR
which prints a constant error message. The other one is CLI_ST_PRINT_DYN
which prints a dynamically allocated message. By doing so we maintain
the compatibility with current code.

It is important to keep in mind that we cannot pre-initialize pointers
and automatically detect what message type it is based on the assigned
fields, because the CLI's context is in a union shared with all other
users, thus unused fields contain anything upon return. This is why we
have no choice but using 4 states. Keeping the two fields <msg> and
<err> remains useful because one is const and not the other one, and
this catches may copy-paste mistakes. It's just that <err> is pretty
confusing here, it should be renamed.
2019-08-09 10:11:38 +02:00
Willy Tarreau
e0d0b4089d CLEANUP: buffer: replace b_drop() with b_free()
Since last commit there's no point anymore in having two variants of the
same function, let's switch to b_free() only. __b_drop() was renamed to
__b_free() for obvious consistency reasons.
2019-08-08 08:07:45 +02:00
Emmanuel Hocdet
c9858010c2 MINOR: ssl: ssl_fc_has_early should work for BoringSSL
CO_FL_EARLY_SSL_HS/CO_FL_EARLY_DATA are removed for BoringSSL. Early
data can be checked via BoringSSL API and ssl_fc_has_early can used it.

This should be backported to all versions till 1.8.
2019-08-07 18:44:49 +02:00
Emmanuel Hocdet
f967c31e75 BUG/MINOR: ssl: fix 0-RTT for BoringSSL
Since BoringSSL commit 777a2391 "Hold off flushing NewSessionTicket until write.",
0-RTT doesn't work. It appears that half-RTT data (response from 0-RTT) never
worked before the BoringSSL fix. For HAProxy the regression come from 010941f8
"BUG/MEDIUM: ssl: Use the early_data API the right way.": the problem is link to
the logic of CO_FL_EARLY_SSL_HS used for OpenSSL. With BoringSSL, handshake is
done before reading early data, 0-RTT data and half-RTT data are processed as
normal data: CO_FL_EARLY_SSL_HS/CO_FL_EARLY_DATA is not needed, simply remove
it.

This should be backported to all versions till 1.8.
2019-08-07 18:44:48 +02:00
Baptiste Assmann
1263540fe8 MINOR: cache: allow caching of OPTIONS request
Allow HAProxy to cache responses to OPTIONS HTTP requests.
This is useful in the use case of "Cross-Origin Resource Sharing" (cors)
to cache CORS responses from API servers.

Since HAProxy does not support Vary header for now, this would be only
useful for "access-control-allow-origin: *" use case.
2019-08-07 15:13:38 +02:00
Baptiste Assmann
db92a836f4 MINOR: cache: add method to cache hash
Current HTTP cache hash contains only the Host header and the url path.
That said, request method should also be added to the mix to support
caching other request methods on the same URL. IE GET and OPTIONS.
2019-08-07 15:13:38 +02:00
Willy Tarreau
6386481cbb CLEANUP: mux-h2: move the demuxed frame check code in its own function
The frame check code in the demuxer was moved to its own function to
keep the demux function clean enough. This also simplifies the test
case as we can now simply call this function once in H2_CS_FRAME_P
state.
2019-08-07 14:25:20 +02:00
Frédéric Lécaille
be36793d1d BUG/MEDIUM: stick-table: Wrong stick-table backends parsing.
When parsing references to stick-tables declared as backends, they are added to
a list of proxies (they are proxies!) which refer to this stick-tables.
Before this patch we added them to these list without checking they were already
present, making the silly hypothesis the actions/sample were checked/resolved in the same
order the proxies are parsed.

This patch implement a simple inline function to in_proxies_list() to test
the presence of a proxy in a list of proxies. We use this function when resolving
/checking samples/actions.

This bug was introduced by 015e4d7 commit.

Must be backported to 2.0.
2019-08-07 10:32:31 +02:00
Willy Tarreau
5488a62bfb BUG/MEDIUM: checks: make sure to close nicely when we're the last to speak
In SMTP, MySQL and PgSQL checks, we're supposed to finish with a message
to politely quit the server, otherwise some of them will log some errors.
This is the case with Postfix as reported in GH issue #187. Since commit
fe4abe6 ("BUG/MEDIUM: connections: Don't call shutdown() if we want to
disable linger.") we are a bit more aggressive on outgoing connection
closure and checks were not prepared for this.

This patch makes the 3 checks above disable the linger_risk for these
checks so that we close cleanly, with the side effect that it will leave
some TIME_WAIT connections behind (hence why it should not be generalized
to all checks). It's worth noting that in issue #187 it's mentioned that
this patch doesn't seem to be sufficient for Postfix, however based only
on local network activity this looks OK, so maybe this will need to be
improved later.

Given that the patch above was backported to 2.0 and 1.9, this one should
as well.
2019-08-06 16:35:55 +02:00
Willy Tarreau
30d05f3557 BUG/MINOR: mux-h2: always reset rcvd_s when switching to a new frame
In Patrick's trace it was visible that after a stream had been missed,
the next stream would receive a WINDOW_UPDATE with the first one's
credit added to its own. This makes sense because in case of error
h2c->rcvd_s is not reset. Given that this counter is per frame, better
reset it when starting to parse a new frame, it's easier and safer.

This must be backported as far as 1.8.
2019-08-06 15:49:51 +02:00
Willy Tarreau
e74679a9c6 BUG/MINOR: mux-h2: always send stream window update before connection's
In h2_process_mux() if we have some room and an attempt to send a window
update for the connection was pending, it's done first. But it's not done
for the stream, which will have for effect of postponing this attempt
till next pass into h2_process_demux(), at the risk of seeing the send
buffer full again. Let's always try to send both pending frames as soon
as possible.

This should be backported as far as 1.8.
2019-08-06 15:39:32 +02:00
Willy Tarreau
9fd5aa8ada BUG/MEDIUM: mux-h2: do not recheck a frame type after a state transition
Patrick Hemmer reported a rare case where the H2 mux emits spurious
RST_STREAM(STREAM_CLOSED) that are triggered by the send path and do
not even appear to be associated with a previous incoming frame, while
the send path never emits such a thing.

The problem is particularly complex (hence its rarity). What happens is
that when data are uploaded (POST) we must refill the sending stream's
window by sending a WINDOW_UPDATE message (and we must refill the
connection's too). But in a highly bidirectional traffic, it is possible
that the mux's buffer will be full and that there is no more room to build
this WINDOW_UPDATE frame. In this case the demux parser switches to the
H2_CS_FRAME_A state, noting that an "acknowledgement" is needed for the
current frame, and it doesn't change the current stream nor frame type.
But the stream's state was possibly updated (typically OPEN->HREM when
a DATA frame carried the ES flag).

Later the data can leave the buffer, wake up h2_io_cb(), which calls
h2_send() to send pending data, itself calling h2_process_mux() which
detects that there are unacked data in the connection's window so it
emits a WINDOW_UPDATE for the connection and resets the counter. so it
emits a WINDOW_UPDATE for the connection and resets the counter. Then
h2_process() calls h2_process_demux() which continues the processing
based on the current frame type and the current state H2_CS_FRAME_A.
Unfortunately the protocol compliance checks matching the frame type
against the current state are still present. These tests are designed
for new frames only, not for those in progress, but they are not
limited by frame types. Thus the current DATA frame is checked again
against the current stream state that is now HREM, and fails the test
with a STREAM_CLOSED error.

The quick and backportable solution consists in adding the test for
this ACK and bypass all these checks that were already validated prior
to the state transition. A better long-term solution would consist in
having a new state between H and P indicating the frame is new and
needs to be checked ("N" for new?) and apply the protocol tests only
in this state. In addition everywhere we decide to send a window
update, we should send a stream WU first if there are unacked data
for the current stream. Last, rcvd_s should always be reset when
transitioning to FRAME_H (and a BUGON for this in dev would help).

The bug will be way harder to trigger on 2.0 than on 1.8/1.9 because
we have a ring buffer for the connection so the buffer full situations
are extremely rare.

This fix must be backpored to all versions having H2 (as far as 1.8).

Special thanks to Patrick for providing exploitable traces.
2019-08-06 15:35:20 +02:00
Willy Tarreau
cfba9d6eaa BUG/MINOR: mux-h2: do not send REFUSED_STREAM on aborted uploads
If the server decides to close early, we don't want to send a
REFUSED_STREAM error but a CANCEL, so that the client doesn't want
to retry. The test in h2_do_shutw() was wrong for this as it would
handle the HLOC case like the case where nothing had been sent for
this stream, which is wrong. Now h2_do_shutw() does nothing in this
case and lets h2_do_shutr() decide.

Note that this partially undoes f983d00a1 ("BUG/MINOR: mux-h2: make
the do_shut{r,w} functions more robust against retries").

This must be backported to 2.0. The patch above was not backported to
1.9 for being too risky there, but if it eventually gets to it, this
one will be needed as well.
2019-08-06 10:32:02 +02:00
Willy Tarreau
082c45769b BUG/MINOR: mux-h2: use CANCEL, not STREAM_CLOSED in h2c_frt_handle_data()
There is a test on the existence of the conn_stream when receiving data,
to be sure to have somewhere to deliver it. Right now it responds with
STREAM_CLOSED, which is not correct since from an H2 point of view the
stream is not closed and a peer could be upset to see this. After some
analysis, it is important to keep this test to be sure not to fill the
rxbuf then stall the connection. Another option could be to modiffy
h2_frt_transfer_data() to silently discard any contents but the CANCEL
error code is designed exactly for this and to save the peer from
continuing to stream data that will be discarded, so better switch to
using this.

This must be backported as far as 1.8.
2019-08-06 10:15:49 +02:00
Willy Tarreau
231f616170 BUG/MINOR: mux-h2: don't refrain from sending an RST_STREAM after another one
The test in h2s_send_rst_stream() is excessive, it refrains from sending an
RST_STREAM if *the last frame* was an RST_STREAM, regardless of the stream
ID. In a context where both clients and servers abort a lot, it could happen
that one RST_STREAM is dropped from responses from time to time, causing
delays to the client.

This must be backported to 2.0, 1.9 and 1.8.
2019-08-06 10:04:55 +02:00
Olivier Houchard
a3a8ea2fbf BUG/MEDIUM: pollers: Clear the poll_send bits as well.
In _update_fd(), if we're about to remove the FD from the poller, remove
both the receive and the send bits, instead of removing the receive bits
twice.
2019-08-05 23:56:26 +02:00
Olivier Houchard
c22580c2cc BUG/MEDIUM: fd: Always reset the polled_mask bits in fd_dodelete().
In fd_dodelete(), always reset the polled_mask bits, instead on only doing
it if we're closing the file descriptor. We call the poller clo() method
anyway, and failing to do so means that if fd_remove() is used while the
fd is polled, the poller won't attempt to poll on a fd with the same value
as the old one.
This leads to fd being stuck in the SSL code while using the async engine.

This should be backported to 2.0, 1.9 and 1.8.
2019-08-05 18:55:04 +02:00
Olivier Houchard
4c18f94c11 BUG/MEDIUM: proxy: Make sure to destroy the stream on upgrade from TCP to H2
In stream_set_backend(), if we have a TCP stream, and we want to upgrade it
to H2 instead of attempting ot reuse the stream, just destroy the
conn_stream, make sure we don't log anything about the stream, and pretend
we failed setting the backend, so that the stream will get destroyed.
New streams will then be created by the mux, as if the connection just
happened.
This fixes a crash when upgrading from TCP to H2, as the H2 mux totally
ignored the conn_stream provided by the upgrade, as reported in github
issue #196.

This should be backported to 2.0.
2019-08-02 18:28:58 +02:00
Willy Tarreau
1d4a0f8810 BUG/MEDIUM: mux-h2: split the stream's and connection's window sizes
The SETTINGS frame parser updates all streams' window for each
INITIAL_WINDOW_SIZE setting received on the connection (like h2spec
does in test 6.5.3), which can start to be expensive if repeated when
there are many streams (up to 100 by default). A quick test shows that
it's possible to parse only 35000 settings per second on a 3 GHz core
for 100 streams, which is rather small.

Given that window sizes are relative and may be negative, there's no
point in pre-initializing them for each stream and update them from
the settings. Instead, let's make them relative to the connection's
initial window size so that any change immediately affects all streams.
The only thing that remains needed is to wake up the streams that were
unblocked by the update, which is now done once at the end of
h2_process_demux() instead of once per setting. This now results in
5.7 million settings being processed per second, which is way better.

In order to keep the change small, the h2s' mws field was renamed to
"sws" for "stream window size", and an h2s_mws() function was added
to add it to the connection's initial window setting and determine the
window size to use when muxing. The h2c_update_all_ws() function was
renamed to h2c_unblock_sfctl() since it's now only used to unblock
previously blocked streams.

This needs to be backported to all versions till 1.8.
2019-08-02 13:43:33 +02:00
Willy Tarreau
9bc1c95855 BUG/MEDIUM: mux-h2: unbreak receipt of large DATA frames
Recent optimization in commit 4d7a88482 ("MEDIUM: mux-h2: don't try to
read more than needed") broke the receipt of large DATA frames because
it would unconditionally subscribe if there was some room left, thus
preventing any new rx from being done since subscription may only be
done once the end was reached, as indicated by ret == 0.

However, fixing this uncovered that in HTX mode previous versions might
occasionally be affected as well, when an available frame is the same
size as the maximum data that may fit into an HTX buffer, we may end
up reading that whole frame and still subscribe since it's still allowed
to receive, thus causing issues to read the next frame.

This patch will only work for 2.1-dev but a minor adaptation will be
needed for earlier versions (down to 1.9, where subscribe() was added).
2019-08-02 13:37:55 +02:00
Willy Tarreau
45bcb37f0f BUG/MINOR: stream-int: also update analysers timeouts on activity
Between 1.6 and 1.7, some parts of the stream forwarding process were
moved into lower layers and the stream-interface had to keep the
stream's task up to date regarding the timeouts. The analyser timeouts
were not updated there as it was believed this was not needed during
forwarding, but actually there is a case for this which is "option
contstats" which periodically triggers the analyser timeout, and this
change broke the option in case of sustained traffic (if there is some
I/O activity during the same millisecond as the timeout expires, then
the update will be missed).

This patch simply brings back the analyser expiration updates from
process_stream() to stream_int_notify().

It may be backported as far as 1.7, taking care to adjust the fields
names if needed.
2019-08-01 18:58:21 +02:00
William Lallemand
6e5f2ceead BUG/MEDIUM: ssl: open the right path for multi-cert bundle
Multi-cert bundle was not working anymore because we tried to open the
wrong path.
2019-08-01 14:47:57 +02:00
Willy Tarreau
a64c703374 BUG/MINOR: stream-int: make sure to always release empty buffers after sending
There are some situations, after sending a request or response, upon I/O
completion, or applet execution, where we end up with an empty buffer that
was not released. This results in excessive memory usage (back to 1.5) and
a lower CPU cache efficiency since buffers are not recycled as fast. This
has changed since the places where we send have changed with the new
layering, but not all cases susceptible of leaving an empty buffer were
properly spotted. Doing so reduces the memory pressure on buffers by about
2/3 in high traffic tests.

This should be backported to 2.0 and maybe 1.9.
2019-08-01 14:34:01 +02:00
Richard Russo
458eafb36d BUG/MAJOR: http/sample: use a static buffer for raw -> htx conversion
Multiple calls to smp_fetch_fhdr use the header context to keep track of
header parsing position; however, when using header sampling on a raw
connection, the raw buffer is converted into an HTX structure each time, and
this was done in the trash areas; so the block reference would be invalid on
subsequent calls.

This patch must be backported to 2.0 and 1.9.
2019-08-01 11:35:29 +02:00
Christopher Faulet
0a52c17f81 BUG/MEDIUM: lb-chash: Ensure the tree integrity when server weight is increased
When the server weight is increased in consistant hash, extra nodes have to be
allocated. So a realloc() is performed on the nodes array of the server. the
previous commit 962ea7732 ("BUG/MEDIUM: lb-chash: Remove all server's entries
before realloc() to re-insert them after") have fixed the size used during the
realloc() to avoid segfaults. But another bug remains. After the realloc(), the
memory area allocated for the nodes array may change, invalidating all node
addresses in the chash tree.

So, to fix the bug, we must remove all server's entries from the chash tree
before the realloc to insert all of them after, old nodes and new ones. The
insert will be automatically handled by the loop at the end of the function
chash_queue_dequeue_srv().

Note that if the call to realloc() failed, no new entries will be created for
the server, so the effective server weight will be unchanged.

This issue was reported on Github (#189).

This patch must be backported to all versions since the 1.6.
2019-08-01 11:35:29 +02:00
Emmanuel Hocdet
1503e05362 BUG/MINOR: ssl: fix ressource leaks on error
Commit 36b84637 "MEDIUM: ssl: split the loading of the certificates"
introduce leaks on fd/memory in case of error.
2019-08-01 11:27:24 +02:00
William Lallemand
6dee29d63d BUG/MEDIUM: ssl: don't free the ckch in multi-cert bundle
When using a ckch we should never try to free its content, because it
won't be usable  after and can result in a NULL derefence during
parsing.

The content was previously freed because the ckch wasn't stored in a
tree to be used later, now that we use it multiple time, we need to keep
the data.
2019-08-01 11:27:24 +02:00
Willy Tarreau
a37cb1880c MINOR: wdt: also consider that waiting in the thread dumper is normal
It happens that upon looping threads the watchdog fires, starts a dump,
and other threads expire their budget while waiting for the other threads
to get dumped and trigger a watchdog event again, adding some confusion
to the traces. With this patch the situation becomes clearer as we export
the list of threads being dumped so that the watchdog can check it before
deciding to trigger. This way such threads in queue for being dumped are
not attempted to be reported in turn.

This should be backported to 2.0 as it helps understand stack traces.
2019-07-31 19:35:31 +02:00
Willy Tarreau
c07736209d BUG/MINOR: debug: fix a small race in the thread dumping code
If a thread dump is requested from a signal handler, it may interrupt
a thread already waiting for a dump to complete, and may see the
threads_to_dump variable go to zero while others are waiting, steal
the lock and prevent other threads from ever completing. This tends
to happen when dumping many threads upon a watchdog timeout, to threads
waiting for their turn.

Instead now we proceed in two steps :
  1) the last dumped thread sets all bits again
  2) all threads only wait for their own bit to appear, then clear it
     and quit

This way there's no risk that a bit performs a double flip in the same
loop and threads cannot get stuck here anymore.

This should be backported to 2.0 as it clarifies stack traces.
2019-07-31 19:35:31 +02:00
William Lallemand
a8c73748f8 BUG/MEDIUM: ssl: does not try to free a DH in a ckch
ssl_sock_load_dh_params() should not free the DH * of a ckch, or the
ckch won't be usable during the next call.
2019-07-31 19:35:31 +02:00
William Lallemand
c4ecddf418 BUG/BUILD: ssl: fix build with openssl < 1.0.2
Recent changes use struct cert_key_and_chain to load all certificates in
frontends, this structure was previously used only to load multi-cert
bundle, which is supported only on >= 1.0.2.
2019-07-31 17:05:09 +02:00
Willy Tarreau
4d7a884827 MEDIUM: mux-h2: don't try to read more than needed
The h2_recv() loop was historically built around a loop to deal with
the callback model but this is not needed anymore, as it the upper
layer wants more data, it will simply try to read again. Right now
50% of the recvfrom() calls made over H2 return EAGAIN. With this
change it doesn't happen anymore. Note that the code simply consists
in breaking the loop, and reporting real data receipt instead of
always returning 1.

A test was made not to subscribe if we actually read data but it
doesn't change anything since we might be subscribed very early
already.
2019-07-31 16:18:25 +02:00
Olivier Houchard
53055055c5 MEDIUM: pollers: Remember the state for read and write for each threads.
In the poller code, instead of just remembering if we're currently polling
a fd or not, remember if we're polling it for writing and/or for reading, that
way, we can avoid to modify the polling if it's already polled as needed.
2019-07-31 14:54:41 +02:00
Olivier Houchard
305d5ab469 MAJOR: fd: Get rid of the fd cache.
Now that the architecture was changed so that attempts to receive/send data
always come from the upper layers, instead of them only trying to do so when
the lower layer let them know they could try, we can finally get rid of the
fd cache. We don't really need it anymore, and removing it gives us a small
performance boost.
2019-07-31 14:12:55 +02:00
Emmanuel Hocdet
a7a0f991c9 MINOR: ssl: clean ret variable in ssl_sock_load_ckchn
In ssl_sock_load_ckchn, ret variable is now in a half dead usage.
Remove it to clean compilation warnings.
2019-07-30 17:54:35 +02:00
Emmanuel Hocdet
efa4b95b78 CLEANUP: ssl: ssl_sock_load_crt_file_into_ckch
Fix comments for this function and remove free before alloc call: ckch
call is correctly balanced  (alloc/free).
2019-07-30 17:54:34 +02:00
Emmanuel Hocdet
54227d8add MINOR: ssl: do not look at DHparam with OPENSSL_NO_DH
OPENSSL_NO_DH can be defined to avoid obsolete and heavy DH processing.
With OPENSSL_NO_DH, parse the entire PEM file to look at DHparam is wast
of time.
2019-07-30 17:54:34 +02:00
Emmanuel Hocdet
03e09f3818 MINOR: ssl: check private key consistency in loading
Load a PEM certificate and use it in CTX are now decorrelated.
Checking the certificate and private key consistency can be done
earlier: in loading phase instead CTX set phase.
2019-07-30 15:53:54 +02:00
Emmanuel Hocdet
1c65fdd50e MINOR: ssl: add extra chain compatibility
cert_key_and_chain handling is now outside openssl 1.0.2 #if: the
code must be libssl compatible. SSL_CTX_add1_chain_cert and
SSL_CTX_set1_chain requires openssl >= 1.0.2, replace it by legacy
SSL_CTX_add_extra_chain_cert when SSL_CTX_set1_chain is not provided.
2019-07-30 15:53:54 +02:00
Emmanuel Hocdet
9246f8bc83 MINOR: ssl: use STACK_OF for chain certs
Used native cert chain manipulation with STACK_OF from ssl lib.
2019-07-30 15:53:54 +02:00
Willy Tarreau
5e83d996cf BUG/MAJOR: queue/threads: avoid an AB/BA locking issue in process_srv_queue()
A problem involving server slowstart was reported by @max2k1 in issue #197.
The problem is that pendconn_grab_from_px() takes the proxy lock while
already under the server's lock while process_srv_queue() first takes the
proxy's lock then the server's lock.

While the latter seems more natural, it is fundamentally incompatible with
mayn other operations performed on servers, namely state change propagation,
where the proxy is only known after the server and cannot be locked around
the servers. Howwever reversing the lock in process_srv_queue() is trivial
and only the few functions related to dynamic cookies need to be adjusted
for this so that the proxy's lock is taken for each server operation. This
is possible because the proxy's server list is built once at boot time and
remains stable. So this is what this patch does.

The comments in the proxy and server structs were updated to mention this
rule that the server's lock may not be taken under the proxy's lock but
may enclose it.

Another approach could consist in using a second lock for the proxy's queue
which would be different from the regular proxy's lock, but given that the
operations above are rare and operate on small servers list, there is no
reason for overdesigning a solution.

This fix was successfully tested with 10000 servers in a backend where
adjusting the dyncookies in loops over the CLI didn't have a measurable
impact on the traffic.

The only workaround without the fix is to disable any occurrence of
"slowstart" on server lines, or to disable threads using "nbthread 1".

This must be backported as far as 1.8.
2019-07-30 14:02:06 +02:00
William Lallemand
fa8922285d MEDIUM: ssl: load DH param in struct cert_key_and_chain
Load the DH param at the same time as the certificate, we don't need to
open the file once more and read it again. We store it in the ckch_node.

There is a minor change comparing to the previous way of loading the DH
param in a bundle. With a bundle, the DH param in a certificate file was
never loaded, it only used the global DH or the default DH, now it's
able to use the DH param from a certificate file.
2019-07-29 15:28:46 +02:00
William Lallemand
6af03991da MEDIUM: ssl: lookup and store in a ckch_node tree
Don't read a certificate file again if it was already stored in the
ckchn tree. It allows HAProxy to start more quickly if the same
certificate is used at different places in the configuration.

HAProxy lookup in the ssl_sock_load_cert() function, doing it at this
level allows to skip the reading of the certificate in the filesystem.

If the certificate is not found in the tree, we insert the ckch_node in
the tree once the certificate is read on the filesystem, the filename or
the bundle name is used as the key.
2019-07-29 15:28:46 +02:00
William Lallemand
36b8463777 MEDIUM: ssl: split the loading of the certificates
Split the functions which open the certificates.

Instead of opening directly the certificates and inserting them directly
into a SSL_CTX, we use a struct cert_key_and_chain to store them in
memory and then we associate a SSL_CTX to the certificate stored in that
structure.

Introduce the struct ckch_node for the multi-cert bundles so we can
store multiple cert_key_and_chain in the same structure.

The functions ssl_sock_load_multi_cert() and ssl_sock_load_cert_file()
were modified so they don't open the certicates anymore on the
filesystem. (they still open the sctl and ocsp though).  These functions
were renamed ssl_sock_load_ckchn() and ssl_sock_load_multi_ckchn().

The new function ckchn_load_cert_file() is in charge of loading the
files in the cert_key_and_chain. (TODO: load ocsp and sctl from there
too).

The ultimate goal is to be able to load a certificate from a certificate
tree without doing any filesystem access, so we don't try to open it
again if it was already loaded, and we share its configuration.
2019-07-29 15:28:46 +02:00
William Lallemand
a59191b894 MEDIUM: ssl: use cert_key_and_chain struct in ssl_sock_load_cert_file()
This structure was only used in the case of the multi-cert bundle.

Using these primitives everywhere when we load the file are a first step
in the deduplication of the code.
2019-07-29 15:28:46 +02:00
William Lallemand
c940207d39 MINOR: ssl: merge ssl_sock_load_cert_file() and ssl_sock_load_cert_chain_file()
This commit merges the function ssl_sock_load_cert_file() and
ssl_sock_load_cert_chain_file().

The goal is to refactor the SSL code and use the cert_key_and_chain
struct to load everything.
2019-07-29 15:28:46 +02:00
Christopher Faulet
61ed7797f6 BUG/MINOR: htx: Fix free space addresses calculation during a block expansion
When the payload of a block is shrinked or enlarged, addresses of the free
spaces must be updated. There are many possible cases. One of them is
buggy. When there is only one block in the HTX message and its payload is just
before the tail room and it needs to be moved in the head room to be enlarged,
addresses are not correctly updated. This bug may be hit by the compression
filter.

This patch must be backported to 2.0.
2019-07-29 11:17:52 +02:00
Christopher Faulet
301eff8e21 BUG/MINOR: hlua: Only execute functions of HTTP class if the txn is HTTP ready
The flag HLUA_TXN_HTTP_RDY was added in the previous commit to know when a
function is called for a channel with a valid HTTP message or not. Of course it
also depends on the calling direction. In this commit, we allow the execution of
functions of the HTTP class only if this flag is set.

Nobody seems to use them from an unsupported context (for instance, trying to
set an HTTP header from a tcp-request rule). But it remains a bug leading to
undefined behaviors or crashes.

This patch may be backported to all versions since the 1.6. It depends on the
commits "MINOR: hlua: Add a flag on the lua txn to know in which context it can
be used" and "MINOR: hlua: Don't set request analyzers on response channel for
lua actions".
2019-07-29 11:17:52 +02:00
Christopher Faulet
bfab2dddad MINOR: hlua: Add a flag on the lua txn to know in which context it can be used
When a lua action or a lua sample fetch is called, a lua transaction is
created. It is an entry in the stack containing the class TXN. Thanks to it, we
can know the direction (request or response) of the call. But, for some
functions, it is also necessary to know if the buffer is "HTTP ready" for the
given direction. "HTTP ready" means there is a valid HTTP message in the
channel's buffer. So, when a lua action or a lua sample fetch is called, the
flag HLUA_TXN_HTTP_RDY is set if it is appropriate.
2019-07-29 11:17:52 +02:00
Christopher Faulet
51fa358432 MINOR: hlua: Don't set request analyzers on response channel for lua actions
Setting some requests analyzers on the response channel was an old trick to be
sure to re-evaluate the request's analyers after the response's ones have been
called. It is no more necessary. In fact, this trick was removed in the version
1.8 and backported up to the version 1.6.

This patch must be backported to all versions since 1.6 to ease the backports of
fixes on the lua code.
2019-07-29 11:17:52 +02:00
Christopher Faulet
84a6d5bc21 BUG/MEDIUM: hlua: Check the calling direction in lua functions of the HTTP class
It is invalid to manipulate responses from http-request rules or to manipulate
requests from http-response rules. When http-request rules are evaluated, the
connection to server is not yet established, so there is no response at all. And
when http-response rules are evaluated, the request has already been sent to the
server.

Now, the calling direction is checked. So functions "txn.http:req_*" can now
only be called from http-request rules and the functions "txn.http:res_*" can
only be called from http-response rules.

This issue was reported on Github (#190).

This patch must be backported to all versions since the 1.6.
2019-07-29 11:17:52 +02:00
Christopher Faulet
fe6a71b8e0 BUG/MINOR: hlua/htx: Reset channels analyzers when txn:done() is called
For HTX streams, when txn:done() is called, the work is delegated to the
function http_reply_and_close(). But it is not enough. The channel's analyzers
must also be reset. Otherwise, some analyzers may still be called while
processing should be aborted.

For instance, if the function is called from an http-request rules on the
frontend, request analyzers on the backend side are still called. So we may try
to add an header to the request, while this one was already reset.

This patch must be backported to 2.0 and 1.9.
2019-07-29 11:17:52 +02:00
Olivier Houchard
dedd30610b MEDIUM: h1: Don't wake the H1 tasklet if we got the whole request.
In h1_rcv_buf(), don't wake the H1 tasklet to attempt to receive more data
if we got the whole request. It will lead to a recv and maybe to a subscribe
while it may not be needed.
If the connection is keep alive, the tasklet will be woken up later by
h1_detach(), so that we'll be able to get the next request, or an end of
connection.
2019-07-26 17:13:21 +02:00
Olivier Houchard
cc3fec8ac9 MEDIUM: h1: Don't try to subscribe if we managed to read data.
In h1_recv(), don't subscribe if we managed to receive data. We may not have
to, if we received a complete request, and a new receive will be attempted
later, as the tasklet is woken up either by h1_rcv_buf() or by h1_detach.
2019-07-26 17:13:17 +02:00
Willy Tarreau
9fbcb7e2e9 BUG/MINOR: log: make sure writev() is not interrupted on a file output
Since 1.9 we support sending logs to various non-blocking outputs like
stdou/stderr or flies, by using writev() which guarantees that it only
returns after having written everything or nothing. However the syscall
may be interrupted while doing so, and this is visible when writing to
a tty during debug sessions, as some logs occasionally appear interleaved
if an xterm or SSH connection is not very fast. Performance here is not a
critical concern, log correctness is. Let's simply take the logger's lock
around the writev() call to prevent multiple senders from stepping onto
each other's toes.

This may be backported to 2.0 and 1.9.
2019-07-26 15:46:18 +02:00
Olivier Houchard
7859526fd6 BUG/MEDIUM: streams: Don't switch the SI to SI_ST_DIS if we have data to send.
In sess_established(), don't immediately switch the backend stream_interface
to SI_ST_DIS if we only got a SHUTR. We may still have something to send,
ie if the request is a POST, and we should be switched to SI_ST8DIS later
when the shutw will happen.

This should be backported to 2.0 and 1.9.
2019-07-26 14:56:41 +02:00
Christopher Faulet
366ad86af7 BUG/MEDIUM: lb-chash: Fix the realloc() when the number of nodes is increased
When the number of nodes is increased because the server weight is changed, the
nodes array must be realloc. But its new size is not correctly set. Only the
total number of nodes is used to set the new size. But it must also depends on
the size of a node. It must be the total nomber of nodes times the size of a
node.

This issue was reported on Github (#189).

This patch must be backported to all versions since the 1.6.
2019-07-26 14:12:59 +02:00
Christopher Faulet
98fbe9531a MEDIUM: mux-h1: Add the support of headers adjustment for bogus HTTP/1 apps
There is no standard case for HTTP header names because, as stated in the
RFC7230, they are case-insensitive. So applications must handle them in a
case-insensitive manner. But some bogus applications erroneously rely on the
case used by most browsers. This problem becomes critical with HTTP/2
because all header names must be exchanged in lowercase. And HAProxy uses the
same convention. All header names are sent in lowercase to clients and servers,
regardless of the HTTP version.

This design choice is linked to the HTX implementation. So, for previous
versions (2.0 and 1.9), a workaround is to disable the HTX mode to fall
back to the legacy HTTP mode.

Since the legacy HTTP mode was removed, some users reported interoperability
issues because their application was not able anymore to handle HTTP/1 message
received from HAProxy. So, we've decided to add a way to change the case of some
headers before sending them. It is now possible to define a "mapping" between a
lowercase header name and a version supported by the bogus application. To do
so, you must use the global directives "h1-case-adjust" and
"h1-case-adjust-file". Then options "h1-case-adjust-bogus-client" and
"h1-case-adjust-bogus-server" may be used in proxy sections to enable the
conversion. See the configuration manual for more info.

Of course, our advice is to urgently upgrade these applications for
interoperability concerns and because they may be vulnerable to various types of
content smuggling attacks. But, if your are really forced to use an unmaintained
bogus application, you may use these directive, at your own risks.

If it is relevant, this feature may be backported to 2.0.
2019-07-24 18:32:47 +02:00
Willy Tarreau
3de3cd4d97 BUG/MINOR: proxy: always lock stop_proxy()
There is one unprotected call to stop_proxy() from the manage_proxy()
task, so there is a single caller by definition, but there is also
another such call from the CLI's "shutdown frontend" parser. This
one does it under the proxy's lock but the first one doesn't use it.
Thus it is theorically possible to corrupt the list of listeners in a
proxy by issuing "shutdown frontend" and SIGUSR1 exactly at the same
time. While it sounds particularly contrived or stupid, it could
possibly happen with automated tools that would send actions via
various channels. This could cause the process to loop forever or
to crash and thus stop faster than expected.

This might be backported as far as 1.8.
2019-07-24 17:42:44 +02:00
Willy Tarreau
daacf36645 BUG/MEDIUM: protocols: add a global lock for the init/deinit stuff
Dragan Dosen found that the listeners lock is not sufficient to protect
the listeners list when proxies are stopping because the listeners are
also unlinked from the protocol list, and under certain situations like
bombing with soft-stop signals or shutting down many frontends in parallel
from multiple CLI connections, it could be possible to provoke multiple
instances of delete_listener() to be called in parallel for different
listeners, thus corrupting the protocol lists.

Such operations are pretty rare, they are performed once per proxy upon
startup and once per proxy on shut down. Thus there is no point trying
to optimize anything and we can use a global lock to protect the protocol
lists during these manipulations.

This fix (or a variant) will have to be backported as far as 1.8.
2019-07-24 16:45:02 +02:00
Olivier Houchard
f0f4238977 BUG/CRITICAL: http_ana: Fix parsing of malformed cookies which start by a delimiter
When client-side or server-side cookies are parsed, HAProxy enters in an
infinite loop if a Cookie/Set-Cookie header value starts by a delimiter (a colon
or a semicolon). Depending on the operating system, the service may become
degraded, unresponsive, or may trigger haproxy's watchdog causing a service stop
or automatic restart.

To fix this bug, in the loop parsing the attributes, we must be sure to always
skip delimiters once the first attribute-value pair was parsed, empty or
not. The credit for the fix goes to Olivier.

CVE-2019-14241 was assigned to this bug. This patch fixes the Github issue #181.

This patch must be backported to 2.0 and 1.9. However, the patch will have to be
adapted.
2019-07-23 14:58:32 +02:00
Christopher Faulet
90cc4811be BUG/MINOR: http_htx: Support empty errorfiles
Empty error files may be used to disable the sending of any message for specific
error codes. A common use-case is to use the file "/dev/null". This way the
default error message is overridden and no message is returned to the client. It
was supported in the legacy HTTP mode, but not in HTX. Because of a bug, such
messages triggered an error.

This patch must be backported to 2.0 and 1.9. However, the patch will have to be
adapted.
2019-07-23 14:58:32 +02:00
Christopher Faulet
9f5839cde2 BUG/MINOR: http_ana: Be sure to have an allocated buffer to generate an error
In http_reply_and_close() and http_server_error(), we must be sure to have an
allocated buffer (buf.size > 0) to consider it as a valid HTX message. For now,
there is no way to hit this bug. But a fix to support "empty" error messages in
HTX is pending. Such empty messages, after parsing, will be converted into
unallocated buffer (buf.size == 0).

This patch must be backported to 2.0 and 1.9. owever, the patch will have to be
adapted.
2019-07-23 14:58:23 +02:00
Willy Tarreau
ef91c939f3 BUG/MEDIUM: tcp-checks: do not dereference inexisting conn_stream
Github user @jpulz reported a crash with tcp-checks in issue #184
where cs==NULL. If we enter the function with cs==NULL and check->result
!= CHK_RES_UKNOWN, we'll go directly to out_end_tcpcheck and dereference
cs. We must validate there that cs is valid (and conn at the same time
since it would be NULL as well).

This fix must be backported as far as 1.8.
2019-07-23 14:37:47 +02:00
Christopher Faulet
f1204b8933 BUG/MINOR: mux-h1: Close server connection if input data remains in h1_detach()
With the previous commit 03627245c ("BUG/MEDIUM: mux-h1: Trim excess server data
at the end of a transaction"), we try to avoid to handle junk data coming from a
server as a response. But it only works for data already received. Starting from
the moment a server sends an invalid response, it is safer to close the
connection too, because more data may come after and there is no good reason to
handle them.

So now, when a conn_stream is detached from a server connection, if there are
some unexpected input data, we simply trim them and close the connection
ASAP. We don't close it immediately only if there are still some outgoing data
to deliver to the server.

This patch must be backported to 2.0 and 1.9.
2019-07-19 14:51:08 +02:00
Willy Tarreau
b082186528 MEDIUM: backend: remove impossible cases from connect_server()
Now that we start by releasing any possibly existing connection,
the conditions simplify a little bit and some of the complex cases
can be removed. A few comments were also added for non-obvious cases.
2019-07-19 13:50:09 +02:00
Willy Tarreau
a5797aab11 MEDIUM: backend: always release any existing prior connection in connect_server()
When entering connect_server() we're not supposed to have a connection
already, except when retrying a failed connection, which is pretty rare.
Let's simplify the code by starting to unconditionally release any existing
connection. For now we don't go further, as this change alone will lead to
quite some simplification that'd rather be done as a separate cleanup.
2019-07-19 13:50:09 +02:00
Willy Tarreau
5a0b25d31c MEDIUM: lua: do not allocate the remote connection anymore
Lua cosockets do not need to allocate the remote connection anymore.
However this was trickier than expected because some tests were made
on this remote connection's existence to detect establishment instead
of relying on the stream interface's state (which is how it's now done).
The flag SF_ADDR_SET was set a bit too early (before assigning the
address) so this was moved to the right place. It should not have had
any impact beyond confusing debugging.

The only remaining occurrence of the remote connection knowledge now
is for getsockname() which requires to access the connection to send
the syscall, and it's unlikely that we'll need to change this before
QUIC or so.
2019-07-19 13:50:09 +02:00
Willy Tarreau
02efedac0c MINOR: peers: now remove the remote connection setup code
The connection is not needed anymore, the backend does the job.
2019-07-19 13:50:09 +02:00
Willy Tarreau
1c8d32bb62 MAJOR: stream: store the target address into s->target_addr
When forcing the outgoing address of a connection, till now we used to
allocate this outgoing connection and set the address into it, then set
SF_ADDR_SET. With connection reuse this causes a whole lot of issues and
difficulties in the code.

Thanks to the previous changes, it is now possible to store the target
address into the stream instead, and copy the address from the stream to
the connection when initializing the connection. assign_server_address()
does this and as a result SF_ADDR_SET now reflects the presence of the
target address in the stream, not in the connection. The http_proxy mode,
the peers and the master's CLI now use the same mechanism. For now the
existing connection code was not removed to limit the amount of tricky
changes, but the allocated connection is not used anymore.

This change also revealed a latent issue that we've been having around
option http_proxy : the address was set in the connection but neither the
SF_ADDR_SET nor the SF_ASSIGNED flags were set. It looks like the connection
could establish only due to the fact that it existed with a non-null
destination address.
2019-07-19 13:50:09 +02:00
Willy Tarreau
9042060b0b MINOR: stream: add a new target_addr entry in the stream structure
The purpose will be to store the target address there and not to
allocate a connection just for this anymore. For now it's only placed
in the struct, a few fields were moved to plug some holes, and the
entry is freed on release (never allocated yet for now). This must
have no impact. Note that in order to fit, the store_count which
previously was an int was turned into a short, which is way more
than enough given that the hard-coded limit is 8.
2019-07-19 13:50:09 +02:00
Willy Tarreau
16aa4aff6b MINOR: connection: don't use clear_addr() anymore, just release the address
Now that we have dynamically allocated addresses, there's no need to
clear an address before reusing it, just release it. Note that this
is not equivalent to saying that an address is never zero, as shown in
assign_server_address() where an address 0.0.0.0 can still be assigned
to a connection for the time it takes to modify it.
2019-07-19 13:50:09 +02:00
Willy Tarreau
ca79f59365 MEDIUM: connection: make sure all address producers allocate their address
This commit places calls to sockaddr_alloc() at the places where an address
is needed, and makes sure that the allocation is properly tested. This does
not add too many error paths since connection allocations are already in the
vicinity and share the same error paths. For the two cases where a
clear_addr() was called, instead the address was not allocated.
2019-07-19 13:50:09 +02:00
Willy Tarreau
ff5d57b022 MINOR: connection: create a new pool for struct sockaddr_storage
This pool will be used to allocate storage for source and destination
addresses used in connections. Two functions sockaddr_{alloc,free}()
were added and will have to be used everywhere an address is needed.
These ones are safe for progressive replacement as they check that the
existing pointer is set before replacing it. The pool is not yet used
during allocation nor freeing. Also they operate on pointers to pointers
so they will perform checks and replace values. The free one nulls the
pointer.
2019-07-19 13:50:09 +02:00
Willy Tarreau
c0e16f208d MEDIUM: backend: turn all conn->addr.{from,to} to conn->{src,dst}
All reads were carefully reviewed for only reading already checked
values. Assignments were commented indicating that an allocation will
be needed once they become dynamic. The memset() used to clear the
addresses should then be turned to a free() and a NULL assignment.
2019-07-19 13:50:09 +02:00
Willy Tarreau
9a1efe1e15 MINOR: http: convert conn->addr.from to conn->src in sample fetches
These calls are safe because the address' validity was already checked
prior to reaching that code.
2019-07-19 13:50:09 +02:00
Willy Tarreau
44a7d8ee89 MINOR: frontend: switch from conn->addr.{from,to} to conn->{src,dst}
All these values were already checked, it's safe to use them as-is.
2019-07-19 13:50:09 +02:00
Willy Tarreau
b3c81cbbbf MINOR: checks: replace conn->addr.to with conn->dst
Two places will require a dynamic address allocation since the connection
is created from scratch. For the source address it looks like the
clear_addr() call will simply have to be removed as the pointer will
already be NULL.
2019-07-19 13:50:09 +02:00
Willy Tarreau
6c6365f455 MINOR: log: use conn->{src,dst} instead of conn->addr.{from,to}
This is used to retrieve the addresses to be logged (client, frontend,
backend, server). In all places the validity check was already performed.
2019-07-19 13:50:09 +02:00
Willy Tarreau
3f4fa0964c MINOR: sockpair: use conn->dst for the target address in ->connect()
No extra check is needed since the destination must be set there.
2019-07-19 13:50:09 +02:00
Willy Tarreau
ca9f5a927a MINOR: unix: use conn->dst for the target address in ->connect()
No extra check is needed since the destination must be set there.
2019-07-19 13:50:09 +02:00
Willy Tarreau
7bbc4a511f MINOR: tcp: replace conn->addr.{from,to} with conn->{src,dst}
Most of the locations were already safe, only two places needed to have
one extra check to avoid assuming that cli_conn->src is necessarily set
(it is in practice but let's stay safe).
2019-07-19 13:50:09 +02:00
Willy Tarreau
4d3c60ad8d MINOR: session: use conn->src instead of conn->addr.from
In session_accept_fd() we'll soon have to dynamically allocate the
address, or better, steal it from the caller and define a strict calling
convention regarding who's responsible for the freeing. In the simpler
session_prepare_log_prefix(), just add an attempt to retrieve the address
if not yet set and do not dereference it on failure.
2019-07-19 13:50:09 +02:00
Willy Tarreau
026efc71c8 MINOR: proxy: switch to conn->src in error snapshots
The source address was taken unchecked from a client connection. In
practice we know it's set but better strengthen this now.
2019-07-19 13:50:09 +02:00
Willy Tarreau
71e34c186a MINOR: stream: switch from conn->addr.{from,to} to conn->{src,dst}
No allocation is needed there. Some extra checks were added in the
stream dump code to make sure the source address is effectively valid
(it always is but it doesn't cost much to be certain).
2019-07-19 13:50:09 +02:00
Willy Tarreau
a48f4b3254 MINOR: htx: switch from conn->addr.{from,to} to conn->{src,dst}
One place (transparent proxy) will require an allocation when the
address becomes dynamic. A few dereferences of the family were adjusted
to preliminary check for the address pointer to exist at all. The
remaining operations were already performed under control of a
successful retrieval.
2019-07-19 13:50:09 +02:00
Willy Tarreau
3ca149018d MINOR: peers: use conn->dst for the peer's target address
The target address is duplicated from the peer's configured one. For
now we keep the target address as-is but we'll have to dynamically
allocate it and place it into the stream instead. Maybe a sockaddr_dup()
will help by the way.

The "show peers" part is safe as it's already called after checking
the addresses' validity.
2019-07-19 13:50:09 +02:00
Willy Tarreau
9da9a6fdca MINOR: lua: switch to conn->dst for a connection's target address
This one will soon need a dynamic allocation, though this will be
temporary as ideally the address will be placed on the stream and no
connection will be allocated anymore.
2019-07-19 13:50:09 +02:00
Willy Tarreau
085a1513ad MINOR: ssl-sock: use conn->dst instead of &conn->addr.to
This part can be definitive as the check was already in place.
2019-07-19 13:50:09 +02:00
Willy Tarreau
226572f55f MINOR: connection: use conn->{src,dst} instead of &conn->addr.{from,to}
This is in preparation for the switch to dynamic address allocation,
let's migrate the code using the old fields to the pointers instead.
Note that no extra check was added for now, the purpose is only to
get the code to use the pointers and still work.

In the proxy protocol message handling we make sure the addresses are
properly allocated before declaring them unset.
2019-07-19 13:50:09 +02:00
Willy Tarreau
cd7ca79e6c MINOR: http: check the source address via conn_get_src() in sample fetch functions
In smp_fetch_url32_src() and smp_fetch_base32_src() it's better to
validate that the source address was properly initialized since it
will soon be dynamic, thus let's call conn_get_src().
2019-07-19 13:50:09 +02:00
Willy Tarreau
428d8e32f4 MINOR: lua: use conn_get_{src,dst} to retrieve connection addresses
This replaces the previous conn_get_{from,to}_addr() and reuses the
existing error checks.
2019-07-19 13:50:09 +02:00
Willy Tarreau
83b5890b47 MINOR: http/htx: use conn_get_dst() to retrieve the destination address
When adding the X-Original-To header, let's use conn_get_dst() and make
sure it succeeds, since  previous call to conn_get_to_addr() was unchecked.
2019-07-19 13:50:09 +02:00
Willy Tarreau
8fa9984a17 MINOR: log: use conn_get_{dst,src}() to retrieve the cli/frt/bck/srv/ addresses
This also allows us to check that the operation succeeded without
logging whatever remained in the memory area in case of failure.
2019-07-19 13:50:09 +02:00
Willy Tarreau
8dfffdb060 MINOR: stream/cli: use conn_get_{src,dst} in "show sess" and "show peers" output
The stream outputs requires to retrieve connections sources and
destinations. The previous call involving conn_get_{to,from}_addr()
was missing a status check which has now been integrated with the
new call since these places already handle connection errors there.

The same code parts were reused for "show peers" and were modified
similarly.
2019-07-19 13:50:09 +02:00
Willy Tarreau
7bb447c3dd MINOR: stream-int: use conn_get_{src,dst} in conn_si_send_proxy()
These ones replace the previous conn_get_{from,to}_addr() used to wait
for the connection establishment before sending a LOCAL line. The
error handling was preserved.
2019-07-19 13:50:09 +02:00
Willy Tarreau
dddd2b422f MINOR: tcp: replace various calls to conn_get_{from,to}_addr with conn_get_{src,dst}
These calls include the operation's status. When the check was already
present, it was merged with the call. when it was not present, it was
added.
2019-07-19 13:50:09 +02:00
Willy Tarreau
f5bdb64d35 MINOR: ssl: switch to conn_get_dst() to retrieve the destination address
This replaces conn_get_to_addr() and the subsequent check.
2019-07-19 13:50:09 +02:00
Willy Tarreau
3cc01d84b3 MINOR: backend: switch to conn_get_{src,dst}() for port and address mapping
The backend connect code uses conn_get_{from,to}_addr to forward addresses
in transparent mode and to map server ports, without really checking if the
operation succeeds. In preparation of future changes, let's switch to
conn_get_{src,dst}() and integrate status check for possible failures.
2019-07-19 13:50:09 +02:00
Willy Tarreau
a0a4b09d08 MINOR: frontend: switch to conn_get_{src,dst}() for logging and debugging
The frontend accept code uses conn_get_{from,to}_addr for logging and
debugging, without really checking if the operation succeeds. In
preparation of future changes, let's switch to conn_get_{src,dst}() and
integrate status check for possible failures.
2019-07-19 13:50:09 +02:00
Christopher Faulet
03627245c6 BUG/MEDIUM: mux-h1: Trim excess server data at the end of a transaction
At the end of a transaction, when the conn_stream is detach from the H1
connection, on the server side, we must release the input buffer to trim any
excess data received from the server to be sure to block invalid responses.  A
typical example of such data would be from a buggy server responding to a HEAD
with some data, or sending more than the advertised content-length.

This issue was reported on Gitbub. See issue #176.

This patch must be backported to 2.0 and 1.9.
2019-07-19 11:39:19 +02:00
Christopher Faulet
f89f0991f6 MINOR: config: Warn only if the option http-use-htx is used with "no" prefix
No warning message is emitted anymore if the option is used to enable the
HTX. But it is still diplayed when the "no" prefix is used to disable the HTX
explicitly. So, for existing configs, we display a warning only if there is a
change in the behavior of HAProxy between the 2.1 and the previous versions.
2019-07-19 11:39:19 +02:00
Willy Tarreau
2ab5c38359 BUG/MINOR: checks: do not exit tcp-checks from the middle of the loop
There's a comment above tcpcheck_main() clearly stating that no return
statement should be placed in the middle, still we did have one after
installing the mux. It looks mostly harmless though as it will only
fail to mark the server as being in error in case of allocation failure
or config issue.

This fix should be backported to 2.0 and probably 1.9 as well.
2019-07-19 11:03:54 +02:00
Christopher Faulet
4da05478e3 CLEANUP: mux-h2: Remove unused flags H2_SF_CHNK_*
Since the legacy HTTP code was removed, these flags are unused anymore.
2019-07-19 09:46:23 +02:00
Christopher Faulet
39566d1892 BUG/MINOR: session: Send a default HTTP error if accept fails for a H1 socket
If session_accept_fd() fails for a raw HTTP socket, we try to send an HTTP error
500. But we must not rely on error messages of the proxy or on the array
http_err_chunks because these are HTX messages. And it should be too expensive
to convert an HTX message to a raw message at this place. So instead, we send a
default HTTP error message from the array http_err_msgs.

This patch must be backported to 2.0 and 1.9.
2019-07-19 09:46:23 +02:00
Christopher Faulet
76f4c370f1 BUG/MINOR: session: Emit an HTTP error if accept fails only for H1 connection
If session_accept_fd() fails for a raw HTTP socket, we try to send an HTTP error
500. But, we must also take care it is an HTTP/1 connection. We cannot rely on
the mux at this stage, because the error, if any, happens before or during its
creation. So, instead, we check if the mux_proto is specified or not. Indeed,
the mux h1 cannot be forced on the bind line and there is no ALPN to choose
another mux on a raw socket. So if there is no mux_proto defined for a raw HTTP
socket, we are sure to have an HTTP/1 connection.

This patch must be backported to 2.0 and 1.9.
2019-07-19 09:46:23 +02:00
Christopher Faulet
f734638976 MINOR: http: Don't store raw HTTP errors in chunks anymore
Default HTTP error messages are stored in an array of chunks. And since the HTX
was added, these messages are also converted in HTX and stored in another
array. But now, the first array is not used anymore because the legacy HTTP mode
was removed.

So now, only the array with the HTX messages are kept. The other one was
removed.
2019-07-19 09:46:23 +02:00
Christopher Faulet
41ba36f8b2 MINOR: global: Preset tune.max_http_hdr to its default value
By default, this tune parameter is set to MAX_HTTP_HDR. This assignment is done
after the configuration parsing, when we check the configuration validity. So
during the configuration parsing, its value is 0. Now, it is set to MAX_HTTP_HDR
from the start. So, it is possible to rely on it during the configuration
parsing.
2019-07-19 09:46:23 +02:00
Christopher Faulet
1b6adb4a51 MINOR: proxy/http_ana: Remove unused req_exp/rsp_exp and req_add/rsp_add lists
The keywords req* and rsp* are now unsupported. So the corresponding lists are
now unused. It is safe to remove them from the structure proxy.

As a result, the code dealing with these rules in HTTP analyzers was also
removed.
2019-07-19 09:24:12 +02:00
Christopher Faulet
8c3b63ae1d MINOR: proxy: Remove the unused list of block rules
The keyword "block" is now unsupported. So the list of block rules is now
unused. It can be safely removed from the structure proxy.
2019-07-19 09:24:12 +02:00
Christopher Faulet
a6a56e6483 MEDIUM: config: Remove parsing of req* and rsp* directives
It was announced for the 2.1. Following keywords are now unsupported:

  * reqadd, reqallow, reqiallow, reqdel, reqidel, reqdeny, reqideny, reqpass,
    reqipass, reqrep, reqirep reqtarpit, reqitarpit

  * rspadd, rspdel, rspidel, rspdeny, rspideny, rsprep, rspirep

a fatal error is emitted if one of these keyword is found during the
configuraion parsing.
2019-07-19 09:24:12 +02:00
Christopher Faulet
73e8ede156 MINOR: proxy: Remove support of the option 'http-tunnel'
The option 'http-tunnel' is deprecated and it was only used in the legacy HTTP
mode. So this option is now totally ignored and a warning is emitted during
HAProxy startup if it is found in a configuration file.
2019-07-19 09:24:12 +02:00
Christopher Faulet
fc9cfe4006 REORG: proto_htx: Move HTX analyzers & co to http_ana.{c,h} files
The old module proto_http does not exist anymore. All code dedicated to the HTTP
analysis is now grouped in the file proto_htx.c. So, to finish the polishing
after removing the legacy HTTP code, proto_htx.{c,h} files have been moved in
http_ana.{c,h} files.

In addition, all HTX analyzers and related functions prefixed with "htx_" have
been renamed to start with "http_" instead.
2019-07-19 09:24:12 +02:00
Christopher Faulet
a8a46e2041 CLEANUP: proto_http: Move remaining code from proto_http.c to proto_htx.c 2019-07-19 09:24:12 +02:00
Christopher Faulet
eb2754bef8 CLEANUP: proto_http: Remove unecessary includes and comments 2019-07-19 09:24:12 +02:00
Christopher Faulet
22dc248c2a CLEANUP: channel: Remove the unused flag CF_WAKE_CONNECT
This flag is tested or cleared but never set anymore.
2019-07-19 09:24:12 +02:00
Christopher Faulet
cc76d5b9a1 MINOR: proto_http: Remove the unused flag HTTP_MSGF_WAIT_CONN
This flag is set but never used. So remove it.
2019-07-19 09:24:12 +02:00
Christopher Faulet
c41547b66e MINOR: proto_http: Remove unused http txn flags
Many flags of the HTTP transction (TX_*) are now unused and useless. So the
flags TX_WAIT_CLEANUP, TX_HDR_CONN_*, TX_CON_CLO_SET and TX_CON_KAL_SET were
removed. Most of TX_CON_WANT_* were also removed. Only TX_CON_WANT_TUN has been
kept.
2019-07-19 09:24:12 +02:00
Christopher Faulet
67bb3bb0c2 MINOR: hlua: Remove useless test on TX_CON_WANT_* flags
When an HTTP applet is initialized, it is useless to force server-close mode on
the HTTP transaction because the connection mode is now handled by muxes. In
HTX, during analysis, the flag TX_CON_WANT_CLO is set by default in
htx_wait_for_request(), and TX_CON_WANT_SCL is never tested anywere.
2019-07-19 09:24:12 +02:00
Christopher Faulet
711ed6ae4a MAJOR: http: Remove the HTTP legacy code
First of all, all legacy HTTP analyzers and all functions exclusively used by
them were removed. So the most of the functions in proto_http.{c,h} were
removed. Only functions to deal with the HTTP transaction have been kept. Then,
http_msg and hdr_idx modules were entirely removed. And finally the structure
http_msg was lightened of all its useless information about the legacy HTTP. The
structure hdr_ctx was also removed because unused now, just like unused states
in the enum h1_state. Note that the memory pool "hdr_idx" was removed and
"http_txn" is now smaller.
2019-07-19 09:24:12 +02:00
Christopher Faulet
bcac786b36 MINOR: stream: Remove code relying on the legacy HTTP mode
Dump of streams information was updated to remove useless info. And it is not
necessary anymore to update msg->sov..
2019-07-19 09:18:27 +02:00
Christopher Faulet
3d11969a91 MAJOR: filters: Remove code relying on the legacy HTTP mode
This commit breaks the compatibility with filters still relying on the legacy
HTTP code. The legacy callbacks were removed (http_data, http_chunk_trailers and
http_forward_data).

For now, the filters must still set the flag FLT_CFG_FL_HTX to be used on HTX
streams.
2019-07-19 09:18:27 +02:00
Christopher Faulet
b7f8890b19 MINOR: stats: Remove code relying on the legacy HTTP mode
The part of the applet dealing with raw buffer was removed, for the HTTP part
only. So the old functions stats_send_http_headers() and
stats_send_http_redirect() were removed and replaced by the htx ones. The legacy
applet I/O handler was replaced by the htx one. And the parsing of POST data was
purged of the legacy HTTP code.
2019-07-19 09:18:27 +02:00
Christopher Faulet
386a0cda23 MINOR: flt_trace: Remove code relying on the legacy HTTP mode
The legacy HTTP callbacks were removed (trace_http_data,
trace_http_chunk_trailers and trace_http_forward_data). And the loop on the HTTP
headers was updated to only handle HTX messages.
2019-07-19 09:18:27 +02:00
Christopher Faulet
89f2b16530 MEDIUM: compression: Remove code relying on the legacy HTTP mode
The legacy HTTP callbacks were removed (comp_http_data, comp_http_chunk_trailers
and comp_http_forward_data). Functions emitting compressed chunks of data for
the legacy HTTP mode were also removed. The state for the compression filter was
updated accordingly. The compression context and the algorigttm used to compress
data are the only useful information remaining.
2019-07-19 09:18:27 +02:00
Christopher Faulet
95e7ea3c62 MEDIUM: cache: Remove code relying on the legacy HTTP mode
The applet delivering cached objects based on the legacy HTTP code was removed
as the filter callback cache_store_http_forward_data(). And the action analyzing
the response coming from the server to store it in the cache or not was purged
of the legacy HTTP code.
2019-07-19 09:18:27 +02:00
Christopher Faulet
12c28b6579 MINOR: http_act: Remove code relying on the legacy HTTP mode
Actions updating the request or the response start-line are concerned.
2019-07-19 09:18:27 +02:00
Christopher Faulet
a209796c80 MEDIUM: hlua: Remove code relying on the legacy HTTP mode
HTTP applets are concerned and functions of the HTTP class too.
2019-07-19 09:18:27 +02:00
Christopher Faulet
7d37fbb753 MEDIUM: backend: Remove code relying on the HTTP legacy mode
The L7 loadbalancing algorithms are concerned (uri, url_param and hdr), the
"sni" parameter on the server line and the "source" parameter on the server line
when used with "use_src hdr_ip()".
2019-07-19 09:18:27 +02:00
Christopher Faulet
4cb2828e96 MINOR: proxy: Don't adjust connection mode of HTTP proxies anymore
This was only used for the legacy HTTP mode where the connection mode was
handled by the HTTP analyzers. In HTX, the function http_adjust_conn_mode() does
nothing. The connection mode is handled by the muxes.
2019-07-19 09:18:27 +02:00
Christopher Faulet
28b18c5e21 CLEANUP: proxy: Remove the flag PR_O2_USE_HTX
This flag is now unused. So we can safely remove it.
2019-07-19 09:18:27 +02:00
Christopher Faulet
8f7fe1c9d7 MINOR: cache: Remove tests on the option 'http-use-htx'
All cache filters now store HTX messages. So it is useless to test if a cache is
used at the same time by a legacy HTTP proxy and an HTX one.
2019-07-19 09:18:27 +02:00
Christopher Faulet
280f85b153 MINOR: hlua: Remove tests on the option 'http-use-htx' to reject TCP applets
TCP applets are now forbidden for all HTTP proxies because all of them use the
HTX mode. So we don't rely anymore on the flag PR_O2_USE_HTX to do so.
2019-07-19 09:18:27 +02:00
Christopher Faulet
60d29b37b2 MINOR: proxy: Remove tests on the option 'http-use-htx' during H1 upgrade
To know if an upgrade from TCP to H1 must be performed, we now only need to know
if a non HTX stream is assigned to an HTTP backend. So we don't rely anymore on
the flag PR_O2_USE_HTX to handle such upgrades.
2019-07-19 09:18:27 +02:00
Christopher Faulet
3494c63770 MINOR: stream: Remove tests on the option 'http-use-htx' in stream_new()
All streams created for an HTTP proxy must now use the HTX internal
resprentation. So, it is no more necessary to test the flag PR_O2_USE_HTX. It
means a stream is an HTX stream if the frontend is an HTTP proxy or if the
frontend multiplexer, if any, set the flag MX_FL_HTX.
2019-07-19 09:18:27 +02:00
Christopher Faulet
0d79c67103 MINOR: config: Remove tests on the option 'http-use-htx'
All proxies have now the option PR_O2_USE_HTX set. So it is useless to still
test it when the validity of the configuratio is checked.
2019-07-19 09:18:27 +02:00
Christopher Faulet
6d1dd46917 MEDIUM: http_fetch: Remove code relying on HTTP legacy mode
Since the legacy HTTP mode is disbabled, all HTTP sample fetches work on HTX
streams. So it is safe to remove all code relying on HTTP legacy mode. Among
other things, the function smp_prefetch_http() was removed with the associated
macros CHECK_HTTP_MESSAGE_FIRST() and CHECK_HTTP_MESSAGE_FIRST_PERM().
2019-07-19 09:18:27 +02:00
Christopher Faulet
9a7e8ce4eb MINOR: stream: Rely on HTX analyzers instead of legacy HTTP ones
Since the legacy HTTP mode is disabled, old HTTP analyzers do nothing but call
those of the HTX. So, it is safe to directly call HTX analyzers from
process_stream().
2019-07-19 09:18:27 +02:00
Christopher Faulet
c985f6c5d8 MINOR: connection: Remove the multiplexer protocol PROTO_MODE_HTX
Since the legacy HTTP mode is disabled and no multiplexer relies on it anymore,
there is no reason to have 2 multiplexer protocols for the HTTP. So the protocol
PROTO_MODE_HTX was removed and all HTTP multiplexers use now PROTO_MODE_HTTP.
2019-07-19 09:18:27 +02:00
Christopher Faulet
5ed8353dcf CLEANUP: h2: Remove functions converting h2 requests to raw HTTP/1.1 ones
Because the h2 multiplexer only uses the HTX mode, following H2 functions were
removed :

  * h2_prepare_h1_reqline
  * h2_make_h1_request()
  * h2_make_h1_trailers()
2019-07-19 09:18:27 +02:00
Christopher Faulet
9b79a1025d MEDIUM: mux-h2: Remove support of the legacy HTTP mode
Now the H2 multiplexer only works in HTX. Code relying on the legacy HTTP mode
was removed.
2019-07-19 09:18:27 +02:00
Christopher Faulet
319303739a MAJOR: http: Deprecate and ignore the option "http-use-htx"
From this commit, the legacy HTTP mode is now definitely disabled. It is the
first commit of a long series to remove the legacy HTTP code. Now, all HTTP
processing is done using the HTX internal representation. Since the version 2.0,
It is the default mode. So now, it is no more possible to disable the HTX to
fallback on the legacy HTTP mode. If you still use "[no] option http-use-htx", a
warning will be emitted during HAProxy startup. Note the passthough multiplexer
is now only usable for TCP proxies.
2019-07-19 09:18:27 +02:00
Christopher Faulet
2bf43f0746 MINOR: htx: Use an array of char to store HTX blocks
Instead of using a array of (struct block), it is more natural and intuitive to
use an array of char. Indeed, not only (struct block) are stored in this array,
but also their payload.
2019-07-19 09:18:27 +02:00
Christopher Faulet
192c6a23d4 MINOR: htx: Deduce the number of used blocks from tail and head values
<head> and <tail> fields are now signed 32-bits integers. For an empty HTX
message, these fields are set to -1. So the field <used> is now useless and can
safely be removed. To know if an HTX message is empty or not, we just compare
<head> against -1 (it also works with <tail>). The function htx_nbblks() has
been added to get the number of used blocks.
2019-07-19 09:18:27 +02:00
Christopher Faulet
5a916f7326 CLEANUP: htx: Remove the unsued function htx_add_blk_type_size() 2019-07-19 09:18:27 +02:00
Christopher Faulet
3b21972061 DOC: htx: Update comments in HTX files
This patch may be backported to 2.0 to have accurate comments.
2019-07-19 09:18:27 +02:00
Christopher Faulet
c63231df55 MINOR: proto_htx: Don't stop forwarding when there is a post-connect processing
The TXN flag HTTP_MSGF_WAIT_CONN is now ignored on HTX streams. There is no
reason to not start to forward data in HTX. This is required for the legacy mode
and this was copied from it during the HTX development. But it is simply
useless.
2019-07-19 09:18:27 +02:00
Christopher Faulet
b5f86f116b MINOR: backend/htx: Don't rewind output data to set the sni on a srv connection
Rewind on output data is useless for HTX streams.
2019-07-19 09:18:27 +02:00
Christopher Faulet
304cc40536 MINOR: proto_htx: Add the function htx_return_srv_error()
Instead of using a function from the legacy HTTP, the HTX code now uses its own
one.
2019-07-19 09:18:27 +02:00
Christopher Faulet
00618aadf9 MINOR: proto_htx: Rely on the HTX function to apply a redirect rules
There is no reason to use the legacy HTTP version here, which falls back on the
HTX version in this case.
2019-07-19 09:18:27 +02:00
Christopher Faulet
75b4cd967d MINOR: proto_htx: Directly call htx_check_response_for_cacheability()
Instead of using the HTTP legacy version.
2019-07-19 09:18:27 +02:00
Christopher Faulet
4d0e263079 BUG/MINOR: hlua: Make the function txn:done() HTX aware
The function hlua_txn_done() still relying, for the HTTP, on the legacy HTTP
mode. Now, for HTX streams, it calls the function htx_reply_and_close().

This patch must be backported to 2.0 and 1.9.
2019-07-19 09:18:27 +02:00
Christopher Faulet
5f2c49f5ee BUG/MINOR: cache/htx: Make maxage calculation HTX aware
The function http_calc_maxage() was not updated to be HTX aware. So the header
"Cache-Control" on the response was never parsed to find "max-age" or "s-maxage"
values.

This patch must be backported to 2.0 and 1.9.
2019-07-19 09:18:27 +02:00
Christopher Faulet
7b889cb387 BUG/MINOR: http_htx: Initialize HTX error messages for TCP proxies
Since the HTX is the default mode for all proxies, HTTP and TCP, we must
initialize all HTX error messages for all HTX-aware proxies and not only for
HTTP ones. It is required to support HTTP upgrade for TCP proxies.

This patch must be backported to 2.0.
2019-07-19 09:18:27 +02:00
Christopher Faulet
cd76195061 BUG/MINOR: http_fetch: Fix http_auth/http_auth_group when called from TCP rules
These sample fetches rely on the static fnuction get_http_auth(). For HTX
streams and TCP proxies, this last one gets its HTX message from the request's
channel. When called from an HTTP rule, There is no problem. Bu when called from
TCP rules for a TCP proxy, this buffer is a raw buffer not an HTX message. For
instance, using the following TCP rule leads to a crash :

  tcp-request content accept if { http_auth(Users) }

To fix the bug, we must rely on the HTX message returned by the function
smp_prefetch_htx(). So now, the HTX message is passed as argument to the
function get_http_auth().

This patch must be backported to 2.0 and 1.9.
2019-07-19 09:18:27 +02:00
Christopher Faulet
6d36e1c282 MINOR: mux-h2: Don't adjust anymore the amount of data sent in h2_snd_buf()
Because the infinite forward is HTX aware, it is useless to tinker with the
number of bytes really sent. This was fixed long ago for the H1 and forgotten to
do so for the H2.
2019-07-19 09:18:27 +02:00
Willy Tarreau
09e0203ef4 BUG/MINOR: backend: do not try to install a mux when the connection failed
If si_connect() failed, do not try to install the mux nor to complete
the operations or add the connection to an idle list, and abort quickly
instead. No obvious side effects were identified, but continuing to
allocate some resources after something has already failed seems risky.

This was a result of a prior fix which already wanted to push this code
further : aa089d80b ("BUG/MEDIUM: server: Defer the mux init until after
xprt has been initialized.") but it ought to have pushed it even further
to maintain the error check just after si_connect().

To be backported to 2.0 and 1.9.
2019-07-18 16:49:11 +02:00
Willy Tarreau
69564b1c49 BUG/MEDIUM: http/htx: unbreak option http_proxy
The temporary connection used to hold the target connection's address
was missing a valid target, resulting in a 500 server error being
reported when trying to connect to a remote host. Strangely this
issue was introduced as a side effect of commit 2c52a2b9e ("MEDIUM:
connection: make mux->detach() release the connection") which at
first glance looks unrelated but solidly stops the bisection (note
that by default this part even crashes). It's suspected that the
error only happens when closing and destroys pending data in fact.

Given that this feature was broken very early during 1.8-rc1 development
it doesn't seem to be used often. This must be backported as far as 1.8.
2019-07-18 16:49:11 +02:00
Olivier Houchard
0ba6c85a0b BUG/MEDIUM: checks: Don't attempt to receive data if we already subscribed.
tcpcheck_main() might be called while we already attempted to subscribe, and
failed. There's no point in trying to call rcv_buf() again, and failing
would lead to us trying to subscribe again, which is not allowed.

This should be backported to 2.0 and 1.9.
2019-07-18 16:42:45 +02:00
Willy Tarreau
8280ea97a0 MINOR: applet: make appctx use their own pool
A long time ago, applets were seen as an alternative to connections,
and since their respective sizes were roughly equal it appeared wise
to share the same pool. Nowadays, connections got significantly larger
but applets are not that often used, except for the cache. However
applets are mostly complementary and not alternatives anymore, as
it's very possible not to have a back connection or to share one with
other streams.

The connections will soon lose their addresses and their size will
shrink so much that appctx won't fit anymore. Given that the old
benefits of sharing these pools have long disappeared, let's stop
doing this and have a dedicated pool for appctx.
2019-07-18 10:45:08 +02:00
Willy Tarreau
45726fd458 BUG/MINOR: dns: remove irrelevant dependency on a client connection
The do-resolve action tests for a client connection to the stream and
tries to get the client's address, otherwise it refrains from performing
the resolution. This really makes no sense at all and looks like an
earlier attempt at resolving the client's address to test that the
code was working. Further, it prevents the action from being used
from other places such as an autonomous applet for example, even if
at the moment this use case does not exist.

This patch simply removes the irrelevant test.

This can be backported to 2.0.
2019-07-17 14:11:57 +02:00
Willy Tarreau
7764a57d32 BUG/MEDIUM: threads: cpu-map designating a single thread/process are ignored
Since commit 81492c989 ("MINOR: threads: flatten the per-thread cpu-map"),
we don't keep the proc*thread matrix anymore to represent the full binding
possibilities, but only the proc and thread ones. The problem is that the
per-process binding is not the same for each thread and for the process,
and the proc[] array was assumed to store the per-proc first thread value
when doing this change. Worse, the logic present there tries to deal with
thread ranges and process ranges in a way which automatically exclused the
other possibility (since ranges cannot be used on both) but as such fails
to apply changes if neither the process nor the thread is expressed as a
range.

The real problem comes from the fact that specifying cpu-map 1/1 doesn't
yet reveal if the per-process mask or the per-thread mask needs to be
updated. In practice it's the thread one but then the current storage
doesn't allow to store the binding of the first thread of each other
process in nbproc>1 configurations.

When removing the proc*thread matrix, what ought to have been kept was
both the thread column for process 1 and the process line for threads 1,
but instead only the thread column was kept. This patch reintroduces the
storage of the configuration for the first thread of each process so that
it is again possible to store either the per-thread or per-process
configuration.

As a partial workaround for existing configurations, it is possible to
systematically indicate at least two processes or two threads at once
and map them by pairs or more so that at least two values are present
in the range. E.g :

  # set processes 1-4 to cpus 0-3 :

     cpu-map auto:1-4/1 0 1 2 3
  # or:
     cpu-map 1-2/1 0 1
     cpu-map 2-3/1 2 3

  # set threads 1-4 to cpus 0-3 :

     cpu-map auto:1/1-4 0 1 2 3
  # or :
     cpu-map 1/1-2 0 1
     cpu-map 3/3-4 2 3

This fix must be backported to 2.0.
2019-07-16 15:23:09 +02:00
Andrew Heberle
9723696759 MEDIUM: mworker-prog: Add user/group options to program section
This patch adds "user" and "group" config options to the "program"
section so the configured command can be run as a different user.
2019-07-15 16:43:16 +02:00
Willy Tarreau
7df8ca6296 BUG/MEDIUM: tcp-check: unbreak multiple connect rules again
The last connect rule used to be ignored and that was fixed by commit
248f1173f ("BUG/MEDIUM: tcp-check: single connect rule can't detect
DOWN servers") during 1.9 development. However this patch went a bit
too far by not breaking out of the loop after a pending connect(),
resulting in a series of failed connect() to be quickly skipped and
only the last one to be taken into account.

Technically speaking the series is not exactly skipped, it's just that
TCP checks suffer from a design issue which is that there is no
distinction between a new rule and this rule's completion in the
"connect" rule handling code. As such, when evaluating TCPCHK_ACT_CONNECT
a new connection is created regardless of any previous connection in
progress, and the previous result is ignored. It seems that this issue
is mostly specific to the connect action if we refer to the comments at
the top of the function, so it might be possible to durably address it
by reworking the connect state.

For now this patch does something simpler, it restores the behaviour
before the commit above consisting in breaking out of the loop when
the connection is in progress and after skipping comment rules. This
way we fall back to the default code waiting for completion.

This patch must be backported as far as 1.8 since the commit above
was backported there. Thanks to Jérôme Magnin for reporting and
bisecting this issue.
2019-07-15 11:10:36 +02:00
Willy Tarreau
9cca8dfc0b BUG/MINOR: mux-pt: do not pretend there's more data after a read0
Commit 8706c8131 ("BUG/MEDIUM: mux_pt: Always set CS_FL_RCV_MORE.")
was a bit excessive in setting this flag, it refrained from removing
it after read0 unless it was on an empty call. The problem it causes
is that read0 is thus ignored on the first call :

  $ strace -tts200 -e trace=recvfrom,epoll_wait,sendto  ./haproxy -db -f tcp.cfg
  06:34:23.956897 recvfrom(9, "blah\n", 15360, 0, NULL, NULL) = 5
  06:34:23.956938 recvfrom(9, "", 15355, 0, NULL, NULL) = 0
  06:34:23.956958 recvfrom(9, "", 15355, 0, NULL, NULL) = 0
  06:34:23.957033 sendto(8, "blah\n", 5, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 5
  06:34:23.957229 epoll_wait(3, [{EPOLLIN|EPOLLHUP|EPOLLRDHUP, {u32=8, u64=8}}], 200, 0) = 1
  06:34:23.957297 recvfrom(8, "", 15360, 0, NULL, NULL) = 0

If CO_FL_SOCK_RD_SH is reported by the transport layer, it indicates the
read0 was already seen thus we must not try again and we must immedaitely
report it. The simple fix consists in removing the test on ret==0 :

  $ strace -tts200 -e trace=recvfrom,epoll_wait,sendto  ./haproxy -db -f tcp.cfg
  06:44:21.634835 recvfrom(9, "blah\n", 15360, 0, NULL, NULL) = 5
  06:44:21.635020 recvfrom(9, "", 15355, 0, NULL, NULL) = 0
  06:44:21.635056 sendto(8, "blah\n", 5, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 5
  06:44:21.635269 epoll_wait(3, [{EPOLLIN|EPOLLHUP|EPOLLRDHUP, {u32=8, u64=8}}], 200, 0) = 1
  06:44:21.635330 recvfrom(8, "", 15360, 0, NULL, NULL) = 0

The issue is minor, it only results in extra syscalls and CPU usage.
This fix should be backported to 2.0 and 1.9.
2019-07-15 06:47:54 +02:00
Olivier Houchard
4bd5867627 BUG/MEDIUM: streams: Don't redispatch with L7 retries if redispatch isn't set.
Move the logic to decide if we redispatch to a new server from
sess_update_st_cer() to a new inline function, stream_choose_redispatch(), and
use it in do_l7_retry() instead of just setting the state to SI_ST_REQ.
That way, when using L7 retries, we won't redispatch the request to another
server except if "option redispatch" is used.

This should be backported to 2.0.
2019-07-12 16:17:50 +02:00
Olivier Houchard
29cac3c5f7 BUG/MEDIUM: streams: Don't give up if we couldn't send the request.
In htx_request_forward_body(), don't give up if we failed to send the request,
and we have L7 retries activated. If we do, we will not retry when we should.

This should be backported to 2.0.
2019-07-12 16:17:50 +02:00
Dave Pirotte
234740f65d BUG/MINOR: mux-h1: Correctly report Ti timer when HTX and keepalives are used
When HTTP keepalives are used in conjunction with HTX, the Ti timer
reports the elapsed time since the beginning of the connection instead
of the end of the previous request as stated in the documentation. Th,
Tq and Tt also report incorrectly as a result.

When creating a new h1s, check if it is the first request on the
connection. If not, set the session create times to the current
timestamp rather than the initial session accept timestamp. This makes
the logged timers behave as stated in the documentation.

This fix should be backported to 1.9 and 2.0.
2019-07-12 16:14:12 +02:00
Christopher Faulet
37243bc61f BUG/MEDIUM: mux-h1: Don't release h1 connection if there is still data to send
When the h1 stream (h1s) is detached, If the connection is not really shutdown
yet and if there is still some data to send, the h1 connection (h1c) must not be
released. Otherwise, the remaining data are lost. This bug was introduced by the
commit 3ac0f430 ("BUG/MEDIUM: mux-h1: Always release H1C if a shutdown for
writes was reported").

Here is the conditions to release an h1 connection when the h1 stream is
detached :

  * An error or a shutdown write occurred on the connection
    (CO_FL_ERROR|CO_FL_SOCK_WR_SH)

  * an error, an h2 upgrade or full shutdown occurred on the h1 connection
    (H1C_F_CS_ERROR||H1C_F_UPG_H2C|H1C_F_CS_SHUTDOWN)

  * A shutdown write is pending on the h1 connection and there is no more data
    in the output buffer
    ((h1c->flags & H1C_F_CS_SHUTW_NOW) && !b_data(&h1c->obuf))

If one of these conditions is fulfilled, the h1 connection is
released. Otherwise, the release is delayed. If we are waiting to send remaining
data, a timeout is set.

This patch must be backported to 2.0 and 1.9. It fixes the issue #164.
2019-07-12 10:06:41 +02:00
Willy Tarreau
f2cb169487 BUG/MAJOR: listener: fix thread safety in resume_listener()
resume_listener() can be called from a thread not part of the listener's
mask after a curr_conn has gone lower than a proxy's or the process' limit.
This results in fd_may_recv() being called unlocked if the listener is
bound to only one thread, and quickly locks up.

This patch solves this by creating a per-thread work_list dedicated to
listeners, and modifying resume_listener() so that it bounces the listener
to one of its owning thread's work_list and waking it up. This thread will
then call resume_listener() again and will perform the operation on the
file descriptor itself. It is important to do it this way so that the
listener's state cannot be modified while the listener is being moved,
otherwise multiple threads can take conflicting decisions and the listener
could be put back into the global queue if the listener was used at the
same time.

It seems like a slightly simpler approach would be possible if the locked
list API would provide the ability to return a locked element. In this
case the listener would be immediately requeued in dequeue_all_listeners()
without having to go through resume_listener() with its associated lock.

This fix must be backported to all versions having the lock-less accept
loop, which is as far as 1.8 since deadlock fixes involving this feature
had to be backported there. It is expected that the code should not differ
too much there. However, previous commit "MINOR: task: introduce work lists"
will be needed as well and should not present difficulties either. For 1.8,
the commits introducing thread_mask() and LIST_ADDED() will be needed as
well, either backporting my_flsl() or switching to my_ffsl() will be OK,
and some changes will have to be performed so that the init function is
properly called (and maybe the deinit one can be dropped).

In order to test for the fix, simply set up a multi-threaded frontend with
multiple bind lines each attached to a single thread (reproduced with 16
threads here), set up a very low maxconn value on the frontend, and inject
heavy traffic on all listeners in parallel with slightly more connections
than the configured limit ( typically +20%) so that it flips very
frequently. If the bug is still there, at some point (5-20 seconds) the
traffic will go much lower or even stop, either with spinning threads or
not.
2019-07-12 09:07:48 +02:00
Willy Tarreau
64e6012eb9 MINOR: task: introduce work lists
Sometimes we need to delegate some list processing to a function running
on another thread. In this case the list element will simply be queued
into a dedicated self-locked list and the task responsible for this list
will be woken up, calling the associated function which will run over the
list.

This is what work_list does. Such lists will be dedicated to a limited
type of work but will significantly ease such remote handling. A function
is provided to create these per-thread lists, their tasks and to properly
bind each task to a distinct thread, so that the caller only has to store
the resulting pointer to the start of the structure.

These structures should not be abused though as each head will consume
4 pointers per thread, hence 32 bytes per thread or 2 kB for 64 threads.
2019-07-12 09:07:48 +02:00
Olivier Houchard
4be7190c10 BUG/MEDIUM: servers: Fix a race condition with idle connections.
When we're purging idle connections, there's a race condition, when we're
removing the connection from the idle list, to add it to the list of
connections to free, if the thread owning the connection tries to free it
at the same time.
To fix this, simply add a per-thread lock, that has to be hold before
removing the connection from the idle list, and when, in conn_free(), we're
about to remove the connection from every list. That way, we know for sure
the connection will stay valid while we remove it from the idle list, to add
it to the list of connections to free.
This should happen rarely enough that it shouldn't have any impact on
performances.
This has not been reported yet, but could provoke random segfaults.

This should be backported to 2.0.
2019-07-11 16:16:38 +02:00
Frédéric Lécaille
51596c166b CLEANUP: proto_tcp: Remove useless header inclusions.
I guess "sys/un.h" and "sys/stat.h" were included for debugging purposes when
"proto_tcp.c" was initially created. There are no more useful.
2019-07-11 10:40:20 +02:00
David Carlier
7df4185f3c BUG/MEDIUM: da: cast the chunk to string.
in fetch mode, the output was incorrect, setting the type to string
explicitally.

This should be backported to all stable versions.
2019-07-11 10:20:09 +02:00
Olivier Houchard
bc89ad8d94 BUG/MEDIUM: checks: Don't attempt to read if we destroyed the connection.
In event_srv_chk_io(), only call __event_srv_chk_r() if we did not subscribe
for reading, and if wake_srv_chk() didn't return -1, as it would mean it
just destroyed the connection and the conn_stream, and attempting to use
those to recv data would lead to a crash.

This should be backported to 1.9 and 2.0.
2019-07-10 16:29:12 +02:00
Willy Tarreau
828675421e MINOR: pools: always pre-initialize allocated memory outside of the lock
When calling mmap(), in general the system gives us a page but does not
really allocate it until we first dereference it. And it turns out that
this time is much longer than the time to perform the mmap() syscall.
Unfortunately, when running with memory debugging enabled, we mmap/munmap()
each object resulting in lots of such calls and a high contention on the
allocator. And the first accesses to the page being done under the pool
lock is extremely damaging to other threads.

The simple fact of writing a 0 at the beginning of the page after
allocating it and placing the POOL_LINK pointer outside of the lock is
enough to boost the performance by 8x in debug mode and to save the
watchdog from triggering on lock contention. This is what this patch
does.
2019-07-09 10:40:33 +02:00
Willy Tarreau
3e853ea74d MINOR: pools: release the pool's lock during the malloc/free calls
The malloc and free calls and especially the underlying mmap/munmap()
can occasionally take a huge amount of time and even cause the thread
to sleep. This is visible when haproxy is compiled with DEBUG_UAF which
causes every single pool allocation/free to allocate and release pages.
In this case, when using the locked pools, the watchdog can occasionally
fire under high contention (typically requesting 40000 1M objects in
parallel over 8 threads). Then, "perf top" shows that 50% of the CPU
time is spent in mmap() and munmap(). The reason the watchdog fires is
because some threads spin on the pool lock which is held by other threads
waiting on mmap() or munmap().

This patch modifies this so that the pool lock is released during these
syscalls. Not only this allows other threads to request try to allocate
their data in parallel, but it also considerably reduces the lock
contention.

Note that the locked pools are only used on small architectures where
high thread counts would not make sense, so this will not provide any
benefit in the general case. However it makes the debugging versions
way more stable, which is always appreciated.
2019-07-09 10:40:33 +02:00
Lukas Tribus
4979916134 BUG/MINOR: ssl: revert empty handshake detection in OpenSSL <= 1.0.2
Commit 54832b97 ("BUILD: enable several LibreSSL hacks, including")
changed empty handshake detection in OpenSSL <= 1.0.2 and LibreSSL,
from accessing packet_length directly (not available in LibreSSL) to
calling SSL_state() instead.

However, SSL_state() appears to be fully broken in both OpenSSL and
LibreSSL.

Since there is no possibility in LibreSSL to detect an empty handshake,
let's not try (like BoringSSL) and restore this functionality for
OpenSSL 1.0.2 and older, by reverting to the previous behavior.

Should be backported to 2.0.
2019-07-09 04:47:18 +02:00
Olivier Houchard
a1ab97316f BUG/MEDIUM: servers: Don't forget to set srv_cs to NULL if we can't reuse it.
In connect_server(), if there were already a CS assosciated with the stream,
but we can't reuse it, because the target is different (because we tried a
previous connection, it failed, and we use redispatch so we switched servers),
don't forget to set srv_cs to NULL. Otherwise, if we end up reusing another
connection, we would consider we already have a conn_stream, and we won't
create a new one, so we'd have a new connection but we would not be able to
use it.
This can explain frozen streams and connections stuck in CLOSE_WAIT when
using redispatch.

This should be backported to 1.9 and 2.0.
2019-07-08 16:32:58 +02:00
Christopher Faulet
037b3ebd35 BUG/MEDIUM: stream-int: Don't rely on CF_WRITE_PARTIAL to unblock opposite si
In the function stream_int_notify(), when the opposite stream-interface is
blocked because there is no more room into the input buffer, if the flag
CF_WRITE_PARTIAL is set on this buffer, it is unblocked. It is a way to unblock
the reads on the other side because some data was sent.

But it is a problem during the fast-forwarding because only the stream is able
to remove the flag CF_WRITE_PARTIAL. So it is possible to have this flag because
of a previous send while the input buffer of the opposite stream-interface is
now full. In such case, the opposite stream-interface will be woken up for
nothing because its input buffer is full. If the same happens on the opposite
side, we will have a loop consumming all the CPU.

To fix the bug, the opposite side is now only notify if there is some available
room in its input buffer in the function si_cs_send(), so only if some data was
sent.

This patch must be backported to 2.0 and 1.9.
2019-07-05 14:26:15 +02:00
Christopher Faulet
86162db15c MINOR: stream-int: Factorize processing done after sending data in si_cs_send()
In the function si_cs_send(), what is done when an error occurred on the
connection or the conn_stream or when some successfully data was send via a pipe
or the channel's buffer may be factorized at the function. It slightly simplify
the function.

This patch must be backported to 2.0 and 1.9 because a bugfix depends on it.
2019-07-05 14:26:15 +02:00
Christopher Faulet
0e54d547f1 BUG/MINOR: mux-h1: Don't process input or ouput if an error occurred
It is useless to proceed if an error already occurred. Instead, it is better to
wait it will be catched by the stream or the connection, depending on which is
the first one to detect it.

This patch must be backported to 2.0.
2019-07-05 14:26:15 +02:00
Christopher Faulet
f8db73efbe BUG/MEDIUM: mux-h1: Handle TUNNEL state when outgoing messages are formatted
Since the commit 94b2c7 ("MEDIUM: mux-h1: refactor output processing"), the
formatting of outgoing messages is performed on the message state and no more on
the HTX blocks read. But the TUNNEL state was left out. So, the HTTP tunneling
using the CONNECT method or switching the protocol (for instance,
the WebSocket) does not work.

This issue was reported on Github. See #131. This patch must be backported to
2.0.
2019-07-05 14:26:15 +02:00
Christopher Faulet
16b2be93ad BUG/MEDIUM: lb_fas: Don't test the server's lb_tree from outside the lock
In the function fas_srv_reposition(), the server's lb_tree is tested from
outside the lock. So it is possible to remove it after the test and then call
eb32_insert() in fas_queue_srv() with a NULL root pointer, which is
invalid. Moving the test in the scope of the lock fixes the bug.

This issue was reported on Github, issue #126.

This patch must be backported to 2.0, 1.9 and 1.8.
2019-07-05 14:26:15 +02:00
Christopher Faulet
8f1aa77b42 BUG/MEDIUM: http/applet: Finish request processing when a service is registered
In the analyzers AN_REQ_HTTP_PROCESS_FE/BE, when a service is registered, it is
important to not interrupt remaining processing but just the http-request rules
processing. Otherwise, the part that handles the applets installation is
skipped.

Among the several effects, if the service is registered on a frontend (not a
listen), the forwarding of the request is skipped because all analyzers are not
set on the request channel. If the service does not depends on it, the response
is still produced and forwarded to the client. But the stream is infinitly
blocked because the request is not fully consumed. This issue was reported on
Github, see #151.

So this bug is fixed thanks to the new action return ACT_RET_DONE. Once a
service is registered, the action process_use_service() still returns
ACT_RET_STOP. But now, only rules processing is stopped. As a side effet, the
action http_action_reject() must now return ACT_RET_DONE to really stop all
processing.

This patch must be backported to 2.0. It depends on the commit introducing the
return code ACT_RET_DONE.
2019-07-05 14:26:14 +02:00
Christopher Faulet
2e4843d1d2 MINOR: action: Add the return code ACT_RET_DONE for actions
This code should be now used by action to stop at the same time the rules
processing and the possible following processings. And from its side, the return
code ACT_RET_STOP should be used to only stop rules processing.

So concretely, for TCP rules, there is no changes. ACT_RET_STOP and ACT_RET_DONE
are handled the same way. However, for HTTP rules, ACT_RET_STOP should now be
mapped on HTTP_RULE_RES_STOP and ACT_RET_DONE on HTTP_RULE_RES_DONE. So this
way, a action will have the possibilty to stop all processing or only rules
processing.

Note that changes about the TCP is done in this commit but changes about the
HTTP will be done in another one because it will fix a bug in the same time.

This patch must be backported to 2.0 because a bugfix depends on it.
2019-07-05 14:26:14 +02:00
Frédéric Lécaille
1b9423d214 MINOR: server: Add "no-tfo" option.
Simple patch to add "no-tfo" option to "default-server" and "server" lines
to disable any usage of TCP fast open.

Must be backported to 2.0.
2019-07-04 14:45:52 +02:00
Olivier Houchard
8d82db70a5 BUG/MEDIUM: servers: Authorize tfo in default-server.
There's no reason to forbid using tfo with default-server, so allow it.

This should be backported to 2.0.
2019-07-04 13:34:25 +02:00
Olivier Houchard
2ab3dada01 BUG/MEDIUM: connections: Make sure we're unsubscribe before upgrading the mux.
Just calling conn_force_unsubscribe() from conn_upgrade_mux_fe() is not
enough, as there may be multiple XPRT involved. Instead, require that
any user of conn_upgrade_mux_fe() unsubscribe itself before calling it.
This should fix upgrading a TCP connection to HTX when using SSL.

This should be backported to 2.0.
2019-07-03 13:57:30 +02:00
Christopher Faulet
9060fc02b5 BUG/MINOR: hlua/htx: Respect the reserve when HTX data are sent
The previous commit 7e145b3e2 ("BUG/MINOR: hlua: Don't use
channel_htx_recv_max()") is buggy. The buffer's reserve must be respected.

This patch must be backported to 2.0 and 1.9.
2019-07-03 11:47:20 +02:00
Christopher Faulet
7e145b3e24 BUG/MINOR: hlua: Don't use channel_htx_recv_max()
The function htx_free_data_space() must be used intead. Otherwise, if there are
some output data not already forwarded, the maximum amount of data that may be
inserted into the buffer may be greater than what we can really insert.

This patch must be backported to 2.0 and 1.9.
2019-07-02 21:32:45 +02:00
Olivier Houchard
f494957980 BUG/MEDIUM: checks: Make sure the tasklet won't run if the connection is closed.
wake_srv_chk() can be called from conn_fd_handler(), and may decide to
destroy the conn_stream and the connection, by calling cs_close(). If that
happens, we have to make sure the tasklet isn't scheduled to run, or it will
probably crash trying to access the connection or the conn_stream.
This fixes a crash that can be seen when using tcp checks.

This should be backported to 1.9 and 2.0.
For 1.9, the call should be instead :
task_remove_from_tasklet_list((struct task *)check->wait_list.task);
That function was renamed in 2.0.
2019-07-02 17:45:35 +02:00
Olivier Houchard
6c7e96a3e1 BUG/MEDIUM: connections: Always call shutdown, with no linger.
Revert commit fe4abe62c7.
The goal was to make sure for health-checks, we would not get sockets in
TIME_WAIT. To do so, we would not call shutdown() if linger_risk is set.
However that is wrong, and that means shutw would never be forwarded to
the server, and thus we could get connection that are never properly closed.
Instead, to fix the original problem as described here :
https://www.mail-archive.com/haproxy@formilux.org/msg34080.html
Just make sure the checks code call cs_shutr() before calling cs_shutw().
If shutr has been called, conn_sock_shutw() will make no attempt to call
shutdown(), as it knows close() will be called.
We should really review and revamp the shutr/shutw code, as described in
github issue #142.

This should be backported to 1.9 and 2.0.
2019-07-02 16:40:55 +02:00
Christopher Faulet
b8fc304e8f BUG/MINOR: mux-h1: Don't return the empty chunk on HEAD responses
HEAD responses must not have any body payload. But, because of a bug, for chunk
reponses, the empty chunk was always added.

This patch fixes the Github issue #146. It must be backported to 2.0 and 1.9.
2019-07-01 16:24:01 +02:00
Christopher Faulet
5433a0b021 BUG/MINOR: mux-h1: Skip trailers for non-chunked outgoing messages
Unlike H1, H2 messages may contains trailers while the header "Content-Length"
is set. Indeed, because of the framed structure of HTTP/2, it is no longer
necessary to use the chunked transfer encoding. So Trailing HEADERS frames,
after all DATA frames, may be added on messages with an explicit content length.

But in H1, it is impossible to have trailers on non-chunked messages. So when
outgoing messages are formatted by the H1 multiplexer, if the message is not
chunked, all trailers must be dropped.

This patch must be backported to 2.0 and 1.9. However, the patch will have to be
adapted for the 1.9.
2019-07-01 16:24:01 +02:00
Willy Tarreau
2df8cad0fe BUG/MEDIUM: checks: unblock signals in external checks
As discussed in issue #140, processes are forked with signals blocked
resulting in haproxy's kill being ignored. This happens when the command
takes more time to complete than the configured check timeout or interval.
Just calling "sleep 30" every second makes the problem obvious.

The fix simply consists in unblocking the signals in the child after the
fork. It needs to be backported to all stable branches containing external
checks and where signals are blocked on startup. It's unclear when it
started, but the following config exhibits the issue :

  global
    external-check

  listen www
    bind :8001
    timeout client 5s
    timeout server 5s
    timeout connect 5s
    option external-check
    external-check command "$PWD/sleep10.sh"
    server local 127.0.0.1:80 check inter 200

  $ cat sleep10.sh
  #!/bin/sh
  exec /bin/sleep 10

The "sleep" processes keep accumulating for 10 seconds and stabilize
around 25 when the bug is present. Just issuing "killall sleep" has no
effect on them, and stopping haproxy leaves these processes behind.
2019-07-01 16:03:44 +02:00
William Lallemand
ad03288e6b BUG/MINOR: mworker/cli: don't output a \n before the response
When using a level lower than admin on the master CLI, a \n is output
before the response, this is caused by the response of the "operator" or
"user" that are sent before the actual command.

To fix this problem we introduce the flag APPCTX_CLI_ST1_NOLF which ask
a command response to not be followed by the final \n.
This patch made a special case with the command operator and user
followed by a - so they are not followed by \n.

This patch must be backported to 2.0 and 1.9.
2019-07-01 15:34:11 +02:00
Christopher Faulet
3ac0f43020 BUG/MEDIUM: mux-h1: Always release H1C if a shutdown for writes was reported
We must take care of this when the stream is detached from the
connection. Otherwise, on the server side, the connexion is inserted in the list
of idle connections of the session. But when reused, because the shutdown for
writes was already catched, nothing is sent to the server and the session is
blocked with a freezed connection.

This patch must be backported to 2.0 and 1.9. It is related to the issue #136
reported on Github.
2019-06-28 17:58:15 +02:00
Olivier Houchard
e488ea865a BUG/MEDIUM: ssl: Don't attempt to set alpn if we're not using SSL.
Checks use ssl_sock_set_alpn() to set the ALPN if check-alpn is used, however
check-alpn failed to check if the connection was indeed using SSL, and thus,
would crash if check-alpn was used on a non-SSL connection. Fix this by
making sure the connection uses SSL before attempting to set the ALPN.

This should be backported to 2.0 and 1.9.
2019-06-28 14:12:28 +02:00
Christopher Faulet
d87d3fab25 BUG/MINOR: mux-h1: Make format errors during output formatting fatal
These errors are unexpected at this staged and there is not much more to do than
to close the connection and leave. So now, when it happens, the flag
H1C_F_CS_ERROR is set on the H1 connection and the flag HTX_FL_PARSING_ERROR is
set on the channel's HTX message.

This patch must be backported to 2.0 and 1.9.
2019-06-26 15:23:06 +02:00
Christopher Faulet
e5438b749c BUG/MEDIUM: mux-h1: Use buf_room_for_htx_data() to detect too large messages
During headers parsing, an error is returned if the message is too large and
does not fit in the input buffer. The mux h1 used the function b_full() to do
so. But to allow zero copy transfers, in h1_recv(), the input buffer is
pre-aligned and thus few bytes remains always free.

To fix the bug, as during the trailers parsing, the function
buf_room_for_htx_data() should be used instead.

This patch must be backported to 2.0 and 1.9.
2019-06-26 15:23:06 +02:00
Christopher Faulet
1d5ec0944f BUG/MEDIUM: proto_htx: Don't add EOM on 1xx informational messages
Since the commit b75b5eaf ("MEDIUM: htx: 1xx messages are now part of the final
reponses"), these messages are part of the response and should not contain
EOM. This block is skipped during responses parsing, but analyzers still add it
for "100-Continue" and "103-Eraly-Hints". It can also be added for error files
with 1xx status code.

Now, when HAProxy generate such transitional responses, it does not emit EOM
blocks. And informational messages are now forbidden in error files.

This patch must be backported to 2.0.
2019-06-26 15:23:06 +02:00
Tim Duesterhus
2164800c1b BUG/MINOR: log: Detect missing sampling ranges in config
Consider a config like:

    global
    	log 127.0.0.1:10001 sample :10 local0

No sampling ranges are given here, leading to NULL being passed
as the first argument to qsort.

This configuration does not make sense anyway, a log without ranges
would never log. Thus output an error if no ranges are given.

This bug was introduced in d95ea2897e.
This fix must be backported to HAProxy 2.0.
2019-06-26 11:15:49 +02:00
Christopher Faulet
2f6d3c0d65 BUG/MINOR: memory: Set objects size for pools in the per-thread cache
When a memory pool is created, it may be allocated from a static array. This
happens for "most common" pools, allocated first. Objects of these pools may
also be cached in a pool cache. Of course, to not cache too much entries, we
track the number of cached objects and the total size of the cache.

But the objects size of each pool in the cache (ie, pool_cache[tid][idx].size,
where tid is the thread-id and idx is the index of the pool) was never set. So
the total size of the cache was never limited. Now when a pool is created, if
these objects may be cached, we set the corresponding objects size in the pool
cache.

This patch must be backported to 2.0 and 1.9.
2019-06-26 09:57:49 +02:00
Christopher Faulet
c2518a53ae BUG/MAJOR: mux-h1: Don't crush trash chunk area when outgoing message is formatted
When an outgoing HTX message is formatted before sending it, a trash chunk is
used to do the formatting. Its content is then copied into the output buffer of
the H1 connection. There are some tricks to avoid this last copy. First, if
possible we perform a zero-copy by swapping the area of the HTX buffer with the
one of the output buffer. If zero-copy is not possible, but if the output buffer
is empty, we don't use a trash chunk. To do so, we change the area of the trash
chunk to point on the one of the output buffer. But it is terribly wrong. Trash
chunks are global variables, allocated statically. If the area is changed, the
old one is lost. Worst, the area of the output buffer is dynamically allocated,
so it is released when emptied, leaving the trash chunk with a freed area (in
fact, it is a bit more complicated because buffers are allocated from a memory
pool).

So, honestly, I don't know why we never experienced any problem because this bug
till now. To fix it, we still use a temporary buffer, but we assign it to a
trash chunk only when other solutions were excluded. This way, we never
overwrite the area of a trash chunk.

This patch must be backported to 2.0 and 1.9.
2019-06-26 09:57:49 +02:00
Christopher Faulet
2bce046eea BUG/MINOR: htx: Save hdrs_bytes when the HTX start-line is replaced
The HTX start-line contains the number of bytes held by all headers as seen by
the mux during the parsing. So it must not be updated during analysis. It was
done when the start-line is replaced, so this update was removed at this
place. But we still save it from the old start-line to not loose it. It should
not be used outside the mux, but there is no reason to skip it. It is a bug,
however it should have no impact.

This patch must be backported to 2.0.
2019-06-26 09:57:49 +02:00
William Lallemand
1933801136 BUG/MEDIUM: mworker/cli: command pipelining doesn't work anymore
Since commit 829bd471 ("MEDIUM: stream: rearrange the events to remove
the loop"), the pipelining in the master CLI does not work anymore.

Indeed when doing:

  echo "@1 show info; @2 show info; @3 show info" | socat /tmp/haproxy.master -

the CLI will only show the response of the first command.

When debugging we can observe that the command is sent, but the client
closes the connection before receiving the response.

The problem is that the flag CF_READ_NULL is not cleared when we
reiniate the flags of the response and we rely on this flag to close.

Must be backported in 2.0
2019-06-25 18:15:46 +02:00
Olivier Houchard
0ff28651c1 BUG/MEDIUM: ssl: Don't do anything in ssl_subscribe if we have no ctx.
In ssl_subscribe(), make sure we have a ssl_sock_ctx before doing anything.
When ssl_sock_close() is called, it wakes any subscriber up, and that
subscriber may decide to subscribe again, for some reason. If we no longer
have a context, there's not much we can do.

This should be backported to 2.0.
2019-06-24 19:00:16 +02:00
Olivier Houchard
6c6dc58da0 BUG/MEDIUM: connections: Always add the xprt handshake if needed.
In connect_server(), we used to only call xprt_add_hs() if CO_FL_SEND_PROXY
was set during the function call, we would not do it if the flag was set
before connect_server() was called. The rational at the time was if the flag
was already set, then the XPRT was already present. But now the xprt_handshake
always removes itself, so we have to re-add it each time, or it wouldn't be
done if the first connection attempt failed.
While I'm there, check any non-ssl handshake flag, instead of just
CO_FL_SEND_PROXY, or we'd miss the SOCKS4 flags.

This should be backported to 2.0.
2019-06-24 19:00:16 +02:00
Olivier Houchard
c31e2cbd28 BUG/MEDIUM: stream_interface: Don't add SI_FL_ERR the state is < SI_ST_CON.
Only add SI_FL_ERR if the stream_interface is connected, or is attempting
a connection. We may get there because the stream_interface's tasklet
was woken up, but before it actually runs, process_stream() may be called,
detect that there were an error, and change the state of the stream_interface
to SI_ST_TAR. When the stream_interface's tasklet then run, the connection
may still have CO_FL_ERROR, but that error was already accounted for, so
just ignore it.

This should be backported to 2.0.
2019-06-24 19:00:16 +02:00
William Lallemand
16866670dd BUG/MEDIUM: mworker: don't call the thread and fdtab deinit
Before switching to wait mode, the per thread deinit should not be
called, because we didn't initiate threads and fdtab.

The problem is that the master could crash if we try to reload HAProxy

The commit 944e619 ("MEDIUM: mworker: wait mode use standard init code
path") removed the deinit code by accident, but its fix 7c756a8
("BUG/MEDIUM: mworker: fix FD leak upon reload") was incomplete and did
not took care of the WAIT_MODE.

This fix must be backported in 1.9 and 2.0
2019-06-24 17:54:05 +02:00
Tim Duesterhus
b298613072 BUG/MINOR: spoe: Fix memory leak if failing to allocate memory
Technically harmless, but it annoys clang analyzer.

This bug was introduced in 336d3ef0e7.
This fix should be backported to HAProxy 1.9+.
2019-06-24 14:38:15 +02:00
Tim Duesterhus
2c9e274f45 BUG/MINOR: mworker-prog: Fix segmentation fault during cfgparse
Consider this configuration:

    frontend fe_http
    	mode http
    	bind *:8080

    	default_backend be_http

    backend be_http
    	mode http
    	server example example.com:80

    program foo bar

Running with valgrind results in:

    ==16252== Invalid read of size 8
    ==16252==    at 0x52AE3F: cfg_parse_program (mworker-prog.c:233)
    ==16252==    by 0x4823B3: readcfgfile (cfgparse.c:2180)
    ==16252==    by 0x47BCED: init (haproxy.c:1649)
    ==16252==    by 0x404E22: main (haproxy.c:2714)
    ==16252==  Address 0x48 is not stack'd, malloc'd or (recently) free'd

Check whether `ext_child` is valid before attempting to free it and its
contents.

This bug was introduced in 9a1ee7ac31.
This fix must be backported to HAProxy 2.0.
2019-06-24 10:09:00 +02:00
Willy Tarreau
76a80c710c BUILD: mworker: silence two printf format warnings around getpid()
getpid() is documented as returning a pit pid_t result, not
necessarily an int. This causes a build warning on Solaris 10
because of '%d' or '%u' are used in the format passed to snprintf().
Let's just cast the result as an int (respectively unsigned int).

This can be backported to 2.0 and possibly older versions though
it really has no impact.
2019-06-22 07:57:56 +02:00
Frédéric Lécaille
9417f4534a BUG/MAJOR: sample: Wrong stick-table name parsing in "if/unless" ACL condition.
This bug was introduced by 1b8e68e commit which supposed the stick-table was always
stored in struct arg at parsing time. This is never the case with the usage of
"if/unless" conditions in stick-table declared as backends. In this case, this is
the name of the proxy which must be considered as the stick-table name.

This must be backported to 2.0.
2019-06-21 09:48:28 +02:00
Christopher Faulet
1ae2a88781 BUG/MEDIUM: lb_fwlc: Don't test the server's lb_tree from outside the lock
In the function fwlc_srv_reposition(), the server's lb_tree is tested from
outside the lock. So it is possible to remove it after the test and then call
eb32_insert() in fwlc_queue_srv() with a NULL root pointer, which is
invalid. Moving the test in the scope of the lock fixes the bug.

This issue was reported on Github, issue #126.

This patch must be backported to 2.0, 1.9 and 1.8.
2019-06-19 13:55:57 +02:00
Christopher Faulet
4f09ec812a BUG/MEDIUM: mux-h2: Remove the padding length when a DATA frame size is checked
When a DATA frame is processed for a message with a content-length, we first
take care to not have a frame size that exceeds the remaining to
read. Otherwise, an error is triggered. But we must remove the padding length
from the frame size because the padding is not included in the announced
content-length.

This patch must be backported to 2.0 and 1.9.
2019-06-19 10:06:31 +02:00
Christopher Faulet
dd2a5620d5 BUG/MEDIUM: mux-h2: Reset padlen when several frames are demux
In the function h2_process_demux(), if several frames are parsed, the padding
length must be reset between each frame. Otherwise we may wrongly think a frame
has a padding block because the previous one was padded.

This patch must be backported to 2.0 and 1.9.
2019-06-19 10:06:31 +02:00
Christopher Faulet
3e2638ee04 BUG/MEDIUM: htx: Fully update HTX message when the block value is changed
Everywhere the value length of a block is changed, calling the function
htx_set_blk_value_len(), the HTX message must be updated. But at many places,
because of the recent changes in the HTX structure, this update was only
partially done. tail_addr and head_addr values were not systematically updated.

In fact, the function htx_set_blk_value_len() was designed as an internal
function to the HTX API. And we used it from outside by convenience. But it is
really painfull and error prone to let the caller update the HTX message. So
now, we use the function htx_change_blk_value_len() wherever is possible. It
changes the value length of a block and updates the HTX message accordingly.

This patch must be backported to 2.0.
2019-06-18 10:02:05 +02:00
Tim Duesterhus
721d686bd1 BUG/MEDIUM: compression: Set Vary: Accept-Encoding for compressed responses
Make HAProxy set the `Vary: Accept-Encoding` response header if it compressed
the server response.

Technically the `Vary` header SHOULD also be set for responses that would
normally be compressed based off the current configuration, but are not due
to a missing or invalid `Accept-Encoding` request header or due to the
maximum compression rate being exceeded.

Not setting the header in these cases does no real harm, though: An
uncompressed response might be returned by a Cache, even if a compressed
one could be retrieved from HAProxy. This increases the traffic to the end
user if the cache is unable to compress itself, but it saves another
roundtrip to HAProxy.

see the discussion on the mailing list: https://www.mail-archive.com/haproxy@formilux.org/msg34221.html
Message-ID: 20190617121708.GA2964@1wt.eu

A small issue remains: The User-Agent is not added to the `Vary` header,
despite being relevant to the response. Adding the User-Agent header would
make responses effectively uncacheable and it's unlikely to see a Mozilla/4
in the wild in 2019.

Add a reg-test to ensure the behaviour as described in this commit message.

see issue #121
Should be backported to all branches with compression (i.e. 1.6+).
2019-06-17 18:51:43 +02:00
Christopher Faulet
a110ecbd84 BUG/MINOR: mux-h1: Add the header connection in lower case in outgoing messages
When necessary, this header is directly added in outgoing messages by the H1
multiplexer. Because there is no HTX conversion first, the header name is not
converserted to its lower case version. So, it must be added in lower case by
the multiplexer.

This patch must be backported to 2.0 and 1.9.
2019-06-17 14:15:32 +02:00
Christopher Faulet
ea418748dd BUG/MINOR: lua/htx: Make txn.req_req_* and txn.res_rep_* HTX aware
These bindings were not updated to support HTX streams.

This patch must be backported to 2.0 and 1.9. It fixes the issue #124.
2019-06-17 13:42:45 +02:00
Baptiste Assmann
da29fe2360 MEDIUM: server: server-state global file stored in a tree
Server states can be recovered from either a "global" file (all backends)
or a "local" file (per backend).

The way the algorithm to parse the state file was first implemented was good
enough for a low number of backends and servers per backend.
Basically, for each backend the state file (global or local) is opened,
parsed entirely and for each line we check if it contains data related to
a server from the backend we're currently processing.
We must read the file entirely, just in case some lines for the current
backend are stored at the end of the file.
This does not scale at all!

This patch changes the behavior above for the "global" file only. Now,
the global file is read and parsed once and all lines it contains are
stored in a tree, for faster discovery.
This result in way much less fopen, fgets, and strcmp calls, which make
loading of very big state files very quick now.
2019-06-17 13:40:42 +02:00
Tim Duesterhus
d437630237 MINOR: sample: Add sha2([<bits>]) converter
This adds a converter for the SHA-2 family, supporting SHA-224, SHA-256
SHA-384 and SHA-512.

The converter relies on the OpenSSL implementation, thus only being available
when HAProxy is compiled with USE_OPENSSL.

See GitHub issue #123. The hypothetical `ssl_?_sha256` fetch can then be
simulated using `ssl_?_der,sha2(256)`:

  http-response set-header Server-Cert-FP %[ssl_f_der,sha2(256),hex]
2019-06-17 13:36:42 +02:00
Tim Duesterhus
24915a55da MEDIUM: Remove 'option independant-streams'
It is deprecated with HAProxy 1.5. Time to remove it.
2019-06-17 13:35:54 +02:00
Tim Duesterhus
86e6b6ebf8 MEDIUM: Make '(cli|con|srv)timeout' directive fatal
They were deprecated with HAProxy 1.5. Time to remove them.
2019-06-17 13:35:54 +02:00
Tim Duesterhus
dac168bc15 MEDIUM: Make 'redispatch' directive fatal
It was deprecated with HAProxy 1.5. Time to remove it.
2019-06-17 13:35:54 +02:00
Tim Duesterhus
7b7c47f05c MEDIUM: Make 'block' directive fatal
It was deprecated with HAProxy 1.5. Time to remove it.
2019-06-17 13:35:54 +02:00
Christopher Faulet
0c6de00d7c BUG/MEDIUM: h2/htx: Update data length of the HTX when the cookie list is built
When an H2 request is converted into an HTX message, All cookie headers are
grouped into one, each value separated by a semicolon (;). To do so, we add the
header "cookie" with the first value and then we update the value by appending
other cookies. But during this operation, only the size of the HTX block is
updated. And not the data length of the whole HTX message.

It is an old bug and it seems to work by chance till now. But it may lead to
undefined behaviour by time to time.

This patch must be backported to 2.0 and 1.9
2019-06-17 11:44:51 +02:00
Willy Tarreau
33ccf1cce0 BUILD: pattern: work around an internal compiler bug in gcc-3.4
gcc-3.4 fails to compile pattern.c :

src/pattern.c: In function `pat_match_ip':
src/pattern.c:1092: error: unrecognizable insn:
(insn 186 185 187 9 src/pattern.c:970 (set (reg/f:SI 179)
        (high:SI (const:SI (plus:SI (symbol_ref:SI ("static_pattern") [flags 0x22] <var_decl fe5bae80 static_pattern>)
                    (const_int 8 [0x8]))))) -1 (nil)
    (nil))
src/pattern.c:1092: internal compiler error: in extract_insn, at recog.c:2083

This happens when performing the memcpy() on the union, and in this
case the workaround is trivial (and even cleaner) using a cast instead.
2019-06-16 18:40:33 +02:00
Willy Tarreau
8daa920ae4 BUILD: tools: work around an internal compiler bug in gcc-3.4
gcc-3.4 fails to compile standard.c :

src/standard.c: In function `str2sa_range':
src/standard.c:1034: error: unrecognizable insn:
(insn 582 581 583 37 src/standard.c:949 (set (reg/f:SI 262)
        (high:SI (const:SI (plus:SI (symbol_ref:SI ("*ss.4") [flags 0x22] <var_decl fe782e80 ss>)
                    (const_int 2 [0x2]))))) -1 (nil)
    (nil))
src/standard.c:1034: internal compiler error: in extract_insn, at recog.c:2083

The workaround is explained here :

    https://gcc.gnu.org/bugzilla/show_bug.cgi?id=21613

It only requires creating a local variable containing the result of the
cast, which is totally harmless, so let's do it.
2019-06-16 18:16:33 +02:00
Olivier Houchard
965e84e2df BUG/MEDIUM: ssl: Make sure we initiate the handshake after using early data.
When we're done sending/receiving early data, and we add the handshake
flags on the connection, make sure we wake the associated tasklet up, so that
the handshake will be initiated.
2019-06-15 21:00:39 +02:00
Willy Tarreau
b6563f4ac4 BUG/MEDIUM: mux-h2: properly account for the appended data in HTX
When commit 0350b90e3 ("MEDIUM: htx: make htx_add_data() never defragment
the buffer") was introduced, it made htx_add_data() actually be able to
add less data than it was asked for, and the callers must use the returned
value to know how much was added. The H2 code used to rely on the frame
length instead of the return value. A version of the code doing this was
written but is obviously not the one that got merged, resulting in breaking
large uploads or downloads when HTX would have instead defragmented the
buffer because the HTX side sees less contents than what the H2 side sees.

This patch fixes this again. No backport is needed.
2019-06-15 11:42:01 +02:00
Olivier Houchard
8694e5bc99 BUG/MEDIUM: connections: Don't try to send early data if we have no mux.
In connect_server(), if we don't yet have a mux, because we're choosing
one depending on the ALPN, don't attempt to send early data. We can't do
it because those data would depend on the mux, that will only be determined
by the handshake.

This should be backported to 1.9.
2019-06-15 11:35:00 +02:00
Olivier Houchard
b4a8b2c63d BUG/MEDIUM: connections: Don't use ALPN to pick mux when in mode TCP.
In connect_server(), don't wait until we negociate the ALPN to choose the
mux, the only mux we want to use is the mux_pt anyway.

This should be backported to 1.9.
2019-06-15 11:34:55 +02:00
Willy Tarreau
76c83826db BUG/MEDIUM: mux-h2: fix early close with option abortonclose
Olivier found that commit 99ad1b3e8 ("MINOR: mux-h2: stop relying on
CS_FL_REOS") managed to break abortonclose again with H2. What happens
is that while the CS_FL_REOS flag was set on some transitions to the
HREM state, it's not set on all and is in fact only set when the low
level connection is closed. So making the replacement condition match
the HREM and ERROR states is not correct and causes completely correct
requests to send advertise an early close of the connection layer while
only the stream's input is closed.

In order to avoid this, we now properly split the checks for the CLOSED
state and for the closed connection. This way there is no risk to set
the EOS flag too early on the connection.

No backport is needed.
2019-06-15 10:04:09 +02:00
Willy Tarreau
bd20a9dd4e BUG: tasks: fix bug introduced by latest scheduler cleanup
In commit 86eded6c6 ("CLEANUP: tasks: rename task_remove_from_tasklet_list()
to tasklet_remove_*") which consisted in removing the casts between tasks
and tasklet, I was a bit too fast to believe that we only saw tasklets in
this function since process_runnable_tasks() also uses it with tasks under
a cast. So removing the bookkeeping on task_list_size was not appropriate.
Bah, the joy of casts which hide the real thing...

This patch does two things at once to address this mess once for all:
  - it restores the decrement of task_list_size when it's a real task,
    but moves it to process_runnable_task() since it's the only place
    where it's allowed to call it with a task

  - it moves the increment there as well and renames
    task_insert_into_tasklet_list() to tasklet_insert_into_tasklet_list()
    of obvious consistency reasons.

This way the increment/decrement of task_list_size is made at the only
places where the cast is enforced, so it has less risks to be missed.
The comments on top of these functions were updated to reflect that they
are only supposed to be used with tasklets and that the caller is responsible
for keeping task_list_size up to date if it decides to enforce a task there.

Now we don't have to worry anymore about how these functions work outside
of the scheduler, which is better longterm-wise. Thanks to Christopher for
spotting this mistake.

No backport is needed.
2019-06-14 18:16:19 +02:00
Christopher Faulet
cd67bffd26 BUG/MINOR: mux-h1: Wake busy mux for I/O when message is fully sent
If a mux is in busy mode when the outgoing EOM is consummed, it is important to
wake it up for I/O. Because in busy mode, the mux is not subscribed for
receive. Otherwise, it depends on the applicative layer to shutdown the H1
stream. Wake it up allows the mux to catch the read0 as soon as possible.

This patch must be backported to 1.9.
2019-06-14 17:40:10 +02:00
Willy Tarreau
86eded6c69 CLEANUP: tasks: rename task_remove_from_tasklet_list() to tasklet_remove_*
The function really only operates on tasklets, its arguments are always
tasklets cast as tasks to match the function's type, to be cast back to
a struct tasklet. Let's rename it to tasklet_remove_from_tasklet_list(),
take a struct tasklet, and get rid of the undesired task casts.
2019-06-14 14:57:03 +02:00
Willy Tarreau
3c39a7d889 CLEANUP: connection: rename the wait_event.task field to .tasklet
It's really confusing to call it a task because it's a tasklet and used
in places where tasks and tasklets are used together. Let's rename it
to tasklet to remove this confusion.
2019-06-14 14:42:29 +02:00
Baptiste Assmann
95c2c01ced MEDIUM: server: server-state only rely on server name
Since h7da71293e431b5ebb3d6289a55b0102331788ee6as has been added, the
server name (srv->id in the code) is now unique per backend, which
means it can reliabely be used to identify a server recovered from the
server-state file.

This patch cleans up the parsing of server-state file and ensure we use
only the server name as a reliable key.
2019-06-14 14:18:55 +02:00
Christopher Faulet
3b44c54129 MINOR: mux-h2: Forward clients scheme to servers checking start-line flags
By default, the scheme "https" is always used. But when an explicit scheme was
defined and when this scheme is "http", we use it in the request sent to the
server. This is done by checking flags of the start-line. If the flag
HTX_SL_F_HAS_SCHM is set, it means an explicit scheme was defined on the client
side. And if the flag HTX_SL_F_SCHM_HTTP is set, it means the scheme "http" was
used.
2019-06-14 11:13:32 +02:00
Christopher Faulet
42993a86c9 MINOR: mux-h1: Set flags about the request's scheme on the start-line
We first try to figure out if the URI of the start-line is absolute or not. So,
if it does not start by a slash ("/"), it means the URI is an absolute one and
the flag HTX_SL_F_HAS_SCHM is set. Then checks are performed to know if the
scheme is "http" or "https" and the corresponding flag is set,
HTX_SL_F_SCHM_HTTP or HTX_SL_F_SCHM_HTTPS. Other schemes, for instance ftp, are
ignored.
2019-06-14 11:13:32 +02:00
Christopher Faulet
a9a5c04c23 MINOR: h2: Set flags about the request's scheme on the start-line
The flag HTX_SL_F_HAS_SCHM is always set because H2 requests have always an
explicit scheme. Then, the pseudo-header ":scheme" is tested. If it is set to
"http", the flag HTX_SL_F_SCHM_HTTP is set. Otherwise, for all other cases, the
flag HTX_SL_F_SCHM_HTTPS is set. For now, it seems reasonable to have a fallback
on the scheme "https".
2019-06-14 11:13:32 +02:00
Christopher Faulet
d20fdb0454 BUG/MEDIUM: proto_htx: Introduce the state ENDING during forwarding
This state is used in the legacy HTTP when everything was received from an
endpoint but a filter doesn't forward all the data. It is used to not report a
client or a server abort, depending on channels flags.

The same must be done on HTX streams. Otherwise, the message may be
truncated. For instance, it may happen with the filter trace with the random
forwarding enabled on the response channel.

This patch must be backported to 1.9.
2019-06-14 11:13:32 +02:00
Christopher Faulet
421e769783 BUG/MEDIUM: htx: Don't change position of the first block during HTX analysis
In the HTX structure, the field <first> is used to know where to (re)start the
analysis. It may differ from the message's head. It is especially important to
update it to handle 1xx messages, to be sure to restart the analysis on the next
message (another 1xx message or the final one). It is also updated when some
data are forwarded (the headers or part of the body). But this update is an
error and must never be done at the analysis level. It is a bug, because some
sample fetches may be used after the data forwarding (but before the first send
of course). At this stage, if the first block position does not point on the
start-line, most of HTTP sample fetches fail.

So now, when something is forwarding by HTX analyzers, the first block position
is not update anymore.

This issue was reported on Github. See #119. No backport needed.
2019-06-14 11:13:32 +02:00
Christopher Faulet
8c65486081 BUG/MINOR: htx: Detect when tail_addr meet end_addr to maximize free rooms
When a block's payload is moved during an expansion or when the whole block is
removed, the addresses of free spaces are updated accordingly. We must be
careful to reset them when <tail_addr> becomes equal to <end_addr>. In this
situation, we can maximize the free space between the blocks and their payload
and set the other one to 0. It is also important to be sure to never have
<end_addr> greater than <tail_addr>.
2019-06-14 11:13:32 +02:00
Christopher Faulet
e4ab11bb88 BUG/MINOR: http: Use the global value to limit the number of parsed headers
Instead of using the macro MAX_HTTP_HDR to limit the number of headers parsed
before throwing an error, we now use the custom global variable
global.tune.max_http_hdr.

This patch must be backported to 1.9.
2019-06-14 11:13:32 +02:00
Christopher Faulet
647fe1d9e1 BUG/MINOR: fl_trace/htx: Be sure to always forward trailers and EOM
Previous fix about the random forwarding on the message body was not enough to
fix the bug in all cases. Among others, when there is no data but only the EOM,
we must forward everything.

This patch must be backported to 1.9 if the patch 0bdeeaacb ("BUG/MINOR:
flt_trace/htx: Only apply the random forwarding on the message body.") is also
backported.
2019-06-14 11:13:32 +02:00
Olivier Houchard
985234d0cb BUG/MEDIUM: h1: Wait for the connection if the handshake didn't complete.
In h1_init(), also add the H1C_F_CS_WAIT_CONN flag if the handshake didn't
complete, otherwise we may end up letting the upper layer sending data too
soon.
2019-06-13 19:14:45 +02:00
Olivier Houchard
6063003c96 BUG/MEDIUM: h1: Don't wait for handshake if we had an error.
In h1_process(), only wait for the handshake if we had no error on the
connection. If the handshake failed, we have to let the upper layer know.
2019-06-13 19:14:45 +02:00
Ben51Degrees
f4a82fb26b BUILD/MINOR: 51d: Updated build registration output to indicate thatif the library is a dummy one or not.
When built with the dummy 51Degrees library for testing, the output will
include "(dummy library)" to ensure it is clear that this is this is not
the API.
2019-06-13 18:00:54 +02:00
William Lallemand
63329e36ab MINOR: doc: update the manpage and usage message about -S
Add -S in the manpage, and update the usage message.

Should be backported to 1.9.
2019-06-13 17:09:27 +02:00
Tim Duesterhus
dda1155ed7 BUILD: Silence gcc warning about unused return value
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

complains:

> src/debug.c: In function "ha_panic":
> src/debug.c:162:2: warning: ignoring return value of "write", declared with attribute warn_unused_result [-Wunused-result]
>  (void) write(2, trash.area, trash.data);
>    ^
2019-06-13 15:47:41 +02:00
William Lallemand
1dc6963086 MINOR: mworker: add the HAProxy version in "show proc"
Displays the HAProxy version so you can compare the version of old
processes and new ones.
2019-06-12 19:19:57 +02:00
William Lallemand
e8669fc9db MINOR: mworker: change formatting in uptime field of "show proc"
Change the formatting of the uptime field in "show proc" so it's easier
to parse it. Remove the space between the day and the hour and align the
field on 15 characters.
2019-06-12 19:19:57 +02:00
Ben51Degrees
31a51f25d6 BUG/MINOR: 51d/htx: The _51d_fetch method, and the methods it calls are now HTX aware.
The _51d_fetch method, and the two methods it calls to fetch HTTP
headers (_51d_set_device_offsets, and _51d_set_headers), now support
both legacy and HTX operation.

This should be backported to 1.9.
2019-06-12 18:06:59 +02:00
Willy Tarreau
3381022d88 MINOR: http: add a new "http-request replace-uri" action
This action is particularly convenient to replace some deprecated usees
of "reqrep". It takes a match and a format string including back-
references. The reqrep warning was updated to suggest it as well.
2019-06-12 18:06:59 +02:00
Olivier Houchard
690e0f07f5 BUG/MEDIUM: h1: Don't consider we're connected if the handshake isn't done.
In h1_process(), don't consider we're connected if we still have handshakes
pending. It used not to happen, because we would not be called if there
were any ongoing handshakes, but that changed now that the handshakes are
handled by a xprt, and not by conn_fd_handler() directly.
2019-06-11 16:41:36 +02:00
Olivier Houchard
92d093d641 BUG/MEDIUM: h1: Don't try to subscribe if we had a connection error.
If the CO_FL_ERROR flag is set, and we weren't connected yet, don't attempt
to subscribe, as the underlying xprt may already have been destroyed.
2019-06-11 16:41:24 +02:00
Willy Tarreau
b5ba2b0177 MINOR: http: turn default error files to HTTP/1.1
For quite a long time we've been saying that the default error files
should produce HTTP/1.1 responses and since it's of low importance, it
always gets forgotten.

So here it finally comes. Each status code now properly contains a
content-length header so that the output is clean and doesn't force
upstream proxies to switch to chunked encoding or to close the connection
immediately after the response, which is particularly annoying for 401
or 407 for example. It's worth noting that the 3xx codes had already
been turned to HTTP/1.1.

This patch will obviously not change anything for user-provided error files.
2019-06-11 16:37:13 +02:00
Willy Tarreau
5abdc760c9 BUG/MINOR: http-rules: mention "deny_status" for "deny" in the error message
The error message indicating an unknown keyword on an http-request rule
doesn't mention the "deny_status" option which comes with the "deny" rule,
this is particularly confusing.

This can be backported to all versions supporting this option.
2019-06-11 16:37:13 +02:00
Olivier Houchard
45c4437b4a Revert "BUG/MEDIUM: H1: When upgrading, make sure we don't free the buffer too early."
This reverts commit 6c7fe5c370.

This patch was harmless, but not needed, conn_upgrade_mux_fe() already takes
care of setting the buffer to BUF_NULL.
2019-06-11 14:07:53 +02:00
Christopher Faulet
86fcf6d6cd MINOR: htx: Add the function htx_move_blk_before()
The function htx_add_data_before() was removed because it was buggy. The
function htx_move_blk_before() may be used if necessary to do something
equivalent, except it just moves blocks. It doesn't handle the adding.
2019-06-11 14:05:25 +02:00
Christopher Faulet
d7884d3449 MAJOR: htx: Rework how free rooms are tracked in an HTX message
In an HTX message, it may have 2 available rooms to store a new block. The first
one is between the blocks and their payload. Blocks are added starting from the
end of the buffer and their payloads are added starting from the begining. So
the first free room is between these 2 edges. The second one is at the begining
of the buffer, when we start to wrap to add new payloads. Once we start to use
this one, the other one is ignored until the next defragmentation of the HTX
message.

In theory, there is no problem. But in practice, some lacks in the HTX structure
force us to defragment too often HTX messages to always be in a known state. The
second free room is not tracked as it should do and the first one may be easily
corrupted when rewrites happen.

So to fix the problem and avoid unecessary defragmentation, the HTX structure
has been refactored. The front (the block's position of the first payload before
the blocks) is no more stored. Instead we keep the relative addresses of 3 edges:

 * tail_addr : The start address of the free space in front of the the blocks
               table
 * head_addr : The start address of the free space at the beginning
 * end_addr  : The end address of the free space at the beginning

Here is the general view of the HTX message now:

           head_addr     end_addr    tail_addr
               |            |            |
               V            V            V
  +------------+------------+------------+------------+------------------+
  |            |            |            |            |                  |
  |  PAYLOAD   | Free space |  PAYLOAD   | Free space |    Blocks area   |
  |    ==>     |     1      |    ==>     |     2      |        <==       |
  +------------+------------+------------+------------+------------------+

<head_addr> is always lower or equal to <end_addr> and <tail_addr>. <end_addr>
is always lower or equal to <tail_addr>.

In addition;, to simplify everything, the blocks area are now contiguous. It
doesn't wrap anymore. So the head is always the block with the lowest position,
and the tail is always the one with the highest position.
2019-06-11 14:05:25 +02:00
Christopher Faulet
50fe9fba4b MINOR: flt_trace: Don't scrash the original offset during the random forwarding
There is no bug here, but this patch improves the debug message reported during
the random forwarding. The original offset is kept untouched so its value may be
used to format the message. Before, 0 was always reported.
2019-06-11 14:05:25 +02:00
Christopher Faulet
86bc8df955 BUG/MEDIUM: compression/htx: Fix the adding of the last data block
The function htx_add_data_before() is buggy and cannot work. It first add a data
block and then move it before another one, passed in argument. The problem
happens when a defragmentation is done to add the new block. In this case, the
reference is no longer valid, because the blocks are rearranged. So, instead of
moving the new block before the reference, it is moved at the head of the HTX
message.

So this function has been removed. It was only used by the compression filter to
add a last data block before a TLR, EOT or EOM block. Now, the new function
htx_add_last_data() is used. It adds a last data block, after all others and
before any TLR, EOT or EOM block. Then, the next bock is get. It is the first
non-data block after data in the HTX message. The compression loop continues
with it.

This patch must be backported to 1.9.
2019-06-11 14:05:25 +02:00
Christopher Faulet
bda8397fba BUG/MINOR: cache/htx: Fix the counting of data already sent by the cache applet
Since the commit 8f3c256f7 ("MEDIUM: cache/htx: Always store info about HTX
blocks in the cache"), it is possible to read info about a data block without
sending anything. It is possible because we rely on the function htx_add_data(),
which will try to add data without any defragmentation. In such case, info about
the data block are skipped but don't count in data sent.

No need to backport this patch, expect if the commit 8f3c256f7 is backported
too.
2019-06-11 14:05:25 +02:00
Willy Tarreau
34a150ccf5 MEDIUM: init/threads: don't use spinlocks during the init phase
PiBa-NL found some pathological cases where starting threads can hinder
each other and cause a measurable slow down. This problem is reproducible
with the following config (haproxy must be built with -DDEBUG_DEV) :

    global
	stats socket /tmp/sock1 mode 666 level admin
	nbthread 64

    backend stopme
	timeout server  1s
	option tcp-check
	tcp-check send "debug dev exit\n"
	server cli unix@/tmp/sock1 check

This will cause the process to be stopped once the checks are ready to
start. Binding all these to just a few cores magnifies the problem.
Starting them in loops shows a significant time difference among the
commits :

  # before startup serialization
  $ time for i in {1..20}; do taskset -c 0,1,2,3 ./haproxy-e186161 -db -f slow-init.cfg >/dev/null 2>&1; done

  real    0m1.581s
  user    0m0.621s
  sys     0m5.339s

  # after startup serialization
  $ time for i in {1..20}; do taskset -c 0,1,2,3 ./haproxy-e4d7c9dd -db -f slow-init.cfg >/dev/null 2>&1; done

  real    0m2.366s
  user    0m0.894s
  sys     0m8.238s

In order to address this, let's use plain mutexes and cond_wait during
the init phase. With this done, waiting threads now sleep and the problem
completely disappeared :

  $ time for i in {1..20}; do taskset -c 0,1,2,3 ./haproxy -db -f slow-init.cfg >/dev/null 2>&1; done

  real    0m0.161s
  user    0m0.079s
  sys     0m0.149s
2019-06-11 11:30:26 +02:00
Frédéric Lécaille
b5ecf0393c BUG/MINOR: dict: race condition fix when inserting dictionary entries.
When checking the result of an ebis_insert() call in an ebtree with unique keys,
if already present, in place of freeing() the old one and return the new one,
rather the correct way is to free the new one, and return the old one. For
this, the __dict_insert() function was folded into dict_insert() as this
significantly simplifies the test of duplicates.

Thanks to Olivier for having reported this bug which came with this one:
"MINOR: dict: Add dictionary new data structure".
2019-06-11 09:54:12 +02:00
Willy Tarreau
e4d7c9dd65 OPTIM/MINOR: init/threads: only call protocol_enable_all() on first thread
There's no point in calling this on each and every thread since the first
thread passing there will enable the listeners, and the next ones will
simply scan all of them in turn to discover that they are already
initialized. Let's only initilize them on the first thread. This could
slightly speed up start up on very large configurations, eventhough most
of the time is still spent in the main thread binding the sockets.

A few measurements have constantly shown that this decreases the startup
time by ~0.1s for 150k listeners. Starting all of them in parallel doesn't
provide better results and can still expose some undesired races.
2019-06-10 10:53:59 +02:00
Willy Tarreau
7109282577 BUG/MEDIUM: init/threads: prevent initialized threads from starting before others
Since commit 6ec902a ("MINOR: threads: serialize threads initialization")
we now serialize threads initialization. But doing so has emphasized another
race which is that some threads may actually start the loop before others
are done initializing.

As soon as all threads enter the first thread_release() call, their rdv
bit is cleared and they're all waiting for all others' rdv to be cleared
as well, with their harmless bit set. The first one to notice the cleared
mask will progress through thread_isolate(), take rdv again preventing
most others from noticing its short pass to zero, and this first one will
be able to run all the way through the initialization till the last call
to thread_release() which it happily crosses, being the only one with the
rdv bit, leaving the room for one or a few others to do the same. This
results in some threads entering the loop before others are done with
their initialization, which is particularly bad. PiBa-NL reported that
some regtests fail for him due to this (which was impossible to reproduce
here, but races are racy by definition). However placing some printf()
in the initialization code definitely shows this unsychronized startup.

This patch takes a different approach in three steps :
  - first, we don't start with thread_release() anymore and we don't
    set the rdv mask anymore in the main call. This was initially done
    to let all threads start toghether, which we don't want. Instead
    we just start with thread_isolate(). Since all threads are harmful
    by default, they all wait for each other's readiness before starting.

  - second, we don't release with thread_release() but with
    thread_sync_release(), meaning that we don't leave the function until
    other ones have reached the point in the function where they decide
    to leave it as well.

  - third, it makes sure we don't start the listeners using
    protocol_enable_all() before all threads have allocated their local
    FD tables or have initialized their pollers, otherwise startup could
    be racy as well. It's worth noting that it is even possible to limit
    this call to thread #0 as it only needs to be performed once.

This now guarantees that all thread init calls start only after all threads
are ready, and that no thread enters the polling loop before all others have
completed their initialization.

Please check GH issues #111 and #117 for more context.

No backport is needed, though if some new init races are reported in
1.9 (or even 1.8) which do not affect 2.0, then it may make sense to
carefully backport this small series.
2019-06-10 10:53:52 +02:00
Willy Tarreau
9a1f57351d MEDIUM: threads: add thread_sync_release() to synchronize steps
This function provides an alternate way to leave a critical section run
under thread_isolate(). Currently, a thread may remain in thread_release()
without having the time to notice that the rdv mask was released and taken
again by another thread entering thread_isolate() (often the same that just
released it). This is because threads wait in harmless mode in the loop,
which is compatible with the conditions to enter thread_isolate(). It's
not possible to make them wait with the harmless bit off or we cannot know
when the job is finished for the next thread to start in thread_isolate(),
and if we don't clear the rdv bit when going there, we create another
race on the start point of thread_isolate().

This new synchronous variant of thread_release() makes use of an extra
mask to indicate the threads that want to be synchronously released. In
this case, they will be marked harmless before releasing their sync bit,
and will wait for others to release their bit as well, guaranteeing that
thread_isolate() cannot be started by any of them before they all left
thread_sync_release(). This allows to construct synchronized blocks like
this :

     thread_isolate()
     /* optionally do something alone here */
     thread_sync_release()
     /* do something together here */
     thread_isolate()
     /* optionally do something alone here */
     thread_sync_release()

And so on. This is particularly useful during initialization where several
steps have to be respected and no thread must start a step before the
previous one is completed by other threads.

This one must not be placed after any call to thread_release() or it would
risk to block an earlier call to thread_isolate() which the current thread
managed to leave without waiting for others to complete, and end up here
with the thread's harmless bit cleared, blocking others. This might be
improved in the future.
2019-06-10 09:42:43 +02:00
Willy Tarreau
31cba0d3e0 MINOR: threads: avoid clearing harmless twice in thread_release()
thread_release() is to be called after thread_isolate(), i.e. when the
thread already has its harmless bit cleared. No need to clear it twice,
thus avoid calling thread_harmless_end() and directly check the rdv
bits then loop on them.
2019-06-09 08:47:35 +02:00
Olivier Houchard
19a2e2d91e BUG/MEDIUM: stream_interface: Make sure we call si_cs_process() if CS_FL_EOI.
In si_cs_recv(), if we got the CS_FL_EOI flag on the conn_stream, make sure
we return 1, so that si_cs_process() will be called, and wake
process_stream() up, otherwise if we're unlucky the flag will never be
noticed, and the stream won't be woken up.
2019-06-07 19:37:21 +02:00
Olivier Houchard
6c7fe5c370 BUG/MEDIUM: H1: When upgrading, make sure we don't free the buffer too early.
In h1_release(), when we want to upgrade the mux to h2, make sure we set
h1c->ibuf to BUF_NULL before calling conn_upgrade_mux_fe().
If the upgrade is successful, the buffer will be provided to the new mux,
h1_release() will be called recursively, it will so try to free h1c->ibuf,
and freeing the buffer we just provided to the new mux would be unfortunate.
2019-06-07 19:37:21 +02:00
Willy Tarreau
9faebe34cd MEDIUM: tools: improve time format error detection
As reported in GH issue #109 and in discourse issue
https://discourse.haproxy.org/t/haproxy-returns-408-or-504-error-when-timeout-client-value-is-every-25d
the time parser doesn't error on overflows nor underflows. This is a
recurring problem which additionally has the bad taste of taking a long
time before hitting the user.

This patch makes parse_time_err() return special error codes for overflows
and underflows, and adds the control in the call places to report suitable
errors depending on the requested unit. In practice, underflows are almost
never returned as the parsing function takes care of rounding values up,
so this might possibly happen on 64-bit overflows returning exactly zero
after rounding though. It is not really possible to cut the patch into
pieces as it changes the function's API, hence all callers.

Tests were run on about every relevant part (cookie maxlife/maxidle,
server inter, stats timeout, timeout*, cli's set timeout command,
tcp-request/response inspect-delay).
2019-06-07 19:32:02 +02:00
Frédéric Lécaille
b65717fa55 MINOR: peers: Optimization for dictionary cache lookup.
When we look up an dictionary entry in the cache used upon transmission
we store the last result in ->prev_lookup of struct dcache_tx so that
to compare it with the subsequent entries to look up and save performances.
2019-06-07 15:47:54 +02:00
Frédéric Lécaille
fd827937ed MINOR: peers: A bit of optimization when encoding cached server names.
When a server name is cached we only send its cache entry ID which has
an encoded length of 1 (because smaller than PEER_ENC_2BYTES_MIN).
So, in this case we only have to encode 1, the already known encoded length
of this ID before encoding it.

Furthermore we do not have to call strlen() to compute the lengths of server
name strings thanks to this commit: "MINOR: dict: Store the length of the
dictionary entries".
2019-06-07 15:47:54 +02:00
Frédéric Lécaille
99de1d0479 MINOR: dict: Store the length of the dictionary entries.
When allocating new dictionary entries we store the length of the strings.
May be useful so that not to have to call strlen() too much often at runing
time.
2019-06-07 15:47:54 +02:00
Frédéric Lécaille
6c39198b57 MINOR peers: data structure simplifications for server names dictionary cache.
We store pointers to server names dictionary entries in a pre-allocated array of
ebpt_node's (->entries member of struct dcache_tx) to cache those sent to remote
peers. Consequently the ID used to identify the server name dictionary entry is
also used as index for this array. There is no need to implement a lookup by key
for this dictionary cache.
2019-06-07 15:47:54 +02:00
Willy Tarreau
6ec902a659 MINOR: threads: serialize threads initialization
There is no point in initializing threads in parallel when we know that
it's the moment where some global variables are turned to thread-local
ones, and/or that some global variables are updated (like global_now or
trash_size). Some FDs might be created/destroyed/reallocated and could
be tricky to follow as well (think about epoll_fd for example).

Instead of having to be extremely careful about all these, and to trigger
false positives in thread sanitizers, let's simply initialize one thread
at a time. The init step is very fast so nobody should even notice, and
we won't have any more doubts about what might have happened when
analysing a dump.

See GH issues #111 and #117 for some background on this.
2019-06-07 15:37:47 +02:00
Willy Tarreau
e18616168f Revert "MINOR: chunks: Make sure trash_size is only set once."
This reverts commit 1c3b83242d.

It was made only to silence the thread sanitizer but ends up creating a
bug. Indeed, if "tune.bufsize" is in the global section, the trash_size
value is not updated anymore and the trash becomes smaller than a buffer!

Let's stop trying to fix the thread sanitizer reports, they are invalid,
and trying to fix them actually introduces bugs where there were none.

See GH issue #117 for more context. No backport is needed.
2019-06-07 15:37:47 +02:00
Olivier Houchard
1c3b83242d MINOR: chunks: Make sure trash_size is only set once.
The trash_size variable is shared by all threads, and is set by all threads,
when alloc_trash_buffers() is called. To make sure it's set only once,
to silence a harmless data race, use a CAS to set it, and only set it if it
was 0.
2019-06-07 14:45:44 +02:00
Willy Tarreau
1bfd6020ce MINOR: logs: use the new bitmap functions instead of fd_sets for encoding maps
The fd_sets we've been using in the log encoding functions are not portable
and were shown to break at least under Cygwin. This patch gets rid of them
in favor of the new bitmap functions. It was verified with the config below
that the log output was exactly the same before and after the change :

    defaults
        mode http
        option httplog
        log stdout local0
        timeout client 1s
        timeout server 1s
        timeout connect 1s

    frontend foo
        bind :8001
        capture request header chars len 255

    backend bar
        option httpchk "GET" "/" "HTTP/1.0\r\nchars: \x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
        server foo 127.0.0.1:8001 check
2019-06-07 11:13:24 +02:00
Willy Tarreau
7348119fb2 BUG/MEDIUM: mux-h2: make sure the connection timeout is always set
There seems to be a tricky case in the H2 mux related to stream flow
control versus buffer a full situation : is a large response cannot
be entirely sent to the client due to the stream window being too
small, the stream is paused with the SFCTL flag. Then the upper
layer stream might get bored and expire this stream. It will then
shut it down first. But the shutdown operation might fail if the
mux buffer is full, resulting in the h2s being subscribed to the
deferred_shut event with the stream *not* added to the send_list
since it's blocked in SFCTL. In the mean time the upper layer completely
closes, calling h2_detach(). There we have a send_wait (the pending
shutw), the stream is marked with SFCTL so we orphan it.

Then if the client finally reads all the data that were clogging the
buffer, the send_list is run again, but our stream is not there. From
this point, the connection's stream list is not empty, the mux buffer
is empty, so the connection's timeout is not set. If the client
disappears without updating the stream's window, nothing will expire
the connection.

This patch makes sure we always keep the connection timeout updated.
There might be finer solutions, such as checking that there are still
living streams in the connection (i.e. streams not blocked in SFCTL
state), though this is not necessarily trivial nor useful, since the
client timeout is the same for the upper level stream and the connection
anyway.

This patch needs to be backported to 1.9 and 1.8 after some observation.
2019-06-07 08:47:44 +02:00
Olivier Houchard
7b3a79f6c4 BUG/MEDIUM: tcp: Make sure we keep the polling consistent in tcp_probe_connect.
In tcp_probe_connect(), if the connection is still pending, do not disable
want_recv, we don't have any business to do so, but explicitely use
__conn_xprt_want_send(), otherwise the next time we'll reach tcp_probe_connect,
fd_send_ready() would return 0 and we would never flag the connection as
CO_FL_CONNECTED, which can lead to various problems, such as check not
completing because they consider it is not connected yet.
2019-06-06 18:17:32 +02:00
Willy Tarreau
43091ed161 BUG/MINOR: time: make sure only one thread sets global_now at boot
All threads call tv_update_date(-1) at boot to set their own local time
offset. While doing so they also overwrite global_now, which is not that
much of a problem except that it's not done using an atomic write and
that it will be overwritten by every there in parallel. We only need the
first thread to set it anyway, so let's simply set it if not set and do
it using a CAS. This should fix GH issue #111.

This may be backported to 1.9.
2019-06-06 16:50:39 +02:00
Willy Tarreau
237f8aef41 BUILD: peers: fix a build warning about an incorrect intiialization
Just got this one :
src/peers.c:528:13: warning: missing braces around initializer [-Wmissing-braces]
src/peers.c:528:13: warning: (near initialization for 'cde.key') [-Wmissing-braces]

Indeed, this struct contains two structs so scalar zero is not a valid
value for the first field. Let's just leave it as an empty struct since
it was the purpose.
2019-06-06 16:42:14 +02:00
Willy Tarreau
1ec9bb5b62 MEDIUM: stream: don't abusively loop back on changes on CF_SHUT*_NOW
These flags are not used by analysers, only by the shut* functions, and
they were covered by CF_MASK_STATIC only because in the past the shut
functions were in the middle of the analysers. But here they are causing
excess loop backs which provide no value and increase processing cost.
Ideally the CF_MASK_STATIC bitfield should be revisited, but doing this
alone is enough to reduce by 30% the number of calls to si_sync_send().
2019-06-06 16:36:19 +02:00
Willy Tarreau
3c5c066d66 MEDIUM: stream: only loop on flags relevant to the analysers
In process_stream() we detect a number of conditions to decide to loop
back to the analysers. Some of them are excessive in that they perform
a strict comparison instead of filtering on the flags relevant to the
analysers as is done at other places, resulting in excess wakeups. One
of the effect is that after a successful WRITE_PARTIAL, a second send is
not possible, resulting in the loss of WRITE_PARTIAL, causing another
wakeup! Let's apply the same mask and verify the flags correctly.
2019-06-06 16:36:19 +02:00
Willy Tarreau
829bd4710f MEDIUM: stream: rearrange the events to remove the loop
The "goto redo" at the end of process_stream() to make the states converge
is still a big source of problems and mostly stems from the very late call
to the send() functions, whose results need to be considered, while it's
being done in si_update_both() when leaving.

This patch extracts the si_sync_send() calls from si_update_both(), and
places them at the relevant places in process_stream(), which are just
after the amount of data to forward is updated and before the shutw()
calls (which were also moved). The stream-interface resynchronization
needs to go slightly upper to take into account the transition from CON
to RDY that will happen consecutive to some successful send(), and that's
all.

By doing so we can now get rid of this loop and have si_update_both()
called only to update the stream interface and channel when leaving the
function, as it was initially designed to work.

It is worth noting that a number of the remaining conditions to perform
a goto resync_XXX still seem suboptimal and would benefit from being
refined to perform les resynchronization. But what matters at this stage
is that the code remains valid and efficient.
2019-06-06 16:36:19 +02:00
Willy Tarreau
3b285d7fbd MINOR: stream-int: make si_sync_send() from the send code of si_update_both()
Just like we have a synchronous recv() function for the stream interface,
let's have a synchronous send function that we'll be able to call from
different places. For now this only moves the code, nothing more.
2019-06-06 16:36:19 +02:00
Willy Tarreau
236c4298b3 MINOR: stream-int: split si_update() into si_update_rx() and si_update_tx()
We should not update the two directions at once, in fact we should update
the Rx path after recv() and the Tx path after send(). Let's start by
splitting the update function in two for this.
2019-06-06 16:36:19 +02:00
Willy Tarreau
d66ed88a78 MEDIUM: stream: re-arrange the connection setup status reporting
Till now when a wakeup happens after a connection is attempted, we go
through sess_update_st_con_tcp() to deal with the various possible events,
then to sess_update_st_cer() to deal with a possible error detected by the
former, or to sess_establish() to complete the connection validation. There
are multiple issues in the way this is handled, which have accumulated over
time. One of them is that any spurious wakeup during SI_ST_CON would validate
the READ_ATTACHED flag and wake the analysers up. Another one is that nobody
feels responsible for clearing SI_FL_EXP if it happened at the same time as
a success (and it is present in all reports of loops to date). And another
issue is that aborts cannot happen after a clean connection setup with no
data transfer (since CF_WRITE_NULL is part of CF_WRITE_ACTIVITY). Last, the
flags cleanup work was hackish, added here and there to please the next
function (typically what had to be donne in commit 7a3367cca to work around
the url_param+reuse issue by moving READ_ATTACHED to CON).

This patch performs a significant lift up of this setup code. First, it
makes sure that the state handlers are the ones responsible for the cleanup
of the stuff they rely on. Typically sess_sestablish() will clean up the
SI_FL_EXP flag because if we decided to validate the connection it means
that we want to ignore this late timeout. Second, it splits the CON and
RDY state handlers because the former only has to deal with failures,
timeouts and non-events, while the latter has to deal with partial or
total successes. Third, everything related to connection success was
moved to sess_establish() since it's the only safe place to do so, and
this function is also called at a few places to deal with synchronous
connections, which are not seen by intermediary state handlers.

The code was made a bit more robust, for example by making sure we
always set SI_FL_NOLINGER when aborting a connection so that we don't
have any risk to leave a connection in SHUTW state in case it was
validated late. The useless return codes of some of these functions
were dropped so that callers only rely on the stream-int's state now
(which was already partially the case anyway).

The code is now a bit cleaner, could be further improved (and functions
renamed) but given the sensitivity of this part, better limit changes to
strictly necessary. It passes all reg tests.
2019-06-06 16:36:19 +02:00
Willy Tarreau
b27f54a88c MAJOR: stream-int: switch from SI_ST_CON to SI_ST_RDY on I/O
Now whenever an I/O event succeeds during a connection attempt, we
switch the stream-int's state to SI_ST_RDY. This allows si_update()
to update R/W timeouts on the channel and end points to start to
consume outgoing data and to subscribe to lower layers in case of
failure. It also allows chk_rcv() to be performed on the other side
to enable data forwarding and make sure we don't fall into a situation
where no more events happen and nothing moves anymore.
2019-06-06 16:36:19 +02:00
Willy Tarreau
4f283fa604 MEDIUM: stream-int: introduce a new state SI_ST_RDY
The main reason for all the trouble we're facing with stream interface
error or timeout reports during the connection phase is that we currently
can't make the difference between a connection attempt and a validated
connection attempt. It is problematic because we tend to switch early
to SI_ST_EST but can't always do what we want in this state since it's
supposed to be set when we don't need to visit sess_establish() again.

This patch introduces a new state betwen SI_ST_CON and SI_ST_EST, which
is SI_ST_RDY. It indicates that we've verified that the connection is
ready. It's a transient state, like SI_ST_DIS, that cannot persist when
leaving process_stream(). For now it is not set, only verified in various
tests where SI_ST_CON was used or SI_ST_EST depending on the cases.

The stream-int state diagram was minimally updated to reflect the new
state, though it is largely obsolete and would need to be seriously
updated.
2019-06-06 16:36:19 +02:00
Willy Tarreau
7ab22adbf7 MEDIUM: stream-int: remove dangerous interval checks for stream-int states
The stream interface state checks involving ranges were replaced with
checks on a set of states, already revealing some issues. No issue was
fixed, all was replaced in a one-to-one mapping for easier control. Some
checks involving a strict difference were also replaced with fields to
be clearer. At this stage, the result must be strictly equivalent. A few
tests were also turned to their bit-field equivalent for better readability
or in preparation for upcoming changes.

The test performed in the SPOE filter was swapped so that the closed and
error states are evicted first and that the established vs conn state is
tested second.
2019-06-06 16:36:19 +02:00
Willy Tarreau
19ecf71b60 BUG/MINOR: stream: don't emit a send-name-header in conn error or disconnect states
The test for the send-name-header field used to cover all states between
SI_ST_CON and SI_ST_CLO, which include SI_ST_CER and SI_ST_DIS. Trying to
send a header in these states makes no sense at all, so let's fix this.
This should have no visible impact so no backport is needed.
2019-06-06 16:36:19 +02:00
Willy Tarreau
975b155ebb MINOR: server: really increase the pool-purge-delay default to 5 seconds
Commit fb55365f9 ("MINOR: server: increase the default pool-purge-delay
to 5 seconds") did this but the setting placed in new_server() was
overwritten by srv_settings_cpy() from the default-server values preset
in init_default_instance(). Now let's put it at the right place.
2019-06-06 16:25:55 +02:00
Frédéric Lécaille
56aec0ddc6 BUG/MINOR: peers: Wrong server name parsing.
This commit was not complete:
   BUG/MINOR: peers: Wrong "server_name" decoding.
We forgot forgotten to move forward <msg_cur> pointer variable after
having parse the server name string.

Again this bug may happen only if we add stick-table new data type after
the server name which is the current last one. Furthermore this bug is
visible only the first time a peer sends a server name for a stick-table
entry.

Nothing to backport.
2019-06-06 16:06:00 +02:00
Olivier Houchard
81284e6908 BUG/MEDIUM: ssl: Don't forget to initialize ctx->send_recv and ctx->recv_wait.
When creating a new ssl_sock_ctx, don't forget to initialize its send_recv
and recv_wait to NULL, or we may end up dereferencing random values, and
crash.
2019-06-06 13:21:23 +02:00
Olivier Houchard
03abf2d31e MEDIUM: connections: Remove CONN_FL_SOCK*
Now that the various handshakes come with their own XPRT, there's no
need for the CONN_FL_SOCK* flags, and the conn_sock_want|stop functions,
so garbage-collect them.
2019-06-05 18:03:38 +02:00
Olivier Houchard
fe50bfb82c MEDIUM: connections: Introduce a handshake pseudo-XPRT.
Add a new XPRT that is used when using non-SSL handshakes, such as proxy
protocol or Netscaler, instead of taking care of it in conn_fd_handler().
This XPRT is installed when any of those is used, and it removes itself once
the handshake is done.
This should allow us to remove the distinction between CO_FL_SOCK* and
CO_FL_XPRT*.
2019-06-05 18:03:38 +02:00
Olivier Houchard
2e055483ff MINOR: connections: Add a new xprt method, add_xprt().
Add a new method to xprt_ops, add_xprt(), that changes the underlying
xprt to the one provided, and optionally provide the old one.
2019-06-05 18:03:38 +02:00
Olivier Houchard
5149b59851 MINOR: connections: Add a new xprt method, remove_xprt.
Add a new method to xprt_ops, remove_xprt. When called, if the provided
xprt_ctx is the same as the xprt's underlying xprt_ctx, it then uses the
new xprt provided, otherwise it calls the remove_xprt method of the next
xprt.
The goal is to be able to add a temporary xprt, that removes itself from
the chain when it did what it had to do. This will be used to implement
a pseudo-xprt for anything that just requires a handshake (such as the
proxy protocol).
2019-06-05 18:03:38 +02:00
Olivier Houchard
000694cf96 MINOR: ssl: Make ssl_sock_handshake() static.
ssl_sock_handshake is now only used by the ssl code itself, there's no need
to export it anymore, so make it static.
2019-06-05 18:03:38 +02:00
Olivier Houchard
ea8dd949e4 MEDIUM: ssl: Handle subscribe by itself.
As the SSL code may have different needs than the upper layer, ie it may want
to receive when the upper layer wants to right, instead of directly forwarding
the subscribe to the underlying xprt, handle it ourself. The SSL code will
know remember any subscribe call, and wake the tasklet when it is ready
for more I/O.
2019-06-05 18:03:38 +02:00
Olivier Houchard
c3df4507fa MEDIUM: connections: Wake the upper layer even if sending/receiving is disabled.
In conn_fd_handler(), if the fd is ready to send/recv, wake the upper layer
even if we have CO_FL_ERROR, or if CO_FL_XPRT_RD_ENA/CO_FL_XPRT_WR_ENA isn't
set. The only reason we should reach that point is if we had a shutw/shutr,
and the upper layer may want to know about it, and is supposed to handle it
anyway.
2019-06-05 18:03:38 +02:00
Olivier Houchard
49065544d0 MEDIUM: checks: Make sure we unsubscribe before calling cs_destroy().
When we want to destroy the conn_stream for some reason, usually on error,
make sure we unsubscribed before doing so. If we subsscribed, the xprt may
ultimately wake our tasklet on close, aand the check tasklet doesn't expect
it ot happen when we have no longer any conn_stream.
2019-06-05 18:03:38 +02:00
Olivier Houchard
14fcc2ebcc BUG/MEDIUM: servers: Don't attempt to destroy idle connections if disabled.
In connect_server(), when deciding if we should attempt to remove idle
connections, because we have to many file descriptors opened, don't attempt
to do so if idle connection pool is disabled (with pool-max-conn 0), as
if it is, srv->idle_orphan_conns won't even be allocated, and trying to
dereference it will cause a crash.
2019-06-05 13:58:06 +02:00
Frédéric Lécaille
344e94816c BUG/MINOR: peers: Wrong "server_name" decoding.
This patch fixes a bug which does not occur at this time because the "server_name"
stick-table data type is the last one (see STKTABLE_DT_SERVER_NAME). It was introduced
by this commit: "MINOR: peers: Make peers protocol support new "server_name" data type".

Indeed when receiving STD_T_DICT stick-table data type we first decode the length
of these data, then we decode the ID of this dictionary entry. To know if there
is remaining data to parse, we check if we have reached the end of the current data,
relying on <msg_end> variable. But <msg_end> is at the end of the entire message!

So this patch computes the correct end of the current STD_T_DICT before doing
anything else with it.

Nothing to backport.
2019-06-05 13:36:34 +02:00
Christopher Faulet
0bdeeaacbb BUG/MINOR: flt_trace/htx: Only apply the random forwarding on the message body.
In the function trace_http_payload(), when the random forwarding is enabled,
only blocks of type HTX_BLK_DATA must be considered. Because other blocks must
be forwarding in one time.

This patch must be backported to 1.9. But it will have to be adapted. Because
several changes on the HTX in the 2.0 are missing in the 1.9.
2019-06-05 10:12:11 +02:00
Christopher Faulet
c31872fc04 BUG/MINOR: mux-h1: Don't send more data than expected
In h1_snd_buf(), we try to consume as much data as possible in a loop. In this
loop, we first format the raw HTTP message from the HTX message, then we try to
send it. But we must be carefull to never send more data than specified by the
stream-interface.

This patch must be backported to 1.9.
2019-06-05 10:12:11 +02:00
Christopher Faulet
54b5e214b0 MINOR: htx: Don't use end-of-data blocks anymore
This type of blocks is useless because transition between data and trailers is
obvious. And when there is no trailers, the end-of-message is still there to
know when data end for chunked messages.
2019-06-05 10:12:11 +02:00
Christopher Faulet
2d7c5395ed MEDIUM: htx: Add the parsing of trailers of chunked messages
HTTP trailers are now parsed in the same way headers are. It means trailers are
converted to K/V blocks followed by an end-of-trailer marker. For now, to make
things simple, the type for trailer blocks are not the same than for header
blocks. But the aim is to make no difference between headers and trailers by
using the same type. Probably for the end-of marker too.
2019-06-05 10:12:11 +02:00
Christopher Faulet
8f3c256f7e MEDIUM: cache/htx: Always store info about HTX blocks in the cache
It was only done for the headers (including the EOH marker). data were prefixed
by the info field of these blocks. The payload and the trailers of the messages
were stored in raw. The total size of headers and payload were kept in the
cached object state to help output formatting.

Now, info about each HTX block is store in the cache. Only data are allowed to
be splitted. Otherwise, all blocks of an HTX message are handled the same way,
both when storing a message in the cache and when delivering it from the
cache. This will help the cache implementation to be more robust to internal
changes in the HTX. Especially for the upcoming parsing of trailers. There is
also no more need to keep extra info in the cached object state.
2019-06-05 10:12:11 +02:00
Christopher Faulet
4c7ce017fc MINOR: mux-h1: Don't count the EOM in the estimated size of headers
If there is not enough space in the HTX message, the EOM can be delayed when a
bodyless message is added. So, don't count it in the estimated size of headers.
2019-06-05 10:12:11 +02:00
Christopher Faulet
82f0160318 MINOR: mux-h1: Add h1_eval_htx_hdrs_size() to estimate size of the HTX headers
It is just a cosmetic change, to avoid code duplication.
2019-06-05 10:12:11 +02:00
Christopher Faulet
ada34b6a86 MINOR: mux-h1: Add the flag HAVE_O_CONN on h1s
This flag is set on h1s when output messages are formatted to know the
connection mode was already processed. It replace the variable process_conn_mode
in the function h1_process_output().
2019-06-05 10:12:11 +02:00
Christopher Faulet
94b2c76399 MEDIUM: mux-h1: refactor output processing
When we format the H1 output, in the loop on the HTX message, instead of
switching on the block types, we now switch on the message state. It is almost
the same, but it will ease futur changes, on trailers and end-of markers.
2019-06-05 10:12:11 +02:00
Christopher Faulet
a2ea158cf2 BUG/MINOR: mux-h1: errflag must be set on H1S and not H1M during output processing
This bug is in an unexpected clause of the switch..case, inside
h1_process_output(). The wrong structure is used to set the error flag.

This patch must be backported to 1.9.
2019-06-05 10:12:11 +02:00
Patrick Hemmer
65674662b4 MINOR: SSL: add client/server random sample fetches
This adds 4 sample fetches:
- ssl_fc_client_random
- ssl_fc_server_random
- ssl_bc_client_random
- ssl_bc_server_random

These fetches retrieve the client or server random value sent during the
handshake.

Their use is to be able to decrypt traffic sent using ephemeral ciphers. Tools
like wireshark expect a TLS log file with lines in a few known formats
(https://code.wireshark.org/review/gitweb?p=wireshark.git;a=blob;f=epan/dissectors/packet-tls-utils.c;h=28a51fb1fb029eae5cea52d37ff5b67d9b11950f;hb=HEAD#l5209).
Previously the only format supported using data retrievable from HAProxy state
was the one utilizing the Session-ID. However an SSL/TLS session ID is
optional, and thus cannot be relied upon for this purpose.

This change introduces the ability to extract the client random instead which
can be used for one of the other formats. The change also adds the ability to
extract the server random, just in case it might have some other use, as the
code change to support this was trivial.
2019-06-05 10:07:44 +02:00
Emmanuel Hocdet
839af57c85 CLEANUP: ssl: remove unneeded defined(OPENSSL_IS_BORINGSSL)
BoringSSL pretend to be compatible with OpenSSL 1.1.0 and
OPENSSL_VERSION_NUMBER is set accordly: cleanup redundante #ifdef.
2019-06-05 10:01:44 +02:00
Frédéric Lécaille
36fb77e295 MINOR: peers: Replace hard-coded values for peer protocol messaging by macros.
Simple patch to replace hard-coded values in relation with bytes identifiers used
for stick-table messages by macros.
2019-06-05 08:42:36 +02:00
Frédéric Lécaille
32b5573b13 MINOR: peers: Replace hard-coded for peer protocol 64-bits value encoding by macros.
With this patch we define macros for the minimum values which are
encoded for 2 up to 10 bytes. This latter is big enough to encode
UINT64_MAX. We replaced at several places 240 value by PEER_ENC_2BYTES_MIN
which is the minimum value which is encoded with 2 bytes. The peer protocol
encoding consisting in encoding with only one byte a value which is
less than PEER_ENC_2BYTES_MIN and with at least 2 bytes a 64-bits value greater
than PEER_ENC_2BYTES_MIN.
2019-06-05 08:42:36 +02:00
Frédéric Lécaille
62b0b0bc02 MINOR: peers: Add dictionary cache information to "show peers" CLI command.
This patch adds dictionary entries cached and used for the server by name
stickiness feature (exchanged thanks to peers protocol).
2019-06-05 08:42:36 +02:00
Frédéric Lécaille
16b4f54533 MINOR: stick-table: Make the CLI stick-table handler support dictionary entry data type.
Simple patch to dump the values (strings) of dictionary entries stored in stick-table
entries with STD_T_DICT as internal data type.
2019-06-05 08:42:36 +02:00
Frédéric Lécaille
8d78fa7def MINOR: peers: Make peers protocol support new "server_name" data type.
Make usage of the APIs implemented for dictionaries (dict.c) and their LRU caches (struct dcache)
so that to send/receive server names used for the server by name stickiness. These
names are sent over the network as follows:

 - in every case we send the encode length of the data (STD_T_DICT), then
 - if the server names is not present in the cache used upon transmission (struct dcache_tx)
   we cache it and we the ID of this TX cache entry followed the encode length of the
   server name, and finally the sever name itseft (non NULL terminated string).
 - if the server name is present, we repead these operations but we only send the TX cache
   entry ID.

Upon receipt, the couple of (cache IDs, server name) are stored the LRU cache used
only upon receipt (struct dcache_rx). As the peers protocol is symetrical, the fact
that the server name is present in the received data (resp. or not) denotes if
the entry is absent (resp. or not).
2019-06-05 08:42:33 +02:00
Frédéric Lécaille
03cdf55e69 MINOR: stream: Stickiness server lookup by name.
With this patch we modify the stickiness server targets lookup behavior.
First we look for this server targets by their names before looking for them by their
IDs if not found. We also insert a dictionary entry for the name of the server targets
and store the address of this entry in the underlying stick-table.
2019-06-05 08:33:35 +02:00
Frédéric Lécaille
7da71293e4 MINOR: server: Add a dictionary for server names.
This patch only declares and defines a dictionary for the server
names (stored as ->id member field).
2019-06-05 08:33:35 +02:00
Frédéric Lécaille
84d6046a33 MINOR: proxy: Add a "server by name" tree to proxy.
Add a tree to proxy struct to lookup by name for servers attached
to this proxy and populated it at parsing time.
2019-06-05 08:33:35 +02:00
Frédéric Lécaille
db52d9087a MINOR: cfgparse: Space allocation for "server_name" stick-table data type.
When parsing sticking rules, with this patch we reserve some room for the new
"server_name" stick-table data type, as this is already done for "server_id",
setting the offset and used space (in bytes) in the stick-table entry thanks
to stkable_alloc_data_type().
2019-06-05 08:33:35 +02:00
Frédéric Lécaille
5ad57ea85f MINOR: stick-table: Add "server_name" new data type.
This simple patch only adds definitions to create a new stick-table
data type ID and a new standard type to store information in relation
wich dictionary entries (STD_T_DICT).
2019-06-05 08:33:35 +02:00
Frédéric Lécaille
74167b25f7 MINOR: peers: Add a LRU cache implementation for dictionaries.
We want to send some stick-table data fields stored as strings in dictionaries
without consuming too much memory and CPU. To do so we implement with this patch
a cache for send/received dictionaries entries. These dictionary of strings entries are
stored in others real dictionary entries with an identifier as key (unsigned int)
and a pointer to the dictionary of strings entries as values.
2019-06-05 08:33:35 +02:00
Frédéric Lécaille
4a3fef834c MINOR: dict: Add dictionary new data structure.
This patch adds minimalistic definitions to implement dictionary new data structure
which is an ebtree of ebpt_node structs with strings as keys. Note that this has nothing
to see with real dictionary data structure (maps of keys in association with values).
2019-06-05 08:33:35 +02:00
Frédéric Lécaille
0e8db97df4 BUG/MINOR: peers: Wrong stick-table update message building.
When creating this patch "CLEANUP: peers: Replace hard-coded values by macros",
we realized there was a remaining place in peer_prepare_updatemsg() where the maximum
of an encoded length harcoded value could be replaced by PEER_MSG_ENCODED_LENGTH_MAXLEN
macro. But in this case, the 1 harcoded value for the header length is wrong. Should
be 2 or PEER_MSG_HEADER_LEN. So, there is a missing byte to encode the length of
remaining data after the header.

Note that the bug was never encountered because even with a missing byte, we could
encode a maximum length which would be (1<<25) (32MB) according to the following
extract of the peers protocol documentation which were from far a never reached limit
I guess:

  I) Encoded Integer and Bitfield.

         0  <= X < 240        : 1 byte  (7.875 bits)  [ XXXX XXXX ]
        240 <= X < 2288       : 2 bytes (11 bits)     [ 1111 XXXX ] [ 0XXX XXXX ]
       2288 <= X < 264432     : 3 bytes (18 bits)     [ 1111 XXXX ] [ 1XXX XXXX ]   [ 0XXX XXXX ]
     264432 <= X < 33818864   : 4 bytes (25 bits)     [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
   33818864 <= X < 4328786160 : 5 bytes (32 bits)     [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
2019-06-05 08:33:34 +02:00
Frédéric Lécaille
39143340ec CLEANUP: peers: Replace hard-coded values by macros.
All the peer stick-table messages are made of a 2-byte header (PEER_MSG_HEADER_LEN)
followed by the encoded length of the remaining data wich is harcoded as 5 (in bytes)
for the maximum (PEER_MSG_ENCODED_LENGTH_MAXLEN). With such a length we can encode
a maximum length which equals to (1 << 32) - 1, which is from far enough.

This patches replaces both these values by macros where applicable.
2019-06-05 08:33:34 +02:00
Willy Tarreau
5598d171b3 BUILD: task: fix a build warning when threads are disabled
The __decl_hathreads() macro will leave a lone semi-colon making the end
of variables declarations, resulting in a warning if threads are disabled.
Let's simply swap it with the last variable. Thanks to Ilya Shipitsin for
reporting this issue.

No backport is needed.
2019-06-04 17:18:40 +02:00
Willy Tarreau
4b7531f48b BUG/MEDIUM: vars: make the tcp/http unset-var() action support conditions
Patrick Hemmer reported that http-request unset-var(foo) if ... fails to
parse. The reason is that it reuses the same parser as "set-var(foo)" which
makes a special case of the arguments, supposed to be a sample expression
for set-var, but which must not exist for unset-var. Unfortunately the
parser finds "if" or "unless" and believes it's an expression. Let's simply
drop the test so that the outer rule parser deals with potential extraneous
keywords.

This should be backported to all versions supporting unset-var().
2019-06-04 16:48:15 +02:00
Willy Tarreau
f37b140b06 BUG/MEDIUM: vars: make sure the scope is always valid when accessing vars
Patrick Hemmer reported that a simple tcp rule involving a variable like
this is enough to crash haproxy :

    frontend foo
        bind :8001
        tcp-request session set-var(txn.foo) src

The tests on the variables scopes is not strict enough, it needs to always
verify if the stream is valid when accessing a req/res/txn variable. This
patch does this by adding a new get_vars() function which does the job
instead of open-coding all the lookups everywhere.

It must be backported to all versions supporting set-var and
"tcp-request session" so at least 1.9 and 1.8.
2019-06-04 16:27:36 +02:00
Willy Tarreau
42a6621d30 BUILD: tools: do not use the weak attribute for trace() on obsolete linkers
The default dummy trace() function is marked weak in order to be easily
replaced at link time. Some linkers are having issues with the weak
attribute, so let's not mark it on these linkers. They will simply not
be able to build with TRACE=1, which is no big deal since it's only used
by developers.
2019-06-04 16:02:26 +02:00
Willy Tarreau
fb55365f9e MINOR: server: increase the default pool-purge-delay to 5 seconds
The default used to be a very aggressive delay of 1 second before starting
to purge idle connections, but tests show that with bursty traffic it's a
bit short. Let's increase this to 5 seconds.
2019-06-04 14:06:31 +02:00
Willy Tarreau
a689c3d8d4 MEDIUM: stream: make a full process_stream() loop when completing I/O on exit
During 1.9 development cycle a shortcut was made in process_stream() to
update the analysers immediately after an I/O even detected on the send()
path while leaving the function. In order to prevent this from being abused
by a single stream stealing all the CPU, the loop didn't cover the initial
recv() call, so that events ultimately converge.

This has caused a number of issues over time because the conditions to
decide to loop are a bit tricky. For example the CF_READ_PARTIAL flag is
not immediately removed from rqf_last and may appear for a long time at
this point, sometimes causing some loops to last long.

Another unexpected side effect is that all analysers are called again with
no data to process, just because CF_WRITE_PARTIAL is present. We cannot get
rid of this event even if of very rare use, because some analysers might
wait for some data to leave a buffer before proceeding. With a full loop,
this event would have been merged with a subsequent recv() allowing analysers
to do something more useful than just ack an event they don't care about.

While during early 1.9-dev it was very important to be kind with the
scheduler, nowadays it's lock-free for local tasks so this optimization
is much less interesting to use it for I/Os, especially if we factor in
the trouble it causes.

This patch thus removes the use of the loop for regular I/Os and instead
performs a task_wakeup() with an I/O event so that the task will be
scheduled after all other ones and will have a chance to perform another
recv() and possibly to gather more I/O events to be processed at once.
Synchronous errors and transitions to SI_ST_DIS however are still handled
by the loop.

Doing so significantly reduces the average number of calls to analysers
(those are typically halved when compression is enabled in legacy mode),
and as a side benefit, has increased the H1 performance by about 1%.
2019-06-03 17:55:23 +02:00
Willy Tarreau
7bb39d7cd6 CLEANUP: connection: remove the now unused CS_FL_REOS flag
Let's remove it before it gets uesd again. It was mostly replaced with
CS_FL_EOI and by mux-specific states or flags.
2019-06-03 14:23:33 +02:00
Willy Tarreau
c493c9cb08 MEDIUM: mux-h1: don't use CS_FL_REOS anymore
This flag was already removed from other muxes and from the upper layers,
because it was misused. It indicates to the mux that the end of a stream
was already seen and is pending after existing data, but this should not
be on the conn_stream but internal to the mux.

This patch creates a new H1S flag H1S_F_REOS to replace it and uses it to
replace the last uses of CS_FL_REOS.
2019-06-03 14:18:22 +02:00
Willy Tarreau
fbdf90a6f9 BUG/MEDIUM: mux-h1: only check input data for the current stream, not next one
The mux-h1 doesn't properly propagate end of streams to the application
layer when requests are pipelined. This is visible by launching h2load
in h1 mode with -m greater than 1 : issuing Ctrl-C has no effect until
the client timeout expires.

The reason is that among the checks conditionning the reporting of the
end of stream status and waking up the streams, is a test on the presence
of remaining input data in the demux. But with pipelining, these data may
be present for another stream and should not prevent the end of stream
condition from being reported.

This patch addresses this issue by introducing a new function
"h1s_data_pending" which returns a boolean indicating if there are in
the demux buffer any data for the current stream. That is, if the stream
is in H1_MSG_DONE state, there are never any data for it. And if it's in
a different state, then the demux buffer is checked. This replaces the
tests on b_data(&h1c->ibuf) and correctly allows end of streams to be
reported at the end of requests.

It's worth noting that 1.9 doesn't suffer from this issue but it possibly
isn't completely immune either given that the same tests are present.
2019-06-03 14:13:23 +02:00
Willy Tarreau
d58f27fead MINOR: mux-h1: don't try to recv() before the connection is ready
Just as we already do in h1_send(), if the connection is not yet ready,
do not proceed and instead subscribe. This avoids a needless recvfrom()
and subscription to polling for a case which will never work since the
request was not even sent.
2019-06-03 10:17:12 +02:00
Willy Tarreau
694fcd0ee4 MINOR: connection: also stop receiving after a SOCKS4 response
Just as is done in previous patch for all handshake handlers,
also stop receiving after a SOCKS4 response was received. This
one escaped the previous cleanup but must be done to keep the
code safe.
2019-06-03 10:16:35 +02:00
Willy Tarreau
6499b9d996 BUG/MEDIUM: connection: fix multiple handshake polling issues
Connection handshakes were rarely stacked on top of each other, but the
recent experiments consisting in sending PROXY over SOCKS4 revealed a
number of issues in these lower layers. First, each handler waiting for
data MUST subscribe to recv events with __conn_sock_want_recv() and MUST
unsubscribe from send events using __conn_sock_stop_send() to avoid any
wake-up loop in case a previous sender has set this. Second, each handler
waiting for sending MUST subscribe to send events with __conn_sock_want_send()
and MUST unsubscribe from recv events using __conn_sock_stop_recv() to
avoid any wake-up loop in case some data are available on the connection.

Till now this was done at various random places, and in particular the
cases where the FD was not ready for recv forgot to re-enable reading.

Second, while senders can happily use conn_sock_send() which automatically
handles EINTR, loops, and marks the FD as not ready with fd_cant_send(),
there is no equivalent for recv so receivers facing EAGAIN MUST call
fd_cant_send() to enable polling. It could be argued that implementing
an equivalent conn_sock_recv() function could be useful and more
long-term proof than the current situation.

Third, both types of handlers MUST unsubscribe from their respective
events once they managed to do their job, and none may even play with
__conn_xprt_*(). Here again this was lacking, and one surprizing call
to __conn_xprt_stop_recv() was present in the proxy protocol parser
for TCP6 messages!

Thanks to Alexander Liu for his help on this issue.

This patch must be backported to 1.9 and possibly some older versions,
though the SOCKS parts should be dropped.
2019-06-03 08:31:22 +02:00
Willy Tarreau
7067b3a92e BUG/MINOR: deinit/threads: make hard-stop-after perform a clean exit
As reported in GH issue #99, when hard-stop-after triggers and threads
are in use, the chance that any thread releases the resources in use by
the other ones is non-null. Thus no thread should be allowed to deinit()
nor exit by itself.

Here we take a different approach. We simply use a 3rd possible value
for the "killed" variable so that all threads know they must break out
of the run-poll-loop and immediately stop.

This patch was tested by commenting the stream_shutdown() calls in
hard_stop() to increase the chances to see a stream use released
resources. With this fix applied, it never crashes anymore.

This fix should be backported to 1.9 and 1.8.
2019-06-02 11:30:07 +02:00
Alexander Liu
2a54bb74cd MEDIUM: connection: Upstream SOCKS4 proxy support
Have "socks4" and "check-via-socks4" server keyword added.
Implement handshake with SOCKS4 proxy server for tcp stream connection.
See issue #82.

I have the "SOCKS: A protocol for TCP proxy across firewalls" doc found
at "https://www.openssh.com/txt/socks4.protocol". Please reference to it.

[wt: for now connecting to the SOCKS4 proxy over unix sockets is not
 supported, and mixing IPv4/IPv6 is discouraged; indeed, the control
 layer is unique for a connection and will be used both for connecting
 and for target address manipulation. As such it may for example report
 incorrect destination addresses in logs if the proxy is reached over
 IPv6]
2019-05-31 17:24:06 +02:00
Olivier Houchard
cfbb3e6560 MEDIUM: tasks: Get rid of active_tasks_mask.
Remove the active_tasks_mask variable, we can deduce if we've work to do
by other means, and it is costly to maintain. Instead, introduce a new
function, thread_has_tasks(), that returns non-zero if there's tasks
scheduled for the thread, zero otherwise.
2019-05-29 21:53:37 +02:00
Olivier Houchard
661167d136 BUG/MEDIUM: connection: Use the session to get the origin address if needed.
In conn_si_send_proxy(), if we don't have a conn_stream yet, because the mux
won't be created until the SSL handshake is done, retrieve the opposite's
connection from the session. At this point, we know the session associated
with the connection is the one that initiated it, and we can thus just use
the session's origin.

This should be backported to 1.9.
2019-05-29 17:56:59 +02:00
Willy Tarreau
201840abf1 BUG/MEDIUM: mux-h2: don't refrain from offering oneself a used buffer
Usually when calling offer_buffer(), we don't expect to offer it to
ourselves. But with h2 we have the same buffer_wait for the two directions
so we can unblock the recv path when completing a send(), or we can unblock
part of the mux buffer after sending the first few buffers that we managed
to collect. Thus it is important to always accept to wake up any requester.

A few parts of this patch could possibly be backported but earlier versions
already have other issues related to low-buffer condition so it's not sure
it's worth taking the risk to make things worse.
2019-05-29 17:54:35 +02:00
Willy Tarreau
7f1265a238 BUG/MEDIUM: mux-h2: fix the conditions to end the h2_send() loop
The test for the mux alloc failure in h2_send() right after an attempt
at h2_process_mux() used to make sense as it tried to detect that this
latter failed to produce data. But now that we have a list of buffers,
it is a perfectly valid situation where there can still be data in the
buffer(s).

So now when we see this flag we only declare it's the last run on the
loop. In addition we need to make sure we break out of the loop on
snd_buf failure, or we'll loop indefinitely, for example when the buf
is full and we can't send.

No backport is needed.
2019-05-29 17:54:35 +02:00
Olivier Houchard
58d87f31f7 BUG/MEDIUM: h2: Don't forget to set h2s->cs to NULL after having free'd cs.
In h2c_frt_stream_new, if we failed to create the stream for some reason,
don't forget to set h2s->cs to NULL before calling h2s_destroy(), otherwise
h2s_destroy() will call h2s_close(), which will attempt to access
h2s->cs->flags if it's non-NULL.

This should be backported to 1.9.
2019-05-29 16:45:13 +02:00
Olivier Houchard
250031e444 MEDIUM: sessions: Introduce session flags.
Add session flags, and add a new flag, SESS_FL_PREFER_LAST, to be set when
we use NTLM authentication, and we should reuse the last connection. This
should fix using NTLM with HTX. This totally replaces TX_PREFER_LAST.

This should be backported to 1.9.
2019-05-29 15:41:47 +02:00
Christopher Faulet
1146f975a9 BUG/MEDIUM: mux-h1: Don't skip the TCP splicing when there is no more data to read
When there is no more data to read (h1m->curr_len == 0 in the state
H1_MSG_DATA), we still call xprt->rcv_pipe() callback. It is important to update
connection's flags. Especially to remove the flag CO_FL_WAIT_ROOM. Otherwise,
the pipe remains marked as full, preventing the stream-interface to fallback on
rcv_buf(). So the connection may be freezed because no more data is received and
the mux H1 remains blocked in the state H1_MSG_DATA.

This patch must be backported to 1.9.
2019-05-29 15:32:14 +02:00
Willy Tarreau
1e928c074b MEDIUM: task: don't grab the WR lock just to check the WQ
When profiling locks, it appears that the WQ's lock has become the most
contended one, despite the WQ being split by thread. The reason is that
each thread takes the WQ lock before checking if it it does have something
to do. In practice the WQ almost only contains health checks and rare tasks
that can be scheduled anywhere, so this is a real waste of resources.

This patch proceeds differently. Now that the WQ's lock was turned to RW
lock, we proceed in 3 phases :
  1) locklessly check for the queue's emptiness

  2) take an R lock to retrieve the first element and check if it is
     expired. This way most visits are performed with an R lock to find
     and return the next expiration date.

  3) if one expiration is found, we perform the WR-locked lookup as
     usual.

As a result, on a one-minute test involving 8 threads and 64 streams at
1.3 million ctxsw/s, before this patch the lock profiler reported this :

    Stats about Lock TASK_WQ:
         # write lock  : 1125496
         # write unlock: 1125496 (0)
         # wait time for write     : 263.143 msec
         # wait time for write/lock: 233.802 nsec
         # read lock   : 0
         # read unlock : 0 (0)
         # wait time for read      : 0.000 msec
         # wait time for read/lock : 0.000 nsec

And after :

    Stats about Lock TASK_WQ:
         # write lock  : 173
         # write unlock: 173 (0)
         # wait time for write     : 0.018 msec
         # wait time for write/lock: 103.988 nsec
         # read lock   : 1072706
         # read unlock : 1072706 (0)
         # wait time for read      : 60.702 msec
         # wait time for read/lock : 56.588 nsec

Thus the contention was divided by 4.3.
2019-05-28 19:15:44 +02:00
Willy Tarreau
ef28dc11e3 MINOR: task: turn the WQ lock to an RW_LOCK
For now it's exclusively used as a write lock though, thus it remains
100% equivalent to the spinlock it replaces.
2019-05-28 19:15:44 +02:00
Willy Tarreau
186e96ece0 MEDIUM: buffers: relax the buffer lock a little bit
In lock profiles it's visible that there is a huge contention on the
buffer lock. The reason is that when offer_buffers() is called, it
systematically takes the lock before verifying if there is any
waiter. However doing so doesn't protect against races since a
waiter can happen just after we release the lock as well. Similarly
in h2 we take the lock every time an h2c is going to be released,
even without checking that the h2c belongs to a wait list. These
two have now been addressed by verifying non-emptiness of the list
prior to taking the lock.
2019-05-28 17:25:21 +02:00
Willy Tarreau
a8b2ce02b8 MINOR: activity: report the number of failed pool/buffer allocations
Haproxy is designed to be able to continue to run even under very low
memory conditions. However this can sometimes have a serious impact on
performance that it hard to diagnose. Let's report counters of failed
pool and buffer allocations per thread in show activity.
2019-05-28 17:25:21 +02:00
Willy Tarreau
2ae84e445d MEDIUM: poller: separate the wait time from the wake events
We have been abusing the do_poll()'s timeout for a while, making it zero
whenever there is some known activity. The problem this poses is that it
complicates activity diagnostic by incrementing the poll_exp field for
each known activity. It also requires extra computations that could be
avoided.

This change passes a "wake" argument to say that the poller must not
sleep. This simplifies the operations and allows one to differenciate
expirations from activity.
2019-05-28 17:25:21 +02:00
Willy Tarreau
d78d08f95b MINOR: activity: report totals and average separately
Some fields need to be averaged instead of summed (e.g. avg_poll_us)
when reported on the CLI. Let's have a distinct macro for this.
2019-05-28 17:25:21 +02:00
Willy Tarreau
a0211b864c MINOR: activity: write totals on the "show activity" output
Most of the time we find ourselves adding per-thread fields to observe
activity, so let's compute these on the fly and display them. Now the
output shows "field: total [ thr0 thr1 ... thrn ]".
2019-05-28 15:16:09 +02:00
Willy Tarreau
0350b90e31 MEDIUM: htx: make htx_add_data() never defragment the buffer
Now instead of trying to fit 100% of the input data into the output
buffer at the risk of defragmenting it, we put what fits into it only
and return the amount of bytes transferred. In a test, compared to the
previous commit, it increases the cached data rate from 44 Gbps to
55 Gbps and saves a lot in case of large buffers : with a 1 MB buffer,
uncached transfers jumped from 700 Mbps to 30 Gbps.
2019-05-28 14:48:59 +02:00
Willy Tarreau
0a7ef02074 MINOR: htx: make htx_add_data() return the transmitted byte count
In order to later allow htx_add_data() to transmit partial blocks and
avoid defragmenting the buffer, we'll need to return the number of bytes
consumed. This first modification makes the function do this and its
callers take this into account. At the moment the function still works
atomically so it returns either the block size or zero. However all
call places have been adapted to consider any value between zero and
the block size.
2019-05-28 14:48:59 +02:00
Willy Tarreau
d4908fa465 MINOR: htx: rename htx_append_blk_value() to htx_add_data_atonce()
This function is now dedicated to data blocks, and we'll soon need to
access it from outside in a rare few cases. Let's rename it and export
it.
2019-05-28 14:48:59 +02:00
Olivier Houchard
692c1d07f9 MINOR: ssl: Don't forget to call the close method of the underlying xprt.
In ssl_sock_close(), don't forget to call the underlying xprt's close method
if it exists. For now it's harmless not to do so, because the only available
layer is the raw socket, which doesn't have a close method, but that will
change when we implement QUIC.
2019-05-28 10:08:39 +02:00
Olivier Houchard
19afb274ad MINOR: ssl: Make sure the underlying xprt's init method doesn't fail.
In ssl_sock_init(), when initting the underlying xprt, check the return value,
and give up if it fails.
2019-05-28 10:08:28 +02:00
Willy Tarreau
11c90fbd92 BUG/MEDIUM: http: fix "http-request reject" when not final
When "http-request reject" was introduced in 1.8 with commit 53275e8b0
("MINOR: http: implement the "http-request reject" rule"), it was already
broken. The code mentions "it always returns ACT_RET_STOP" and obviously
a gross copy-paste made it ACT_RET_CONT. If the rule is the last one it
properly blocks, but if not the last one it gets ignored, as can be seen
with this simple configuration :

    frontend f1
        bind :8011
        mode http
        http-request reject
        http-request redirect location /

This trivial fix must be backported to 1.9 and 1.8. It is tracked by
github issue #107.
2019-05-28 08:26:17 +02:00
Christopher Faulet
39744f792d MINOR: htx: Remove support of pseudo headers because it is unused
The code to handle pseudo headers is unused and with no real value. So remove
it.
2019-05-28 07:42:33 +02:00
Christopher Faulet
ced39006a2 MINOR: htx: don't rely on htx_find_blk() anymore in the function htx_truncate()
the function htx_find_blk() is used by only one function, htx_truncate(). So
because this function does nothing very smart, we don't use it anymore. It will
be removed by another commit.
2019-05-28 07:42:33 +02:00
Christopher Faulet
0f6d6a9ab6 MINOR: htx: Optimize htx_drain() when all data are drained
Instead of looping on the HTX message to drain all data, the message is now
reset..
2019-05-28 07:42:33 +02:00
Christopher Faulet
ee847d45d0 MEDIUM: filters/htx: Filter body relatively to the first block
The filters filtering HTX body, in the callback http_payload, must now loop on
an HTX message starting from the first block position. The offset passed as
parameter is relative to this position and not the head one. It is mandatory
because once filtered, data are now forwarded using the function
channel_htx_fwd_payload(). So the first block position is always updated.
2019-05-28 07:42:33 +02:00
Christopher Faulet
16af60e540 MINOR: proto-htx: Use channel_htx_fwd_all() when unfiltered body are forwarded
So the first block position of the HTX message will always be updated
accordingly.
2019-05-28 07:42:33 +02:00
Christopher Faulet
8fa60e4613 MINOR: stats/htx: don't use the first block position but the head one
Applets must never rely on the first block position to consume an HTX
message. The head position must be used instead. For the request it is always
the start-line. At this stage, it is not a bug, because the first position of
the request is never changed by HTX analysers.
2019-05-28 07:42:33 +02:00
Christopher Faulet
29f1758285 MEDIUM: htx: Store the first block position instead of the start-line one
We don't store the start-line position anymore in the HTX message. Instead we
store the first block position to analyze. For now, it is almost the same. But
once all changes will be made on this part, this position will have to be used
by HTX analyzers, and only in the analysis context, to know where the analyse
should start.

When new blocks are added in an HTX message, if the first block position is not
defined, it is set. When the block pointed by it is removed, it is set to the
block following it. -1 remains the value to unset the position. the first block
position is unset when the HTX message is empty. It may also be unset on a
non-empty message, meaning every blocks were already analyzed.

From HTX analyzers point of view, this position is always set during headers
analysis. When they are waiting for a request or a response, if it is unset, it
means the analysis should wait. But once the analysis is started, and as long as
headers are not forwarded, it points to the message start-line.

As mentionned, outside the HTX analysis, no code must rely on the first block
position. So multiplexers and applets must always use the head position to start
a loop on an HTX message.
2019-05-28 07:42:33 +02:00
Christopher Faulet
ee1bd4b4f7 MINOR: proto-htx: Use channel_htx_fwd_headers() to forward 1xx responses
Instead of doing it by hand, we now call the dedicated function to do so.
2019-05-28 07:42:33 +02:00
Christopher Faulet
17fd8a261f MINOR: filters/htx: Use channel_htx_fwd_headers() after headers filtering
Instead of doing it by hand in the function flt_analyze_http_headers(), we now
call the dedicated function to do so.
2019-05-28 07:42:33 +02:00
Christopher Faulet
b75b5eaf26 MEDIUM: htx: 1xx messages are now part of the final reponses
1xx informational messages (all except 101) are now part of the HTTP reponse,
semantically speaking. These messages are not followed by an EOM anymore,
because a final reponse is always expected. All these parts can also be
transferred to the channel in same time, if possible. The HTX response analyzer
has been update to forward them in loop, as the legacy one.
2019-05-28 07:42:30 +02:00
Christopher Faulet
a61e97bcae MINOR: htx: Be sure to xfer all headers in one time in htx_xfer_blks()
In the function htx_xfer_blks(), we take care to transfer all headers in one
time. When the current block is a start-line, we check if there is enough space
to transfer all headers too. If not, and if the destination is empty, a parsing
error is reported on the source.

The H2 multiplexer is the only one to use this function. When a parsing error is
reported during the transfer, the flag CS_FL_EOI is also set on the conn_stream.
2019-05-28 07:42:12 +02:00
Christopher Faulet
a39d8ad086 MINOR: mux-h1: Set hdrs_bytes on the SL when an HTX message is produced 2019-05-28 07:42:12 +02:00
Christopher Faulet
33543e73a2 MINOR: h2/htx: Set hdrs_bytes on the SL when an HTX message is produced 2019-05-28 07:42:12 +02:00
Christopher Faulet
05c083ca8d MINOR: htx: Add a field to set the memory used by headers in the HTX start-line
The field hdrs_bytes has been added in the structure htx_sl. It should be used
to set how many bytes are help by all headers, from the start-line to the
corresponding EOH block. it must be set to -1 if it is unknown.
2019-05-28 07:42:12 +02:00
Christopher Faulet
2f6edc84a8 MINOR: mux-h2/htx: Support zero-copy when possible in h2_rcv_buf()
If the channel's buffer is empty and the message is small enough, we can swap
the H2S buffer with the channel one.
2019-05-28 07:42:12 +02:00
Christopher Faulet
9cdd5036f3 MINOR: stream-int: Don't use the flag CO_RFL_KEEP_RSV anymore in si_cs_recv()
Because the channel_recv_max() always return the right value, for HTX and legacy
streams, we don't need to set this flag. The multiplexer don't use it anymore.
2019-05-28 07:42:12 +02:00
Christopher Faulet
8a9ad4c0e8 MINOR: mux-h2: Use the count value received from the SI in h2_rcv_buf()
Now, the SI calls h2_rcv_buf() with the right count value. So we can rely on
it. Unlike the H1 multiplexer, it is fairly easier for the H2 multiplexer
because the HTX message already exists, we only transfer blocks from the H2S to
the channel. And this part is handled by htx_xfer_blks().
2019-05-28 07:42:12 +02:00
Christopher Faulet
30db3d737b MEDIUM: mux-h1: Use the count value received from the SI in h1_rcv_buf()
Now, the SI calls h1_rcv_buf() with the right count value. So we can rely on
it. During the parsing, we now really respect this value to be sure to never
exceed it. To do so, once headers are parsed, we should estimate the size of the
HTX message before copying data.
2019-05-28 07:42:12 +02:00
Christopher Faulet
156852b613 BUG/MINOR: htx: Change htx_xfer_blk() to also count metadata
This patch makes the function more accurate. Thanks to the function
htx_get_max_blksz(), the transfer of data has been simplified. Note that now the
total number of bytes copied (metadata + payload) is returned. This slighly
change how the function is used in the H2 multiplexer.
2019-05-28 07:42:12 +02:00
Christopher Faulet
a3f1550dfa MEDIUM: http/htx: Perform analysis relatively to the first block
The first block is the start-line, if defined. Otherwise it the head of the HTX
message. So now, during HTTP analysis, lookup are all done using the first block
instead of the head. Concretely, for now, it is the same because only one HTTP
message is stored at a time in an HTX message. 1xx informational messages are
handled separatly from the final reponse and from each other. But it will make
sense when the 1xx informational messages and the associated final reponse will
be stored in the same HTX message.
2019-05-28 07:42:12 +02:00
Christopher Faulet
7b7d507a5b MINOR: http/htx: Use sl_pos directly to replace the start-line
Since the HTX start-line is now referenced by position instead of by its payload
address, it is fairly easier to replace it. No need to search the rigth block to
find the start-line comparing the payloads address. It just enough to get the
block at the position sl_pos.
2019-05-28 07:42:12 +02:00
Christopher Faulet
297fbb45fe MINOR: htx: Replace the function http_find_stline() by http_get_stline()
Now, we only return the start-line. If not found, NULL is returned. No lookup is
performed and the HTX message is no more updated. It is now the caller
responsibility to update the position of the start-line to the right value. So
when it is not found, i.e sl_pos is set to -1, it means the last start-line has
been already processed and the next one has not been inserted yet.

It is mandatory to rely on this kind of warranty to store 1xx informational
responses and final reponse in the same HTX message.
2019-05-28 07:42:12 +02:00
Christopher Faulet
b77a1d26a4 MINOR: mux-h2/htx: Get the start-line from the head when HEADERS frame is built
in the H2 multiplexer, when a HEADERS frame is built before sending it, we have
the warranty the start-line is the head of the HTX message. It is safer to rely
on this fact than on the sl_pos value. For now, it's safe to use sl_pos in muxes
because HTTP 1xx messages are considered as full messages in HTX and only one
HTTP message can be stored at a time in HTX. But we are trying to handle 1xx
messages as a part of the reponse message. In this way, an HTTP reponse will be
the sum of all 1xx informational messages followed by the final response. So it
will be possible to have several start-line in the same HTX message. And the
sl_pos will point to the first unprocessed start-line from the analyzers point
of view.
2019-05-28 07:42:12 +02:00
Christopher Faulet
9c66b980fa MINOR: htx: Store start-line block's position instead of address of its payload
Nothing much to say. This change is just mandatory to consider 1xx informational
messages as part of a response.
2019-05-28 07:42:12 +02:00
Christopher Faulet
28f29c7eea MINOR: htx: Store the head position instead of the wrap one
The head of an HTX message is heavily used whereas the wrap position is only
used when a block is added or removed. So it is more logical to store the head
position in the HTX message instead of the wrap one. The wrap position can be
easily deduced. To get it, the new function htx_get_wrap() may be used.
2019-05-28 07:42:12 +02:00
Christopher Faulet
429b91d308 MINOR: htx: Remove the macro IS_HTX_SMP() and always use IS_HTX_STRM() instead
The macro IS_HTX_SMP() is only used at a place, in a context where the stream
always exists. So, we can remove it to use IS_HTX_STRM() instead.
2019-05-28 07:42:12 +02:00
Willy Tarreau
b01302f9ac MEDIUM: config: now alert when two servers have the same name
We've been emitting warnings for over 5 years (since 1.5-dev22) about
configs accidently carrying multiple servers with the same name in the
same backend, and this starts to cause some real trouble in dynamic
environments since it's still very difficult to accurately process
a state-file and we still can't transport a server's name over the
peers protocol because of this.

It's about time to force users to fix their configs if they still
hadn't given that there is zero technical justification for doing this,
beyond the "yyp" (or copy-paste accident) when editing the config.

The message remains as clear as before, indicating the file and lines
of the conflict so that the user can easily fix it.
2019-05-27 19:31:06 +02:00
Willy Tarreau
c3b5958255 BUG/MEDIUM: threads: fix double-word CAS on non-optimized 32-bit platforms
On armv7 haproxy doesn't work because of the fixes on the double-word
CAS. There are two issues. The first one is that the last argument in
case of dwcas is a pointer to the set of value and not a value ; the
second is that it's not enough to cast the data as (void*) since it will
be a single word. Let's fix this by using the pointers as an array of
long. This was tested on i386, armv7, x86_64 and aarch64 and it is now
fine. An alternate approach using a struct was attempted as well but it
used to produce less optimal code.

This fix must be backported to 1.9. This fixes github issue #105.

Cc: Olivier Houchard <ohouchard@haproxy.com>
2019-05-27 17:40:59 +02:00
Willy Tarreau
bff005ae58 BUG/MEDIUM: queue: fix the tree walk in pendconn_redistribute.
In pendconn_redistribute() we scan the queue using eb32_next() on the
node we've just deleted, which is wrong since the node is not in the
tree anymore, and it could dereference one node that has already been
released by another thread. Note that we cannot use eb32_first() in the
loop here instead because we need to skip pendconns having SF_FORCE_PRST.
Instead, let's keep a copy of the next node before deleting it.

In addition, the pendconn retrieved there is wrong, it uses &node as
the pointer instead of node, resulting in very quick crashes when the
server list is scanned.

Fortunately this only happens when "option redispatch" is used in
conjunction with "maxconn" on server lines, "cookie" for the stickiness,
and when a server goes down with entries in its queue.

This bug was introduced by commit 0355dabd7 ("MINOR: queue: replace
the linked list with a tree") so the fix must be backported to 1.9.
2019-05-27 10:29:59 +02:00
Willy Tarreau
b6195ef2a6 BUG/MAJOR: lb/threads: make sure the avoided server is not full on second pass
In fwrr_get_next_server(), we optionally pass a server to avoid. It
usually points to the current server during a redispatch operation. If
this server is usable, an "avoided" pointer is set and we continue to
look for another server. If in the end no other server is found, then
we fall back to this avoided one, which is still better than nothing.

The problem that may arise with threads is that in the mean time, this
avoided server might have received extra connections and might not be
usable anymore. This causes it to be queued a second time in the "full"
list and the loop to search for a server again, ending up on this one
again and so on.

This patch makes sure that we break out of the loop when we have to
pick the avoided server. It's probably what the code intended to do
as the current break statement causes fwrr_update_position() and
fwrr_dequeue_srv() to be called again on the avoided server.

It must be backported to 1.9 and 1.8, and seems appropriate for older
versions though it's unclear what the impact of this bug might be
there since the race doesn't exist and we're left with the double
update of the server's position.
2019-05-27 10:29:59 +02:00
Willy Tarreau
d6a7850200 MINOR: cli/activity: add 3 general purpose counters in development mode
The unused fd_del and fd_skip were being abused during debugging sessions
as general purpose event counters. With their removal, let's officially
have dedicated counters for such use cases. These counters are called
"ctr0".."ctr2" and are listed at the end when DEBUG_DEV is set.
2019-05-27 07:03:38 +02:00
Willy Tarreau
394c9b4215 MINOR: cli/activity: remove "fd_del" and "fd_skip" from show activity
These variables are never set anymore and were always reported as zero.
2019-05-27 06:59:14 +02:00
Ilya Shipitsin
0590f44254 BUILD: ssl: fix latest LibreSSL reg-test error
starting with OpenSSL 1.0.0 recommended way to disable compression is
using SSL_OP_NO_COMPRESSION when creating context.

manipulations with SSL_COMP_get_compression_methods, sk_SSL_COMP_num
are only required for OpenSSL < 1.0.0
2019-05-26 21:26:02 +02:00
Willy Tarreau
08e2b41e81 BUILD: connections: shut up gcc about impossible out-of-bounds warning
Since commit 88698d9 ("MEDIUM: connections: Add a way to control the
number of idling connections.") when building without threads, gcc
complains that the operations made on the idle_orphan_conns[] list is
out of bounds, which is always false since 1) <i> can only equal zero,
and 2) given it's equal to <tid> we never even enter the loop. But as
usual it thinks it knows better, so let's mask the origin of this <i>
value to shut it up. Another solution consists in making <i> unsigned
and adding an explicit range check.
2019-05-26 11:54:20 +02:00
Willy Tarreau
9c218e7521 MAJOR: mux-h2: switch to next mux buffer on buffer full condition.
Now when we fail to send because the mux buffer is full, before giving
up and marking MFULL, we try to allocate another buffer in the mux's
ring to try again. Thanks to this (and provided there are enough buffers
allocated to the mux's ring), a single stream picked in the send_list
cannot steal all the mux's room at once. For this, we expand the ring
size to 31 buffers as it seems to be optimal on benchmarks since it
divides the number of context switches by 3. It will inflate each H2
conn's memory by 1 kB.

The bandwidth is now much more stable. Prior to this, it a test on
h2->h1 with very large objects (1 GB), a few tens of connections and
a few tens of streams per connection would show a varying performance
between 34 and 95 Gbps on 2 cores/4 threads, with h2_snd_buf() stopped
on a buffer full condition between 300000 and 600000 times per second.
Now the performance is constantly between 88 and 96 Gbps. Measures show
that buffer full conditions are met around only 159 times per second
in this case, or rougly 2000 to 4000 times less often.
2019-05-26 11:33:19 +02:00
Willy Tarreau
60f62682b1 MINOR: mux-h2: report the mbuf's head and tail in "show fd"
It's useful to know how the mbuf spans over the whole area and to have
access to the first and last ones, so let's dump just this.
2019-05-26 11:33:18 +02:00
Willy Tarreau
bcc4595e57 CLEANUP: mux-h2: consistently use a local variable for the mbuf
This makes the code more readable and reduces the calls to br_tail().
In addition, all calls to h2_get_buf() are now made via this local
variable, which should significantly help for retries.
2019-05-26 10:52:47 +02:00
Willy Tarreau
41c4d6a2c5 MEDIUM: mux-h2: make the send() function iterate over all mux buffers
Now send() uses a loop to iterate over all buffers to be sent. These
buffers are released and deleted from the vector once completely sent.
If any buffer gets released, offer_buffers() is called to wake up some
waiters.
2019-05-26 10:52:25 +02:00
Willy Tarreau
2e3c000c1c MINOR: mux-h2: introduce h2_release_mbuf() to release all buffers in the mbuf ring
This function iterates over all buffers in the mbuf ring to release all
of them from the head to the tail.
2019-05-26 10:51:25 +02:00
Willy Tarreau
662fafc02b MEDIUM: mux-h2: make the conditions to send based on mbuf, not just its tail
This is in preparation for iterating over lists. First we need to always
check the buffer's head and not its tail.
2019-05-26 10:50:50 +02:00
Willy Tarreau
5133096df2 MEDIUM: mux-h2: replace all occurrences of mbuf with a buffer ring
For now it's only one buffer long so the head and tails are always the
same, thus it doesn't change what used to work. In short, br_tail(h2c->mbuf)
was inserted everywhere we used to have h2c->mbuf.
2019-05-26 10:50:18 +02:00
Willy Tarreau
455d5681b6 MEDIUM: mux-h2: avoid doing expensive buffer realigns when not absolutely needed
Transferring large objects over H2 sometimes shows unexplained performance
variations. A long analysis resulted in the following discovery. Often the
mux buffer looks like this :

    [ empty_head |    data     | empty_tail ]

Typical numbers are (very common) :
  - empty_head = 31
  - empty_tail = 16  (total free=47)
  - data = 16337
  - size = 16384
  - data to copy: 43

The reason for these holes are the blocking factors that are not always
the same in and out (due to keeping 9 bytes for the frame size, or the
56 bytes corresponding to the HTX header). This can easily happen 10000
times a second if the network bandwidth permits it!

In this case, while copying a DATA frame we find that the buffer has its
free space wrapped so we decide to realign it to optimize the copy. It's
possible that this practice stems from the code used to emit headers,
which do not support fragmentation and which had no other option left.
But it comes with two problems :
  - we don't check if the data fits, which results in a memcpy for nothing
  - we can move huge amounts of data to just copy a small block.

This patch addresses this two ways :
  - first, by not forcing a data realignment if what we have to copy does
    not fit, as this is totally pointless ;

  - second, by refusing to move too large data blocks. The threshold was
    set to 1 kB, because it may make sense to move 1 kB of data to copy
    a 15 kB one at once, which will leave as a single 16 kB block, but
    it doesn't make sense to mvoe 15 kB to copy just 1 kB. In all cases
    the data would fit and would just be split into two blocks, which is
    not very expensive, hence the low limit to 1 kB

With such changes, realignments are very rare, they show up around once
every 15 seconds at 60 Gbps, and look like this, resulting in a much more
stable bit rate :

  buf=0x7fe6ec0c3510,h=16333,d=35,s=16384 room=16349 in=16337

This patch should be safe for backporting to 1.9 if some performance
issues are reported there.
2019-05-25 20:31:53 +02:00
Ilya Shipitsin
e242f3dfb8 BUG/MINOR: ssl_sock: Fix memory leak when disabling compression
according to manpage:

       sk_TYPE_zero() sets the number of elements in sk to zero. It
       does not free sk so after this call sk is still valid.

so we need to free all elements

[wt: seems like it has been there forever and should be backported
 to all stable branches]
2019-05-25 07:45:55 +02:00
Christopher Faulet
b8fd4c031c BUG/MINOR: htx: Remove a forgotten while loop in htx_defrag()
Fortunately, this loop does nothing. Otherwise it would have led to an infinite
loop. It was probably forgotten during a refactoring, in the early stage of the
HTX.

This patch must be backported to 1.9.
2019-05-24 09:11:10 +02:00
Christopher Faulet
f90c24d14c BUG/MEDIUM: proto-htx: Not forward too much data when 1xx reponses are handled
When an 1xx reponse is processed, we forward it immediatly. But another message
may already be in the channel's buffer, waiting to be processed. This may be
another 1xx reponse or the final one. So instead of forwarding everything, we
must take care to only forward the processed 1xx response.

This patch must be backported to 1.9.
2019-05-24 09:11:07 +02:00
Christopher Faulet
8e9e3ef15c BUG/MINOR: mux-h1: Report EOI instead EOS on parsing error or H2 upgrade
When a parsing error occurrs in the H1 multiplexer, we stop to copy HTX
blocks. So the error may be reported with an emtpy HTX message. For instance, if
the headers parsing failed. When it happens, the flag CS_FL_EOS is also set on
the conn_stream. But it is an error. Most of time, it is set on established
connections, so it is not really an issue. But if it happens when the server
connection is not fully established, the connection is shut down immediatly and
the stream-interface is switched from SI_ST_CON to SI_ST_DIS/CLO. So HTX
analyzers have no chance to catch the error.

Instead of setting CS_FL_EOS, it is fairly better to set CS_FL_EOI, which is the
right flag to use. The same is also done on H2 upgrade. As a side effet of this
fix, in the stream-interface code, we must now set the flag CF_READ_PARTIAL on
the channel when the flag CF_EOI is set. It is a warranty to wakeup the stream
when EOI is reported to the channel while no data are received.

This patch must be backported to 1.9.
2019-05-24 09:11:01 +02:00
Christopher Faulet
316934d3c9 BUG/MINOR: mux-h2: Count EOM in bytes sent when a HEADERS frame is formatted
In HTX, when a HEADERS frame is formatted before sending it to the client or the
server, If an EOM is found because there is no body, we must count it in the
number bytes sent.

This patch must be backported to 1.9.
2019-05-24 09:10:46 +02:00
Christopher Faulet
256b69a82d BUG/MINOR: lua: Set right direction and flags on new HTTP objects
When a LUA HTTP object is created using the current TXN object, it is important
to also set the right direction and flags, using ones from the TXN object.

This patch may be backported to all supported branches with the lua
support. But, it seems to have no impact for now.
2019-05-24 09:07:57 +02:00
Christopher Faulet
55ae8a64e4 BUG/MEDIUM: spoe: Don't use the SPOE applet after releasing it
In spoe_release_appctx(), the SPOE applet may be used after it was released to
get its exit status code. Of course, HAProxy crashes when this happens.

This patch must be backported to 1.9 and 1.8.
2019-05-24 09:07:30 +02:00
Christopher Faulet
08e6646460 BUG/MINOR: proto-htx: Try to keep connections alive on redirect
As fat as possible, we try to keep the connections alive on redirect. It's
possible when the request has no body or when the request parsing is finished.

No backport is needed.
2019-05-24 09:06:59 +02:00
Willy Tarreau
1713c03825 MINOR: stats: report the global output bit rate in human readable form
The stats page now reports the per-process output bit rate and applies
the usual conversions needed to turn the TCP payload rate to an Ethernet
bit rate in order to give a reasonably accurate estimate of how far from
interface saturation we are.
2019-05-23 12:31:51 +02:00
Willy Tarreau
7cf0e4517d MINOR: raw_sock: report global traffic statistics
Many times we've been missing per-process traffic statistics. While it
didn't make sense in multi-process mode, with threads it does. Thus we
now have a counter of bytes emitted by raw_sock, and a freq counter for
these as well. However, freq_ctr are limited to 32 bits, and given that
loads of 300 Gbps have already been reached over a loopback using
splicing, we need to downscale this a bit. Here we're storing 1/32 of
the byte rate, which gives a theorical limit of 128 GB/s or ~1 Tbps,
which is more than enough. Let's have fun re-reading this sentence in
2029 :-)  The values can be read in "show info" output on the CLI.
2019-05-23 11:45:38 +02:00
Willy Tarreau
bc1b820606 BUILD: watchdog: condition it to USE_RT
It's needed on Linux to have access to timerfd_*, and on FreeBSD this
lib is needed as well, though not enabled in our default build. We can
see later if it's OK to enable it, for now let's fix the build issues.
2019-05-23 10:20:55 +02:00
Willy Tarreau
02255b24df BUILD: watchdog: use si_value.sival_int, not si_int for the timer's value
Bah, the linux manpage suggests to use si_int but it's a fake, it's only
a define on sigval.sival_int where sigval is defined as si_value. Let's
use si_value.sival_int, at least it builds on both Linux and FreeBSD. It's
likely that this code will have to be limited to a small subset of OSes
if it causes difficulties like this.
2019-05-23 08:36:29 +02:00
Willy Tarreau
96d5195862 MEDIUM: config: deprecate the antique req* and rsp* commands
These commands don't follow the same flow as the rest of the commands,
each of them iterates over all header lines before switching to the
next directive. In addition they make no distinction between start
line and headers and can lead to unparsable rewrites which are very
difficult to deal with internally.

Most of them are still occasionally found in configurations, mainly
because of the usual "we've always done this way". By marking them
deprecated and emitting a warning and recommendation on first use of
each of them, we will raise users' awareness of users regarding the
cleaner, faster and more reliable alternatives.

Some use cases of "reqrep" still appear from time to time for URL
rewriting that is not so convenient with other rules. But at least
users facing this requirement will explain their use case so that we
can best serve them. Some discussion started on this subject in a
thread linked to from github issue #100.

The goal is to remove them in 2.1 since they require to reparse the
result before indexing it and we don't want this hack to live long.
The following directives were marked deprecated :

  -reqadd
  -reqallow
  -reqdel
  -reqdeny
  -reqiallow
  -reqidel
  -reqideny
  -reqipass
  -reqirep
  -reqitarpit
  -reqpass
  -reqrep
  -reqtarpit
  -rspadd
  -rspdel
  -rspdeny
  -rspidel
  -rspideny
  -rspirep
  -rsprep
2019-05-22 20:43:45 +02:00
Willy Tarreau
3844747536 CLEANUP: raw_sock: remove support for very old linux splice bug workaround
We've been dealing with a workaround for a bug in splice that used to
affect version 2.6.25 to 2.6.27.12 and which was fixed 10 years ago
in kernel versions which are not supported anymore. Given that people
who would use a kernel in such a range would face much more serious
stability and security issues, it's about time to get rid of this
workaround and of the ASSUME_SPLICE_WORKS build option used to disable
it.
2019-05-22 20:02:15 +02:00
Willy Tarreau
e5733234f6 CLEANUP: build: rename some build macros to use the USE_* ones
We still have quite a number of build macros which are mapped 1:1 to a
USE_something setting in the makefile but which have a different name.
This patch cleans this up by renaming them to use the USE_something
one, allowing to clean up the makefile and make it more obvious when
reading the code what build option needs to be added.

The following renames were done :

 ENABLE_POLL -> USE_POLL
 ENABLE_EPOLL -> USE_EPOLL
 ENABLE_KQUEUE -> USE_KQUEUE
 ENABLE_EVPORTS -> USE_EVPORTS
 TPROXY -> USE_TPROXY
 NETFILTER -> USE_NETFILTER
 NEED_CRYPT_H -> USE_CRYPT_H
 CONFIG_HAP_CRYPT -> USE_LIBCRYPT
 CONFIG_HAP_NS -> DUSE_NS
 CONFIG_HAP_LINUX_SPLICE -> USE_LINUX_SPLICE
 CONFIG_HAP_LINUX_TPROXY -> USE_LINUX_TPROXY
 CONFIG_HAP_LINUX_VSYSCALL -> USE_LINUX_VSYSCALL
2019-05-22 19:47:57 +02:00
Willy Tarreau
823bda0eb7 BUILD: time: remove the test on _POSIX_C_SOURCE
It seems it's not defined on FreeBSD while it's mentioned on Linux that
clock_gettime() can be detected using this. Given that we also have the
test for _POSIX_TIMERS>0 that should cover it well enough. If it breaks
on other systems, we'll see.

Report was here :
    https://github.com/haproxy/haproxy/runs/133866993
2019-05-22 19:14:59 +02:00
Willy Tarreau
082b62828d BUG/MEDIUM: init/threads: provide per-thread alloc/free function callbacks
We currently have the ability to register functions to be called early
on thread creation and at thread deinitialization. It turns out this is
not sufficient because certain such functions may use resources that are
being allocated by the other ones, thus creating a race condition depending
only on the linking order. For example the mworker needs to register a
file descriptor while the pollers will reallocate the fd_updt[] array.
Similarly logs and trashes may be used by some init functions while it's
unclear whether they have been deduplicated.

The same issue happens on deinit, if the fd_updt[] or trash is released
before some functions finish to use them, we'll get into trouble.

This patch creates a couple of early and late callbacks for per-thread
allocation/freeing of resources. A few init functions were moved there,
and the fd init code was split between the two (since it used to both
allocate and initialize at once). This way the init/deinit sequence is
expected to be safe now.

This patch should be backported to 1.9 as at least the trash/log issue
seems to be present. The run_thread_poll_loop() code is a bit different
there as the mworker is not a callback, but it will have no effect and
it's enough to drop the mworker changes.

This bug was reported by Ilya Shipitsin in github issue #104.
2019-05-22 14:59:08 +02:00
Willy Tarreau
aabbe6a3bb MINOR: WURFL: do not emit warnings when not configured
At the moment the WURFL module emits 3 lines of warnings upon startup
when it is not referenced in the configuration file, which is quite
confusing. Let's make sure to keep it silent when not configured, as
detected by the absence of the wurfl-data-file statement.
2019-05-22 14:01:22 +02:00
mbellomi
ae4fcf1e67 MINOR: WURFL: module version bump to 2.0
Make it version 2.0.
2019-05-22 12:06:42 +02:00
mbellomi
2c07700098 MEDIUM: WURFL: HTX awareness.
Now wurfl fetch process is fully  HTX aware.
2019-05-22 12:06:38 +02:00
mbellomi
9896981675 MINOR: WURFL: wurfl_get() and wurfl_get_all() now return an empty string if device detection fails 2019-05-22 12:06:38 +02:00
mbellomi
e9fedf560a MINOR: WURFL: removes heading wurfl-information-separator from wurfl-get-all() and wurfl-get() results 2019-05-22 12:06:38 +02:00
mbellomi
4304e30af1 MINOR: WURFL: shows log messages during module initialization
Now some useful startup information is logged to stderr. Previously they
were lost because logs were not yet enabled.
2019-05-22 12:06:34 +02:00
mbellomi
f9ea1e2fd4 MINOR: WURFL: fixed Engine load failed error when wurfl-information-list contains wurfl_root_id 2019-05-22 12:06:07 +02:00
mbellomi
d173e93aa7 BUG/MEDIUM: WURFL: segfault in wurfl-get() with missing info.
A segfault may happen in ha_wurfl_get() when dereferencing information not
present in wurfl-information-list. Check the node retrieved from the tree,
not its container.

This fix must be backported to 1.9.
2019-05-22 12:06:02 +02:00
Willy Tarreau
0a7a4fbbc8 CLEANUP: mux-h1: use "H1" and not "h1" as the mux's name
The mux's name is the only one reported in lower case in "show sess"
or "haproxy -vv" while the other ones are upper case, so it loses and
the other ones win :-)
2019-05-22 11:50:48 +02:00
Willy Tarreau
b106ce1c3d MINOR: stream: remove the cpu time detection from process_stream()
It was not as efficient as the watchdog in that it would only trigger
after the problem resolved by itself, and still required a huge margin
to make sure we didn't trigger for an invalid reason. This used to leave
little indication about the cause. Better use the watchdog now and
improve it if needed.

The detector of unkillable tasks remains active though.
2019-05-22 11:50:48 +02:00
Willy Tarreau
2bfefdbaef MAJOR: watchdog: implement a thread lockup detection mechanism
Since threads were introduced, we've naturally had a number of bugs
related to locking issues. In addition we've also got some issues
with corrupted lists in certain rare cases not necessarily involving
threads. Not only these events cause a lot of trouble to the production
as it is very hard to detect that the process is stuck in a loop and
doesn't deliver the service anymore, but it's often difficult (or too
late) to collect more debugging information.

The patch presented here implements a lockup detection mechanism, also
known as "watchdog". The principle is that (on systems supporting it),
each thread will have its own CPU timer which progresses as the thread
consumes CPU cycles, and when a deadline is met, a signal is delivered
(SIGALRM here since it doesn't interrupt gdb by default).

The thread handling this signal (which is not necessarily the one which
triggered the timer) figures the thread ID from the signal arguments and
checks if it's really stuck by looking at the time spent since last exit
from poll() and by checking that the thread's scheduler is still alive
(so that even when dealing with configuration issues resulting in insane
amount of tasks being called in turn, it is not possible to accidently
trigger it). Checking the scheduler's activity will usually result in a
second chance, thus doubling the detecting time.

In order not to incorrectly flag a thread as being the cause of the
lockup, the thread_harmless_mask is checked : a thread could very well
be spinning on itself waiting for all other threads to join (typically
what happens when issuing "show sess"). In this case, once all threads
but one (or two) have joined, all the innocent ones are marked harmless
and will not trigger the timer. Only the ones not reacting will.

The deadline is set to one second, which already appears impossible to
reach, especially since it's 1 second of CPU usage, not elapsed time
with the CPU being preempted by other threads/processes/hypervisor. In
practice due to the scheduler's health verification it takes up to two
seconds to decide to panic.

Once all conditions are met, the goal is to crash from the offending
thread. So if it's the current one, we call ha_panic() otherwise the
signal is bounced to the offending thread which deals with it. This
will result in all threads being woken up in turn to dump their context,
the whole state is emitted on stderr in hope that it can be logged, and
the process aborts, leaving a chance for a core to be dumped and for a
service manager to restart it.

An alternative mechanism could be implemented for systems unable to
wake up a thread once its CPU clock reaches a deadline (e.g. FreeBSD).
Instead of waking the timer each and every deadline, it is possible to
use a standard timer which is reset each time we leave poll(). Since
the signal handler rechecks the CPU consumption this will also work.
However a totally idle process may trigger it from time to time which
may or may not confuse some debugging sessions. The same is true for
alarm() which could be another option for systems not having such a
broad choice of timers (but it seems that in this case they will not
have per-thread CPU measurements available either).

The feature is currently implemented only when threads are enabled in
order to keep the code clean, since the main purpose is to detect and
address inter-thread deadlocks. But if it proves useful for other
situations this condition might be relaxed.
2019-05-22 11:50:48 +02:00
Willy Tarreau
e6a02fa65a MINOR: threads: add a "stuck" flag to the thread_info struct
This flag is constantly cleared by the scheduler and will be set by the
watchdog timer to detect stuck threads. It is also set by the "show
threads" command so that it is easy to spot if the situation has evolved
between two subsequent calls : if the first "show threads" shows no stuck
thread and the second one shows such a stuck thread, it indicates that
this thread didn't manage to make any forward progress since the previous
call, which is extremely suspicious.
2019-05-22 11:50:48 +02:00
Willy Tarreau
578ea8be55 MINOR: debug: dump streams when an applet, iocb or stream is known
Whenever we can retrieve a valid stream pointer, we now call stream_dump()
to get a detailed dump of the stream currently running on the processor.
This is used by "show threads" and by ha_panic().
2019-05-22 11:50:48 +02:00
Willy Tarreau
5484d58a17 MINOR: stream: introduce a stream_dump() function and use it in stream_dump_and_crash()
This function dumps a lot of information about a stream into the provided
buffer. It is now used by stream_dump_and_crash() and will be used by the
debugger as well.
2019-05-22 11:50:48 +02:00
Willy Tarreau
fade80d162 CLEANUP: debug: make use of ha_tkill() and remove ifdefs
This way we always signal the threads the same way.
2019-05-22 11:50:48 +02:00
Willy Tarreau
2beaaf7d46 MINOR: threads: implement ha_tkill() and ha_tkillall()
These functions are used respectively to signal one thread or all threads.
When multithreading is disabled, it's always the current thread which is
signaled.
2019-05-22 11:50:48 +02:00
Willy Tarreau
8b35ba54bc CLEANUP: debug: always report harmless/want_rdv even without threads
This way we have a more consistent output and we can remove annoying
ifdefs.
2019-05-22 11:50:48 +02:00
Willy Tarreau
05ed14cfc4 CLEANUP: threads: really move thread_info to hathreads.c
Commit 5a6e2245f ("REORG: threads: move the struct thread_info from
global.h to hathreads.h") didn't hold its promise well, as the thread_info
struct was still declared and initialized in haproxy.c in addition to being
in hathreads.c. Let's move it for real now.
2019-05-22 11:50:48 +02:00
Willy Tarreau
ddd8533f1b MINOR: debug: switch to SIGURG for thread dumps
The current choice of SIGPWR has the adverse effect of stopping gdb each
time it is triggered using "show threads" or example, which is not really
convenient. Let's switch to SIGURG instead, which we don't use either.
2019-05-22 11:50:48 +02:00
Tim Duesterhus
9b7a976cd6 BUG/MINOR: mworker: Fix memory leak of mworker_proc members
The struct mworker_proc is not uniformly freed everywhere, sometimes leading
to leaks of the `id` string (and possibly the other strings).

Introduce a mworker_free_child function instead of duplicating the freeing
logic everywhere to prevent this kind of issues.

This leak was reported in issue #96.

It looks like the leaks have been introduced in commit 9a1ee7ac31,
which is specific to 2.0-dev. Backporting `mworker_free_child` might be
helpful to ease backporting other fixes, though.
2019-05-22 11:29:18 +02:00
Willy Tarreau
f61782418c CLEANUP: time: refine the test on _POSIX_TIMERS
The clock_gettime() man page says we must check that _POSIX_TIMERS is
defined to a value greater than zero, not just that it's simply defined
so let's fix this right now.
2019-05-21 20:03:03 +02:00
Olivier Houchard
aacc405c1f BUG/MEDIUM: streams: Don't switch from SI_ST_CON to SI_ST_DIS on read0.
When we receive a read0, and we're still in SI_ST_CON state (so on an
outgoing conneciton), don't immediately switch to SI_ST_DIS, or, we would
never call sess_establish(), and so the analysers will never run.
Instead, let sess_establish() handle that case, and switch to SI_ST_DIS if
we already have CF_SHUTR on the channel.

This should be backported to 1.9.
2019-05-21 19:05:09 +02:00
Emmanuel Hocdet
0ba4f483d2 MAJOR: polling: add event ports support (Solaris)
Event ports are kqueue/epoll polling class for Solaris. Code is based
on https://github.com/joyent/haproxy-1.8/tree/joyent/dev-v1.8.8.
Event ports are available only on SunOS systems derived from
Solaris 10 and later (including illumos systems).
2019-05-21 15:16:45 +02:00
Willy Tarreau
663fda4c90 BUILD: threads: only assign the clock_id when supported
I took extreme care to always check for _POSIX_THREAD_CPUTIME before
manipulating clock_id, except at one place (run_thread_poll_loop) as
found by Manu, breaking Solaris. Now fixed, no backport needed.
2019-05-21 15:14:08 +02:00
Willy Tarreau
9c8800af3b MINOR: debug: report each thread's cpu usage in "show thread"
Now we can report each thread's CPU time, both at wake up (poll) and
retrieved while dumping (now), then the difference, which directly
indicates how long the thread has been running uninterrupted. A very
high value for the diff could indicate a deadlock, especially if it
happens between two threads. Note that it may occasionally happen
that a wrong value is displayed since nothing guarantees that the
date is read atomically.
2019-05-20 21:14:14 +02:00
Willy Tarreau
81036f2738 MINOR: time: move the cpu, mono, and idle time to thread_info
These ones are useful across all threads and would be better placed
in struct thread_info than thread-local. There are very few users.
2019-05-20 21:14:14 +02:00
Willy Tarreau
8323a375bc MINOR: threads: add a thread-local thread_info pointer "ti"
Since we're likely to access this thread_info struct more frequently in
the future, let's reserve the thread-local symbol to access it directly
and avoid always having to combine thread_info and tid. This pointer is
set when tid is set.
2019-05-20 21:14:12 +02:00
Willy Tarreau
624dcbf41e MINOR: threads: always place the clockid in the struct thread_info
It will be easier to deal with the internal API to always have it.
2019-05-20 21:13:01 +02:00
Willy Tarreau
5a6e2245fa REORG: threads: move the struct thread_info from global.h to hathreads.h
It doesn't make sense to keep this struct thread_info in global.h, it
causes difficulties to access its contents from hathreads.h, let's move
it to the threads where it ought to have been created.
2019-05-20 20:00:25 +02:00
Willy Tarreau
a9f9fc9e5b MINOR: debug: make ha_panic() report threads starting at 1
Internally they start at zero but everywhere (config, dumps) we show
them starting at 1, so let's fix the confusion.
2019-05-20 17:46:14 +02:00
Willy Tarreau
3710105945 MINOR: tools: provide a may_access() function and make dump_hex() use it
It's a bit too easy to crash by accident when using dump_hex() on any
area. Let's have a function to check if the memory may safely be read
first. This one abuses the stat() syscall checking if it returns EFAULT
or not, in which case it means we're not allowed to read from there. In
other situations it may return other codes or even a success if the
area pointed to by the file exists. It's important not to abuse it
though and as such it's tested only once per output line.
2019-05-20 16:59:37 +02:00
Willy Tarreau
6bdf3e9b11 MINOR: debug/cli: add some debugging commands for developers
When haproxy is built with DEBUG_DEV, the following commands are added
to the CLI :

  debug dev close <fd>        : close this file descriptor
  debug dev delay [ms]        : sleep this long
  debug dev exec  [cmd] ...   : show this command's output
  debug dev exit  [code]      : immediately exit the process
  debug dev hex   <addr> [len]: dump a memory area
  debug dev log   [msg] ...   : send this msg to global logs
  debug dev loop  [ms]        : loop this long
  debug dev panic             : immediately trigger a panic
  debug dev tkill [thr] [sig] : send signal to thread

These are essentially aimed at helping developers trigger certain
conditions and are expected to be complemented over time.
2019-05-20 16:59:30 +02:00
Willy Tarreau
56131ca58e MINOR: debug: implement ha_panic()
This function dumps all existing threads using the thread dump mechanism
then aborts. This will be used by the lockup detection and by debugging
tools.
2019-05-20 16:51:30 +02:00
Willy Tarreau
9fc5dcbd71 MINOR: tools: add dump_hex()
This is used to dump a memory area into a buffer for debugging purposes.
2019-05-20 16:51:30 +02:00
Willy Tarreau
da5a63f8f1 CLEANUP: stream: remove an obsolete debugging test
The test consisted in checking that there was always a timeout on a
stream's task and was only enabled when built in development mode,
but 1) it is never tested and 2) if it had been tested it would have
been noticed that it triggers a bit too easily on the CLI. Let's get
rid of this old one.
2019-05-20 16:19:40 +02:00
Willy Tarreau
91e6df01fa MINOR: threads: add each thread's clockid into the global thread_info
This is the per-thread CPU runtime clock, it will be used to measure
the CPU usage of each thread and by the lockup detection mechanism. It
must only be retrieved at the beginning of run_thread_poll_loop() since
the thread must already have been started for this. But it must be done
before performing any per-thread initcall so that all thread init
functions have access to the clock ID.

Note that it could make sense to always have this clockid available even
in non-threaded situations and place the process' clock there instead.
But it would add portability issues which are currently easy to deal
with by disabling threads so it may not be worth it for now.
2019-05-20 11:42:25 +02:00
Willy Tarreau
522cfbc1ea MINOR: init/threads: make the global threads an array of structs
This way we'll be able to store more per-thread information than just
the pthread pointer. The storage became an array of struct instead of
an allocated array since it's very small (typically 512 bytes) and not
worth the hassle of dealing with memory allocation on this. The array
was also renamed thread_info to make its intended usage more explicit.
2019-05-20 11:37:57 +02:00
Willy Tarreau
64a47b943c CLEANUP: memory: make the fault injection code use the OTHER_LOCK label
The mem_should_fail() function sets a lock while it's building its
messages, and when this was done there was no relevant label available
hence the confusing use of START_LOCK. Now OTHER_LOCK is available for
such use cases, so let's switch to this one instead as START_LOCK is
going to disappear.
2019-05-20 11:26:12 +02:00
Willy Tarreau
619a95f5ad MEDIUM: init/mworker: make the pipe register function a regular initcall
Now that we have the guarantee that init calls happen before any other
thread starts, we don't need anymore the workaround installed by commit
1605c7ae6 ("BUG/MEDIUM: threads/mworker: fix a race on startup") and we
can instead rely on a regular per-thread initcall for this function. It
will only be performed on worker thread #0, the other ones and the master
have nothing to do, just like in the original code that was only moved
to the function.
2019-05-20 11:26:12 +02:00
Willy Tarreau
3078e9f8e2 MINOR: threads/init: synchronize the threads startup
It's a bit dangerous to let threads initialize at different speeds on
startup. Some are still in their init functions while others area already
running. It was even subject to some race condition bugs like the one
fixed by commit 1605c7ae6 ("BUG/MEDIUM: threads/mworker: fix a race on
startup").

Here in order to secure all this, we take a very simplistic approach
consisting in using half of the rendez-vous point, which is made
exactly for this purpose : we first initialize the mask of the threads
requesting a rendez-vous to the mask of all threads, and we simply call
thread_release() once the init is complete. This guarantees that no
thread will go further than the initialization code during this time.

This could even safely be backported if any other issue related to an
init race was discovered in a stable release.
2019-05-20 11:26:12 +02:00
William Lallemand
7b302d8dd5 MINOR: init: setenv HAPROXY_CFGFILES
Set the HAPROXY_CFGFILES environment variable which contains the list of
configuration files used to start haproxy, separated by semicolon.
2019-05-20 11:21:00 +02:00
Willy Tarreau
c7091d89ae MEDIUM: debug/threads: implement an advanced thread dump system
The current "show threads" command was too limited as it was not possible
to dump other threads' detailed states (e.g. their tasks). This patch
goes further by using thread signals so that each thread can dump its
own state in turn into a shared buffer provided by the caller. Threads
are synchronized using a mechanism very similar to the rendez-vous point
and using this method, each thread can safely dump any of its contents
and the caller can finally report the aggregated ones from the buffer.

It is important to keep in mind that the list of signal-safe functions
is limited, so we take care of only using chunk_printf() to write to a
pre-allocated buffer.

This mechanism is enabled by USE_THREAD_DUMP and is enabled by default
on Linux 2.6.28+. On other platforms it falls back to the previous
solution using the loop and the less precise dump.
2019-05-17 17:16:20 +02:00
Willy Tarreau
0ad46fa6f5 MINOR: stream: detach the stream from its own task on stream_free()
This makes sure that the stream is not visible from its own task just
before starting to free some of its components. This way we have the
guarantee that a stream found in a task list is totally valid and can
safely be dereferenced.
2019-05-17 17:16:20 +02:00
Willy Tarreau
01f3489752 MINOR: task: put barriers after each write to curr_task
This one may be watched by signal handlers, we don't want the compiler
to optimize its assignment away at the end of the loop and leave some
wandering pointers there.
2019-05-17 17:16:20 +02:00
Willy Tarreau
38171daf21 MINOR: thread: implement ha_thread_relax()
At some places we're using a painful ifdef to decide whether to use
sched_yield() or pl_cpu_relax() to relax in loops, this is hardly
exportable. Let's move this to ha_thread_relax() instead and une
this one only.
2019-05-17 17:16:20 +02:00
Willy Tarreau
20db9115dc BUG/MINOR: debug: don't check the call date on tasklets
tasklets don't have a call date, so when a tasklet is cast into a task
and is present at the end of a page we run a risk of dereferencing
unmapped memory when dumping them in ha_task_dump(). This commit
simplifies the test and uses to distinct calls for tasklets and tasks.
No backport is needed.
2019-05-17 17:16:20 +02:00
Willy Tarreau
5cf64dd1bd MINOR: debug: make ha_thread_dump() and ha_task_dump() take a buffer
Instead of having them dump into the trash and initialize it, let's have
the caller initialize a buffer and pass it. This will be convenient to
dump multiple threads at once into a single buffer.
2019-05-17 17:16:20 +02:00
Willy Tarreau
14a1ab75d0 BUG/MINOR: debug: make ha_task_dump() actually dump the requested task
It used to only dump the current task, which isn't different for now
but the purpose clearly is to dump the requested task. No backport is
needed.
2019-05-17 17:16:20 +02:00
Willy Tarreau
231ec395c1 BUG/MINOR: debug: make ha_task_dump() always check the task before dumping it
For now it cannot happen since we're calling it from a task but it will
break with signals. No backport is needed.
2019-05-17 17:16:20 +02:00
Olivier Houchard
6db1699f77 BUG/MEDIUM: streams: Try to L7 retry before aborting the connection.
In htx_wait_for_response, in case of error, attempt a L7 retry before
aborting the connection if the TX_NOT_FIRST flag is set.
If we don't do that, then we wouldn't attempt L7 retries after the first
request, or if we use HTTP/2, as with HTTP/2 that flag is always set.
2019-05-17 15:49:21 +02:00
Olivier Houchard
ce1a0292bf BUG/MEDIUM: streams: Don't use CF_EOI to decide if the request is complete.
In si_cs_send(), don't check CF_EOI on the request channel to decide if the
request is complete and if we should save the buffer to eventually attempt
L7 retries. The flag may not be set yet, and it may too be set to early,
before we're done modifying the buffer. Instead, get the msg, and make sure
its state is HTTP_MSG_DONE.
That way we will store the request buffer when sending it even in H2.
2019-05-17 15:49:21 +02:00
Willy Tarreau
4e2b646d60 MINOR: cli/debug: add a thread dump function
The new function ha_thread_dump() will dump debugging info about all known
threads. The current thread will contain a bit more info. The long-term goal
is to make it possible to use it in signal handlers to improve the accuracy
of some dumps.

The function dumps its output into the trash so as it was trivial to add,
a new "show threads" command appeared on the CLI.
2019-05-16 18:06:45 +02:00
Willy Tarreau
58d9621fc8 MINOR: cli/activity: show the dumping thread ID starting at 1
Both the config and gdb report thread IDs starting at 1, so better do the
same in "show activity" to limit confusion. We also display the full
permitted range.

This could be backported to 1.9 since it was present there.
2019-05-16 18:02:03 +02:00
Tim Duesterhus
3506dae342 MEDIUM: Make 'resolution_pool_size' directive fatal
This directive never appeared in a stable release and instead was
introduced and deprecated within 1.8-dev. While it technically could
be outright removed we detect it and error out for good measure.
2019-05-16 18:02:03 +02:00
Tim Duesterhus
10c6c16cde MEDIUM: Make 'option forceclose' actually warn
It is deprecated since 315b39c391 (1.9-dev),
but only was deprecated in the docs.

Make it warn when being used and remove it from the docs.
2019-05-16 18:02:03 +02:00
Christopher Faulet
c1f40dd492 BUG/MINOR: http_fetch: Rely on the smp direction for "cookie()" and "hdr()"
A regression was introduced in the commit 89dc49935 ("BUG/MAJOR: http_fetch: Get
the channel depending on the keyword used") on the samples "cookie()" and
"hdr()". Unlike other samples manipulating the HTTP headers, these ones depend
on the sample direction. To fix the bug, these samples use now their own
functions. Depending on the sample direction, they call smp_fetch_cookie() and
smp_fetch_hdr() with the appropriate keyword.

Thanks to Yves Lafon to report this issue.

This patch must be backported wherever the commit 89dc49935 was backported. For
now, 1.9 and 1.8.
2019-05-16 11:31:28 +02:00
Olivier Houchard
35d116885d MINOR: connections: Use BUG_ON() to enforce rules in subscribe/unsubscribe.
It is not legal to subscribe if we're already subscribed, or to unsubscribe
if we did not subscribe, so instead of trying to handle those cases, just
assert that it's ok using the new BUG_ON() macro.
2019-05-14 18:18:25 +02:00
Olivier Houchard
00b8f7c60b MINOR: h1: Use BUG_ON() to enforce rules in subscribe/unsubscribe.
It is not legal to subscribe if we're already subscribed, or to unsubscribe
if we did not subscribe, so instead of trying to handle those cases, just
assert that it's ok using the new BUG_ON() macro.
2019-05-14 18:18:25 +02:00
Olivier Houchard
f8338151a3 MINOR: h2: Use BUG_ON() to enforce rules in subscribe/unsubscribe.
It is not legal to subscribe if we're already subscribed, or to unsubscribe
if we did not subscribe, so instead of trying to handle those cases, just
assert that it's ok using the new BUG_ON() macro.
2019-05-14 18:18:25 +02:00
Christopher Faulet
fa922f03a3 BUG/MEDIUM: mux-h2: Set EOI on the conn_stream during h2_rcv_buf()
Just like CS_FL_REOS previously, the CS_FL_EOI flag is abused as a proxy
for H2_SF_ES_RCVD. The problem is that this flag is consumed by the
application layer and is set immediately when an end of stream was met,
which is too early since the application must retrieve the rxbuf's
contents first. The effect is that some transfers are truncated (mostly
the first one of a connection in most tests).

The problem of mixing CS flags and H2S flags in the H2 mux is not new
(and is currently being addressed) but this specific one was emphasized
in commit 63768a63d ("MEDIUM: mux-h2: Don't mix the end of the message
with the end of stream") which was backported to 1.9. Note that other
flags, particularly CS_FL_REOS still need to be asynchronously reported,
though their impact seems more limited for now.

This patch makes sure that all internal uses of CS_FL_EOI are replaced
with a test on H2_SF_ES_RCVD (as there is a 1-to-1 equivalence) and that
CS_FL_EOI is only reported once the rxbuf is empty.

This should ideally be backported to 1.9 unless it causes too much
trouble due to the recent changes in this area, as 1.9 *seems* not
to be directly affected by this bug.
2019-05-14 15:47:57 +02:00
Willy Tarreau
99ad1b3e8c MINOR: mux-h2: stop relying on CS_FL_REOS
This flag was introduced early in 1.9 development (a3f7efe00) to report
the fact that the rxbuf that was present on the conn_stream was followed
by a shutr. Since then the rxbuf moved from the conn_stream to the h2s
(638b799b0) but the flag remained on the conn_stream. It is problematic
because some state transitions inside the mux depend on it, thus depend
on the CS, and as such have to test for its existence before proceeding.

This patch replaces the test on CS_FL_REOS with a test on the only
states that set this flag (H2_SS_CLOSED, H2_SS_HREM, H2_SS_ERROR).
The few places where the flag was set were removed (the flag is not
used by the data layer).
2019-05-14 15:47:57 +02:00
Willy Tarreau
4c688eb8d1 MINOR: mux-h2: add macros to check multiple stream states at once
At many places we need to test for several stream states at once, let's
have macros to make a bit mask from a state to ease this.
2019-05-14 15:47:57 +02:00
Willy Tarreau
f8fe3d63f0 CLEANUP: mux-h2: don't test for impossible CS_FL_REOS conditions
This flag is currently set when an incoming close was received, which
results in the stream being in either H2_SS_HREM, H2_SS_CLOSED, or
H2_SS_ERROR states, so let's remove the test for the OPEN and HLOC
cases.
2019-05-14 15:47:57 +02:00
Willy Tarreau
3cf69fe6b2 BUG/MINOR: mux-h2: make sure to honor KILL_CONN in do_shut{r,w}
If the stream closes and quits while there's no room in the mux buffer
to send an RST frame, next time it is attempted it will not lead to
the connection being closed because the conn_stream will have been
released and the KILL_CONN flag with it as well.

This patch reserves a new H2_SF_KILL_CONN flag that is copied from
the CS when calling shut{r,w} so that the stream remains autonomous
on this even when the conn_stream leaves.

This should ideally be backported to 1.9 though it depends on several
previous patches that may or may not be suitable for backporting. The
severity is very low so there's no need to insist in case of trouble.
2019-05-14 15:47:57 +02:00
Willy Tarreau
aebbe5ef72 MINOR: mux-h2: make h2s_wake_one_stream() not depend on temporary CS flags
In h2s_wake_one_stream() we used to rely on the temporary flags used to
adjust the CS to determine the new h2s state. This really is not convenient
and creates far too many dependencies. This commit just moves the same
condition to the places where the temporary flags were set so that we
don't have to rely on these anymore. Whether these are relevant or not
was not the subject of the operation, what matters was to make sure the
conditions to adjust the stream's state and the CS's flags remain the
same. Later it could be studied if these conditions are correct or not.
2019-05-14 15:47:57 +02:00
Willy Tarreau
13b6c2e8b3 MINOR: mux-h2: make h2s_wake_one_stream() the only function to deal with CS
h2s_wake_one_stream() has access to all the required elements to update
the connstream's flags and figure the necessary state transitions, so
let's move the conditions there from h2_wake_some_streams().
2019-05-14 15:47:57 +02:00
Willy Tarreau
234829111f MINOR: mux-h2: make h2_wake_some_streams() not depend on the CS flags
It's problematic to have to pass some CS flags to this function because
that forces some h2s state transistions to update them just in time
while some of them are supposed to only be updated during I/O operations.

As a first step this patch transfers the decision to pass CS_FL_ERR_PENDING
from the caller to the leaf function h2s_wake_one_stream(). It is easy
since this is the only flag passed there and it depends on the position of
the stream relative to the last_sid if it was set.
2019-05-14 15:47:57 +02:00
Willy Tarreau
c3b1183f57 MINOR: mux-h2: remove useless test on stream ID vs last in wake function
h2_wake_some_streams() first looks up streams whose IDs are greater than
or equal to last+1, then checks if the id is lower than or equal to last,
which by definition will never match. Let's remove this confusing leftover
from ancient code.
2019-05-14 15:47:57 +02:00
William Lallemand
920fc8bbe4 BUG/MINOR: mworker: use after free when the PID not assigned
Commit 4528611 ("MEDIUM: mworker: store the leaving state of a process")
introduced a bug in the mworker_env_to_proc_list() function.

This is very unlikely to occur since the PID should always be assigned.
It can probably happen if the environment variable is corrupted.

No backport needed.
2019-05-14 11:28:16 +02:00
Willy Tarreau
f983d00a1c BUG/MINOR: mux-h2: make the do_shut{r,w} functions more robust against retries
These functions may fail to emit an RST or an empty DATA frame because
the mux is full or busy. Then they subscribe the h2s and try again.
However when doing so, they will already have marked the error state on
the stream and will not pass anymore through the sequence resulting in
the failed frame to be attempted to be sent again nor to the close to
be done, instead they will return a success.

It is important to only leave when the stream is already closed, but
to go through the whole sequence otherwise.

This patch should ideally be backported to 1.9 though it's possible that
the lack of the WANT_SHUT* flags makes this difficult or dangerous. The
severity is low enough to avoid this in case of trouble.
2019-05-14 11:13:06 +02:00
Frédéric Lécaille
90a10aeb65 BUG/MINOR: log: Wrong log format initialization.
This patch fixes an issue introduced by 0bad840b commit
"MINOR: log: Extract some code to send syslog messages" which leaded
to wrong log format variable initializations at least for "short" and "raw" format.
This commit skipped the cases where even if passed to __do_send_log(), the
syslog tag and syslog pid string must not be used to format the log message
with "short" and "raw". This is done iniatilizing "tag_max" and "pid_max"
variables (the lengths of the tag and pid strings) to 0, then updating to them to
the length of the tag and pid strings passed as variables to __do_send_log()
depending on the log format and in every cases using this length for the iovec
variable used to send() the log.

This bug is specific to 2.0.
2019-05-14 11:12:00 +02:00
Willy Tarreau
8bdb5c9bb4 CLEANUP: connection: remove the handle field from the wait_event struct
It was only set and not consumed after the previous change. The reason
is that the task's context always contains the relevant information,
so there is no need for a second pointer.
2019-05-13 19:14:52 +02:00
Willy Tarreau
88bdba31fa CLEANUP: mux-h2: simply use h2s->flags instead of ret in h2_deferred_shut()
This one used to rely on the combined return statuses of the shutr/w
functions but now that we have the H2_SF_WANT_SHUT{R,W} flags we don't
need this anymore if we properly remove these flags after their operations
succeed. This is what this patch does.
2019-05-13 19:14:52 +02:00
Willy Tarreau
2c249ebc75 MINOR: mux-h2: add two H2S flags to report the need for shutr/shutw
Currently when a shutr/shutw fails due to lack of buffer space, we abuse
the wait_event's handle pointer to place up to two bits there in addition
to the original pointer. This pointer is not used for anything but this
and overall the intent becomes clearer with h2s flags than with these
two alien bits in the pointer, so let's use clean flags now.
2019-05-13 19:14:52 +02:00
Willy Tarreau
c234ae38f8 CLEANUP: mux-h2: use LIST_ADDED() instead of LIST_ISEMPTY() where relevant
Lots of places were using LIST_ISEMPTY() to detect if a stream belongs
to one of the send lists or to detect if a connection was already
waiting for a buffer or attached to an idle list. Since these ones are
not list heads but list elements, let's use LIST_ADDED() instead.
2019-05-13 19:14:52 +02:00
William Lallemand
7e1770b151 BUG/MAJOR: ssl: segfault upon an heartbeat request
7b5fd1e ("MEDIUM: connections: Move some fields from struct connection
to ssl_sock_ctx.") introduced a bug in the heartbleed mitigation code.

Indeed the code used conn->ctx instead of conn->xprt_ctx for the ssl
context, resulting in a null dereference.
2019-05-13 16:03:44 +02:00
Tim Duesterhus
a6cc7e872a BUG/MINOR: vars: Fix memory leak in vars_check_arg
vars_check_arg previously leaked the string containing the variable
name:

Consider this config:

    frontend fe1
        mode http
        bind :8080
        http-request set-header X %[var(txn.host)]

Starting HAProxy and immediately stopping it by sending a SIGINT makes
Valgrind report this leak:

    ==7795== 9 bytes in 1 blocks are definitely lost in loss record 15 of 71
    ==7795==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==7795==    by 0x4AA2AD: my_strndup (standard.c:2227)
    ==7795==    by 0x51FCC5: make_arg_list (arg.c:146)
    ==7795==    by 0x4CF095: sample_parse_expr (sample.c:897)
    ==7795==    by 0x4BA7D7: add_sample_to_logformat_list (log.c:495)
    ==7795==    by 0x4BBB62: parse_logformat_string (log.c:688)
    ==7795==    by 0x4E70A9: parse_http_req_cond (http_rules.c:239)
    ==7795==    by 0x41CD7B: cfg_parse_listen (cfgparse-listen.c:1466)
    ==7795==    by 0x480383: readcfgfile (cfgparse.c:2089)
    ==7795==    by 0x47A081: init (haproxy.c:1581)
    ==7795==    by 0x4049F2: main (haproxy.c:2591)

This leak can be detected even in HAProxy 1.6, this patch thus should
be backported to all supported branches

[Cf: This fix was reverted because the chunk's area was inconditionnaly
     released, making haproxy to crash when spoe was enabled. Now the chunk is
     released by calling chunk_destroy(). This function takes care of the
     chunk's size to release it or not. It is the responsibility of callers to
     set or not the chunk's size.]
2019-05-13 11:09:12 +02:00
Christopher Faulet
bf9bcb0a00 MINOR: spoe: Set the argument chunk size to 0 when SPOE variables are checked
When SPOE variables are registered during HAProxy startup, the argument used to
call the function vars_check_arg() uses the trash area. To be sure it is never
released by the callee function, the size of the internal chunk (arg.data.str)
is set to 0. It is important to do so because, to fix a memory leak, this buffer
must be released by the function vars_check_arg().

This patch must be backported to 1.9.
2019-05-13 11:07:00 +02:00
Willy Tarreau
ce9bbf523c BUG/MINOR: htx: make sure to always initialize the HTTP method when parsing a buffer
smp_prefetch_htx() is used when trying to access the contents of an HTTP
buffer from the TCP rulesets. The method was not properly set in this
case, which will cause the sample fetch methods relying on the method
to randomly fail in this case.

Thanks to Tim Düsterhus for reporting this issue (#97).

This fix must be backported to 1.9.
2019-05-13 10:10:44 +02:00
Tim Duesterhus
04bcaa1f9f BUG/MINOR: peers: Fix memory leak in cfg_parse_peers
cfg_parse_peers previously leaked the contents of the `kws` string,
as it was unconditionally filled using bind_dump_kws, but only used
(and freed) within the error case.

Move the dumping into the error case to:
1. Ensure that the registered keywords are actually printed as least once.
2. The contents of kws are not leaked.

This move allows to narrow the scope of `kws`, so this is done as well.

This bug was found using valgrind:

    ==28217== 590 bytes in 1 blocks are definitely lost in loss record 51 of 71
    ==28217==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==28217==    by 0x4AD4C7: indent_msg (standard.c:3676)
    ==28217==    by 0x47E962: cfg_parse_peers (cfgparse.c:700)
    ==28217==    by 0x480273: readcfgfile (cfgparse.c:2147)
    ==28217==    by 0x479D51: init (haproxy.c:1585)
    ==28217==    by 0x404A02: main (haproxy.c:2585)

with this super simple configuration:

    peers peers
    	bind :8081
    	server A

This bug exists since the introduction of cfg_parse_peers in commit
355b2033ec (which was introduced for HAProxy
2.0, but marked as backportable). It should be backported to all branches
containing that commit.
2019-05-13 10:10:01 +02:00
Willy Tarreau
f7b0523425 Revert "BUG/MINOR: vars: Fix memory leak in vars_check_arg"
This reverts commit 6ea00195c4.

As found by Christopher, this fix is not correct due to the way args
are built at various places. For example some config or runtime parsers
will place a substring pointer there, and calling free() on it will
immediately crash the program. A quick audit of the code shows that
there are not that many users, but the way it's done requires to
properly set the string as a regular chunk (size=0 if free not desired,
then call chunk_destroy() at release time), and given that the size is
currently set to len+1 in all parsers, a deeper audit needs to be done
to figure the impacts of not setting it anymore.

Thus for now better leave this harmless leak which impacts only the
config parsing time.

This fix must be backported to all branches containing the fix above.
2019-05-13 10:10:01 +02:00
Willy Tarreau
4087346dab BUG/MAJOR: mux-h2: do not add a stream twice to the send list
In this long thread, Maciej Zdeb reported that the H2 mux was still
going through endless loops from time to time :

  https://www.mail-archive.com/haproxy@formilux.org/msg33709.html

What happens is the following :
- in h2s_frt_make_resp_data() we can set H2_SF_BLK_SFCTL and remove the
  stream from the send_list
- then in h2_shutr() and h2_shutw(), we check if the list is empty before
  subscribing the element, which is true after the case above
- then in h2c_update_all_ws() we still have H2_SF_BLK_SFCTL with the item
  in the send_list, thus LIST_ADDQ() adds it a second time.

This patch adds a check of list emptiness before performing the LIST_ADDQ()
when the flow control window opens. Maciej reported that it reliably fixed
the problem for him.

As later discussed with Olivier, this fixes the consequence of the issue
rather than its cause. The root cause is that a stream should never be in
the send_list with a blocking flag set and the various places that can lead
to this situation must be revisited. Thus another fix is expected soon for
this issue, which will require some observation. In the mean time this one
is easy enough to validate and to backport.

Many thanks to Maciej for testing several versions of the patch, each
time providing detailed traces which allowed to nail the problem down.

This patch must be backported to 1.9.
2019-05-13 08:15:10 +02:00
Willy Tarreau
6a38b3297c BUILD: threads: fix again the __ha_cas_dw() definition
This low-level asm implementation of a double CAS was implemented only
for certain architectures (x86_64, armv7, armv8). When threads are not
used, they were not defined, but since they were called directly from
a few locations, they were causing build issues on certain platforms
with threads disabled. This was addressed in commit f4436e1 ("BUILD:
threads: Add __ha_cas_dw fallback for single threaded builds") by
making it fall back to HA_ATOMIC_CAS() when threads are not defined,
but this actually made the situation worse by breaking other cases.

This patch fixes this by creating a high-level macro HA_ATOMIC_DWCAS()
which is similar to HA_ATOMIC_CAS() except that it's intended to work
on a double word, and which rely on the asm implementations when threads
are in use, and uses its own open-coded implementation when threads are
not used. The 3 call places relying on __ha_cas_dw() were updated to
use HA_ATOMIC_DWCAS() instead.

This change was tested on i586, x86_64, armv7, armv8 with and without
threads with gcc 4.7, armv8 with gcc 5.4 with and without threads, as
well as i586 with gcc-3.4 without threads. It will need to be backported
to 1.9 along with the fix above to fix build on armv7 with threads
disabled.
2019-05-11 18:13:29 +02:00
Willy Tarreau
295d614de1 CLEANUP: ssl: move all BIO_* definitions to openssl-compat
The following macros are now defined for openssl < 1.1 so that we
can remove the code performing direct access to the structures :

  BIO_get_data(), BIO_set_data(), BIO_set_init(), BIO_meth_free(),
  BIO_meth_new(), BIO_meth_set_gets(), BIO_meth_set_puts(),
  BIO_meth_set_read(), BIO_meth_set_write(), BIO_meth_set_create(),
  BIO_meth_set_ctrl(), BIO_meth_set_destroy()
2019-05-11 17:39:08 +02:00
Willy Tarreau
11b167167e CLEANUP: ssl: remove ifdef around SSL_CTX_get_extra_chain_certs()
Instead define this one in openssl-compat.h when
SSL_CTRL_GET_EXTRA_CHAIN_CERTS is not defined (which was the current
condition used in the ifdef).
2019-05-11 17:38:21 +02:00
Willy Tarreau
366a6987a7 CLEANUP: ssl: move the SSL_OP_* and SSL_MODE_* definitions to openssl-compat
These ones were defined in the middle of ssl_sock.c, better move them
to the include file to find them.
2019-05-11 17:37:44 +02:00
Tim Duesterhus
6ea00195c4 BUG/MINOR: vars: Fix memory leak in vars_check_arg
vars_check_arg previously leaked the string containing the variable
name:

Consider this config:

    frontend fe1
        mode http
        bind :8080
        http-request set-header X %[var(txn.host)]

Starting HAProxy and immediately stopping it by sending a SIGINT makes
Valgrind report this leak:

    ==7795== 9 bytes in 1 blocks are definitely lost in loss record 15 of 71
    ==7795==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==7795==    by 0x4AA2AD: my_strndup (standard.c:2227)
    ==7795==    by 0x51FCC5: make_arg_list (arg.c:146)
    ==7795==    by 0x4CF095: sample_parse_expr (sample.c:897)
    ==7795==    by 0x4BA7D7: add_sample_to_logformat_list (log.c:495)
    ==7795==    by 0x4BBB62: parse_logformat_string (log.c:688)
    ==7795==    by 0x4E70A9: parse_http_req_cond (http_rules.c:239)
    ==7795==    by 0x41CD7B: cfg_parse_listen (cfgparse-listen.c:1466)
    ==7795==    by 0x480383: readcfgfile (cfgparse.c:2089)
    ==7795==    by 0x47A081: init (haproxy.c:1581)
    ==7795==    by 0x4049F2: main (haproxy.c:2591)

This leak can be detected even in HAProxy 1.6, this patch thus should
be backported to all supported branches.
2019-05-11 06:00:50 +02:00
Olivier Houchard
ddf0e03585 MINOR: streams: Introduce a new retry-on keyword, all-retryable-errors.
Add a new retry-on keyword, "all-retryable-errors", that activates retry
for all errors that are considered retryable.
This currently activates retry for "conn-failure", "empty-response",
"junk-respones", "response-timeout", "0rtt-rejected", "500", "502", "503" and
"504".
2019-05-10 18:05:35 +02:00
Olivier Houchard
602bf7d2ea MEDIUM: streams: Add a new http action, disable-l7-retry.
Add a new action for http-request, disable-l7-retry, that can be used to
disable any attempt at retry requests (see retry-on) if it fails for any
reason other than a connection failure.
This is useful for example to make sure POST requests aren't retried.
2019-05-10 17:49:09 +02:00
Olivier Houchard
ad26d8d820 BUG/MEDIUM: streams: Make sur SI_FL_L7_RETRY is set before attempting a retry.
In a few cases, we'd just check if the backend is configured to do retries,
and not if it's still allowed on the stream_interface.
The SI_FL_L7_RETRY flag could have been removed because we failed to allocate
a buffer, or because the request was too big to fit in a single buffer,
so make sure it's there before attempting a retry.
2019-05-10 17:48:59 +02:00
Olivier Houchard
bfe2a83c24 BUG/MEDIUM: h2: Don't check send_wait to know if we're in the send_list.
When we have to stop sending due to the stream flow control, don't check
if send_wait is NULL to know if we're in the send_list, because at this
point it'll always be NULL, while we're probably in the list.
Use LIST_ISEMPTY(&h2s->list) instead.
Failing to do so mean we might be added in the send_list when flow control
allows us to emit again, while we're already in it.
While I'm here, replace LIST_DEL + LIST_INIT by LIST_DEL_INIT.

This should be backported to 1.9.
2019-05-10 15:06:54 +02:00
Christopher Faulet
132f7b496c BUG/MEDIUM: http: Use pointer to the begining of input to parse message headers
In the legacy HTTP, when the message headers are parsed, in http_msg_analyzer(),
we must use the begining of input and not the head of the buffer. Most of time,
it will be the same pointers because there is no outgoing data when a new
message is received. But when a 1xx informational response is parsed, it is
forwarded and the parsing restarts immediatly. In this case, we have outgoing
data when the next response is parsed.

This patch must be backported to 1.9.
2019-05-10 11:47:00 +02:00
Christopher Faulet
7a3367cca0 BUG/MINOR: stream: Attach the read side on the response as soon as possible
A backend stream-interface attached to a reused connection remains in the state
SI_ST_CONN until some data are sent to validate the connection. But when the
url_param algorithm is used to balance connections, no data are sent while the
connection is not established. So it is a chicken and egg situation.

To solve the problem, if no error is detected and when the request channel is
waiting for the connect(), we mark the read side as attached on the response
channel as soon as possible and we wake the request channel up once. This
happens in 2 places. The first one is right after the connect(), when the
stream-interface is still in state SI_ST_CON, in the function
sess_update_st_con_tcp(). The second one is when an applet is used instead of a
real connection to a server, in the function sess_prepare_conn_req(). In fact,
it is done when the backend stream-interface is set to the state SI_ST_EST.

This patch must be backported to 1.9.
2019-05-10 11:47:00 +02:00
Willy Tarreau
c125cef6da CLEANUP: ssl: make inclusion of openssl headers safe
It's always a pain to have to stuff lots of #ifdef USE_OPENSSL around
ssl headers, it even results in some of them appearing in a random order
and multiple times just to benefit form an existing ifdef block. Let's
make these headers safe for inclusion when USE_OPENSSL is not defined,
they now perform the test themselves and do nothing if USE_OPENSSL is
not defined. This allows to remove no less than 8 such ifdef blocks
and make include blocks more readable.
2019-05-10 09:58:43 +02:00
Willy Tarreau
8d164dc568 CLEANUP: ssl: never include openssl/*.h outside of openssl-compat.h anymore
Since we're providing a compatibility layer for multiple OpenSSL
implementations and their derivatives, it is important that no C file
directly includes openssl headers but only passes via openssl-compat
instead. As a bonus this also gets rid of redundant complex rules for
inclusion of certain files (engines etc).
2019-05-10 09:36:42 +02:00
Willy Tarreau
9356dacd22 REORG: ssl: move some OpenSSL defines from ssl_sock to openssl-compat
Some defines like OPENSSL_VERSION or X509_getm_notBefore() have nothing
to do in ssl_sock and must move to openssl-compat.h so that they are
consistently shared by the whole code. A warning in the code was added
against wild additions of macros there.
2019-05-10 09:31:06 +02:00
Willy Tarreau
5599456ee2 REORG: ssl: move openssl-compat from proto to common
This way we can include it much earlier to cover types/ as well.
2019-05-10 09:19:50 +02:00
Willy Tarreau
df17e0e1a7 BUILD: ssl: fix libressl build again after aes-gcm-enc
Enabling aes-gcm-enc in last commit (MINOR: ssl: enable aes_gcm_dec
on LibreSSL) uncovered a wrong condition on the define of the
EVP_CTRL_AEAD_SET_IVLEN macro which I forgot to add when making the
commit, resulting in breaking libressl build again. In case libressl
later defines this macro, the test will have to change for a version
range instead.
2019-05-10 09:19:07 +02:00
Willy Tarreau
86a394e44d MINOR: ssl: enable aes_gcm_dec on LibreSSL
This one requires OpenSSL 1.0.1 and above, and libressl was forked from
1.0.1g and is compatible (build-tested). No need to exclude it anymore
from using this converter.
2019-05-09 14:26:40 +02:00
Willy Tarreau
5db847ab65 CLEANUP: ssl: remove 57 occurrences of useless tests on LIBRESSL_VERSION_NUMBER
They were all check to comply with the advertised openssl version. Now
that libressl doesn't pretend to be a more recent openssl anymore, we
can simply rely on the regular openssl version tests without having to
deal with exceptions for libressl.
2019-05-09 14:26:39 +02:00
Willy Tarreau
1d158ab12d BUILD: ssl: make libressl use its own version numbers
LibreSSL causes lots of build issues by pretending to be OpenSSL 2.0.0,
and it requires lots of care for each #if added to cover any specific
OpenSSL features.

This commit addresses the problem by making LibreSSL only advertise the
version it forked from (1.0.1g) and by starting to use tests based on
its real version to enable features instead of working by exclusion.
2019-05-09 14:25:47 +02:00
Willy Tarreau
9a1ab08160 CLEANUP: ssl-sock: use HA_OPENSSL_VERSION_NUMBER instead of OPENSSL_VERSION_NUMBER
Most tests on OPENSSL_VERSION_NUMBER have become complex and break all
the time because this number is fake for some derivatives like LibreSSL.
This patch creates a new macro, HA_OPENSSL_VERSION_NUMBER, which will
carry the real openssl version defining the compatibility level, and
this version will be adjusted depending on the variants.
2019-05-09 14:25:43 +02:00
Willy Tarreau
affd1b980a BUILD: ssl: fix again a libressl build failure after the openssl FD leak fix
As with every single OpenSSL fix, LibreSSL build broke again, this time
after commit 56996dabe ("BUG/MINOR: mworker/ssl: close OpenSSL FDs on
reload"). A definitive solution will have to be found quickly. For now,
let's exclude libressl from the version test.

This patch must be backported to 1.9 since the fix above was already
backported there.
2019-05-09 13:55:33 +02:00
Olivier Houchard
d9986ed51e BUG/MEDIUM: h2: Make sure we set send_list to NULL in h2_detach().
In h2_detach(), if we still have a send_wait pointer, because we woke the
tasklet up, but it hasn't ran yet, explicitely set send_wait to NULL after
we removed the tasklet from the task list.
Failure to do so may lead to crashes if the h2s isn't immediately destroyed,
because we considered there were still something to send.

This should be backported to 1.9.
2019-05-09 13:26:48 +02:00
Christopher Faulet
6f3cb1801b MINOR: htx: Remove support for unused OOB HTX blocks
This type of block was introduced in the early design of the HTX and it is not
used anymore. So, just remove it.

This patch may be backported to 1.9.
2019-05-07 22:16:41 +02:00
Christopher Faulet
6177509eb7 MINOR: htx: Don't try to append a trailer block with the previous one
In H1 and H2, one and only one trailer block is emitted during the HTTP
parsing. So it is useless to try to append this block with the previous one,
like for data block.

This patch may be backported to 1.9.
2019-05-07 22:16:41 +02:00
Christopher Faulet
bc5770b91e MINOR: htx: Split on DATA blocks only when blocks are moved to an HTX message
When htx_xfer_blks() is called to move blocks from an HTX message to another
one, most of blocks must be transferred atomically. But some may be splitted if
there is not enough space to move all the block. This was true for DATA and TLR
blocks. But it is a bad idea to split trailers. During HTTP parsing, only one
TLR block is emitted. It simplifies the processing of trailers to keep the block
untouched.

This patch must be backported to 1.9 because some fixes may depend on it.
2019-05-07 22:16:41 +02:00
Christopher Faulet
cc5060217e BUG/MINOR: htx: Never transfer more than expected in htx_xfer_blks()
When the maximum free space available for data in the HTX message is compared to
the number of bytes to transfer, we must take into account the amount of data
already transferred. Otherwise we may move more data than expected.

This patch must be backported to 1.9.
2019-05-07 22:16:41 +02:00
Christopher Faulet
39593e6ae3 BUG/MINOR: mux-h1: Fix the parsing of trailers
Unlike other H1 parsing functions, the 3rd parameter of the function
h1_measure_trailers() is the maximum number of bytes to read. For others
functions, it is the relative offset where to stop the parsing.

This patch must be backported to 1.9.
2019-05-07 22:16:41 +02:00
Christopher Faulet
3b1d004d41 BUG/MEDIUM: spoe: Be sure the sample is found before setting its context
When a sample fetch is encoded, we use its context to set info about the
fragmentation. But if the sample is not found, the function sample_process()
returns NULL. So we me be sure the sample exists before setting its context.

This patch must be backported to 1.9 and 1.8.
2019-05-07 22:16:41 +02:00
Willy Tarreau
201fe40653 BUG/MINOR: mux-h2: fix the condition to close a cs-less h2s on the backend
A typo was introduced in the following commit : 927b88ba0 ("BUG/MAJOR:
mux-h2: fix race condition between close on both ends") making the test
on h2s->cs never being done and h2c->cs being dereferenced without being
tested. This also confirms that this condition does not happen on this
side but better fix it right now to be safe.

This must be backported to 1.9.
2019-05-07 19:17:50 +02:00
William Lallemand
27edc4b915 MINOR: mworker: support a configurable maximum number of reloads
This patch implements a new global parameter for the master-worker mode.
When setting the mworker-max-reloads value, a worker receive a SIGTERM
if its number of reloads is greater than this value.
2019-05-07 19:09:01 +02:00
Willy Tarreau
f656279347 CLEANUP: task: remove unneeded tests before task_destroy()
Since previous commit it's not needed anymore to test a task pointer
before calling task_destory() so let's just remove these tests from
the various callers before they become confusing. The function's
arguments were also documented. The same should probably be done
with tasklet_free() which involves a test in roughly half of the
call places.
2019-05-07 19:08:16 +02:00
Dragan Dosen
7d61a33921 BUG/MEDIUM: stick-table: fix regression caused by a change in proxy struct
In commit 1b8e68e ("MEDIUM: stick-table: Stop handling stick-tables as
proxies."), the ->table member of proxy struct was replaced by a pointer
that is not always checked and in some situations can cause a segfault,
eg. during reload or while using "show table" on CLI socket.

No backport is needed.
2019-05-07 14:56:59 +02:00
Rob Allen
56996dabe6 BUG/MINOR: mworker/ssl: close OpenSSL FDs on reload
From OpenSSL 1.1.1, the default behaviour is to maintain open FDs to any
random devices that get used by the random number library. As a result,
those FDs leak when the master re-execs on reload; since those FDs are
not marked FD_CLOEXEC or O_CLOEXEC, they also get inherited by children.
Eventually both master and children run out of FDs.

OpenSSL 1.1.1 introduces a new function to control whether the random
devices are kept open. When clearing the keep-open flag, it also closes
any currently open FDs, so it can be used to clean-up open FDs too.
Therefore, a call to this function is made in mworker_reload prior to
re-exec.

The call is guarded by whether SSL is in use, because it will cause
initialisation of the OpenSSL random number library if that has not
already been done.

This should be backported to 1.9 and 1.8.
2019-05-07 14:11:55 +02:00
Willy Tarreau
2135f91d18 BUG/MEDIUM: h2/htx: never leave a trailers block alone with no EOM block
If when receiving an H2 response we fail to add an EOM block after too
large a trailers block, we must not leave the trailers block alone as it
violates the internal assumptions by not being followed by an EOM, even
when an error is reported. We must then make sure the error will safely
be reported to upper layers and that no attempt will be made to forward
partial blocks.

This must be backported to 1.9.
2019-05-07 11:17:32 +02:00
Willy Tarreau
fb07b3f825 BUG/MEDIUM: mux-h2/htx: never wait for EOM when processing trailers
In message https://www.mail-archive.com/haproxy@formilux.org/msg33541.html
Patrick Hemmer reported an interesting bug affecting H2 and trailers.

The problem is that in order to close the stream we have to see the EOM
block, but nothing guarantees it will atomically be delivered with the
trailers block(s). So the code currently waits for it by returning zero
when it was not found, resulting in the caller (h2_snd_buf()) to loop
forever calling it again.

The current internal connection/connstream API doesn't allow a send
actor to notify its caller that it cannot process the data until it
gets more, so even returning zero will only lead to calls in loops
without any guarantee that any progress will be made.

Some late amendments to HTX already guaranteed the atomicity of the
trailers block during snd_buf(), which is currently ensured by the
fact that producers create exactly one such trailers block for all
trailers. So in practice we can only loop between trailers and EOM.

This patch changes the behaviour by making h2s_htx_make_trailers()
become atomic by not consuming the EOM block. This way either it finds
the end of trailers marker (empty line) or it fails. Once it sends the
trailers block, ES is set so the stream turns HLOC or CLOSED. Thanks
to previous patch "MEDIUM: mux-h2: discard contents that are to be sent
after a shutdown" is is now safe to interrupt outgoing data processing,
and the late EOM block will silently be discarded when the caller
finally sends it.

This is a bit tricky but should remain solid by design, and seems like
the only option we have that is compatible with 1.9, where it must be
backported along with the aforementioned patch.
2019-05-07 11:08:02 +02:00
Willy Tarreau
2b77848418 MEDIUM: mux-h2: discard contents that are to be sent after a shutdown
In h2_snd_buf() we discard any possible buffer contents requested to be
sent after a close or an error. But in practice we can extend this to
any case where the stream is locally half-closed since it means we will
never be able to send these data anymore.

For now it must not change anything, but it will be used by subsequent
patches to discard lone a HTX EOM block arriving after the trailers
block.
2019-05-07 11:08:02 +02:00
Willy Tarreau
aab1a60977 BUG/MEDIUM: h2/htx: always fail on too large trailers
In case a header frame carrying trailers just fits into the HTX buffer
but leaves no room for the EOM block, we used to return the same code
as the one indicating we're missing data. This could would result in
such frames causing timeouts instead of immediate clean aborts. Now
they are properly reported as stream errors (since the frame was
decoded and the compression context is still synchronized).

This must be backported to 1.9.
2019-05-07 11:08:02 +02:00
Willy Tarreau
5121e5d750 BUG/MINOR: mux-h2: rely on trailers output not input to turn them to empty data
When sending trailers, we may face an empty HTX trailers block or even
have to discard some of the headers there and be left with nothing to
send. RFC7540 forbids sending of empty HEADERS frames, so in this case
we turn to DATA frames (which is possible since after other DATA).

The code used to only check the input frame's contents to decide whether
or not to switch to a DATA frame, it didn't consider the possibility that
the frame only used to contain headers discarded later, thus it could still
emit an empty HEADERS frame in such a case. This patch makes sure that the
output frame size is checked instead to take the decision.

This patch must be backported to 1.9. In practice this situation is never
encountered since the discarded headers have really nothing to do in a
trailers block.
2019-05-07 11:07:59 +02:00
Dragan Dosen
2674303912 MEDIUM: regex: modify regex_comp() to atomically allocate/free the my_regex struct
Now we atomically allocate the my_regex struct within function
regex_comp() and compile the regex or free both in case of failure. The
pointer to the allocated my_regex struct is returned directly. The
my_regex* argument to regex_comp() is removed.

Function regex_free() was modified so that it systematically frees the
my_regex entry. The function does nothing when called with a NULL as
argument (like free()). It will avoid existing risk of not properly
freeing the initialized area.

Other structures are also updated in order to be compatible (the ones
related to Lua and action rules).
2019-05-07 06:58:15 +02:00
Frédéric Lécaille
7fcc24d4ef MINOR: peers: Do not emit global stick-table names.
This commit "MINOR: stick-table: Add prefixes to stick-table names"
prepended the "peers" section name to stick-table names declared in such "peers"
sections followed by a '/' character.  This is not this name which must be sent
over the network to avoid collisions with stick-table name declared as backends.
As the '/' character is forbidden as first character of a backend name, we prefix
the stick-table names declared in peers sections only with a '/' character.
With such declarations:

    peers mypeers
       table t1

	backend t1
	   stick-table ... peers mypeers

at peer protocol level, "t1" declared as stick-table in "mypeers" section is different
of "t1" stick-table declared as backend.

In src/peers.c, only two modifications were required: use ->nid stktable struct
member in place of ->id in peer_prepare_switchmsg() to prepare the stick-table
definition messages. Same thing in peer_treat_definemsg() to treat a stick-table
definition messages.
2019-05-07 06:54:07 +02:00
Frédéric Lécaille
c02766a267 MINOR: stick-table: Add prefixes to stick-table names.
With this patch we add a prefix to stick-table names declared in "peers" sections
concatenating the "peers" section name followed by a '/' character with
the stick-table name. Consequently, "peers" sections have their own
namespace for their stick-tables. Obviously, these stick-table names are not the
ones which should be sent over the network. So these configurations must be
compatible and should make A and B peers communicate with peers protocol:

    # haproxy A config, old way stick-table declerations
    peers mypeers
        peer A ...
        peer B ...

    backend t1
        stick-table type string size 10m store gpc0 peers mypeers

    # haproxy B config, new way stick-table declerations
    peers mypeers
        peer A ...
        peer B ...
        table t1 type string size store gpc0 10m

This "network" name is stored in ->nid new field of stktable struct. The "local"
stktable-name is still stored in ->id.
2019-05-07 06:54:07 +02:00
Frédéric Lécaille
015e4d7d93 MINOR: stick-tables: Add peers process binding computing.
Add a list of proxies for all the stick-tables (->proxies_list struct stktable
member) so that to be able to compute the process bindings of the peers after having
parsed the configuration file.
The proxies are added to the stick-tables they reference when parsing
stick-tables lines in proxy sections, when checking the actions in
check_trk_action() and when resolving samples args for stick-tables
without checking is they are duplicates. We check only there is no loop.
Then, after having parsed everything, we add the proxy bindings to the
peers frontend bindings with stick-tables they reference.
2019-05-07 06:54:07 +02:00
Frédéric Lécaille
1b8e68e89a MEDIUM: stick-table: Stop handling stick-tables as proxies.
This patch adds the support for the "table" line parsing in "peers" sections
to declare stick-table in such sections. This also prevents the user from having
to declare dummy backends sections with a unique stick-table inside.
Even if still supported, this usage will become deprecated.

To do so, the ->table member of proxy struct which is a stktable struct is replaced
by a pointer to a stktable struct allocated at parsing time in src/cfgparse-listen.c
for the dummy stick-table backends and in src/cfgparse.c for "peers" sections.
This has an impact on the code for stick-table sample converters and on the stickiness
rules parsers which first store the name of the dummy before resolving the rules.
This patch replaces proxy_tbl_by_name() calls by stktable_find_by_name() calls
to lookup for stick-tables stored in "stktable_by_name" ebtree at parsing time.
There is only one remaining place where proxy_tbl_by_name() is used: src/hlua.c.

At several places in the code we relied on the fact that ->size member of stick-table
was equal to zero to consider the stick-table was present by not configured,
this do not make sense anymore as ->table member of struct proxyis fow now on a pointer.
These tests are replaced by a test on ->table value itself.

In "peers" section we do not have to temporary store the name of the section the
stick-table are attached to because this name is obviously already known just after
having entered this "peers" section.

About the CLI stick-table I/O handler, the pointer to proxy struct is replaced by
a pointer to a stktable struct.
2019-05-07 06:54:06 +02:00
Frédéric Lécaille
d456aa4ac2 MINOR: config: Extract the code of "stick-table" line parsing.
With this patch we move the code responsible of parsing "stick-table"
lines to implement parse_stick_table() function in src/stick-tabble.c
so that to be able to parse "stick-table" elsewhere than in proxy sections.
We have have also added a conf struct to stktable struct to store the filename
and the line in the file the stick-table has been parsed to help in
diagnosing and displaying any configuration issue.
2019-05-07 06:54:06 +02:00
Willy Tarreau
034c88cf03 MEDIUM: tcp: add the "tfo" option to support TCP fastopen on the server
This implements support for the new API which relies on a call to
setsockopt().
On systems that support it (currently, only Linux >= 4.11), this enables
using TCP fast open when connecting to server.
Please note that you should use the retry-on "conn-failure", "empty-response"
and "response-timeout" keywords, or the request won't be able to be retried
on failure.

Co-authored-by: Olivier Houchard <ohouchard@haproxy.com>
2019-05-06 22:29:39 +02:00
Olivier Houchard
fdcb007ad8 MEDIUM: proto: Change the prototype of the connect() method.
The connect() method had 2 arguments, "data", that tells if there's pending
data to be sent, and "delack" that tells if we have to use a delayed ack
inconditionally, or if the backend is configured with tcp-smart-connect.
Turn that into one argument, "flags".
That way it'll be easier to provide more informations to connect() without
adding extra arguments.
2019-05-06 22:12:57 +02:00
Olivier Houchard
4cd2af4e5d BUG/MEDIUM: ssl: Don't attempt to use early data with libressl.
Libressl doesn't yet provide early data, so don't put the CO_FL_EARLY_SSL_HS
on the connection if we're building with libressl, or the handshake will
never be done.
2019-05-06 15:20:42 +02:00
Ilya Shipitsin
54832b97c6 BUILD: enable several LibreSSL hacks, including
SSL_SESSION_get0_id_context is introduced in LibreSSL-2.7.0
async operations are not supported by LibreSSL
early data is not supported by LibreSSL
packet_length is removed from SSL struct in LibreSSL
2019-05-06 07:26:24 +02:00
Tim Duesterhus
473c283d95 CLEANUP: Remove appsession documentation
I was about to partly revert 294d0f08b3,
because there were no 'X' for 'appsession' in the keyword matrix until
I checked the blame, realizing that the feature does not exist any more.

Clearly the documentation is confusing here, the removal note is only
listed *below* the old documentation and the supported sections still
show 'backend' and 'listen'.

It's been 3.5 years and 4 releases (1.6, 1.7, 1.8 and 1.9), I guess
this can be removed from the documentation of future versions.
2019-05-06 07:15:08 +02:00
Willy Tarreau
55e2f5ad14 BUG/MINOR: logs/threads: properly split the log area upon startup
If logs were emitted before creating the threads, then the dataptr pointer
keeps a copy of the end of the log header. Then after the threads are
created, the headers are reallocated for each thread. However the end
pointer was not reset until the end of the first second, which may result
in logs emitted by multiple threads during the first second to be mangled,
or possibly in some cases to use a memory area that was reused for something
else. The fix simply consists in reinitializing the end pointers immediately
when the threads are created.

This fix must be backported to 1.9 and 1.8.
2019-05-05 10:16:13 +02:00
Willy Tarreau
4fc49a9aab BUG/MEDIUM: checks: make sure the warmup task takes the server lock
The server warmup task is used when a server uses the "slowstart"
parameter. This task affects the server's weight and maxconn, and may
dequeue pending connections from the queue. This must be done under
the server's lock, which was not the case.

This must be backported to 1.9 and 1.8.
2019-05-05 06:54:22 +02:00
Willy Tarreau
223995e8ca BUG/MINOR: stream: also increment the retry stats counter on L7 retries
It happens that the retries stats use their own counter and are not
derived from the stream interface, so we need to update it as well
when performing an L7 retry.

No backport is needed.
2019-05-04 10:40:00 +02:00
Olivier Houchard
e3249a98e2 MEDIUM: streams: Add a new keyword for retry-on, "junk-response"
Add a way to retry requests if we got a junk response from the server, ie
an incomplete response, or something that is not valid HTTP.
To do so, one can use the new "junk-response" keyword for retry-on.
2019-05-04 10:20:24 +02:00
Olivier Houchard
865d8392bb MEDIUM: streams: Add a way to replay failed 0rtt requests.
Add a new keyword for retry-on, 0rtt-rejected. If set, we will try to
replay requests for which we sent early data that got rejected by the
server.
If that option is set, we will attempt to use 0rtt if "allow-0rtt" is set
on the server line even if the client didn't send early data.
2019-05-04 10:20:24 +02:00
Olivier Houchard
a254a37ad7 MEDIUM: streams: Add the ability to retry a request on L7 failure.
When running in HTX mode, if we sent the request, but failed to get the
answer, either because the server just closed its socket, we hit a server
timeout, or we get a 404, 408, 425, 500, 501, 502, 503 or 504 error,
attempt to retry the request, exactly as if we just failed to connect to
the server.

To do so, add a new backend keyword, "retry-on".

It accepts a list of keywords, which can be "none" (never retry),
"conn-failure" (we failed to connect, or to do the SSL handshake),
"empty-response" (the server closed the connection without answering),
"response-timeout" (we timed out while waiting for the server response),
or "404", "408", "425", "500", "501", "502", "503" and "504".

The default is "conn-failure".
2019-05-04 10:19:56 +02:00
Olivier Houchard
f4bda993dd BUG/MEDIUM: streams: Don't add CF_WRITE_ERROR if early data were rejected.
In sess_update_st_con_tcp(), if we have an error on the stream_interface
because we tried to send early_data but failed, don't flag the request
channel as CF_WRITE_ERROR, or we will never reach the analyser that sends
back the 425 response.

This should be backported to 1.9.
2019-05-03 22:23:41 +02:00
Olivier Houchard
010941f876 BUG/MEDIUM: ssl: Use the early_data API the right way.
We can only read early data if we're a server, and write if we're a client,
so don't attempt to mix both.

This should be backported to 1.8 and 1.9.
2019-05-03 21:00:10 +02:00
Willy Tarreau
c40efc1919 MINOR: init/threads: make the threads array global
Currently the thread array is a local variable inside a function block
and there is no access to it from outside, which often complicates
debugging. Let's make it global and export it. Also the allocation
return is now checked.
2019-05-03 10:16:30 +02:00
Willy Tarreau
b4f7cc3839 MINOR: init/threads: remove the useless tids[] array
It's still obscure how we managed to initialize an array of integers
with values always equal to the index, just to retrieve the value
from an opaque pointer to the index instead of directly using it! I
suspect it's a leftover from the very early threading experiments.

This commit gets rid of this and simply passes the thread ID as the
argument to run_thread_poll_loop(), thus significantly simplifying the
few call places and removing the need to allocate then free an array
of identity.
2019-05-03 09:59:15 +02:00
Willy Tarreau
81492c989c MINOR: threads: flatten the per-thread cpu-map
When we initially experimented with threads and processes support, we
needed to implement arrays of threads per process for cpu-map, but this
is not needed anymore since we support either threads or processes.
Let's simply make the thread-based cpu-map per thread and not per
thread and per process since that's not used anymore. Doing so reduces
the global struct from 33kB to 1.5kB.
2019-05-03 09:46:45 +02:00
Olivier Houchard
a48237fd07 BUG/MEDIUM: connections: Make sure we remove CO_FL_SESS_IDLE on disown.
When for some reason the session is not the owner of the connection anymore,
make sure we remove CO_FL_SESS_IDLE, even if we're about to call
conn->mux->destroy(), as the destroy may not destroy the connection
immediately if it's still in use.
This should be backported to 1.9.
u
2019-05-02 12:08:39 +02:00
Dragan Dosen
e99af978c8 BUG/MEDIUM: pattern: fix memory leak in regex pattern functions
The allocated regex is not freed properly and can cause a memory leak,
eg. when patterns are updated via CLI socket.

This patch should be backported to all supported versions.
2019-05-02 10:05:11 +02:00
Dragan Dosen
026ef570e1 BUG/MINOR: checks: free memory allocated for tasklets
The check->wait_list.task and agent->wait_list.task were not
freed properly on deinit().

This patch should be backported to 1.9.
2019-05-02 10:05:09 +02:00
Dragan Dosen
61302da0e7 BUG/MINOR: log: properly free memory on logformat parse error and deinit()
This patch may be backported to all supported versions.
2019-05-02 10:05:07 +02:00
Dragan Dosen
2a7c20f602 BUG/MINOR: haproxy: fix rule->file memory leak
When using the "use_backend" configuration directive, the configuration
file name stored as rule->file was not freed in some situations. This
was introduced in commit 4ed1c95 ("MINOR: http/conf: store the
use_backend configuration file and line for logs").

This patch should be backported to 1.9, 1.8 and 1.7.
2019-05-02 10:05:06 +02:00
Olivier Houchard
b51937ebaa BUG/MEDIUM: ssl: Don't pretend we can retry a recv/send if we got a shutr/w.
In ha_ssl_write() and ha_ssl_read(), don't pretend we can retry a read/write
if we got a shutr/shutw, or we will never properly shutdown the connection.
2019-05-01 17:37:33 +02:00
Ilya Shipitsin
0c50b1ecbb BUG/MEDIUM: servers: fix typo "src" instead of "srv"
When copying the settings for all servers when using server templates,
fix a typo, or we would never copy the length of the ALPN to be used for
checks.

This should be backported to 1.9.
2019-04-30 23:04:47 +02:00
Christopher Faulet
02f3cf19ed CLEANUP: config: Don't alter listener->maxaccept when nbproc is set to 1
This patch only removes a useless calculation on listener->maxaccept when nbproc
is set to 1. Indeed, the following formula has no effet in such case:

  listener->maxaccept = (listener->maxaccept + nbproc - 1) / nbproc;

This patch may be backported as far as 1.5.
2019-04-30 15:28:29 +02:00
Christopher Faulet
6b02ab8734 MINOR: config: Test validity of tune.maxaccept during the config parsing
Only -1 and positive integers from 0 to INT_MAX are accepted. An error is
triggered during the config parsing for any other values.

This patch may be backported to all supported versions.
2019-04-30 15:28:29 +02:00
Christopher Faulet
102854cbba BUG/MEDIUM: listener: Fix how unlimited number of consecutive accepts is handled
There is a bug when global.tune.maxaccept is set to -1 (no limit). It is pretty
visible with one process (nbproc sets to 1). The functions listener_accept() and
accept_queue_process() don't expect to handle negative maxaccept values. So
instead of accepting incoming connections without any limit, none are never
accepted and HAProxy loop infinitly in the scheduler.

When there are 2 or more processes, the bug is a bit more subtile. The limit for
a listener is set to 1. So only one connection is accepted at a time by a given
listener. This happens because the listener's maxaccept value is an unsigned
integer. In check_config_validity(), it is first set to UINT_MAX (-1 casted in
an unsigned integer), and then some calculations on it leads to an integer
overflow.

To fix the bug, the listener's maxaccept value is now a signed integer. So, if a
negative value is set for global.tune.maxaccept, we keep it untouched for the
listener and no calculation is made on it. Then, in the listener code, this
signed value is casted to a unsigned one. It simplifies all tests instead of
dealing with negative values. So, it limits the number of connections accepted
at a time to UINT_MAX at most. But, honestly, it not an issue.

This patch must be backported to 1.9 and 1.8.
2019-04-30 15:28:29 +02:00
Willy Tarreau
bc13bec548 MINOR: activity: report context switch counts instead of rates
It's not logical to report context switch rates per thread in show activity
because everything else is a counter and it's not even possible to compare
values. Let's only report counts. Further, this simplifies the scheduler's
code.
2019-04-30 14:55:18 +02:00
Willy Tarreau
49ee3b2f9a BUG/MAJOR: map/acl: real fix segfault during show map/acl on CLI
A previous commit 8d85aa44d ("BUG/MAJOR: map: fix segfault during
'show map/acl' on cli.") was provided to address a concurrency issue
between "show acl" and "clear acl" on the CLI. Sadly the code placed
there was copy-pasted without changing the element type (which was
struct stream in the original code) and not tested since the crash
is still present.

The reproducer is simple : load a large ACL file (e.g. geolocation
addresses), issue "show acl #0" in loops in one window and issue a
"clear acl #0" in the other one, haproxy crashes.

This fix was also tested with threads enabled and looks good since
the locking seems to work correctly in these areas though. It will
have to be backported as far as 1.6 since the commit above went
that far as well...
2019-04-30 11:50:59 +02:00
Frédéric Lécaille
d803e475e5 MINOR: log: Enable the log sampling and load-balancing feature.
This patch implements the sampling and load-balancing of log servers configured
with "sample" new keyword implemented by this commit:
    'MINOR: log: Add "sample" new keyword to "log" lines'.
As the list of ranges used to sample the log to balance is ordered, we only
have to maintain ->curr_idx member of smp_info struct which is the index of
the sample and check if it belongs or not to the current range to decide if we
must send it to the log server or not.
2019-04-30 09:25:09 +02:00
Frédéric Lécaille
d95ea2897e MINOR: log: Add "sample" new keyword to "log" lines.
This patch implements the parsing of "sample" new optional keyword for "log" lines
to be able to sample and balance the load of log messages between serveral log
destinations declared by "log" lines. This keyword must be followed by a list of
comma seperated ranges of indexes numbered from 1 to define the samples to be used
to balance the load of logs to send. This "sample" keyword must be used on "log" lines
obviously before the remaining optional ones without keyword. The list of ranges
must be followed by a colon character to separate it from the log sampling size.

With such following configuration declarations:

   log stderr local0
   log 127.0.0.1:10001 sample 2-3,8-11:11 local0
   log 127.0.0.2:10002 sample 5:5 local0

in addition to being sent to stderr, about the second "log" line, every 11 logs
the logs #2 up to #3 would be sent to 127.0.0.1:10001, then #8 up tp #11 four
logs would be sent to the same log server and so on periodically. Logs would be
sent to 127.0.0.2:100002 every 5 logs.

It is also possible to define the size of the sample with a value different of
the maximum of the high limits of the ranges, for instance as follows:

   log 127.0.0.1:10001 sample 2-3,8-11:15 local0

as before the two logs #2 and #3 would be sent to 127.0.0.1:10001, then #8
up tp #11 logs, but in this case here, this would be done periodically every 15
messages.

Also note that the ranges must not overlap each others. This is to ease the
way the logs are periodically sent.
2019-04-30 09:25:09 +02:00
Christopher Faulet
85db3212b8 MINOR: spoe: Use the sample context to pass frag_ctx info during encoding
This simplifies the API and hide the details in the sample. This way, only
string and binary are aware of these info, because other types cannot be
partially encoded.

This patch may be backported to 1.9 and 1.8.
2019-04-29 16:02:05 +02:00
Kevin Zhu
f7f54280c8 BUG/MEDIUM: spoe: arg len encoded in previous frag frame but len changed
Fragmented arg will do fetch at every encode time, each fetch may get
different result if SMP_F_MAY_CHANGE, for example res.payload, but
the length already encoded in first fragment of the frame, that will
cause SPOA decode failed and waste resources.

This patch must be backported to 1.9 and 1.8.
2019-04-29 16:02:05 +02:00
Christopher Faulet
1907ccc2f7 BUG/MINOR: http: Call stream_inc_be_http_req_ctr() only one time per request
The function stream_inc_be_http_req_ctr() is called at the beginning of the
analysers AN_REQ_HTTP_PROCESS_FE/BE. It as an effect only on the backend. But we
must be careful to call it only once. If the processing of HTTP rules is
interrupted in the middle, when the analyser is resumed, we must not call it
again. Otherwise, the tracked counters of the backend are incremented several
times.

This bug was reported in github. See issue #74.

This fix should be backported as far as 1.6.
2019-04-29 16:01:47 +02:00
Willy Tarreau
97215ca284 BUG/MEDIUM: mux-h2: properly deal with too large headers frames
In h2c_decode_headers(), now that we support CONTINUATION frames, we
try to defragment all pending frames at once before processing them.
However if the first is exactly full and the second cannot be parsed,
we don't detect the problem and we wait for the next part forever due
to an incorrect check on exit; we must abort the processing as soon as
the current frame remains full after defragmentation as in this case
there is no way to make forward progress.

Thanks to Yves Lafon for providing traces exhibiting the problem.

This must be backported to 1.9.
2019-04-29 10:20:21 +02:00
David CARLIER
4de0eba848 MEDIUM: da: HTX mode support.
The DeviceAtlas module now can support both the legacy
mode and the new HTX's with the known set of support headers
for the latter.
2019-04-26 17:06:32 +02:00
David Carlier
0470d704a7 BUILD/MEDIUM: contrib: Dummy DeviceAtlas API.
Creating a "mocked" version mainly for testing purposes.
2019-04-26 17:06:32 +02:00
Willy Tarreau
4ad574fbe2 MEDIUM: streams: measure processing time and abort when detecting bugs
On some occasions we've had loops happening when processing actions
(e.g. a yield not being well understood) resulting in analysers being
called in loops until the analysis timeout without incrementing the
stream's call count, thus this type of bug cannot be caught by the
current protection system.

What this patch proposes is to start to measure the time spent in analysers
when profiling is enabled on the thread, in order to detect if a stream is
really misbehaving. In this case we measured the consumed CPU time, not the
wall clock time, so as not to be affected by possible noisy neighbours
sharing the same CPU. When more than 100ms are spent in an analyser, we
trigger the stream_dump_and_crash() function to report the anomaly.

The choice of 100ms comes from the fact that regular calls only take around
1 microsecond and it seems reasonable to accept a degradation factor of
100000, which covers very slow machines such as home gateways running on
sub-ghz processors, with extremely heavy configurations. Some complete
tests show that even this common bogus map_regm() entry supposedly designed
to extract a port from an IP:port entry does not trigger the timeout (25 ms
evaluation time for a 4kB header, exercise left to the reader to spot the
mistake) :

   ([0-9]{0,3}).([0-9]{0,3}).([0-9]{0,3}).([0-9]{0,3}):([0-9]{0,5}) \5

However this one purposely designed to kill haproxy definitely dies as it
manages to completely freeze the whole process for more than one second
on a 4 GHz CPU for only 120 bytes in :

   (.{0,20})(.{0,20})(.{0,20})(.{0,20})(.{0,20})b \1

This protection will definitely help during the code stabilization period
and may possibly be left enabled later depending on reported issues or not.

If you've noticed that your workload is affected by this patch, please
report it as you have very likely found a bug. And in the mean time you
can turn profiling off to disable it.
2019-04-26 14:30:59 +02:00
Willy Tarreau
3d07a16f14 MEDIUM: stream/debug: force a crash if a stream spins over itself forever
If a stream is caught spinning over itself at more than 100000 loops per
second and for more than one second, the process will be aborted and the
offender reported on the console and logs. Typical figures usually are just
a few tens to hundreds per second over a very short time so there is a huge
margin here. Using even higher values could also work but there is the risk
of not being able to catch offenders if multiple ones start to bug at the
same time and share the load. This code should ideally be disabled for
stable releases, though in theory nothing should ever trigger it.
2019-04-26 13:16:14 +02:00
Willy Tarreau
dcb0e1d37d MEDIUM: appctx/debug: force a crash if an appctx spins over itself forever
If an appctx is caught spinning over itself at more than 100000 loops per
second and for more than one second, the process will be aborted and the
offender reported on the console and logs. Typical figures usually are just
a few tens to hundreds per second over a very short time so there is a huge
margin here. Using even higher values could also work but there is the risk
of not being able to catch offenders if multiple ones start to bug at the
same time and share the load. This code should ideally be disabled for
stable releases, though in theory nothing should ever trigger it.
2019-04-26 13:15:56 +02:00
Willy Tarreau
71c07ac65a MINOR: stream/debug: make a stream dump and crash function
During 1.9 development (and even a bit after) we've started to face a
significant number of situations where streams were abusively spinning
due to an uncaught error flag or complex conditions that couldn't be
correctly identified. Sometimes streams wake appctx up and conversely
as well. More importantly when this happens the only fix is to restart.

This patch adds a new function to report a serious error, some relevant
info and to crash the process using abort() so that a core dump is
available. The purpose will be for this function to be called in various
situations where the process is unfixable. It will help detect these
issues much earlier during development and may even help fixing test
platforms which are able to automatically restart when such a condition
happens, though this is not the primary purpose.

This patch only provides the function and doesn't use it yet.
2019-04-26 13:15:56 +02:00
Willy Tarreau
5e370daa52 BUG/MINOR: proto_http: properly reset the stream's call rate on keep-alive
The stream's call rate measurement was added by commit 2e9c1d296 ("MINOR:
stream: measure and report a stream's call rate in "show sess"") but it
forgot to reset it in case of HTTP keep-alive (legacy mode), resulting
in incorrect measurements.

No backport is needed, unless the patch above is backported.
2019-04-25 18:33:37 +02:00
Willy Tarreau
d5ec4bfe85 CLEANUP: standard: use proper const to addr_to_str() and port_to_str()
The input parameter was not marked const, making it painful for some calls.
2019-04-25 17:48:16 +02:00
Willy Tarreau
d2d3348acb MINOR: activity: enable automatic profiling turn on/off
Instead of having to manually turn task profiling on/off in the
configuration, by default it will work in "auto" mode, which
automatically turns on on any thread experiencing sustained loop
latencies over one millisecond averaged over the last 1024 samples.

This may happen with configs using lots of regex (thing map_reg for
example, which is the lazy way to convert Apache's rewrite rules but
must not be abused), and such high latencies affect all the process
and the problem is most often intermittent (e.g. hitting a map which
is only used for certain host names).

Thus now by default, with profiling set to "auto", it remains off all
the time until something bad happens. This also helps better focus on
the issues when looking at the logs as well as in "show sess" output.
It automatically turns off when the average loop latency over the last
1024 calls goes below 990 microseconds (which typically takes a while
when in idle).

This patch could be backported to stable versions after a bit more
exposure, as it definitely improves observability and the ability to
quickly spot the culprit. In this case, previous patch ("MINOR:
activity: make the profiling status per thread and not global") must
also be taken.
2019-04-25 17:26:46 +02:00
Willy Tarreau
d9add3acc8 MINOR: activity: make the profiling status per thread and not global
In order to later support automatic profiling turn on/off, we need to
have it per-thread. We're keeping the global option to know whether to
turn it or on off, but the profiling status is now set per thread. We're
updating the status in activity_count_runtime() which is called before
entering poll(). The reason is that we'll extend this with run time
measurement when deciding to automatically turn it on or off.
2019-04-25 17:26:19 +02:00
Willy Tarreau
d636675137 BUG/MINOR: activity: always initialize the profiling variable
It happens it was only set if present in the configuration. It's
harmless anyway but can still cause doubts when comparing logs and
configurations so better correctly initialize it.

This should be backported to 1.9.
2019-04-25 17:26:19 +02:00
Willy Tarreau
22d63a24d9 MINOR: applet: measure and report an appctx's call rate in "show sess"
Very similarly to previous commit doing the same for streams, we now
measure and report an appctx's call rate. This will help catch applets
which do not consume all their data and/or which do not properly report
that they're waiting for something else. Some of them like peers might
theorically be able to exhibit some occasional peeks when teaching a
full table to a nearby peer (e.g. the new replacement process), but
nothing close to what a bogus service can do so there is no risk of
confusion.
2019-04-24 16:04:23 +02:00
Willy Tarreau
2e9c1d2960 MINOR: stream: measure and report a stream's call rate in "show sess"
Quite a few times some bugs have made a stream task incorrectly
handle a complex combination of events, which was often reported as
"100% CPU", and was usually caused by the event not being properly
identified and flushed, and the stream's handler called in loops.

This patch adds a call rate counter to the stream struct. It's not
huge, it's really inexpensive (especially compared to the rest of the
processing function) and will easily help spot such tasks in "show sess"
output, possibly even allowing to kill them.

A future patch should probably consist in alerting when they're above a
certain threshold, possibly sending a dump and killing them. Some options
could also consist in aborting in order to get an analyzable core dump
and let a service manager restart a fresh new process.
2019-04-24 16:04:23 +02:00
Willy Tarreau
0212fadd65 MINOR: tasks/activity: report the context switch and task wakeup rates
It's particularly useful to spot runaway tasks to see this. The context
switch rate covers all tasklet calls (tasks and I/O handlers) while the
task wakeups only covers tasks picked from the run queue to be executed.
High values there will indicate either an intense traffic or a bug that
mades a task go wild.
2019-04-24 16:04:23 +02:00
Willy Tarreau
69b5a7f1a3 CLEANUP: task: report calls as unsigned in show sess
The "show sess" output used signed ints to report the number of calls,
which is confusing for runaway tasks where the call count can turn
negative.
2019-04-24 16:04:23 +02:00
Christopher Faulet
4904058661 BUG/MINOR: htx: Exclude TCP proxies when the HTX mode is handled during startup
When tests are performed on the HTX mode during HAProxy startup, only HTTP
proxies are considered. It is important because, since the commit 1d2b586cd
("MAJOR: htx: Enable the HTX mode by default for all proxies"), the HTX is
enabled on all proxies by default. But for TCP proxies, it is "deactivated".

This patch must be backported to 1.9.
2019-04-24 15:40:02 +02:00
Willy Tarreau
274ba67862 BUG/MAJOR: lb/threads: fix AB/BA locking issue in round-robin LB
An occasional divide by zero in the round-robin scheduler was addressed
in commit 9df86f997 ("BUG/MAJOR: lb/threads: fix insufficient locking on
round-robin LB") by grabing the server's lock in fwrr_get_server_from_group().

But it happens that this is not the correct approach as it introduces a
case of AB/BA deadlock reported by Maksim Kupriianov. This happens when
a server weight changes from/to zero while another thread extracts this
server from the tree. The reason is that the functions used to manipulate
the state work under the server's lock and grab the LB lock while the ones
used in LB work under the LB lock and grab the server's lock when needed.

This commit mostly reverts the changes above and instead further completes
the locking analysis performed on this code to identify areas that really
need to be protected by the server's lock, since this is the only algorithm
which happens to have this requirement. This audit showed that in fact all
locations which require the server's lock are already protected by the LB
lock. This was not noticed the first time due to the server's lock being
taken instead and due to some functions misleadingly using atomic ops to
modify server fields which are under the LB lock protection (these ones
were now removed).

The change consists in not taking the server's lock anymore here, and
instead making sure that the aforementioned function which used to
suffer from the server's weight becoming zero only uses a copy of the
weight which was preliminary verified to be non-null (when the weight
is null, the server will be removed from the tree anyway so there is
no need to recalculate its position).

With this change, the code survived an injection at 200k req/s split
on two servers with weights changing 50 times a second.

This commit must be backported to 1.9 only.
2019-04-24 14:23:40 +02:00
Olivier Houchard
a28454ee21 BUG/MEDIUM: ssl: Return -1 on recv/send if we got EAGAIN.
In ha_ssl_read()/ha_ssl_write(), if we couldn't send/receive data because
we got EAGAIN, return -1 and not 0, as older SSL versions expect that.
This should fix the problems with OpenSSL < 1.1.0.
2019-04-24 12:06:08 +02:00
Christopher Faulet
371723b0c2 BUG/MINOR: spoe: Don't systematically wakeup SPOE stream in the applet handler
This can lead to wakeups in loop between the SPOE stream and the SPOE applets
waiting to receive agent messages (mainly AGENT-HELLO and AGENT-DISCONNECT).

This patch must be backported to 1.9 and 1.8.
2019-04-23 21:20:47 +02:00
Christopher Faulet
5e1a9d715e BUG/MEDIUM: stream: Fix the way early aborts on the client side are handled
A regression was introduced with the commit c9aecc8ff ("BUG/MEDIUM: stream:
Don't request a server connection if a shutw was scheduled"). Among other this,
it breaks the CLI when the shutr on the client side is handled with the client
data. To depend on the flag CF_SHUTW_NOW to not establish the server connection
when an error on the client side is detected is the right way to fix the bug,
because this flag may be set without any error on the client side.

So instead, we abort the request where the error is handled and only when the
backend stream-interface is in the state SI_ST_INI. This way, there is no
ambiguity on the reason why the abort accurred. The stream-interface is also
switched to the state SI_ST_CLO.

This patch must be backported to 1.9. If the commit c9aecc8ff is backported to
previous versions, this one MUST also be backported. Otherwise, it MAY be
backported to older versions that 1.9 with caution.
2019-04-23 21:20:47 +02:00
Frédéric Lécaille
bed883abe8 BUG/MAJOR: stream: Missing DNS context initializations.
Fix some missing initializations wich came with 333939c commit (MINOR: action:
new '(http-request|tcp-request content) do-resolve' action). The DNS contexts of
streams which were allocated were not initialized by stream_new(). This leaded to
accesses to non-allocated memory when freeing these contexts with stream_free().
2019-04-23 20:24:11 +02:00