138 lines
5.4 KiB
Markdown
138 lines
5.4 KiB
Markdown
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) implemented.
|
|
- STUN message parser + builder in `src/stun.rs`.
|
|
- CredentialStore trait + in-memory implementation in `src/auth.rs`.
|
|
- Minimal logic: on any STUN request, server replies with a 401 challenge (REALM + NONCE).
|
|
|
|
Design
|
|
- Modules
|
|
- `stun.rs` - STUN/TURN message parsing and builders.
|
|
- `auth.rs` - CredentialStore trait and an `InMemoryStore` impl. Use the trait to swap for DB-backed stores later.
|
|
- `main.rs` - Bootstraps UDP listener, parses requests, and emits challenges for auth.
|
|
|
|
CredentialStore interface
|
|
- `CredentialStore` is an async trait with `get_password(username) -> Option<String>`.
|
|
- The default `InMemoryStore` is provided for tests and local dev. Swap in a production store by implementing the trait.
|
|
|
|
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 in-repo long-term auth implementation is intentionally minimal for the MVP and
|
|
uses legacy constructs (A1/MD5 derivation + HMAC-SHA1 MESSAGE-INTEGRITY). MD5 is not recommended
|
|
for new secure systems — this is present for RFC compatibility and testing only. We will replace
|
|
this with a secure credential workflow (ephemeral/REST credentials, PBKDF/KDF storage, or mTLS)
|
|
before any production deployment. See `src/auth.rs` for the current simple store and helpers.
|
|
|
|
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"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Wenn `appsettings.json` vorhanden ist, verwendet der Server die `server.bind` Adresse und befüllt den anfänglichen Credential-Store aus dem `credentials`-Array. Falls die Datei fehlt, verwendet der Server die internen Defaults (Bind `0.0.0.0:3478` und Demo-Cred `testuser`).
|
|
|
|
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.
|
|
|