OpenVPN-hookhändelser: varför namn och tidsstämpel inte är en nyckel
En frånkopplingshook rapporterar anslutningstiden, inte frånkopplingstiden. Tillsammans med användarnamnet kan den avsluta fel session; äg en identitet i stället.
En frånkopplingspost kommer efter att en andra anslutning under samma namn redan har börjat, och en hanterare som uppdaterar den nyaste raden för den användaren stänger fel session. Felet är inte själva tidsstämpeljämförelsen. Det är antagandet att ett namn plus en hel sekund identifierar en session. Hookhändelser beskriver anslutningar, och en anslutning behöver en nyckel som bara tillhör den.
Börja med vad frånkopplingsvariablerna egentligen betyder. Först då blir valet av identifierare meningsfullt.
Vad frånkopplingshooken egentligen bär
I Community OpenVPN 2.6 definierar hook-referensen time_unix som ögonblicket då klienten anslöt; det sätts innan anslutningshooken körs och omdefinieras inte när frånkopplingshooken senare utlöses. time_duration anger längden på den sessionen i sekunder, så slutet är ungefär anslutningstiden plus varaktigheten. Båda är hela sekunder, och ingen av dem är ögonblicket då din databas behandlade händelsen. Det är att hålla dessa tre tider åtskilda som gör att en korrelation håller, i stället för att bara se rätt ut under testning.
Den här aritmetiken förtjänar att skrivas ned, eftersom det är den enda sluttid som hooken själv erbjuder. Bearbetningsfördröjning och klockavvikelser mellan värdar ligger fortfarande utanför.
Varför det uppenbara paret inte är unikt
Att para ihop namnet med anslutningstiden snävar in sökningen och identifierar fortfarande inte en session. En klient kan återansluta inom samma sekund, så två sessioner kan dela båda värdena. Två daemoninstanser, eller ett serverbyte som behåller samma konfiguration, kan producera det paret från olika processer. Tunneladresser återvinns av samma skäl, vilket gör dem till attribut för en session snarare än identifierare för den.
Fellget är tyst. En sen frånkoppling för den första sessionen matchar den nyaste raden och avslutar en tilldelning som den andra sessionen fortfarande använder, så användaren upplever en slumpmässig förlust av åtkomst som de inte orsakade. Ett radantal som ser korrekt ut efteråt gör problemet svårare att upptäcka.
Varifrån en stabil identitet kommer
Hanteringsgränssnittet tilldelar varje klient en klientinstansidentifierare, och den identifieraren är begränsad till den daemoninstans som utfärdade den. En användbar extern nyckel kombinerar en stabil serveridentifierare, en epok som ändras när daemonen startar, och det klient-ID:t. Epoken spelar roll eftersom identifierare startar om med processen, och ett bart process-ID kan senare återanvändas av något orelaterat.
Miljövariabler som sätts inuti ett underordnat anslutningsskript färdas inte till den överordnade daemonens senare frånkopplingsskript, eftersom dessa skript körs som separata processer med egna miljöer. Därför är generering av ett UUID vid anslutning bara halva lösningen. Frånkopplingssidan måste kunna namnge samma UUID, vilket innebär att identiteten måste leva någonstans där båda händelserna kan nå den.
Gör avslutningen villkorad och idempotent
Avsluta efter sessionens ägare, inte efter användare. En hanterare som raderar vilken tilldelning som helst som för närvarande tillhör ett namn kommer till slut att radera fel, och det enda försvaret är att kontrollera att posten som tas bort är posten som den här händelsen beskriver.
Hanteringsgränssnittet accepterar en ansluten hanteringsklient i taget, så integrera med den som redan äger det i stället för att fästa en andra observatör som konkurrerar om samma socket.
Hantera upprepade händelser utan att ändra resultatet två gånger, och spara oparade händelser för avstämning i stället för att kasta bort dem. En frånkopplingscallback har dokumenterade livscykelvillkor och kommer kanske aldrig efter en krasch eller en hård stopp, så designen behöver ett sätt att representera en session vars sluthändelse saknas.
Testa de besvärliga fallen med avsikt: två återanslutningar inom en sekund, två daemoninstanser, en anslutning vars bearbetning misslyckades, och en daemonomstart mitt i en session. En nyckel som överlever alla fyra är en nyckel värd att lita på.