Linux

Zusammenlegung zweier LANs

mithilfe von VPN über ein Trägernetz

Einleitung

In der heutigen Zeit sind Internet und der damit verbundene Datenaustausch nicht mehr wegzudenken. Viele Anwender gehen dazu über, Schnittstellen, wie FTP-, Streaming- und SMB-Server aufzusetzen, um Daten auszutauschen. Für reinen Datenaustausch kann man sich dieser Methoden einfach bedienen.
Geht es aber darum, an sensiblen Projekten und von verschiedenen Standorten aus zu arbeiten, kommt man mit dem reinen Portforwarding nicht weiter. Hier soll eine Alternative auf der Basis eines virtuellen privaten Netzwerkes dargestellt werden.

Motivation

Virtuelle private Netzwerke werden schon seit geraumer Zeit für vereinfachten Datenaustausch verwendet. Es wird jedoch eine stabile, nicht kommerzielle Variante gesucht, die ausnahmslos alle Netzwerkgeräte unterstützen kann, ohne dass jedes Gerät dafür konfiguriert werden muss.
Außerdem ist die Tatsache sehr störend, dass manche Programme oder Anwendungen Virtuelle Geräte, welche bei einer VPN-Verbindung erstellt werden, nicht richtig erkennen oder nutzen. Die Lösung dieses Problems wird durch die Verbindung der beiden privaten Netzwerk zu einem gemeinsamen Netz erreicht.

Problemstellung

Ausgehend von den genannten Tatsachen wurden die folgenden Rahmenbedingungen für das Projekt festgelegt:
Es gilt eine stabile, möglichst wartungsfreie Verbindung zwischen den beide Netzen herzustellen. Bei Ausfall eines Netzes soll das Andere noch problemlos funktionieren.
Es soll möglich gemacht werden, auf Netzwerkgeräte des jeweils anderen Netzes ohne Umwege zuzugreifen.

Ansatz

Wir entschieden uns für eine Variante, bei der auf beiden Seiten eine Bridge zwischen der lokalen und der virtuellen Schnittstelle des VPNs erstellt wird. Eine geroutete Verbindung kommt nicht in Frage, da auf der einen Seite der Router nicht dafür konfiguriert werden kann. Es wurden zwei Rechner ausgewählt, die im jeweiligen Netz dafür online sind. Aus Sicherheitsgründen wird das Betriebssystem Linux verwendet. Außerdem erweist sich Linux, bei Netzwerkeinrichtungen, um einiges umgänglicher als Microsoft Windows. Als Distribution wird Gentoo verwendet. Konfigurationsdateien und Systembedienungshinweise in dieser Dokumentation werden sich auf Gentoo-Linux beschränken. Sollten einige Beispiele bei anderen Distributionen grundlegend anders sein, wird das Äquivalent von Debian-Linux als Beispiel dargestellt.

Netzaufbau

Der folgende Netzwerkplan zeigt die beiden vorhandenen Netze vor dem Aufbau des VPNs.

Netzplan vor der Umstrukturierung

Um sich in der IP-Adress-Vergabe nicht beschränken zu müssen, haben wir die Subnetmaske von 255.255.255.0 auf 255.255.254.0 abgeändert. Damit die Netzwerke auch im selben Subnet sind, musste das LAN 1 von 192.168.116.0/24 auf 192.168.223.0/23 und das LAN 2 von 192.168.222.0/24 auf 192.168.222.0/23 abgeändert werden.

Netzplan nach der Umstrukturierung

Die Adressvergabe wird so geregelt, dass, wenn man am Standort LAN 2 eine IP bezieht, eine aus dem Pool 192.168.223.0/23 erhält und äquivalent am Standort LAN 1 eine aus dem Pool 192.168.222.0/23. Als Routing- und DNS-Informationen werden jeweils die des aktuellen Standortes übergeben.

VPN Grundlagen

VPN wird dazu benutzt, um in einem Netzwerk ein unabhängiges, eigenes Netzwerk zu erstellen. Dieses kann verschlüsselt sein.

VPN-Unterschiede

Es gibt mehrere, technische und logische Arten von VPNs.

Logische Unterschiede:

site-to-site

Dieser Aufbau verbindet zwei benachbarte Netze über ein Trägernetz miteinander. Diesen nennt man site-to-site. Die Teilnehmer der Netze haben somit die Illusion, direkt in einem Netz verbunden zu sein.

end-to-end

Eine andere Möglichkeit ist, die sogenannte end-to-end Verbindung. Jeder Teilnehmer in diesem Aufbau, hat eine eigene Verbindung mit dem VPN-Server. Auch hier können alle Teilnehmer so miteinander kommunizieren, als wären sie physikalisch in einem Netzwerk. Es kann allerdings am Server eingestellt werden, ob die Clients miteinander kommunizieren dürfen. Ist dies nicht der Fall, können Clients nur auf die Ressourcen zugreifen, die der Server freigibt.

Diese beiden logischen Aufbauten können auch gemischt werden.

Gemischter Aufbau

Technische Unterschiede:
Die zwei wichtigsten und meist benutzten Arten von VPNs, ist der Aufbau mit IPsec und TLS/SSL.
Der Unterschied ist, dass IPsec, im Gegensatz zu TLS/SSL, direkt in der Vermittlungsschicht (Schicht 3 des OSI-Referenzmodels) arbeitet. TLS/SSL arbeiten oberhalb der Transportschicht (>Schicht 4 des OSI-Referenzmodel).

Verbindung vom Netzwerk zum VPN

Hier entscheidet sich, wo und womit die VPN-Verbindung aufgebaut wird. Ist es der Router an sich, so wird die erste Methode, das Routing verwendet. Hierbei wird in der Konfigurationsdatei als Device-Type tun verwendet. Wird die VPN-Verbindung hinter einem Router erstellt, wird im Allgemeinen eine Bridge verwendet. Für eine Bridge muss die Virtuelle Netzwerkschnittstelle vom Typ tap sein. Bei dem geroutetem VPN, wird das Virtuelle VPN-Netzwerkgerät zu dem Hardwaregerät, oder einem anderen, virtuellen Netzwerkgerät geroutet. Dieses geschieht auf der Vermittlungsschicht (Schicht 3 des OSI-Referenzmodell), mithilfe von sogenannten Routingtabellen. Der große Nachteil ist, dass die angeschlossenen Geräte sich nicht ''sehen'' können.
Die Bridge hingegen arbeitet auf der Sicherungsschicht (Schicht 2 des OSI-Referenzmodell). Hier wird eine Virtuelle Bridge erstellt ( brctl addbr ).
Mit brctl addif wird die reelle oder Virtuelle Netzwerkschnittstelle ifname zur Bridge brname hinzugefügt.

Implementierung

Wir haben uns für die freie VPN-Software, OpenVPN entschieden, da diese auf den meisten Betriebssystemen installierbar ist, beziehungsweise auf vielen zu erwerbenden Netzwerkgeräten entweder vorinstalliert oder nachträglich zu installieren ist. Dieser Umstand macht dieses VPN auch fähig, einzelne site-to-end Verbindungen zu erlauben.
Die Bridges werden über die bridge-utils der verwendeten Distributionen, hier auf Client- und Serverseite Gentoo, eingestellt. Da es sich bei OpenVPN um eine Anwendung handelt, die auf der Serverseite von außen immer erreichbar sein muss, wird empfohlen, immer die aktuellsten Versionen des Programms und die zur Verschlüsselung genutzten SSL-Libraries installiert zu haben.

TCP/UDP

OpenVPN bietet an, entweder das Protokoll TCP oder UDP zur Übertragung zu nutzen. In unserer Testphase fiel uns auf, dass die Verbindung mit UDP nach einigen Minuten abbrach und das VPN sich neu verbinden musste. Unsere Überprüfung hat ergeben, dass die Datenpakete der VPN-Verbindung in falscher Reihenfolge eintrafen. Aufgrund der von OpenVPN verwendeten Verschlüsselung (MAC), verlangte der OpenVPN-Server den erneuten Austausch der Schlüssel.
Um dieses Phänomen zu testen, haben wir eine VPN-Verbindung über UDP in einem LAN aufgebaut. Diese Verbindung blieb stabil und es wurde keine erneute Verbindung erzwungen. Anfragen bei dem ISP haben uns bei dem Problem nicht weitergeholfen. Aus diesem Grund stellt unser System die Verbindung über das TCP her.
Im Gegensatz zu UDP baut TCP vor Übertragen von Daten eine Verbindung auf. Deshalb wird TCP zu den verbindungorientierten Protokollen gezählt. Durch den sogenannten HandShake wird die Verbindung etabliert. Dieses Verfahren sichert den Datenstrom so ab, dass er beim Empfänger fehlerfrei zusammengesetzt wird. Nachteil diese Verfahrens ist, dass durch Zusatzinformationen und dem Aushandeln der Verbindung, der Bandbreitenverbrauch zunimmt, also die Verbindung langsamer wird.

Konfiguration

Zunächst wird auf beiden Seiten, der Einfachheit halber, eine Virtuelle TAP-Schnittstelle, welche beim Booten gestartet wird, erstellt.

# cd /etc/init.d/
# ln -s net.lo net.vpn
# rc-update add net.vpn default

Diese Virtuelle Schnittstelle erfordert, dass sie in die Netzwerkkonfigurationsdatei eingestellt wird.
Ebenso werden auf Client- und Server-Seite die Bridges in die Netzkonfig. eingetragen und entsprechend beim Boot aktiviert. Konfigurationsbeispiele finden sich im Anhang. Die Bridge wird genau wie die VPN-Schnittstelle zum Bootvorgang hinzugefügt.

# rc-update add net.xbr0 default

Serverseite

Auf der Serverseite werden in diesem Fall alle Schlüssel generiert. Das OpenVPN-Paket liefert einige Scripte zur Zertifikatserstellung mit. Im Konfigurationsordner erstellen wir zunächst den Ordner für die Key-Erstellung. Danach wird die Datei mit den benötigten Umgebungsvariablen kopiert und die Scripte symbolisch verlinkt.

# cd /etc/openvpn
# mkdir easy-rsa
# cd easy-rsa
# cp -v /usr/share/openvpn/easy-rsa/vars ./
# ln -sv /usr/share/openvpn/easy-rsa/{build-ca|build-key|build-dh|build-key-server|clean-all|pkitool|openssl.cnf}

Die Datei vars (/etc/openvpn/easy-rsa/vars) wird nun, den Ansprüchen entsprechend, editiert.

export EASY_RSA="`pwd`"
export KEY_CONFIG="$EASY_RSA/openssl.cnf"
export KEY_DIR="$EASY_RSA/keys"
export KEY_SIZE=2048 # 1024 wäre als Key-Grösse etwas zu unsicher, 4096 wäre paranoid.
export CA_EXPIRE=9999
export KEY_EXPIRE=9999
export KEY_COUNTRY="DE"
export KEY_PROVINCE="Niedersachsen"
export KEY_CITY="Emden"
export KEY_ORG="TestSystem"
export KEY_EMAIL="root@testnetz"

Als nächster Schritt wird die Certificate-Authority erstellt. Dieser Schlüssel ist der wichtigste im gesamten Verschlüsselungsverfahren. Je nachdem wie sicher das VPN-System sein muss, wird dieser Schlüssel auf einem externen Server ausgelagert. Die Schlüsseldatei kann auch mit einem Passwort gesichert werden (Option: -pass). Da sich diese VPN-Installation aber auf einem komplett verschlüsseltem System befindet, wird der Private-CA-Key ohne Passwort auf diesem Rechner gespeichert.

# cd /etc/openvpn/easy-rsa
# source vars # nach jeder Änderung in "vars" muss die Datei "gesourced" werden, dass heißt die Umgebungsvariablen werden geupdatet.
# ./clean-all # evtl. vorhandene Zertifikatsdateien in KEY_DIR werden gelöscht!!
# ./build-ca
# # "Organizational Unit Name" -> leer lassen
# ls /etc/openvpn/easy-rsa/keys/ca* # ca.crt (Zertifikat) ca.key (Private-Key)
# openssl x509 -in /etc/openvpn/easy-rsa/keys/ca.crt -text -noout | less # Zertifikat prüfen
# openssl rsa -in /etc/openvpn/easy-rsa/keys/ca.key -text -noout | less # Key anschauen

Bei der Erstellung des Server-Zertifikates ist es wichtig, einen individuellen Common Name zu vergeben, der die VPN-Verbindung eindeutig kennzeichnet. Hier wird xyz-server verwendet. Der Common Name taucht in der Client-Konfigurationsdatei wieder auf und dient als eindeutige Identifizierung um man-in-the-middle-Angriffe zu verhindern.

# ./build-key-server xyz-Server # xyz-Server: Common Name des Zertifikats
# # "challenge password" -> leer lassen
# # "An optional company name" -> leer lassen
# # "Sign the certificate? [y/n]" -> y
# # "1 out of 1 certificate requests certified, commit?" -> y
# rm /etc/openvpn/easy-rsa/keys/server.csr # wird nicht benötigt, da Key/Zertifikat zugleich erstellt werden
# ls /etc/openvpn/easy-rsa/keys/server.* # server.crt server.key
# # Ersetze "server" durch den gewählten Common Name (z.B. "xyz-Server").

Die Client-Schlüssel werden folgendermaßen erstellt:

# ./build-key client1 # Angaben analog zum Server-Zertifikat
# rm /etc/openvpn/easy-rsa/keys/client1.csr # wird nicht benötigt, da Key/Zertifikat zugleich erstellt werden
# ls /etc/openvpn/easy-rsa/keys/client1.* # client1.crt client1.key

Als Nächstes wird der Diffie-Hellman-Parameter erstellt. Diesen Key benötigt OpenVPN für die sichere Aushandelung der Verschlüsselung.

# ./build-dh # dafür ca. 5-1000 min., je nach KEY_SIZE in "vars"
# ls /etc/openvpn/easy-rsa/keys/dh* # dh2048.pem (bzw. dh1024.pem, je nach KEY_SIZ)

Ebenso arbeitet dieses System mit einem statischen Key, der vor dem eigentlichen Schlüesselaustausch übertragen wird. Dieser wird am Ende zusammen mit den Client-Keys auf den Client übertragen.

# openvpn --genkey --secret /etc/openvpn/easy-rsa/keys/ta.key
# ls /etc/openvpn/easy-rsa/keys/ta.key # ta.key

Nun müssen die Schlüsseldateien nur noch auf den Client übertragen werden. Dies sollte auf einem möglichst sicheren Weg passieren, wie in dem folgenden Beispiel über scp.

# cd /etc/openvpn/easy-rsa/keys
# scp ca.crt ta.key client1.* 192.168.223.10:/etc/openvpn/testnetz/

Als Letztes muss für den Server die Konfigurationsdatei geschrieben werden. Im Anhang (7.1) findet sich die komplette Datei.
Die Variablen local und port bezeichnet die IP-Adresse und den dazugehörigen Port, an der OpenVPN auf Verbindungen wartet.
proto bezeichnet das verwendete Protokoll zur Übertragung, es sind tcp und udp möglich. UDP ist, da es auf einen HandShake verzichtet, schneller als TCP, jedoch auch fehleranfälliger. Um die Verbindung zu garantieren wird in diesem Fall TCP genutzt.
Der server-bridge-Parameter ist für die IP-Vergabe zuständig. Hier muss der DHCP-Server entsprechend konfiguriert sein, damit keine Komplikationen entstehen.
cipher stellt den Daten-Verschlüsselung-Algorithmus ein. OpenVPN bietet drei verschiedenen Algorithmen an. AES-256-CBC ist, aufgrund der verwendeten Algorithmen und Länge, der sicherste.
comp-lzo aktiviert die Kompression, diese ist nur bei langsameren Verbindungen wie DSL zu empfehlen Bei einer LAN-VPN-Verbindung verbraucht es nur unnötig Ressourcen.

Nun darf der OpenVPN-Dienst gestartet werden. Damit Verbindungen von außen an den VPN-Server gelangen können, muss eine Port-Weiterleitung im Router eingerichtet werden. Diese ist in diesem Fall:

# iptables -t nat -A PREROUTING -p TCP --dport 1234 -i ppp0 -j DNAT --to 192.168.222.22:1234
# /etc/init.d/openvpn start

Clientseite

Die Client-Konfiguration unterscheidet sich nur wenig von der Serverkonfiguration. Wir gehen davon aus, dass die benötigten Keys und Zertifikate wie in den vorhergehenden Schritten erstellt und übertragen wurden.
In der openvpn.conf wird local mit remote ausgetauscht und anstatt der lokalen IP-Adresse wird die entfernte, oder der Hostname des OpenVPN-Servers eingetragen. Durch den Parameter client wird OpenVPN im Clientmodus gestartet.
Besonders bei Verbindungen zu dynamischen IP-Adressen ist die Option resolv-retry infinite wichtig. Sollte die Verbindung nach dem, durch keepalive angegeben Zeitraum nicht wieder hergestellt sein, wird versucht die IP zu dem Hostnamen neu aufzulösen.
ns-cert-type server und tls-remote server sind die Einstellungen für das Serverzertifikat und für die Art der Authentifizierung.
Die komplette Konfiguration ist im Anhang zu finden.

Nun wird der Dämon auf der Clientseite gestartet und die Verbindung wird hergestellt. Bei Erfolg sollte jeder Rechner in der Lage sein, einen oder mehrere Rechner aus dem anderen Netz zu pingen.

# /etc/init.d/openvpn start

Ausblick - Dienste in zusammengelegten Netzen DHCP

Das ''Dynamic Host Configuration Protocol'' wird in beiden Netzwerken verwendet. Ein DHCP-Server kann auf Anfrage für beliebige Netzwerkgeräte IP-Adressen, Routing-, DNS- und weitere Informationen bereitstellen.
In unserem Fall haben beide Netze eine Internetverbindung über einen Router an jedem Standort. Logisch betrachtet haben alle Geräte in beiden Netzen die Möglichkeit, einen oder beide Router als Verbindung mit dem Internet zu nutzen. Um zu verhindern, dass sämtliche Internetverbindungen über das VPN geschickt werden, verteilen die DHCP-Server in dem System die entsprechnden Informationen an die Clients, damit diese nur die lokale Internetverbindung nutzen.
Das Problem dabei ist, dass immer die Informationen vom schnelleren DHCP-Server verwendet werden und nicht nur die vom lokalen Server.
Wir haben das Problem mittels ebtables gelöst. Die Ports 67 (DHCP-Server-Port) und 68 (DHCP-Client-Port) wurden jeweils auf der Bridge beider Standorte gesperrt. Dieses funktioniert aber nur, wenn der DHCP-Server-Dienst jeweils auf dem Server mit der VPN-Bridge läuft. Versuche, auf anderen Geräten einen DHCP-Server zu nutzen, ergaben, dass Anfragen und Antworten wieder ungeblockt über das VPN übertragen wurden.
Dieses Verhalten kann folgendermaßen erklärt werden: ebtables ist nur in der Lage, Pakete vor Betreten oder nach Verlassen der Bridge zu filtern. Werden die DHCP-Antwortpakete auf dem System generiert, welches die VPN-Verbindung aufbaut, so kann ebtables das Paket analysieren und verwalten. Pakete, die an die reelle Netzwerkschnittstelle der Bridge kommen, können nur vor der Bridge abgefangen werden, da die DHCP-Information vor dem Austreten durch OpenVPN verschlüsselt wird. Dadurch hat ebtables keine Möglichkeit, das Paket komplett auszulesen.
In unserem Fall ist die Filterung der DHCP-Pakete vor der Bridge nicht möglich, da noch eine zweite, Virtuelle Schnittstelle mit der Bridge verbunden ist. Über diese Schnittstelle müssen DHCP-Informationen übertragbar sein.

Fazit

Zusammenfassend ist zu sagen, dass OpenVPN eine stabile und kostengünstige Methode ist, um zwei oder mehr Netzwerke über ein Trägernetz - wie das Internet - zusammen zu legen. Im Laufe unseres Projekts haben sich einige, aber lösbare Schwierigkeiten bei dem Bridging ergeben.
Durch die Zusammenlegung mehrerer Netzwerke, werden viele Sicherheitslücken verhindert, die durch Portforwarding vieler Ports entstehen. Innerhalb des VPNs können die Protokolle und Dienste, wie FTP, SMB, und SSH weiter genutzt werden, ohne dass von außerhalb jemand darauf Einfluss nehmen kann.
Portforwarding kann natürlich nicht vollkommen ausgeschlossen werden. Jedoch benötigt man nicht für jeden Dienst eine Portweiterleitung, die potenziell gefährlich sein kann. Wartung und Fehlerbehebung sind durch eine übersichtliche Logdatei einfach und zeitsparend.
Je nach Anwendungsgebiet, wägt der Benutzer ab, ob oder wie sicher die Verschlüsselung sein soll. Die Stärke der Verschlüsselung steht immer im Zusammenhang mit der zur Verfügung stehenden Bandbreite und Rechenleistung.
Durch unser Projekt wurde uns nochmals deutlich, dass Open Source Produkte, wie OpenVPN, immer als Alternative zu kommerziellen Produkten bedacht werden sollten.

Anhang

Literatur

[Gentoo-Wiki] OpenVPN: http://en.gentoo-wiki.com/wiki/OpenVPN, 12.02.2010
[OpenVPN]: http://openvpn.net, 11.02.2010
[OpenVPN e.V.]: http://www.openvpn.eu, 11.02.2010
[heise Security]: VPN-Knigge: http://www.heise.de/security/artikel/VPN-Knigge-270796.html, 11.02.2010

Diese Dokumentation ist im Rahmen eines Projektes, in der FH-Emden, zusammen mit Jan Meyer, erstellt worden.

Letzte Änderung: 19. Sep 2011

© Joachim Janßen
CSS ist valide! Valid XHTML 1.0 Transitional