OpenVPN-hookgebeurtenissen: waarom naam en tijdstempel geen sleutel zijn
Een verbindingsverbrekingshook meldt de verbindingstijd, niet de verbrekingstijd. Samen met de gebruikersnaam kan hij de verkeerde sessie beëindigen; bezit in plaats daarvan een identiteit.
Een verbrekingsrecord komt binnen nadat een tweede verbinding onder dezelfde naam al is begonnen, en een handler die de nieuwste rij voor die gebruiker bijwerkt, sluit de verkeerde sessie. De fout is niet de vergelijking van tijdstempels. Het is de aanname dat een naam plus een hele seconde één sessie identificeren. Hookgebeurtenissen beschrijven verbindingen, en een verbinding heeft een sleutel nodig die alleen bij haar hoort.
Begin met wat de verbrekingsvariabelen werkelijk betekenen. Pas dan is de keuze van identificatie zinvol.
Wat de verbrekingshook werkelijk draagt
In Community OpenVPN 2.6 definieert de hook-referentie time_unix als het moment waarop de client verbond; deze wordt ingesteld voordat de verbindingshook loopt en wordt niet opnieuw gedefinieerd wanneer de verbrekingshook later afgaat. time_duration geeft de lengte van die sessie in seconden, dus het einde is ongeveer de verbindingstijd plus de duur. Beide zijn hele seconden, en geen van beide is het moment waarop uw database de gebeurtenis verwerkte. Juist het gescheiden houden van die drie tijden zorgt ervoor dat een correlatie standhoudt, in plaats van alleen tijdens tests juist te lijken.
Deze rekenkunde verdient het opgeschreven te worden, want het is de enige eindtijd die de hook zelf biedt. Verwerkingsvertraging en klokverschillen tussen hosts vallen er nog steeds buiten.
Waarom het voor de hand liggende paar niet uniek is
Het koppelen van de naam aan de verbindingstijd vernauwt de zoektocht en identificeert nog steeds geen sessie. Een client kan binnen dezelfde seconde opnieuw verbinden, dus twee sessies kunnen beide waarden delen. Twee daemon-instanties, of een serververvanging die dezelfde configuratie behoudt, kunnen dat paar uit verschillende processen produceren. Tunneladressen worden om dezelfde reden hergebruikt, wat ze tot attributen van een sessie maakt in plaats van identificaties ervoor.
De faalmodus is stil. Een late verbreking voor de eerste sessie past bij de nieuwste rij en beëindigt een toewijzing die de tweede sessie nog gebruikt, zodat de gebruiker een willekeurig toegangsverlies ervaart dat hij niet heeft veroorzaakt. Een rijaantal dat er daarna correct uitziet, maakt het probleem moeilijker te ontdekken.
Waar een stabiele identiteit vandaan komt
De beheerinterface kent elke client een client-instantie-identificatie toe, en die identificatie is beperkt tot de daemon-instantie die haar heeft uitgegeven. Een bruikbare externe sleutel combineert een stabiele serveridentificatie, een epoche die verandert wanneer de daemon start, en die client-ID. De epoche is belangrijk omdat identificaties met het proces opnieuw beginnen, en een kale proces-ID kan later door iets ongerelateerds opnieuw worden gebruikt.
Omgevingsvariabelen die binnen een onderliggend verbindingsscript worden ingesteld, reizen niet naar het latere verbrekingsscript van de bovenliggende daemon, omdat die scripts als afzonderlijke processen met hun eigen omgeving draaien. Daarom is het genereren van een UUID op verbindingstijd slechts de helft van een oplossing. De verbrekingskant moet dezelfde UUID kunnen benoemen, wat betekent dat de identiteit ergens moet leven waar beide gebeurtenissen haar kunnen bereiken.
Maak het beëindigen voorwaardelijk en idempotent
Beëindig op sessie-eigenaar, niet op gebruiker. Een handler die elke toewijzing verwijdert die momenteel bij een naam hoort, verwijdert uiteindelijk de verkeerde, en de enige verdediging is controleren dat het record dat wordt verwijderd het record is dat deze gebeurtenis beschrijft.
De beheerinterface accepteert één verbonden beheerclient per keer, dus integreer met degene die haar al bezit in plaats van een tweede waarnemer aan te sluiten die om dezelfde socket strijdt.
Behandel herhaalde gebeurtenissen zonder de uitkomst twee keer te wijzigen, en bewaar ongepaarde gebeurtenissen voor afstemming in plaats van ze weg te gooien. Een verbrekingscallback heeft gedocumenteerde levenscyclusvoorwaarden en komt na een crash of een harde stop mogelijk nooit aan, dus het ontwerp heeft een manier nodig om een sessie weer te geven waarvan de eindgebeurtenis ontbreekt.
Test de lastige gevallen expres: twee herverbindingen binnen één seconde, twee daemon-instanties, een verbinding waarvan de verwerking mislukte, en een daemon-herstart midden in een sessie. Een sleutel die alle vier overleeft, is een sleutel die vertrouwen waard is.