Kan ett OpenVPN-krokskript använda tunneln det just byggde?
OpenVPN kör krokar inne i sin egen uppstart, så ett skript som behöver tunneln väntar på en tunnel som väntar på det. Koppla loss arbetet och välj krok efter händelse.
Om ett krokskript når andra sidan av tunneln beror på tre villkor: vilken händelse det är knutet till, om OpenVPN fortfarande är inne i sin uppstartssekvens när skriptet körs, och om arbetet har kopplats loss från den sekvensen. De flesta skript misslyckas på det tredje. Att lägga till en paus behandlar ett livscykelproblem som ett tajmningsproblem, och det fungerar precis ofta nog för att vilseleda.
Bestäm först händelsen, sedan mekanismen för att skjuta upp arbete, sedan platsen där det uppskjutna arbetet körs. De tre besluten är oberoende, och att blanda ihop dem är hur en krok på två rader blir en hel eftermiddag.
Varför kroken väntar på en tunnel som väntar på den
OpenVPN anropar sina krokar synkront, inne i samma process som flyttar paket. up utlöses när tun- eller tap-enheten finns, men innan någon rutt läggs till, och route-up utlöses efter rutterna; ingen av stunderna lovar att motparten svarar. Medan ett skript från någon av krokarna fortfarande körs vidarebefordrar inte daemonen, så ett kommando som förväntar sig att trafiken korsar tunneln väntar på en tunnel som väntar på kommandot. Den cirkulära väntan är anledningen till att en manuell körning går igenom och kroken får timeout.
Den uppenbara lappen, att sova några sekunder, fungerar ibland eftersom fjärränden kom upp av sig själv, inte för att pausen reparerade något. En hjälpare som frågar efter beredskap är ett annat svar: kroken återvänder, vidarebefordran börjar, och hjälparen får det den behöver när det faktiskt finns där.
Välj kroken efter händelse, inte efter bekvämlighet
Knyt up till arbete som bara behöver enheten, route-up till arbete som behöver rutter, och spara client-connect och client-disconnect till uppgifter per klient på serversidan. Rensning vid frånkoppling måste tåla att köras två gånger, eftersom återanslutningar över ett beständigt gränssnitt inte följer samma sekvens som en full omstart. På servern utlöses client-connect när en klient autentiserar sig, inte när daemonen startar, vilket är värt att bekräfta innan logiken flyttas dit. Om arbetet hör till tjänstens livscykel och inte till en enda anslutning, är en systemd-enhet ett bättre hem än någon krok.
Krokkommandon körs direkt av daemonen, utan skal emellan, så ifconfig_remote på en up-rad kommer som bokstavlig text. Packa in kommandot i ett uttryckligt skal, eller håll logiken i ett skript som läser miljön. ipchange är ett direktiv som lägger till egna argument: det ger adressen och porten till kommandot, så ett skript skrivet för ingen ser två oväntade.
Tre sätt att koppla loss arbetet
Det första alternativet är att lägga hjälparen i bakgrunden inifrån kroken: starta den med setsid eller systemd-run --scope, stäng de ärvda deskriptorerna och avsluta med noll direkt. Det andra är att låta kroken skriva en liten tillståndsfil och låta en systemd-timer eller en path-enhet agera på den, vilket håller kroken trivial och lägger återförsökspolicyn där det finns loggar. Det tredje är att släppa kroken helt och flytta arbetet till en enhet som ordnas efter VPN-tjänsten, vilket är rätt svar när arbetet inte alls är per anslutning. Alla tre delar en regel: kroken måste återvända innan den behöver tunneln.
Vad du än väljer, gör hjälparen idempotent och observerbar. Två överlappande anrop bör inte utföra samma oåterkalleliga åtgärd två gånger, och en hjälpare som misslyckas måste lämna något en människa kan läsa.
Skilj sandlådefel från livscykelfel
När ett skript körs från en root-prompt och misslyckas som tjänst är orsaken oftast en sandlåda och inte nätverket. En restriktiv ProtectHome, en skrivskyddad ProtectSystem eller en arbetskatalog som inte finns kan göra skriptet eller dess data oåtkomliga, och på en SELinux-värd behöver filen också ett sammanhang som tillåter körning. Läs enheten med systemctl cat openvpn-server@server och journalen med journalctl -u openvpn-server@server -n 80, och leta sedan efter ett behörighets- eller sammanhangsfel i stället för en anslutningstimeout. Att inaktivera sandlådan bör vara det sista draget, inte det första.
Ett livscykelfel ser annorlunda ut: kroken startar, hjälparen körs och socketen är helt enkelt inte där ännu. Skriv en tidsstämplad rad från kroken själv, koppla från och anslut igen, och läs händelserna i ordning. När hjälparen verkligen behöver tunneln, låt den fråga efter beredskap i stället för att sova en fast period.
Tre fält gör nästa rapport användbar: vilken krok som kördes, vilket konto den använde och var den stannade. Utan dem börjar varje senare undersökning om.