Événements de hook OpenVPN : pourquoi le nom et l’horodatage ne sont pas une clé
Un hook de déconnexion rapporte l’heure de connexion, pas l’heure de déconnexion. Associé au nom d’utilisateur, il peut retirer la mauvaise session ; possédez plutôt une identité.
Un enregistrement de déconnexion arrive après qu’une seconde connexion sous le même nom a déjà commencé, et un gestionnaire qui met à jour la ligne la plus récente de cet utilisateur ferme la mauvaise session. L’erreur n’est pas la comparaison des horodatages. C’est l’hypothèse qu’un nom plus une seconde entière identifient une session. Les événements de hook décrivent des connexions, et une connexion a besoin d’une clé qui lui appartient en propre.
Commencez par ce que signifient réellement les variables de déconnexion. C’est alors seulement que le choix de l’identifiant a un sens.
Ce que le hook de déconnexion transporte vraiment
Dans Community OpenVPN 2.6, la référence des hooks time_unix définit le moment où le client s’est connecté ; il est fixé avant l’exécution du hook de connexion et n’est pas redéfini lorsque le hook de déconnexion se déclenche plus tard. time_duration donne la durée de cette session en secondes, si bien que la fin est à peu près l’heure de connexion plus la durée. Les deux sont des secondes entières, et aucune n’est le moment où votre base de données a traité l’événement. C’est en gardant ces trois temps distincts qu’une corrélation tient, au lieu de seulement paraître correcte pendant les tests.
Cette arithmétique mérite d’être écrite, car c’est la seule heure de fin que le hook lui-même offre. Le délai de traitement et les écarts d’horloge entre hôtes restent en dehors.
Pourquoi la paire évidente n’est pas unique
Associer le nom à l’heure de connexion restreint la recherche et n’identifie toujours pas une session. Un client peut se reconnecter dans la même seconde, si bien que deux sessions peuvent partager les deux valeurs. Deux instances de démon, ou un remplacement de serveur qui conserve la même configuration, peuvent produire cette paire depuis des processus différents. Les adresses de tunnel sont recyclées pour la même raison, ce qui en fait des attributs d’une session plutôt que des identifiants de celle-ci.
Le mode de défaillance est silencieux. Une déconnexion tardive de la première session correspond à la ligne la plus récente et retire une allocation que la seconde session utilise encore, si bien que l’utilisateur subit une perte d’accès aléatoire qu’il n’a pas provoquée. Un nombre de lignes qui semble correct ensuite rend le problème plus difficile à repérer.
D’où vient une identité stable
L’interface de gestion attribue à chaque client un identifiant d’instance de client, et cet identifiant est limité à l’instance de démon qui l’a émis. Une clé externe exploitable combine un identifiant de serveur stable, une époque qui change au démarrage du démon et cet ID de client. L’époque compte parce que les identifiants redémarrent avec le processus, et un simple ID de processus peut être réutilisé plus tard par quelque chose sans rapport.
Les variables d’environnement définies dans un script de connexion enfant ne voyagent pas vers le script de déconnexion ultérieur du démon parent, car ces scripts s’exécutent comme des processus séparés avec leurs propres environnements. Générer un UUID au moment de la connexion n’est donc qu’une demi-solution. Le côté déconnexion doit pouvoir nommer le même UUID, ce qui signifie que l’identité doit vivre quelque part où les deux événements peuvent l’atteindre.
Rendez la retraite conditionnelle et idempotente
Retirez par propriétaire de session, pas par utilisateur. Un gestionnaire qui supprime toute allocation appartenant actuellement à un nom finira par supprimer la mauvaise, et la seule défense est de vérifier que l’enregistrement supprimé est celui que cet événement décrit.
L’interface de gestion n’accepte qu’un seul client de gestion connecté à la fois, alors intégrez-vous à celui qui la possède déjà plutôt que d’attacher un second observateur qui se dispute la même socket.
Gérez les événements répétés sans modifier le résultat deux fois, et conservez les événements non appariés pour la réconciliation au lieu de les jeter. Un rappel de déconnexion a des conditions de cycle de vie documentées et peut ne jamais arriver après un plantage ou un arrêt brutal, donc la conception a besoin d’un moyen de représenter une session dont l’événement de fin manque.
Testez les cas délicats exprès : deux reconnexions dans la même seconde, deux instances de démon, une connexion dont le traitement a échoué et un redémarrage du démon au milieu d’une session. Une clé qui survit aux quatre mérite la confiance.