TCP-Forwarding über das Iroh-Netz (QUIC), adressiert per Public Key statt IP (Umsetzung von Option B aus recherche-vpn-vs-p2p-netzwerk.md). - server: nimmt Iroh-Verbindungen an, leitet QUIC-Streams an lokalen Port weiter - client: lauscht lokal auf TCP, öffnet pro Verbindung einen QUIC-Stream zum Peer - keygen: erzeugt Key-Datei und gibt EndpointId aus (Vorab-Verteilung) - Allowlist (--allow) erlaubter Client-EndpointIds - QUIC-Multiplexing, Reconnect mit Backoff, n0-Default-Relays + DNS-Discovery Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
207 lines
10 KiB
Markdown
207 lines
10 KiB
Markdown
# Recherche: VPN vs. P2P-Netzwerk
|
||
|
||
---
|
||
|
||
## Teil 1 – Vergleichende Übersicht
|
||
|
||
### Klassifikation nach Betriebsmodell
|
||
|
||
| Begriff | Bedeutung |
|
||
| ------- | --------- |
|
||
| **Netzwerk-Tunnel / Daemon** | Läuft als System-Dienst, erzeugt ein virtuelles Netzwerkinterface (tun/tap). Routing erfolgt OS-seitig. |
|
||
| **Overlay-Netzwerk / Mesh** | Spannt ein virtuelles Netz über bestehende Infrastruktur auf. Jeder Knoten kennt (ggf. über Koordination) alle anderen. |
|
||
| **App-Konnektivität / P2P-SDK** | Keine Netzwerkschnittstelle im OS. Konnektivität wird direkt in die Applikation eingebettet. Verbindung über kryptographische Schlüssel, nicht IPs. |
|
||
|
||
---
|
||
|
||
### Protokoll-Vergleich
|
||
|
||
| Protokoll | OSI-Schicht | Betriebsmodell | Koordination | Verschlüsselung | Besonderheiten |
|
||
| --------- | ----------- | -------------- | ------------ | --------------- | -------------- |
|
||
| **IPSec** | L3–L4 (Netzwerk/Transport) | Netzwerk-Tunnel / Kernel | Manuell (IKEv2/IKEv1) oder PKI | AES-GCM, ChaCha20 (via Suite B) | Standard in Enterprise-Firewalls; komplex in Konfiguration; NAT-Probleme (NAT-T nötig); zwei Modi: Transport (L4-Header bleibt) und Tunnel (ganzes IP-Paket) |
|
||
| **OpenVPN** | L4-Tunnel → präsentiert L2/L3 | Netzwerk-Tunnel / Daemon | CA-basiert (TLS-Zertifikate) | TLS (OpenSSL/mbedTLS) | TUN=L3, TAP=L2; läuft über UDP oder TCP; sehr verbreitet, aber langsam (Userspace); gut durch Firewalls tunnelbar (TCP:443) |
|
||
| **WireGuard** | L3 (Netzwerk) | Overlay-Netzwerk / Kernel-Modul | Manuell (Pre-shared Keys + Public Keys) | ChaCha20-Poly1305, Curve25519 | Minimaler Kernel-Code (\~4000 Zeilen); kein Handshake-Overhead im Betrieb; keine eingebaute Key-Discovery; bildet Basis für Tailscale/Netbird |
|
||
| **Yggdrasil** | L3-Overlay (IPv6) | Overlay-Netzwerk / Mesh-Daemon | Selbstorganisierend (distributed routing) | X25519 + Ed25519 | Adresse = Hash des Public Key; kein zentraler Koordinator; schlechte Performance bei sehr großem Mesh; experimentell |
|
||
| **Tailscale** | L3-Overlay | Overlay-Netzwerk / Managed Mesh | Zentraler Koordinations-Server (control plane) | WireGuard darunter | „Zero-config VPN"; DERP-Relay-Netz von Tailscale für NAT-Traversal; SaaS-Modell (oder Headscale self-hosted); gut für Team-Zugriff auf interne Dienste |
|
||
| **Iroh** | L4–L7 (QUIC/Application) | App-Konnektivität / P2P-SDK | Relay-Server (optional, betreibbar) | TLS 1.3 über QUIC | Kein Netzwerkinterface; Bibliothek (Rust, Python, Node.js, Swift, Kotlin); Adressierung über Public Keys; 95 % direkte Verbindungen; QUIC Multipath; kein Flottenmanagement eingebaut |
|
||
|
||
---
|
||
|
||
### L4 vs. L7 – was bedeutet das hier konkret?
|
||
|
||
**L4 (Transport):**
|
||
|
||
- IPSec Tunnel-Modus, OpenVPN, WireGuard und Tailscale operieren auf dieser Ebene oder darunter
|
||
- Das OS erhält ein virtuelles Interface (`wg0`, `tun0`) und routet IP-Traffic darüber
|
||
- Alle Anwendungen profitieren automatisch – keine Code-Änderung nötig
|
||
|
||
**L7 (Applikation):**
|
||
|
||
- Iroh arbeitet ausschließlich auf Applikationsebene
|
||
- Die Anwendung selbst öffnet eine Iroh-Verbindung (QUIC-Session) zu einem Remote-Node via dessen Public Key
|
||
- Kein System-Routing, kein Interface – die App muss Iroh aktiv nutzen
|
||
- Vergleichbar mit WebRTC: im Browser transparent, aber nur für eingebettete Anwendungen sinnvoll
|
||
|
||
---
|
||
|
||
### Wann welches Modell?
|
||
|
||
| Szenario | Empfehlung |
|
||
| -------- | ---------- |
|
||
| Site-to-Site zwischen Firewalls | IPSec (native OPNsense-Support) |
|
||
| Remote-Access für Mitarbeiter | Tailscale oder WireGuard |
|
||
| Self-hosted Mesh ohne SaaS | WireGuard + Netbird/Headscale |
|
||
| P2P in eigener Anwendung gebaut | Iroh |
|
||
| Gerät soll von überall erreichbar sein, ohne feste IP | Iroh oder Tailscale |
|
||
| Experimentelles dezentrales Netz | Yggdrasil |
|
||
|
||
---
|
||
|
||
## Teil 2 – Iroh-Integration in bestehendes Setup
|
||
|
||
### Ausgangslage
|
||
|
||
```
|
||
Internet
|
||
│
|
||
[OPNsense] ──── Firewall / Router
|
||
│
|
||
[Nginx] ──── Reverse Proxy (terminiert TLS, routet vhosts)
|
||
│
|
||
[Serving Host] ──── Anwendungsserver (bisher feste IP / internes Netz)
|
||
```
|
||
|
||
Das Problem: Der Serving Host muss derzeit über ein geroutetes Netz (VPN oder direkt) erreichbar sein. Ziel ist es, ihn **standortunabhängig** zu betreiben – ohne VPN-Konfiguration auf Netzwerkebene.
|
||
|
||
---
|
||
|
||
### Iroh-Konzept: Dial by Key, not by IP
|
||
|
||
Jeder Iroh-Node hat ein Ed25519-Schlüsselpaar. Der **Public Key ist die Adresse**. Solange ein Node seinen Relay kennt (oder direkten QUIC-Hole-Punch schafft), ist er erreichbar – unabhängig von Netzwerkposition, NAT oder dynamischer IP.
|
||
|
||
---
|
||
|
||
### Verfügbare Iroh-Tools (ohne eigenen Code)
|
||
|
||
| Tool | Funktion | Einsatzbarkeit |
|
||
| ---- | -------- | -------------- |
|
||
| **dumbpipe** | Bidirektionale Byte-Pipe zwischen zwei Iroh-Nodes (wie `nc` über Iroh) | Ja – als TCP-Tunnel mit socat kombinierbar |
|
||
| **sendme** | Einmalige Dateiübertragung | Nein – kein dauerhafter Dienst |
|
||
| **iroh-relay** | Eigener Relay-Server (DERP-ähnlich) | Ja – für selbst-gehostetes Setup |
|
||
|
||
**dumbpipe** ist die einzige Komponente, die einen dauerhaften Kanal aufbauen kann – aber sie überträgt einen Byte-Stream, kein TCP-Multiplexing. Für einen HTTP-Upstream im Nginx braucht man ein TCP-Forward-Setup.
|
||
|
||
---
|
||
|
||
### Architektur-Optionen
|
||
|
||
#### Option A: dumbpipe + socat als TCP-Proxy-Kette
|
||
|
||
```
|
||
[Client]
|
||
↓ HTTPS
|
||
[Nginx] → upstream: localhost:8080
|
||
↓
|
||
socat LISTEN:8080 → dumbpipe connect <serving-host-key>
|
||
↓ [Iroh-Netz]
|
||
dumbpipe listen → socat → localhost:3000 (App)
|
||
[Serving Host]
|
||
```
|
||
|
||
**Vorgehen:**
|
||
|
||
```
|
||
# Serving Host
|
||
dumbpipe listen | socat - TCP:localhost:3000
|
||
# → gibt Node-Key aus, z.B. "ki2..."
|
||
|
||
# Nginx-Host
|
||
socat TCP-LISTEN:8080,fork EXEC:"dumbpipe connect ki2..."
|
||
# Nginx: proxy_pass http://127.0.0.1:8080;
|
||
```
|
||
|
||
**Problem:** dumbpipe ist eine Single-Connection-Pipe, kein TCP-Listener. Für parallele HTTP-Verbindungen müsste man pro Request eine neue Pipe öffnen oder ein Connection-Multiplexer vorschalten. **Für produktiven Einsatz ungeeignet** ohne eigenen Code.
|
||
|
||
---
|
||
|
||
#### Option B: Eigenes Iroh-TCP-Forward-Tool (empfohlen)
|
||
|
||
Ein kleines Tool in Rust oder Python (ca. 100–200 Zeilen), das:
|
||
|
||
- **Serving Host**: Iroh-Endpunkt öffnet, akzeptiert Verbindungen, leitet an lokalen Port weiter
|
||
- **Nginx-Host**: Lauscht auf lokalem TCP-Port, öffnet pro Verbindung eine neue Iroh-QUIC-Stream
|
||
|
||
Iroh unterstützt nativ **multiple Streams pro Connection** (QUIC), daher skaliert das ohne Tricks.
|
||
|
||
```
|
||
[Nginx]
|
||
proxy_pass http://127.0.0.1:9080
|
||
↓
|
||
[iroh-forward-client] lauscht :9080, öffnet QUIC-Stream zu Serving Host
|
||
↓ QUIC / Iroh
|
||
[iroh-forward-server] auf Serving Host, leitet weiter an :3000
|
||
↓
|
||
[App]
|
||
```
|
||
|
||
Aufwand: \~1–2 Tage Entwicklung in Rust mit der `iroh`-Crate. Python-Bindings sind verfügbar, aber QUIC-Performance ist in Rust besser.
|
||
|
||
---
|
||
|
||
#### Option C: OPNsense bleibt unberührt, Iroh nur Nginx ↔ Serving Host
|
||
|
||
Dies ist das sauberste Setup: OPNsense braucht nichts von Iroh zu wissen. Der Iroh-Tunnel existiert **nur auf Applikationsebene** zwischen Nginx-Host und Serving Host.
|
||
|
||
```
|
||
Internet → OPNsense → Nginx (Port 443) → iroh-forward-client → [Iroh] → Serving Host
|
||
```
|
||
|
||
OPNsense sieht nur: Nginx-Host macht ausgehende QUIC-Verbindungen (UDP) zu Iroh-Relays. Kein eingehender Traffic auf dem Serving Host nötig.
|
||
|
||
---
|
||
|
||
### Credential-Verteilung
|
||
|
||
| Komponente | Credential | Wo gespeichert | Übergabe |
|
||
| ---------- | ---------- | -------------- | -------- |
|
||
| Iroh Node Key (Serving Host) | Ed25519-Keypair | `/etc/iroh/node.key` (Serving Host) | Public Key wird einmalig aus dem Log extrahiert |
|
||
| Iroh Node Key (Nginx-Host) | Ed25519-Keypair | `/etc/iroh/client.key` (Nginx-Host) | Automatisch generiert beim ersten Start |
|
||
| Serving Host Public Key | Public Key (String) | Nginx-Host Config / `.env` | Out-of-band: z.B. über Ansible/Vault, Gitea-Secret, o.ä. |
|
||
| Relay-URL | URL | beide Hosts | Im iroh-config oder Env-Variable |
|
||
| App-Credentials | DB-Passwörter etc. | Serving Host lokal | Unverändert – Iroh ändert nichts daran |
|
||
|
||
**Wichtig:** Der Public Key des Serving Host muss sicher und authentisch übertragen werden – er ist der einzige Vertrauensanker. Wird er kompromittiert (Man-in-the-Middle beim Austausch), kann ein Angreifer eine eigene Verbindung vortäuschen.
|
||
|
||
---
|
||
|
||
### Vor- und Nachteile
|
||
|
||
#### Vorteile
|
||
|
||
- **Standortunabhängigkeit**: Serving Host kann in Hetzner, Zuhause, AWS oder hinter CGNAT laufen – kein eingehender Port nötig
|
||
- **Kein VPN-Daemon**: Keine WireGuard-Konfiguration, keine IKEv2-PKI – Aufwand sinkt deutlich
|
||
- **OPNsense bleibt unberührt**: Firewall-Regeln, Routing-Tabellen – alles unverändert
|
||
- **Ende-zu-Ende-verschlüsselt**: TLS 1.3 über QUIC; Relay sieht nur verschlüsselte Bytes
|
||
- **Selbst-hostbarer Relay**: Kein SaaS-Abhängigkeit wie bei Tailscale; `iroh-relay` ist Open Source
|
||
- **Direkte Verbindungen** wo möglich: 95 % der Verbindungen gehen ohne Relay-Hop durch (Iroh-Angabe)
|
||
|
||
#### Nachteile
|
||
|
||
- **L7-only**: Nginx muss explizit konfiguriert werden; kein transparentes OS-Routing
|
||
- **Kein Flottenmanagement**: Key-Rotation, Revocation, Inventar – alles selbst gebaut
|
||
- **dumbpipe reicht nicht** für HTTP-Upstream: Eigene Entwicklung nötig (Option B)
|
||
- **QUIC-Firewall-Probleme**: Manche Netze blockieren UDP; WebSocket-Fallback existiert, aber nicht alle Clients unterstützen ihn
|
||
- **Relay-Abhängigkeit** bei symmetrischem NAT: Eigener Relay nötig für vollständige Unabhängigkeit
|
||
- **Fehlerdiagnose schwieriger**: Kein `tcpdump` auf dem Iroh-Interface; Debugging läuft über Iroh-eigene Logs
|
||
- **Nginx kennt keine echte Client-IP**: Bei Relay-Routing kommt Traffic von der Relay-IP; `X-Forwarded-For` muss manuell gesetzt werden
|
||
|
||
---
|
||
|
||
### Empfehlung
|
||
|
||
Für ein **produktives Setup** ist Option B (eigenes Iroh-Forward-Tool) der richtige Weg. Der Aufwand ist überschaubar und man bekommt ein sauberes TCP-Forwarding mit QUIC-Multiplexing, ohne auf dumbpipe-Hacks angewiesen zu sein.
|
||
|
||
Für einen ersten **Proof of Concept** reicht Option A mit dumbpipe + socat aus, um die Prinzipien zu validieren, bevor eigener Code entsteht.
|
||
|
||
OPNsense und Nginx müssen in keinem der Szenarien strukturell verändert werden – Iroh ist eine reine Ergänzung auf Applikationsebene.
|