Två DNS-namn, en OpenVPN-port: vad som faktiskt väljer
Två värdnamn som pekar på en adress når ändå fram till en enda lyssnare. Bara ett fält som klienten skickar kan välja en backend, och vanlig OpenVPN skickar inget.
Två A-poster, en adress, en daemon: vilket namn användaren än skriver är paketet som anländer identiskt, och processen som är bunden till port 1194 har ingenting att skilja de två med. Det här är inte en felkonfiguration som väntar på reparation; det är gränsen för vad en namnsökning kan uttrycka. Allt som väljer mellan två OpenVPN-instanser måste vara ett värde som klienten lägger i anslutningen och som frontend kan läsa tillbaka, och en vanlig OpenVPN-klient lägger inget sådant värde i klartext. Det som följer är var det lämnar dig, och vilka uppställningar som faktiskt delar trafiken.
Börja med det som resolvern lämnar tillbaka
En klient frågar efter vpn-a.example och får en adress; den adressen plus en port är allt den ringer. Namnet förbrukas lokalt, under uppslaget, och blir aldrig ett fält på ledningen, så lyssnaren i andra änden kan inte se vilken etikett som användes. Peka vpn-a.example och vpn-b.example mot samma värd, och båda uppslagen ger samma destination, och därför suger daemonen upp båda anslutningarna i en enda instans utan att registrera någon skillnad. Adressbaserade profiler beter sig precis som namnasbaserade, av samma skäl.
Det här stänger också en familj av frestande kringgåenden: extra alias, att välja ett certifikat per namn på en enda socket, eller en brandväggsregel knuten till namnet som frågades efter. Ingen av dem kan agera på information som redan var kastad innan det första paketet lämnade klienten. Om två servrar måste förbli åtskilda, måste uppdelningen resa med själva anslutningen, det vill säga en adress, en port eller ett nyttolastfält som protokollet definierar.
Den enda väljaren som räknas färdas inuti paketet
HTTP löser detta med ett Host-huvud, och TLS med en servernamnsutvidgning i ClientHello, och så betjänar en adress många webbplatser bakom en enda lyssnare. Båda fungerar eftersom protokollet på ledningen bär en förfrågan om en viss tjänst. Det relevanta faktumet om OpenVPN är att inget av dessa fält finns på det lager som en mellanliggande box undersöker.
I en vanlig uppställning sker TLS-handskakningen som skyddar kontrollkanalen efter att den yttre sessionen upprättats, och den bärs inuti den, så en lyssnare som inte avslutat den sessionen ser en ogenomskinlig ström. Den kan fortfarande säga att detta är OpenVPN, eftersom opkoden och ramningen i de första byten är igenkännbara, men servernamnet, om det finns, sitter i den krypterade delen. En design som förväntar sig att läsa en virtuell värd från det yttre paketet läser ett fält som protokollet aldrig skriver där. Det kommer av hur tunneln är byggd, inte av en lucka som en smartare mönstermatchning skulle kunna stänga.
Där en protokolldelare stannar
En multiplexer av det slag som sslh-projektet dokumenterar lyssnar på en port, undersöker de första byten och överlämnar anslutningen till den backend som talar det protokoll den kände igen. Det är verkligt värde när en enda port måste betjäna SSH, HTTPS och OpenVPN samtidigt.
sslh håller en separat sond per protokoll, och dess TLS-sond kan dra ut ett servernamn eller ett ALPN-värde ur en äkta ClientHello. Att känna igen vanlig OpenVPN är en annan klassificering än att läsa en TLS-utvidgning, och de två komponerar inte, eftersom en klient som aldrig skickar en ClientHello till lyssnarsocketen lämnar sonden utan något att läsa. En regel som matchar OpenVPN svarar därför ”detta är en OpenVPN-klient” och går inte vidare. Två OpenVPN-backends bakom den regeln går inte att skilja, frontend har ingen grund för ett val, och varje session landar på samma ställe. Multiplexing delar en port mellan olika tjänster; det gör ingen virtuell hosting inuti en tjänst.
Uppställningar som verkligen skiljer två servrar
Den billigaste ärliga uppdelningen är en andra offentlig adress, en per instans, och befintliga profiler bär redan det som behövs eftersom de pekar på olika adresser. Nästa är en annan port på samma adress, vilket inte kostar något utöver en siffra i varje profil. TCP och UDP håller separata porttabeller, så 1194/tcp och 1194/udp är obesläktade sockets och en av varje kan existera på samma värd; det är transportdelning och inte namnrouting, och det förväxlas ofta med det. Båda alternativen överlever en brandväggsgranskning, eftersom regeln matchar något som paketet faktiskt innehåller.
Om gränsen du behöver går mellan grupper av användare i stället för mellan två implementationer, kan en instans med olika klientkonfigurationer, egen certifikathantering och en uttrycklig åtkomstpolicy täcka det. Det köper policy inuti en server, inte isolering mellan servrar, och de två är olika krav. Isolering som måste hålla under kompromettering behöver fortfarande adressen eller brandväggskanten.
En TLS-terminator framför OpenVPN kan exponera ett riktigt servernamn för en kapabel frontend, men bara när klientsidan också är konfigurerad för det extra lagret. Befintliga profiler får inte beteendet genom att pekas mot samma adress.
Bevisa väljaren innan du bygger
Namnge fältet som ska identifiera en backend, och bekräfta sedan att klienten faktiskt skickar det; om svaret är en adress håller planen, och om det är ett servernamn inuti en handskakning som aldrig når lyssnaren räddar ingen mängd DNS-arbete det. Tre kommandon avgör lyssnarsidan snabbt.
ss -lntup | grep -E ':443|:1194'
openssl s_client -connect vpn-a.example:443 -servername vpn-a.example </dev/null | head -n 20
journalctl -u openvpn-server@server-a -n 20 --no-pager
openssl-raden ger bara ett certifikat där något på den adressen avslutar TLS; mot en vanlig OpenVPN-lyssnare stannar den eller misslyckas, och det är i sig självt svaret på vad det yttre lagret exponerar. journal-raden, läst på varje backend, visar vilken instans som accepterade sessionen. Frontend-loggar registrerar vad som klassificerades och aldrig vad som avsågs, så backenden är fortfarande den enda auktoriteten för var en användare landade.
Avsluta med två profiler avsedda att nå olika servrar, anslut dem en i taget och notera backend-loggen för var och en. Om båda sessionerna dyker upp i samma journal saknas väljaren i stället för att vara felkonfigurerad, och rättelsen är en adress eller en port som klienten kan sikta på. Att redigera routingregeln hjälper inte, eftersom regeln aldrig fick något att routa på. När uppdelningen är verklig, skriv den bredvid profilerna så att nästa person inte lägger till ett extra alias och förväntar sig att det gör jobbet.