Når et client-connect-script afslutter med en kode, der ikke er nul, afviser OpenVPN klienten, og administratorer antager normalt, at det tilsvarende client-disconnect-script rydder op. Ofte kører det aldrig, fordi disconnect-behandling afhænger af, hvad connect-fasen nåede at fuldføre. At behandle afvisning og tilbagerulning som én mekanisme er det, der gør et mislykket login til en lækket firewallregel eller en forældreløs post. Det er to separate forpligtelser, og kun den ene er automatisk. Læs hookens egen exit-sti, før du bebrejder serveren, at den efterlader tilstand.

En ikke-nul exit afviser klienten; den ruller ikke dit arbejde tilbage

Exit-status for client-connect er en adgangsbeslutning. Nul betyder adgang, alt andet betyder, at instansen rives ned, før den er fuldt etableret. Intet i den kontrakt undersøger, hvad scriptet allerede har gjort mod omverdenen. Hvis scriptet tilføjede en iptables-regel, skrev en række eller øgede en tæller, overlever disse ændringer afvisningen.

Den samme asymmetri gælder for plugins, hvor flere connect-funktioner kan køre for én instans. En senere fejl annullerer ikke en tidligere succes med tilbagevirkende kraft, og den tidligere funktion har ingen måde at erfare, at en søskendefunktion fejlede.

Afvisning er automatisk, oprydning er ikke

OpenVPN 2.6-manualen binder behandlingen af client-disconnect til, at den forudgående connect-behandling er lykkedes. En dokumenteret undtagelse dækker kaskaderede kæder: hvis ét connect-trin allerede har returneret succes, kører de tilsvarende disconnect-trin stadig, når instansen rives ned, selv om et senere connect-trin fejlede. Undtagelsen er snæver og afhænger af, hvor mange callbacks der er konfigureret, og derfor fortæller test af ét shell-script dig intet om en kæde.

Kortlæg den faktiske konfiguration, før du designer omkring den: hvilket script, hvilket plugin og i hvilken rækkefølge de kører. Tabellen nedenfor viser, hvad et halvfærdigt opsæt efterlader.

What the hook did before failingWhat the client seesWhat stays behind
Created a firewall entryA rejection, with no tunnelA rule matching an address nobody owns
Wrote a state rowA rejection, with no tunnelA record of a session that never started
Allocated a tunnel addressA rejection, with no tunnelAn address marked busy until something releases it

Hver række ender ens for klienten og forskelligt for værten. Klienten kan ikke se, hvilken af dem der skete, så hooken skal rulle tilbage, hvad den gjorde, før den returnerer fejlstatussen.

Kompensér inde i det script, der fejlede

Validér alt, hvad du kan, før du rører delt tilstand: certifikatfelter, adressens tilgængelighed, den gruppe klienten tilhører. Den billigste afvisning er den, der sker før nogen tildeling. Når opsætningen spænder over flere eksterne operationer, før en oversigt over, hvilke der blev fuldført, og rul dem tilbage i omvendt rækkefølge, før du returnerer fejlstatussen.

Et konkret tilfælde: scriptet opretter en firewallpost pr. klient og fejler derefter med at skrive den tilstandslinje, der beskriver den. Den fejlende gren skal fjerne posten, den netop oprettede, og derefter afslutte med ikke-nul. At vente på en disconnect-hændelse, der måske aldrig bliver planlagt, er hvordan en regel overlever den session, den var beregnet til.

Gør kompensationen idempotent og ejet

Oprydning skal kunne køres to gange uden skade og være præcis om, hvad den må slette. En sen hændelse fra et tidligere forsøg bør ikke fjerne en nyere sessions tildeling, blot fordi begge deler et fælles navn eller en genbrugt tunneladresse. Registrér det konkrete håndtag eller operations-id sammen med ressourcen, og slet ud fra den nøgle i stedet for efter navn. Databasetransaktioner hjælper kun med databasens egne ændringer; en firewallregel uden for den grænse kræver et eksplicit kompensationstrin.

Antag, at processen kan dø mellem ændringen og oprydningen, og tilføj en afstemmer, der efter en tidsplan sammenligner ekstern tilstand med listen over optagede klienter.

Test de tre stier, der faktisk er forskellige

Øv tre tilfælde: en afvisning før noget som helst er tildelt, en efter en delvis tildeling og en normal optaget session, der senere slutter. De tre giver forskellige loglinjer og forskellige rester. Verificér den eksterne tilstand efter hver af dem, ikke kun klientens fejlmeddelelse, fordi klientens fejl er det forventede resultat i to af de tre.

Log hookens fase, exit-status og hvad der blev tildelt eller frigivet, uden legitimationsoplysninger. En hook-log, der navngiver den ressource, den oprettede, er det, der gør en lækket regel findbar seks måneder senere.

Relaterede artikler