Un registro de desconexión llega después de que ya haya comenzado una segunda conexión con el mismo nombre, y un manejador que actualiza la fila más reciente de ese usuario cierra la sesión equivocada. El error no es la comparación de marcas de tiempo. Es la suposición de que un nombre más un segundo entero identifican una sesión. Los eventos de hook describen conexiones, y una conexión necesita una clave que le pertenezca solo a ella.

Empiece por lo que significan realmente las variables de desconexión. Solo entonces tiene sentido la elección del identificador.

Qué transporta realmente el hook de desconexión

En Community OpenVPN 2.6, la referencia de hooks time_unix define como el momento en que se conectó el cliente; se establece antes de que se ejecute el hook de conexión y no se redefine cuando el hook de desconexión se activa después. time_duration da la duración de esa sesión en segundos, así que el final es aproximadamente la hora de conexión más la duración. Ambos son segundos enteros, y ninguno es el momento en que su base de datos procesó el evento. Mantener esos tres tiempos separados es lo que hace que una correlación se sostenga en lugar de solo parecer correcta durante las pruebas.

Esta aritmética merece escribirse, porque es el único tiempo de finalización que ofrece el propio hook. El retraso de procesamiento y las diferencias de reloj entre hosts siguen quedando fuera.

Por qué el par obvio no es único

Emparejar el nombre con la hora de conexión reduce la búsqueda y sigue sin identificar una sesión. Un cliente puede reconectarse dentro del mismo segundo, así que dos sesiones pueden compartir ambos valores. Dos instancias del demonio, o un reemplazo de servidor que conserva la misma configuración, pueden producir ese par desde procesos distintos. Las direcciones de túnel se reciclan por la misma razón, lo que las convierte en atributos de una sesión más que en identificadores de una.

El modo de fallo es silencioso. Una desconexión tardía de la primera sesión coincide con la fila más reciente y retira una asignación que la segunda sesión todavía usa, así que el usuario experimenta una pérdida de acceso aleatoria que no provocó. Un recuento de filas que después parece correcto hace que el problema sea más difícil de detectar.

De dónde viene una identidad estable

La interfaz de administración asigna a cada cliente un identificador de instancia de cliente, y ese identificador está limitado a la instancia del demonio que lo emitió. Una clave externa viable combina un identificador de servidor estable, una época que cambia cuando arranca el demonio y ese ID de cliente. La época importa porque los identificadores se reinician con el proceso, y un ID de proceso desnudo puede reutilizarse más tarde por algo no relacionado.

Las variables de entorno definidas dentro de un script de conexión hijo no viajan al script de desconexión posterior del demonio padre, porque esos scripts se ejecutan como procesos separados con sus propios entornos. Por eso, generar un UUID en el momento de la conexión es media solución. El lado de la desconexión tiene que poder nombrar el mismo UUID, lo que significa que la identidad debe vivir en algún lugar al que puedan llegar ambos eventos.

Haga la retirada condicional e idempotente

Retire por propietario de sesión, no por usuario. Un manejador que elimina cualquier asignación que actualmente pertenezca a un nombre acabará eliminando la equivocada, y la única defensa es comprobar que el registro que se elimina es el registro que describe este evento.

La interfaz de administración acepta un solo cliente de administración conectado a la vez, así que intégrese con quien ya la posee en lugar de adjuntar un segundo observador que compita por el mismo socket.

Gestione eventos repetidos sin cambiar el resultado dos veces, y conserve los eventos no emparejados para la reconciliación en lugar de descartarlos. Una devolución de llamada de desconexión tiene condiciones de ciclo de vida documentadas y puede no llegar nunca tras un fallo o una parada forzada, así que el diseño necesita una forma de representar una sesión cuyo evento final falta.

Pruebe los casos incómodos a propósito: dos reconexiones dentro de un segundo, dos instancias del demonio, una conexión cuyo procesamiento falló y un reinicio del demonio en medio de una sesión. Una clave que sobrevive a los cuatro es una clave digna de confianza.

Artículos relacionados