You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
NAT rebinding and Wi-Fi-to-cellular are ordinary events on a UDP transport, and QUIC exists partly to survive them. ioxide currently does not.
The shim discards the address every datagram arrives from:
intiq_conn_read(iq_conn*c, constvoid*remote_sa, size_tremote_salen, ...)
{
(void)remote_sa; (void)remote_salen; /* milestone: no migration; path is fixed at accept */
so ngtcp2 is told every packet came from the accept-time path, never emits a PATH_CHALLENGE, and every reply goes to the original 4-tuple. QuicConnection.UpdatePeerAddress exists, is public, is documented as "adopt a validated peer migration" — and has zero callers anywhere in the repo.
The failure is silent on both sides. The clients packets still route (the connection id has not changed), the server keeps answering an address nobody is listening on, and the connection dies at the idle sweep with no error to either peer.
Two things to be careful about when this is implemented, both from nginxs quic_migration.t:
A migration must be validated before it is adopted — this was wrong, and PR quic: let a connection survive its peer changing address #209's reviewers caught it. ngtcp2 adopts first and validates after: conn_recv_non_probing_pkt_on_new_path copies the new DCID into dcid.currentbefore creating the path validation, and for a plain remote-address change the pref_addr guard is false, so adoption is unconditional. What prevents amplification is not the ordering: the packet must decrypt under 1-RTT keys, which an off-path spoofer cannot forge, and ngtcp2 caps an unvalidated path at 3× what it received. A binding that waited for validation before moving its send address would send ngtcp2's own new-path packets to the old address.
nginx ticket #2488 was $remote_addr coming back truncated mid-migration, because a stream cached a pointer plus an old length while the address was rewritten under it. UpdatePeerAddress memcpys into the same PeerAddr allocation and updates PeerAddrLen afterwards — the identical shape, so it wants the length updated first or the buffer swapped rather than edited.
Blocked in practice on #205: on a multi-reactor server the datagram may not even reach the reactor that owns the connection.
NAT rebinding and Wi-Fi-to-cellular are ordinary events on a UDP transport, and QUIC exists partly to survive them. ioxide currently does not.
The shim discards the address every datagram arrives from:
so ngtcp2 is told every packet came from the accept-time path, never emits a
PATH_CHALLENGE, and every reply goes to the original 4-tuple.QuicConnection.UpdatePeerAddressexists, is public, is documented as "adopt a validated peer migration" — and has zero callers anywhere in the repo.The failure is silent on both sides. The clients packets still route (the connection id has not changed), the server keeps answering an address nobody is listening on, and the connection dies at the idle sweep with no error to either peer.
Two things to be careful about when this is implemented, both from nginxs
quic_migration.t:A migration must be validated before it is adopted— this was wrong, and PR quic: let a connection survive its peer changing address #209's reviewers caught it. ngtcp2 adopts first and validates after:conn_recv_non_probing_pkt_on_new_pathcopies the new DCID intodcid.currentbefore creating the path validation, and for a plain remote-address change thepref_addrguard is false, so adoption is unconditional. What prevents amplification is not the ordering: the packet must decrypt under 1-RTT keys, which an off-path spoofer cannot forge, and ngtcp2 caps an unvalidated path at 3× what it received. A binding that waited for validation before moving its send address would send ngtcp2's own new-path packets to the old address.$remote_addrcoming back truncated mid-migration, because a stream cached a pointer plus an old length while the address was rewritten under it.UpdatePeerAddressmemcpys into the samePeerAddrallocation and updatesPeerAddrLenafterwards — the identical shape, so it wants the length updated first or the buffer swapped rather than edited.Blocked in practice on #205: on a multi-reactor server the datagram may not even reach the reactor that owns the connection.