Commit Graph

8831 Commits

Author SHA1 Message Date
Willy Tarreau 86ff9c8f3a REGTEST: the cache regtest requires haproxy 1.9
The chunks and the max-object-size features require version 1.9.
2018-12-12 15:21:56 +01:00
Remi Gacogne 00488ddef5 BUG: dns: Fix off-by-one write in dns_validate_dns_response()
The maximum number of bytes in a DNS name is indeed 255, but we
need to allocate one more byte for the NULL-terminating byte.
Otherwise dns_read_name() might return 255 for a very long name,
causing dns_validate_dns_response() to write a NULL value one
byte after the end of the buffer:

dns_answer_record->name[len] = 0;

The next fields in the struct being filled from the content of the
query, it might have been possible to fill them with non-0 values,
causing for example a strlen() of the name to read past the end of
the struct and access unintended parts of the memory, possibly
leading to a crash.

To be backported to 1.8, probably also 1.7.
2018-12-12 14:44:52 +01:00
Remi Gacogne bc552102ad BUG: dns: Fix out-of-bounds read via signedness error in dns_validate_dns_response()
Since the data_len field of the dns_answer_item struct was an int16_t,
record length values larger than 2^15-1 were causing an integer
overflow and thus may have been interpreted as negative, making us
read well before the beginning of the buffer.
This might have led to information disclosure or a crash.

To be backported to 1.8, probably also 1.7.
2018-12-12 14:44:38 +01:00
Remi Gacogne efbbdf7299 BUG: dns: Prevent out-of-bounds read in dns_validate_dns_response()
We need to make sure that the record length is not making us read
past the end of the data we received.
Before this patch we could for example read the 16 bytes
corresponding to an AAAA record from the non-initialized part of
the buffer, possibly accessing anything that was left on the stack,
or even past the end of the 8193-byte buffer, depending on the
value of accepted_payload_size.

To be backported to 1.8, probably also 1.7.
2018-12-12 14:44:29 +01:00
Remi Gacogne 2d19fbcab2 BUG: dns: Prevent out-of-bounds read in dns_read_name()
Some callers of dns_read_name() do not make sure that we can read
the first byte, holding the length of the next label, without going
past our buffer, so we need to make sure of that.
In addition, if the label is a compressed one we need to make sure
that we can read the following byte to compute the target offset.

To be backported to 1.8, probably also 1.7.
2018-12-12 14:44:13 +01:00
Remi Gacogne 58df5aea0a BUG: dns: Prevent stack-exhaustion via recursion loop in dns_read_name
When a compressed pointer is encountered, dns_read_name() will call
itself with the pointed-to offset in the packet.
With a specially crafted packet, it was possible to trigger an
infinite-loop recursion by making the pointer points to itself.
While it would be possible to handle that particular case differently
by making sure that the target is different from the current offset,
it would still be possible to craft a packet with a very long chain
of valid pointers, always pointing backwards. To prevent a stack
exhaustion in that case, this patch restricts the number of recursive
calls to 100, which should be more than enough.

To be backported to 1.8, probably also 1.7.
2018-12-12 14:43:25 +01:00
Christopher Faulet adb2220041 BUG/MEDIUM: mux-h1: Fix the zero-copy on output for chunked messages
The commit 3815b227f ("MEDIUM: mux-h1: implement true zero-copy of DATA blocks")
broke the output of chunked messages. When the zero-copy was performed on such
messages, no chunk size was emitted nor ending CRLF.

Now, the chunked envelope is added when necessary. We have at least the size of
the struct htx to emit it. So 40 bytes for now. It should be enough.
2018-12-12 13:56:35 +01:00
William Lallemand 256bf0d37b MINOR: cli: change 'show proc' output of old processes
Change the output of the relative pid for the old processes, displays
"[was: X]" instead of just "X" which was confusing if you want to
connect to the CLI of an old PID.
2018-12-12 13:54:17 +01:00
Willy Tarreau 2a59e87735 MINOR: mux-h2: force reads to be HTX-aligned in HTX mode
H2 has a 9-byte frame header, and HTX has a 40-byte frame header.
By artificially advancing the Rx header and limiting the amount of
bytes read to protect the end of the buffer, we can make the data
payload perfectly aligned with HTX blocks and optimize the copy.
2018-12-12 11:52:45 +01:00
Willy Tarreau 98de12a5d1 MEDIUM: mux-h2: implement true zero-copy send of large HTX DATA blocks
This is similar to what was done for the H1 mux : when the mux's buffer
is empty and the htx area contains exactly one data block of the same
size as the requested count, and all window and frame size conditions are
satisfied, then it's possible to simply swap the caller's buffer with the
mux's output buffer and adjust offsets and length to match the entire
DATA HTX block in the middle. An H2 frame header has to be prepended
before the block but this always fits in an HTX frame header.

In this case we perform a true zero-copy operation from end-to-end. This
is the situation that happens all the time with large files. When using
HTX over H2 over TLS, this brings a 3% extra performance gain. TLS remains
a limiting factor here but the copy definitely has a cost. Also since
haproxy can now use H2 in clear, the savings can be higher.
2018-12-12 11:52:45 +01:00
Willy Tarreau 06ae84a8ac MINOR: mux-h2: avoid copying large blocks into full buffers
Due to blocking factor being different on H1 and H2, we regularly end
up with tails of data blocks that leave room in the mux buffer, making
it tempting to copy the pending frame into the remaining room left, and
possibly realigning the output buffer.

Here we check if the output buffer contains data, and prefer to wait
if either the current frame doesn't fit or if it's larger than 1/4 of
the buffer. This way upon next call, either a zero copy, or a larger
and aligned copy will be performed, taking the whole chunk at once.

Doing so increases the H2 bandwidth by slightly more than 1% on large
objects.
2018-12-12 11:52:45 +01:00
William Lallemand 142db37043 DOC: master CLI documentation in management.txt
Documentation which explains the basic usage of the master CLI.
2018-12-12 11:47:24 +01:00
Willy Tarreau dc572364c6 BUG/MINOR: mux-h2: advertise a larger connection window size
By default H2 uses a 65535 bytes window for the connection, and changing
it requires sending a WINDOW_UPDATE message. We only used to update the
window when receiving data, thus never increasing it further.

As reported by user klzgrad on the mailing list, this seriously limits
the upload bitrate, and will have an even higher impact on the backend
H2 connections to origin servers.

There is no technical reason for keeping this window so low, so let's
increase it to the maximum possible value (2G-1). We do this by
pretending we've already received that many data minus the maximum
data the client might already send (65535), so that an early
WINDOW_UPDATE message is sent right after the SETTINGS frame.

This should be backported to 1.8. This patch depends on previous
patch "BUG/MINOR: mux-h2: refrain from muxing during the preface".
2018-12-12 09:23:41 +01:00
Willy Tarreau 75a930affb BUG/MINOR: mux-h2: refrain from muxing during the preface
The condition to refrain from processing the mux was insufficient as it
would only handle the outgoing connections. In essence it is not that much
of a problem since we don't have streams yet on an incoming connetion. But
it prevents waiting for the end of the preface before sending an early
WINDOW_UPDATE message, thus causing the connections to fail in this case.

This must be backported to 1.8 with a few minor adaptations.
2018-12-12 09:23:41 +01:00
Willy Tarreau c77d364905 MINOR: config: round up global.tune.bufsize to the next multiple of 2 void*
Since HTX casts the buffer to a struct and stores relative pointers at the
end, it is mandatory that its end is properly aligned. This patch enforces
a buffer size rounding up to the next multiple of two void*, thus 8 on
32-bit and 16 on 64-bit, to match what malloc() already does on the beginning
of the buffer. In pratice it will never be really noticeable since default
sizes already are such multiples.
2018-12-12 06:19:42 +01:00
Willy Tarreau 3815b227fe MEDIUM: mux-h1: implement true zero-copy of DATA blocks
When the mux's buffer is empty and the htx area contains exactly one
data block of the same size as the requested count, then it's possible
to simply swap the caller's buffer with the mux's output buffer and
adjust offsets and length to match the entire DATA HTX block in the
middle. In this case we perform a true zero-copy operation from
end-to-end. This is the situation that happens all the time with large
files. With this change, the HTX bit rate performance catches up again
with the legacy mode (measured at 97%).
2018-12-11 19:56:06 +01:00
Willy Tarreau 0007d0afbc CLEANUP: stream: remove SF_TUNNEL, SF_INITIALIZED, SF_CONN_TAR
These flags haven't been used for a while. SF_TUNNEL was reintroduced
by commit d62b98c6e ("MINOR: stream: don't set backend's nor response
analysers on SF_TUNNEL") to handle the two-level streams needed to
deal with the first model for H2, and was not removed after this model
was abandonned. SF_INITIALIZED was only set. SF_CONN_TAR was never
referenced at all.
2018-12-11 18:01:38 +01:00
Willy Tarreau afba57ae80 REORG: h1: merge types+proto into common/h1.h
These two files are self-contained and do not depend on other
layers, so let's remerge them together for easier manipulation.
2018-12-11 17:15:13 +01:00
Willy Tarreau 30925659ef CLEANUP: h1: remove some occurrences of unneeded h1.h inclusions
Several places where h1.h was included didn't need it at all since
they in fact relied on the legacy HTTP definitions.
2018-12-11 17:15:13 +01:00
Willy Tarreau 326e27ed08 REORG: h1: move the h1_state definition to proto_http
This is the legacy HTTP/1 state, it's never used from within h1 users,
let's move it to proto_http with the rest of the legacy code.
2018-12-11 17:15:13 +01:00
Willy Tarreau 538746ad38 REORG: h1: move legacy http functions to http_msg.c
Now that h1 and legacy HTTP are two distinct things, there's no need
to keep the legacy HTTP parsers in h1.c since they're only used by
the legacy code in proto_http.c, and h1.h doesn't need to include
hdr_idx anymore. This concerns the following functions :

- http_parse_reqline();
- http_parse_stsline();
- http_msg_analyzer();
- http_forward_trailers();

All of these were moved to http_msg.c.
2018-12-11 17:15:13 +01:00
Willy Tarreau c5a4fd5c30 REORG: http: create http_msg.c to place there some legacy HTTP parts
Lots of HTTP code still uses struct http_msg. Not only this code is
still huge, but it's part of the legacy interface. Let's move most
of these functions to a separate file http_msg.c to make it more
visible which file relies on what. It's mostly symmetrical with
what is present in http_htx.c.

The function http_transform_header_str() which used to rely on two
function pointers to look up a header was simplified to rely on
two variants http_legacy_replace_{,full_}header(), making both
sides of the function much simpler.

No code was changed beyond these moves.
2018-12-11 17:15:13 +01:00
Willy Tarreau b96b77ed6e REORG: htx: merge types+proto into common/htx.h
All the HTX definition is self-contained and doesn't really depend on
anything external since it's a mostly protocol. In addition, some
external similar files (like h2) also placed in common used to rely
on it, making it a bit awkward.

This patch moves the two htx.h files into a single self-contained one.
The historical dependency on sample.h could be also removed since it
used to be there only for http_meth_t which is now in http.h.
2018-12-11 17:15:04 +01:00
Christopher Faulet 99a17a2d91 MEDIUM: cache: Require an explicit filter declaration if other filters are used
As for the compression filter, the cache filter must be explicitly declared
(using the filter keyword) if other filters than cache are used. It is mandatory
to explicitly define the filters order.

Documentation has been updated accordingly.
2018-12-11 17:09:31 +01:00
Christopher Faulet afd819c54a MEDIUM: cache/compression: Add a way to safely combined compression and cache
This is only true for HTX proxies. On legacy HTTP proxy, if the compression and
the cache are both enabled, an error during HAProxy startup is triggered.

With the HTX, now you can use both in any order. If the compression is defined
before the cache, then the responses will be stored compressed. If the
compression is defined after the cache, then the responses will be stored
uncompressed. So in the last case, when a response is served from the cache, it
will compressed too like any response.
2018-12-11 17:09:31 +01:00
Christopher Faulet f4a4ef7d7c MINOR: filters: Export the name of known filters
It could be useful to know if some filter is declared on a proxy or if it is
enabled on a stream.
2018-12-11 17:09:31 +01:00
Christopher Faulet 95220e2ed8 MINOR: cache: Improve and simplify the cache configuration check
To do so, a dedicated configuration has been added on cache filters. Before the
cache filter configuration pointed directly to the cache it used. Now, it is the
dedicated structure cache_flt_conf. Store and use rules also point to this
structure. It is linked to the cache the filter must used. It also contains a
flags field. This will allow us to define the behavior of a cache filter when a
response is stored in the cache or delivered from it.

And now, Store and use rules uses a common parsing function. So if it does not
already exists, a filter is always created for both kind of rules. The cache
filters configuration is checked using their check callback. In the postparser
function, we only check the caches configuration. This removes the loop on all
proxies in the postparser function.
2018-12-11 17:09:31 +01:00
Christopher Faulet 54a8d5a4a0 MEDIUM: cache/htx: Add the HTX support into the cache
The cache is now able to store and resend HTX messages. When an HTX message is
stored in the cache, the headers are prefixed with their block's info (an
uint32_t), containing its type and its length. Data, on their side, are stored
without any prefix. Only the value is copied in the cache. 2 fields have been
added in the structure cache_entry, hdrs_len and data_len, to known the size, in
the cache, of the headers part and the data part. If the message is chunked, the
trailers are also copied, the same way as data. When the HTX message is
recreated in the cache applet, the trailers size is known removing the headers
length and the data lenght from the total object length.
2018-12-11 17:09:31 +01:00
Christopher Faulet 67658c9c9a MINOR: cache: Register the cache as a data filter only if response is cacheable
Instead of calling register_data_filter() when the stream analyze starts, we now
call it when we are sure the response is cacheable. It is done in the
http_headers callback, just before the body analyzis, and only if the headers
was already been cached. And during the body analyzis, if an error occurred or
if the response is too big, we unregistered the cache immediatly.

This patch may be backported in 1.8. It is not a bug but a significant
improvement.
2018-12-11 17:09:31 +01:00
Christopher Faulet 1f672c536d MINOR: cache/htx: Don't use the same cache on HTX and legacy HTTP proxies
It is not possible to mix the format of messages stored in a cache. So we reject
the configurations with a cache used by an HTX proxy and a legacy HTTP proxy in
same time.
2018-12-11 17:09:31 +01:00
Christopher Faulet c9df7f728f MINOR: compression: Rename the function check_legacy_http_comp_flt()
To not mix it up with the legacy HTTP representation, this function has been
rename check_implicit_http_comp_flt().
2018-12-11 17:09:31 +01:00
William Lallemand 459e18e9e7 MINOR: cli: use pcli_flags for prompt activation
Instead of using a variable to activate the prompt, we just use a flag.
2018-12-11 17:05:40 +01:00
William Lallemand ebf61804ef MEDIUM: cli: handle payload in CLI proxy
The CLI proxy was not handling payload. To do that, we needed to keep a
connection active on a server and to transfer each new line over that
connection until we receive a empty line.

The CLI proxy handles the payload in the same way that the CLI do it.

Examples:

   $ echo -e "@1;add map #-1 <<\n$(cat data)\n" | socat /tmp/master-socket -

   $ socat /tmp/master-socket readline
   prompt
   master> @1
   25130> add map #-1 <<
   + test test
   + test2 test2
   + test3 test3
   +

   25130>
2018-12-11 17:05:36 +01:00
William Lallemand 3de09d5c7e BUG/MINOR: cli: wait for payload data even without prompt
During a payload transfer, we need to wait for the data even when we are
not in interactive mode. Indeed, the data could be received line per
line progressively instead of in one recv.

Previously the CLI was doing a SHUTW just after the first line if it was
not in interactive mode. We now check if we are in payload mode to do
a SHUTW.

Should be backported in 1.8.
2018-12-11 16:54:18 +01:00
William Lallemand 5f61068dbd MINOR: cli: implements 'quit' in the CLI proxy
Implements the 'quit' command. Works the same way as the CLI command.
2018-12-11 16:54:18 +01:00
William Lallemand 5b80fa2864 MINOR: cli: parse prompt command in the CLI proxy
Handle the prompt command. Works the same way as the CLI.
2018-12-11 16:54:18 +01:00
William Lallemand bddd33af0b MEDIUM: cli: rework the CLI proxy parser
Rework the CLI proxy parser to look more like the CLI parser, corner
case and escaping are handled the same way.

The parser now splits the commands in words instead of just handling
the prefixes.

It's easier to compare words and arguments of a command this way and to
parse internal command that will be consumed directly by the CLI proxy.
2018-12-11 16:54:18 +01:00
Willy Tarreau 1a18b54142 REORG: connection: centralize the conn_set_{tos,mark,quickack} functions
There were a number of ugly setsockopt() calls spread all over
proto_http.c, proto_htx.c and hlua.c just to manipulate the front
connection's TOS, mark or TCP quick-ack. These ones entirely relied
on the connection, its existence, its control layer's presence, and
its addresses. Worse, inet_set_tos() was placed in proto_http.c,
exported and used from the two other ones, surrounded in #ifdefs.

This patch moves this code to connection.h and makes the other ones
rely on it without ifdefs.
2018-12-11 16:41:51 +01:00
Willy Tarreau 64225e1f88 REGTEST: add the HTTP rules test involving HTX processing
It's the exact same test as the HTTP rules test except that it runs
with HTX enabled.
2018-12-11 09:14:59 +01:00
Willy Tarreau 907998194b MEDIUM: mux-h2: make use of hpack_encode_path() to encode the path
The HTTP path encoding was open-coded with a HPACK byte matching the
"/" or "/index.html" paths. Let's make use of the new functions to
avoid this.
2018-12-11 09:07:02 +01:00
Willy Tarreau eaeeb68f23 MINOR: hpack: provide a function to encode an HTTP path
The new function hpack_encode_path() supports encoding a path into
the ":path" header. It knows about "/" and "/index.html" which use
a single byte, and falls back to literal encoding for other ones,
with a fast path for short paths < 127 bytes.
2018-12-11 09:07:02 +01:00
Willy Tarreau 7561bcbb36 MEDIUM: mux-h2: make use of hpack_encode_scheme() to encode the scheme
The HTTP scheme encoding was open-coded with a HPACK byte matching the
"https" scheme. Let's make use of the new functions to avoid this.
2018-12-11 09:07:02 +01:00
Willy Tarreau 820b391260 MINOR: hpack: provide a function to encode an HTTP scheme
The new function hpack_encode_scheme() supports encoding a scheme
into the ":scheme" header. It knows about "https" and "http" which use
a single byte, and falls back to literal encoding for other ones.
2018-12-11 09:07:02 +01:00
Willy Tarreau bdabc3a25f MEDIUM: mux-h2: make use of hpack_encode_method() to encode the method
The HTTP method encoding was open-coded with raw HPACK bytes, which is
not suitable there. Let's make use of the new functions to avoid this.
2018-12-11 09:07:02 +01:00
Willy Tarreau 39c80ebff0 MINOR: hpack: provide a function to encode an HTTP method
The new function hpack_encode_method() supports encoding a method.
It knows about GET and POST which use a single byte, and falls back
to literal encoding for other ones.
2018-12-11 09:07:02 +01:00
Willy Tarreau aafdf58333 MEDIUM: mux-h2: make use of standard HPACK encoding functions for the status
This way we don't open-code the HPACK status codes anymore in the H2
code. Special care was taken not to cause any slowdown as this code is
very sensitive.
2018-12-11 09:07:02 +01:00
Willy Tarreau 8895367fb1 MINOR: hpack: provide new functions to encode the ":status" header
This header exists with 7 different values, it's worth taking them
into account for the encoding, hence these functions. One of them
makes use of an integer only and computes the 3 output bytes in case
of literal. The other one benefits from the knowledge of an existing
string, which for example exists in the case of H1 to H2 encoding.
2018-12-11 09:07:02 +01:00
Willy Tarreau bd5659bbe1 MINOR: hpack: provide a function to encode a long indexed header
For long header values whose index is known, hpack_encodde_long_idx()
may now be used. This function emits the short index and follows with
the header's value.
2018-12-11 09:07:01 +01:00
Willy Tarreau 30eb809fdb MINOR: hpack: provide a function to encode a short indexed header
Most direct calls to HPACK functions are made to encode short header
fields like methods, schemes or statuses, whose lengths and indexes
are known. Let's have a small function to do this.
2018-12-11 09:06:46 +01:00
Willy Tarreau bad0a381d3 MINOR: hpack: move the length computation and encoding functions to .h
We'll need these functions from other inline functions, let's make them
accessible. len_to_bytes() was renamed to hpack_len_to_bytes() since it's
now exposed.
2018-12-11 09:06:46 +01:00