Prázdné pole $_ENV ve skriptu hooku vypadá jako důkaz, že OpenVPN nic nepředalo. Obvykle je to důkaz něčeho úplně jiného: PHP bylo nastaveno, aby tenhle superglobal neplnilo, a hodnoty celou dobu seděly v prostředí procesu. Druhý chybný závěr je jemnější, protože dvě proměnné adresy v hooku spojení znamenají různé věci a používají se zaměnitelně. Obě chyby stojí odpoledne, pokud začnete tou špatnou.

Dvě adresy, dvě různá tvrzení

Vnější koncový bod je to, co server pozoroval při připojení klienta, dostupný jako trusted_ip pro IPv4 a trusted_ip6 pro IPv6. Virtuální adresa je to, co pool přidělil této relaci, dostupná jako ifconfig_pool_remote_ip.

Odpovídají na různé otázky a záznam obvykle potřebuje jednu z nich, ne obě. První je, odkud spojení přišlo, což může být sdílená NAT adresa, kterou používá stovky lidí. Druhá je, kde tato relace žije uvnitř tunelu, a může být později přidělena jiné relaci. Záměna obou dává záznamy, které vypadají věrohodně a jsou špatné.

Minimální čtení vypadá takto.

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

Ani jedna z hodnot neidentifikuje člověka. Jedna je síťové pozorování, druhá je pronájem, a záznam, který kteroukoli z nich bere jako stabilní identifikátor zařízení, bude špatný poprvé, kdy se klient připojí z jiné sítě nebo dostane jinou adresu z poolu. Vyberte pole podle otázky, na kterou má záznam odpovědět, a pak tu otázku napište vedle sloupce.

Zkontrolujte, jak bylo PHP spuštěno, ne svůj shell

Hook běží jako potomek VPN démona s prostředím, které démon sestaví. Vaše interaktivní shell má jiné a ruční spuštění skriptu testuje prostředí shellu, ne hooku.

Začněte potvrzením, že se hook skutečně spustil ve fázi, kterou jste očekávali. Skript připojený ke špatné fázi, nebo takový, který se nikdy nespustil, protože direktiva ukazuje na jinou cestu, dává přesně stejný příznak jako chybějící proměnná. Přidejte na začátek skriptu záměrný značkovací řádek a potvrďte, že se objeví, než začnete zkoumat cokoli dalšího. Jediný řádek s časovým razítkem v logu odděluje „nikdy neběžel“ od „běžel bez hodnoty“.

Potom potvrďte, který interpret a který konfigurační soubor toto volání používá. Úprava PHP konfigurace pro webový server nic nemění na procesu CLI spuštěném OpenVPN a oba mohou načítat zcela odlišné soubory php.ini.

Proč prázdné $_ENV nic nedokazuje

PHP reference getenv dokumentuje přímé čtení prostředí procesu, které vrací false, když jméno chybí. Superglobal $_ENV se plní zvlášť a direktiva variables_order rozhoduje, které superglobaly se naplní.

Pokud tato direktiva vynechá E, $_ENV zůstane prázdné bez ohledu na to, co prostředí obsahuje. Kód, který ho indexuje, pak hlásí chybějící proměnnou, která ve skutečnosti existuje, a vyšetřování míří k OpenVPN, zatímco odpověď je v php.ini. Zkontrolujte direktivu konkrétně pro CLI konfiguraci, ne pro webový server.

Čtení přes getenv se celé této třídě zmatení vyhýbá, a obalový skript, který před voláním interpretu vyčistí prostředí, ho zavádí znovu v jiné podobě.

Ukládejte asociaci, ne aktualizaci řádku

Rozhodněte, kterou hodnotu záznam potřebuje, než ji zapíšete. Pokud je cílem poznamenat, odkud relace přišla, uložte vnější koncový bod a označte ho jako pozorování. Pokud je cílem namapovat relaci na adresu tunelu po dobu spojení, uložte adresu z poolu a přivažte ji k relaci.

Aktualizujte podle ověřené identity a aktuální relace, ne podle každého řádku sdílejícího adresu tunelu, protože adresy z poolu se znovu používají a pozdní událost odpojení může jinak přepsat data novějšího spojení. Ošetřete IPv6 výslovně místo tichého zápisu jen hodnoty IPv4. Řádek s NULL vnější adresou je lepší než řádek s nesprávnou, protože první je viditelně neúplný.

Přivažte zápis k identifikátoru relace, který OpenVPN poskytuje, aby opětovné připojení vytvořilo nový záznam místo úpravy starého. Používejte parametrizované příkazy a účet jen s oprávněními, která operace potřebuje. Hook běží s pravomocemi démona, takže nedbalý dotaz je širší problém než špatný řádek logu.

Diagnostikujte bez výpisu prostředí

Zaznamenejte, která jména byla přítomná, která fáze běžela a který interpret byl použit. Nevypisujte celé prostředí, protože proces hooku může zdědit nesouvisející hodnoty, které by neměly skončit v logu.

Ověřte jedno spojení od začátku do konce: přečtěte vnější koncový bod, přečtěte přidělenou adresu a potvrďte obojí proti vlastnímu pohledu serveru na tuto relaci. Jakmile je dvojice potvrzena pro jednoho klienta, asociaci lze věřit i jinde.

Související články