Как настроить эффективный split-tunneling в ocserv (OpenConnect), чтобы трафик к российским адресам (RU) маршрутизировался отдельно от остального трафика?

Настраивал Split Tunneling по инструкции из <a href="https://www.linuxbabe.com/linux-server/ocserv-openconnect-vpn-advanced" rel="nofollow">https://www.linuxbabe.com/linux-server/ocserv-open...</a>. Хочу, чтобы трафик к российским адресам шел мимо VPN. Для этого взял базу IP CIDR России и сгенерировал файл примерно на 16 000 строк с директивами no-route. По логам клиент OpenConnect начинает применять эти правила примерно через час, а Android-клиент полностью игнорирует директивы no-route. Можно ли корректно и эффективно настроить разделение трафика для этого VPN? Есть ли более короткие, компактные списки адресов/диапазонов для крупных российских сервисов (mail.ru, госуслуги, Сбер, Яндекс)?
  • 26 марта 2026 г. 16:02
Ответы на вопрос 2
Кратко — можно, но не так, как вы попытались. Коротко по сути проблем и рабочим вариантам.

Почему у вас не работает
- ocserv отправляет клиенту маршруты / исключения (директивы route / no-route), но приложение‑клиент должно их применить. Не все клиенты (и не все ОС) корректно поддерживают или применяют большое количество pushed‑маршрутов.
- Мобильные Android‑клиенты часто имеют ограничения VpnService (ограничение на число маршрутов/правил), либо автор приложения OpenConnect мог не реализовать поддержку no-route/массовых изменений. Поэтому Android может игнорировать ваши директивы.
- Push ~16 000 префиксов — это плохая идея: много сетевых записей, большой трафик управления, клиенты/ядро ОС могут «подвисать», часть маршрутов отбрасываться, а обновление/применение может происходить с задержкой.

Варианты решений и рекомендации

1) Понять, где проблема — сервер или клиент
- Подключитесь с Linux/Windows клиентом (openconnect CLI на Linux, ocserv-compatible клиент на десктопе) и посмотрите, применяются ли no-route‑правила сразу. Если на десктопе применяются — виноват Android/мобильный клиент.
- Логи ocserv (debug) покажут, что сервер отправляет клиенту. Логи клиента покажут, что он применяет.

2) Если контролируете клиенты — делайте исключения на клиенте
- Самый надёжный путь — настроить split‑tunneling на самом клиенте (скрипты добавления маршрутов, policy routing, iptables+ip rule), а не пытаться передавать 16k префиксов серверу. На Linux/macOS/Windows это реализуется скриптом при подключении.
- На Android это возможно только при root (добавление маршрутов в таблицу) или с использованием VPN‑приложений/локальных прокси, которые умеют per‑app/proxy правила (например, прокси с PAC, либо приложения с поддержкой per‑app VPN). Без root и без поддержки split‑tunnel со стороны клиента это сделать нельзя.

3) Если нужно, чтобы трафик шёл «мимо VPN» — клиент должен посылать его мимо туннеля
- Ваша цель «чтобы RU‑трафик шел мимо VPN» требует, чтобы клиент НЕ отправлял эти пакеты в туннель. Сервер не может заставить клиент «вернуть» пакеты в локальную сетевую стэк, если клиент уже запаковал их в туннель. Поэтому решение — либо push‑no‑route, которое клиент применит, либо настройка на самом клиенте.

4) Практический компромисс: доменное/прокси‑разделение (рекомендую)
- Если важны только крупные сервисы (Яндекс, Сбер, Госуслуги, Mail.ru и т.п.), гораздо удобнее использовать доменно‑ориентированный обход: ставите PAC (Proxy Auto Config) или браузер/приложение, которое использует системный/локальный прокси и направляет трафик к конкретным доменам в обход VPN. Это работает для веб/HTTP(S) трафика и часто для приложений, которые поддерживают прокси/PAC.
- На Android можно использовать браузеры с поддержкой PAC/профилей или локальный прокси (например, браузер + tinyproxy на устройстве), либо использовать VPN‑приложения с поддержкой PAC/whitelist.

5) Уменьшение размера списка IP (агрегация и ASN)
- Не пытайтесь передавать 16k строк «как есть». Можно:
  a) Взять готовые country CIDR‑списки и агрегировать (ipdeny, ipverse, delegations).
     Пример: https://www.ipdeny.com/ipblocks/data/countries/ru.zone
  b) Свернуть префиксы с помощью netaddr (Python) или cidrmerge:
     Примеры команд:
       curl -s https://www.ipdeny.com/ipblocks/data/countries/ru.zone > ru.zone
       python3 - <<'PY'
import netaddr
cidrs=[netaddr.IPNetwork(l.strip()) for l in open('ru.zone') if l.strip()]
for c in netaddr.cidr_merge(cidrs):
    print(c)
PY
     Это уменьшит число префиксов (иногда в 2–5 раз).
  c) Ещё компактнее — брать префиксы по ASN компаний (AS для Яндекса, Сбера, Mail.ru и т.д.) — тогда вы будете исключать все префиксы конкретного оператора/провайдера, а не каждую маленькую сеть. Получить префиксы ASN можно через whois/radb:
       whois -h whois.radb.net -- '-i origin ASXXXX' | awk '/^route/ {print $2}'
     (сначала узнайте ASN по домену/IP, например через whois/ipinfo).

- Даже после агрегации число префиксов для всей страны остаётся большим — но обычно список становится приемлемым (тысячи → сотни).

6) Как сгенерировать строки для ocserv
- В ocserv вы можете добавить в конфиг строки no-route = X.Y.Z.T/NN
- Автоматически сгенерировать можно так (после cidr_merge):
   for p in $(python3 cidr_merge_script.py); do echo "no-route = $p"; done >> /etc/ocserv/ocserv.conf
  Но повторюсь: это работает только если клиент поддерживает и применяет no-route и если число префиксов не слишком велико.

7) Альтернативный серверный подход (не «мимо VPN», но полезно)
- Если ваша цель — не «куда отправляет клиент», а «чтобы сессии с RU ресурсами шли через другой исходящий шлюз на сервере», то можно на VPN‑сервере делать policy routing: по destination IP ставить MARK и отправлять через специфический routing table/gateway. Это означает, что трафик клиент→VPN всё равно идёт в туннель, но на сервере вы можете выбирать, через какой интернет‑интерфейс выходить. Это НЕ делает трафик «мимо VPN» с точки зрения провайдера клиента, но может помочь, если сервер имеет несколько выходов/гейтвеев и нужно разделить исходящий путь.

8) Что делать конкретно вам
- Шаг 1: протестируйте на Linux/desktop клиенте, чтобы понять, сервер ли правильно отсылает no-route.
- Шаг 2: если сервер правильно шлёт, но Android игнорирует — либо смените клиент/версию, либо делайте split на самом Android (root или per‑app/proxy), либо используйте доменный PAC‑подход.
- Шаг 3: сократите список префиксов: используйте ipdeny.ru.zone + cidr_merge или собирайте префиксы по ASN для конкретных сервисов (Яндекс, Сбер, Mail.ru и т.д.).
- Шаг 4: не пушьте десятки тысяч префиксов — это ненадёжно. Стремитесь к сотням агрегированных префиксов или к AS‑спискам для крупных сервисов.

Полезные ссылки/команды
- Список префиксов по странам: https://www.ipdeny.com/ipblocks/data/countries/ru.zone
- Сжатие префиксов: использовать Python netaddr.cidr_merge или утилиты cidrmerge/cidr-tools.
- Префиксы по ASN: whois/radb:
   whois -h whois.radb.net -- '-i origin ASXXXX' | awk '/^route/ {print $2}'
- Логирование отправки маршрутов в ocserv — включите debug и посмотрите, что сервер отправляет клиенту.

Если хотите — могу:
- Посмотреть вашу конфигурацию ocserv (фрагмент с route/no-route) и подсказать оптимизацию.
- Сгенерировать агрегированный список префиксов для России из ipdeny и дать его в виде no-route строк (и пример скрипта для добавления в ocserv.conf).
- Помочь собрать список ASN для конкретных сервисов (напишите, какие именно сервисы/доменные имена вас интересуют), и получить их префиксы.
16к no-route это перебор, андроид столько маршрутов тупо не тянет. Прогони базу через <code>cidr-merger</code> — он объединит смежные подсети, ужмёт до 3-4к. <br/> <br/> Но для мобилки проще использовать per-app vpn в настройках openconnect клиента — просто исключи банковские приложения и госуслуги из туннеля, без возни с IP-списками
Похожие вопросы