Как сделать универсальное решение для туннелирования по IP и доменам для домашней сети?

У меня настроена такая система: на мобильных устройствах VPN до дома, дома роутер принимает BGP-маршруты с VPS (на VPS их формирует из общедоступных списков специально отдельный скрипт) и заворачивает часть трафика в VPN. Также дома свои DNS, которые шлют запросы через TLS (DoT).
Первая проблема возникает с Cloudflare и другими CDN, в которой на одних и тех же адресах могут быть как заблокированные в России или заблокировавшиеся от России, так и российские сайты, которые не любят VPN. Также я замечаю, что некоторые (неправильно настроенные) серверы за Cloudflare, например lostfilm.tv вообще не открываются при частичной маршрутизации, ситуацию спасает только полное туннелирование всего трафика.
Вторая проблема - надежность использования решения на наиболее распространенных протоколах VPN в перспективе.

Промежуточный вариант - использовать наряду с маршрутами к заблокированным IP список заблокированных доменов без их резолвинга в адреса. Но я не нашел никакого более удобного варианта кроме как использовать плагины типа Switchy Omega. Но они не для всех браузеров, и уж точно не для айфонов.

Я представляю себе решение примерно следующим образом: на домашнем сервере стоит нечто (sing-box, xray, GOST ?), принимающее одновременно и списки IP-адресов, и списки доменов. Роутер отправляет весь исходящий трафик на этот сервер, где принимается решение:

  1. если TCP (а может можно и UDP?) на 443 порт и в сторону списка доменов, в туннель;
  2. если иное и в сторону списка адресов, в туннель;
  3. в противном случае - напрямую.
    Для отработки первого случая, как я понимаю, во всех браузерах один раз нужно будет прописать настройки прокси, работающего на домашнем сервере.

Вопросы:

  1. какое приложение использовать в качестве комбайна, чтобы и оба варианта списков мог переваривать мог, и имел входящий proxy, например Socks5?
  2. как разделить трафик домашнего сервера на трафик самого сервера и входящий-исходящий при наличии одного физического интерфейса? mpls? несколько ip-адресов? как это лучше сделать?
  3. как сообщать роутеру, какие пакеты куда слать? на ум приходит mpls, ну или в зависимости от того, с какого ip от сервера приходят пакеты.

Перечитал все известные статьи комрада MiraclePtr с Хабра, но не нашел какого-то более менее универсального варианта. Предложенные варианты клиентов типа nekoray или shadowrocket достаточно гибкие с точки зрения настроек, но это именно клиенты, которые должны ставиться на клиентских устройствах. Я же пытаюсь реализовать так, чтобы с одной стороны был сервер, а с другой - клиент. Видел подобное в китайских прокси (inbounds, outbounds), но так и не смог найти, как это все правильно использовать вместе. Тот же xray в качестве inbounds принимает отдельные протоколы, весь трафик туда направить не получится. А может и не нужно?
Укажите, пожалуйста, направление :slight_smile:

По списку на все вопросы не отвечу, но скажу, как у меня сделано (или планируется сделать). У меня очень похожая система - во всех домах/офисах роутеры, в России сервер для VPN. И плюс отдельный сервер, который по заданным критериям (IP, подсеть, домен, AS) формирует списки, через какую выходную точку (сервер / роутер) маршрутизировать пакеты. Этот последний сервер по BGP раздаёт получившиеся списки префиксов для каждой выходной точки в виде отдельного BGP community роутерам и VPN-серверу.

Так вот, что порекомендую из своего опыта по Вашим вопросам:

  1. Во-первых, DNS-сервер должен быть свой, использоваться всеми клиентами в локальной сети и VPN, и именно с использованием этого DNS-сервера должны ресолвится домены для списков маршрутизации (и обновляться периодически). Это спасёт хотя бы от ситуации “сервер для целей маршрутизации выдал IP для одного региона, а клиент у себя получил IP для другого, и маршрут к нему построился неправильно”. Но не спасает от рандомно меняющихся IP, которыми многие CDN и иже с ними грешат. Тут пока что добавляю в списки целыми AS.

  2. Во-вторых, отделить и по-разному маршрутизировать трафик клиентов и собственный трафик сервера элементарно, но вот готовую инструкцию тут не напишу, отправлю читать маны :slight_smile: Ключевые слова - ip rule, iptables CONNMARK (ну или что там у nftables аналогичное, к стыду своему на них не переполз до сих пор)

  3. В-третьих, чтобы полностью решить проблему с рандомными ответами некоторых DNS, а заодно и проблему с ресолвингом по маске домена (*.example.com) вижу один способ - на своём DNS-сервере включить логирование всех запросов (unbound позволяет) и фоном парсить эти логи на предмет соответствия включённым в наши критерии маршрутизации доменам/маскам, при совпадении - обновлять списки префиксов. Но тут надо писать что-то не совсем примитивное (без асинхронности никак), так что до сих пор руки не дошли.

  4. В-четвёртых, прокси (VLESS и иже с ними) на текущий момент только добавляют лишней головной боли, особенно если нужен не только доступ к заблокированному, но и доступ к своей сети извне. Amnezia-WG работает, очень шустро, пока не блокируется, но имеет шансы. WG внутри Cloak работает, не так шустро, но приемлемо, шансы блокировки не выше, чем у VLESS со товарищи. Так что между серверами/роутерами я настроил оба этих варианта и OSPF, который перекинет маршрут с амнезии на клоак при отпадании первой автоматически. А для клиентов VPN-сервера - OpenConnect.

Спасибо за советы!

  1. У меня уже все готово, за исключением того, что DNS для дома и мобильных устройств, а VPS ресолвит всё сам. Попробую проверить, станет ли лучше, если VPS начнет обращаться к домашним DNS.
  2. Уже использую connection mark, но не думал, что можно в таком ключе! Но если речь об опросе DNS, возможно лучше приглядеться к другим вариантам (см. дальше).
  3. Похоже на то, что было описано в статье Обход блокировок РКН с помощью DNSTap и BGP / Хабр. Вероятно под это дело можно взять отдельное готовое приложение для сбора логов с DNS, и тогда запариваться с асинхронностью лишний раз не придется. Ещё автор предлагает манипулировать маршрутами, полученными на основании анализа DNS, с помощью BGP с небольшим TTL.
  4. Тоже настроил для входящих домой как резервные варианты, в том числе OpenConnect. Про наводку Wireguard + Cloak для исходящих также спасибо, буду думать.

Хм… за наводку на DNSTap (точнее, dnstap-bgp) спасибо, оно, по ходу, делает бóльшую часть того, что я собирался писать сам.

Про WG через Cloak - для понимания тяжести проблемы, на трансграничном канале, который выдаёт около 800 Мбит/с без всяких туннелей, WG и Amnezia-WG выжимают около 600 Мбит/с (Амнезия почти не снижает скорость, но несколько больше нагружает CPU, чем обычный WG, который на уровне ядра), - WG через Cloak выдаёт около 250 Мбит/с. Не знаю, можно ли эту пропорцию экстраполировать на более и менее широкие каналы, но для грубой оценки, думаю, можно взять, а там смотрите, насколько для Вас это критично. VLESS должен дать большую скорость, но если надо обеспечить полноценную связность сетей по обе стороны туннеля - это так себе решается через VLESS.

Я думаю, что лучше настроить больше и всего сразу и выбирать лучше из того, что работает, чем потом в спешке что-то прикручивать, когда РКН запустит в пульт гаечным ключом, как это было с “блокировкой” Телеграма.

И всё-таки возвращаясь к моему вопросу: а что если попробовать сделать прям собственный DPI с маркировкой пакетов? Понятно, что железо при этом потребуется производительнее, но и поставить старый компьютер под такое дело - не проблема. Я нахожу и опенсорсные решения, только не совсем представляю (нет опыта работы с DPI), насколько их можно использовать не для блокировки трафика (как IDS/IPS), а именно для маркировки с последующей маршрутизацией.

Не понимаю, чем Вам MARK/CONNMARK не такой “DPI” (ну точнее тут нет DPI, но маркировка пакетов это и есть в чистом виде)? Вы именно что добавляете к каждому пакету (а для CONNMARK - и к последующим пакетам того же соединения) дополнительное поле, по которому потом можно или в следующих цепочках обрабатывать, или в другую таблицу маршрутизации отправлять.

P.S. А, понял, Вы хотите в Layer 7 залезть для классификации пакетов, так? Ну тогда возьмите какой-нибудь nDPI и лезьте :slight_smile:
P.P.S. Однако, со времён, когда я в эту сторону смотрел, многое изменилось :thinking: Раньше можно было собрать ndpi-netfilter и прямо в iptables использовать возможности этой библиотеки, а сейчас этот проект мёртвый, авторы ndpi предлагают использовать свой продукт nprobe за денежку… в общем, надо разбираться.

Есть четыре принципиальных подхода к решению задачи:

  1. То, что у вас или у @borouhin сейчас, в каком-либо виде, сводящееся к маршрутизации по IP-адресам. Пре-резолв заблокированных доменов, динамическое добавление маршрутов через dnsmasq ipset/dnstap — не принципиально.

  2. Анализ доменов на уровне DNS и переадресация заблокированных в какие-то другие IP-адреса (как в VPN АнтиЗапрета).
    Реализовано в

  3. Выборочное или полное перенаправление TCP/UDP-трафика на локальный прокси с поддержкой «сниффига» (анализа HTTP/TLS/QUIC-пакетов и вычленения домена) и правил маршрутизации: v2fly/xray/sing-box сотоварищи.
    Вам не нужен Socks5 в качестве inbound, используйте то, что понимает iptables redirect. В v2fly это называется dokodemo-door.

  4. «Сниффинг» домена на уровне netfilter и перенаправление трафика на уровне маршрутизации метками или как-либо еще («свой DPI»). Если распарсить пакет и определить домен достаточно просто:

    то перенаправление по другому маршруту/интерфейсу потребует переустановки соединения, каких-либо готовых инструментов для этого я не знаю.

Первый подход чреват оверинжинирингом всего и вся, но не решает проблем, с которыми вы же и столкнулись. То, что вы здесь описываете с bgp-dnstap сродни выкидывания мусора в иллюминатор с МКС.
Второй требует использования только DNS сервера, и с другими работать не будет. Если какое-либо приложение внутри себя использует сторонний DNS/DoH, либо же просто устанавливает соединение по фиксированному адресу, то DNS этого не поймает.
Третий способ легко и гибко конфигурируется, но также легко отбирает у вас все возможности по маршрутизации на сетевом уровне. Не знаю, как в аналогах, но в v2fly сломан mark на freedom outbound, остаются, разве что, разные source ip-адреса в качестве возможной метки.
Четвертый способ самый прикольный (и позволит делать и другие вещи, как например, прозрачное перенаправление bittorrent-трафика через другой канал), но нет реализаций, и сделать её правильно может быть не так тривиально, как кажется.

Мне кажется, если всё-таки решать более общую задачу, кроме первого способа ничего и не остаётся.

Когда у нас один список заблокированных доменов, который для всех клиентов надо маршрутизировать через один сервер, - могут быть варианты. А когда, как у меня сейчас, семь списков, четыре выходных точки, и в каждом сегменте сети свои настройки, какой список через какую точку маршрутизировать… (простейший пример - для зарубежного сегмента список GeoIP-RU перенаправляем через российский сервер, а для российского игнорируем его, а для списка РКН наоборот). При этом списки могут формироваться как из готовых перечней IP/подстей/AS/GeoIP/доменов/масок, так и динамически (пример - турецкие блокировки, единого реестра, который можно скачать, нет, но есть сервис, который позволяет проверить, заблокирован ли IP/домен).

В общем, как только задачка становится чуть более широкой, а в нынешних непростых условиях она неизбежно становится :slight_smile: - вариант 1 это не оверинжиниринг, а суровая необходимость. Вообще в идеале хотелось бы сделать максимально модульную систему, к которой любая новая страна добавляется путём заведения в оной VPSки и изменения конфига.

@ValdikSS, спасибо большое за подробный ликбез. К четвертому подходу я слабо представляю как подступиться (сохранять весь трафик и посылать повторные запросы от нового адреса с DPI-сервера, а потом переписывать ответные пакеты с помощью dynamic NAT для RELATED и ESTABLISHED?).
Да, подход с dnstap и мне кажется чрезчур наивным, поэтому я склоняюсь к третьему варианту из перечисленных. И мне кажется, что такой вариант позволяет

А ещё

очень хорошо сочетается с конфигом китайских прокси типа xray, vray и тд., в которых можно и прописывать AS, и GeoIP, и подцеплять списки IP и доменов. Вы наверное просто не видели это в деле. Я как раз загорелся идеей этого поста, поковыряв конфиг XTLS в nekoray и поняв, насколько он гибкий. Здесь прямо напрашивается сделать клиент еще и сервером.
Да, минус такого подхода в том, что двухстороннюю связность таким образом не настроишь, но это же proxy, а не VPN, и цель тут не в настройке свзяности и проброске сетей.

Быстрый гуглеж не дал найти сломанные mark в issues аналогов v2ray, но учитывая что они все в той или иной степени форки, очень даже вероятно проблема есть у многих или у всех. Однако свойство “sendThrough” в конфиге приведенного примера (а также например xray 出站代理 | Project X) позволяет направлять трафик на разные IP-адреса. @ValdikSS, разве этого недостаточно, чтобы передать информацию для роутера, куда это слать дальше, или я не учитываю что-то еще?

Увы, мне совершенно не нужен прокси, который не VPN, и очень нужна связность сетей на каждой плодащке, так что изыскания в этом направлении не могу комментировать :slight_smile:

@ValdikSS у меня сейчас есть в разработке еще один вариант. Точнее он уже успешно работает но пока выкатываеть его стыдно, за несколько лет путем проб и ошибок вывел себе идеальную систему под все свои задачи.
Общая суть следующая.
1 Раскидываются ULA префиксы на свои сети.
2 Маршрутизация этих префиксов между домашними роутерами\vps\vds.
3 В нужных локация поднимается nat64, к примеру tayga. Скажем в США, Европе и РФ.
4 Дальше мой говнософт в виде мидлваров к coredns.
4.1 первый мидлвар снифает входящие запросы, сверяет с бд, если есть то отправляет на следующий dns, если нет то просто резольвит.
4.2 особый мидлвар который делает dns64. Отходя от стандартов мапирует v4 в v6 как обычно, но необычно что выпиливает все не dns64 ответы в виде оригинальных v4 и v6 адресов, ломает dnssec
Для пункты 4.1 есть restapi по управлению бд на лету, она к слову inmem, могут синхронизироваться между инстансами. Можно более одной бд вести.

На выходе:
1 никаких трюков с маркировкой в фаирволе или гигансткими таблицами маршрутизации с bgp\ospf
2 набивка бд только нужными доменами с возможностью заворотов в нужную локацию. Скажем нетфликс надо через америкосию, ибей через европу, а госуслуги через рф.
3 rest по синхронной набивке бд.
4 очень компактно по ресурсам на серверах, по сути tayga для nat64 и coredns.
5 Довольно геморно для разворачивания и это не вариант в установил и запустил.

Когда чуть облагорожу исходники и допишу хоть какие то readme то вкину на гитхаб всё и где нибудь тут.