Hook PHP de OpenVPN: trusted_ip frente a ifconfig_pool_remote_ip
Dos direcciones con dos significados distintos, leídas por un proceso que no lanzaste tú. Qué son las variables del hook y por qué un $_ENV vacío no demuestra nada.
Una matriz $_ENV vacía en un script de hook parece la prueba de que OpenVPN no pasó nada. Normalmente es la prueba de algo completamente distinto: PHP estaba configurado para no rellenar esa superglobal, y los valores llevaban todo el tiempo en el entorno del proceso. La segunda conclusión falsa es más sutil, porque las dos variables de dirección de un hook de conexión significan cosas distintas y se usan de forma intercambiable. Ambos errores cuestan una tarde si empiezas por el equivocado.
Dos direcciones, dos afirmaciones distintas
El extremo externo es lo que el servidor observó cuando se conectó el cliente, disponible como trusted_ip para IPv4 y trusted_ip6 para IPv6. La dirección virtual es la que el pool asignó a esta sesión, disponible como ifconfig_pool_remote_ip.
Responden a preguntas distintas, y un registro normalmente necesita una de las dos en lugar de ambas. La primera es de dónde llegó la conexión, que puede ser una dirección NAT compartida por cientos de personas. La segunda es dónde vive esta sesión dentro del túnel, y puede reasignarse a otra sesión más adelante. Confundir las dos produce registros que parecen plausibles y son incorrectos.
Una lectura mínima tiene este aspecto.
$outer4 = getenv('trusted_ip');
$outer6 = getenv('trusted_ip6');
$inner = getenv('ifconfig_pool_remote_ip');
$outer = $outer4 !== false ? $outer4 : $outer6;Ninguno de los dos valores identifica a una persona. Uno es una observación de red, el otro un arrendamiento, y un registro que trate cualquiera de los dos como identificador estable de dispositivo estará mal la primera vez que un cliente se reconecte desde otra red o reciba otra dirección del pool. Elige el campo por la pregunta que el registro debe responder, y luego escribe esa pregunta junto a la columna.
Comprueba cómo se lanzó PHP, no tu shell
El hook se ejecuta como hijo del demonio VPN con un entorno que el demonio construye. Tu shell interactiva tiene otro, y ejecutar el script a mano prueba el entorno de la shell y no el del hook.
Empieza confirmando que el hook se disparó realmente en la etapa que esperabas. Un script asociado a la etapa equivocada, o uno que nunca se ejecutó porque la directiva apunta a otra ruta, produce exactamente el mismo síntoma que una variable ausente. Añade una línea marcadora deliberada al principio del script y confirma que aparece antes de inspeccionar cualquier otra cosa. Una sola línea con marca de tiempo en el registro separa nunca se ejecutó de se ejecutó sin el valor.
Después confirma qué intérprete y qué archivo de configuración usa esa invocación. Editar la configuración de PHP de un servidor web no cambia nada en un proceso CLI iniciado por OpenVPN, y ambos pueden cargar archivos php.ini completamente distintos.
Por qué un $_ENV vacío no demuestra nada
La referencia de getenv de PHP documenta una lectura directa del entorno del proceso, que devuelve false cuando el nombre no está. La superglobal $_ENV se rellena por separado, y la directiva variables_order decide qué superglobales se rellenan.
Si esa directiva omite E, $_ENV se queda vacía sin importar lo que contenga el entorno. El código que la indexa entonces informa de una variable ausente que en realidad está presente, y la investigación va hacia OpenVPN cuando la respuesta está en php.ini. Comprueba la directiva específicamente para la configuración CLI, no para el servidor web.
Leer con getenv evita toda esta clase de confusión, y un script envoltorio que limpie el entorno antes de invocar al intérprete la reintroduce de otra forma.
Guarda una asociación, no una actualización de fila
Decide qué valor necesita el registro antes de escribirlo. Si el objetivo es anotar de dónde vino una sesión, guarda el extremo externo y etiquétalo como observación. Si el objetivo es mapear una sesión a una dirección de túnel durante una conexión, guarda la dirección del pool y vincúlala a la sesión.
Actualiza por la identidad autenticada y la sesión actual en lugar de por cada fila que comparte una dirección de túnel, porque las direcciones del pool se reutilizan y un evento de desconexión tardío puede sobrescribir los datos de una conexión más reciente. Trata IPv6 de forma explícita en vez de escribir en silencio solo el valor IPv4. Una fila con dirección externa NULL es mejor que una con la equivocada, porque la primera es visiblemente incompleta.
Vincula la escritura al identificador de sesión que proporciona OpenVPN, para que una reconexión cree un registro nuevo en lugar de editar el antiguo. Usa sentencias parametrizadas y una cuenta con solo los permisos que necesita la operación. Un hook se ejecuta con la autoridad del demonio, así que una consulta descuidada es un problema más amplio que una línea de registro errónea.
Diagnostica sin volcar el entorno
Registra qué nombres estaban presentes, qué etapa se ejecutó y qué intérprete se usó. No imprimas todo el entorno, porque un proceso de hook puede heredar valores ajenos que no deberían acabar en un archivo de registro.
Verifica una conexión de extremo a extremo: lee el extremo externo, lee la dirección asignada y confirma ambas contra la visión propia del servidor de esa sesión. Una vez confirmado el par para un cliente, la asociación se puede confiar en otros lugares.