Пустой массив $_ENV в скрипте хука кажется доказательством того, что OpenVPN ничего не передал. Обычно он доказывает совсем другое: PHP был настроен не заполнять эту суперглобальную переменную, а значения всё это время лежали в окружении процесса. Второй ложный вывод тоньше, потому что две переменные адреса в хуке соединения означают разные вещи, а используются как взаимозаменяемые. Обе ошибки стоят половины дня, если начать с неправильной.

Два адреса, два разных утверждения

Внешняя конечная точка — это то, что сервер наблюдал при подключении клиента, доступна как trusted_ip для IPv4 и trusted_ip6 для IPv6. Виртуальный адрес — это то, что пул выделил для этого сеанса, доступен как ifconfig_pool_remote_ip.

Они отвечают на разные вопросы, и записи обычно нужен один из них, а не оба. Первый говорит, откуда пришло соединение, и это может быть общий адрес NAT, которым пользуются сотни людей. Второй говорит, где этот сеанс живёт внутри туннеля, и позже его можно переназначить другому сеансу. Смешение двух даёт записи, которые выглядят правдоподобно и при этом неверны.

Минимальное чтение выглядит так.

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

Ни одно из значений не идентифицирует человека. Одно — сетевое наблюдение, другое — аренда, и запись, которая считает любое из них стабильным идентификатором устройства, окажется неверной в первый же раз, когда клиент переподключится из другой сети или получит другой адрес из пула. Выбирайте поле по вопросу, на который должна отвечать запись, а затем запишите этот вопрос рядом со столбцом.

Проверяйте, как запущен PHP, а не свою оболочку

Хук работает как дочерний процесс демона VPN с окружением, которое создаёт демон. У вашей интерактивной оболочки оно другое, и запуск скрипта вручную проверяет окружение оболочки, а не хука.

Начните с подтверждения, что хук действительно сработал на том этапе, которого вы ждали. Скрипт, привязанный к неверному этапу, или такой, который так и не запустился, потому что директива указывает на другой путь, даёт ровно тот же симптом, что и отсутствующая переменная. Добавьте намеренную строку-маркер в начало скрипта и убедитесь, что она появляется, прежде чем проверять что-либо ещё. Одна строка с отметкой времени в журнале отличает «так и не запускался» от «запускался без значения».

Затем убедитесь, какой интерпретатор и какой файл конфигурации использует этот вызов. Правка конфигурации PHP для веб-сервера ничего не меняет в процессе CLI, запущенном OpenVPN, и оба могут загружать совершенно разные файлы php.ini.

Почему пустой $_ENV ничего не доказывает

PHP справка по getenv описывает прямое чтение окружения процесса, которое возвращает false, когда имени нет. Суперглобальная переменная $_ENV заполняется отдельно, а директива variables_order решает, какие суперглобальные заполняются.

Если эта директива опускает E, $_ENV остаётся пустым независимо от того, что содержит окружение. Код, который к нему обращается, тогда сообщает об отсутствующей переменной, которая на самом деле есть, и расследование уходит в сторону OpenVPN, тогда как ответ лежит в php.ini. Проверяйте директиву именно для конфигурации CLI, а не для веб-сервера.

Чтение через getenv избавляет от всей этой путаницы, а скрипт-обёртка, очищающий окружение перед вызовом интерпретатора, возвращает её в другой форме.

Храните связь, а не обновление строки

Решите, какое значение нужно записи, прежде чем её писать. Если цель — отметить, откуда пришёл сеанс, сохраните внешнюю конечную точку и пометьте её как наблюдение. Если цель — связать сеанс с адресом туннеля на время соединения, сохраните адрес из пула и привяжите его к сеансу.

Обновляйте по аутентифицированной личности и текущему сеансу, а не по каждой строке с одним и тем же адресом туннеля, потому что адреса из пула используются повторно, и позднее событие отключения иначе может перезаписать данные более нового соединения. Обрабатывайте IPv6 явно, а не пишите молча только значение IPv4. Строка с NULL во внешнем адресе лучше строки с неверным, потому что первая видимо неполна.

Привязывайте запись к идентификатору сеанса, который предоставляет OpenVPN, чтобы переподключение создавало новую запись, а не правил старую. Используйте параметризованные запросы и учётную запись только с теми правами, которые нужны операции. Хук работает с полномочиями демона, поэтому небрежный запрос — проблема шире, чем неверная строка журнала.

Диагностируйте, не вываливая окружение

Записывайте, какие имена присутствовали, какой этап выполнялся и какой интерпретатор использовался. Не печатайте всё окружение, потому что процесс хука может унаследовать посторонние значения, которым не место в файле журнала.

Проверьте одно соединение от начала до конца: прочитайте внешнюю конечную точку, прочитайте выданный адрес и сверьте оба с собственным представлением сервера об этом сеансе. Как только пара подтверждена для одного клиента, связи можно доверять и в других местах.

Похожие статьи