Skip to content

fix: correct TCP window and duplicate-ACK reporting - #589

Open
domcyrus wants to merge 3 commits into
mainfrom
fix/tcp-window-size-per-direction
Open

fix: correct TCP window and duplicate-ACK reporting#589
domcyrus wants to merge 3 commits into
mainfrom
fix/tcp-window-size-per-direction

Conversation

@domcyrus

@domcyrus domcyrus commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Three related defects in the Details Transport Health card.

Window size mixed both directions. One slot, overwritten by every segment
either way, so the value flipped between the local and remote advertised
windows (e.g. 8 one refresh, 1100 the next). Now tracked per direction and
shown as local (bounds inbound) / remote (bounds outbound).

Window scaling is negotiated only in the SYN handshake (RFC 7323), so on a
connection rustnet joined mid-stream the scale is unknowable from the wire and
the raw 16-bit field stands for anything up to 16384 times its value. That row
now reads unknown (no handshake) instead of a number nobody can act on. A
window never observed at all still reads -.

A connection's first packet never reached the analytics. New connections
went through create_connection_from_packet, which never called
analyze_tcp_segment. For a connection this host initiates that skipped packet
is its own SYN, the only carrier of the local window-scale option, so the local
shift stayed unknown for the connection's whole life and windows could not be
reported in bytes even with the full handshake captured. It also left the
sequence high-water marks unseeded.

Duplicate ACKs counted keepalives and window updates. RFC 5681 §2 also
requires outstanding data and an unchanged window; only the no-data test was
implemented. An idle connection that the capture joined mid-stream reported 12
duplicate ACKs and 1 fast retransmit against 0 retransmits. A RST's window
field is meaningless, so it no longer overwrites the last advertisement either.

The Details help overlay gains a Transport Health section covering the window
pair, the unknown case, and why Initial RTT can be blank; USAGE.md and
USAGE.zh-CN.md document the row.

QUIC and transactional-UDP counters were checked for the same problems: they
are cumulative event counts, not last-value samples, so none of them mix
directions.

Benchmarked with cargo bench --bench connection_merge: within run-to-run
noise (~33 ns per merged packet before and after).

https://claude.ai/code/session_017EwRvzAya3cHc66f2YeKR8

One shared slot was overwritten by whichever side sent last, so the
Details window jumped between the local and remote advertised windows.
Track both, and show bytes only when the handshake proved the scale.

Claude-Session: https://claude.ai/code/session_017EwRvzAya3cHc66f2YeKR8
@domcyrus
domcyrus force-pushed the fix/tcp-window-size-per-direction branch from 799dc01 to 7ba725e Compare August 29, 2026 10:35
The packet that created a connection skipped the analytics, so a
connection's own SYN never taught it the local window scale. Duplicate
ACKs now require outstanding data and an unchanged window (RFC 5681),
and a RST no longer overwrites the last advertised window.

Claude-Session: https://claude.ai/code/session_017EwRvzAya3cHc66f2YeKR8
@domcyrus domcyrus changed the title fix: report TCP window size per direction fix: correct TCP window and duplicate-ACK reporting Aug 29, 2026
A window whose scale was never observed stands for anything up to 16384
times the header field, so print unknown instead of that number. Details
help gains a Transport Health section and USAGE documents the row.

Claude-Session: https://claude.ai/code/session_017EwRvzAya3cHc66f2YeKR8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant