En tom $_ENV-array i ett hookskript känns som bevis för att OpenVPN inte skickade något. Oftast bevisar den något helt annat: PHP var konfigurerat att inte fylla den superglobala variabeln, och värdena låg i processens miljö hela tiden. Den andra felaktiga slutsatsen är mer subtil, eftersom de två adressvariablerna i en anslutningshook betyder olika saker och används om vartannat. Båda felen kostar en eftermiddag om du börjar med det felaktiga.

Två adresser, två olika påståenden

Den yttre ändpunkten är vad servern observerade när klienten anslöt, tillgänglig som trusted_ip för IPv4 och trusted_ip6 för IPv6. Den virtuella adressen är vad poolen tilldelade för denna session, tillgänglig som ifconfig_pool_remote_ip.

De svarar på olika frågor, och en post behöver oftast en av dem, inte båda. Den första är varifrån anslutningen kom, vilket kan vara en delad NAT-adress som hundratals människor använder. Den andra är var denna session bor inne i tunneln, och den kan tilldelas en annan session senare. Att blanda ihop de två ger poster som ser rimliga ut och är felaktiga.

En minimal läsning ser ut så här.

$outer4 = getenv('trusted_ip');
$outer6 = getenv('trusted_ip6');
$inner  = getenv('ifconfig_pool_remote_ip');
$outer  = $outer4 !== false ? $outer4 : $outer6;

Inget av värdena identifierar en person. Det ena är en nätverksobservation, det andra ett arrende, och en post som behandlar något av dem som en stabil enhetsidentifierare blir fel första gången en klient återansluter från ett annat nätverk eller får en annan pooladress. Välj fältet efter frågan posten måste svara på och skriv den frågan bredvid kolumnen.

Kontrollera hur PHP startades, inte ditt skal

Hooken körs som ett barn till VPN-demonen med en miljö som demonen bygger. Ditt interaktiva skal har en annan, och att köra skriptet för hand testar skalets miljö, inte hookens.

Börja med att bekräfta att hooken faktiskt utlöstes i det skede du förväntade dig. Ett skript kopplat till fel skede, eller ett som aldrig kördes eftersom direktivet pekar på en annan sökväg, ger exakt samma symptom som en saknad variabel. Lägg till en avsiktlig markörrad högst upp i skriptet och bekräfta att den syns innan du undersöker något annat. En enda tidsstämplad rad i loggen skiljer «kördes aldrig» från «kördes utan värdet».

Bekräfta sedan vilken tolk och vilken konfigurationsfil den anropet använder. Att ändra PHP-konfigurationen för en webbserver ändrar ingenting för en CLI-process som startats av OpenVPN, och de två kan läsa in helt olika php.ini-filer.

Varför en tom $_ENV inte bevisar något

PHPs getenv-referens dokumenterar en direkt läsning av processmiljön, som returnerar false när namnet saknas. Den superglobala variabeln $_ENV fylls separat, och direktivet variables_order avgör vilka superglobala variabler som fylls.

Om det direktivet utelämnar E förblir $_ENV tomt oavsett vad miljön innehåller. Kod som indexerar det rapporterar då en saknad variabel som faktiskt finns, och utredningen går mot OpenVPN medan svaret finns i php.ini. Kontrollera direktivet specifikt för CLI-konfigurationen, inte för webbservern.

Läsning med getenv undviker hela denna förvirring, och ett omslagsskript som rensar miljön innan det anropar tolken återinför den i en annan form.

Lagra en koppling, inte en raduppdatering

Bestäm vilket värde posten behöver innan du skriver den. Om målet är att notera varifrån en session kom, lagra den yttre ändpunkten och märk den som en observation. Om målet är att koppla en session till en tunneladress under en anslutnings varaktighet, lagra pooladressen och nyckla den till sessionen.

Uppdatera efter den autentiserade identiteten och den aktuella sessionen, inte efter varje rad som delar en tunneladress, eftersom pooladresser återanvänds och en sen frånkopplingshändelse annars kan skriva över en nyare anslutnings data. Hantera IPv6 explicit i stället för att tyst skriva bara IPv4-värdet. En rad med NULL yttre adress är bättre än en rad med den felaktiga, eftersom den första är synligt ofullständig.

Nyckla skrivningen till sessionsidentifieraren som OpenVPN tillhandahåller så att en återanslutning skapar en ny post i stället för att redigera den gamla. Använd parametriserade satser och ett konto med bara de behörigheter operationen behöver. En hook körs med demonens befogenhet, så en slarvig fråga är ett större problem än en felaktig loggpost.

Diagnostisera utan att dumpa miljön

Logga vilka namn som fanns, vilket skede som kördes och vilken tolk som användes. Skriv inte ut hela miljön, eftersom en hookprocess kan ärva orelaterade värden som inte bör hamna i en loggfil.

Verifiera en anslutning från början till slut: läs den yttre ändpunkten, läs den tilldelade adressen och bekräfta båda mot serverns egen bild av den sessionen. När paret är bekräftat för en klient går det att lita på kopplingen på andra ställen.

Relaterade artiklar