Identify the sources of page load latency in traffic.pcapng. Also, check whether TCP or QUIC retransmissions are slowing page load.
Capture: 12,266 packets, ~42 s, ~600 sessions across DNS, TCP/TLS, QUIC, HTTP, HTTP/2, HTTP/3. Single client 192.168.184.137, gateway-resolver 192.168.184.2. TLS keylog decryption enabled.
Session outcomes
| Type | Outcome | Count |
|---|---|---|
| dns-query | success::dns-resolved | 121 |
| http3-stream | success::http3-2xx | 366 |
| http3-stream | failure::http3-client-error | 4 |
| http3-stream | incomplete::no-close | 29 |
| http2-stream | success::http2-2xx | 21 |
| http2-stream | failure::http2-rst-stream | 8 |
| quic-connection | incomplete::no-close | 38 |
| tcp-connection | failure::tcp-reset | 2 |
| tcp-connection | success::graceful-fin | 40 |
Primary latency source — DNS (the smoking gun)
Every DNS lookup against 192.168.184.2 reports dns.time ≈ 2.0–2.3 s, with a handful at 3.3 s. The first www.google.com A query goes out at T=0.000 — its reply does not arrive until T=2.079 s. The first TCP SYN to Google is at T=2.086 s, i.e. the page can't start dialing for ~2 s, every name.
Examples (all No-Error, just slow): www.google.com A 2.079 s www.google.com AAAA 2.078 s www.mozilla.org A 2.041 s fonts.gstatic.com A 2.041 s static.doubleclick… A 2.117 s (slowest A) 3.365 s
The tight 2.0 s clustering is a classic forwarder-timeout-then-fallback signature — not real resolver latency.
The rest of the path is healthy
- TCP iRTT (SYN→SYN-ACK) to Google: 30–55 ms; gstatic mirrors 60–80 ms.
- TLS 1.3 handshakes complete in 1 RTT directly after SYN-ACK.
- QUIC Initial→Handshake→HANDSHAKE_DONE: ~70–90 ms.
DNS therefore adds 40–60× the actual network RTT on every new name.
TCP / QUIC retransmissions — not a meaningful factor
| Counter | Count |
|---|---|
| tcp.analysis.retransmission | 0 |
| tcp.analysis.fast_retransmission | 0 |
| tcp.analysis.spurious_retransmission | 0 |
| tcp.analysis.out_of_order | 0 |
| tcp.analysis.duplicate_ack | 0 |
| tcp.analysis.zero_window / window_full | 0 |
| QUIC "reused stream offset (retransmission?)" | 6 of 12,266 (~0.05%) |
The 6 QUIC retransmissions are scattered across 4 connections and recover immediately. The 38 ⚠️ events in the explore output are all TLS Close-Notify alerts (warning-level) — normal end-of-connection markers, not loss.
Bottom line
- DNS ~2 s per query — fix the upstream at
192.168.184.2or switch to1.1.1.1/8.8.8.8. Single biggest win. - H3/H2 stream resets, TCP RSTs exist (8 H2 RST, 4 H3 client-errors, 2 TCP RSTs) but are by-design Happy Eyeballs / image-cancel behavior.
- TCP / QUIC loss not a contributor — transport layer is clean.
Thanks for the info. What is the distribution of HTTP 1.x, HTTP 2, and HTTP 3 traffic?
By application-layer transactions — one stream / one request = one transaction:
| Version | Transactions | Share | Notes |
|---|---|---|---|
| HTTP/1.x | 4 | 0.9% | 4 GETs total — 3 × 200 OK, 1 × redirect |
| HTTP/2 | 32 | 7.4% | 22 × 2xx, 3 × redirect, 8 × RST_STREAM (cancelled image fetches on encrypted-tbn0.gstatic.com) |
| HTTP/3 | 400 | 91.7% | 366 × 2xx, 1 × redirect, 4 × client-error, 29 × incomplete-no-close |
| Total | 436 | 100% |
And on the wire, sampled from the explore NDJSON labels:
| Version | Requests | Responses | Frame-type chatter |
|---|---|---|---|
| HTTP/1.x | 4 GETs | 3 × 2xx + redirects | minimal |
| HTTP/2 | 31 GETs | 22 × 2xx + 3 × 3xx | 168 SETTINGS, 66 DATA, 37 GOAWAY, 8 RST_STREAM, 21 PING |
| HTTP/3 | 876 HEADERS frames (req + resp) | 84 SETTINGS, 22 DATA, 65 Stream Reset, 517 uni-streams (QPACK / control) | |
Takeaways
- HTTP/3 dominates — ~92% of all HTTP transactions. Modern Google/YouTube/gstatic endpoints all negotiated h3.
- HTTP/2 is the fallback path (~7%) — mostly image-CDN traffic to
encrypted-tbn0.gstatic.comwhere some streams hitRST_STREAM. - HTTP/1.x is negligible (~1%) — 4 transactions, likely captive-portal / connectivity-check style requests (Mozilla detect).
Show me the top 10 hosts by traffic volume. Also, what is the distribution of IPv4 vs IPv6 traffic?
Top 10 hosts by traffic volume
Excluding the local client 192.168.184.137 (~10 MB aggregate) and the LAN resolver 192.168.184.2 (30 kB). Ranked by bytes, from tshark -z endpoints,ip:
| # | IP | Host | Packets | Bytes |
|---|---|---|---|---|
| 1 | 74.125.130.93 | 🎬 www.youtube.com | 3,928 | 4.52 MB |
| 2 | 74.125.24.105 | 🌐 www.google.com | 4,298 | 3.70 MB |
| 3 | 203.117.34.146 | 🎬 rr7.sn-…googlevideo.com (video CDN) | 744 | 824 kB |
| 4 | 74.125.24.94 | 🔤 fonts.gstatic.com | 348 | 201 kB |
| 5 | 74.125.130.119 | 🖼 i.ytimg.com | 230 | 184 kB |
| 6 | 74.125.200.94 | 🔤 fonts.gstatic.com / gstatic | 197 | 125 kB |
| 7 | 142.250.4.132 | (Google edge) | 108 | 109 kB |
| 8 | 142.251.12.94 | 🌐 www.google.com.sg / fonts | 153 | 103 kB |
| 9 | 142.251.12.95 | 🌐 jnn-pa.googleapis.com | 110 | 92 kB |
| 10 | 172.253.118.139 | 🖼 encrypted-tbn0.gstatic.com | 207 | 88 kB |
YouTube plus its video CDN (googlevideo.com) and google.com together account for ~9 MB of the ~10 MB total — this capture is overwhelmingly a YouTube / Google session.
IPv4 vs IPv6 distribution
| Layer | Frames | Bytes | Share |
|---|---|---|---|
| IPv4 | 12,232 | 10,962,052 | 99.98% |
| IPv6 | 2 | 177 | 0.002% |
| ARP (L2, no IP) | 32 | 1,920 | 0.018% |
The IPv6 traffic is just one link-local mDNS announce + one ICMPv6 packet — essentially zero application IPv6. Even though many DNS responses returned AAAA records (e.g. www.google.com → 2404:6800:4003:c00::67), the client opened all TCP/QUIC connections over IPv4. Likely the host has no usable IPv6 default route, so Happy Eyeballs fell back to v4 every time.
Method. Capture rendered with VisualEther using its MCP integration with Claude — analyze_capture → explore for the master sequence diagram, then extract_sessions for per-session outcome buckets. Volume and protocol-mix counters cross-checked with tshark -2 -z endpoints,ip, -z io,phs, and _ws.expert.message queries against the TLS-key-decrypted pcap.