OpenVPN-Client hängt, wenn sein Server auf demselben Host läuft
Zwei OpenVPN-Instanzen auf einem Host streiten um denselben lokalen Port und dieselbe Routing-Tabelle. Legen Sie den Port fest, trennen Sie die Geräte und prüfen Sie, welche Tabelle gewinnt.
Ich hatte eine Laborbox, die einen Tunnel von einem entfernten Standort annahm und zugleich zu einem Anbieternetz wählte. Das ausgehende Profil hatte wochenlang funktioniert. Nachdem der eingehende Server hinzugefügt wurde, verband sich der ausgehende und hörte dann innerhalb von Sekunden auf, Datenverkehr durchzuleiten, oder er verweigerte den Start mit einem Fehler, dass die Adresse bereits verwendet wird. Die Konfigurationsdateien hatten sich nicht geändert; der Host hatte einfach einen zweiten OpenVPN-Prozess mit eigener Meinung zu Ports und Routen bekommen.
Der Fehler ist nicht zufällig, und er ist kein Authentifizierungsproblem. Zwei Daemons auf einer Maschine konkurrieren um denselben lokalen Socket und dieselbe Routing-Tabelle, und wer zuletzt startet oder sich neu verbindet, gewinnt meist. Zu wissen, welche dieser beiden Kollisionen vorliegt, entscheidet, wo man zuerst nachsieht.
Lesen Sie das Symptom rückwärts
Beginnen Sie damit, wann der Tunnel stirbt. Ein Bind-Fehler beim Start zeigt auf die Lauschenseite: Etwas besitzt den Port bereits, und OpenVPN weigert sich zu starten, statt ihn zu teilen. Ein Tunnel, der hochkommt und dann verstummt, zeigt auf das Routing, weil eine von der anderen Instanz installierte Route die Pakete der äußeren Verbindung von ihrem Pfad abbringen kann.
Beide Fälle erzeugen dieselbe Beschwerde des Nutzers, weshalb Wiederholungsschleifen und Watchdog-Skripte nichts reparieren. Sie verbinden den Client wieder in denselben Konflikt. Die nützliche erste Frage ist, ob der Prozess noch läuft, wenn der Verkehr stoppt.
Ein Socket und ein Gerät pro Instanz
Ein lauschender Server bindet seinen Port; ein ausgehender Client braucht ebenfalls einen lokalen Port für seinen gekapselten Verkehr. Wenn beide auf demselben Host leben, kann das Standardverhalten des Clients mit dem Port des Servers kollidieren. Der lokale Port des Clients lässt sich festlegen, und das Binden kann übersprungen werden, wo die Gegenseite keinen festen Quellport benötigt:
lport 1195
nobind
dev tun1Diese Zahlen sind Beispiele, keine Vorgabe. Entscheidend ist, dass der Client aufhört, um den Port des Servers zu konkurrieren, und dass jede Instanz ein eigenes Tunnelgerät bekommt. Zwei Daemons, die tun0 teilen, überschreiben den Gerätezustand des jeweils anderen, selbst wenn ihre Ports unterschiedlich sind, also ist ein Gerät pro Tunnel nicht optional.
nobind gehört zur Clientseite. Ein Server muss weiterhin binden und lauschen, kopieren Sie die Zeile also nicht in die Serverkonfiguration, und deaktivieren Sie das Binden nicht bei einem Client, dessen Gegenseite auf einen festen Quellport filtert.
Wählen Sie einen Eigentümer für die Standardroute
Nur eine Verbindung kann eine Standardroute installieren. Wenn beide Profile den gesamten Verkehr umleiten, ersetzt die zweite Verbindung still die erste, und die erste scheint zu brechen. Entweder halten Sie den ausgehenden Tunnel geteilt und schieben nur die Anbieterpräfixe, oder Sie geben ihm eine eigene Routing-Tabelle.
ip rule add from 10.9.0.2 table 120
ip route add default dev tun1 table 120
ip route get 10.9.0.2Die Adressen und die Tabellennummer oben sind Platzhalter. Bestätigen Sie unmittelbar nach dem Hinzufügen der Regel, dass die eigene Adresse des VPN-Servers noch über die normale Tabelle aufgelöst wird; eine Tabelle, die den äußeren Transport einfängt, bricht den Tunnel, den sie schützen sollte, und die folgende Wiederverbindungsschleife wirkt wie ein unzuverlässiger Anbieter.
Für ein Setup, das Wiederverbindungen und Neustarts überstehen muss, ist ein Netzwerk-Namespace die robustere Grenze. Der zweite Client läuft in seinem eigenen Namespace mit eigenen Schnittstellen und Routen, und nur die Dienste, die die Grenze überqueren müssen, werden exponiert. Der Host behält eine Standardroute, und eine Namespace-Wiederverbindung kann sie nicht überschreiben.
Prüfen Sie mit der Tabelle, nicht mit der Statuszeile
Ein Client, der verbunden meldet, beweist nur seinen Steuerkanal. Erfassen Sie den Routing-Zustand vor und nach jeder Verbindung und fragen Sie dann den Kernel, welches Gerät ein echtes Ziel verwenden würde:
ip route show
ip route get 10.40.0.20
ss -lunp | grep 1194Wenn sich das ausgewählte Gerät für die Anbieteradresse ändert, wenn der zweite Tunnel startet, haben Sie die Routen-Kollision. Wenn beide Prozesse auf demselben lokalen Port erscheinen, haben Sie die Socket-Kollision. Das erste ohne das zweite zu beheben, verschiebt den Fehler nur auf die nächste Wiederverbindung.
Schreiben Sie Ports, Geräte, Tabellen und Routeneigentümer in das Runbook des Hosts. Sonst wird die nächste Person, die einen dritten Tunnel hinzufügt, dieselbe Kollision neu entdecken, und der einzige sichtbare Beweis wird eine Verbindung sein, die funktioniert, bis der Daemon von jemand anderem neu startet.