Ein Weg aus dieser Workstation ist ein SOCKS-Proxy, und OpenVPN dahinter meldet einen Verbindungs-Timeout ohne brauchbare Angaben. Ein Browser auf derselben Maschine arbeitet über diesen Proxy, die Zugangsdaten stimmen, und der Port antwortet. Drei Dinge weichen oft genug ab, um sie zuerst zu prüfen: die SOCKS-Version, die der Proxy spricht, der Transport, den der Client gewählt hat, und wo die Namensauflösung stattfindet. Bestätigen Sie jedes davon, bevor Sie die Firewall verantwortlich machen.

Die SOCKS-Version vor der Firewall abgleichen

Community-OpenVPN spricht SOCKS5 für socks-proxy. Richten Sie es auf einen Proxy, der nur SOCKS4 anbietet, öffnet sich die TCP-Verbindung und bleibt dann hängen, weil der Client auf eine Antwort auf eine Begrüßung wartet, die die Gegenseite nie parst. Von außen sieht dieses Hängen genau wie ein gefilterter Port aus, weshalb die Versionsfrage vor jeder Firewall-Regel kommt. Ein SOCKS-fähiger Abruf klärt das mit einem Befehl.

curl --socks5-hostname 127.0.0.1:9050 gw.lab.example

Eine abgeschlossene Anfrage beweist zwei Dinge zugleich: Der Proxy hat die SOCKS-Anfrage angenommen, und er hat den Namen aufgelöst. Kein URL-Schema ist nötig, weil curl einen bloßen Host als HTTP behandelt, was für diesen Test ausreicht.

Dieser Abruf schließt auch den Fehler aus, den das Client-Log verbirgt. Ein Proxy kann den Browser zulassen und das VPN-Ziel trotzdem ablehnen; dann geschieht die Ablehnung bei CONNECT, vor jeder VPN-Authentifizierung. OpenVPN meldet nur einen Timeout, also ist die Antwort des Proxys selbst der Beweis, den Sie brauchen.

Der Transport muss auf beiden Seiten TCP sein

SOCKS5 trägt hier einen TCP-Strom, also braucht der Tunnel selbst proto tcp-client. Ein Profil, das noch auf UDP steht, funktioniert über diesen Weg nicht, weil der Client den UDP-Association-Modus des Protokolls nicht nutzt. Das Profil umzustellen ist eine echte Änderung und keine Formalität: Die Gegenseite muss auf demselben Port auf TCP lauschen. Die Nutzlast wird dann TCP in TCP, wo ein verlorenes Segment zweimal neu übertragen wird und das Tempo sinkt, was interaktive Sitzungen weit stärker bemerken als große Übertragungen.

proto tcp-client
remote gw.lab.example 8443
socks-proxy 127.0.0.1 9050

Die Direktive nimmt den Proxy-Host, einen optionalen Port und eine optionale Datei mit Zugangsdaten. Legen Sie diese in das Profil selbst, damit sich eine Kopie anderswo identisch verhält.

Die ganze Kette in einen Container einsperren

Die Kette auf dem Host zu betreiben heißt, seine Standardroute zu übernehmen und den Resolver in einem Zustand zu hinterlassen, den später niemand erklären kann. Ein Namespace oder ein Container begrenzt sie stattdessen, sodass der Host seinen eigenen Weg behält, während SOCKS-Hop und Tunnel zusammen leben. Darin kommt nichts hoch ohne ein Tunnelgerät, die Rechte zum Konfigurieren dieses Geräts und einen erreichbaren Proxy. Ein Compose-Dienst bekommt das mit cap_add: NET_ADMIN und einem eingebundenen /dev/net/tun.

cap_add:
  - NET_ADMIN
devices:
  - /dev/net/tun:/dev/net/tun

Dieses Paar ist enger als der privilegierte Container und umfasst den gesamten nötigen Gerätezugriff. Ein Tor-Client oder ein separater Proxy-Container kann den Listener bereitstellen. Binden Sie ihn in jedem Fall an Loopback und erreichen Sie ihn aus dem Namespace über den Host, statt den Proxy ins Netzwerk zu stellen.

Die Namensauflösung ist der Punkt, an dem die Isolierung scheitert

Ein Tunnel, der Pakete trägt und dabei den Resolver des Hosts fragt, hat nichts isoliert. Zwei Dinge machen die Isolierung echt: Der Namespace hat einen eigenen Resolver, und seine Abfragen laufen über den Proxy oder den Tunnel, nie über die physische Schnittstelle. Verwenden Sie zwei Namen für den Test: einen, der nur hinter dem Tunnel existiert, und einen öffentlichen, der demselben Weg folgen sollte.

docker compose exec vpn cat /etc/resolv.conf
docker compose exec vpn getent hosts internal.lab.example

Löst der Name der Gegenseite auf und der öffentliche nicht, ist die Kette selektiv statt defekt, und der Unterschied sagt Ihnen, welchen Weg jede Abfrage genommen hat. Lösen beide vom Host auf, aber keiner im Container, leiht der Container noch den Resolver des Hosts. Notieren Sie die gefundene Resolver-Datei, denn das ist die Einstellung, die sich ändern muss.

Jeden Hop der Reihe nach beweisen

Die Liste ist kurz. Eine SOCKS5-Anfrage bekommt eine Antwort, der Tunnel erreicht seinen Listener über den Proxy, und Pakete, die den Namespace verlassen, tragen die Adresse, die die Gegenseite erwartet. Bestätigen Sie jede einzeln, statt weitere Konfiguration zu stapeln. Wenn der Client „verbunden“ meldet und sich nichts bewegt, steckt der Bruch fast immer in der zweiten oder dritten Tatsache.

curl --socks5-hostname 127.0.0.1:9050 gw.lab.example
docker compose exec vpn ip route get 203.0.113.10
docker compose exec vpn getent hosts internal.lab.example

Notieren Sie die Kombination, die funktioniert hat: SOCKS-Version, Transport, Resolver und Namespace-Einstellungen. Diese Kette ein zweites Mal aus dem Kopf zu lösen kostet mehr als die Notiz. Halten Sie die vier Fakten im Ticket fest, nicht in einem Chat-Verlauf.

Eine Kette, die „verbunden“ meldet und nichts durchlässt, ist meist an dem Hop gescheitert, den Sie noch nicht bewiesen haben. Testen Sie diesen Hop, bevor Sie eine weitere Schicht hinzufügen.

Ähnliche Artikel