Selbstverteidigung
Sicher im Internet mit eigenem VPN und ZeroTier-Gateway
Kommerzielle VPNs versprechen Schutz vor Attacken in unbekannten WLAN-Hotspots, doch manche VPN-Anbieter spionieren ihre Kunden selbst aus. Wir beschreiben, wie Sie mit ZeroTier und einem 5-Euro-vServer solch einen Dienst für Freunde und sich selbst aufsetzen.
ZeroTier ist ein modernes virtuelles privates Netz (VPN) auf Peer-to-Peer-Grundlage, mit dem man zum Beispiel ferne Geräte warten oder auf Freigaben zugreifen kann. Wie das geht, haben wir in c’t 7/23 ausführlich beschrieben. Dabei bilden die ZeroTier-Clients ein vom Internet abgetrenntes Mesh-VPN (auch Overlay-Netz genannt). Diese Grundarchitektur taugt nicht zum Schutz in WLAN-Hotspots, weil sie kein Gateway enthält, das den VPN-Verkehr ins Internet weitergibt. Aber den kann man mit etwas Aufwand nachrüsten. Dann können Sie zum Beispiel den Verkehr Ihres Notebooks in einem Hotel-WLAN verschlüsselt verschicken und erst im sicheren Hafen des von Ihnen gewählten Gateways ins Internet lassen.
Als Gateway eignen sich vServer mit Linux von Digital Ocean oder Hetzner; man bekommt sie für 4 bis 5 Euro monatlich. Dabei können die ZeroTier-Clients und das Gateway nicht nur das moderne IPv6-Protokoll tunneln, sondern auch das veraltete IPv4 (Dual-Stack).
Prinzipiell lassen sich solche Gateways auch mit WireGuard oder OpenVPN auf einem vServer aufsetzen. Mit ZeroTier klappt das einfacher, weil man die Client-Konfigurationen im Webinterface „ZeroTier Central“ zusammenklickt und dann über das ZeroTier-Backend automatisch verteilen lässt. Daher muss man die Clients nicht persönlich beehren, was Admins besonders bei späteren Änderungen, etwa am IP-Adressbereich oder an statischen Routen, sehr schätzen. Die Serverkonfiguration läuft freilich wie bei WireGuard und anderen im Terminal ab und erfordert einige Geduld und etwas Netzwerk-Know-how.
Außerdem kann man über ZeroTier Central globale IPv6-Adressen verteilen, was man nutzen kann, um auf Clients IPv6 nachzurüsten, falls der Provider noch nicht so weit ist. Dann sind Zugriffe auf ferne Clients möglich, die hinter DS-Lite-Anschlüssen nur per IPv6 erreichbar sind, obwohl der lokale Anschluss nur IPv4-Verkehr befördert.
Die Anleitung besteht aus drei Teilen: Gateway-Einrichten für IPv4 und IPv6 sowie Client-Konfiguration. Den Linux-Server konfigurieren Sie über eine Handvoll Konfigurationsdateien. Damit Sie nicht jeden Buchstaben selbst tippen müssen, haben wir unter ct.de/y9v8 Muster bereitgestellt, die Sie nur an wenigen Stellen an Ihre Umgebung anpassen müssen.
Der IPv4-Tunnel genügt für Clients, die nur per IPv4 ins Internet kommen (z. B. an DSL-Anschlüssen von Vodafone) und nur IPv4-Ziele ansprechen. Wenn die Clients ihren gesamten IPv4-Verkehr durch den Tunnel über das Gateway ins Internet schicken (Full-VPN), wird die öffentliche IPv4-Adresse des vServers zur Internetadresse des Clients.
Aber für Clients, die über Dual-Stack-Anschlüsse ins Internet kommen – also solche, die sowohl iPv4 als auch iPv6 befördern –, reicht der IPv4-Tunnel nicht aus. Denn wenn solche Clients Dual-Stack-Ziele ansteuern (z. B. Webseiten, die sowohl per IPv6 als auch per IPv4 erreichbar sind), dann bevorzugen sie für die Übertragung die globale IPv6-Adresse, die sie vom Provider erhalten haben und ignorieren den IPv4-Tunnel. Um dann allen Verkehr zu tunneln, muss man entweder – die weit schlechtere Lösung – IPv6 abschalten oder den Tunnel um IPv6 erweitern. Wir zeigen, wie Sie auch den IPv6-Verkehr in den Tunnel bringen.
vServer einrichten
Richten Sie nun einen neuen vServer ein. Bei Hetzner beispielsweise legt man dafür ein neues Projekt an und trägt einen Namen wie ZT-Router ein. Mit einem Klick auf „Server erstellen“ können Sie den Standort (z. B. Nürnberg) und andere Merkmale wählen. Die kleinste CPU und SSD genügen. 20 Terabyte Verkehr monatlich sind inklusive, was für kleine bis mittlere Arbeitsgruppen genügen sollte.
Wir haben die Anleitung mit einem vServer und aktuellem Debian-Linux ausprobiert. Stellen Sie sicher, dass IPv4- und IPv6-Adressen zugeteilt werden, laden Sie für die Fernwartung Ihren öffentlichen SSH-Schlüssel hoch und tragen Sie ganz unten den Servernamen ein, also etwa ZT-Router. Der Klick auf „Kostenpflichtig erstellen“ erzeugt die Serverinstanz; derzeit für 4,51 Euro monatlich.
Im Webinterface sind nun einige Statusmeldungen und die IPv4-Adresse des Servers aufgeführt (z. B. 198.51.100.11). Kopieren Sie diese, beenden Sie die Sitzung und wählen Sie sich per SSH auf dem neuen Server ein:
ssh root@198.51.100.11
Gateway im ZT-Netz
Aktualisieren Sie die Debian-Installation und installieren Sie die iptables-Firewall sowie die Pakete gpg und ndppd (NDP Proxy Daemon) mit den Kommandos, die nach diesem Absatz folgen. Die Firewall soll die Pakete der Clients zwischen der virtuellen ZeroTier- und der physischen Ethernet-Schnittstelle des vServers umschlagen. Gpg und ndppd sind für die ZeroTier-Installation und die IPv6-Routen erforderlich.
apt update apt full-upgrade apt install iptables iptables-persistent gpg ndppd
Falls noch nicht geschehen, legen Sie auf zerotier.com ein Konto an, melden Sie sich an und erzeugen Sie mit „Create A Network“ ein neues Netz. Installieren Sie dann den ZeroTier-Client auf dem vServer, indem Sie der Linux-Anleitung auf zerotier.com/download folgen. Fügen Sie dem Client Ihr ZT-Netz hinzu; kopieren Sie dafür die Netzwerk-ID aus dem ZeroTier-Webinterface heraus und setzen Sie sie in den folgenden Befehl anstelle von Network-ID ein:
zerotier-cli join Network-ID
Im ZT-Webinterface scrollen Sie nach unten zum Abschnitt Members, um den vServer zu finden. Erlauben Sie ihm den Zutritt. Tragen Sie dann im Webinterface seinen Namen ein (ZT-Router).
Tragen Sie dann im Bereich „DNS“ im Feld „Search Domain“ eine private Domain wie „lokal“ ein und im Feld „Server Address“ die IP-Adresse eines öffentlichen DNS-Resolvers ein, beispielsweise 9.9.9.9 vom gemeinnützigen Schweizer Unternehmen Quad9. So können Clients alle für den IP-Verkehr erforderlichen DNS-Anfragen über den Tunnel schicken.
IPv4-Router
Schalten Sie danach das Weiterleiten von IPv4- und IPv6-Paketen ein. Öffnen Sie dafür die Datei /etc/sysctl.conf mit dem Editor nano und entfernen Sie vor den Variablen net.ipv4.ip_forward und net.ipv6.conf.all.forwarding die Kommentarzeichen. Speichern Sie die Änderungen mit Strg+X und Strg+Y (Ctrl+X und Ctrl+Y auf einem Mac).
Laden Sie dann unsere Konfigurationsvorlagen von ct.de/y9v8 herunter. Die Datei heißt Gateway-Configs.zip. Wenn Sie sie im Download-Ordner entpackt haben, wechseln Sie im Terminal dorthin und bringen Sie die Regeln an ihren Platz:
cd ~/Downloads/Gateway-Configs cp ct-rules.v4 /etc/iptables/rules.v4 cp ct-rules.v6 /etc/iptables/rules.v6
Lesen Sie mit ip a die Namen des physischen und des ZT-Interfaces aus. Im Beispiel heißt das physische Interface eth0 und das ZT-Interface ztfp6bm43a. Tragen Sie dann beide in die IPv4-Firewall-Regeln anstelle der Platzhalter ein:
sudo nano /etc/iptables/rules.v4
Damit die Regeln wirksam werden, lesen Sie sie mit iptables-restore ein:
sudo iptables-restore /etc/iptables/rules.v4
Anschließend aktivieren Sie den iptables-Dienst und starten ihn mit dem Befehl systemctl:
systemctl enable iptables systemctl start iptables
Damit die Clients den Tunnel verwenden, muss man ihnen die richtige Route zum ZT-Client auf dem vServer mitteilen. Lesen Sie dafür zunächst die von ZeroTier zugeteilte private IPv4-Adresse des vServers aus und tragen Sie sie im ZT-Webinterface im Bereich „Managed Routes“ als IPv4-Route ein: Destination 0.0.0.0/0 via ZT-Adresse des vServers. Wenn Sie auf „Submit“ klicken, weist das Backend von ZeroTier die neue Route automatisch den angemeldeten ZT-Clients zu und erspart Ihnen diese Arbeit. Damit ist die Gateway-Konfiguration für IPv4 abgeschlossen.
IPv6-Router
Die IPv6-Regeln sind komplexer, denn die Clients benötigen für den Verkehr mit dem modernen Protokoll globale IPv6-Adressen aus dem Adressraum des vServers und die Route muss an mehreren Stellen gesetzt werden. Um beides einzurichten, liest man zunächst die globale IPv6-Adresse des vServers mit ip a aus; Sie finden sie in der Zeile, die mit „scope global“ endet. Ein Beispiel sieht so aus:
2001:db8:beef:beef::1/64 scope global
Hetzner teilt den vServern standardmäßig ein /64-Netz zu, also etwa 2001:db8:beef:beef::/64. Davon zwackt man einen kleinen Bereich (z. B. /80) für die ZT-Clients ab und trägt diesen in das ZT-Webinterface ein. Die Start- und Endadresse werfen Adressrechner wie https://www.gestioip.net/cgi-bin/subnet_calculator.cgi aus.
Bilden Sie zunächst ein /80-Teilnetz, indem Sie 1 an das vServer-Präfix anfügen. Wenn das /64-er Präfix Ihres Servers 2001:db8:beef:beef::1/64 lautet, dann sieht der /80-Teil so aus: 2001:db8:beef:beef:1::/80. Geben Sie das in den Subnet-Calculator ein und als „network range“ erscheint 2001:db8:beef:beef:0001:0000:0000:0000 und 2001:db8:beef:beef:0001:ffff:ffff:ffff.
Aktivieren Sie im ZT-Interface die Option „Auto-Assign from Range“ und tragen Sie die Adressen in die Felder „Range Start“ und „Range End“ ein. Klicken Sie dann auf „Submit“, um die Einstellungen zu übernehmen.
Weil die globalen IPv6-Adressen zu Hetzners Netzwerk und Routingbaum gehören, funktioniert die IPv6-Kommunikation mit anderen Internet-Hosts nicht ohne Weiteres. Dafür richten Sie zunächst für den Verkehr zwischen ZT-Clients und vServer eine statische IPv6-Route mittels einer Universal Local Address ein (ULA, beginnt mit „fd“). Die fd-Adresse des vServers finden Sie im ZT-Interface im Bereich Members, beispielsweise fd42:42ca:a427:b42c:9993:9422:7fd:91.
Die Route für den IPv6-Verkehr trägt man ebenfalls in „Managed Routes“ ein: Destination ::0/0 via fd42:42ca:a427:b42c:9993:9422:7fd:91. Klicken Sie auf „Submit“, damit das Backend die Route an die Clients weitergibt.
Als nächstes teilt man ZT das /80-Teilnetz des vServers mit, im Beispiel 2001:db8:beef:beef::/64. Dafür trägt man ebenfalls in „Managed Routes“ links im Feld „Destination“ das /80-Subnetz ein; das via-Feld rechts daneben bleibt leer. Klicken Sie zum Übernehmen auf „Submit“. Nach dem Übernehmen sollte ZT rechts neben dem IPv6-LAN ein Erdkugelsymbol einblenden, was so viel heißt wie „dieses Netzwerk verwendet globale IPv6-Adressen“.
Kehren Sie zurück zum Terminal und zur Server-Konfiguration. Damit das Gateway die für Clients bestimmten IPv6-Pakete aus dem Internet korrekt zustellt, setzt man im vServer die passende IPv6-Route zum ZT-Interface. Das erledigt das Bash-Skript zt-ipv6-route.sh. Damit das beim Booten automatisch passiert, legt man eine Systemd-Unit an.
Kopieren Sie dafür die Unit-Datei zt-ipv6-route.service aus ~/Downloads/Gateway-Configs in den Ordner /etc/systemd/system/, das Bash-Skript zt-ipv6-route.sh in den Ordner /usr/local/sbin und schalten Sie für das Skript das Ausführungsbit ein:
chmod +x /usr/local/sbin/zt-ipv6-route.sh
Lesen Sie mit ip a den Namen des ZT-Interfaces aus, zum Beispiel ztfp6bm43a. Suchen Sie mit dem Befehl systemctl nach dem ZT-Netzwerk-Device, das beim Systemstart hochgefahren wird:
systemctl list-units -a -t device | grep -i ztfp6bm43a
Im Beispiel heißt der Eintrag sys-devices-virtual-net-ztfp6bm43a.device. Ersetzen Sie in /etc/systemd/system/zt-ipv6-route.service den Device-Namen in den Zeilen „Requires“ und „After“ mit Ihrem Device-Namen. Ersetzen Sie in /usr/local/bin/zt-ipv6-route.sh das /80-Teilnetz und den ZT-Interface-Namen mit Ihren Daten. Aktivieren und starten Sie den Dienst:
systemctl enable zt-ipv6-route systemctl start zt-ipv6-route
Starten Sie den vServer neu und prüfen Sie mit sudo ip -6 route show, ob das Unit-File die Route zum /80-Teilnetz gesetzt hat. In der Ausgabe sollte das /80-Netz zusammen mit dem ZT-Interface in der zweiten Zeile erscheinen. Falls Sie von vorn beginnen müssen: eine fehlerhafte Route kann man so löschen:
sudo ip -6 route del 2001:db8:beef:beef:1::/80
Konfigurieren Sie nun die IPv6-Firewall-Regeln; das Muster steht bereits in /etc/rules.v6. Öffnen Sie diese Datei mit nano und ersetzen Sie darin das ZT-Interface und das Client-IPv6-Netz mit Ihren Angaben. Laden Sie die Regeln mit:
sudo ip6tables-restore /etc/iptables/rules.v6
Aktivieren und starten Sie die IPv6-Firewall:
systemctl enable ip6tables systemctl start ip6tables
Zum Schluss muss das vServer-Netz lernen, wie die Clients mit ihren globalen IPv6-Adressen erreichbar sind. Dafür kann man den IPv6-Dienst Neighbor Discovery Protocol (NDP) verwenden, der im Daemon ndppd implementiert ist. Er beantwortet auf dem vServer NDP-Anfragen für Ihr /80-Subnetz. Verfrachten Sie die von uns vorbereitete Konfiguration an Ihr Ziel:
cd ~/Downloads/Gateway-Configs cp ct-ndppd.conf /etc/ndppd.conf
Öffnen Sie /etc/ndppd.conf mit nano und ersetzen Sie darin in der Zeile „rule“ das /64-Teilnetz mit dem /64-Teilnetz, das der vServer verwendet und in der Zeile iface das ZT-Interface. Wenn Sie ndppd aktivieren und starten, ist das Gateway fertig eingerichtet:
systemctl enable ndppd systemctl start ndppd
Schnelle Testfahrt
Am schnellsten lässt sich der Tunnel auf Smartphones testen, auch wegen der grafischen Bedienoberfläche. Installieren Sie ZT und bringen Sie den ZT-Client ins ZeroTier-Netz. Aktivieren Sie die Option „Enable Default Route“ und rufen Sie im Browser die Webseite ct.de/ip auf. Wenn das Routing wie geplant funktioniert, sollte die Webseite als Anfragequelle entweder die IPv4-Adresse des vServers oder eine globale IPv6-Adresse des Clients zeigen, die aus dem /80-Netz des vServers stammt.
Im mehrwöchigen Test hat das ZT-VPN zuverlässig funktioniert, sowohl auf Smartphones als auch Notebooks mit Linux, macOS und Windows. Etwas lästig ist nur, dass die ZT-Clients umständlich über Menü- oder Kommandozeilenabfragen zeigen, ob aller Verkehr durch den Tunnel geht oder nur der Teil, der für das ZT-Netz eingerichtet ist. Immerhin kann man aber zwischen den beiden Modi schnell umschalten. (dz@ct.de)
ZT- und vServer-Infos: ct.de/y9v8