W logach nic nie wygląda źle: interfejs działa, resolver zgłasza serwer DNS VPN, a plik na dysku go wymienia. Mimo to wewnętrzna nazwa hosta nadal jest rozwiązywana przez lokalny router. Te trzy stwierdzenia nie są sprzeczne, ponieważ plik, stan każdego łącza i ścieżka zapytania to różne obiekty, które przypadkiem dzielą nazwę. Poniżej opisano ścieżkę, którą zapytanie naprawdę przechodzi na hoście z systemd-resolved.

Trzy obiekty o nazwie resolv.conf

Na hoście z resolved /etc/resolv.conf jest zwykle dowiązaniem symbolicznym do /run/systemd/resolve/stub-resolv.conf. Ten cel zawiera adres lokalnego odbiornika stub, 127.0.0.53, oraz domeny wyszukiwania obliczone przez resolved. To widok stanu, a nie sam stan.

Stan żyje w konfiguracji resolved dla każdego łącza, dlatego resolvectl status może nie zgadzać się z plikiem i nadal mieć rację. Każde łącze niesie własne serwery i własne domeny routingu, a stub sięga po te dane, gdy przychodzi zapytanie. Podręcznik systemd-resolved opisuje generowane pliki i model dla każdego łącza; rozdzielenie widoku i stanu to część warta zapamiętania. Zmiana celu dowiązania zmienia to, co czytają tradycyjne klienty, a nie to, co wie resolver.

Trzeci obiekt, /run/systemd/resolve/resolv.conf, spłaszcza każde łącze do jednej listy serwerów. Program wskazujący na ten plik wysyła zapytania wprost do wymienionych serwerów i pomija stub, więc polityka dla każdego łącza już go nie dotyczy. Dlatego dwa programy na tej samej maszynie mogą odpowiedzieć na tę samą nazwę różnie, i żaden nie jest zepsuty.

Prześledź jedno zapytanie przez NSS

glibc czyta /etc/nsswitch.conf, aby zdecydować, kto odpowiada na nazwę. Wiersz hosts zawierający resolve kieruje pytanie do nss-resolve, który pyta resolved przez D-Bus i otrzymuje odpowiedź dla łącza. Wiersz z samym files dns wysyła zapytanie na adres, który trzyma /etc/resolv.conf.

Ten jeden wiersz wyjaśnia większość rozbieżności między przeglądarką a dig. dig czyta resolv.conf bezpośrednio i nigdy nie dotyka NSS, więc sprawdza stub albo serwer nadrzędny, a nie ścieżkę, której używa aplikacja. getent hosts internal.example przechodzi przez NSS, a porównanie jego odpowiedzi z odpowiedzią dig to pierwszy użyteczny pomiar.

Aplikacje, które mają własny resolver albo mówią DNS przez HTTPS do stałego punktu końcowego, omijają obie ścieżki. Nic w resolv.conf ani w stanie resolved ich nie ogranicza.

Sprawdź, kto jest właścicielem pliku i dokąd on wskazuje

Przeczytaj łańcuch dowiązań, zanim cokolwiek zmienisz, bo własność decyduje, który plik jest miarodajny. Każde polecenie poniżej tylko czyta stan.

stat -c '%N' /etc/resolv.conf
resolvectl status --no-pager
grep '^hosts' /etc/nsswitch.conf
ls -l /run/systemd/resolve/

Pierwszy wiersz wypisuje dowiązanie i jego cel razem, a zwykły plik należący do skryptu VPN oznacza, że resolver nigdy nie traktuje tego zapisu jako wejścia. Wyjście stanu wymienia serwery dla każdego łącza oraz domeny routingu, które decydują, dokąd trafia każde zapytanie. Wiersz nsswitch mówi, czy stub jest w ogóle konsultowany, więc adres stub w pliku bez resolve oznacza, że zapytania docierają do lokalnego odbiornika, gdy nic nie zarządza podziałem. Ta ostatnia lista też ma znaczenie, bo host bez stub-resolv.conf nie prowadzi opisanego tu układu.

Jeśli łańcuch kończy się na pliku zarządzanym przez inny pakiet, klient VPN i ten pakiet to dwaj właściciele, których trzeba pogodzić. Zastąpienie dowiązania wyrzuca pracę jednego właściciela i zostawia pracę drugiego na miejscu.

Napraw u właściciela dowiązania

Połączenie VPN powinno rejestrować swoje serwery i domeny na własnym łączu, a potem wycofywać je przy rozłączeniu. Integracja resolved w NetworkManagerze i własny pomocnik klienta działają właśnie tak; skrypt, który tylko przepisuje resolv.conf, nie.

Na już istniejącym łączu mechanizm pokazują ustawienia czasu działania. resolvectl dns tun0 10.40.0.53 przypina serwer, a resolvectl domain tun0 '~corp.example' przypina domenę routingu. Tylda jest znakiem nośnym: ogranicza zapytania dla tego sufiksu do tego łącza i zostawia resztę w spokoju, podczas gdy ta sama wartość bez niej staje się domeną wyszukiwania i podział wyparowuje. Te adresy to przykłady laboratoryjne, nie trwała konfiguracja. Potwierdź za pomocą resolvectl query host.corp.example i odczytaj, które łącze odpowiedziało.

Zarejestrowany serwer nadal potrzebuje trasy. Gdy zapytanie dotrze do właściwego łącza i skończy się czas, usterka leży w osiągalności przez tunel, a nie we własności resolvera.

Jak wygląda działający stan

Zdrowy wynik jest spójny we wszystkich trzech widokach: serwery każdego łącza odpowiadają temu, co rozdał VPN, domeny routingu obejmują tylko sufiksy wewnętrzne, a aplikacja, która ma znaczenie, rozwiązuje nazwę wewnętrzną, podczas gdy nazwa publiczna nadal idzie ścieżką lokalną. Jedno udane zapytanie dowodzi mniej niż ta zgodność.

Potem rozłącz się i powtórz oba zapytania. Klient, który po rozmontowaniu zostawia swoje domeny zarejestrowane, tworzy maszynę, która godziny później zawodzi na wewnętrznych zapytaniach, bez otwartego tunelu i bez oczywistej przyczyny.

Powiązane artykuły