# 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 ↓ [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.