Commit graph

7733 commits

Author SHA1 Message Date
Sergey Kandaurov
0d8ddc57e8 QUIC: ngx_quic_send_alert() callback moved to its place. 2021-11-30 14:30:59 +03:00
Sergey Kandaurov
a9546f2161 QUIC: simplified ngx_quic_send_alert() callback.
Removed sending CLOSE_CONNECTION directly to avoid duplicate frames,
since it is sent later again in SSL_do_handshake() error handling.
As such, removed redundant settings of error fields set elsewhere.
While here, improved debug message.
2021-11-30 14:30:59 +03:00
Vladimir Homutov
5ddebcaaff QUIC: removed unnecessary closing of active/backup sockets.
All open sockets are stored in a queue.  There is no need to close some
of them separately.  If it happens that active and backup point to same
socket, double close may happen (leading to possible segfault).
2021-11-18 14:33:21 +03:00
Vladimir Homutov
70907fdbe0 QUIC: fixed migration during NAT rebinding.
The RFC 9000 allows a packet from known CID arrive from unknown path:

    These requirements regarding connection ID reuse apply only to the
    sending of packets, as unintentional changes in path without a change
    in connection ID are possible.  For example, after a period of
    network inactivity, NAT rebinding might cause packets to be sent on a
    new path when the client resumes sending.

Before the patch, such packets were rejected with an error in the
ngx_quic_check_migration() function.  Removing the check makes the
separate function excessive - remaining checks are early migration
check and "disable_active_migration" check.  The latter is a transport
parameter sent to client and it should not be used by server.

The server should send "disable_active_migration" "if the endpoint does
not support active connection migration" (18.2). The support status depends
on nginx configuration: to have migration working with multiple workers,
you need bpf helper, available on recent Linux systems.  The patch does
not set "disable_active_migration" automatically and leaves it for the
administrator. By default, active migration is enabled.

RFC 900 says that it is ok to migrate if the peer violates
"disable_active_migration" flag requirements:

   If the peer violates this requirement,

   the endpoint MUST either drop the incoming packets on that path without
   generating a Stateless Reset

   OR

   proceed with path validation and allow the peer to migrate.  Generating a
   Stateless Reset or closing the connection would allow third parties in the
   network to cause connections to close by spoofing or otherwise manipulating
   observed traffic.

So, nginx adheres to the second option and proceeds to path validation.


Note:

The ngtcp2 may be used for testing both active migration and NAT rebinding:

ngtcp2/client --change-local-addr=200ms --delay-stream=500ms <ip> <port> <url>

ngtcp2/client --change-local-addr=200ms --delay-stream=500ms --nat-rebinding \
              <ip> <port> <url>
2021-11-29 11:51:14 +03:00
Vladimir Homutov
1c29db5dba QUIC: refactored multiple QUIC packets handling.
Single UDP datagram may contain multiple QUIC datagrams.  In order to
facilitate handling of such cases, 'first' flag in the ngx_quic_header_t
structure is introduced.
2021-11-29 11:49:09 +03:00
Vladimir Homutov
2730e38d8b QUIC: fixed handling of RETIRE_CONNECTION_ID frame.
Previously, the retired socket was not closed if it didn't match
active or backup.

New sockets could not be created (due to count limit), since retired socket
was not closed before calling ngx_quic_create_sockets().

When replacing retired socket, new socket is only requested after closing
old one, to avoid hitting the limit on the number of active connection ids.

Together with added restrictions, this fixes an issue when a current socket
could be closed during migration, recreated and erroneously reused leading
to null pointer dereference.
2021-11-18 14:19:36 +03:00
Vladimir Homutov
64488e4e6f QUIC: additional checks for the RETIRE_CONNECTION_ID frame. 2021-11-18 14:19:31 +03:00
Roman Arutyunyan
52021bf4a0 QUIC: handle DATA_BLOCKED frame from client.
Previously the frame was not handled and connection was closed with an error.
Now, after receiving this frame, global flow control is updated and new
flow control credit is sent to client.
2021-11-17 23:07:51 +03:00
Roman Arutyunyan
75c17858cc QUIC: update stream flow control credit on STREAM_DATA_BLOCKED.
Previously, after receiving STREAM_DATA_BLOCKED, current flow control limit
was sent to client.  Now, if the limit can be updated to the full window size,
it is updated and the new value is sent to client, otherwise nothing is sent.

The change lets client update flow control credit on demand.  Also, it saves
traffic by not sending MAX_STREAM_DATA with the same value twice.
2021-11-17 23:07:38 +03:00
Roman Arutyunyan
7bd866a9a5 HTTP/3: fixed compilation with QUIC, but without HTTP/3. 2021-11-17 18:49:48 +03:00
Roman Arutyunyan
07a983f8df QUIC: reject streams which we could not create.
The reasons why a stream may not be created by server currently include hitting
worker_connections limit and memory allocation error.  Previously in these
cases the entire QUIC connection was closed and all its streams were shut down.
Now the new stream is rejected and existing streams continue working.

To reject an HTTP/3 request stream, RESET_STREAM and STOP_SENDING with
H3_REQUEST_REJECTED error code are sent to client.  HTTP/3 uni streams and
Stream streams are not rejected.
2021-11-11 19:07:00 +03:00
Sergey Kandaurov
8d62635537 QUIC: stop processing new client streams at the closing state. 2021-11-12 16:29:07 +03:00
Roman Arutyunyan
56bbbf72d0 HTTP/3: send Stream Cancellation instruction.
As per quic-qpack-21:

   When a stream is reset or reading is abandoned, the decoder emits a
   Stream Cancellation instruction.

Previously the instruction was not sent.  Now it's sent when closing QUIC
stream connection if dynamic table capacity is non-zero and eof was not
received from client.  The latter condition means that a trailers section
may still be on its way from client and the stream needs to be cancelled.
2021-10-18 14:48:11 +03:00
Roman Arutyunyan
f72a2bb3f6 HTTP/3: allowed QUIC stream connection reuse.
A QUIC stream connection is treated as reusable until first bytes of request
arrive, which is also when the request object is now allocated.  A connection
closed as a result of draining, is reset with the error code
H3_REQUEST_REJECTED.  Such behavior is allowed by quic-http-34:

   Once a request stream has been opened, the request MAY be cancelled
   by either endpoint. Clients cancel requests if the response is no
   longer of interest; servers cancel requests if they are unable to or
   choose not to respond.

   When the server cancels a request without performing any application
   processing, the request is considered "rejected."  The server SHOULD
   abort its response stream with the error code H3_REQUEST_REJECTED.

   The client can treat requests rejected by the server as though they had
   never been sent at all, thereby allowing them to be retried later.
2021-10-18 15:47:06 +03:00
Roman Arutyunyan
261439aed2 HTTP/3: adjusted QUIC connection finalization.
When an HTTP/3 function returns an error in context of a QUIC stream, it's
this function's responsibility now to finalize the entire QUIC connection
with the right code, if required.  Previously, QUIC connection finalization
could be done both outside and inside such functions.  The new rule follows
a similar rule for logging, leads to cleaner code, and allows to provide more
details about the error.

While here, a few error cases are no longer treated as fatal and QUIC connection
is no longer finalized in these cases.  A few other cases now lead to
stream reset instead of connection finalization.
2021-10-18 15:22:33 +03:00
Vladimir Homutov
a6eadf8dc0 QUIC: fixed PATH_RESPONSE frame expansion.
The PATH_RESPONSE frame must be expanded to 1200, except the case
when anti-amplification limit is in effect, i.e. on unvalidated paths.

Previously, the anti-amplification limit was always applied.
2021-11-11 15:15:07 +03:00
Vladimir Homutov
f5c17cf3b7 QUIC: removed ngx_quic_error_text() declaration.
This is a leftover from cab3b7a070ef.
2021-11-10 14:36:36 +03:00
Vladimir Homutov
d7aaf8eb18 QUIC: fixed GSO packets count.
Thanks to Andrey Kolyshkin <a.kolyshkin@corp.vk.com>
2021-11-09 21:17:05 +03:00
Vladimir Homutov
ce10c373e8 QUIC: removed dead code.
The function is no longer used since b3d9e57d0f62.
2021-11-10 13:49:01 +03:00
Vladimir Homutov
9a035adb05 QUIC: converted client_tp_done to bitfield. 2021-11-08 15:41:12 +03:00
Vladimir Homutov
f765b64594 QUIC: fixed removal of unused client IDs.
If client ID was never used, its refcount is zero.  To keep things simple,
the ngx_quic_unref_client_id() function is now aware of such IDs.

If client ID was used, the ngx_quic_replace_retired_client_id() function
is supposed to find all users and unref the ID, thus ngx_quic_unref_client_id()
should not be called after it.
2021-10-13 14:48:33 +03:00
Vladimir Homutov
e945e92ece QUIC: connections with wrong ALPN protocols are now rejected.
Previously, it was not enforced in the stream module.
Now, since b9e02e9b2f1d it is possible to specify protocols.

Since ALPN is always required, the 'require_alpn' setting is now obsolete.
2021-11-03 13:36:21 +03:00
Vladimir Homutov
6c1a6d7bb3 QUIC: refactored packet creation.
The "min" and "max" arguments refer to UDP datagram size.  Generating payload
requires to account properly for header size, which is variable and depends on
payload size and packet number.
2021-10-07 13:48:29 +03:00
Vladimir Homutov
273b23d5a7 QUIC: removed unused argument in ngx_quic_create_short_header(). 2021-10-07 12:24:47 +03:00
Vladimir Homutov
c13ab56118 QUIC: added function to initialize packet. 2021-09-30 12:02:29 +03:00
Vladimir Homutov
2e001d8708 QUIC: fixed processing of minimum packet size.
If packet needs to be expanded (for example Initial to 1200 bytes),
but path limit is less, such packet should not be created/sent.
2021-10-22 12:59:44 +03:00
Vladimir Homutov
9ff755cd7c QUIC: added shutdown support in stream proxy. 2021-09-23 16:25:49 +03:00
Sergey Kandaurov
965f51cde3 Merged with the default branch. 2021-11-03 11:22:07 +03:00
Maxim Dounin
a1459645ce release-1.21.4 tag 2021-11-02 17:49:22 +03:00
Maxim Dounin
65d47e2d65 nginx-1.21.4-RELEASE 2021-11-02 17:49:22 +03:00
Maxim Dounin
d828e18761 Changed ngx_chain_update_chains() to test tag first (ticket #2248).
Without this change, aio used with HTTP/2 can result in connection hang,
as observed with "aio threads; aio_write on;" and proxying (ticket #2248).

The problem is that HTTP/2 updates buffers outside of the output filters
(notably, marks them as sent), and then posts a write event to call
output filters.  If a filter does not call the next one for some reason
(for example, because of an AIO operation in progress), this might
result in a state when the owner of a buffer already called
ngx_chain_update_chains() and can reuse the buffer, while the same buffer
is still sitting in the busy chain of some other filter.

In the particular case a buffer was sitting in output chain's ctx->busy,
and was reused by event pipe.  Output chain's ctx->busy was permanently
blocked by it, and this resulted in connection hang.

Fix is to change ngx_chain_update_chains() to skip buffers from other
modules unconditionally, without trying to wait for these buffers to
become empty.
2021-10-30 02:39:19 +03:00
Maxim Dounin
a1593eb4d6 Changed default value of sendfile_max_chunk to 2m.
The "sendfile_max_chunk" directive is important to prevent worker
monopolization by fast connections.  The 2m value implies maximum 200ms
delay with 100 Mbps links, 20ms delay with 1 Gbps links, and 2ms on
10 Gbps links.  It also seems to be a good value for disks.
2021-10-29 20:21:57 +03:00
Maxim Dounin
79ea33d679 Upstream: sendfile_max_chunk support.
Previously, connections to upstream servers used sendfile() if it was
enabled, but never honored sendfile_max_chunk.  This might result
in worker monopolization for a long time if large request bodies
are allowed.
2021-10-29 20:21:54 +03:00
Maxim Dounin
f9fcb63842 Fixed sendfile() limit handling on Linux.
On Linux starting with 2.6.16, sendfile() silently limits all operations
to MAX_RW_COUNT, defined as (INT_MAX & PAGE_MASK).  This incorrectly
triggered the interrupt check, and resulted in 0-sized writev() on the
next loop iteration.

Fix is to make sure the limit is always checked, so we will return from
the loop if the limit is already reached even if number of bytes sent is
not exactly equal to the number of bytes we've tried to send.
2021-10-29 20:21:51 +03:00
Maxim Dounin
7ce5186ee0 Simplified sendfile_max_chunk handling.
Previously, it was checked that sendfile_max_chunk was enabled and
almost whole sendfile_max_chunk was sent (see e67ef50c3176), to avoid
delaying connections where sendfile_max_chunk wasn't reached (for example,
when sending responses smaller than sendfile_max_chunk).  Now we instead
check if there are unsent data, and the connection is still ready for writing.
Additionally we also check c->write->delayed to ignore connections already
delayed by limit_rate.

This approach is believed to be more robust, and correctly handles
not only sendfile_max_chunk, but also internal limits of c->send_chain(),
such as sendfile() maximum supported length (ticket #1870).
2021-10-29 20:21:48 +03:00
Maxim Dounin
417cfe8951 Switched to using posted next events after sendfile_max_chunk.
Previously, 1 millisecond delay was used instead.  In certain edge cases
this might result in noticeable performance degradation though, notably on
Linux with typical CONFIG_HZ=250 (so 1ms delay becomes 4ms),
sendfile_max_chunk 2m, and link speed above 2.5 Gbps.

Using posted next events removes the artificial delay and makes processing
fast in all cases.
2021-10-29 20:21:43 +03:00
Roman Arutyunyan
2e7c8460a8 Mp4: mp4_start_key_frame directive.
The directive enables including all frames from start time to the most recent
key frame in the result.  Those frames are removed from presentation timeline
using mp4 edit lists.

Edit lists are currently supported by popular players and browsers such as
Chrome, Safari, QuickTime and ffmpeg.  Among those not supporting them properly
is Firefox[1].

Based on a patch by Tracey Jaquith, Internet Archive.

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=1735300
2021-10-28 14:14:25 +03:00
Roman Arutyunyan
65dd05879e Mp4: added ngx_http_mp4_update_mdhd_atom() function.
The function updates the duration field of mdhd atom.  Previously it was
updated in ngx_http_mp4_read_mdhd_atom().  The change makes it possible to
alter track duration as a result of processing track frames.
2021-10-28 13:11:31 +03:00
Sergey Kandaurov
69805192b4 QUIC: style. 2021-10-26 18:05:57 +03:00
Sergey Kandaurov
369804cacb QUIC: speeding up processing 0-RTT.
After fe919fd63b0b, processing QUIC streams was postponed until after handshake
completion, which means that 0-RTT is effectively off.  With ssl_ocsp enabled,
it could be further delayed.  This differs from how OCSP validation works with
SSL_read_early_data().  With this change, processing QUIC streams is unlocked
when obtaining 0-RTT secret.
2021-10-26 17:43:10 +03:00
Sergey Kandaurov
63aa8908c5 QUIC: refactored OCSP validation in preparation for 0-RTT support. 2021-10-26 17:43:10 +03:00
Vladimir Homutov
d5e61b4c8c QUIC: switched to integer arithmetic in rtt calculations.
RFC 9002 uses constants implying effective implementation,
i.e. using bit shift operations instead of floating point.
2021-10-19 14:32:50 +03:00
Vladimir Homutov
a07e6d352e QUIC: optimized ack range processing.
The sent queue is sorted by packet number.  It is possible to avoid
traversing full queue while handling ack ranges.  It makes sense to
start traversing from the queue head (i.e. check oldest packets first).
2021-10-15 12:26:42 +03:00
Roman Arutyunyan
b35afd4e4a QUIC: limited the total number of frames.
Exceeding 10000 allocated frames is considered a flood.
2021-10-13 14:46:51 +03:00
Roman Arutyunyan
49b5584de3 QUIC: traffic-based flood detection.
With this patch, all traffic over a QUIC connection is compared to traffic
over QUIC streams.  As long as total traffic is many times larger than stream
traffic, we consider this to be a flood.
2021-10-13 14:41:46 +03:00
Roman Arutyunyan
6fe2069e12 HTTP/3: traffic-based flood detection.
With this patch, all traffic over HTTP/3 bidi and uni streams is counted in
the h3c->total_bytes field, and payload traffic is counted in the
h3c->payload_bytes field.  As long as total traffic is many times larger than
payload traffic, we consider this to be a flood.

Request header traffic is counted as if all fields are literal.  Response
header traffic is counted as is.
2021-10-07 13:22:42 +03:00
Roman Arutyunyan
334d204baf HTTP/3: fixed request length calculation.
Previously, when request was blocked, r->request_length was not updated.
2021-10-06 14:51:16 +03:00
Roman Arutyunyan
513f850061 HTTP/3: removed client-side encoder support.
Dynamic tables are not used when generating responses anyway.
2021-10-06 14:48:59 +03:00
Martin Duke
d3f0dd0321 QUIC: attempt decrypt before checking for stateless reset.
Checking the reset after encryption avoids false positives.  More importantly,
it avoids the check entirely in the usual case where decryption succeeds.

RFC 9000, 10.3.1  Detecting a Stateless Reset

    Endpoints MAY skip this check if any packet from a datagram is
    successfully processed.
2021-10-12 11:57:50 +03:00
Martin Duke
1f523e0d47 QUIC: Check if CID has been used in stateless reset check
Section 10.3.1 of RFC9000 requires this check.
2021-10-12 11:56:49 +03:00