Waarom een VPN-firewallhook dezelfde regel twee keer toevoegt
Een herverbinding kan je hook opnieuw uitvoeren, dus ontwerp voor de gewenste toestand: eigen chains, een test vóór het invoegen, één geserialiseerde wijziging en een smalle afbraak.
De hook werkt de eerste keer, en na drie herverbindingen bevat de chain drie kopieën van dezelfde regel. Niets faalde luid; het script deed simpelweg wat hem elke keer dat hij liep werd gezegd. Een VPN-hook is een configuratiebewerking die meer dan één keer kan draaien, dus heeft hij een eigenaar, een gewenste toestand en één geserialiseerde wijziging nodig. Volg die volgorde en de duplicaten stoppen.
Geef de regels een eigenaar voordat je er een schrijft
Bepaal welke chain of tabel deze integratie bezit voordat je één regel schrijft. Een toegewijde chain die de hook aanmaakt en leegmaakt is de duidelijkste vorm van eigendom, omdat het opruimen die chain dan kan verwijderen zonder iemands anders beleid te raken. Als je regels aan een gedeelde chain moet toevoegen, markeer ze met een commentaar zodat een latere zoekopdracht precies de jouwe vindt. Eigendom maakt de afbraak veilig, en de afbraak is het deel dat stilletjes faalt.
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
Een commentaar is hier geen versiering. Het is het verschil tussen jouw regel verwijderen en een regel verwijderen die toevallig lijkt op de jouwe, en het overleeft in de opgeslagen regelset. Schrijf het commentaar één keer in een variabele en gebruik dezelfde string in elk commando dat toevoegt, test of verwijdert.
Test de gewenste toestand in plaats van opnieuw toe te voegen
Schrijf op wat er moet bestaan terwijl de tunnel omhoog is: welke interfaces, welke bron en bestemming, welk protocol en welke poort. Druk daarna elke regel uit als een test gevolgd door een invoeging, zodat een tweede run de regel vindt en niets doet. Het controlecommando eindigt met nul wanneer de regel bestaat, en dat is precies het signaal dat het script nodig heeft. De iptables-referentie documenteert de hier gebruikte vormen voor controle, toevoegen en invoegen.
iptables -C VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT ||
iptables -A VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT
Wees voorzichtig met de positie. Een regel controleren en bovenaan invoegen kan een toestemming vóór een bewuste weigering schuiven die eerder vooraan stond, zodat de tweede run het gedrag verandert ook al voegt hij niets toe. Voeg achteraan toe binnen je eigen chain, en beheer de volgorde via de plaats van de sprong naar die chain. Als de volgorde binnen de chain belangrijk is, bouw de chain dan opnieuw op uit een bekende lijst in plaats van hem regel voor regel te patchen.
Stop als de regel die je nodig hebt niet als een stabiele test kan worden uitgedrukt. Dat betekent meestal dat de gewenste toestand nog vaag is.
Serialiseer de wijziging in plaats van te hopen dat die blijft
Twee aanroepen van de hook kunnen overlappen, en beide kunnen een ontbrekende regel zien voordat een van beide hem toevoegt. De wachtoptie van xtables laat een commando op het slot wachten, maar maakt een controle-dan-toevoegen-reeks niet atomair over twee commando’s. Serialiseer de hele bewerking met je eigen slot, of gebruik een beheerder die een gedeclareerde batch als één transactie toepast. nftables kan het laatste, wat een reden is om het te verkiezen op hosts waar het beschikbaar is.
flock /run/vpn-hook.lock /usr/local/sbin/vpn-firewall-apply
nft -f /etc/nftables/vpn-hook.nft
Welk mechanisme je ook kiest, houd het kritieke deel kort en maak het herintreedbaar: een hook die halverwege faalt, moet veilig opnieuw uitvoerbaar zijn. Log het resultaat zodat een herhaalde run zichtbaar is in het journaal in plaats van te worden afgeleid uit een regelaantal. Als twee verschillende supervisors de hook kunnen aanroepen, los dat dan eerst op; geen slot repareert twee eigenaren.
Breek alleen af wat van jou is
Afbraak moet een vervangende verbinding onderscheiden van degene die hij met pensioen stuurde, en hij moet een gebeurtenis overleven die nooit een nette opruiming krijgt. Verwijder met dezelfde identifiers die je gebruikte om toe te voegen, en maak nooit een gedeelde chain leeg om de opruiming eenvoudig te maken. Na een harde stop, voer bij de volgende start een verzoeningsronde uit in plaats van aan te nemen dat de down-hook liep.
iptables -D VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT
iptables -F VPN_HOOK
ip -brief link show type tun
De levensduur van de interface hoort ook bij het ontwerp. Een herverbinding kan een apparaat met een andere naam maken, zodat een regel die de naam van de tweede tunnel hardcodeert verouderd raakt terwijl hij er nog geldig uitziet. Geef de voorkeur aan de identiteit die de verbinding zelf blootlegt, en lees die bij elke run opnieuw. Test de drie gebeurtenissen afzonderlijk: een herhaalde verbinding, een vervangende verbinding en een afsluiting. Het toegestane verkeer moet alle drie overleven zonder duplicaten, en niet-gerelateerde diensten moeten onaangeroerd blijven.
De wandeling eindigt wanneer de hook een eigenaar heeft, een test voor elke regel die hij toevoegt, één geserialiseerd pad en een afbraak die alleen zijn eigen toestand verwijdert. Een hook die veilig twee keer draait is meer waard dan een hook die één keer slim is.