Клиенты подключаются и проходят аутентификацию, а затем их трафик уходит через неправильный восходящий канал, потому что единственный маршрут по умолчанию на машине принадлежит самому шлюзу. Замена этого маршрута сломала бы собственные обновления машины и доступ к управлению, поэтому выбор должен быть уже, чем «весь трафик». Работоспособная форма — правило политики, привязанное к внутреннему адресу источника пула клиентов и указывающее на вторую таблицу маршрутизации, которой принадлежит альтернативный WAN. Дальше контрольный список касается полноты и поведения при сбое, а не самого правила.

Убедитесь, что адрес источника доживает до решения о маршрутизации

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

Именно здесь локальные тесты вводят в заблуждение. Запущенный на шлюзе curl — это локально созданный поток с адресом шлюза, поэтому он берёт основную таблицу и ничего не доказывает о пути клиента. Проверяйте с подключённого клиента или создавайте трафик с источником, который действительно принадлежит пулу.

Начните с записи реальных значений: префикса пула, интерфейса туннеля, который его несёт, адреса и следующего перехода второго WAN, а также номера таблицы, которую вы собираетесь использовать. Очистите старые правила любой предыдущей попытки, прежде чем добавлять новые, потому что дублирующиеся правила с разными приоритетами дают сбои, которые выглядят случайными.

Постройте выбранную таблицу, которая является полной

Таблица — это не маршрут по умолчанию с приятелем. Ей нужно достаточно маршрутов, чтобы каждый поиск разрешался внутри неё, включая связанный маршрут для подсети WAN, чтобы следующий переход был достижим. Для пула 10.77.0.0/24 на tun1, адреса WAN 203.0.113.20/24 со следующим переходом 203.0.113.1 и таблицы 600:

ip -4 route replace 203.0.113.0/24 dev usb0 src 203.0.113.20 table 600
ip -4 route replace 10.77.0.0/24 dev tun1 table 600
ip -4 route replace default via 203.0.113.1 dev usb0 table 600
ip -4 rule add priority 1500 from 10.77.0.0/24 lookup 600

Правило стоит на приоритете ниже любого существующего правила, перехватывающего всё, поэтому подходящие клиенты сначала попадают в таблицу 600, а всё остальное проваливается в основную таблицу. Справочник по ip-rule полностью описывает модель упорядоченного поиска и синтаксис селектора.

Затем подумайте, чего в таблице нет. Назначение, у которого маршрут есть только в основной таблице, например подсеть управления, доступная через eth0, не будет найдено в таблице 600 и не вернётся в основную, как только там появится маршрут по умолчанию. Если эти пути важны, добавьте их в выбранную таблицу явно, что обычно и является правильным ответом для таблицы выхода VPN.

Держите собственный трафик слушателя вне политики

У слушателя OpenVPN есть собственное внешнее соединение, которое идёт через тот восходящий канал, по которому клиент до него добрался. Этот трафик должен сохранять обратный путь, с которым он пришёл, а широкое правило, покрывающее публичный адрес сервера или весь интерфейс туннеля, может затянуть его в альтернативную таблицу. Ограничьте правило внутренним пулом и ничем больше.

Фильтрация обратного пути заслуживает внимания по той же причине. Когда ответы клиентам уходят через usb0, а запрос пришёл по другому каналу, строгая настройка rp_filter может отбросить пакеты, которые политика маршрутизации считает допустимыми. Проверьте действующие значения sysctl на обоих интерфейсах, прежде чем делать вывод, что правило не сработало.

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

Согласуйте пересылку и трансляцию с маршрутом

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

Если второй WAN не будет маршрутизировать частный пул обратно к вам, транслируйте источник на этом выходе. Для интерфейса с динамическим адресом обычный выбор — узкое правило masquerade, ограниченное пулом и интерфейсом:

iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -o usb0 -j MASQUERADE

Здесь охват важнее цели. Правило masquerade, совпадающее с любым исходящим интерфейсом, перепишет и трафик, который правильно уходит через eth0, а это скрывает ошибки маршрутизации вместо того, чтобы их исправлять. Трансляция выполняется после решения о маршрутизации, поэтому она никогда не сможет исправить пакет, отправленный не в тот восходящий канал.

Накладные расходы туннеля тоже требуют внимания, когда пути различаются. Если клиенты согласуют большой TCP MSS, а у альтернативного WAN ниже MTU или внутри него туннель, крупные сегменты застревают, а мелкие работают. Ограничение MSS на пути пересылки превращает это в предсказуемое поведение вместо периодического зависания.

Решите, что произойдёт, когда usb0 исчезнет

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

Там, где такой откат неприемлем, добавьте в таблицу 600 явный терминальный маршрут, например маршрут по умолчанию blackhole, или отбросьте пул в межсетевом экране, пока интерфейс выключен. Любой из двух вариантов — это решение, которое можно записать; молчание им не является.

Устойчивость — последний пункт. Кто бы ни владел обоими каналами, будь то сетевой менеджер, скрипт отправки или жизненный цикл соединения, он должен при каждом переподключении заново создавать маршруты и правило, не добавляя дубликатов. Проверьте запросом от реального клиента и отдельным запросом со шлюза, подтвердите наблюдаемый выход в обоих случаях, затем выдерните второй WAN и посмотрите, какой из двух спроектированных результатов действительно происходит. IPv6 нужны собственные таблица, правило и трансляция; приведённое выше правило IPv4 ничего об этом не говорит.

Похожие статьи