Skip to content

v0.3.6

Choose a tag to compare

@doronz88 doronz88 released this 13 Aug 04:55
· 6 commits to main since this release

Third round from the 2026-08 stability audit: TCP hot-path hygiene and long-run state bounds. Verified per-commit on Python 3.9 with the full test suite (4167 tests) and smoke-tested end-to-end against a physical iOS device over the pymobiledevice3 userspace tunnel (zero stranded tasks, latency unchanged at ~0.8 s).

Highlights

  • Out-of-order queue hygiene. Entries stranded below RCV.NXT by a re-segmented retransmission were unreachable by the exact-key consume path: each pinned its full packet buffer for the session's remaining life and kept being advertised as a SACK block below the peer's SND.UNA — which RFC 2883 peers parse as DSACK, wrongly undoing their cwnd reductions. The consume path now purges them, and the queue is bounded (64 entries, Linux tcp_prune_ofo_queue-style) so disjoint tiny out-of-order segments can no longer pin one buffer per in-window byte.
  • Tail Loss Probe actually fires under long SRTT. The RFC 8985 §7.2 "do not outlast RTO" clamp read a timer field that no longer exists, so it was dead code: whenever 2×SRTT reached past the remaining RTO, the RTO always preempted the probe and every tail loss degraded to a full RTO + slow-start. The clamp now reads the live per-session retransmit deadline.
  • Datagram rx queues are bounded (512 datagrams, POSIX full-buffer newest-drop). Worst prior case: the IPv4 ACD defense socket buffered every ARP frame on the segment between DHCP BOUND polls — up to T1, i.e. hours.
  • Slow-growth state tables fixed for the runs-for-days profile: the IPv6 DAD registry now drops entries when their address is removed (each rotated RFC 8981 temp address previously leaked one forever); the TCP Fast-Open negative cache is FIFO-bounded like the cookie cache; timed-out default routers are removed per RFC 4861 §6.3.5 instead of merely hidden (an on-link RA spoofing attacker could previously grow the list without bound).