OpenVPN client-connect neuspjeh: je li čišćenje pri disconnect zajamčeno?
Odbijeni klijent ne poništava firewall pravilo ni zapisani red. Uporedite ugovor povratnog poziva s vraćanjem unazad koje vaš hook mora izvesti sam.
Kada skripta client-connect završi s nenultim kodom, OpenVPN odbija klijenta, a administratori obično pretpostavljaju da će odgovarajuća skripta client-disconnect počistiti. Često se nikad ne pokrene, jer obrada disconnect ovisi o tome šta je connect faza uspjela dovršiti. Tretiranje odbijanja i vraćanja unazad kao jednog mehanizma pretvara neuspješnu prijavu u procurjelo firewall pravilo ili zapis bez vlasnika. To su dvije odvojene obaveze, a samo je jedna automatska. Pročitajte vlastiti izlazni put hooka prije nego što okrivite server da je ostavio stanje za sobom.
Nenulti izlaz odbija klijenta; ne poništava vaš rad
Izlazni status client-connect je odluka o prijemu. Nula znači prihvatiti, sve ostalo znači rušenje instance prije nego što je potpuno uspostavljena. Ništa u tom ugovoru ne provjerava šta je skripta već učinila vanjskom svijetu. Ako je skripta dodala iptables pravilo, zapisala red ili povećala brojač, te promjene nadživljavaju odbijanje.
Ista asimetrija vrijedi za dodatke, gdje se za jednu instancu može izvršiti nekoliko connect funkcija. Kasniji neuspjeh ne poništava retroaktivno raniji uspjeh, a ranija funkcija ne može saznati da je srodna funkcija podbacila.
Odbijanje je automatsko, čišćenje nije
Priručnik OpenVPN 2.6 veže obradu client-disconnect uz uspješno dovršenu prethodnu obradu connect. Dokumentirani izuzetak pokriva kaskadne lance: ako je jedan connect korak već vratio uspjeh, odgovarajući disconnect koraci se ipak izvršavaju pri rušenju instance, iako je kasniji connect korak podbacio. Taj izuzetak je uzak i zavisi od broja konfiguriranih povratnih poziva, zato vam testiranje jedne shell skripte ne govori ništa o lancu.
Mapirajte stvarnu konfiguraciju prije nego što dizajnirate oko nje: koja skripta, koji dodatak i kojim redoslijedom se izvršavaju. Tabela ispod navodi šta polovično dovršeno postavljanje ostavlja za sobom.
| 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 |
Svaki red završava isto za klijenta, a drugačije za host. Klijent ne može reći koji se od njih dogodio, pa hook mora poništiti ono što je učinio prije nego što vrati status neuspjeha.
Nadoknadite unutar skripte koja je podbacila
Provjerite sve što možete prije nego što dotaknete dijeljeno stanje: polja certifikata, dostupnost adrese, grupu kojoj klijent pripada. Najjeftinije odbijanje je ono koje se dogodi prije bilo kakve dodjele. Kada postavljanje obuhvati nekoliko vanjskih operacija, vodite evidenciju koje su dovršene i poništite ih obrnutim redoslijedom prije vraćanja statusa neuspjeha.
Konkretan slučaj: skripta stvara firewall unos za svakog klijenta, a zatim ne uspije zapisati red stanja koji ga opisuje. Grana koja podbaci treba ukloniti unos koji je upravo stvorila i zatim izaći s nenultim kodom. Čekanje na disconnect događaj koji možda nikad neće biti zakazan jeste način da pravilo nadživi sesiju kojoj je bilo namijenjeno.
Učinite nadoknadu idempotentnom i s vlasnikom
Čišćenje mora biti sigurno za dvostruko pokretanje i precizno u pogledu toga šta smije izbrisati. Kasni događaj iz ranijeg pokušaja ne smije ukloniti dodjelu novije sesije samo zato što obje dijele zajedničko ime ili recikliranu adresu tunela. Zabilježite konkretni ručku ili identifikator operacije uz resurs i brišite po tom ključu, a ne po imenu. Transakcije baze podataka pomažu samo s vlastitim promjenama baze; firewall pravilo izvan te granice zahtijeva izričit korak nadoknade.
Pretpostavite da proces može umrijeti između promjene i čišćenja i dodajte usklađivač koji po rasporedu poredi vanjsko stanje s popisom prihvaćenih klijenata.
Testirajte tri puta koji se stvarno razlikuju
Vježbajte tri slučaja: odbijanje prije bilo kakve dodjele, odbijanje nakon djelimične dodjele i normalnu prihvaćenu sesiju koja kasnije završi. Ta tri daju različite linije dnevnika i različite ostatke. Provjerite vanjsko stanje nakon svakog, ne samo poruku o neuspjehu klijenta, jer je neuspjeh klijenta očekivani ishod u dva od tri slučaja.
Bilježite fazu hooka, izlazni status i šta je dodijeljeno ili oslobođeno, bez vjerodajnica. Dnevnik hooka koji imenuje resurs koji je stvorio jeste ono što procurjelo pravilo čini pronalazivim šest mjeseci kasnije.