Эта статья предназначена для тех, кто хочет настроить выборочный роутинг на основе доменных имен на своих маршрутизаторах Keenetic. Основная цель — оптимизировать управление сетевым трафиком по доменным именам, избегая необходимости вручную добавлять многочисленные маршруты в таблицу маршрутизации. Такой подход значительно упрощает настройку и позволяет гибко перенаправлять трафик через VPN-туннели.

Эта инструкция собрана из различных источников и протестирована на версии KeeneticOS 4.3 beta — всё работает стабильно. Процесс на других версиях KeeneticOS 4.x будет идентичным.

Предварительные условия

  1. Роутер Keenetic с подключённым внешним сервером WireGuard (WG) или Amnezia. Используются стандартные средства Keenetic для подключения туннеля.

    Важно: статья касается перенаправления трафика в зависимости от домена, а не настройки VPN.

  2. На туннеле должен быть установлен чекбокс «использовать для выхода в интернет».

  3. Установленные компоненты операционной системы: Протокол IPv6, Модули ядра подсистемы Netfilter.

  4. Установите Entware по этой инструкции.

  5. Получите доступ к SSH с установленным Entware. После этого выполните следующие команды:

opkg update
opkg install mc dnsmasq-full ipset iptables

Настройка DNS-сервера

  1. Откройте файл /opt/etc/dnsmasq.conf и добавьте строку:

conf-file=/opt/etc/unblock.dnsmasq

Весь конфиг для dnsmasq будет храниться в файле /opt/etc/unblock.dnsmasq

  1. Создайте файл /opt/etc/unblock.dnsmasq и добавьте в него следующую конфигурацию (где @nwg0 — ваш VPN-интерфейс, узнать его можно через команду ip a):

port=5354
server=1.1.1.1@nwg0
user=root
group=root

ipset=/youtube.com/bypass
ipset=/googlevideo.com/bypass
  1. Перезапустите сервер dnsmasq:

/opt/etc/init.d/S56dnsmasq restart
  1. Отключите автоматическое получение DNS-серверов в настройках интерфейса провайдера.

  2. В настройках DNS роутера укажите сервер с портом 5354 (например, 192.168.2.1:5354). У меня это 192.168.2.1:5354, у вас адрес может отличаться.

    Примечание: localhost и 127.0.0.1 Keenetic не позволяет указать.

    PS: Я у себя оставил DoH сервера Яндекса и дополнительно прописал только домены из списка выше. Это решение на ваше усмотрение, но в случае падения туннеля я не хочу остаться без интернета. По этой же причине я не хотел делегировать роль DNS-сервера целиком сервису dnsmasq.

Подготовка политик доступа

Далее будем использовать возможности интерфейса Keenetic для настройки политик доступа.

  1. Переходим в раздел «Приоритеты подключений». Нам нужно создать две новые политики доступа:

    • Политика "TO_VPN" будет использоваться для устройств, которые должны выходить в интернет только через VPN. Оставляем галочку только у VPN соединения.

    • Политика "Internet" будет использоваться для всех остальных устройств. Вы должны перенести все устройства из "политики по умолчанию". Эти устройства будут подключаться к интернету через основного провайдера, но для доменов, указанных в конфигурации dnsmasq, трафик будет перенаправляться через VPN (политика "TO_VPN").

Маркирование трафика

Keenetic маркирует трафик в зависимости от группы устройств. Нам нужно выяснить, какие маркеры присваиваются для политик "TO_VPN" и "Internet".

  1. Добавьте устройства в нужные группы (узнайте их IP-адреса) и выполните команду:

iptables-save | grep MARK

Например, для политики Internet можно увидеть строку:

-j MARK --set-xmark 0xffffaaa/0xffffffff

А для TO_VPN:

-j MARK --set-xmark 0xffffaab/0xffffffff

Запомните свои маркеры. У вас они будут отличаться.

Скрипт iptables

Теперь создаём скрипт для маршрутизации трафика:

  1. Создайте файл /opt/root/iptables.sh и сделайте его исполняемым:

chmod +x /opt/root/iptables.sh

Внутри файла укажите следующие строки:

[ -n "$(iptables-save | grep TO_VPN)" ] && exit 0
ipset create bypass hash:net -exist
iptables -t mangle -N TO_VPN
iptables -t mangle -A TO_VPN -j MARK --set-mark 0xffffaab
iptables -t mangle -A TO_VPN -j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff
iptables -t mangle -A PREROUTING -p all -m mark --mark 0xffffaaa -m set --match-set bypass dst -j TO_VPN
iptables -t mangle -A OUTPUT -p udp -d 1.1.1.1 --dport 53 -j TO_VPN

Где:

  • -p all — любой протокол,

  • -m mark --mark 0xffffaaa — инициатор пакета из группы "Internet",

  • -m set --match-set bypass dst — IP адрес назначения соответствует списку IP-адресов bypass (этот ipset обновляется нашим DNS-сервером на лету).

Скрипт также ловит DNS-запросы из OUTPUT (локально сгенерированные запросы от dnsmasq). Транзитные DNS-запросы, например, если клиент использует сервер 8.8.8.8, пойдут без VPN.

  1. Теперь вы можете запустить этот скрипт вручную для проверки. Если всё работает корректно, его можно добавить в автозагрузку:

Добавление в автозагрузку

Для добавления скрипта в автозагрузку создаём файл /opt/etc/ndm/netfilter.d/iptables_reload.sh и делаем его исполняемым:

chmod +x /opt/etc/ndm/netfilter.d/iptables_reload.sh

Содержимое файла:

#!/bin/sh

[ "$type" == "ip6tables" ] && exit 0   # проверяем протокол
[ "$table" == "mangle" ] || exit 0     # проверяем таблицу

logger "iptables $table reloaded: load /opt/root/iptables.sh"

/opt/root/iptables.sh

Таким образом, скрипт будет вызываться роутером при каждой перезагрузке таблицы mangle или nat.

Теперь всё готово! Вы можете протестировать настройки и убедиться, что выборочный роутинг через VPN работает корректно.

Комментарии (11)


  1. nicolas_d
    22.10.2024 17:51

    Разве то же самое не делает opkg пакет kvas?


    1. BaCuJIuu Автор
      22.10.2024 17:51

      В kvas требуется отключать системный DNS-сервер, что для меня не подходит. Мне удобен системный DNS благодаря его GUI. К тому же, у меня настроены туннели до работы, и часть зон я маршрутизирую через них. Администрировать это через dnsmasq или bind мне не хочется.

      Ну и в целом, мне было интереснее разобраться, как это работает, чем просто взять готовое решение.


      1. nicolas_d
        22.10.2024 17:51

        Кстати, спасибо за статью. Это дает чуть большее понимание, как работает связка dnsmasq + ipset. Смотрю в сторону kvas для домашнего маршрутизатора, но мне не нравится именно то, что не используются системные dns, которые видно явно и нет необходимости в ручном рестарте сервиса при их изменении.

        Видимо, придется сделать форк, т.к. в решении возможно привязаться только к VPN соединению, а у меня заходят 2 провайдера и есть необходимость в делении некоторого трафика на разных провайдеров, помимо VPN. Но это у меня частный случай.


  1. tigreavecdesailes
    22.10.2024 17:51

    Довольно сумбурно написано. Перевожу кратко:
    на (домашнем) роутере ставится кэширующий днс (dnsmasq) и результаты резолва для определённых доменов он не только отдаёт клиентам, а ещё и складывает в специальный список в ядре линукса (ipset). В дальнейшем, файрвол (netfilter в ядре линукса) роутера сравнивает ip назначения исходящего трафика с этим списком и если находит совпадение, то направляет этот трафик через отдельный интерфейс (поднятый впн).

    Прикольная связка двух казалось бы несоединимых процессов - резолв и роутинг. Спасибо dnsmasq.
    Можно использовать не только на кинетике, а везде где есть dnsmasq+netfilter.


    1. BaCuJIuu Автор
      22.10.2024 17:51

      Отличный краткий пересказ, спасибо! :)


    1. bdaring
      22.10.2024 17:51

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


  1. AndreyYu
    22.10.2024 17:51

    Как посоветуете быть, если статический внешний адрес выдается провайдером по dhcp и если отключаешь dhcp, в т.ч. настройки dns и прописываешь те же самые настройки ручками, то работать подключение отказывается.


  1. Dusty77
    22.10.2024 17:51

    Кто знает как сделать чтобы при доступе к ресурсу если не 200 или 302 код в ответе скрипт бы перекидывал в ВПН канал траффик. Может быть есть готовые решения. Не привязываясь к кинетику у меня другой роутер.


  1. Marsezi
    22.10.2024 17:51

    Чувствует моя душа что наконец-то мы близко к статье о частичной маршрутизации на стандартной прошивке asus роутера. То там сейчас можно или полностью трафик пустить или конкретных машин. Жду больше года уже )


  1. uneasy
    22.10.2024 17:51

    "в случае падения туннеля я не хочу остаться без интернета"

    Можно вместо server=1.1.1.1@nwg0 использовать server=1.1.1.1 и отдельно настроить на кинетике маршрутизацию для 1.1.1.1, сняв галочку "эксклюзивный маршрут"


    1. BaCuJIuu Автор
      22.10.2024 17:51

      Способ рабочий, но в случае отказа флешки с Entware я тоже не хочу остаться без интернета :)