Hooket virker første gang, og efter tre genopkoblinger indeholder kæden tre kopier af den samme regel. Intet fejlede højlydt; scriptet gjorde ganske enkelt, hvad det fik besked om, hver gang det kørte. Et VPN-hook er en konfigurationsoperation, der kan køre mere end én gang, så det har brug for en ejer, en ønsket tilstand og en serialiseret ændring. Gå frem i den rækkefølge, og dubletterne stopper.

Giv reglerne en ejer, før du skriver nogen

Beslut, hvilken kæde eller tabel denne integration ejer, før du skriver en enkelt regel. En dedikeret kæde, som hooket opretter og tømmer, er den tydeligste form for ejerskab, fordi oprydning derefter kan fjerne den kæde uden at røre nogens anden politik. Hvis du er nødt til at føje regler til en delt kæde, så mærk dem med en kommentar, så en senere søgning kan finde præcis dine. Ejerskab er det, der gør nedrivning sikker, og nedrivning er den del, der fejler stille.

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

En kommentar er ikke pynt her. Den er forskellen mellem at fjerne din regel og at fjerne en regel, der tilfældigvis ser ens ud, og den overlever i det gemte regelsæt. Skriv kommentaren én gang i en variabel, og brug den samme streng i hver kommando, der tilføjer, tester eller sletter.

Test for den ønskede tilstand i stedet for at tilføje igen

Skriv ned, hvad der skal findes, mens tunnelen er oppe: hvilke grænseflader, hvilken kilde og destination, hvilken protokol og hvilken port. Udtryk derefter hver regel som en test efterfulgt af en indsættelse, så en anden kørsel finder reglen og ikke gør noget. Kontrolkommandoen afslutter med nul, når reglen findes, og det er præcis det signal, scriptet har brug for. iptables-referencen dokumenterer de former for kontrol, tilføjelse og indsættelse, der bruges her.

iptables -C VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT ||
  iptables -A VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT

Vær forsigtig med placeringen. At kontrollere en regel og indsætte den i toppen kan flytte en tilladelse foran en bevidst afvisning, der før kom først, så den anden kørsel ændrer adfærd, selv om den intet tilføjer. Tilføj inden i din egen kæde, og styr rækkefølgen via placeringen af springet til den kæde. Hvis rækkefølgen inde i kæden er vigtig, så genopbyg kæden ud fra en kendt liste i stedet for at lappe den regel for regel.

Stop, hvis den regel, du har brug for, ikke kan udtrykkes som en stabil test. Det betyder som regel, at den ønskede tilstand stadig er uklar.

Serialiser ændringen i stedet for at håbe, den holder

To hook-kald kan overlappe, og begge kan se en manglende regel, før en af dem tilføjer den. xtables’ ventetilvalg får en kommando til at vente på låsen, men det gør ikke en kontrol-derefter-tilføj-sekvens atomisk over to kommandoer. Serialiser hele operationen med din egen lås, eller brug en manager, der anvender en deklareret batch som én transaktion. nftables kan det sidste, hvilket er en grund til at foretrække det på værter, hvor det er tilgængeligt.

flock /run/vpn-hook.lock /usr/local/sbin/vpn-firewall-apply
nft -f /etc/nftables/vpn-hook.nft

Uanset hvilken mekanisme du vælger, hold den kritiske sektion kort, og gør den genindtrædelig: et hook, der fejler halvvejs, skal kunne køres igen. Log resultatet, så en gentagen kørsel er synlig i journalen i stedet for at blive udledt af et regelantal. Hvis to forskellige supervisorer kan kalde hooket, så ret det først; ingen lås reparerer to ejere.

Riv kun det ned, du ejer

Nedrivning skal skelne en erstatningsforbindelse fra den, den har pensioneret, og den skal overleve en hændelse, der aldrig får en ordentlig oprydning. Slet efter de samme identifikatorer, som du brugte til at tilføje, og tøm aldrig en delt kæde for at gøre oprydningen enkel. Efter et hårdt stop skal du køre en afstemning ved næste start i stedet for at antage, at down-hooket kørte.

iptables -D VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT
iptables -F VPN_HOOK
ip -brief link show type tun

Grænsefladens levetid hører også med i designet. En genopkobling kan oprette en enhed med et andet navn, så en regel, der hardcoder den anden tunnels navn, bliver forældet, mens den stadig ser gyldig ud. Foretræk den identitet, som forbindelsen selv afslører, og læs den igen ved hver kørsel. Test de tre hændelser hver for sig: en gentaget forbindelse, en erstatningsforbindelse og en nedlukning. Den tilladte trafik skal overleve alle tre uden dubletter, og urelaterede tjenester skal være urørte.

Gennemgangen slutter, når hooket har en ejer, en test for hver regel, det tilføjer, én serialiseret vej og en nedrivning, der kun fjerner dets egen tilstand. Et hook, der er sikkert at køre to gange, er mere værd end et hook, der er smart én gang.

Relaterede artikler