Of een hookscript de andere kant van de tunnel bereikt, hangt van drie voorwaarden af: aan welke gebeurtenis het is gekoppeld, of OpenVPN zich nog in zijn opstartreeks bevindt wanneer het script loopt, en of het werk van die reeks is losgekoppeld. De meeste scripts falen op de derde. Een slaap toevoegen behandelt een levenscyclusprobleem als een timingprobleem, en het werkt net vaak genoeg om te misleiden.

Bepaal eerst de gebeurtenis, dan het mechanisme om werk uit te stellen, dan de plek waar het uitgestelde werk draait. Die drie beslissingen zijn onafhankelijk, en ze door elkaar halen is hoe een hook van twee regels een hele middag wordt.

Waarom de hook wacht op een tunnel die op hem wacht

OpenVPN roept zijn hooks synchroon aan, binnen hetzelfde proces dat pakketten verplaatst. up wordt geactiveerd zodra het tun- of tap-apparaat bestaat, maar voordat een route wordt toegevoegd, en route-up wordt geactiveerd na de routes; geen van beide momenten belooft dat de tegenpartij antwoordt. Zolang een script van een van de hooks nog draait, stuurt de daemon niet door, dus een commando dat verwacht dat verkeer de tunnel doorkruist, wacht op een tunnel die op het commando wacht. Die cirkelvormige wachttijd is de reden dat een handmatige uitvoering slaagt en de hook een time-out krijgt.

De voor de hand liggende pleister, een paar seconden slapen, werkt soms omdat de andere kant vanzelf omhoogkwam, niet omdat de slaap iets repareerde. Een helper die de gereedheid opvraagt, is een ander antwoord: de hook keert terug, het doorsturen begint, en de helper krijgt wat hij nodig heeft zodra het er echt is.

Kies de hook op gebeurtenis, niet op gemak

Koppel up aan werk dat alleen het apparaat nodig heeft, route-up aan werk dat routes nodig heeft, en houd client-connect en client-disconnect voor taken per client aan de serverkant. Opruimen bij het verbreken moet het aankunnen om twee keer te draaien, omdat herverbindingen over een permanente interface niet dezelfde volgorde volgen als een volledige herstart. Op de server wordt client-connect geactiveerd wanneer een client zich authenticeert, niet wanneer de daemon start, wat de moeite waard is om te bevestigen voordat logica daarheen verhuist. Als het werk bij de levenscyclus van de dienst hoort en niet bij één verbinding, is een systemd-unit een betere plek dan welke hook dan ook.

Hookcommando's worden rechtstreeks door de daemon uitgevoerd, zonder shell ertussen, dus ifconfig_remote in een up-regel komt als letterlijke tekst aan. Wikkel het commando in een expliciete shell, of houd de logica in een script dat de omgeving leest. ipchange is één richtlijn die eigen argumenten toevoegt: het geeft het adres en de poort aan het commando, dus een script dat voor geen is geschreven ziet twee onverwachte.

Drie manieren om het werk los te koppelen

De eerste optie is de helper vanuit de hook naar de achtergrond te sturen: start hem met setsid of systemd-run --scope, sluit de geërfde descriptoren en stop onmiddellijk met nul. De tweede is de hook een klein statusbestand laten schrijven en een systemd-timer of een pad-unit daarop laten reageren, wat de hook triviaal houdt en het herhaalbeleid legt waar logboeken zijn. De derde is de hook helemaal laten vallen en het werk verplaatsen naar een unit die na de VPN-dienst is geordend, wat het juiste antwoord is wanneer het werk helemaal niet per verbinding is. Alle drie delen één regel: de hook moet terugkeren voordat hij de tunnel nodig heeft.

Wat u ook kiest, maak de helper idempotent en observeerbaar. Twee overlappende aanroepen mogen dezelfde onomkeerbare actie niet twee keer uitvoeren, en een helper die faalt moet iets achterlaten dat een mens kan lezen.

Scheid sandboxfouten van levenscyclusfouten

Wanneer een script vanaf een root-prompt draait en als dienst faalt, is de oorzaak meestal een sandbox en niet het netwerk. Een beperkende ProtectHome, een alleen-lezen ProtectSystem, of een werkmap die niet bestaat kunnen het script of zijn gegevens onbereikbaar maken, en op een SELinux-host heeft het bestand ook een context nodig die uitvoering toestaat. Lees de unit met systemctl cat openvpn-server@server en het journaal met journalctl -u openvpn-server@server -n 80, en zoek dan naar een rechten- of contextfout in plaats van een verbindingstime-out. De sandbox uitschakelen zou de laatste stap moeten zijn, niet de eerste.

Een levenscyclusfout ziet er anders uit: de hook start, de helper draait en de socket is er gewoon nog niet. Schrijf een regel met tijdstempel uit de hook zelf, verbreek en herstel de verbinding, en lees de gebeurtenissen op volgorde. Als de helper de tunnel echt nodig heeft, laat hem dan de gereedheid opvragen in plaats van een vaste periode te slapen.

Drie velden maken het volgende rapport nuttig: welke hook liep, welk account hij gebruikte en waar hij stopte. Zonder hen begint elk later onderzoek opnieuw.

Gerelateerde artikelen