Маршрутизация отдельных доменов через другой интефейс (в OpenWrt)

Системы, которые не вошли в список.

Модератор: Модераторы разделов

Аватара пользователя
Bizdelnick
Модератор
Сообщения: 19431
Статус: nulla salus bello
ОС: Debian GNU/Linux

Маршрутизация отдельных доменов через другой интефейс

Сообщение Bizdelnick »

Поделюсь решением задачи с общественностью. Поскольку отдельные её части подробно описаны в вики, буду по возможности просто давать ссылки на неё, а больше внимания уделю увязыванию этих частей воедино.

Дано: роутер с OpenWrt и ряд доменов, трафик к которым (включая поддомены) надо заворачивать через отдельный интерфейс. При этом IP-адреса, соответствующие доменам, периодически меняются, что не должно ломать конфигурацию.

Решение:
В dnsmasq есть фича, позволяющая при ресолвинге доменов добавлять полученные адреса в определённый ipset. Далее маршруты до этих адресов можно завернуть на нужный интерфейс разными способами, я воспользовался mwan3 (просто потому что он был у меня уже установлен и настроен, хотя это не самая простая вещь).
Необходимый софт: dnsmasq-full (в устанавливаемой по умолчанию сборке dnsmasq поддержка ipset отключена), ipset, mwan3, обвязка для них в uci/luci, ну и то, что нужно для поднятия интерфейса, в который, собственно, и заворачивается трафик (wireguard в моём случае). Чтобы не париться установкой пакетов, я сразу собрал образ, в котором это всё есть, с помощью ImageBuilder. Команда сборки такая: make image PROFILE=netgear_wndr3800 PACKAGES='dnsmasq-full ipset kmod-wireguard luci luci-app-mwan3 luci-app-upnp luci-app-wireguard luci-i18n-base-ru luci-i18n-firewall-ru luci-i18n-mwan3-ru luci-i18n-wireguard-ru mwan3 stubby wireguard-tools luci-i18n-opkg-ru -dnsmasq' (здесь netgear_wndr3800 — модель моего роутера, надо заменить на свою; stubby добавлен для решения другой задачи, но не то чтобы совсем не связанной с данной). Тем, кто не пользуется mwan3, рекомендую заменить его на vpn-policy-routing (в комплекте с luci-app-vpn-policy-routing и luci-i18n-vpn-policy-routing-ru): он не такой навороченный, с ним легче разобраться.

Далее по шагам.
  1. Настройка интерфейса. Описание опущу, здесь у каждого своё. Из важного далее упомяну только, что в моём случае интерфейс называется wg0.
  2. Создание маршрута по умолчанию через этот интерфейс. Поскольку надо, чтобы трафик по умолчанию всё же шёл через интерфейс WAN, а через wg0 — только когда мы явно его туда направим, этот маршрут должен иметь бо́льшую метрику, чем уже существующий шлюз по умолчанию через сеть провайдера.
    В зависимости от того, как создаётся интерфейс, настройка отличается. В случае wireguard в настройках самого интерфейса возможности задать его в качестве шлюза по умолчанию нет, поэтому надо прописать его как статический маршрут. В моём случае настройка в /etc/config/network выглядит так:

    Код: Выделить всё

    config route
            option interface 'wg0'
            option target '0.0.0.0/0'
            option gateway '192.0.2.1'
            option metric '50'
    Здесь сеть назначения 0.0.0.0/0 означает, что это шлюз по умолчанию, 192.0.2.1 — адрес удалённого сервера, выполняющего роль шлюза, в виртуальной сети, а метрика 50 больше метрики для провайдерского шлюза по умолчанию (10). Маршрут можно создать через веб-интерфейс.
  3. Создание пустого ipset. У меня ему соответствует такая секция в /etc/config/firewall:

    Код: Выделить всё

    config ipset
            option name 'tunnel'
            option match 'src_ip'
            option storage 'hash'
            option enabled '1'
    Имя вместо 'tunnel' можно задать любое, остальные опции должны быть точно такими, как у меня.
    Вот тут веб-интерфейсом не обойтись. После правки конфига надо сделать fw3 reload. Проверить, что ipset создался, можно командой ipset list tunnel.
  4. Настройка dnsmasq. Тоже не вынесена в веб-интерфейс. В /etc/config/dhcp добавляется примерно такая секция:

    Код: Выделить всё

    config ipset 'filter'
            list name 'tunnel'
            list domain 'example.net'
            list domain 'example.org'
    Здесь вместо 'filter' можно использовать любое имя. Число доменов может быть любое. Для применения настроек надо сделать /etc/init.d/dnsmasq restart. Если в дальнейшем потребуется добавить домены в список, после этого также потребуется выполнение /etc/init.d/dnsmasq restart.
  5. Настройка vpn-policy-routing (проще) или mwan3 (сложнее). Тут уже можно воспользоваться веб-интерфейсом, чтобы направить адреса из ipset под названием tunnel через нужный интерфейс (wg0).
После этого основная часть трафика будет идти через провайдерский шлюз, только к example.net и example.org (и поддоменам вроде www.example.org) — через туннель.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 19431
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Маршрутизация отдельных доменов через другой интефейс

Сообщение Bizdelnick »

Должен сделать два дополнения по итогам настройки ещё одного роутера.
1. При использовании vpn-policy-routing пункты 2–4 не нужны, он это всё делает сам. И настраивается через веб-интерфейс полностью.
2. Забыл упомянуть о том, как бороться с шибко умными браузерами, использующими сторонний DoH. Понятное дело, в таком случае dnsmasq не получит запроса и не добавит адреса в ipset. В Firefox для того, чтобы сообщить браузеру о необходимости использовать DNS-сервер в локалке, предусмотрен способ. Имплементируется так:

Код: Выделить всё

uci add_list dhcp.@dnsmasq[0].address /use-application-dns.net/
uci commit
/etc/init.d/dnsmasq restart
Или же в веб-интерфейсе в настройках DNS-сервера задать правило для адреса /use-application-dns.net/ (именно так, домен без адреса, чтобы сервер вернул ответ NXDOMAIN).
Проверка:

Shell

% dig use-application-dns.net

; <<>> DiG 9.16.1-Ubuntu <<>> use-application-dns.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 31209
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;use-application-dns.net. IN A

;; Query time: 199 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Вс июл 03 18:29:27 +04 2022

%
Это работает для Firefox с настройками по умолчанию. Если пользователь сам явным образом включит в настройках DoH, это уже не поможет. Что касается Chromium, то как оно там работает — я не в курсе.

P. S. При проверке свежевыполненных настроек важно сбросить все кеши DNS, чтобы запрос дошёл до dnsmasq. В Firefox внутренний кеш сбрасывается кнопочкой в about:networking#dns. Если в системе используется systemd-resolved, надо сделать resolvectl flush-caches. Если есть ещё какие-то кешеры — не забудьте про них.

P. P. S. Если кто не понимает, как сочетать вышеописанное с шифрованным сторонним DNS, ещё раз повторю, что stubby выше упоминался не случайно.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали: