Für einen Server-Umzug sollte das neue System übergangsweise mit IP-Adressen des alten Systems betrieben werden. Da das neue System bei einem anderen Anbieter gehostet wird als das alte, war eine Übernahme der IP-Adressen via Routing nicht möglich. Daher habe ich ein Routing über einen verschlüsselten Tunnel via Tinc-VPN eingerichtet.
Der Prozess war nicht ganz so einfach wie ich dachte. Wie ich es zum Laufen bekommen habe, dokumentiere ich in diesem Artikel.
Die Theorie
Mein Plan war wir folgt. Via Tinc baue ich einen Tunnel zwischen beiden Maschinen im „switch“-Modus auf. In diesem Modus habe ich an beiden Enden ein Netzwerk-Device, welches sich so verhält, als wäre es eine Netzwerkkarte, die mit dem anderen Ende via Kabel oder Switch verbunden ist. Nun kann ich darüber die gewünschten IPs routen.
Die Praxis
Für das Beispiel verwende ich die folgenden IP-Adressen:
1.1.1.1 – öffentliche IP-Adresse des alten Systems
2.2.2.2 – öffentliche IP-Adresse des neuen Systems
3.3.3.3 – öffentliche IP-Adresse des alten Systems, welche auf das neue System geroutet werden soll
9.9.9.9 – externe öffentliche IP-Adresse, von der aus ich die Erreichbarkeit der zu routenden Adresse prüfe
Auf dem alten System
Zunächst ist Tinc (via apt) zu installieren. Anschließend wird auf dem alten System eine Konfiguration erstellt:
mkdir /etc/tinc/altzuneu mkdir /etc/tinc/altzuneu/hosts
Datei /etc/tinc/altzuneu/tinc.conf:
Name = alt Mode = switch ConnectTo = neu
Datei /etc/tinc/altzuneu/tinc-up
#!/bin/sh ifconfig $INTERFACE 0.0.0.0 up
Datei /etc/tinc/altzuneu/hosts/alt
Address = 1.1.1.1
Datei /etc/tinc/altzuneu/hosts/neu
Address = 2.2.2.2
Nun werden die Keys für den alten Host erzeugt:
tincd -n altzuneu -K
Auf dem neuen System
Das Setup des neuen Systems erfolgt exakt wie beim alten System. Allerdings sind in tinc.conf Name und ConnectTo zu vertauschen:
Name = neu Mode = switch ConnectTo = alt
Nachdem die Keys hier generiert sind, müssen noch die Public-Keys der beiden Systeme ausgetauscht werden. Das geschieht, indem /etc/tinc/altzuneu/hosts/alt vom alten auf das neue System und /etc/tinc/altzuneu/hosts/neu vom neuen auf das alte System kopiert werden.
Erster Test
Sind beide Seiten konfiguriert, wird das VPN zur Liste der zu startenden VPNs hnzugefügt und tinc gestartet
echo "altzuneu" >> /etc/tinc/nets.boot service tinc restart
Der Befehl ifconfig zeigt nun auf beiden Seiten ein Device „altzuneu“ ohne IP-Adresse an. Ich vergebe beiden Enden eine IP-Adresse in einem nicht verwendeten internen Subnetz:
auf "alt": ifconfig altzuneu 192.168.1.1 up auf "neu": ifconfig altzuneu 192.168.1.2 up
Beide Enden sollten sich nun gegenseitg auf dieser IP anpingen können.
Mit echter IP
Auf dem neuen System soll natürlich kein internes Netz sondern die öffentliche IP geroutet werden. Da ich hier kein Gegenstück aus dem gleichen Subnetz habe, verwende ich auf der Seite „alt“ eine einzelne interne IP und auf der Seite „neu“ die zu routende öffentliche IP. Damit das Funktioniert, müssen entsprechende Routen gesetzt werden:
auf "alt": ifconfig altzuneu 192.168.1.1/32 up ip route add 3.3.3.3/32 via 192.168.1.1 scope link auf "neu": ifconfig altzuneu 3.3.3.3/32 up ip route add 192.168.1.1/32 via 3.3.3.3 scope link
Und schon kann ich von alt auf 3.3.3.3 pingen. Damit das auch von extern geht, muss auf „alt“ noch ip forwarding aktiviert werden:
echo "1" > /proc/sys/net/ipv4/ip_forward
Leider klappt aus irgend einem Grund der Ping von meiner externen IP auf 3.3.3.3 noch nicht.
Rückfahrschein
Mittels TCPDUMP auf „neu“ ist das Problem schnell gefunden:
tcpdump -n -i altzuneu icmp [...] 9.9.9.9 > 3.3.3.3: ICMP echo request [...]
Auf dem VPN-Interfaces sind nur Echo-Requests zu sehen. Die Antworten fehlen jedoch.
tcpdump -n -i eth0 icmp [...] 3.3.3.3 > 9.9.9.9: ICMP echo reply [...]
Die Antworten finden sich auf dem öffentlichen Interface wieder. Der Grund ist, dass das System eingehende Anfragen aus dem Internet sieht. Die Antworten darauf werden über das Default-Gateway gesendet. Nun könnte ich das Default-Gateway zwar ändern, dann habe ich das selbe Problem aber für Traffic, der über die neue IP des neuen Systems (2.2.2.2) reinkommt.
Die Lösung lautet Source Policy Routing. Dieses Kernel-Feature erlaubt es, IP-Paketen aufgrund Ihrer Eigenschaften eine eigene Routing-Tabelle zuzuweisen. Diese kann dann ein eigenes Default-Gateway haben, welches keinen Einfluss auf andere Pakete haben. Die „spezielle Eigenschaft“ der entsprechenden Pakete ist hier, dass sie die IP 3.3.3.3 als Quelle haben.
auf "neu": ip rule add from 3.3.3.3 table 2 ip route add default via 192.168.1.1 table 2
Und schon kennt das neue System die Rückroute für Pakete der gerouteten IP.
Paketgrößen
Die Path-MTU zwischen unterschiedlichen Rechenzentren ist in der Regel 1500 byte. Dies kann ermittelt werden, indem mit
ping -s 1472 -c 10 -M do EXTERNE-IP
auf das jeweils andere System gepingt wird. Durch den VPN-Overhead reduziert sich die MTU auf 1445 bytes (Ping mit -s 1417 von neu auf 192.168.1.1). Tinc fragmentiert intern die Pakete entsprechend, sauberer ist es jedoch, dem VPN-Device gleichd ie richtige MTU zu geben:
ifconfig altzuneu mtu 1445
Alles zusammen fügen
Damit man obige Einstellungen nicht bei jedem Neustart neu machen muss, können die Befehle in das tinc-up-Script aufgenommen werden.
tinc-up auf „alt“:
#!/bin/sh ifconfig $INTERFACE 192.168.1.1/32 mtu 1445 up ip route add 3.3.3.3/32 via 192.168.1.1 scope link echo "1" > /proc/sys/net/ipv4/ip_forward
tinc-up auf „neu“:
#!/bin/sh ifconfig $INTERFACE 3.3.3.3/32 mtu 1445 up ip route add 192.168.1.1/32 via 3.3.3.3 scope link ip rule add from 3.3.3.3 table 2 ip route add default via 192.168.1.1 table 2
Nach dem Neustart der beiden Tinc-Daemons sollte 3.3.3.3 weiterhin extern erreichbar sein. Ein tracepath von extern auf die IP sollte zwar den Bruch in der MTU zeigen, die intern verwendete 192.168.1.1 sollte jedoch nicht auftauchen.
Fazit
Mittels Routing über ein VPN kann eine öffentliche IP von einem Server zu einem anderen getunnelt werden. Die Übertragung erfolgt dabei verschlüsselt. Im Gegensatz zu Port-Weiterleitungen (z.b. mit rinetd oder NAT) bleibt Original-IP des Anfragenden erhalten und wird in Logfiles korrekt angezeigt. Damit alles korrekt funktioniert, muss besonderes Augenmerk auf das Source-Policy-Routing-Setup gelegt werden.
Eine gute Idee mit echt cooler Umsetzung!
Danke für die Inspiration 😉