O înregistrare de deconectare sosește după ce o a doua conexiune sub același nume a început deja, iar un handler care actualizează cel mai recent rând pentru acel utilizator închide sesiunea greșită. Greșeala nu este comparația marcajelor de timp. Greșeala este presupunerea că un nume plus o secundă întreagă identifică o sesiune. Evenimentele hook descriu conexiuni, iar o conexiune are nevoie de o cheie care îi aparține doar ei.

Începeți cu ceea ce înseamnă de fapt variabilele de deconectare. Abia atunci alegerea identificatorului are sens.

Ce transportă de fapt hook-ul de deconectare

În Community OpenVPN 2.6, referința hook-urilor time_unix îl definește ca momentul în care clientul s-a conectat; el este stabilit înainte ca hook-ul de conectare să ruleze și nu este redefinit când hook-ul de deconectare se declanșează mai târziu. time_duration oferă durata acelei sesiuni în secunde, deci sfârșitul este aproximativ ora conectării plus durata. Ambele sunt secunde întregi și niciuna nu este momentul în care baza dumneavoastră de date a procesat evenimentul. Tocmai păstrarea separată a acestor trei timpuri face ca o corelație să reziste, în loc să pară doar corectă în timpul testelor.

Această aritmetică merită scrisă, pentru că este singurul timp de sfârșit pe care îl oferă hook-ul însuși. Întârzierea de procesare și diferențele de ceas între gazde rămân în afara ei.

De ce perechea evidentă nu este unică

Asocierea numelui cu ora conectării restrânge căutarea și tot nu identifică o sesiune. Un client se poate reconecta în aceeași secundă, așa că două sesiuni pot împărtăși ambele valori. Două instanțe ale daemonului, sau o înlocuire de server care păstrează aceeași configurație, pot produce acea pereche din procese diferite. Adresele de tunel sunt reciclate din același motiv, ceea ce le face atribute ale unei sesiuni, nu identificatori pentru ea.

Modul de eșec este silențios. O deconectare târzie pentru prima sesiune corespunde celui mai recent rând și închide o alocare pe care a doua sesiune o folosește încă, așa că utilizatorul experimentează o pierdere aleatorie de acces pe care nu a provocat-o. Un număr de rânduri care pare corect după aceea face problema mai greu de observat.

De unde vine o identitate stabilă

Interfața de administrare atribuie fiecărui client un identificator de instanță de client, iar acel identificator este limitat la instanța daemonului care l-a emis. O cheie externă viabilă combină un identificator stabil de server, o epocă ce se schimbă la pornirea daemonului și acel ID de client. Epoca contează pentru că identificatorii repornesc odată cu procesul, iar un ID de proces gol poate fi reutilizat mai târziu de ceva nelegat.

Variabilele de mediu setate în interiorul unui script de conectare copil nu călătoresc către scriptul de deconectare ulterior al daemonului părinte, pentru că acele scripturi rulează ca procese separate cu propriile medii. Așadar, generarea unui UUID la momentul conectării este jumătate de soluție. Partea de deconectare trebuie să poată numi același UUID, ceea ce înseamnă că identitatea trebuie să trăiască undeva unde ambele evenimente pot ajunge.

Faceți retragerea condiționată și idempotentă

Retrageți după proprietarul sesiunii, nu după utilizator. Un handler care șterge orice alocare care aparține în prezent unui nume va șterge în cele din urmă pe cea greșită, iar singura apărare este să verificați că înregistrarea eliminată este înregistrarea pe care o descrie acest eveniment.

Interfața de administrare acceptă un singur client de administrare conectat odată, așa că integrați-vă cu cel care o deține deja în loc să atașați un al doilea observator care concurează pentru același socket.

Gestionați evenimentele repetate fără a schimba rezultatul de două ori și păstrați evenimentele neîmperecheate pentru reconciliere în loc să le aruncați. Un callback de deconectare are condiții de ciclu de viață documentate și poate să nu sosească niciodată după o prăbușire sau o oprire dură, așa că designul are nevoie de o modalitate de a reprezenta o sesiune al cărei eveniment final lipsește.

Testați cazurile incomode intenționat: două reconectări într-o secundă, două instanțe ale daemonului, o conexiune a cărei procesare a eșuat și o repornire a daemonului la mijlocul unei sesiuni. O cheie care supraviețuiește tuturor patru este o cheie demnă de încredere.

Articole similare