# TCP/TLS Data-Plane (TURN over TCP/TLS) in niom-turn Dieses Dokument erklärt **wofür** eine TCP/TLS Data-Plane bei TURN gebraucht wird und **wie** `niom-turn` sie (aktuell) implementiert. ## Wofür wird das benötigt? TURN hat zwei Arten von Traffic: - **Control-Plane**: STUN/TURN Requests/Responses (Allocate, CreatePermission, ChannelBind, Refresh, …) - **Data-Plane**: Nutzdaten zwischen Client und Peer, die über das Relay laufen (Send/Data-Indication oder ChannelData) In vielen realen Netzen ist **UDP eingeschränkt oder komplett blockiert** (Corporate WLAN, Mobilfunk-APNs, Captive Portals, Proxy-Umgebungen). WebRTC/ICE versucht deshalb typischerweise: 1. UDP (schnell, bevorzugt) 2. TURN über TCP 3. TURN über TLS ("turns:") als letzte, aber oft funktionierende Option Damit TURN über TCP/TLS wirklich nutzbar ist, muss nicht nur die Control-Plane über den Stream laufen, sondern auch der **Rückweg Peer → Client** (Data-Plane) über **dieselbe TCP/TLS Verbindung** beim Client ankommen. ## Was implementiert niom-turn konkret? - Client ↔ Server Transport kann **UDP**, **TCP** oder **TLS** sein. - Das Relay zum Peer ist weiterhin **UDP** (klassisches TURN UDP-Relay). - Bei **TCP/TLS** liefert der Server die Data-Plane zurück an den Client über den **Stream** (statt über UDP an die Client-Adresse zu senden). Das entspricht dem üblichen WebRTC-Fallback: "Client-Server über TCP/TLS, Peer-Transport über UDP". ## Architektur im Code - Stream-Handler (TCP/TLS): [src/turn_stream.rs](../src/turn_stream.rs) - TCP Listener: [src/tcp.rs](../src/tcp.rs) - TLS Listener: [src/tls.rs](../src/tls.rs) - Allocation + Relay: [src/alloc.rs](../src/alloc.rs) ### Schlüsselidee: `ClientSink` Damit der Relay-Loop Peer-Pakete an unterschiedliche Client-Transporte schicken kann, gibt es in [src/alloc.rs](../src/alloc.rs) eine Abstraktion: - `ClientSink::Udp { sock, addr }` → sendet Peer-Daten per `udp.send_to(..., addr)` - `ClientSink::Stream { tx }` → queued Bytes in einen Writer-Task, der auf den TCP/TLS Stream schreibt Wenn ein Client über TCP/TLS allocatet, wird die Allocation mit einem `ClientSink::Stream` erzeugt. ## Framing: STUN vs. ChannelData auf einem Byte-Stream Auf UDP bekommt man Datagramme; auf TCP/TLS bekommt man einen **kontinuierlichen Byte-Stream**. TURN over TCP/TLS multiplexed: - STUN/TURN Messages (Control-Plane) - ChannelData Frames (Data-Plane, Client → Server) `niom-turn` parst daher im Stream in einer Schleife "nächstes Frame" (siehe `try_pop_next_frame(...)` in [src/turn_stream.rs](../src/turn_stream.rs)): ### STUN Message - Header ist 20 Bytes - Length-Feld ist die Body-Länge - Gesamtlänge ist: $20 + length$ ### ChannelData Frame - 4 Byte Header: `CHANNEL-NUMBER` (2) + `LENGTH` (2) - Channel-Nummern liegen im Bereich `0x4000..=0x7FFF` (Top-Bits `01`) - Gesamtlänge ist: $4 + length$ Wichtig: Bei TCP/TLS darf **kein Padding** als "separate Bytes" im Stream verbleiben. Deshalb baut `niom-turn` ChannelData als exakt `4 + len` Bytes (siehe [src/stun.rs](../src/stun.rs)). ### Hardening: Resync & Limits Da TCP/TLS ein Byte-Stream ist, können kaputte oder bösartige Clients den Parser sonst leicht „desynchronisieren“. `niom-turn` implementiert daher im Stream-Parser: - **Magic-Cookie Check** für STUN: Ungültige Cookies führen zu einem Byte-weisen Resync (statt auf riesige Längen zu warten). - **Frame-Size Limits** (STUN-Body und ChannelData), um Speicher-/DoS-Risiken zu begrenzen. - **Max Buffer Limit** pro Verbindung: wenn der Eingangspuffer zu groß wird, wird die Verbindung geschlossen. ## Datenfluss (TCP/TLS) 1. Client verbindet sich per TCP oder TLS. 2. Der Stream-Handler liest Frames: - STUN/TURN Requests → verarbeitet wie UDP-Pfad (Auth, Allocation, Permission, ChannelBind, Send, Refresh) - ChannelData (Client→Peer) → wird über das UDP-Relay an den Peer geschickt 3. Peer sendet UDP an die Relay-Adresse. 4. Relay-Loop leitet die Bytes an den `ClientSink` weiter: - bei Stream: `tx.send(bytes)` → Writer-Task schreibt Data-Indication oder ChannelData zurück auf denselben Stream ## Grenzen / Noch nicht implementiert - Kein TCP-Relay zum Peer (TURN TCP allocations / CONNECT-Methoden wie in RFC6062). - Fokus liegt auf: Client-Server Transport über TCP/TLS + UDP-Relay. - IPv6 ist im aktuellen MVP noch nicht vollständig umgesetzt. ## Tests - TCP Stream Data-Plane: `tests/tcp_turn.rs` - TLS Stream Data-Plane: `tests/tls_data_plane.rs` - Gemeinsames Framing (STUN + ChannelData): `tests/support/stream.rs` Wenn du willst, kann ich als nächsten Schritt die Doku um eine kurze Interop-Checkliste (WebRTC/ICE Verhalten, Candidate-Types, typische Fehlerbilder) ergänzen.