Returnarea unei adrese dintr-un script client-connect pare să ar trebui să seteze IP-ul clientului. Nu o face: singurul canal al hook-ului către server este un fișier temporar al cărui cale vine ca ultim argument al scriptului, iar adresa trebuie scrisă acolo în sintaxa ifconfig-push. Un script care tipărește adresa sau iese cu zero fără să scrie nimic produce un client conectat cu o adresă din pool, iar jurnalul serverului pare perfect sănătos.

Confuzia este rezonabilă, pentru că mai multe alte hook-uri chiar răspund prin coduri de ieșire sau variabile de mediu. Acesta are propriul contract, iar contractul începe cu un nume de fișier.

Hook-ul scrie un fișier, nu o valoare de returnare

Declarația este de două linii: script-security 2 pentru a permite apelul, apoi client-connect /etc/openvpn/server/assign-address.sh. Când un client se autentifică, serverul rulează acel script cu calea fișierului generat adăugată ca ultim argument, care este $1 doar dacă declarația nu transmite argumente suplimentare proprii. Tot ce se aplică acelui client merge în acel fișier ca directive obișnuite, una pe linie, exact cum ar apărea într-o configurație. Un wrapper care adaugă propriii parametri deplasează poziția, iar simptomul clasic este un script care scrie într-o cale care arată ca --verbose.

Starea de ieșire este cealaltă jumătate a contractului. Zero înseamnă acceptă și citește fișierul; orice altceva respinge conexiunea, și așa o identitate nemapată este refuzată în loc să cadă în tăcere înapoi în pool. Scrie directiva completă înainte de a returna succes, ca un fișier scris pe jumătate să nu devină niciodată configurația unui client.

Două directive merită atenție pentru că interacționează cu tot restul. ifconfig-push fixează adresa, în timp ce un route trimis îi spune clientului ce este accesibil prin tunel; returnează prima și uită a doua și obții un client cu adresă și fără unde să meargă. Ordinea în fișier nu contează, dar completitudinea contează. Un hook care trimite o rută pentru un prefix la care niciun peer nu poate ajunge este aceeași greșeală văzută de la celălalt capăt.

Intrările vin prin variabile de mediu: common_name, trusted_ip, ifconfig_pool_remote_ip și restul. Tratează-le pe toate ca șiruri din afara serverului, niciodată ca fragmente de shell.

Maparea adreselor este o politică, nu aritmetică

O scurtătură tentantă este să analizezi numele certificatului și să folosești cifrele lui ca ultim octet. Acesta nu este un alocator și eșuează în moduri obișnuite: două nume cu același sufix se ciocnesc, un nume care se termină în 300 nu este o adresă, iar un certificat redenumit de un administrator mută în tăcere un dispozitiv. Validează la fiecare apel apartenența la subrețea, intervalul de gazde utilizabil, adresele rezervate și unicitatea, și ține maparea într-un tabel pe care o persoană îl poate citi.

Cine controlează numele controlează adresa, așa că decide ce reprezintă de fapt common_name în această implementare. Cu username-as-common-name activat, identitatea este autentificarea, nu subiectul certificatului. Nu transmite niciodată acea valoare evaluării shell și nu lăsa niciodată clientul să influențeze o cale de fișier.

Un alocator bazat pe registru trebuie să supraviețuiască concurenței. Rezervă adresa atomic, gestionează o scriere eșuată fără a admite un client pe jumătate configurat și etichetează fiecare alocare cu conexiunea care o deține, astfel încât o deconectare târzie dintr-o sesiune mai veche să nu poată elibera o adresă pe care una mai nouă o deține deja. Mai multe instanțe de server care partajează un pool fac această cerință mai ascuțită, nu opțională.

Topologia decide ce înseamnă ifconfig-push

Cu topology subnet pe 10.77.0.0/24, ifconfig-push 10.77.0.20 255.255.255.0 este o adresă plus masca ei de rețea. Sub topology net30 al doilea argument nu este deloc o mască, ci adresa perechii, așa că copierea formei de subrețea pe un server net30 îți dă un client care se asociază și nu poate trece trafic. Schimbă topologia deliberat, niciodată pentru ca un exemplu să pară consistent. Un server care rulează deja net30 are clienți activi pe adresarea veche, așa că schimbarea este o migrare cu fereastră de mentenanță, nu o editare de o linie.

Adresele statice trebuie să stea în afara pool-ului dinamic și în afara oricărei alte atribuiri statice, inclusiv cele date de fișierele client-config-dir obișnuite. Dacă două mecanisme pot produce aceeași adresă pentru clienți diferiți, unul dintre ele va face asta în cele din urmă.

Testează patru cazuri înainte să te bazezi pe el

Rulează aceleași verificări pe o identitate mapată, una nemapată, o reconectare și o defecțiune simulată a registrului. openvpn --config client.ovpn --verb 4 arată adresa atribuită în răspunsul push, iar pe server grep -A2 PUSH_REPLY /var/log/openvpn/openvpn.log confirmă ce s-a trimis efectiv. Pentru identitatea nemapată rezultatul așteptat este o conexiune respinsă, nu o adresă din pool.

Apoi inspectează directorul în care daemonul scrie acele fișiere temporare. Scriptul rulează în contextul de serviciu coborât, așa că o cale în care root poate scrie, dar daemonul nu, transformă fiecare conexiune într-o respingere cu o eroare de permisiuni îngropată câteva linii mai jos în jurnal.

Alocarea nu este autorizare: o adresă fixată tot nu oferă acces la fiecare destinație din spatele serverului. Ține politica de rutare și firewall în propriul strat și verific-o față de adresa pe care tocmai ai fixat-o.

Articole similare