Kierowanie zapytania DNS klienta WireGuard do innego resolvera wygląda jak jedna reguła, a zachowuje się jak trzy decyzje. Cel trzeba przepisać, pakiet trzeba przekazać, a odpowiedź musi znaleźć drogę powrotną przez stan translacji utworzony przez bramę. Pomiń trzeci krok, a zapytanie czysto wyjdzie, podczas gdy klient czeka wiecznie.

Weźmy przykład autoryzowanych klientów w 10.77.0.0/24, którzy przychodzą przez wg0, odpytują ogłoszony adres 10.77.0.1 i potrzebują resolvera pod 203.0.113.53. Adres nadrzędny to placeholder dokumentacyjny, a nie działająca usługa.

Przekierowanie zapytania zmienia tylko jego cel

Reguła NAT celu w PREROUTING przepisuje adres przed podjęciem decyzji o trasowaniu, więc pakiet jest następnie trasowany do nowego celu zamiast starego. Adres źródłowy klienta pozostaje nietknięty przez tę operację. Dlatego reguła, która wygląda na kompletną, wciąż może dawać ciszę: żądanie podróżuje teraz do resolvera, który nigdy nie słyszał o prywatnym zakresie klienta. Brama przetłumaczyła jedno pole i odziedziczyła drugi problem.

Oba transporty DNS potrzebują pasujących reguł, bo klient wraca do TCP, gdy odpowiedź jest ucinana.

Poniższe reguły wybierają jeden interfejs wejściowy, jeden zakres klientów i jeden pierwotny adres celu. Nic innego na bramie nie jest dotknięte, a zapytanie samej bramy w ogóle nie pasuje.

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -i wg0 -s 10.77.0.0/24 -d 10.77.0.1 -p udp --dport 53 -j DNAT --to-destination 203.0.113.53:53
iptables -t nat -A PREROUTING -i wg0 -s 10.77.0.0/24 -d 10.77.0.1 -p tcp --dport 53 -j DNAT --to-destination 203.0.113.53:53

Ścieżka odpowiedzi to osobna decyzja

Dwa układy pozwalają odpowiedzi wrócić, a wczesny wybór jednego oszczędza sesję debugowania. Albo resolver nadrzędny ma trasę powrotną do 10.77.0.0/24 przez tę bramę, albo brama tłumaczy źródło na wyjściu, dzięki czemu odpowiedź dociera na adres, który strona nadrzędna już zna. Oba działają; tylko jeden odpowiada poziomowi kontroli, jaką masz nad stroną nadrzędną.

Trasowanie zasługuje na pierwszą próbę, bo utrzymuje adres klienta widocznym dla resolvera i unika drugiej warstwy translacji. Gdy strona nadrzędna jest poza twoją kontrolą, translacja źródła na konkretnym interfejsie wyjściowym jest praktycznym wyborem.

Ogranicz tę translację tak ściśle jak przekierowanie, inaczej reguła stanie się NAT ogólnego przeznaczenia dla wszystkiego, co przypadkiem do niej pasuje:

iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -d 203.0.113.53 -o eth0 -p udp --dport 53 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -d 203.0.113.53 -o eth0 -p tcp --dport 53 -j MASQUERADE

Śledzenie połączeń utrzymuje mapowanie w parach, więc odpowiedź jest przepisywana z powrotem na oryginalny tuple klienta w drodze powrotnej. Bez reguły wyjściowej resolver wysyła odpowiedź na prywatny adres, którego nie może osiągnąć, a klient widzi przekroczenie czasu zamiast błędu.

Pisz reguły węziej, niż wygląda zadanie

Zgoda na przekazywanie należy do tego samego zakresu. Zezwól na przepływ od klienta do resolvera i ruch powrotny, który conntrack już rozpoznaje, zamiast akceptować każde połączenie DNAT na maszynie. Ogólna akceptacja autoryzuje też przekierowania portów, które nie mają nic wspólnego z DNS.

Własny resolver bramy to inna ścieżka kodu. Zapytanie wydane lokalnie przechodzi przez OUTPUT, więc test z powłoki bramy nie ćwiczy ani reguły PREROUTING, ani polityki przekazywania. Dlatego test lokalny może przejść, gdy każdy klient zawodzi, a odwrotnie jest równie częste.

Nic tutaj nie obejmuje DNS przez HTTPS na porcie 443 ani DNS przez TLS na porcie 853, i nic nie obejmuje IPv6. Klient ze skonfigurowanym resolverem IPv6 z ochotą zignoruje cały układ.

Co dowodzi świeże zapytanie

Śledzenie połączeń pamięta wcześniejsze mapowania, więc zapytanie wysłane przed zmianą reguły może zostać obsłużone ze starego stanu i sprawić, że nowa reguła będzie wyglądać na zepsutą. Zacznij od nowego portu źródłowego i, tam gdzie klient cachuje odpowiedzi, od nowej nazwy.

dig @10.77.0.1 example.com A +short
conntrack -L -p udp --dport 53 | head

Pierwsze polecenie pokazuje, czy ścieżka klienta w ogóle się rozwiązuje, a drugie pokazuje translację, którą brama faktycznie zainstalowała, łącznie z oboma kierunkami tuple. Mapowanie wskazujące właściwy resolver z licznikiem odpowiedzi zablokowanym na zerze to problem ścieżki powrotnej, a nie filtrowania.

Zanim cokolwiek przekierujesz, potwierdź, że resolver zna nazwy, których oczekujesz. Zamiennik, który odpowiada na nazwy publiczne, ale nie na twoją strefę prywatną zamienia działające wyszukiwanie w NXDOMAIN, który wygląda jak zepsuty tunel. Przetestuj resolver bezpośrednio, z bramy, zanim zaangażowana będzie ścieżka klienta. A dokumentacja rozszerzeń iptables dokumentuje semantykę DNAT i masquerade, na której opierają się te reguły.

Powiązane artykuły