Commit Graph

7305 Commits

Author SHA1 Message Date
Sergey Kandaurov
7bd3868715 QUIC: speeding up handshake completion.
As per quic-recovery draft, section-6.2.3: resend CRYPTO frames
when receiving an Initial packet containing duplicate CRYPTO data.
2020-10-01 12:10:22 +01:00
Sergey Kandaurov
b64446f6f9 QUIC: fixed clang-ast asserts. 2020-10-01 12:09:47 +01:00
Sergey Kandaurov
154536a64f QUIC: fixed build with OpenSSL after bed310672f39. 2020-10-01 12:00:12 +01:00
Vladimir Homutov
0f843cfb74 QUIC: moved ssl configuration pointer to quic configuration.
The ssl configuration is obtained at config time and saved for future use.
2020-10-01 10:04:35 +03:00
Vladimir Homutov
f797a8a5b5 QUIC: added stateless reset support.
The new "quic_stateless_reset_token_key" directive is added.  It sets the
endpoint key used to generate stateless reset tokens and enables feature.

If the endpoint receives short-header packet that can't be matched to
existing  connection, a stateless reset packet is generated with
a proper token.

If a valid stateless reset token is found in the incoming packet,
the connection is closed.

Example configuration:

http {
    quic_stateless_reset_token_key  "foo";
    ...
}
2020-09-30 20:54:46 +03:00
Vladimir Homutov
2c3ada5722 QUIC: refined the "c->quic->initialized" flag usage.
The flag is tied to the initial secret creation.  The presence of c->quic
pointer is sufficient to enable execution of ngx_quic_close_quic().

The ngx_quic_new_connection() function now returns the allocated quic
connection object and the c->quic pointer is set by the caller.

If an early error occurs before secrets initialization (i.e. in cases
of invalid retry token or nginx exiting), it is still possible to
generate an error response by trying to initialize secrets directly
in the ngx_quic_send_cc() function.

Before the change such early errors failed to send proper connection close
message and logged an error.

An auxilliary ngx_quic_init_secrets() function is introduced to avoid
verbose call to ngx_quic_set_initial_secret() requiring local variable.
2020-09-30 21:27:52 +03:00
Vladimir Homutov
99d4f2399d QUIC: packet processing refactoring.
All packet header parsing is now performed by ngx_quic_parse_packet()
function, located in the ngx_quic_transport.c file.

The packet processing is centralized in the ngx_quic_process_packet()
function which decides if the packet should be accepted, ignored or
connection should be closed, depending on the connection state.

As a result of refactoring, behavior has changed in some places:

 - minimal size of Initial packet is now always tested
 - connection IDs are always tested in existing connections
 - old keys are discarded on encryption level switch
2020-09-30 15:14:09 +03:00
Vladimir Homutov
fe626bda84 QUIC: simplified packet header parsing.
Now flags are processed in ngx_quic_input(), and raw->pos points to the first
byte after the flags. Redundant checks from ngx_quic_parse_short_header() and
ngx_quic_parse_long_header() are removed.
2020-09-25 21:47:28 +03:00
Roman Arutyunyan
80958b29a2 QUIC: keep the entire packet size in pkt->len.
Previously pkt->len kept the length of the packet remainder starting from
pkt->raw->pos.
2020-09-25 21:46:55 +03:00
Vladimir Homutov
6c0be4b4cf QUIC: switched to using fixed-length server connection IDs. 2020-09-18 15:53:37 +03:00
Roman Arutyunyan
469f69bf2c QUIC: resend frames by moving them to output queue.
Previously, when a packet was declared lost, another packet was sent with the
same frames.  Now lost frames are moved to the output frame queue and push
event is posted.  This has the advantage of forming packets with more frames
than before.

Also, the start argument is removed from the ngx_quic_resend_frames()
function as excess information.
2020-09-30 20:23:16 +01:00
Roman Arutyunyan
1f90fccd97 QUIC: switch stream context to a server selected by SNI.
Previously the default server configuration context was used until the
:authority or host header was parsed.  This led to using the configuration
parameters like client_header_buffer_size or request_pool_size from the default
server rather than from the server selected by SNI.

Also, the switch to the right server log is implemented.  This issue manifested
itself as QUIC stream being logged to the default server log until :authority
or host is parsed.
2020-09-29 22:09:09 +01:00
Sergey Kandaurov
0824d61fc9 QUIC: unbreak client certificate verification after 0d2b2664b41c.
Initially, client certificate verification didn't work due to the missing
hc->ssl on a QUIC stream, which is started to be set in 7738:7f0981be07c4.
Then it was lost in 7999:0d2b2664b41c introducing "quic" listen parameter.

This change re-adds hc->ssl back for all QUIC connections, similar to SSL.
2020-09-23 13:13:04 +01:00
Vladimir Homutov
766fc16f55 QUIC: prevented posted push event while in the draining state.
If the push event was posted before ngx_quic_close_connection(), it could send
data in the draining state.
2020-09-21 13:58:17 +03:00
Roman Arutyunyan
be719bbec8 HTTP/3: rearranged length check when parsing header.
The new code looks simpler and is similar to other checks.
2020-09-16 20:21:03 +01:00
Roman Arutyunyan
ebbcc329cb HTTP/3: removed HTTP/3 parser call from discard body filter.
Request body discard is disabled for QUIC streams anyway.
2020-09-16 19:48:33 +01:00
Roman Arutyunyan
9fff3b7516 HTTP/3: reject HTTP/2 frames.
As per HTTP/3 draft 30, section 7.2.8:

   Frame types that were used in HTTP/2 where there is no corresponding
   HTTP/3 frame have also been reserved (Section 11.2.1).  These frame
   types MUST NOT be sent, and their receipt MUST be treated as a
   connection error of type H3_FRAME_UNEXPECTED.
2020-09-16 12:27:23 +01:00
Pavel Pautov
c85d6fec21 Stream: set module.
Adds 'set' directive to the stream server context.
2020-08-28 14:10:54 -07:00
Sergey Kandaurov
3bbeb1b8de SSL: abort handshake on SSL_set_SSL_CTX() errors.
In rare cases, such as memory allocation failure, SSL_set_SSL_CTX() returns
NULL, which could mean that a different SSL configuration has not been set.
Note that this new behaviour seemingly originated in OpenSSL-1.1.0 release.
2020-09-24 13:51:29 +01:00
Maxim Dounin
6c89d752c8 HTTP/2: run posted requests after reading body.
HTTP/2 code failed to run posted requests after calling the request body
handler, and this resulted in connection hang if a subrequest was created
in the body handler and no other actions were made.
2020-09-23 19:52:31 +03:00
Maxim Dounin
7c67ff7363 HTTP/2: fixed segfault on DATA frames after 400 errors.
If 400 errors were redirected to an upstream server using the error_page
directive, DATA frames from the client might cause segmentation fault
due to null pointer dereference.  The bug had appeared in 6989:2c4dbcd6f2e4
(1.13.0).

Fix is to skip such frames in ngx_http_v2_state_read_data() (similarly
to 7561:9f1f9d6e056a).  With the fix, behaviour of 400 errors in HTTP/2
is now similar to one in HTTP/1.x, that is, nginx doesn't try to read the
request body.

Note that proxying 400 errors, as well as other early stage errors, to
upstream servers might not be a good idea anyway.  These errors imply
that reading and processing of the request (and the request headers)
wasn't complete, and proxying of such incomplete request might lead to
various errors.

Reported by Chenglong Zhang.
2020-09-23 19:50:49 +03:00
Maxim Dounin
e9a8612c13 SSL: disabled shutdown when there are buffered data.
This fixes "SSL_shutdown() failed (SSL: ... bad write retry)" errors
as observed on the second SSL_shutdown() call after SSL shutdown fixes in
09fb2135a589 (1.19.2), notably when HTTP/2 connections are closed due
to read timeouts while there are incomplete writes.
2020-09-16 18:26:25 +03:00
Maxim Dounin
f6c28f93af SSL: disabled shutdown after connection errors.
This fixes "SSL_shutdown() failed (SSL: ... bad write retry)" errors
as observed on the second SSL_shutdown() call after SSL shutdown fixes in
09fb2135a589 (1.19.2), notably when sending fails in ngx_http_test_expect(),
similarly to ticket #1194.

Note that there are some places where c->error is misused to prevent
further output, such as ngx_http_v2_finalize_connection() if there
are pending streams, or in filter finalization.  These places seem
to be extreme enough to don't care about missing shutdown though.
For example, filter finalization currently prevents keepalive from
being used.
2020-09-16 18:26:24 +03:00
Maxim Dounin
a1864c2586 SSL: fixed event handling during shutdown.
The c->read->ready and c->write->ready flags need to be cleared to ensure
that appropriate read or write events will be reported by kernel.  Without
this, SSL shutdown might wait till the timeout after blocking on writing
or reading even if there is a socket activity.
2020-09-16 18:26:23 +03:00
Maxim Dounin
82cf625ab5 SSL: workaround for incorrect SSL_write() errors in OpenSSL 1.1.1.
OpenSSL 1.1.1 fails to return SSL_ERROR_SYSCALL if an error happens
during SSL_write() after close_notify alert from the peer, and returns
SSL_ERROR_ZERO_RETURN instead.  Broken by this commit, which removes
the "i == 0" check around the SSL_RECEIVED_SHUTDOWN one:

https://git.openssl.org/?p=openssl.git;a=commitdiff;h=8051ab2

In particular, if a client closed the connection without reading
the response but with properly sent close_notify alert, this resulted in
unexpected "SSL_write() failed while ..." critical log message instead
of correct "SSL_write() failed (32: Broken pipe)" at the info level.

Since SSL_ERROR_ZERO_RETURN cannot be legitimately returned after
SSL_write(), the fix is to convert all SSL_ERROR_ZERO_RETURN errors
after SSL_write() to SSL_ERROR_SYSCALL.
2020-09-16 18:26:22 +03:00
Sergey Kandaurov
dc1b14126e Cache: keep c->body_start when Vary changes (ticket #2029).
If the variant hash doesn't match one we used as a secondary cache key,
we switch back to the original key.  In this case, c->body_start was kept
updated from an existing cache node overwriting the new response value.
After file cache update, it led to discrepancy between a cache node and
cache file seen as critical errors "file cache .. has too long header".
2020-09-09 19:26:27 +03:00
Roman Arutyunyan
d294369915 HTTP/3: skip unknown frames on request stream.
As per HTTP/3 draft 29, section 4.1:

   Frames of unknown types (Section 9), including reserved frames
   (Section 7.2.8) MAY be sent on a request or push stream before,
   after, or interleaved with other frames described in this section.

Also, trailers frame is now used as an indication of the request body end.
2020-08-24 09:56:36 +03:00
Roman Arutyunyan
46173bd4b4 HTTP/3: fixed handling request body eof.
While for HTTP/1 unexpected eof always means an error, for HTTP/3 an eof right
after a DATA frame end means the end of the request body.  For this reason,
since adding HTTP/3 support, eof no longer produced an error right after recv()
but was passed to filters which would make a decision.  This decision was made
in ngx_http_parse_chunked() and ngx_http_v3_parse_request_body() based on the
b->last_buf flag.

Now that since 0f7f1a509113 (1.19.2) rb->chunked->length is a lower threshold
for the expected number of bytes, it can be set to zero to indicate that more
bytes may or may not follow.  Now it's possible to move the check for eof from
parser functions to ngx_http_request_body_chunked_filter() and clean up the
parsing code.

Also, in the default branch, in case of eof, the following three things
happened, which were replaced with returning NGX_ERROR while implementing
HTTP/3:

- "client prematurely closed connection" message was logged
- c->error flag was set
- NGX_HTTP_BAD_REQUEST was returned

The change brings back this behavior for HTTP/1 as well as HTTP/3.
2020-09-16 18:59:25 +01:00
Vladimir Homutov
0bc772d1fb QUIC: switched to draft 29 by default. 2020-09-11 10:56:05 +03:00
Roman Arutyunyan
2e24e3811b QUIC: allowed old DCID for initial packets until first ACK.
If a packet sent in response to an initial client packet was lost, then
successive client initial packets were dropped by nginx with the unexpected
dcid message logged.  This was because the new DCID generated by the server was
not available to the client.
2020-09-09 16:35:29 +03:00
Roman Arutyunyan
f3bed9cd67 QUIC: eliminated idle timeout restart for dropped packets. 2020-09-08 15:54:02 +03:00
Sergey Kandaurov
786a74e34e QUIC: removed check for packet size beyond MAX_UDP_PAYLOAD_SIZE.
The check tested the total size of a packet header and unprotected packet
payload, which doesn't include the packet number length and expansion of
the packet protection AEAD.  If the packet was corrupted, it could cause
false triggering of the condition due to unsigned type underflow leading
to a connection error.

Existing checks for the QUIC header and protected packet payload lengths
should be enough.
2020-09-08 13:35:50 +03:00
Sergey Kandaurov
d8360f912a QUIC: check that the packet length is of at least sample size.
From quic-tls draft, section 5.4.2:
   An endpoint MUST discard packets that are not long enough to contain
   a complete sample.

The check includes the Packet Number field assumed to be 4 bytes long.
2020-09-08 13:28:56 +03:00
Sergey Kandaurov
952c6f1989 QUIC: update packet length for short packets too.
During long packet header parsing, pkt->len is updated with the Length
field value that is used to find next coalesced packets in a datagram.
For short packets it still contained the whole QUIC packet size.

This change uniforms packet length handling to always contain the total
length of the packet number and protected packet payload in pkt->len.
2020-09-08 13:27:39 +03:00
Roman Arutyunyan
e43ef3dda9 QUIC: added logging output stream frame offset. 2020-09-07 20:55:36 +03:00
Vladimir Homutov
6f78befe99 QUIC: refactored ngx_quic_retry_input().
The function now returns NGX_DECLINED for packets that need to be ignored
and integrates nicely into ngx_quic_input().
2020-09-04 15:48:53 +03:00
Roman Arutyunyan
6983bc0a37 QUIC: do not send STOP_SENDING after STREAM fin.
Previously STOP_SENDING was sent to client upon stream closure if rev->eof and
rev->error were not set.  This was an indirect indication that no RESET_STREAM
or STREAM fin has arrived.  But it is indeed possible that rev->eof is not set,
but STREAM fin has already been received, just not read out by the application.
In this case sending STOP_SENDING does not make sense and can be misleading for
some clients.
2020-09-06 14:51:23 +03:00
Vladimir Homutov
d6065b2791 QUIC: added support for multiple connection IDs.
The peer may issue additional connection IDs up to the limit defined by
transport parameter "active_connection_id_limit", using NEW_CONNECTION_ID
frames, and retire such IDs using RETIRE_CONNECTION_ID frame.
2020-09-03 13:11:27 +03:00
Vladimir Homutov
c36c54f500 QUIC: style.
Moved processing of RETIRE_CONNECTION_ID right after the NEW_CONNECTION_ID.
2020-08-27 10:15:37 +03:00
Vladimir Homutov
fb54f2acd9 QUIC: pass return code from ngx_quic_decrypt() to the caller.
It is required to distinguish internal errors from corrupted packets and
perform actions accordingly: drop the packet or close the connection.

While there, made processing of ngx_quic_decrypt() erorrs similar and
removed couple of protocol violation errors.
2020-09-02 22:34:15 +03:00
Vladimir Homutov
ff4cfa80e5 QUIC: discard unrecognized long packes.
While there, updated comment about discarded packets.
2020-09-02 09:54:15 +03:00
Roman Arutyunyan
e443b1244f HTTP/3: do not set the never-indexed literal bit by default.
The "Literal Header Field Never Indexed" header field representation is not
used in HTTP/2, and it makes little sense to make a distinction in HTTP/3.
2020-08-31 18:42:26 +03:00
Vladimir Homutov
d73a289c43 QUIC: discard incorrect packets instead of closing the connection.
quic-transport

5.2:
    Packets that are matched to an existing connection are discarded if
    the packets are inconsistent with the state of that connection.

5.2.2:
   Servers MUST drop incoming packets under all other circumstances.
2020-09-01 17:20:42 +03:00
Roman Arutyunyan
2087359675 QUIC: do not update largest packet number from a bad packet.
The removal of QUIC packet protection depends on the largest packet number
received.  When a garbage packet was received, the decoder still updated the
largest packet number from that packet.  This could affect removing protection
from subsequent QUIC packets.
2020-09-01 15:21:49 +03:00
Roman Arutyunyan
6f0e1bc14f QUIC: handle PATH_CHALLENGE frame.
A PATH_RESPONSE frame with the same data is sent in response.
2020-08-28 12:01:35 +03:00
Roman Arutyunyan
d69471b81b QUIC: enforce flow control on incoming STREAM and CRYPTO frames. 2020-08-25 17:22:57 +03:00
Roman Arutyunyan
693e55a4b2 HTTP/3: drop the unwanted remainder of the request.
As per HTTP/3 draft 29, section 4.1:

   When the server does not need to receive the remainder of the request,
   it MAY abort reading the request stream, send a complete response, and
   cleanly close the sending part of the stream.
2020-08-25 12:45:21 +03:00
Roman Arutyunyan
4e4d0938b9 QUIC: send STOP_SENDING on stream closure.
The frame is sent for a read-enabled stream which has not received a FIN or
RESET_STREAM.
2020-08-25 14:07:26 +03:00
Vladimir Homutov
2cd05e1909 QUIC: updated README.
- version negotiation is implemented
 - quic recovery implementation is greatly improved
2020-08-21 14:55:32 +03:00
Sergey Kandaurov
e153f4993c QUIC: disabled bidirectional SSL shutdown after 09fb2135a589.
On QUIC connections, SSL_shutdown() is used to call the send_alert callback
to send a CONNECTION_CLOSE frame.  The reverse side is handled by other means.
At least BoringSSL doesn't differentiate whether this is a QUIC SSL method,
so waiting for the peer's close_notify alert should be explicitly disabled.
2020-08-21 14:41:42 +03:00