Dlaczego hook zapory VPN dodaje tę samą regułę dwa razy
Ponowne połączenie może uruchomić hook jeszcze raz, więc projektuj pod stan docelowy: własne łańcuchy, test przed wstawieniem, jedna serializowana zmiana i wąskie sprzątanie.
Hook działa za pierwszym razem, a po trzech ponownych połączeniach łańcuch zawiera trzy kopie tej samej reguły. Nic nie zawiodło głośno; skrypt po prostu robił to, co mu kazano przy każdym uruchomieniu. Hook VPN to operacja konfiguracyjna, która może działać więcej niż raz, więc potrzebuje właściciela, stanu docelowego i serializowanej zmiany. Idź w tej kolejności, a duplikaty się skończą.
Nadaj regułom właściciela, zanim napiszesz którąkolwiek
Zdecyduj, który łańcuch lub tabela należy do tej integracji, zanim napiszesz jedną regułę. Dedykowany łańcuch, który hook tworzy i czyści, jest najjaśniejszą formą własności, ponieważ sprzątanie może potem usunąć ten łańcuch bez dotykania cudzej polityki. Jeśli musisz dodawać reguły do współdzielonego łańcucha, oznacz je komentarzem, aby późniejsze wyszukiwanie znalazło dokładnie twoje. Własność czyni sprzątanie bezpiecznym, a sprzątanie jest tą częścią, która cicho zawodzi.
iptables -N VPN_HOOK 2>/dev/null || true
iptables -C INPUT -j VPN_HOOK 2>/dev/null || iptables -I INPUT -j VPN_HOOK
iptables -S VPN_HOOK
Komentarz nie jest tu ozdobą. To różnica między usunięciem twojej reguły a usunięciem reguły, która przypadkiem wygląda podobnie, i przetrwa w zapisanym zestawie reguł. Zapisz komentarz raz w zmiennej i używaj tego samego ciągu w każdym poleceniu, które dodaje, testuje lub usuwa.
Testuj stan docelowy zamiast dodawać ponownie
Zapisz, co ma istnieć, gdy tunel jest podniesiony: które interfejsy, jakie źródło i cel, który protokół i który port. Następnie wyraź każdą regułę jako test, po którym następuje wstawienie, aby drugie uruchomienie znalazło regułę i nic nie zrobiło. Polecenie sprawdzające kończy się zerem, gdy reguła istnieje, i to jest dokładnie ten sygnał, którego potrzebuje skrypt. Dokumentacja iptables opisuje użyte tu formy sprawdzania, dodawania i wstawiania.
iptables -C VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT ||
iptables -A VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT
Uważaj na pozycję. Sprawdzenie reguły i wstawienie jej na początku może przesunąć zezwolenie przed zamierzoną odmowę, która wcześniej była pierwsza, więc drugie uruchomienie zmienia zachowanie, mimo że niczego nie dodaje. Dodawaj na końcu wewnątrz własnego łańcucha i kontroluj kolejność przez miejsce skoku do tego łańcucha. Jeśli kolejność wewnątrz łańcucha ma znaczenie, przebuduj łańcuch ze znanej listy zamiast łatać go reguła po regule.
Zatrzymaj się, jeśli potrzebnej reguły nie można wyrazić jako stabilnego testu. To zwykle znaczy, że stan docelowy jest wciąż niejasny.
Serializuj zmianę zamiast liczyć, że się utrzyma
Dwa wywołania hooka mogą się nakładać i oba mogą zobaczyć brakującą regułę, zanim którekolwiek ją doda. Opcja oczekiwania xtables każe poleceniu czekać na blokadę, ale nie czyni sekwencji sprawdź-i-dodaj atomową w obrębie dwóch poleceń. Serializuj całą operację własną blokadą albo użyj menedżera, który stosuje zadeklarowaną partię jako jedną transakcję. nftables potrafi to drugie, co jest jednym z powodów, by preferować go na hostach, gdzie jest dostępny.
flock /run/vpn-hook.lock /usr/local/sbin/vpn-firewall-apply
nft -f /etc/nftables/vpn-hook.nft
Niezależnie od wybranego mechanizmu trzymaj sekcję krytyczną krótko i uczyń ją ponownie wejściową: hook, który zawodzi w połowie, powinien być bezpieczny do ponownego uruchomienia. Zapisuj wynik, aby powtórne uruchomienie było widoczne w dzienniku, a nie wywnioskowane z liczby reguł. Jeśli dwa różne nadzory mogą wywołać hook, najpierw to napraw; żadna blokada nie naprawi dwóch właścicieli.
Sprzątaj tylko to, co jest twoje
Sprzątanie musi odróżnić połączenie zastępcze od tego, które odesłano na emeryturę, i musi przetrwać zdarzenie, które nigdy nie dostaje porządnego czyszczenia. Usuwaj po tych samych identyfikatorach, których użyto do dodania, i nigdy nie opróżniaj współdzielonego łańcucha, aby uprościć sprzątanie. Po twardym zatrzymaniu uruchom przy następnym starcie przebieg uzgadniania, zamiast zakładać, że hook zejścia zadziałał.
iptables -D VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT
iptables -F VPN_HOOK
ip -brief link show type tun
Czas życia interfejsu też należy do projektu. Ponowne połączenie może utworzyć urządzenie o innej nazwie, więc reguła, która na sztywno koduje nazwę drugiego tunelu, starzeje się, choć nadal wygląda na ważną. Preferuj tożsamość, którą ujawnia samo połączenie, i czytaj ją ponownie przy każdym uruchomieniu. Testuj trzy zdarzenia osobno: powtórzone połączenie, połączenie zastępcze i wyłączenie. Dozwolony ruch powinien przetrwać wszystkie trzy bez duplikatów, a niepowiązane usługi powinny pozostać nietknięte.
Wędrówka kończy się, gdy hook ma właściciela, test dla każdej dodawanej reguły, jedną serializowaną ścieżkę i sprzątanie, które usuwa tylko jego własny stan. Hook, który bezpiecznie uruchomić dwa razy, jest wart więcej niż hook, który raz jest sprytny.