summaryrefslogtreecommitdiffhomepage
path: root/src/event/quic (follow)
AgeCommit message (Collapse)AuthorFilesLines
2025-05-23QUIC: using QUIC API introduced in OpenSSL 3.5.Sergey Kandaurov3-46/+375
Similarly to the QUIC API originated in BoringSSL, this API allows to register custom TLS callbacks for an external QUIC implementation. See the SSL_set_quic_tls_cbs manual page for details. Due to a different approach used in OpenSSL 3.5, handling of CRYPTO frames was streamlined to always write an incoming CRYPTO buffer to the crypto context. Using SSL_provide_quic_data(), this results in transient allocation of chain links and buffers for CRYPTO frames received in order. Testing didn't reveal performance degradation of QUIC handshakes, https://github.com/nginx/nginx/pull/646 provides specific results.
2025-05-23QUIC: better approach for premature handshake completion.Sergey Kandaurov1-1/+1
Using SSL_in_init() to inspect a handshake state was replaced with SSL_is_init_finished(). This represents a more complete fix to the BoringSSL issue addressed in 22671b37e. This provides awareness of the early data handshake state when using OpenSSL 3.5 TLS callbacks in 0-RTT enabled configurations, which, in particular, is used to avoid premature completion of the initial TLS handshake, before required client handshake messages are received. This is a non-functional change when using BoringSSL. It supersedes testing non-positive SSL_do_handshake() results in all supported SSL libraries, hence simplified. In preparation for using OpenSSL 3.5 TLS callbacks.
2025-05-23QUIC: ssl_encryption_level_t abstraction layer.Sergey Kandaurov13-128/+174
Encryption level values are decoupled from ssl_encryption_level_t, which is now limited to BoringSSL QUIC callbacks, with mappings provided. Although the values match, this provides a technically safe approach, in particular, to access protection level sized arrays. In preparation for using OpenSSL 3.5 TLS callbacks.
2025-05-23QUIC: factored out SSL_provide_quic_data() to the helper function.Sergey Kandaurov1-17/+36
It is now called from ngx_quic_handle_crypto_frame(), prior to proceeding with the handshake. With this logic removed, the handshake function is renamed to ngx_quic_handshake() to better match ngx_ssl_handshake().
2025-05-23QUIC: defined SSL API macros in a single place.Sergey Kandaurov4-20/+17
All definitions now set in ngx_event_quic.h, this includes moving NGX_QUIC_OPENSSL_COMPAT from autotests to compile time. Further, to improve code readability, a new NGX_QUIC_QUICTLS_API macro is used for QuicTLS that provides old BoringSSL QUIC API.
2025-05-23QUIC: logging missing mandatory TLS extensions only once.Sergey Kandaurov1-8/+15
Previously, they might be logged on every add_handshake_data callback invocation when using OpenSSL compat layer and processing coalesced handshake messages. Further, the ALPN error message is adjusted to signal the missing extension. Possible reasons were previously narrowed down with ebb6f7d65 changes in the ALPN callback that is invoked earlier in the handshake.
2025-05-23QUIC: reset qc->error to zero again.Sergey Kandaurov2-4/+4
Following the previous change that removed posting a close event in OpenSSL compat layer, now ngx_quic_close_connection() is always called on error path with either NGX_ERROR or qc->error set. This allows to remove a special value -1 served as a missing error, which simplifies the code. Partially reverts d3fb12d77. Also, this improves handling of the draining connection state, which consists of posting a close event with NGX_OK and no qc->error set, where it was previously converted to NGX_QUIC_ERR_INTERNAL_ERROR. Notably, this is rather a cosmetic fix, because drained connections do not send any packets including CONNECTION_CLOSE, and qc->error is not otherwise used.
2025-05-23QUIC: adjusted handling of callback errors.Sergey Kandaurov3-16/+22
Changed handshake callbacks to always return success. This allows to avoid logging SSL_do_handshake() errors with empty or cryptic "internal error" OpenSSL error messages at the inappropriate "crit" log level. Further, connections with failed callbacks are closed now right away when using OpenSSL compat layer. This change supersedes and reverts c37fdcdd1, with the conditions to check callbacks invocation kept to slightly improve code readability of control flow; they are optimized out in the resulting assembly code.
2025-05-23QUIC: logging of SSL library errors.Sergey Kandaurov1-4/+4
Logging level for such errors, which should not normally happen, is changed to NGX_LOG_ALERT, and ngx_log_error() is replaced with ngx_ssl_error() for consistency with the rest of the code.
2025-05-23QUIC: logging level of handshake errors.Sergey Kandaurov1-1/+1
Various errors reported by SSL_do_handshake() are now logged at the "info" or "crit" level, akin to handshakes on regular TCP connections.
2025-05-23QUIC: removed ALPN feature test.Sergey Kandaurov1-8/+2
ALPN support is present in all libraries that have QUIC support, it is safe to compile it unconditionally.
2025-05-23QUIC: removed excessive casts for ngx_ssl_get_connection().Sergey Kandaurov1-6/+6
They were blindly copied from ngx_ssl_info_callback(), where the ngx_ssl_conn_t pointer is passed with const qualifier.
2025-05-23QUIC: removed level field from ngx_quic_compat_record_t.Sergey Kandaurov1-3/+0
It was made unused in d15f8f2 after introducing reusable crypto contexts.
2025-04-29QUIC: do not block ACKs by congestion control.Sergey Kandaurov1-7/+17
Previously, it was not possible to send acknowledgments if the congestion window was limited or temporarily exceeded, such as after sending a large response or MTU probe. If ACKs were not received from the peer for some reason to update the in-flight bytes counter below the congestion window, this might result in a stalled connection. The fix is to send ACKs regardless of congestion control. This meets RFC 9002, Section 7: : Similar to TCP, packets containing only ACK frames do not count : toward bytes in flight and are not congestion controlled. This is a simplified implementation to send ACK frames from the head of the queue. This was made possible after 6f5f17358. Reported in trac ticket #2621 and subsequently by Vladimir Homutov: https://mailman.nginx.org/pipermail/nginx-devel/2025-April/ZKBAWRJVQXSZ2ISG3YJAF3EWMDRDHCMO.html
2025-04-23QUIC: fixed a typo.nandsky1-3/+3
2025-04-17Fixed -Wunterminated-string-initialization with gcc15.Roman Arutyunyan1-5/+7
2025-04-17QUIC: lowered log level for unsupported transport parameters.Roman Arutyunyan1-1/+1
2025-04-15QUIC: dynamic packet threshold.Roman Arutyunyan1-9/+39
RFC 9002, Section 6.1.1 defines packet reordering threshold as 3. Testing shows that such low value leads to spurious packet losses followed by congestion window collapse. The change implements dynamic packet threshold detection based on in-flight packet range. Packet threshold is defined as half the number of in-flight packets, with mininum value of 3. Also, renamed ngx_quic_lost_threshold() to ngx_quic_time_threshold() for better compliance with RFC 9002 terms.
2025-04-15QUIC: optimized connection frame threshold.Roman Arutyunyan3-1/+6
Previosly the threshold was hardcoded at 10000. This value is too low for high BDP networks. For example, if all frames are STREAM frames, and MTU is 1500, the upper limit for congestion window would be roughly 15M (10000 * 1500). With 100ms RTT it's just a 1.2Gbps network (15M * 10 * 8). In reality, the limit is even lower because of other frame types. Also, the number of frames that could be used simultaneously depends on the total amount of data buffered in all server streams, and client flow control. The change sets frame threshold based on max concurrent streams and stream buffer size, the product of which is the maximum number of in-flight stream data in all server streams at any moment. The value is divided by 2000 to account for a typical MTU 1500 and the fact that not all frames are STREAM frames.
2025-04-15QUIC: CUBIC congestion control.Roman Arutyunyan4-12/+185
2025-04-15QUIC: ignore congestion control when sending MTU probes.Roman Arutyunyan1-0/+1
If connection is network-limited, MTU probes have little chance of being sent since congestion window is almost always full. As a result, PMTUD may not be able to reach the real MTU and the connection may operate with a reduced MTU. The solution is to ignore the congestion window. This may lead to a temporary increase in in-flight count beyond congestion window.
2025-04-15QUIC: do not shrink congestion window after losing an MTU probe.Roman Arutyunyan3-0/+10
As per RFC 9000, Section 14.4: Loss of a QUIC packet that is carried in a PMTU probe is therefore not a reliable indication of congestion and SHOULD NOT trigger a congestion control reaction.
2025-04-15QUIC: do not increase underutilized congestion window.Roman Arutyunyan4-1/+37
As per RFC 9002, Section 7.8, congestion window should not be increased when it's underutilized.
2025-04-15QUIC: all-levels commit and revert functions.Roman Arutyunyan1-43/+53
Previously, these functions operated on a per-level basis. This however resulted in excessive logging of in_flight and will also led to extra work detecting underutilized congestion window in the followup patches.
2025-04-15QUIC: ngx_msec_t overflow protection.Roman Arutyunyan1-8/+14
On some systems the value of ngx_current_msec is derived from monotonic clock, for which the following is defined by POSIX: For this clock, the value returned by clock_gettime() represents the amount of time (in seconds and nanoseconds) since an unspecified point in the past. As as result, overflow protection is needed when comparing two ngx_msec_t. The change adds such protection to the ngx_quic_detect_lost() function.
2025-04-15QUIC: prevent spurious congestion control recovery mode.Roman Arutyunyan3-14/+44
Since recovery_start field was initialized with ngx_current_msec, all congestion events that happened within the same millisecond or cycle iteration, were treated as in recovery mode. Also, when handling persistent congestion, initializing recovery_start with ngx_current_msec resulted in treating all sent packets as in recovery mode, which violates RFC 9002, see example in Appendix B.8. While here, also fixed recovery_start wrap protection. Previously it used 2 * max_idle_timeout time frame for all sent frames, which is not a reliable protection since max_idle_timeout is unrelated to congestion control. Now recovery_start <= now condition is enforced. Note that recovery_start wrap is highly unlikely and can only occur on a 32-bit system if there are no congestion events for 24 days.
2025-04-15QUIC: use path MTU in congestion window computations.Roman Arutyunyan3-8/+8
As per RFC 9002, Section B.2, max_datagram_size used in congestion window computations should be based on path MTU.
2025-04-15QUIC: graph-friendly congestion control logging.Roman Arutyunyan1-19/+25
Improved logging for simpler data extraction for plotting congestion window graphs. In particular, added current milliseconds number from ngx_current_msec. While here, simplified logging text and removed irrelevant data.
2025-01-28QUIC: added missing casts in iov_base assignments.Aleksei Bavshin1-2/+2
This is consistent with the rest of the code and fixes build on systems with non-standard definition of struct iovec (Solaris, Illumos).
2024-12-27QUIC: fixed accessing a released stream.Roman Arutyunyan1-5/+13
While trying to close a stream in ngx_quic_close_streams() by calling its read event handler, the next stream saved prior to that could be destroyed recursively. This caused a segfault while trying to access the next stream. The way the next stream could be destroyed in HTTP/3 is the following. A request stream read event handler ngx_http_request_handler() could end up calling ngx_http_v3_send_cancel_stream() to report a cancelled request stream in the decoder stream. If sending stream cancellation decoder instruction fails for any reason, and the decoder stream is the next in order after the request stream, the issue is triggered. The fix is to postpone calling read event handlers for all streams being closed to avoid closing a released stream.
2024-12-26QUIC: ignore version negotiation packets.Roman Arutyunyan1-0/+5
Previously, such packets were treated as long header packets with unknown version 0, and a version negotiation packet was sent in response. This could be used to set up an infinite traffic reflect loop with another nginx instance. Now version negotiation packets are ignored. As per RFC 9000, Section 6.1: An endpoint MUST NOT send a Version Negotiation packet in response to receiving a Version Negotiation packet.
2024-12-10QUIC: fixed client request timeout in 0-RTT scenarios.nandsky1-1/+1
Since 0-RTT and 1-RTT data exist in the same packet number space, ngx_quic_discard_ctx incorrectly discards 1-RTT packets when 0-RTT keys are discarded. The issue was introduced by 58b92177e7c3c50f77f807ab3846ad5c7bbf0ebe.
2024-11-26QUIC: got rid of memory copy when initializing constant values.Sergey Kandaurov1-8/+9
2024-11-26QUIC: constified nonce parameter of crypto functions.Sergey Kandaurov2-7/+7
This follows OpenSSL and BoringSSL API, and gives a hint to compiler that this parameter may not be modified.
2024-11-25QUIC: prevented BIO leak in case of error.Roman Arutyunyan1-0/+1
2024-10-08QUIC: prevent deleted stream frame retransmissions.nandsky1-7/+6
Since a2a513b93cae, stream frames no longer need to be retransmitted after it was deleted. The frames which were retransmitted before, could be stream data frames sent prior to a RESET_STREAM. Such retransmissions are explicitly prohibited by RFC 9000, Section 19.4.
2024-09-24Fixed a typo of bpf makefile debug option.tzssangglass1-1/+1
2024-08-09QUIC: zero out existing keying material only.Sergey Kandaurov1-6/+23
Previously, this used to have extra ngx_explicit_memzero() calls from within ngx_quic_keys_cleanup(), which might be suboptimal.
2024-08-09QUIC: discarding 0-RTT keys.Sergey Kandaurov1-0/+10
For simplicity, this is done on successful decryption of a 1-RTT packet.
2024-05-28QUIC: ngx_quic_buffer_t use-after-free protection.Roman Arutyunyan1-0/+1
Previously the last chain field of ngx_quic_buffer_t could still reference freed chains and buffers after calling ngx_quic_free_buffer(). While normally an ngx_quic_buffer_t object should not be used after freeing, resetting last_chain field would prevent a potential use-after-free.
2024-05-28QUIC: ignore CRYPTO frames after handshake completion.Roman Arutyunyan1-0/+5
Sending handshake-level CRYPTO frames after the client's Finished message could lead to memory disclosure and a potential segfault, if those frames are sent in one packet with the Finished frame.
2024-05-28QUIC: client transport parameter data length checking.Sergey Kandaurov1-0/+8
2024-04-10QUIC: fixed close timer processing with early data.Vladimir Khomutov1-1/+4
The ngx_quic_run() function uses qc->close timer to limit the handshake duration. Normally it is removed by ngx_quic_do_init_streams() which is called once when we are done with initial SSL processing. The problem happens when the client sends early data and streams are initialized in the ngx_quic_run() -> ngx_quic_handle_datagram() call. The order of set/remove timer calls is now reversed; the close timer is set up and the timer fires when assigned, starting the unexpected connection close process. The fix is to skip setting the timer if streams were initialized during handling of the initial datagram. The idle timer for quic is set anyway, and stream-related timeouts are managed by application layer.
2024-02-14QUIC: fixed stream cleanup (ticket #2586).Roman Arutyunyan1-0/+1
Stream connection cleanup handler ngx_quic_stream_cleanup_handler() calls ngx_quic_shutdown_stream() after which it resets the pointer from quic stream to the connection (sc->connection = NULL). Previously if this call failed, sc->connection retained the old value, while the connection was freed by the application code. This resulted later in a second attempt to close the freed connection, which lead to allocator double free error. The fix is to reset the sc->connection pointer in case of error.
2024-02-14QUIC: trial packet decryption in response to invalid key update.Sergey Kandaurov1-2/+13
Inspired by RFC 9001, Section 6.3, trial packet decryption with the current keys is now used to avoid a timing side-channel signal. Further, this fixes segfault while accessing missing next keys (ticket #2585).
2024-02-14QUIC: fixed unsent MTU probe acknowledgement.Roman Arutyunyan1-7/+12
Previously if an MTU probe send failed early in ngx_quic_frame_sendto() due to allocation error or congestion control, the application level packet number was not increased, but was still saved as MTU probe packet number. Later when a packet with this number was acknowledged, the unsent MTU probe was acknowledged as well. This could result in discovering a bigger MTU than supported by the path, which could lead to EMSGSIZE (Message too long) errors while sending further packets. The problem existed since PMTUD was introduced in 58afcd72446f (1.25.2). Back then only the unlikely memory allocation error could trigger it. However in efcdaa66df2e congestion control was added to ngx_quic_frame_sendto() which can now trigger the issue with a higher probability.
2023-12-16QUIC: fixed format specifier after a6f79f044de5.Sergey Kandaurov1-1/+1
2023-12-12QUIC: path aware in-flight bytes accounting.Sergey Kandaurov3-0/+16
On-packet acknowledgement is made path aware, as per RFC 9000, Section 9.4: Packets sent on the old path MUST NOT contribute to congestion control or RTT estimation for the new path. To make this possible in a single congestion control context, the first packet to be sent after the new path has been validated, which includes resetting the congestion controller and RTT estimator, is now remembered in the connection. Packets sent previously, such as on the old path, are not taken into account. Note that although the packet number is saved per-connection, the added checks affect application level packets only. For non-application level packets, which are only processed prior to the handshake is complete, the remembered packet number remains set to zero.
2023-12-12QUIC: reset RTT estimator for the new path.Sergey Kandaurov3-8/+10
RTT is a property of the path, it must be reset on confirming a peer's ownership of its new address.
2023-11-29QUIC: path revalidation after expansion failure.Roman Arutyunyan2-4/+19
As per RFC 9000, Section 8.2.1: When an endpoint is unable to expand the datagram size to 1200 bytes due to the anti-amplification limit, the path MTU will not be validated. To ensure that the path MTU is large enough, the endpoint MUST perform a second path validation by sending a PATH_CHALLENGE frame in a datagram of at least 1200 bytes.