Att returnera en adress från ett client-connect-skript ser ut som att det ska sätta klientens IP. Det gör det inte: hookens enda kanal till servern är en tillfällig fil vars sökväg kommer som skriptets sista argument, och adressen måste skrivas där i ifconfig-push-syntax. Ett skript som skriver ut adressen eller avslutar med noll utan att skriva något ger en ansluten klient med en adress från poolen, och serverloggen ser helt frisk ut.

Förvirringen är rimlig, eftersom flera andra hooks faktiskt svarar via exitkoder eller miljövariabler. Den här har sitt eget kontrakt, och kontraktet börjar med ett filnamn.

Hooken skriver en fil, inte ett returvärde

Deklarationen är två rader: script-security 2 för att tillåta anropet, sedan client-connect /etc/openvpn/server/assign-address.sh. När en klient autentiserar sig kör servern det skriptet med den genererade filsökvägen tillagd som sista argument, vilket bara är $1 om deklarationen inte skickar egna extra argument. Allt som tillämpas på den klienten går in i den filen som vanliga direktiv, ett per rad, precis som de skulle stå i en konfiguration. Ett omslag som lägger till sina egna parametrar förskjuter positionen, och det klassiska symptomet är ett skript som skriver till en sökväg som liknar --verbose.

Exitstatusen är den andra halvan av kontraktet. Noll betyder acceptera och läs filen; allt annat avvisar anslutningen, och det är så en ej mappad identitet nekas i stället för att tyst falla tillbaka till poolen. Skriv det kompletta direktivet innan du returnerar framgång, så att en halvskriven fil aldrig blir en klients konfiguration.

Två direktiv förtjänar uppmärksamhet eftersom de samverkar med allt annat. ifconfig-push låser adressen, medan en skickad route berättar för klienten vad som är nåbart genom tunneln; returnera den första och glöm den andra och du får en klient med adress och ingenstans att ta vägen. Ordningen i filen spelar ingen roll, men fullständigheten gör det. En hook som skickar en rutt för ett prefix som ingen peer kan nå är samma misstag sett från andra änden.

Indata kommer via miljövariabler: common_name, trusted_ip, ifconfig_pool_remote_ip och resten. Behandla dem alla som strängar utifrån servern, aldrig som shellfragment.

Adressmappning är en policy, inte aritmetik

En frestande genväg är att tolka certifikatnamnet och använda dess siffror som sista oktett. Det är inte en allokator, och det misslyckas på vanliga sätt: två namn med samma suffix kolliderar, ett namn som slutar på 300 är inte en adress, och ett certifikat som en administratör byter namn på flyttar tyst en enhet. Validera subnättillhörighet, det användbara värdintervallet, reserverade adresser och unikhet vid varje anrop, och håll mappningen i en tabell som en människa kan läsa.

Den som kontrollerar namnet kontrollerar adressen, så bestäm vad common_name egentligen representerar i den här driftsättningen. Med username-as-common-name aktiverat är identiteten inloggningen och inte certifikatets subjekt. Skicka aldrig det värdet till shell-utvärdering, och låt aldrig klienten påverka en filsökväg.

En registerbaserad allokator måste överleva samtidighet. Reservera adressen atomiskt, hantera en misslyckad skrivning utan att släppa in en halvkonfigurerad klient, och märk varje tilldelning med anslutningen som äger den, så att en sen frånkoppling från en äldre session inte kan frigöra en adress som en nyare redan håller. Flera serverinstanser som delar en pool gör kravet skarpare i stället för valfritt.

Topologin avgör vad ifconfig-push betyder

Med topology subnet på 10.77.0.0/24 är ifconfig-push 10.77.0.20 255.255.255.0 en adress plus dess nätmask. Under topology net30 är det andra argumentet inte alls en mask utan peer-adressen, så kopiering av subnätformen till en net30-server ger dig en klient som associerar och inte kan föra trafik. Ändra topologin med avsikt, aldrig för att ett exempel ska se konsekvent ut. En server som redan kör net30 har levande klienter på den gamla adresseringen, så bytet är en migrering med underhållsfönster, inte en enradig ändring.

Statiska adresser måste ligga utanför den dynamiska poolen och utanför varje annan statisk tilldelning, inklusive dem som vanliga client-config-dir-filer delar ut. Om två mekanismer kan producera samma adress för olika klienter, kommer en av dem till slut att göra det.

Testa fyra fall innan du litar på det

Kör samma kontroller mot en mappad identitet, en ej mappad, en återanslutning och ett simulerat registerfel. openvpn --config client.ovpn --verb 4 visar den tilldelade adressen i push-svaret, och på servern bekräftar grep -A2 PUSH_REPLY /var/log/openvpn/openvpn.log vad som faktiskt skickades. För den ej mappade identiteten är det förväntade resultatet en avvisad anslutning, inte en adress från poolen.

Undersök sedan katalogen där daemonen skriver de tillfälliga filerna. Skriptet körs i den nedgraderade tjänstekontexten, så en sökväg som root kan skriva till men inte daemonen gör varje anslutning till ett avslag med ett behörighetsfel begravt flera rader ner i loggen.

Tilldelning är inte auktorisering: en fäst adress ger fortfarande inte åtkomst till varje destination bakom servern. Håll routnings- och brandväggspolicyn i sitt eget lager och verifiera den mot adressen du just fäste.

Relaterade artiklar