niom-turn/README.md

173 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

niom-turn
=========
Minimal TURN server scaffold for the niom project (MVP).
Goals
- Provide a TURN server with long-term authentication and TLS (turns) for WebRTC clients.
- Start with a minimal, well-tested parsing/utility layer and an in-memory credential store interface that can be replaced later.
Current status
- UDP listener on 0.0.0.0:3478 (STUN/TURN) with Allocate, CreatePermission, ChannelBind, and Send flows forwarding traffic via relay sockets.
- Long-term authentication with REALM/NONCE challenges and MESSAGE-INTEGRITY validation driven by `AuthManager`.
- STUN message parser + builder in `src/stun.rs`.
- Optional TLS listener (0.0.0.0:5349) mirrors the UDP path for `turns:` clients.
Design
- Modules
- `stun.rs` STUN/TURN message parsing, MESSAGE-INTEGRITY helpers, and response builders.
- `auth.rs` `AuthManager` orchestrates nonce minting, realm checking, and key derivation using the pluggable `CredentialStore` (default: `InMemoryStore`).
- `alloc.rs` Relay allocation management with permission and channel tracking.
- `main.rs` / `tls.rs` Runtime wiring for UDP and TLS listeners using the shared authentication + allocation stack.
Authentication & credential store
- `CredentialStore` is an async trait with `get_password(username) -> Option<String>` used by `AuthManager`.
- `AuthManager` derives the RFC long-term key (`MD5(username:realm:password)`) and validates MESSAGE-INTEGRITY while issuing signed, timestamped nonces.
- The default `InMemoryStore` is provided for tests and local dev. Swap in a production store by implementing the trait and passing it to `AuthManager`.
How to build
```bash
cd niom-turn
cargo build
```
How to test (quick local smoke)
- Start the server in one terminal (it listens on UDP/3478):
```bash
cd niom-turn
cargo run
```
- From another machine or container, use a STUN client or `sipsak`/custom script to send a minimal STUN Binding request and observe the 401 reply.
Next steps
- Implement full STUN attribute parsing (MESSAGE-INTEGRITY, FINGERPRINT).
- Implement long-term auth validation using MESSAGE-INTEGRITY.
- Implement Allocate + relayed sockets and permission handling.
- Add TLS listener (port 5349) using `tokio-rustls` and support `turns:`.
Security / Deployment
- For production, run behind properly provisioned TLS certs (Let's Encrypt or mounted certs) and secure credential storage.
- Ensure UDP and TCP/TLS ports (3478/5349) are reachable from the internet when used as a public TURN server.
Auth caveat
- The current implementation intentionally keeps things simple: credentials live in-memory, A1 keys
are derived via MD5 for RFC compatibility, and nonces are signed with HMAC-SHA1. Replace these
pieces (Argon2-backed store, modern KDFs, nonce rotation) before production rollout. See
`src/auth.rs` for the pluggable surface.
Milestone 1 — Protocol Backlog
------------------------------
This milestone focuses on turning the current MVP into a feature-complete TURN core that can be used
reliably by `niom-webrtc`.
**Prioritised Backlog (live order)**
1. **TURN Data Plane Enablement**`CreatePermission`, `ChannelBind`, Send/Data indications, and
peer forwarding so allocations actually relay packets between clients and peers.
2. **Authentication Hardening** — nonce lifecycle, realm configuration, Argon2-backed credential
storage, and detailed error handling for 401/438 responses.
3. **Allocation Lifecycle & Quotas** — timers, refresh requests, cleanup of expired allocations,
and resource limits per user/IP.
4. **Protocol Compliance Extras** — FINGERPRINT support, XOR-MAPPED-ADDRESS, IPv6 evaluation,
checksum validation, and fuzz/interop testing.
5. **Observability & Limits** — structured tracing, metrics, rate limiting, and CI coverage (incl.
the bundled `smoke_client`).
Artifacts that track this milestone live in two places:
1. This README section is kept up to date while the milestone is in progress.
2. Inline module docs (`//!`) inside `src/` record the current responsibilities and open backlog
items for each subsystem as we iterate.
**Task in progress**
- TURN data plane enablement:
- [x] `CreatePermission` handling and permission tracking
- [x] `ChannelBind` setup and `Send` forwarding to peers
- [x] ChannelData framing and Data Indication responses from relay to client
License: MIT
Smoke-Test (End-to-End)
-----------------------
Diese Anleitung beschreibt, wie du lokal den laufenden TURN/STUN-Server prüfst und welche Ergebnisse zu erwarten sind.
1) Server starten
Starte den Server im Projektverzeichnis; die Ausgabe wird normal in stdout geschrieben. In meinen Tests habe ich den Server im Hintergrund gestartet und die Logs in `/tmp/niom-turn-server.log` umgeleitet:
```bash
cd niom-turn
# Im Vordergrund (für Entwicklung)
cargo run --bin niom-turn
# Oder im Hintergrund mit Log-Redirect
cargo run --bin niom-turn &>/tmp/niom-turn-server.log &
```
2) Smoke-Client ausführen
Das Repo enthält ein kleines Test-Binary `smoke_client`, das eine STUN Binding-Request mit `USERNAME` und `MESSAGE-INTEGRITY` an `127.0.0.1:3478` sendet.
```bash
# Build (falls noch nicht gebaut)
cargo build --bin smoke_client
# Ausführen
./target/debug/smoke_client
```
3) Erwartetes Ergebnis
Der Smoke-Client gibt die erhaltenen Bytes aus. Bei einer erfolgreichen MESSAGE-INTEGRITY-Prüfung sendet der Server eine STUN Success Response (Message Type 0x0101). Beispielsweise habe ich folgende Rückgabe gesehen:
```
got 20 bytes from 127.0.0.1:3478
[01, 01, 00, 00, 21, 12, a4, 42, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07, 07]
```
Erklärung:
- `01 01` → STUN Success Response (0x0101)
- `21 12 a4 42` → Magic Cookie (0x2112A442)
- die folgenden 12 Bytes sind die Transaction ID (in diesem Test `07` wiederholt)
Das bedeutet: Der Server hat die MESSAGE-INTEGRITY des Requests akzeptiert und eine 200-Antwort gesendet.
Wenn stattdessen eine 401-Antwort (Challenge) ausgegeben wird, sieht man im Hex typischerweise einen Fehler-Response-Typ und REALM/NONCE-Attribute im Payload; das zeigt, dass die Authentifizierung nicht erfolgt ist und der Client die Challenge verarbeiten muss.
Hinweis
- Die derzeitige Auth-Implementierung ist minimal und für Tests gedacht. Für Produktion bitte die README-Abschnitte "Auth caveat" beachten: sichere Credentials, TLS, und ggf. ephemeral credentials verwenden.
Configuration (appsettings.json)
--------------------------------
Das Projekt kann eine JSON-Konfigdatei `appsettings.json` im Arbeitsverzeichnis lesen. Eine Beispiel-Datei `appsettings.example.json` liegt im Repository und zeigt die erwartete Struktur:
```json
{
"server": {
"bind": "0.0.0.0:3478",
"tls_cert": null,
"tls_key": null
},
"credentials": [
{
"username": "testuser",
"password": "secretpassword"
}
],
"auth": {
"realm": "niom-turn.local",
"nonce_secret": null,
"nonce_ttl_seconds": 300
}
}
```
Wenn `appsettings.json` vorhanden ist, verwendet der Server die `server.bind` Adresse, befüllt den Credential-Store aus dem `credentials`-Array und übernimmt zusätzlich Realm/Nonce-Einstellungen aus `auth`. Falls die Datei fehlt, verwendet der Server die internen Defaults (Bind `0.0.0.0:3478`, Demo-Cred `testuser`, Realm `niom-turn.local`).
Deployment & TLS / Long-term Auth roadmap
-----------------------------------------
Siehe `DEPLOYMENT_TLS_AUTH.md` für eine kurze Roadmap und empfohlene Schritte zur Integration von TLS (`turns:` / TCP+TLS Port 5349) und der Implementierung von RFC-konformer Long-Term Authentication.