W macOS przełącznik bezpieczeństwa jest tylko tak dobry, jak polityka filtra pakietów za nim, a pf to część, która tę politykę egzekwuje. Polityka musi robić dwie przeciwne rzeczy naraz: wpuszczać klienta do jego serwera, aby tunel mógł istnieć, i zatrzymywać wszystko inne przed bezpośrednim wyjściem. Większość opublikowanych zestawów reguł radzi sobie z drugim i zapomina o pierwszym, więc maszyna traci łączność zamiast zyskiwać ochronę. Wersja, która działa, nazywa punkt końcowy, resolver i tunel, i nic więcej.

Co filtr pakietów może rozstrzygnąć, a czego nie

pf patrzy na interfejsy, adresy, numery protokołów i porty i na tym poprzestaje. Nigdy nie dowiaduje się, który proces otworzył gniazdo, więc uprawnienie napisane dla jednego programu staje się uprawnieniem dla każdego programu, który może dotrzeć do tego samego portu. Tak hojny wyjątek UDP zamienia przełącznik bezpieczeństwa z powrotem w zwykłą sieć. Blokowanie świadome aplikacji należy do klienta lub rozszerzenia systemowego, nie do tego pliku.

Filtr nie tworzy też tras. Gdy klient padnie, trasa domyślna może nadal wskazywać martwy tunel, a pf zamienia to w zablokowane pakiety zamiast cichego powrotu do Wi-Fi. Blokada jest zamierzonym wynikiem, a nie usterką, którą trzeba obejść.

Kolejność rozstrzyga wynik częściej niż treść reguły. Bez quick pf ocenia dalej po dopasowaniu i wygrywa ostatnia pasująca reguła, więc szerokie przepuszczenie na dole unieważnia staranne wyjątki powyżej. Oznaczenie przepuszczeń quick czyni pierwsze dopasowanie ostatecznym, co autor polityki zwykle ma na myśli.

Najpierw przeczytaj fakty o interfejsie i punkcie końcowym

Interfejsy bezprzewodowe nie są numerowane tak samo na każdym Macu, a urządzenie tunelu dostaje numer, który może się zmienić między uruchomieniami. Reguła nazywająca nieistniejące urządzenie zawodzi przy parsowaniu, co jest głośne i łatwe do wychwycenia, natomiast reguła nazywająca niewłaściwe istniejące urządzenie parsuje się czysto i przepuszcza ruch, który chciałeś zatrzymać.

Zbieraj fakty, dopóki klient jest połączony, bo urządzenie tunelu istnieje tylko wtedy. Potrzebujesz interfejsu trzymającego trasę domyślną, urządzenia utworzonego przez klienta oraz adresu i portu serwera, do którego się łączy. Właśnie tę ostatnią wartość większość zestawów reguł pomija, a pomijanie jej jest powodem, dla którego skopiowany zestaw blokuje własny tunel.

route -n get default
ifconfig -l
scutil --nc list

Pierwsze polecenie nazywa interfejs, który teraz wygrywa, drugie wylicza każde urządzenie znane jądru, a trzecie pokazuje konfiguracje VPN, które system może uruchomić. Zapisz te odpowiedzi, a potem odczytaj adres i port serwera z własnej konfiguracji klienta.

Napisz zestaw reguł wokół ścieżki tunelu

Plik poniżej domyślnie odmawia i ponownie wpuszcza pięć rzeczy: loopback, urządzenie tunelu, ścieżkę klienta do jego serwera, resolver używany przed powstaniem tunelu oraz dwie wymiany, które utrzymują łącze bezprzewodowe w użyteczności. Nazwy interfejsów i adres serwera pochodzą z twojej maszyny, więc podstaw potwierdzone wartości. Numer tunelu też nie będzie zgodny z twoim.

set skip on lo0
block all
pass out quick on utun0
# maintain this line when the server address changes
pass out quick on en1 inet proto udp to 203.0.113.10 port 1194
# only the resolver the client uses before the tunnel exists
pass out quick on en1 inet proto udp to 192.0.2.53 port 53
pass out quick on en1 inet proto udp from any port 68 to any port 67
pass out quick on en1 inet proto udp to 224.0.0.251 port 5353

Linia DHCP istnieje, bo Mac prosi o adres, zanim go ma, więc żądanie wychodzi z portu 68 w stronę portu 67 bez użytecznego adresu źródłowego. Linia multicast pozwala systemowi ocenić, czy łącze bezprzewodowe jest warte użycia, a jej usunięcie daje maszynę, która zgłasza brak połączenia w działającej sieci. Linia punktu końcowego jest tym, co OpenVPN w ogóle pozwala dotrzeć do jego serwera; bez niej block all odrzuca zewnętrzny uścisk dłoni i tunel nigdy nie wstaje. Linia resolvera jest węższa niż ogólne uprawnienie DNS, bo nazywa jeden adres i jeden port zamiast każdego zapytania, które wykonuje maszyna.

Te wyjątki punktu końcowego i resolvera są dwoma, które muszą istnieć; wszystko inne pozostaje zablokowane. Jeśli klient łączy się z dosłownym adresem, usuń linię resolvera i zachowaj linię punktu końcowego. Jeśli adres serwera się zmienia, zaktualizuj tę linię przed następnym połączeniem albo wypełnij tabelę pf z własnego haka klienta i dopasowuj zamiast tego tabelę.

Opuść tunel, a potem uruchom ponownie

Parsuj przed załadowaniem, bo błąd składni jest tani w próbie na sucho i kosztowny w sesji zdalnej. Potem załaduj plik, włącz filtr, jeśli był wyłączony, i odczytaj, co naprawdę obowiązuje. Odczyt nie jest ceremonią: inna kotwica może dodać reguły, których nie napisałeś, więc porównaj wydrukowany zestaw ze swoim plikiem.

sudo pfctl -n -v -f /etc/pf.conf
sudo pfctl -f /etc/pf.conf
sudo pfctl -e
sudo pfctl -s rules
sudo pfctl -s Anchors
sudo pfctl -a <anchor> -s rules
sudo pfctl -s info

Mając reguły załadowane, opuść tunel i spróbuj wczytać stronę. Zwykły ruch powinien się zatrzymać i powinien pozostać zatrzymany po uśpieniu i wybudzeniu maszyny, bo właśnie w tym przejściu wraca nieaktualny stan. Połącz się ponownie i potwierdź, że ruch wraca bez dotykania zestawu reguł. Jeśli przeglądarka nadal działa przy opuszczonym tunelu, jakaś reguła jest szersza, niż myślałeś, i odczyt zwykle ją nazywa.

Ponowne uruchomienie to część, którą ludzie pomijają. macOS czyta /etc/pf.conf przy starcie, ale czytanie pliku nie jest tym samym co włączenie filtra, więc zestaw reguł, który teraz działa, może być nieaktywny po restarcie. Uruchom potem sudo pfctl -s info i potwierdź, że linia stanu zgłasza filtr jako włączony.

Utrzymuj wyjście i ścieżkę restartu uczciwymi

Zestaw reguł, który blokuje wszystko, może też odciąć cię od maszyny, którą administrujesz zdalnie. Edytuj z sesji lokalnej, gdy możesz, trzymaj poprzedni plik obok nowego i znaj drogę powrotu, zanim będzie potrzebna. Polecenia poniżej wyłączają filtr i ładują ponownie zachowaną kopię, i to jest sekwencja do uruchomienia z konsoli, a nie przez tunel, który właśnie przeciąłeś. Pięciosekundowy powrót bije sprytną regułę za każdym razem.

sudo pfctl -d
sudo pfctl -f /etc/pf.conf.previous
sudo pfctl -s rules

Trwałość wymaga demona uruchamianego, który wykonuje pfctl -e i ładuje twój plik przy starcie. Traktuj go jak każdą inną uprzywilejowaną pracę: ścieżki bezwzględne, dziennik, który możesz potem przeczytać, i test na maszynie, do której możesz fizycznie dotrzeć. Demon, który zawodzi po cichu, zostawia maszynę niechronioną i wyglądającą normalnie.

Udokumentuj luki, zaczynając od drugiego klienta VPN, który tworzy własne urządzenie tunelu. Twoje reguły nazywają jeden interfejs tunelu, więc drugi pozostaje zablokowany albo łapie go szeroka reguła dodana później. Interfejsy tetheringu i hotspotu pojawiają się tylko czasami i zasługują na tę samą notatkę. Żadna z tych luk nie jest powodem, by pomijać politykę; to warunki, w których nadal obowiązuje.

Powiązane artykuły