Эта статья предназначена для тех, кто хочет настроить выборочный роутинг на основе доменных имен на своих маршрутизаторах Keenetic. Основная цель — оптимизировать управление сетевым трафиком по доменным именам, избегая необходимости вручную добавлять многочисленные маршруты в таблицу маршрутизации. Такой подход значительно упрощает настройку и позволяет гибко перенаправлять трафик через VPN-туннели.
Эта инструкция собрана из различных источников и протестирована на версии KeeneticOS 4.3 beta — всё работает стабильно. Процесс на других версиях KeeneticOS 4.x будет идентичным.
Предварительные условия
-
Роутер Keenetic с подключённым внешним сервером WireGuard (WG) или Amnezia. Используются стандартные средства Keenetic для подключения туннеля.
Важно: статья касается перенаправления трафика в зависимости от домена, а не настройки VPN.
На туннеле должен быть установлен чекбокс «использовать для выхода в интернет».
Установленные компоненты операционной системы: Протокол IPv6, Модули ядра подсистемы Netfilter.
Установите Entware по этой инструкции.
Получите доступ к SSH с установленным Entware. После этого выполните следующие команды:
opkg update
opkg install mc dnsmasq-full ipset iptables
Настройка DNS-сервера
Откройте файл
/opt/etc/dnsmasq.conf
и добавьте строку:
conf-file=/opt/etc/unblock.dnsmasq
Весь конфиг для dnsmasq будет храниться в файле /opt/etc/unblock.dnsmasq
Создайте файл
/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
Перезапустите сервер
dnsmasq:
/opt/etc/init.d/S56dnsmasq restart
Отключите автоматическое получение DNS-серверов в настройках интерфейса провайдера.
-
В настройках DNS роутера укажите сервер с портом 5354 (например,
192.168.2.1:5354
). У меня это 192.168.2.1:5354, у вас адрес может отличаться.Примечание: localhost и 127.0.0.1 Keenetic не позволяет указать.
PS: Я у себя оставил DoH сервера Яндекса и дополнительно прописал только домены из списка выше. Это решение на ваше усмотрение, но в случае падения туннеля я не хочу остаться без интернета. По этой же причине я не хотел делегировать роль DNS-сервера целиком сервису dnsmasq.
Подготовка политик доступа
Далее будем использовать возможности интерфейса Keenetic для настройки политик доступа.
-
Переходим в раздел «Приоритеты подключений». Нам нужно создать две новые политики доступа:
Политика "TO_VPN" будет использоваться для устройств, которые должны выходить в интернет только через VPN. Оставляем галочку только у VPN соединения.
Политика "Internet" будет использоваться для всех остальных устройств. Вы должны перенести все устройства из "политики по умолчанию". Эти устройства будут подключаться к интернету через основного провайдера, но для доменов, указанных в конфигурации dnsmasq, трафик будет перенаправляться через VPN (политика "TO_VPN").
Маркирование трафика
Keenetic маркирует трафик в зависимости от группы устройств. Нам нужно выяснить, какие маркеры присваиваются для политик "TO_VPN" и "Internet".
Добавьте устройства в нужные группы (узнайте их IP-адреса) и выполните команду:
iptables-save | grep MARK
Например, для политики Internet можно увидеть строку:
-j MARK --set-xmark 0xffffaaa/0xffffffff
А для TO_VPN:
-j MARK --set-xmark 0xffffaab/0xffffffff
Запомните свои маркеры. У вас они будут отличаться.
Скрипт iptables
Теперь создаём скрипт для маршрутизации трафика:
Создайте файл
/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.
Теперь вы можете запустить этот скрипт вручную для проверки. Если всё работает корректно, его можно добавить в автозагрузку:
Добавление в автозагрузку
Для добавления скрипта в автозагрузку создаём файл /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)
tigreavecdesailes
22.10.2024 17:51Довольно сумбурно написано. Перевожу кратко:
на (домашнем) роутере ставится кэширующий днс (dnsmasq) и результаты резолва для определённых доменов он не только отдаёт клиентам, а ещё и складывает в специальный список в ядре линукса (ipset). В дальнейшем, файрвол (netfilter в ядре линукса) роутера сравнивает ip назначения исходящего трафика с этим списком и если находит совпадение, то направляет этот трафик через отдельный интерфейс (поднятый впн).
Прикольная связка двух казалось бы несоединимых процессов - резолв и роутинг. Спасибо dnsmasq.
Можно использовать не только на кинетике, а везде где есть dnsmasq+netfilter.bdaring
22.10.2024 17:51Вот кстати да, в таких статьях-инструкциях зачастую очень не хватает, где-нибудь в начале, описания общими словами, как же именно работает представленное решение.
AndreyYu
22.10.2024 17:51Как посоветуете быть, если статический внешний адрес выдается провайдером по dhcp и если отключаешь dhcp, в т.ч. настройки dns и прописываешь те же самые настройки ручками, то работать подключение отказывается.
Dusty77
22.10.2024 17:51Кто знает как сделать чтобы при доступе к ресурсу если не 200 или 302 код в ответе скрипт бы перекидывал в ВПН канал траффик. Может быть есть готовые решения. Не привязываясь к кинетику у меня другой роутер.
Marsezi
22.10.2024 17:51Чувствует моя душа что наконец-то мы близко к статье о частичной маршрутизации на стандартной прошивке asus роутера. То там сейчас можно или полностью трафик пустить или конкретных машин. Жду больше года уже )
uneasy
22.10.2024 17:51"в случае падения туннеля я не хочу остаться без интернета"
Можно вместо
server=1.1.1.1@nwg0
использоватьserver=1.1.1.1
и отдельно настроить на кинетике маршрутизацию для 1.1.1.1, сняв галочку "эксклюзивный маршрут"BaCuJIuu Автор
22.10.2024 17:51Способ рабочий, но в случае отказа флешки с Entware я тоже не хочу остаться без интернета :)
nicolas_d
Разве то же самое не делает opkg пакет kvas?
BaCuJIuu Автор
В kvas требуется отключать системный DNS-сервер, что для меня не подходит. Мне удобен системный DNS благодаря его GUI. К тому же, у меня настроены туннели до работы, и часть зон я маршрутизирую через них. Администрировать это через dnsmasq или bind мне не хочется.
Ну и в целом, мне было интереснее разобраться, как это работает, чем просто взять готовое решение.
nicolas_d
Кстати, спасибо за статью. Это дает чуть большее понимание, как работает связка dnsmasq + ipset. Смотрю в сторону kvas для домашнего маршрутизатора, но мне не нравится именно то, что не используются системные dns, которые видно явно и нет необходимости в ручном рестарте сервиса при их изменении.
Видимо, придется сделать форк, т.к. в решении возможно привязаться только к VPN соединению, а у меня заходят 2 провайдера и есть необходимость в делении некоторого трафика на разных провайдеров, помимо VPN. Но это у меня частный случай.