El hook funciona la primera vegada, i després de tres reconnexions la cadena conté tres còpies de la mateixa regla. Res no va fallar sorollosament; l’script simplement va fer el que se li va dir cada vegada que es va executar. Un hook de VPN és una operació de configuració que pot executar-se més d’una vegada, així que necessita un propietari, un estat desitjat i un canvi serialitzat. Segueix aquest ordre i els duplicats s’aturen.

Dona un propietari a les regles abans d’escriure’n cap

Decideix quina cadena o taula posseeix aquesta integració abans d’escriure una sola regla. Una cadena dedicada que el hook crea i buida és la forma més clara de propietat, perquè la neteja pot després eliminar aquesta cadena sense tocar la política de ningú més. Si has d’afegir regles a una cadena compartida, marca-les amb un comentari perquè una cerca posterior trobi exactament les teves. La propietat és el que fa segur el desmuntatge, i el desmuntatge és la part que falla en silenci.

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

Un comentari aquí no és decoració. És la diferència entre eliminar la teva regla i eliminar una regla que casualment s’assembla, i sobreviu al conjunt de regles desat. Escriu el comentari una vegada en una variable i utilitza la mateixa cadena a cada ordre que afegeixi, provi o elimini.

Prova l’estat desitjat en lloc de tornar a afegir

Escriu què ha d’existir mentre el túnel està aixecat: quines interfícies, quina font i destinació, quin protocol i quin port. Després expressa cada regla com una prova seguida d’una inserció, perquè una segona execució trobi la regla i no faci res. L’ordre de comprovació surt amb zero quan la regla existeix, i aquest és exactament el senyal que necessita l’script. La referència d’iptables documenta les formes de comprovació, afegit i inserció que s’utilitzen aquí.

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

Ves amb compte amb la posició. Comprovar una regla i inserir-la al cap pot moure un permís davant d’una denegació deliberada que abans anava primer, així que la segona execució canvia el comportament encara que no afegeixi res. Afegeix al final dins de la teva pròpia cadena i controla l’ordre amb la posició del salt a aquesta cadena. Si l’ordre importa dins de la cadena, reconstrueix la cadena a partir d’una llista coneguda en lloc d’anar-la pedaçant regla per regla.

Atura’t si la regla que necessites no es pot expressar com una prova estable. Normalment això vol dir que l’estat desitjat encara és vague.

Serialitza el canvi en lloc d’esperar que es mantingui

Dues invocacions del hook es poden solapar, i totes dues poden veure una regla absent abans que cap l’afegeixi. L’opció d’espera d’xtables fa que una ordre esperi el bloqueig, però no fa atòmica una seqüència de comprova-i-afegeix entre dues ordres. Serialitza tota l’operació amb el teu propi bloqueig, o fes servir un gestor que apliqui un lot declarat com una sola transacció. nftables pot fer això últim, i és una raó per preferir-lo en amfitrions on està disponible.

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

Sigui quin sigui el mecanisme que triïs, mantén la secció crítica curta i fes-la reentrant: un hook que falla a mig camí hauria de ser segur de tornar a executar. Registra el resultat perquè una execució repetida sigui visible al journal en lloc de deduir-se del recompte de regles. Si dos supervisors diferents poden invocar el hook, arregla-ho primer; cap bloqueig arregla dos propietaris.

Desmunta només el que és teu

El desmuntatge ha de distingir una connexió de substitució de la que ha retirat, i ha de sobreviure a un esdeveniment que mai no rep una neteja graciosa. Elimina amb els mateixos identificadors que vas fer servir per afegir, i no buidis mai una cadena compartida per simplificar la neteja. Després d’una aturada dura, executa una passada de conciliació al següent inici en lloc de suposar que el hook de baixada es va executar.

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

La vida útil de la interfície també forma part del disseny. Una reconnexió pot crear un dispositiu amb un nom diferent, així que una regla que fixa el nom del segon túnel queda obsoleta mentre encara sembla vàlida. Prefereix la identitat que exposa la mateixa connexió i torna-la a llegir a cada execució. Prova els tres esdeveniments per separat: una connexió repetida, una connexió de substitució i un apagat. El trànsit permès ha de sobreviure als tres sense duplicats, i els serveis no relacionats han de quedar intactes.

El recorregut acaba quan el hook té un propietari, una prova per a cada regla que afegeix, un camí serialitzat i un desmuntatge que elimina només el seu propi estat. Un hook que és segur d’executar dues vegades val més que un hook que és enginyós una vegada.

Articles relacionats