Wie ein OpenVPN-Client hinter NAT zum Internet-Ausgang wird
Der Ausgang wählt selbst nach außen, sein Router braucht also keinen eingehenden Port. Verfolgen Sie, was der Hub routet, was der Ausgang weiterleitet und woher der Rückweg kommt.
Drei Linux-Hosts, ein Entwurf: ein öffentlich erreichbarer OpenVPN-Hub, ein Verbraucher-Laptop und eine Ausgangsmaschine hinter einem gewöhnlichen Heimrouter, der nichts nach innen weiterleitet. Der Ausgang wählt sich selbst beim Hub ein. Der Internetverkehr des Verbrauchers gelangt dann am Laptop in den Tunnel und verlässt ihn über den eigenen Uplink des Ausgangs. Alles Überraschende an diesem Aufbau folgt aus einem Detail: Der Ausgang hat die Verbindung aufgebaut, also existiert der Weg nach innen bereits, und es ist keine Portweiterleitung nötig, um ihn zu schaffen.
Das Folgende verfolgt den Paketweg statt die Konfigurationsreihenfolge, denn die Konfiguration ergibt erst Sinn, wenn man weiß, welche Komponente welche Entscheidung trifft. Jede Schicht trifft genau eine Entscheidung, und die Fehler sammeln sich dort, wo zwei Schichten für eine gehalten werden.
Zwei Transportsitzungen, ein innerer Pfad
Jeder Host hält seine eigene äußere Verbindung zum Hub, und keine davon weiß von der anderen. Der Verkehr des Verbrauchers ins Internet ist ein getrennter innerer Fluss, der zufällig im Tunnel des Verbrauchers transportiert und dann aus dem Tunnel des Ausgangs erneut ausgesendet wird. Diesen inneren Fluss muss der Hub routen, und ihn muss der Ausgang weiterleiten.
outer: consumer --TLS--> hub
outer: exit --TLS--> hub
inner: consumer --tun--> hub --internal--> exit --tun--> uplink
Da beide äußeren Verbindungen von der Clientseite ausgehen, sieht der Router des Ausgangs nie ein eingehendes SYN und braucht nie eine Destination-NAT-Regel. Er muss nur den aufgebauten Transport am Leben halten, was er für jede langlebige Verbindung ohnehin tut. Nichts im öffentlichen Internet muss den Ausgang zuerst erreichen, deshalb ist eine dynamische Adresse auf diesem Uplink kein Problem. Der Router muss die ausgehende Sitzung weiterhin erlauben, aber das ist dieselbe Erlaubnis, die ein Browser bereits nutzt.
Was iroute tatsächlich im Server installiert
Der Hub ist das einzige Gerät, das entscheidet, welcher Peer welches Ziel besitzt, und er trifft diese Entscheidung in seiner eigenen Userspace-Routingtabelle, nicht in der des Kernels. Ein client-config-dir-Eintrag für den Ausgang namens exit-node kann dort das Standardpräfix beanspruchen:
# /etc/openvpn/server/ccd/exit-node
iroute 0.0.0.0 0.0.0.0
Diese Zeile sagt dem Serverprozess: "Innere Pakete mit beliebigem Ziel gehören diesem Client". Sie fügt dem Betriebssystem des Hubs keine Standardroute hinzu und macht den Hub nicht zu einem Internet-Gateway. OpenVPN-2.6-Referenz hält client-spezifisches internes Routing und Kernel-Routing als getrennte Mechanismen, und genau diese Trennung ist der Grund, warum der Entwurf funktioniert, ohne die Standardroute des Hubs anzutasten.
Der Verbraucher braucht die spiegelbildliche Anweisung, als Push zugestellt, damit sein eigener Verkehr in den Tunnel geht statt über sein lokales Gateway zu verlassen. Bei Subnetz-Topologie ist der Pool eine verbundene Route auf dem tun-Gerät des Ausgangs, also braucht die Rückrichtung keinen zusätzlichen Push; was der Ausgang nicht erhalten darf, ist die Umleitung unten, die seinen eigenen Uplink-Verkehr zurück in den Tunnel schicken würde, den er nutzen will. Senden Sie sie nur an den Verbraucher und lesen Sie die angewandten Routen auf dem Client, statt darauf zu vertrauen, dass die CCD-Datei ausgewählt wurde.
# /etc/openvpn/server/ccd/consumer-01
push "redirect-gateway def1"
Der Kernel des Ausgangs übernimmt die Weiterleitung
Im Ausgang trifft ein Paket vom Verbraucher auf dem tun-Interface ein, adressiert an irgendeinen Internet-Host. Der Kernel konsultiert seine Routingtabelle, findet den echten Uplink als beste Übereinstimmung und wendet dann zwei unabhängige Richtlinien an: Darf dieses Paket überhaupt weitergeleitet werden, und darf es über dieses Interface mit dieser Quelladresse hinaus. Weiterleitung ist ein sysctl und bei vielen Distributionen standardmäßig aus.
Der Ausgang braucht also dauerhaft aktivierte IPv4-Weiterleitung, eine Weiterleitungsregel, die die Tunnelquellen des Verbrauchers zum Uplink zulässt, und den Antwortweg zurück durch das tun. Weiterleitung für den ganzen Host zu aktivieren ändert auch das Verhalten alles anderen, was durch ihn routet, deshalb sollte die Regel Quellen und Interfaces benennen statt alles zu akzeptieren.
Der Rückweg wird durch Quellübersetzung erkauft
Ein Internet-Host hat keine Route zu einer 10.90.0.x-Adresse, also würden Antworten verworfen, bevor sie den Ausgang je erreichen. Die Quelle umzuschreiben, während das Paket den Uplink verlässt, löst das, und Connection Tracking macht das Umschreiben auf dem Rückweg rückgängig.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 10.90.0.0/24 -o enp1s0 -j MASQUERADE
ip -4 route get 10.90.0.9 # run on the exit: must point at the tun
Die Regel oben ist ein Ausgangspunkt für ein Uplink-Interface, keine Firewall-Richtlinie. Verengen Sie die Quelle auf die Zuweisungen, die Sie tatsächlich autorisiert haben, und halten Sie die eigene Eingangsrichtlinie des Ausgangs getrennt, damit das Maskieren von Tunnelverkehr nicht stillschweigend lokale Dienste offenlegt. Auf einem Host mit dynamischer Uplink-Adresse erspart Ihnen das Maskieren auch die manuelle Verfolgung der Adresse.
Wo der Hub durchsetzen kann und wo nicht
Mit client-to-client und dem traditionellen Userspace-Datenpfad übergibt der Hub innere Pakete zwischen Peers innerhalb des Serverprozesses. Sie durchlaufen nie die FORWARD-Kette des Hub-Kernels, also kann eine Kernel-Regel dort den Peer-zu-Peer-Transit nicht einschränken, so sorgfältig sie auch geschrieben ist. Durchsetzung muss in der eigenen Richtlinie des Servers liegen: wer sich verbinden darf, welche CCD-Datei er bekommt und ob der Standardbesitz des Ausgangs überhaupt gewährt wird.
Deshalb ist ein Standard-iroute eine breite Vertrauensentscheidung. Der Ausgang muss Rückverkehr von beliebigen Internetadressen legitim annehmen, und er muss eine Maschine sein, die Sie kontrollieren, patchen und überwachen. Demselben Besitz einem Peer zu geben, dem Sie keinen Router anvertrauen würden ist der Fehler, zu dem dieser Entwurf einlädt.
Mitgliedschaft ist die eigentliche Kontrolle. Jeder Client, der seine eigenen Routen konfigurieren kann, kann versuchen, den Ausgang zu nutzen, deshalb ist die Beschränkung, wer sich verbinden darf oder welchen Peers der Ausgang dient, Teil des Entwurfs und kein Nachgedanke.
Sicher scheitern, wenn der Ausgang verschwindet
Nehmen Sie den Ausgang offline, und der interne Standardbesitz verschwindet mit seiner Sitzung. Was nicht passieren darf, ist, dass der Hub stillschweigend zum Ersatzausgang wird: keine Standardroute aus dem VPN-Pool in den Uplink des Hubs und keine breite Maskerade-Regel auf dem Hub, die denselben Verkehr bereitwillig weiterleiten würde. Testen Sie dieses Scheitern absichtlich und danach die Wiederherstellung mit einem frischen Fluss statt mit einer bereits offenen Seite.
# on the consumer, with the exit up and then down
ip -4 route get 1.1.1.1
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com
Wenn der Verkehr des Verbrauchers nach dem Verschwinden des Ausgangs noch ins Internet gelangt, trägt ihn etwas anderes, und die beabsichtigte Grenze existiert nicht. Behandeln Sie auch DNS und IPv6 als getrennte Entscheidungen: Eine IPv4-Route plus Maskerade sagt nichts über AAAA-Verkehr, und ein vom Hub geschobener Resolver antwortet von dort, wo die Anfrage tatsächlich hinausgeht.