📱 Подписаться
IT и цифровая трансформация

Policy-Based Routing (PBR): как способ починить домашний интернет

📰 Habr 👁️ 0 просмотров

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 — ежедневные материалы о бизнес-процессах, операционном управлении и повышении эффективности

💬 Подписаться на канал