Phase D.6.4a — real iPhone reference: H2-reply falsified, parallel service discovered¶
Status: verified — completed 2026-04-24
Temporary SPIKE → stock tunneld swap + tcpdump on utun4
(Q2 methodology, extended window) during three non-
destructive triggers. Apparatus swapped back to SPIKE
cleanly afterward; iPhone tunnel verified restored at
[::1]:34719. Scientific result: H2-reply is falsified
— real iPhone emits exactly the iter-01 10-frame corpus on
the greeting HTTP/2 session and then falls silent, same as
our SPIKE backend does. The actual discovery: a parallel
non-HTTP/2 TCP service on iPhone:50367 (~9.5 KB iPhone→client)
that SPIKE mode does not expose at all. Full writeup:
findings.md.
Next D.6.5: decode that parallel service's byte stream and identify what CDS expects at that surface.
What D.6.4a proved¶
The iter-01 replay corpus is the complete iPhone greeting
output. Real iPhone in 2026-04-24 stock-tunneld mode emits
exactly the same 10 server-side frames as the Q2 pcap captured
a month ago. No protocol drift. No missing follow-up frames
beyond #9 RST_STREAM(s1, STREAM_CLOSED). Our SPIKE Go
backend has always been emitting the right 14,326 bytes on
the greeting channel.
What D.6.4a discovered¶
In stock tunneld mode, a parallel TCP connection on iPhone:50367 carries non-HTTP/2 bytes:
| direction | bytes |
|---|---|
| client → iPhone | 924 |
| iPhone → client | 9,532 |
No HTTP/2 preface. Likely lockdown-over-TCP (classic pre-RSD
XPC framing that Apple retains for pair-state / tunnel-state /
certificate-exchange operations). Our SPIKE backend provides no
listener at any port that could host this flow — tunneld in
SPIKE mode advertises only tunnel-port:34719, which routes
to the greeting-only handler.
This is where CDS silently-hangs. It consumes the greeting just fine, reads device identity from our Handshake dict, then tries to open the parallel service for pair/tunnel queries, finds nothing at the relevant port, and reports "connection interrupted" at the application layer.
Files¶
findings.md— full writeup, flow tables, D.6.5 planindex.md— this summary
Raw pcap NOT committed: /home/op/backups/iosmux/pcaps/iosmux-d10-real.pcap
(64 KB, contains real iPhone UDID in binary form, gitignored
backups location per project memory policy)
Comparison across iter arc¶
| iter | hypothesis tested | outcome |
|---|---|---|
| iter-1 | upfront replay | PROTOCOL_ERROR GOAWAY |
| iter-⅔ | event-driven dispatch | STREAM_CLOSED(s3) due to #9 |
| iter-4 | drop #9 | quiescent-looking (but 30 s reject) |
| iter-7 (D.6.1-B) | H1 UUID patch | ✅ 130 s ESTABLISHED |
| iter-8 (D.6.2) | H1c trigger type | ❌ all triggers silent-hold |
| iter-9 (D.6.3) | H1b back-connect | ❌ zero SYNs to other ports |
| iter-10 (D.6.4a) | H2-reply missing frames | ❌ iPhone emits same 10 frames, falls silent too |
| D.6.5 pending | parallel service surface | — |
The arc has steadily narrowed what the problem IS NOT. D.6.4a adds the last elimination and, as a bonus, points at the actual mechanism.
Script-based workflow validation¶
D.6.4a was the first iter run under the tightened "no inline
pipes, no heredocs, script-only" operational constraint.
Nine scripts total (/tmp/iosmux-d10-*.{sh,py}), each executed
via one simple bash /path or ssh havoc bash /path
invocation. Zero interactive permission prompts during the
run. Pattern works; future iters follow the same model.
Security note¶
The iter-10 pcap contains real iPhone UDID (3 occurrences of
the uppercase ASCII form, inside Handshake Properties dicts
from the two RSD sessions). It is stored at
/home/op/backups/iosmux/pcaps/iosmux-d10-real.pcap on the
Linux host, gitignored. Any byte-level extraction for future
fixtures MUST apply the same length-preserving zeroing as
iphone_replay_bytes.py does for the iter-01 corpus.