Włączenie klienta OpenVPN w trybie pełnego tunelu na maszynie, do której łączysz się przez SSH, może zerwać sesję w ciągu sekundy, a maszyna nie robi nic złego. Tunel nie zmienia tego, jak pakiety docierają do serwera; zmienia to, jak wychodzą odpowiedzi. Gdy tylko domyślna trasa wskazuje tun0, odpowiedź do twojego klienta SSH trafia do sieci dostawcy, która nie ma trasy z powrotem do twojego adresu. Połączenie zawiesza się, następna próba kończy się przekroczeniem czasu, a demon przez cały czas nasłuchuje na porcie 22.

Przeczytaj tablicę routingu, zanim przeczytasz log VPN. Log powie, że tunel wstał, i będzie miał rację. Pytanie brzmi, któremu interfejsowi jest przekazywana każda odpowiedź, a to wyszukiwanie dla każdego pakietu w tablicy, którą tunel właśnie przepisał.

Dlaczego odpowiedź wychodzi złymi drzwiami

Pakiety przychodzące nadal docierają do interfejsu fizycznego, ponieważ klient VPN nie może zmienić tego, jak internet dociera do publicznego adresu twojego serwera. Odpowiedzi to osobna decyzja: dla każdego pakietu jądro szuka celu, a po --redirect-gateway domyślny wpis mówi tunel. Wyjście dostawcy widzi cel, którego nie obsługuje, i odrzuca pakiet.

Własna ochrona OpenVPN obejmuje dokładnie jeden cel. Podręcznik 2.6 opisuje --redirect-gateway jako sekwencję: dodaje trasę hosta dla peera VPN przez bramę używaną przed tunelem, żeby zaszyfrowany ruch nie mógł zawrócić do siebie, a następnie zastępuje domyślną trasę. Ta trasa hosta jest tylko dla peera. Twój klient SSH to po prostu kolejny adres internetowy i nie dostaje żadnego wyjątku.

Jeden błąd prefiksu warto wykluczyć wcześnie. ip route add -net 0.0.0.0 gw 10.8.0.1 dev tun0 bez długości pasuje do pojedynczego adresu 0.0.0.0, a nie do internetu; musi to być 0.0.0.0/0. A jeśli przejęcie domyślnej trasy psuje własny transport tunelu, dodaj punkt końcowy jako trasę hosta przez interfejs fizyczny, używając prawdziwego adresu dostawcy.

Przypnij adres klienta SSH, aby naprawić od razu

Najszybsza naprawa to trasa hosta dla adresu twojego klienta przez bramę, której serwer używał przed tunelem. Po swojej stronie znajdź adres, który zobaczy serwer, a potem przeczytaj tablicę serwera, żeby znać starą bramę:

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

Na serwerze dodaj wyjątek, zanim klient wystartuje. Adresy tutaj są zastępcze; liczy się kształt:

sudo ip route add 80.128.240.55 via 192.168.178.1

To jest naprawa użyta w zgłoszonym przypadku i działa natychmiast. Jest też krucha w dwojaki przewidywalny sposób: trasa znika przy restarcie i staje się błędna w chwili, gdy twój ISP daje ci inny adres. Traktuj ją jako środek awaryjny i świadomie zrób ją trwałą, przez jednostkę sieciową albo hook dispatchera, lub przyjmij, że jest tymczasowa, i zapisz ścieżkę odzyskiwania.

Nie pozwól klientowi przejąć trasy domyślnej

Czystsza opcja to niepozwalanie tunelowi zastępować trasy domyślnej. route-nopull, użyty z --client lub --pull, akceptuje wypychane opcje z wyjątkiem tras, block-outside-dns i opcji w stylu DHCP, takich jak serwery DNS, więc dodajesz tylko potrzebne prefiksy. Węższym narzędziem jest filtr pobierania, który odrzuca jedną problematyczną dyrektywę i zachowuje resztę:

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

Użyj jednego albo drugiego, nie obu, i jasno wiedz, co się zmienia. Bez domyślnej trasy przez tunel serwer nie przegląda już internetu przez dostawcę; dociera tylko do tego, co jawnie zroutowałeś. Jeśli pełny tunel był całym sensem konfiguracji, to jest zła dźwignia, a trasa hosta powyżej jest właściwa.

Podziel ścieżkę powrotną według źródła lub połączenia

Gdy adres przychodzący jest stabilny, reguła źródła trzyma odpowiedzi lokalnie, nie ruszając własnych tras tunelu. Daj adresowi interfejsu fizycznego własną tablicę z prefiksem LAN i fizyczną trasą domyślną, a potem wybierz tę tablicę dla ruchu, który z niej pochodzi:

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

Działa to dlatego, że odpowiedzi na przychodzące połączenie SSH pochodzą z adresu, z którym połączył się klient. Zgłoszony przypadek, w którym każda usługa przychodząca musiała dalej działać, używał dokładnie takiego kształtu. Gdy adres przychodzący pływa albo ścieżka jest dynamiczna, oznacz połączenie: postaw znacznik conntrack na pierwszym pakiecie z interfejsu fizycznego, skopiuj go na pakiety odpowiedzi w OUTPUT i routuj oznaczone pakiety przez tablicę wskazującą na fizyczną bramę.

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

Podczas testów trzymaj osobno znacznik połączenia, znacznik firewalla i numer tablicy. Ponowne użycie jednego numeru do dwóch ról daje regułę, która wygląda poprawnie i trafia w złe pakiety. Domyślny wpis tablicy wymaga też via z bramą LAN na zwykłym łączu Ethernet; goły dev eth0 działa tylko wtedy, gdy interfejs jest punkt-punkt albo następny skok jest rozwiązywany inaczej. Zgłoszony host Jessie siedział na łączu, gdzie goła forma działała, co nie jest regułą dystrybucji do kopiowania.

Sprawdź, nie zamykając sobie dostępu

Nie testuj przez rozłączanie. Zostaw pierwszą sesję otwartą, podnieś tunel i zapytaj jądro, którą ścieżką poszedłby twój własny adres:

ip route get 80.128.240.55

Odpowiedź powinna wskazać interfejs fizyczny i starą bramę, a nie tunel. Potem otwórz drugie połączenie SSH; to jest prawdziwy test, bo stara sesja może przetrwać na stanie, którego nowe połączenie nie odtworzy. Jeśli druga zawiesza się, gdy pierwsza jeszcze odpowiada, reguła nigdy nie trafiła w ruch, który się liczy, i to znaczniki albo adres źródłowy są miejscem do sprawdzenia.

Miej przez całe ćwiczenie pod ręką konsolę poza pasmem. Serwera, którego jedyną drogą dostępu jest tunel, który właśnie zepsułeś, nie da się naprawić przez ten tunel, a wycofanie jest łatwiejsze, gdy zapisałeś numery tablic i prefiksy, które dodałeś.

Powiązane artykuły