Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Зачем людям ранее был нужен VPN (кроме мошенников конечно)? Чтоб ходить на Linkedin и обходить всякие разные запреты РКН.
Когда ввели санкции и некоторые сайты перекрасились в сине-желтый цвет, то многие по старой памяти подумали - включим VPN и всё сразу станет как раньше, разве что русские сайты начнут открываться на 50мс медленнее.
Но не тут-то было. Вместе с перекраской сайтов, началась волна DDoS и хакерских атак на различные сервисы в РФ. В итоге, российские сайты закрылись от остального интернета. И с VPN стало очень некомфортно - хочешь пользоваться Terraform или, там, MatterMost скачать - включаешь VPN... И... сразу же не можешь сходить ни на Ozon ни на Госуслуги.
Интернет разделился на InnerNet и OuterNet.
Различные (удачные и нет попытки).
Сама собой возникла потребность более умного VPN, который русские сайты отправит по одному маршруту, а не-русские - по другому.
Сделать это можно различными способами.
Первый, который пришел в голову - это конечно же старый добрый squid: ставим два хоста, соединяем тоннелем. На первом хосте, ставим второй апстримом для определенных доменных зон или доменов, настраиваем SSL-BUMP.
Однако такое решение, хоть оно и достаточно эффективное, имеет определенные минусы :
Нужно везде прописывать проксю. Когда мы делаем не поделку, а решение - это плохо.
Нужно везде грузить сертификаты CA. И если в браузере это +- несложно, то, например, в различных продуктах от JetBrains - их нужно прописывать отдельно. В общем, чтоб завернуть весь трафик из дома или из офиса - нужно СЛИШКОМ МНОГО движений.
Ну и заявлять всем : "ребята, я вам сделал удобно, но учтите, что теперь я имею возможность читать весь ваш трафик, переписку и сайты с порнухой" - настолько не очень, что люди не будут пользоваться, или будут так же включать - от случая к случаю. А хочется - set and forget.
Второй вариант - SNI (как, например, работает DPI) - в SSL трафике хостнейм передается (всё реже и реже) открыто. Но, в TLS 1.3 это уже не актуально. Да и в целом - анализировать весь трафик слишком накладно.
В итоге - остаются только айпишки. С ними я и начал работать (после того, как полностью поднял инфру на SQUID + генерацию CA :) )
Получился...
Гео-роутинг.
В принципе зароутить трафик не сложно :
Между входящим ВПН-сервером и второй его головой настраивается тоннель. Настраиваем PBR - то, что пометили в mangle - отправляем на вторую голову. То, что не пометили - выпускаем. Входящий ставим в РФ, второй - там, где остальной мир не будет вас блочить.
Первый этап так же не сложен - распаковываем базу GEOIP и все подсетки, которые находятся в гео RU - помечаем для выпуска сразу. Однако, не подсетками едиными (тут я как раз столкнулся с Ozon) - некоторые русские сервисы хостятся не в РФ (а, например, в Германии), при этом, пускают только русских. Для таких нужен отдельный список и котел в аду за кроссбординг ПД. А еще, мейнтейнить список айпишек несколько неудобно, особенно, если учесть, что айпишки у сайта могут меняться без предупреждения (потому, что часть Озона за клаудфларой).
Когда браузер обращается к сайту, он вначале резолвит имя в айпишник. Выход напросился сам собой : перехватываем DNS-запрос, если он к нужному сайту или нужной зоне - добавляем айпишник в iptables. Причем, в отличие от решения с SNI - мы успеем добавить айпишник еще до соединения браузера с сайтом. Главное делать это быстро : секунда-две на каждый запрос к ресурсу в пост-модемные времена - непозволительно долго.
Здесь мне помог PowerDNS - отличное решение, которое позволяет делать пост-обработку ответов DNS через LUA :
Ловим каждый запрос.
Отправляем по вебсокету демону на питоне.
Демон принимает решение и настраивает IPT.
Конечно, помня, что в DNS есть еще и CNAMEs, простейшим алгоритмом не обойтись - приходится строить цепочки записей и обходить их как слева направо, так и справа налево. Тем не менее работает достаточно эффективно - в пределе, на самой дешевой яндексовской виртуалке, обработка DNS-запроса занимает 100мс. А обычно, укладываемся в несколько мс.
В отдельных случаях, при холодном старте, всё-таки не всегда успевает добавить в IPT для отдельных сайтов. Поэтому, тот же озон при холодном старте инфраструктуры, на первое обращение часто отдает 403. Чистка кеша на клиенте и последующий релоад страницы приводит роутинг в чувства.
NFTables.
Изначально, я хотел использовать NFTables - я их очень люблю, и они в целом эффективнее чем iptables/netfilter. Позволяют творить такое, что IPT/NF даже не снилось. Но, не тут-то было. Большой набор рул в nft не загрузить потому, что nft работает через RT_NETLINK так, что туда много не влезает. В аутернетах есть бенчи, которые показывают, что nft весьма медленно добавляет рулы по сравнению с IPT/NF.
Итог.
В итоге, получился MRVPN, который можно скчать отсюда : https://github.com/AlexMKX/mrvpn
Деплой осуществляется через ansible role, что современно модно и молодежно.
Для клиентов используется FireZone - один из лучших фронтов для WireGuard, который поддерживает гугловый SAML (а в коммерческой версии и другие), что важно для корпов.