Две DNS имена, един порт на OpenVPN: какво всъщност избира
Две имена на хостове, сочещи към един адрес, пак стигат до един слушател. Само поле, което клиентът изпраща, може да избере бекенд, а стандартният OpenVPN не изпраща такова.
Два A записа, един адрес, един демон: което и име да въведе потребителят, пристигащият пакет е идентичен и процесът, вързан към порт 1194, няма с какво да различи двата. Това не е грешна конфигурация, която чака поправка; това е границата на това, което може да изрази едно търсене по име. Всичко, което избира между два екземпляра на OpenVPN, трябва да бъде стойност, която клиентът поставя в съединението и която фронтендът може да прочете обратно, а стандартният клиент на OpenVPN не поставя такава стойност в открит вид. Следва накъде ви оставя това и кои подредби наистина разделят трафика.
Започнете с това, което резолверът връща
Клиентът пита за vpn-a.example и получава адрес; този адрес плюс порт е всичко, към което се свързва. Името се изразходва локално, по време на търсенето, и никога не става поле по мрежата, затова слушателят от другата страна не може да види коя отметка е използвана. Насочете vpn-a.example и vpn-b.example към един хост и двете търсения ще дадат една и съща дестинация, поради което демонът поглъща двете връзки в един екземпляр, без да регистрира разлика. Профилите, базирани на адрес, се държат точно като тези, базирани на име, по същата причина.
Това също затваря едно семейство изкушаващи заобиколни решения: допълнителни псевдоними, избор на сертификат за всяко име на един сокет или правило на защитна стена, обвързано с питаното име. Никое от тях не може да действа върху информация, която вече е била изхвърлена, преди първият пакет да напусне клиента. Ако два сървъра трябва да останат разделени, разделението трябва да пътува със самото съединение, което означава адрес, порт или поле в полезния товар, което протоколът дефинира.
Единственият селектор, който се брои, пътува вътре в пакета
HTTP се справя с това чрез заглавка Host, а TLS — чрез разширение за име на сървър в ClientHello, и така един адрес обслужва много сайтове зад един слушател. И двете работят, защото мрежовият протокол носи заявка за конкретна услуга. Същественото за OpenVPN е, че нито едно от тези полета не присъства на слоя, който междинна кутия преглежда.
При стандартна подредба TLS ръкостискането, което защитава контролния канал, се случва след установяване на външната сесия и се пренася вътре в нея, така че слушател, който не е прекратил тази сесия, вижда непрозрачен поток. Той все още може да каже, че това е OpenVPN, защото кодът на операцията и рамкирането в началните байтове са разпознаваеми, но името на сървъра, ако съществува, седи в криптираната част. Дизайн, който очаква да прочете виртуален хост от външния пакет, чете поле, което протоколът никога не пише там. Това идва от начина, по който е изграден тунелът, а не от празнина, която по-хитро съвпадение на шаблон би могло да запълни.
Къде разделителят на протоколи спира
Мултиплексор от вида, който документира проектът sslh, слуша на един порт, преглежда началните байтове и предава връзката на онзи бекенд, който говори разпознатия протокол. Това е истинска стойност, когато един порт трябва да обслужва SSH, HTTPS и OpenVPN заедно.
sslh поддържа отделна проба за всеки протокол и неговата TLS проба може да извлече име на сървър или стойност на ALPN от истински ClientHello. Разпознаването на стандартен OpenVPN е различна класификация от четенето на TLS разширение и двете не се съчетават, защото клиент, който никога не изпраща ClientHello към слушащия сокет, оставя пробата без нищо за четене. Затова правило, което съвпада с OpenVPN, отговаря „това е клиент на OpenVPN“ и не отива по-нататък. Два OpenVPN бекенда зад това правило са неразличими, фронтендът няма основа за избор и всяка сесия каца на едно и също място. Мултиплексирането споделя един порт между различни услуги; то не прави виртуален хостинг в една услуга.
Подредби, които наистина разделят два сървъра
Най-евтиното честно разделение е втори публичен адрес, по един на екземпляр, а съществуващите профили вече носят нужното, защото сочат към различни адреси. Следващото е различен порт на същия адрес, което не струва нищо освен едно число във всеки профил. TCP и UDP поддържат отделни таблици на портовете, така че 1194/tcp и 1194/udp са несвързани сокети и по един от всеки може да съществува на един хост; това е транспортно разделение, а не маршрутизация по име, и често се бърка с нея. И двете опции издържат преглед на защитна стена, защото правилото съвпада с нещо, което пакетът наистина съдържа.
Ако границата, която ви трябва, минава между групи потребители, а не между две реализации, един екземпляр с различни клиентски конфигурации, собствена обработка на сертификати и явна политика за достъп може да я покрие. Това купува политика вътре в сървъра, а не изолация между сървъри, и двете са различни изисквания. Изолация, която трябва да издържи при компрометиране, все още се нуждае от адреса или от ръба на защитната стена.
TLS терминатор, поставен пред OpenVPN, може да изложи истинско име на сървър пред способен фронтенд, но само когато клиентската страна също е конфигурирана за този допълнителен слой. Съществуващите профили не придобиват това поведение само като бъдат насочени към същия адрес.
Докажете селектора, преди да строите
Назовете полето, което ще идентифицира бекенд, после потвърдете, че клиентът наистина го изпраща; ако отговорът е адрес, планът издържа, а ако е име на сървър вътре в ръкостискане, което никога не стига до слушателя, никаква работа по DNS няма да го спаси. Три команди решават въпроса за слушащата страна бързо.
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 дава сертификат само там, където нещо на този адрес прекратява TLS; срещу стандартен OpenVPN слушател той засича или се проваля, което само по себе си е отговорът за това какво разкрива външният слой. Редът journal, прочетен на всеки бекенд, показва кой екземпляр е приел сесията. Фронтенд журналите записват какво е класифицирано и никога какво е било предвидено, затова бекендът остава единственият авторитет за това къде е кацнал потребителят.
Завършете с два профила, предназначени за различни сървъри, свържете ги един по един и запишете журнала на бекенда за всеки. Ако и двете сесии се появят в един и същ журнал, селекторът липсва, а не е грешно конфигуриран, и поправката е адрес или порт, който клиентът може да атакува. Редактирането на правилото за маршрутизация няма да помогне, защото на правилото никога не са давали нещо, по което да маршрутизира. Щом разделението е реално, запишете го до профилите, за да не добави следващият човек втори псевдоним и да очаква, че той ще свърши работата.