Направьте одну подсеть LAN через OpenVPN и сохраните маршрут по умолчанию
Сохраните маршрут LAN по умолчанию, пока одна подсеть идёт через туннель. Сравните таблицу политик с правками основной таблицы, затем выберите NAT или маршрут на стороне сервера.
Устройства, которые маршрутизируют для LAN и одновременно поднимают VPN, попадают в один и тот же спор с самими собой: туннель хочет владеть маршрутом по умолчанию, а LAN нужно вернуть его себе. Когда OpenVPN подключается, он может установить маршрут по умолчанию через туннель или пару половинных маршрутов по умолчанию, что правильно для ноутбука и неправильно для шлюза, соседи которого ждут ответов с его адреса LAN. Ответ не в том, чтобы отказаться от VPN. Ответ в том, чтобы дать двум решениям разные таблицы.
Один маршрут по умолчанию, два владельца
Пересылаемый трафик и трафик, созданный локально, не обязаны идти одним путём. Клиентам LAN туннель нужен только для выбранных вами назначений, а собственным сессиям управления хоста и его ответам этим клиентам нужен маршрут LAN по умолчанию. Смешивание обоих в основной таблице навязывает один ответ двум разным вопросам.
У OpenVPN есть переключатель именно для этого. route-noexec не даёт клиенту вообще трогать основную таблицу, а значения, которые он иначе использовал бы, экспортируются в скрипт route-up как route_vpn_gateway, dev и адреса интерфейса. Затем вы решаете, какая таблица получит какой маршрут, в коде, который можно прочитать позже.
Таблица политик против переписывания основной
| Approach | What it buys | What it costs |
|---|---|---|
| Separate table plus source rule | LAN traffic and host traffic keep independent defaults | Every lookup now depends on rule order |
| Editing the main table only | Fewer moving parts on a single-purpose host | One mistake takes the gateway offline entirely |
| Two half-default routes | Works for a full-tunnel client | Ambiguous on a host that must answer on its LAN address |
Отдельная таблица — единственный вариант, который масштабируется дальше одной подсети. Дайте ей имя один раз, а затем ссылайтесь по имени, чтобы никому не приходилось помнить число:
echo "10 vpn" >> /etc/iproute2/rt_tables
ip rule add from 192.168.50.0/24 table vpn
ip route add default via 10.8.0.1 dev tun0 table vpnАдреса здесь — заполнители. Замените префикс LAN, шлюз туннеля и имя устройства из своего развёртывания, прежде чем что-либо запускать.
Правило должно совпадать и с хостом
Правило, совпадающее только с префиксом LAN, покрывает пересылаемые пакеты. Оно не покрывает трафик, который создаёт сам шлюз, и не покрывает ответы, которые он отправляет обратно клиентам LAN, а они несут адрес LAN шлюза как источник. Эти поиски проваливаются в main и всё ещё могут уйти через туннель.
Добавьте второе правило для собственного адреса шлюза в LAN или расширьте первое правило до набора, включающего оба. Порядок важен: более конкретное правило ставьте первым и проверяйте результат поиском, который явно называет источник.
ip route get 203.0.113.9 from 192.168.50.1Если это показывает устройство туннеля для назначения, которое должно остаться локальным, набор правил неверен независимо от того, что содержит таблица.
NAT или маршрут на дальней стороне
Сервер VPN знает подсеть туннеля и больше ничего. Пакеты, приходящие с адресом источника из LAN, не имеют обратного пути, если кто-то его не обеспечит, и обеспечить его можно ровно двумя способами. Добавление маршрута для префикса LAN на сервере сохраняет исходный источник видимым от края до края, чего обычно хочет проверенный дизайн. Маскирование на шлюзе переписывает источник на адрес туннеля и не требует содействия сервера.
iptables -t nat -A POSTROUTING -s 192.168.50.0/24 -o tun0 -j MASQUERADEВыбирайте NAT, когда вы не контролируете сервер и не можете добавить там маршруты. Выбирайте маршрут на стороне сервера, когда важны журналы, контроль доступа или симметрия обратного пути, потому что маскирование стирает исходный адрес из всего, что фиксирует дальняя сторона.
В любом случае пересылка должна быть включена, а строгая фильтрация обратного пути может отбросить ответ, если main не выбрал бы туннель для этого источника. Проверьте фактическое значение, прежде чем винить туннель.
Сделайте так, чтобы разделение пережило переподключение
Правила и маршруты, добавленные вручную, исчезают при пересоздании интерфейса, а устаревшая запись в таблице может пережить сеанс, который её оправдывал. Поместите правило таблицы, маршрут туннеля и запись маскирования в скрипт route-up клиента и очистите таблицу в начале скрипта, чтобы старый шлюз не пережил в новом сеансе.
Проверьте с обеих сторон: поиск на шлюзе с источником из LAN и настоящий запрос от клиента LAN к назначению, которое должно пройти через туннель. Маршрут, который существует, но никогда не выбирается, ведёт себя точно так же, как полное отсутствие маршрута, пока вы не прочитаете счётчики.