Большинство конфигураций полного туннеля отправляют каждый пакет через VPN, и именно директива redirect-gateway делает это возможным. Один отдельный адресат всё же можно исключить. Добавление маршрута к хосту для этого адреса с заполнителем net_gateway говорит клиенту достигать его через исходный шлюз машины, а всё остальное продолжает использовать туннель.

Строка выглядит безобидно и часто ею и является, но она решает только один вопрос: куда идут пакеты для именно этого IPv4-адреса. Она не меняет DNS, IPv6, политику брандмауэра или то, какой процесс открыл соединение, и каждое из этого может тихо свести исключение на нет.

Что на самом деле называет net_gateway

Запись профиля для этого исключения — одна строка: route 198.51.100.77 255.255.255.255 net_gateway. Первый адрес — документационный заполнитель для адресата, маска делает его маршрутом к одному хосту, а последний токен называет заполнитель шлюза. OpenVPN разрешает заполнители шлюзов, когда устанавливает маршруты. vpn_gateway означает собственный шлюз туннеля, дальнюю сторону соединения VPN. net_gateway означает шлюз по умолчанию, который был у хоста до того, как VPN что-либо изменила, обычно это локальный маршрутизатор в физической сети.

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

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

Почему маршрут к хосту побеждает маршрут по умолчанию туннеля

Маршрутизация определяется наиболее конкретным подходящим префиксом. redirect-gateway def1 обычно не заменяет маршрут по умолчанию; он добавляет две половины, маршрут для нижней половины адресного пространства и один для верхней, так что исходный маршрут по умолчанию сохраняется для других целей. Эти половины шире одного адреса.

Маршрут к одному адресу с маской 255.255.255.255 — это /32, то есть максимальная конкретность, которую даёт IPv4. Когда оценивается пакет для этого адреса, /32 совпадает и побеждает независимо от того, какой маршрут был установлен первым. Это и есть механизм исключения, и он работает одинаково в Linux, macOS и Windows, пока маршрут действительно присутствует.

Windows добавляет второе измерение. Когда два маршрута одинаково конкретны, побеждает тот, у которого метрика ниже, а VPN-адаптер может нести метрику интерфейса, меняющую результат. /32 всё ещё конкретнее половин, поэтому исключение обычно сохраняется, но устаревший маршрут из прошлой сессии может дать запутанный результат, если он столь же конкретен.

Чего исключение не покрывает

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

IPv6 — вторая. Директива маршрута обрабатывает только IPv4. Двойной стек-адресат может предпочесть IPv6, который в зависимости от политики следует туннелю или маршруту IPv6 по умолчанию хоста, так что исключение для IPv4 никогда не вступает в силу. Вам нужен соответствующий маршрут IPv6 или осознанное решение отключить IPv6 для этого клиента.

Область приложений — третья. Правило основано на адресате, поэтому каждый процесс, подключающийся к этому адресу, использует прямой путь, тот ли это процесс, который вы имели в виду, или нет. И наоборот, сайт может отвечать с нескольких адресов, поэтому исключение одного /32 не исключает сайт. Если настоящее требование — маршрутизация по приложениям, таблица маршрутов клиента Community — неподходящий инструмент.

Проверка исключения без самообмана

Начните с установленного маршрута, а не с браузера. В Linux спросите ядро, какой маршрут и следующий переход оно использует для конкретного адреса; в Windows прочитайте таблицу маршрутов для этого /32. Убедитесь, что шлюз физический, а не туннельный. Если записи нет, профиль не применён или у клиента не было прав менять маршруты.

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

Наконец, проверьте механизмы, которые могут переопределить маршрут. Kill switch на стороне клиента или настройка Windows block-outside-dns может запретить прямой трафик, и это проявляется как соединение, которое не работает, хотя маршрут верен. Не отключайте эти механизмы, чтобы исключение выглядело работающим; если политика запрещает прямой путь, исключение — проблема проектирования для владельца службы VPN.

Проверьте снова после переподключения или смены сети, потому что шлюз до VPN и доступный путь — это свойства момента, а не профиля.

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