Дополнительным маршрутам VPN на Mac нужен владелец, а не скрипт входа
Маршрут, добавленный один раз при входе, — не политика переподключения. Дайте удалённым префиксам владельца и решите, как они появляются, меняются и исчезают вместе с этим соединением.
Доступ к частному префиксу через VPN — это требование с длительностью: оно действует, пока это соединение пригодно, и заканчивается, когда заканчивается соединение. Скрипт входа не может это выразить, потому что вход и поднятие туннеля — разные моменты, и туннель, существующий при входе, может быть не тем, который через минуту несёт трафик. Первое решение — не какую команду выполнить. А какой компонент владеет префиксом.
Префиксу нужен владелец, а не момент
Начните с того, что запишете требование как предложение с подлежащим: достигните 10.77.0.0/24 через офисный VPN, пока это соединение поднято. Это предложение называет префикс, соединение и условие и сразу исключает две популярные замены: хук входа и имя интерфейса вроде ppp0 или utun2.
Имена интерфейсов назначаются во время выполнения и не стабильны между переподключениями. Хук, совпадающий с именем, которое он видел на прошлой неделе, либо не сработает, либо сработает на чужом интерфейсе. Оба исхода выглядят как ошибка маршрутизации, а не как устаревшее допущение, которым они являются. То же возражение относится к любому скрипту, привязанному к имени, которое существует только пока поднят один конкретный туннель.
Используйте поддерживаемый источник намерения маршрута
Шлюз, управляемый профиль или документированный механизм маршрутов владеющего клиента — правильное место, когда этот механизм может выразить требование. Какой из них применим, зависит от протокола и провайдера, и ключи между ними не переносятся, поэтому значение, настраивающее профиль OpenVPN ничего не говорит о встроенном клиенте L2TP или IKEv2.
| Mechanism | Can carry extra prefixes | Who owns the lifetime |
|---|---|---|
| Gateway-pushed routes | Often, if the gateway is configured for it | The connection |
| Managed profile settings | Depends on the client and profile format | The profile |
| Provider tunnel settings | Yes, as included and excluded routes | The provider process |
| Manual command | Yes, once | Nobody |
Для разработчиков пакетных туннелей настройки туннеля IPv4 от Apple явно показывают включённые и исключённые маршруты, и у IPv6 есть свой аналог. Это API, которые использует провайдер, а не доказательство того, что каждая встроенная панель VPN предлагает администратору произвольный список маршрутов. Если текущая комбинация не может выразить нужные префиксы, следующий шаг — поддерживаемый путь настройки от оператора, а не другое приложение, установленное в надежде, что оно поведёт себя лучше.
Срок жизни включает очистку
Иногда внешний помощник действительно нужен, и тогда «добавь маршрут» — самая маленькая часть его работы. Он должен знать, какому соединению служит и какой интерфейс использует это соединение, дождаться, пока соответствующее состояние сети успокоится, оставаться идемпотентным при двух запусках подряд, и не очищать ничего, что он сам не установил.
Последнее условие — то, которое болит. Помощник, удаляющий каждый маршрут, совпадающий с офисным префиксом, рано или поздно удалит маршрут, который он не добавлял. Возникший сбой списывают на VPN-клиент, потому что клиент — это часть, которую видит пользователь. Решить, чем владеет помощник, до его написания дешевле, чем потом объяснять, почему локальная подсеть перестала отвечать.
Гонка при переподключении
Представьте быстрое переподключение. Сеанс A падает, сеанс B поднимается и устанавливает свой маршрут, а затем наконец запускается отложенная очистка A. Если эта очистка удаляет маршруты по префиксу, она забирает с собой действительное состояние B, и соединение, работавшее секунду назад, теперь маршрутизируется в никуда.
Это гонка владения, и добавление паузы в скрипт меняет только то, какая сторона её выиграет. Решение — сделать очистку зависящей от идентичности: сравните интерфейс и сеанс, установленные помощником, с теми, что ещё действуют, и удаляйте только при совпадении.
Что тестировать и чего маршрут не может
Приёмка должна охватывать четыре перехода: первое соединение, переподключение на другой интерфейс, неудачную попытку подключения и окончательное отключение. После каждого читайте маршрут, который система фактически выбрала для адреса на удалённой стороне, а не тот, который вы ожидали.
route -n get 10.77.0.5
netstat -rn -f inet
Включите неудобные случаи в тот же проход: IPv6 там, где он нужен, локальный префикс, пересекающийся с удалённым, и маршрут к самому публичному конечному пункту VPN, который должен продолжать работать, пока туннель поднят. Затем запишите, чем маршрут не является. Он выбирает пакеты; он не даёт разрешения на удалённой стороне и не создаёт обратный путь, и это остаётся отдельными требованиями с отдельными владельцами.
Результат, который вы хотите, — это префикс, следующий за своим поддерживаемым владельцем соединения через каждый переход, а не команда, которая случайно один раз сработала на машине, где была написана.