Article

WebRTC Debugging: Wie ein iPad-Freeze zwei Bugs in einem Trenchcoat enthüllte

Eine faszinierende Debugging-Story von einem Entwickler, der zwei Wochen brauchte, um einen scheinbar simplen Fehler zu verstehen: Ein iPad fror bei WebRTC-Verbindungen über Tailscale willkürlich ein. Die Ursache? Zwei Bugs, die sich einen Trenchcoat teilten – eine hardcoded Konstante in webrtc-rs und eine Design-Entscheidung in Tailscale.

Das Symptom

Ein WebRTC-Stream über Tailscale funktionierte auf jedem Gerät – außer einem iPad. Bei Refreshs stieg der Outbound-Buffer des Senders auf 8KB und stoppte. SCTP-Retransmissions in klassischen Backoff-Intervallen (+1.2s, +2s, +4s, +8s), niemals bestätigt. Kleine Pakete flossen weiterhin in beide Richtungen – Heartbeats, ACKs, Connectivity Checks. Die Verbindung wirkte gesund, außer den eigentlichen Daten-Payloads.

Der erste Bug: webrtc-rs

Die Ursache lag in einer hardcoded Konstante:

// sctp/src/association/mod.rs
pub(crate) const INITIAL_MTU: u32 = 1228;

WebRTC nutzt SCTP über DTLS über UDP. Die 1228-Byte-Konstante war für IPv4 korrekt, aber für IPv6 zu groß – IPv6 hat eine minimale MTU von 1280 Bytes, was mit DTLS-Overhead die Grenze sprengt. Normalerweise fragmentiert der Kernel und setzt Pakete wieder zusammen. Der Bug blieb unsichtbar – außer wenn Fragmente verschwanden.

Der zweite Bug: Tailscale frisst IPv6-Fragmente

Die entscheidende Erkenntnis: Tailscale verwirft IPv6-Fragmente auf allen Plattformen. Ein Counter in Tailscale zeigte reasmFails – Fragment-Reassembly-Failures. Die Fragmente kamen an, wurden aber nicht zusammengesetzt.

Warum nur auf manchen Geräten sichtbar? Nur Tailscale-Endpunkte zeigten das Verhalten. Direct-Connections ohne Tailscale funktionierten. Ein minimales Repro-Projekt bestätigte: Jeder Tailscale-Knoten frisst IPv6-Fragmente.

Debugging-Lektionen

Zwei Takeaways für komplexe Netzwerk-Debugging:

  1. Sender-Side Packet Capture beweist nur, dass Pakete abgesendet wurden. tcpdump auf der Box zeigte schön abgehende Fragmente – die dann auf Empfängerseite starben. Der Empfänger muss überwacht werden (schwer mit einem non-jailbroken iPad).

  2. Wenn ein Bug nur auf einem Gerät auftritt, frage: Was ist anders an der Netzwerk-Pipeline? Das iPad war nicht schuld – es war das einzige Gerät, das via Tailscale verbunden war.


Quelle: p2claw Blog, webrtc-rs Issue #806, Tailscale Issue #20083