summaryrefslogtreecommitdiffhomepage
path: root/src/event/quic/ngx_event_quic_migration.c (follow)
AgeCommit message (Collapse)AuthorFilesLines
2025-04-15QUIC: CUBIC congestion control.Roman Arutyunyan1-0/+1
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 Arutyunyan1-0/+1
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: prevent spurious congestion control recovery mode.Roman Arutyunyan1-1/+1
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 Arutyunyan1-2/+2
As per RFC 9002, Section B.2, max_datagram_size used in congestion window computations should be based on path MTU.
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-12QUIC: path aware in-flight bytes accounting.Sergey Kandaurov1-0/+6
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 Kandaurov1-0/+2
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 Arutyunyan1-3/+17
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.
2023-11-29QUIC: congestion control in ngx_quic_frame_sendto().Roman Arutyunyan1-20/+29
Previously ngx_quic_frame_sendto() ignored congestion control and did not contribute to in_flight counter. Now congestion control window is checked unless ignore_congestion flag is set. Also, in_flight counter is incremented and the frame is stored in ctx->sent queue if it's ack-eliciting. This behavior is now similar to ngx_quic_output_packet().
2023-11-22QUIC: ignore duplicate PATH_CHALLENGE frames.Roman Arutyunyan1-0/+8
According to RFC 9000, an endpoint SHOULD NOT send multiple PATH_CHALLENGE frames in a single packet. The change adds a check to enforce this claim to optimize server behavior. Previously each PATH_CHALLENGE always resulted in a single response datagram being sent to client. The effect of this was however limited by QUIC flood protection. Also, PATH_CHALLENGE is explicitly disabled in Initial and Handshake levels, see RFC 9000, Table 3. However, technically it may be sent by client in 0-RTT over a new path without actual migration, even though the migration itself is prohibited during handshake. This allows client to coalesce multiple 0-RTT packets each carrying a PATH_CHALLENGE and end up with multiple PATH_CHALLENGEs per datagram. This again leads to suboptimal behavior, see above. Since the purpose of sending PATH_CHALLENGE frames in 0-RTT is unclear, these frames are now only allowed in 1-RTT. For 0-RTT they are silently ignored.
2023-11-22QUIC: fixed anti-amplification with explicit send.Roman Arutyunyan1-0/+6
Previously, when using ngx_quic_frame_sendto() to explicitly send a packet with a single frame, anti-amplification limit was not properly enforced. Even when there was no quota left for the packet, it was sent anyway, but with no padding. Now the packet is not sent at all. This function is called to send PATH_CHALLENGE/PATH_RESPONSE, PMTUD and probe packets. For all these cases packet send is retried later in case the send was not successful.
2023-11-29QUIC: avoid partial expansion of PATH_CHALLENGE/PATH_RESPONSE.Roman Arutyunyan1-24/+27
By default packets with these frames are expanded to 1200 bytes. Previously, if anti-amplification limit did not allow this expansion, it was limited to whatever size was allowed. However RFC 9000 clearly states no partial expansion should happen in both cases. Section 8.2.1. Initiating Path Validation: An endpoint MUST expand datagrams that contain a PATH_CHALLENGE frame to at least the smallest allowed maximum datagram size of 1200 bytes, unless the anti-amplification limit for the path does not permit sending a datagram of this size. Section 8.2.2. Path Validation Responses: An endpoint MUST expand datagrams that contain a PATH_RESPONSE frame to at least the smallest allowed maximum datagram size of 1200 bytes. ... However, an endpoint MUST NOT expand the datagram containing the PATH_RESPONSE if the resulting data exceeds the anti-amplification limit.
2023-08-31QUIC: ignore path validation socket error (ticket #2532).Roman Arutyunyan1-3/+1
Previously, a socket error on a path being validated resulted in validation error and subsequent QUIC connection closure. Now the error is ignored and path validation proceeds as usual, with several retries and a timeout. When validating the old path after an apparent migration, that path may already be unavailable and sendmsg() may return an error, which should not result in QUIC connection close. When validating the new path, it's possible that the new client address is spoofed (See RFC 9000, 9.3.2. On-Path Address Spoofing). This address may as well be unavailable and should not trigger QUIC connection closure.
2023-08-14QUIC: path MTU discovery.Roman Arutyunyan1-58/+303
MTU selection starts by doubling the initial MTU until the first failure. Then binary search is used to find the path MTU.
2023-08-08QUIC: allowed ngx_quic_frame_sendto() to return NGX_AGAIN.Roman Arutyunyan1-3/+3
Previously, NGX_AGAIN returned by ngx_quic_send() was treated by ngx_quic_frame_sendto() as error, which triggered errors in its callers. However, a blocked socket is not an error. Now NGX_AGAIN is passed as is to the ngx_quic_frame_sendto() callers, which can safely ignore it.
2023-07-06QUIC: removed path->limited flag.Roman Arutyunyan1-4/+0
Its value is the opposite of path->validated.
2023-04-27QUIC: fixed addr_text after migration (ticket #2488).Roman Arutyunyan1-6/+3
Previously, the post-migration value of addr_text could be truncated, if it was longer than the previous one. Also, the new value always included port, which should not be there.
2023-05-09QUIC: reschedule path validation on path insertion/removal.Sergey Kandaurov1-3/+45
Two issues fixed: - new path validation could be scheduled late - a validated path could leave a spurious timer
2023-05-09QUIC: lower bound path validation PTO.Sergey Kandaurov1-2/+2
According to RFC 9000, 8.2.4. Failed Path Validation, the following value is recommended as a validation timeout: A value of three times the larger of the current PTO or the PTO for the new path (using kInitialRtt, as defined in [QUIC-RECOVERY]) is RECOMMENDED. The change adds PTO of the new path to the equation as the lower bound.
2023-05-09QUIC: separated path validation retransmit backoff.Sergey Kandaurov1-3/+4
Path validation packets containing PATH_CHALLENGE frames are sent separately from regular frame queue, because of the need to use a decicated path and pad the packets. The packets are sent periodically, separately from the regular probe/lost detection mechanism. A path validation packet is resent up to 3 times, each time after PTO expiration, with increasing per-path PTO backoff.
2022-09-30QUIC: "info" logging level on insufficient client connection ids.Sergey Kandaurov1-1/+1
Apparently, this error is reported on NAT rebinding if client didn't previously send NEW_CONNECTION_ID to supply additional connection ids.
2022-04-20QUIC: separate UDP framework for QUIC.Roman Arutyunyan1-4/+3
Previously, QUIC used the existing UDP framework, which was created for UDP in Stream. However the way QUIC connections are created and looked up is different from the way UDP connections in Stream are created and looked up. Now these two implementations are decoupled.
2022-02-16QUIC: fixed indentation.Sergey Kandaurov1-2/+2
2022-01-28QUIC: got rid of hash symbol in backup and logging.Vladimir Homutov1-10/+10
Now all objectes with sequence number (i.e. sockets, connection ids and paths) are logged as "foo seq:N".
2022-01-26QUIC: fixed handling of initial source connection id.Vladimir Homutov1-2/+2
This was broken in 1e2f4e9c8195. While there, adjusted formatting of debug message with socket seqnum.
2022-01-20QUIC: additional limit for probing packets.Vladimir Homutov1-0/+11
RFC 9000, 9.3. Responding to Connection Migration: An endpoint only changes the address to which it sends packets in response to the highest-numbered non-probing packet. The patch extends this requirement to probing packets. Although it may seem excessive, it helps with mitigation of reply attacks (when an off-path attacker has copied packet with PATH_CHALLENGE and uses different addresses to exhaust available connection ids).
2022-01-19QUIC: reworked migration handling.Vladimir Homutov1-215/+187
The quic connection now holds active, backup and probe paths instead of sockets. The number of migration paths is now limited and cannot be inflated by a bad client or an attacker. The client id is now associated with path rather than socket. This allows to simplify processing of output and connection ids handling. New migration abandons any previously started migrations. This allows to free consumed client ids and request new for use in future migrations and make progress in case when connection id limit is hit during migration. A path now can be revalidated without losing its state. The patch also fixes various issues with NAT rebinding case handling: - paths are now validated (previously, there was no validation and paths were left in limited state) - attempt to reuse id on different path is now again verified (this was broken in 40445fc7c403) - former path is now validated in case of apparent migration
2021-12-16QUIC: refactored ngx_quic_validate_path().Vladimir Homutov1-6/+3
The function now accepts path argument, as suggested by the name. Socket is not really needed inside.
2021-12-16QUIC: added missing check for backup path existence.Vladimir Homutov1-6/+15
2021-12-13QUIC: decoupled path state and limitation status.Vladimir Homutov1-3/+9
The path validation status and anti-amplification limit status is actually two different variables. It is possible that validating path should not be limited (for example, when re-validating former path).
2021-12-13QUIC: improved path validation.Vladimir Homutov1-24/+14
Previously, path was considered valid during arbitrary selected 10m timeout since validation. This is quite not what RFC 9000 says; the relevant part is: An endpoint MAY skip validation of a peer address if that address has been seen recently. The patch considers a path to be 'recently seen' if packets were received during idle timeout. If a packet is received from the path that was seen not so recently, such path is considered new, and anti-amplification restrictions apply.
2021-12-06QUIC: added missing frame initialization.Vladimir Homutov1-0/+4
Currently, all used fields are initialized, but usage may change in future.
2021-12-09QUIC: refactored ngx_quic_frame_sendto() function.Vladimir Homutov1-36/+3
The function now takes path as an argument to deal with associated restrictions and update sent counter.
2021-12-01QUIC: removed excessive check.Vladimir Homutov1-1/+1
The c->udp->dgram may be NULL only if the quic connection was just created: the ngx_event_udp_recvmsg() passes information about datagrams to existing connections by providing information in c->udp. If case of a new connection, c->udp is allocated by the QUIC code during creation of quic connection (it uses c->sockaddr to initialize qsock->path). Thus the check for qsock->path is excessive and can be read wrong, assuming that other options possible, leading to warnings from clang static analyzer.
2021-11-29QUIC: fixed migration during NAT rebinding.Vladimir Homutov1-62/+17
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-29QUIC: refactored multiple QUIC packets handling.Vladimir Homutov1-6/+1
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-11QUIC: fixed PATH_RESPONSE frame expansion.Vladimir Homutov1-3/+11
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-07-28QUIC: handle EAGAIN properly on UDP sockets.Vladimir Homutov1-3/+3
Previously, the error was ignored leading to unnecessary retransmits. Now, unsent frames are returned into output queue, state is reset, and timer is started for the next send attempt.
2021-06-16QUIC: updated specification references.Sergey Kandaurov1-10/+31
This includes updating citations and further clarification.
2021-05-05QUIC: simplified sending 1-RTT only frames.Sergey Kandaurov1-5/+4
2021-05-05QUIC: relaxed client id requirements.Vladimir Homutov1-6/+13
Client IDs cannot be reused on different paths. This change allows to reuse client id previosly seen on the same path (but with different dcid) in case when no unused client IDs are available.
2021-04-29QUIC: connection migration.Vladimir Homutov1-8/+695
The patch adds proper transitions between multiple networking addresses that can be used by a single quic connection. New networking paths are validated using PATH_CHALLENGE/PATH_RESPONSE frames.
2021-04-14QUIC: headers cleanup.Vladimir Homutov1-2/+0
The "ngx_event_quic.h" header file now contains only public definitions, used by modules. All internal definitions are moved into the "ngx_event_quic_connection.h" header file.
2021-03-31QUIC: distinct files for connection migration.Vladimir Homutov1-0/+46
The connection migration-related code from quic.c with dependencies is moved into separate file.