woodger13 часов назадОбъяснить с
Policy-Based Routing (PBR): как способ починить домашний интернет
Уровень сложностиСреднийВремя на прочтение6 минОхват и читатели6.3KLinux*Сетевые технологии*КейсВесной 2025 я заметил, что у меня начались регулярные проблемы с доступом в интернет. Сайты открывались, но часть изображений не загружалась. Некоторые мобильные приложения периодически жаловались на сеть. При этом те же ресурсы нормально работали через мобильный интернет или VPN.
Я поднял на домашнем роутере OpenVPN-клиент. Проблемные ресурсы заработали. Зато российские сервисы начали видеть зарубежный IP-адрес, а задержка увеличилась.
Получилось, что VPN не устранил проблему, а лишь подменил одно другим.
В итоге я разделил трафик с помощью Policy-Based Routing: основной внешний трафик домашней сети направил в VPN, а исключения оставил на обычном WAN подключении. Ниже — устройство этой схемы, конфигурация OpenWrt.
Почему VPN-тунель решил задачу только наполовину
OpenVPN-сервер отправляет клиенту redirect-gateway def1, весь трафик идет через VPN.
Меняем правила:
• внешний трафик пойдет через VPN;
• российские ресурсы — напрямую через провайдера;
• при падении VPN устройства в сети не должны полностью терять интернет.Часть задачи можно решить статическими маршрутами. Но я не хотел вручную поддерживать файл /etc/hosts в акуальном состоянии.
На помошь пришел Policy-Based Routing (PBR), как решение которое позволяет выбирать путь с дополнительным условиям. В Linux правила ip rule могут учитывать, например, адрес источника и метку пакета, а затем направлять поиск маршрута в нужную таблицу.
Разделяй и властвуй
Для реализации решения нам понадобится довольно мощное и современное железо. Роутер, который вам дал в аренду ваш провайдер скорее всего не подойдет.
В статье я буду использовать Banana Pi BPI-R4 с официальное сборкой OpenWrt.
ОбозначениеНазначениеlanДомашняя сеть 192.168.0.0/24wanОсновное проводное подключение к провайдеруvpn, tun0Логический интерфейс и устройство OpenVPN-туннеляУпрощённая схема выбора пути для внешнего IPv4-трафика из LAN:
LAN 192.168.0.0/24
|
OpenWrt на BPI-R4
|
+-- login.beeline.ru ------> wan
+-- адрес из ru.zone ------> main --> обычный uplink
+-- остальные назначения -> vpn (tun0) --> VPN-серверVPN здесь работает поверх обычного подключения: до публичного адреса VPN-сервера роутер добирается через провайдера. Туннель даёт дополнительный путь для пользовательского трафика.
Пакеты OpenWrt
Для реализации этой схемы на роутере понадобятся:
ПакетНазначениеpbrСоздаёт политики, правила и таблицы маршрутизацииopenvpn-opensslOpenVPN-клиент, который поднимает VPN-туннель.dnsmasq-fullDNS/DHCP-сервис с поддержкой nftset для доменных политик при resolver_set 'dnsmasq.nftset'curlПозволяет PBR читать адресный список по file:///www/iplist/ru.zonednsmasq-full устанавливается взамен обычного dnsmasq. Порядок замены и требования к доменным политикам описаны в документации PBR.
ip-full устанавливается автоматически вместе с pbr.
Главная идея: VPN не должен владеть default route
Ключевое решение оказалось таким:
Не разрешать OpenVPN менять default route, а выбор VPN перенести в отдельные PBR-политики
OpenVPN через netifd
В моей сборке туннель запускается через netifd, поэтому его параметры находятся в /etc/config/network:
config interface 'vpn'
option proto 'openvpn'
option config '/etc/openvpn/client.ovpn'
option pull_filter 'ignore "redirect-gateway"'
option dev 'tun0'
option defaultroute '0'pull_filter заставляет клиент игнорировать полученную от сервера директиву redirect-gateway. defaultroute '0' запрещает netifd устанавливать полученный шлюз как обычный default route. Эти настройки действуют на разных уровнях, поэтому я оставил обе.
Явное dev 'tun0' связывает логический интерфейс vpn с устройством туннеля, которое затем использует PBR. Проверять нужно и интерфейс, и фактические маршруты: две настройки в конфигурации сами по себе не показывают результат.
Firewall для выхода через VPN
Выбранный маршрут должен быть разрешён firewall. VPN у меня находится в отдельной зоне. Часть /etc/config/firewall, отвечающая за выход из LAN:
config zone
option name 'vpn'
list network 'vpn'
option input 'REJECT'
option output 'ACCEPT'
option forward 'REJECT'
option masq '1'
option mtu_fix '1'
config forwarding
option src 'lan'
option dest 'vpn'lan -> vpn разрешает пересылку, а masq '1' подменяет адрес источника на адрес туннеля. В этой схеме VPN-серверу не требуется обратный маршрут к каждому домашнему адресу.
Обычный выход lan -> wan с NAT также остаётся разрешённым: через него работают прямые исключения и запасной путь при недоступности VPN.
Три политики PBR
Конфигурация /etc/config/pbr:
config pbr 'config'
option enabled '1'
option strict_enforcement '0'
option procd_reload_delay '5'
option uplink_interface 'wan'
option resolver_set 'dnsmasq.nftset'
config policy
option name 'Beeline login'
option interface 'wan'
option dest_addr 'login.beeline.ru'
config policy
option name 'Bypass IPs'
option interface 'ignore'
option dest_addr 'file:///www/iplist/ru.zone'
config policy
option name 'Default VPN'
option interface 'vpn'
option src_addr '192.168.0.0/24'Порядок правил имеет значение.
ПолитикаЧто совпадаетКак выбирается путьBeeline loginАдреса домена login.beeline.ruЧерез проводной wanBypass IPsАдрес назначения из ru.zoneПропустить дальнейшую обработку PBR и использовать обычную маршрутизациюDefault VPNИсточник из 192.168.0.0/24Через vpn для оставшегося внешнего трафика
Почему для RU bypass выбран ignore
ignore здесь означает выход из обработки политиками PBR. В моей конфигурации основным подключением остаётся WAN, адреса из списка идут через него.
У портала провайдера другая задача: login.beeline.ru относится к проводному подключению Билайн. Поэтому он закреплён именно за wan, а его правило стоит выше общего списка исключений. Это нужно, чтобы мы могли залогинится у провайдера.
Файл /www/iplist/ru.zone должен существовать на роутере до загрузки политики. Это обычный текстовый список IPv4-сетей в CIDR, по одной сети на строку.
Пример формата:
5.8.0.0/13
5.16.0.0/12
31.128.0.0/10
...ip-full предоставляет полноценную команду ip, которой PBR управляет таблицами и правилами маршрутизации. Для доменных политик при resolver_set 'dnsmasq.nftset' нужен dnsmasq-full с поддержкой nftset: он наполняет адресные наборы по DNS-ответам.
Для чтения локального адресного списка через file:// нужен curl. Требования к пакетам описаны в документации PBR.
Получение регионального файла через IPCC
Для получения файла ru.zone я использовал собственное решение — IPCC. Утилита загружает статистику региональных интернет-регистраторов (RIR), выбирает сети по коду страны и агрегирует их в список CIDR.
Скачивание и запуск
Нужно будет склонировать репозиторий:
git clone git@github.com:woodger/ipcc.git
cd ipcc
python3 ./ipcc --helpIPCC запускается из исходников и использует стандартную библиотеку Python. В этой схеме развёртывание сводится к размещению репозитория на компьютере и запуску утилиты из его каталога.
Генерация списка
Для российских IPv4-сетей указываю код страны RU и имя выходного файла:
python3 ./ipcc --country RU --output ru.zoneУтилита загружает данные RIR из интернета и записывает результат в ru.zone в текущем каталоге. После успешного завершения проверяю число строк и начало файла:
wc -l ru.zone # ~8500
head -n 5 ru.zoneКаждая строка должна содержать IPv4-сеть в формате CIDR, как в примере выше. Число сетей меняется вместе с исходными данными.
ПараметрНазначение--country RUВыбрать страну по двухбуквенному коду; по умолчанию используется RU--output ru.zoneУказать путь к выходному файлу--ipv6Сформировать IPv6-список вместо IPv4; для показанного RU bypass используется IPv4--verboseВключить подробное журналирование
Передача списка на роутер
Нужно передать файл ru.zone на роутер по пути /www/iplist/ru.zone, который уже указан в политике Bypass IPs как file:///www/iplist/ru.zone.
Что происходит при отказе VPN
У меня намеренно установлено:
option strict_enforcement '0'Это выбор в пользу доступности. Когда PBR обрабатывает отключение VPN-интерфейса, трафик может вернуться к обычной маршрутизации через доступное подключение. Часть проблемных ресурсов при этом снова может перестать работать, зато остаётся возможность пользоваться остальным интернетом.
Цена такого решения — выход трафика напрямую при отказе VPN. Если требуется обязательная передача только через туннель, нужен другой режим и проверка блокировки при его отключении. Значение strict_enforcement и порядок политик описаны в документации PBR.
Итог
В результате RU-трафик идет через WAN. OpenVPN только поднимает дополнительный путь. Firewall разрешает и маскарадует трафик. dnsmasq превращает доменные исключения в наборы адресов. PBR решает, какую таблицу использовать конкретному пакету из LAN. Доменные правила при этом не будут зависеть от DNS.
Такая схема сохраняет обычный выход в интернет и задаёт исключения явно: какой трафик направлять в VPN, какой выпускать напрямую и что делать при отключении туннеля.
Ссылки
• IPCC — генератор CIDR-списков по странам
• Документация пакета pbr
• Формат статистики RIRТеги:• pbr
• openwrt
• openvpn
• firewall
• ipccХабы:• Linux
• Сетевые технологии
Получайте больше инсайтов о систематизации бизнеса
Подписывайтесь на Telegram-канал Business Operations — ежедневные материалы о бизнес-процессах, операционном управлении и повышении эффективности
💬 Подписаться на канал→ Оригинальная статья