Kroken fungerar första gången, och efter tre återanslutningar innehåller kedjan tre kopior av samma regel. Inget misslyckades högljutt; skriptet gjorde helt enkelt vad det blev tillsagt varje gång det kördes. En VPN-krok är en konfigurationsoperation som kan köras mer än en gång, så den behöver en ägare, ett önskat tillstånd och en serialiserad ändring. Följ den ordningen och dubbletterna slutar.

Ge reglerna en ägare innan du skriver någon

Bestäm vilken kedja eller tabell den här integrationen äger innan du skriver en enda regel. En dedikerad kedja som kroken skapar och tömmer är den tydligaste formen av ägande, eftersom städningen då kan ta bort den kedjan utan att röra någon annans policy. Om du måste lägga regler i en delad kedja, märk dem med en kommentar så att en senare sökning hittar exakt dina. Ägandet gör nedrivningen säker, och nedrivningen är den del som misslyckas tyst.

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 är inte utsmyckning här. Den är skillnaden mellan att ta bort din regel och att ta bort en regel som råkar se likadan ut, och den överlever i den sparade regeluppsättningen. Skriv kommentaren en gång i en variabel och använd samma sträng i varje kommando som lägger till, testar eller tar bort.

Testa önskat tillstånd i stället för att lägga till igen

Skriv ned vad som ska finnas medan tunneln är uppe: vilka gränssnitt, vilken källa och destination, vilket protokoll och vilken port. Uttryck sedan varje regel som ett test följt av en infogning, så att en andra körning hittar regeln och inte gör något. Kontrollkommandot avslutas med noll när regeln finns, och det är precis den signal skriptet behöver. iptables-referensen dokumenterar de former för kontroll, tillägg och infogning som används här.

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

Var försiktig med placeringen. Att kontrollera en regel och infoga den överst kan flytta ett tillstånd före en avsiktlig nekning som tidigare kom först, så den andra körningen ändrar beteendet trots att den inte lägger till något. Lägg till i slutet inne i din egen kedja och styr ordningen efter var hoppet till den kedjan sitter. Om ordningen inne i kedjan spelar roll, bygg om kedjan från en känd lista i stället för att lappa den regel för regel.

Stoppa om regeln du behöver inte kan uttryckas som ett stabilt test. Det betyder oftast att det önskade tillståndet fortfarande är otydligt.

Serialisera ändringen i stället för att hoppas att den håller

Två anrop av kroken kan överlappa, och båda kan se en saknad regel innan någon av dem lägger till den. xtables väntealternativ får ett kommando att vänta på låset, men det gör inte en kontrollera-sedan-lägg-till-sekvens atomär över två kommandon. Serialisera hela operationen med ditt eget lås, eller använd en hanterare som tillämpar en deklarerad batch som en enda transaktion. nftables kan göra det senare, vilket är en anledning att föredra det på värdar där det är tillgängligt.

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

Vilken mekanism du än väljer, håll det kritiska avsnittet kort och gör det återinträdbart: en krok som misslyckas halvvägs bör vara säker att köra igen. Logga resultatet så att en upprepad körning syns i journalen i stället för att härledas från ett regelantal. Om två olika övervakare kan anropa kroken, åtgärda det först; inget lås reparerar två ägare.

Riv bara ned det du äger

Nedrivningen måste skilja en ersättningsanslutning från den den pensionerade, och den måste överleva en händelse som aldrig får en snygg städning. Ta bort med samma identifierare som du använde för att lägga till, och töm aldrig en delad kedja för att förenkla städningen. Efter ett hårt stopp, kör en avstämning vid nästa start i stället för att anta att ned-kroken kördes.

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

Gränssnittets livslängd hör också till designen. En återanslutning kan skapa en enhet med ett annat namn, så en regel som hårdkodar den andra tunnelns namn blir inaktuell medan den fortfarande ser giltig ut. Föredra identiteten som anslutningen själv avslöjar, och läs den igen vid varje körning. Testa de tre händelserna separat: en upprepad anslutning, en ersättningsanslutning och en avstängning. Den tillåtna trafiken ska överleva alla tre utan dubbletter, och orelaterade tjänster ska vara orörda.

Genomgången slutar när kroken har en ägare, ett test för varje regel den lägger till, en serialiserad väg och en nedrivning som bara tar bort sitt eget tillstånd. En krok som är säker att köra två gånger är värd mer än en krok som är smart en gång.

Relaterade artiklar