Skip to content

Eine Defaultroute überschreiben, ohne sie zu überschreiben

Eine gängige Herausforderung, Fall 1: Ein mobiles Clientsystem soll mit HIlfe eines VPN-Clients mit einem geschützten Netzwerk verbunden werden. Dabei ist gewünscht, dass während der Tunnel aufgebaut ist der gesamte Netzwerktraffic des Clients über das VPN geht. Nach Abbau des Tunnels soll wieder alles so sein wie vorher.

Fall 2: Ein Dual-Homed Host in einem RZ (z.B. ein Proxy) soll im Wartungsbetrieb seine Defaultroute "nach innen" gesetzt haben, so wie sie auch aus dem Deployment-System herausfällt. Im Wirkbetrieb jedoch soll die Defaultroute "nach außen" gesetzt sein, damit die Kommunikation mit dem Internet möglich wird.

Beide Aufgaben erfordern ein temporäres Umsetzen der Defaultroute. Macht man das auf dem naiven Weg, muss man sich irgendwie merken, wohin die Defaultroute vor dem Umsetzen zeigte, um sie danach wieder herzustellen.

In diesem Artikel stelle ich einen einfachen und eleganten Weg vor, um sich die Zwischenspeicherung der "alten" Defaultroute zu sparen. Ich kenne ihn schon seit ein paar Jahren aus der OpenVPN-Welt und bin immer wieder über die Situation gestolpert, dass er an einer Stelle hilfreich ist und ich ihn den Leutern erklären muss, die ihn noch nicht kennen. Mit diesem Artikel möchte ich mir diese Erklärungen in der Zukunft etwas einfacher machen.

Für den Rest dieses Artikels setze ich voraus, dass der Blogartikel über IP-Routing gelesen und verstanden wurde.

Fall 1

ohne VPN-Tunnel

Die Grundkonfiguration sei die folgende:

0.0.0.0/0 via 172.16.0.1
172.16.0.0/24 dev lanw0

Jetzt betrachten wir ein Paket für die Adresse 8.8.8.8:

Address:   8.8.8.8              00001000.00001000.00001000. 00001000
Netmask:   255.255.255.0 = 24   11111111.11111111.11111111. 00000000
Network:   8.8.8.0              00001000.00001000.00001000. 00000000
Route:     172.16.0.0           10101100.00010000.00000000. 00000000

Die Route für 172.16.0.0 für unser Ziel greift nicht. Also gehen wir weiter:

Address:   8.8.8.8              00001000.00001000.00001000.00001000
Netmask:   0.0.0.0 = 0          00000000.00000000.00000000.00000000
Network:   0.0.0.0              00000000.00000000.00000000.00000000
Route:     0.0.0.0              00000000.00000000.00000000.00000000

die Route greift. Das Paket geht also via 172.16.0.1 raus und alles ist fein.

mit VPN-Tunnel

Nun bauen wir einen VPN-Tunnel auf. Das Gateway auf der anderen Seite des Tunnels sei 10.8.0.1, und der VPN-Server drückt uns - und das ist der Trick! - zwei /1-Routen auf. Ein Netz mit Netzmaske /1 aka 128.0.0.0 ist "ganz zufällig" die Hälfte des IPv4-Adressraums, so dass wir mit zwei /1-Routen (einer für die erste Hälfte - erstes Bit Null, und einer für die zweite Hälfte, erstes Bit Eins) den kompletten Adressraum abdecken. Unsere Routingtabelle sieht nun so aus:

0.0.0.0/0 via 172.16.0.1
0.0.0.0/1 via 10.8.0.1
128.0.0.0/1 via 10.8.0.1
172.16.0.0/24 dev lanw0

Nun wird unser Paket für das Ziel 8.8.8.8 so geroutet:

Address:   8.8.8.8              00001000.00001000.00001000. 00001000
Netmask:   255.255.255.0 = 24   11111111.11111111.11111111. 00000000
Network:   8.8.8.0              00001000.00001000.00001000. 00000000
Route:     172.16.0.0           10101100.00010000.00000000. 00000000

Wie gehabt, liegt 8.8.8.8 nicht im LAN. Wir betrachten also weiter die nächste Route, das ist zufällig die 128.0.0.0/1:

Address:   8.8.8.8              00001000.00001000.00001000. 00001000
Netmask:   128.0.0.0 = 1        10000000.00000000.00000000. 00000000
Network:   128.0.0.0            10000000.00000000.00000000. 00000000
Route:     0.0.0.0              00000000.00000000.00000000. 00000000

Wir sehen, dass hier für die Routingentscheidung nur das erste Bit betrachtet wird, das erste Bit des Ziels und das erste Bit der Netzadresse der Route sind unterschiedlich. Auch diese Route greift nicht.

Als nächstes betrachten wir die Route für 0.0.0.0/1:

Address:   8.8.8.8              00001000.00001000.00001000. 00001000
Netmask:   128.0.0.0 = 1        10000000.00000000.00000000. 00000000
Network:   0.0.0.0              00000000.00000000.00000000. 00000000
Route:     0.0.0.0              00000000.00000000.00000000. 00000000

Auch hier wird nur das erste Bit der Adresse betrachtet; hier sind beide Bits gleich und die Route greift. Das Paket geht also nach 10.8.0.1 raus. Die ebenfalls "passende" Route für 0.0.0.0/0 ist weniger spezifisch und wird ignoriert.

Dasselbe passiert "analog andersrum" für Adressen, deren erstes Bit gesetzt ist (z.B. 192.0.2.1) und die 128.0.0.0/1 Route: Hier sind auch die ersten Bits gleich, diesmal 1, und die Route greift. Auch hier wird die Route für 0.0.0.0/0 ignoriert, da weniger spezifisch.

Wir sehen also, dass die Route für 0.0.0.0/0 quasi lahmgelegt ist, da für den gesamten IPv4-Adressraum spezifischere Routen, nämlich die beiden /1 Routen, vorliegen. Wir missbrauchen den Routingtabelleneintrag für 0.0.0.0/0 hier nur als "Zwischenspeicher" für die "eigentliche" Defaultroute, die wir uns hätten merken müssen, wenn die die Defaultroute mit dem neuen Gateway 10.8.0.1 überschrieben hätten.

Wenn der VPN-Tunnel nun abgebaut wird, kann der VPN-Client die beiden /1-Routen stumpf löschen. Damit wird automatisch die Route für 0.0.0.0/0, die die ganze Zeit unverändert aktiv gewesen ist (es kam nur nichts mehr an), direkt wieder wirksam.

Fall 2: Der Dual-Homed Host

Wartungsbetrieb

Für Fall 2 mit dem Dual-Homed Host trägt man einfach die beiden /1-Routen dann ein, wenn der Wirkbetrieb mit der Defaultroute "nach außen" beginnen soll und trägt sie wieder aus, wenn der Host in den Wartungsbetrieb gehen soll. Wenn der Host auch im Wirkbetrieb aus dem "inneren" Netz administriert werden können soll, oder wenn er "interne" Backends erreichen muss (also eigentlich immer), muss man den IP-Adressraum des "internen" Netzes kennen und für diesen eine "more specific" Route "nach innen" eintragen. Wenn unser internes Netz den Adressraum 192.168.0.0/22 umfasst, haben wir also eine Standard-Routingtabelle:

0.0.0.0/0 via 172.16.0.1
192.168.0.0/22 via 172.16.0.1
172.16.0.0/24 dev lani0
172.17.0.0/24 dev lano0

Im Wartungsbetrieb geht langweilig alles über 172.16.0.1 raus - weil alles, was nicht auf 192.168.0.0/22 passt, über die Defaultroute ebenfalls nach 172.16.0.1 geht.

Wirkbetrieb

Im Wirkbetrieb werden die beiden /1-Routen sozusagen "dazwischen" geschoben:

0.0.0.0/0 via 172.16.0.1
192.168.0.0/22 via 172.16.0.1
0.0.0.0/1 via 172.17.0.1
128.0.0.0/1 via 172.17.0.1
172.16.0.0/24 dev lanw0
172.17.0.0/24 dev lano0

Wer kann's ohne die Bitmasken erklären?

Pakete für 192.168.0.0/22, also beispielsweise 192.168.1.24, werden von der /22-Route (die für dieses Paket die spezifischste Route ist) abgefischt und gehen nach innen.

Für Pakete für 8.8.8.8 greift die /22-Route nicht (Netzwerkteil passt nicht), also kann die 0.0.0.0/1 Route greifen. Für Pakete für 192.0.2.4 greift die 128.0.0.0/1 Route; die Defaultroute greift wie oben nie. Bei der Rückkehr in den Wartungsbetrieb verschwinden die beiden /1-Routen und alles ist wie vorher.

Einfach und elegant, nicht?

Und v6?

Genauso. Hier kann man sich zunutze machen, dass im IPv6-Adressraum aktuell nur der Teil 2000::/3 verwendet wird. Hat der Host also eine Defaultroute (also 0::/0), überlädt man diese vollständig mit einer Route für 2000::/3.

Ist 2000/3 in der Routingtabelle der Maschine bereits in Benutzung, nimmt man hier den Trick mit zwei /4-Routen: 2000::/4 und 3000::/4.

Trackbacks

No Trackbacks

Comments

Display comments as Linear | Threaded

Jakob on :

Für die zusätzliche, "weniger spezifische" IPv6-default-route müßte auch ::/1 oder ::/2 funktionieren, oder?

Marc 'Zugschlus' Haber on :

Natürlich. Aber dann überschreibt das der Kollege mit 2000/3

Add Comment

Markdown format allowed
Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.
E-Mail addresses will not be displayed and will only be used for E-Mail notifications.
Form options