Постоянные маршруты для VPN на Mac: networksetup или хук подключения?
Маршрут, вводимый после каждого переподключения, — не политика. Решите, принадлежит ли префикс VPN-службе, временному тесту или хуку для адресов, известных только после согласования.
Маршрут, вводимый после каждого подключения, решает момент, а не неделю. В macOS устойчивый выбор обычно — префикс, хранимый вместе с VPN-службой, потому что служба переустанавливает его при каждом подключении и удаляет, когда служба отключена. Альтернативы — временный route add для тестирования и хук подключения для адресов, известных только после согласования.
Решите, принадлежит ли маршрут службе или сеансу
Спросите, от чего зависит префикс. Если это фиксированная частная сеть за собственной VPN-службой, маршрут принадлежит этой службе. Если он зависит от адреса партнёра, который меняется при каждом подключении, хук или задача, управляемая состоянием, может быть лучшим владельцем. Если вы проверяете путь только на следующие пять минут, временного маршрута достаточно.
Маршрут, привязанный к службе, имеет самый чистый жизненный цикл. Он появляется вместе со службой и исчезает, когда служба не подключена, поэтому не может пережить туннель, на который указывает. Это свойство ценнее удобства однострочной команды.
Маршрут, привязанный к сеансу, принадлежит интерфейсу, и этот номер меняется без предупреждения. Переподключение может дать туннелю другое имя utun, чем использовал предыдущий сеанс, и это превращает жёстко заданную команду в маршрут, который не указывает никуда или, хуже того, на другой туннель.
Прочитайте текущее состояние маршрута и службы
Начните с имён, которые система действительно использует. Имя службы в настройках сети — идентификатор для команд ниже, а текущая таблица маршрутов показывает, что установил подключённый клиент. Прочитайте оба, пока туннель активен.
scutil --nc list
networksetup -listnetworkserviceorder
netstat -rn | head -30
route get 10.20.5.5
Этот поиск показывает, какой шлюз и интерфейс ядро выбрало бы для этого адреса в данный момент. Если оно уже выбирает туннель, префикс покрыт и новый маршрут был бы излишним. Если оно выбирает локальный маршрутизатор, туннелю не хватает этого префикса.
Запишите адрес партнёра, пока подключены. Он становится значением шлюза в маршруте, привязанном к службе, и обычно это пункт назначения, показанный для маршрута по умолчанию туннеля в netstat -rn.
Сохраните префикс с помощью networksetup
Инструмент networksetup прикрепляет дополнительные маршруты к сетевой службе. Для службы с именем OfficeVPN и частного префикса, достижимого через партнёра туннеля, форма такова:
sudo networksetup -setadditionalroutes OfficeVPN 10.20.0.0 255.255.0.0 10.8.0.6
networksetup -getadditionalroutes OfficeVPN
Каждая тройка после имени службы задаёт пункт назначения, его сетевую маску и партнёра туннеля как шлюз. Один вызов может нести несколько префиксов, а пустой вызов очищает сохранённый список. Читатель — это шаг проверки; если список пуст, настройка не применилась к той службе, о которой вы думаете.
Шлюз должен быть партнёром туннеля, а не физическим маршрутизатором. Маршрут, называющий локальный шлюз, отправляет частный префикс через физический интерфейс — это исходный сбой с лишними шагами. Устаревший партнёр — самая частая причина, по которой внешне правильный маршрут никогда не передаёт трафик. Перечитайте партнёра из подключённого состояния, а не копируйте адрес из старой заметки.
Используйте route add только для теста
Прямой маршрут полезен, чтобы доказать, что префикс работает, прежде чем делать его постоянным. Форма с интерфейсом избегает поиска шлюза:
sudo route -n add -net 10.20.0.0/16 -interface utun4
Маршрут исчезает при следующем переподключении и зависит от номера интерфейса, который существует сегодня. Это делает его диагностикой, а не развёртыванием. Если тест работает, а маршрут, привязанный к службе, нет, сначала сравните значение шлюза; это поле чаще всего бывает неверным.
Остерегайтесь советов, которые заменяют маршрут по умолчанию VPN, чтобы навязать разделение. Клиент, применяющий полный туннель, может переустановить свои маршруты после переподключения или обновления политики, поэтому ручное изменение тихо отменяется. Несколько частных префиксов — это проблема маршрутизации; удерживать весь интернет-трафик локально против политики полного туннеля — решение на стороне сервера.
Выбирайте хук только тогда, когда адрес согласуется
Для соединений на основе PPP, например L2TP, macOS выполняет /etc/ppp/ip-up после установления соединения. Скрипт получает имя интерфейса и согласованные локальный и удалённый адреса, поэтому может добавить маршрут, зависящий от партнёра, назначенного сервером. Это именно тот случай, который фиксированный маршрут службы выразить не может.
IKEv2 и клиенты производителей могут вообще не использовать этот путь PPP, а значит, скрипт может молчать весь сеанс. Когда это происходит, задание launchd, которое опрашивает scutil --nc status и реагирует на изменение состояния, — эквивалентный механизм, с небольшой задержкой.
Какой бы хук вы ни использовали, сделайте его идемпотентным и разрешите ему удалять только созданные им маршруты. Скрипт, удаляющий каждый маршрут, упоминающий туннель, в конце концов удалит маршрут, который поддерживает доступность VPN-сервера, и соединение упадёт, как только это удастся.
Завершите проверкой частного пункта назначения, обычного просмотра и цикла переподключения или сна. Затем проверьте scutil --dns, потому что разрешение имён — отдельная политика, и работающий маршрут не доказывает, что частные имена разрешаются.