Napaka client-connect v OpenVPN: je čiščenje pri disconnect zagotovljeno?
Zavrnjen odjemalec ne razveljavi požarnega pravila ali zapisanega zapisa. Primerjajte pogodbo povratnega klica z razveljavitvijo, ki jo mora vaš hook izvesti sam.
Ko skript client-connect konča z neničelno kodo, OpenVPN zavrne odjemalca, in skrbniki običajno domnevajo, da bo ustrezni skript client-disconnect vse pospravil. Pogosto se nikoli ne zažene, ker je obdelava disconnect odvisna od tega, kaj je uspela dokončati faza connect. Obravnavanje zavrnitve in razveljavitve kot enega mehanizma je tisto, kar neuspešno prijavo spremeni v uhajajoče požarno pravilo ali osirotel zapis. To sta dve ločeni obveznosti in le ena od njiju je samodejna. Preberite lastno izhodno pot hooka, preden krivite strežnik, da je pustil stanje.
Neničelni izhod zavrne odjemalca; ne razveljavi vašega dela
Izhodni status client-connect je odločitev o sprejemu. Nič pomeni sprejeti, karkoli drugega pomeni porušiti instanco, preden se v celoti vzpostavi. Nič v tej pogodbi ne pregleduje, kaj je skript že storil v zunanjem svetu. Če je skript dodal pravilo iptables, zapisal vrstico ali povečal števec, te spremembe preživijo zavrnitev.
Enaka asimetrija velja za vtičnike, kjer se lahko za eno instanco izvede več funkcij connect. Poznejša napaka ne razveljavi retroaktivno prejšnjega uspeha in prejšnja funkcija ne more izvedeti, da je sestrska funkcija spodletela.
Zavrnitev je samodejna, čiščenje ni
Priročnik OpenVPN 2.6 veže obdelavo client-disconnect na uspešno dokončanje predhodne obdelave connect. Dokumentirana izjema pokriva kaskadne verige: če je en korak connect že vrnil uspeh, se ustrezni koraki disconnect ob rušenju instance vseeno izvedejo, tudi če je poznejši korak connect spodletel. Ta izjema je ozka in je odvisna od števila nastavljenih povratnih klicev, zato vam testiranje enega skripta lupine ne pove ničesar o verigi.
Pred načrtovanjem okoli nje preslikajte dejansko konfiguracijo: kateri skript, kateri vtičnik in v kakšnem vrstnem redu se izvajajo. Spodnja tabela navaja, kaj pusti za sabo napol dokončna nastavitev.
| What the hook did before failing | What the client sees | What stays behind |
|---|---|---|
| Created a firewall entry | A rejection, with no tunnel | A rule matching an address nobody owns |
| Wrote a state row | A rejection, with no tunnel | A record of a session that never started |
| Allocated a tunnel address | A rejection, with no tunnel | An address marked busy until something releases it |
Vsaka vrstica se konča enako za odjemalca in drugače za gostitelja. Odjemalec ne more ugotoviti, katera se je zgodila, zato mora hook pred vrnitvijo statusa napake razveljaviti, kar je storil.
Nadomestite znotraj skripta, ki je spodletel
Preverite vse, kar lahko, preden se dotaknete skupnega stanja: polja potrdila, razpoložljivost naslova, skupino, ki ji odjemalec pripada. Najcenejša zavrnitev je tista, ki se zgodi pred kakršno koli dodelitvijo. Ko nastavitev zajema več zunanjih operacij, vodite evidenco, katere so bile dokončane, in jih pred vrnitvijo statusa napake razveljavite v obratnem vrstnem redu.
Konkreten primer: skript ustvari požarni vnos za vsakega odjemalca, nato pa ne uspe zapisati vrstice stanja, ki ga opisuje. Veja, ki spodleti, mora odstraniti pravkar ustvarjeni vnos in nato končati z neničelno kodo. Čakanje na dogodek disconnect, ki morda ne bo nikoli načrtovan, je način, kako pravilo preživi sejo, ki ji je bilo namenjeno.
Naredite nadomestilo idempotentno in z lastnikom
Čiščenje mora biti varno za dvakratni zagon in natančno glede tega, kaj sme izbrisati. Poznejši dogodek iz prejšnjega poskusa ne sme odstraniti dodelitve novejše seje samo zato, ker si oba delita skupno ime ali recikliran naslov tunela. Zabeležite konkretni ročaj ali ID operacije skupaj z virom in brišite po tej ključi, ne po imenu. Transakcije podatkovne baze pomagajo le pri lastnih spremembah baze; požarno pravilo zunaj te meje potrebuje izrecen korak nadomestila.
Predpostavite, da lahko proces umre med spremembo in čiščenjem, in dodajte usklajevalnik, ki po urniku primerja zunanje stanje s seznamom sprejetih odjemalcev.
Preizkusite tri poti, ki se res razlikujejo
Vadite tri primere: zavrnitev, preden je karkoli dodeljeno, zavrnitev po delni dodelitvi in običajno sprejeto sejo, ki se pozneje konča. Ti trije dajejo različne vrstice dnevnika in različne ostanke. Po vsakem preverite zunanje stanje, ne le sporočila o napaki odjemalca, ker je napaka odjemalca pričakovan izid v dveh od treh.
Zabeležite fazo hooka, izhodni status in kaj je bilo dodeljeno ali sproščeno, brez poverilnic. Dnevnik hooka, ki poimenuje ustvarjeni vir, je tisto, kar naredi uhajajoče pravilo najdljivo pol leta pozneje.