Een OpenVPN-client met volledige tunnel aanzetten op een machine die je via SSH bereikt, kan de sessie binnen een seconde kappen, en de machine doet niets verkeerd. De tunnel verandert niet hoe pakketten de server bereiken; hij verandert hoe de antwoorden naar buiten gaan. Zodra de standaardroute naar tun0 wijst, gaat een antwoord aan je SSH-client de netwerk van de provider in, dat geen route terug naar jouw adres heeft. De verbinding hangt, de volgende poging loopt af, en de daemon blijft al die tijd op poort 22 luisteren.

Lees de routingtabel voordat je het VPN-log leest. Het log zal zeggen dat de tunnel omhoog kwam, en dat klopt. De vraag is aan welke interface elk antwoord wordt overgedragen, en dat is een opzoeking per pakket in een tabel die de tunnel net heeft herschreven.

Waarom het antwoord door de verkeerde deur naar buiten gaat

Inkomende pakketten komen nog steeds binnen op de fysieke interface, omdat een VPN-client niet kan veranderen hoe het internet het publieke adres van je server bereikt. Antwoorden zijn een aparte beslissing: voor elk pakket zoekt de kernel de bestemming op, en na --redirect-gateway zegt de standaardvermelding tunnel. De uitgang van de provider ziet een bestemming die hij niet bedient en laat het pakket vallen.

De eigen bescherming van OpenVPN dekt precies één bestemming. De handleiding voor 2.6 beschrijft --redirect-gateway als een reeks: hij voegt een hostroute voor de VPN-peer toe via de gateway die vóór de tunnel in gebruik was, zodat het versleutelde verkeer niet in zichzelf kan teruglopen, en vervangt daarna de standaardroute. Die hostroute is alleen voor de peer. Je SSH-client is gewoon nog een internetadres en krijgt geen uitzondering.

Eén prefixfout is het waard om vroeg uit te sluiten. ip route add -net 0.0.0.0 gw 10.8.0.1 dev tun0 zonder lengte komt overeen met het enkele adres 0.0.0.0, niet met het internet; het moet 0.0.0.0/0 zijn. En als het nemen van de standaard de eigen transport van de tunnel breekt, voeg dan het eindpunt toe als hostroute via de fysieke interface, met het echte adres van de provider.

Pin je SSH-clientadres voor een onmiddellijke oplossing

De snelste reparatie is een hostroute voor het adres van je client via de gateway die de server gebruikte voordat de tunnel bestond. Zoek aan jouw kant het adres op dat de server zal zien, en lees dan de tabel van de server zodat je de oude gateway kent:

curl -s https://ifconfig.co
ip route

Voeg op de server de uitzondering toe voordat de client start. De adressen hier zijn plaatsaanduidingen; de vorm is wat telt:

sudo ip route add 80.128.240.55 via 192.168.178.1

Dit is de reparatie die in het gemelde geval is gebruikt, en hij werkt onmiddellijk. Hij is ook op twee voorspelbare manieren kwetsbaar: de route verdwijnt bij herstart, en hij wordt fout op het moment dat je provider je een ander adres geeft. Behandel hem als noodmaatregel en maak hem bewust duurzaam, via een netwerkeenheid of een dispatcher-hook, of accepteer dat hij tijdelijk is en schrijf het herstelpad op.

Houd de client tegen om de standaard te nemen

De schonere optie is de tunnel de standaardroute helemaal niet te laten vervangen. route-nopull, gebruikt met --client of --pull, accepteert de gepushte opties behalve routes, block-outside-dns en DHCP-achtige opties zoals DNS-servers, dus je voegt alleen de prefixen toe die je nodig hebt. Een smaller hulpmiddel is een pull-filter, dat één problematische richtlijn laat vallen en de rest houdt:

route-nopull
pull-filter ignore "redirect-gateway"

Gebruik het ene of het andere, niet beide, en wees duidelijk over wat er verandert. Zonder standaardroute door de tunnel surft de server niet meer via de provider op het internet; hij bereikt alleen wat je expliciet hebt gerouteerd. Als de volledige tunnel het hele doel van de opzet was, is dit de verkeerde knop en is de hostroute hierboven de juiste.

Splits de terugweg op bron of op verbinding

Als het inkomende adres stabiel is, houdt een bronregel de antwoorden lokaal zonder de eigen routes van de tunnel aan te raken. Geef het adres van de fysieke interface een eigen tabel met het LAN-prefix en de fysieke standaard, en kies die tabel dan voor verkeer dat daarvan afkomstig is:

ip rule add from 192.168.1.11 table 128
ip route add table 128 to 192.168.1.0/24 dev eth0
ip route add table 128 default via 192.168.1.1

Dit werkt omdat antwoorden op een inkomende SSH-verbinding van het adres komen waarmee de client verbond. Een gemeld geval waarin elke inkomende dienst moest blijven werken, gebruikte precies deze vorm. Als het inkomende adres zweeft of het pad dynamisch is, markeer dan de verbinding: zet een conntrack-markering op het eerste pakket van de fysieke interface, kopieer die naar antwoordpakketten in OUTPUT, en routeer gemarkeerde pakketten via een tabel die naar de fysieke gateway wijst.

iptables -t mangle -A PREROUTING -i eth0 -m conntrack --ctstate NEW -j CONNMARK --set-mark 1234
iptables -t mangle -A OUTPUT -m connmark --mark 1234 -j MARK --set-mark 4321
ip route add default via 192.168.1.1 dev eth0 table 3412
ip rule add fwmark 4321 table 3412

Houd de verbindingsmarkering, firewallmarkering en tabelnummer apart tijdens het testen. Het hergebruiken van één nummer voor twee rollen levert een regel op die er correct uitziet en de verkeerde pakketten raakt. De standaardvermelding van de tabel heeft ook via nodig met de LAN-gateway op een gewone Ethernet-verbinding; een kale dev eth0 werkt alleen als de interface punt-naar-punt is of de volgende hop anders wordt opgelost. De gemelde Jessie-host zat toevallig op een verbinding waar de kale vorm werkte, wat geen distributieregel is om te kopiëren.

Verifieer zonder jezelf buiten te sluiten

Test niet door te ontkoppelen. Houd de eerste sessie open, breng de tunnel omhoog en vraag de kernel welk pad je eigen adres zou nemen:

ip route get 80.128.240.55

Het antwoord hoort de fysieke interface en de oude gateway te noemen, niet de tunnel. Open daarna een tweede SSH-verbinding; dat is de echte test, omdat de oude sessie kan overleven op toestand die een nieuwe verbinding niet kan reproduceren. Als de tweede hangt terwijl de eerste nog antwoordt, heeft de regel nooit het verkeer geraakt dat ertoe doet, en de markeringen of het bronadres zijn waar je moet kijken.

Houd een console buiten de band beschikbaar tijdens de hele oefening. Een server waarvan de enige toegangsweg de tunnel is die je net hebt gebroken, kan niet via die tunnel worden gerepareerd, en de terugrol is makkelijker als je de tabelnummers en prefixen hebt opgeschreven die je hebt toegevoegd.

Gerelateerde artikelen