Хук-скрипт срабатывает, читает ppp0 и применяет маршруты к тому интерфейсу, который в этот момент носит это имя. Иногда это нужный вам туннель; иногда — сессия, подключившаяся минутой раньше. Следующее переподключение сдвигает номер, и тот же скрипт тихо настраивает не ту связь. Решение — брать интерфейс из только что выполненного вызова и нести рядом с ним нужный профиль.

Проследите одну сессию от опций до хука

Начните там, где создаётся сессия. xl2tpd запускает pppd с файлом опций, указанным в pppoptfile этого туннеля, поэтому плагин, номер устройства и любой маркер профиля определяются там, а не в глобальном файле. Менеджер соединений может генерировать собственные опции, то есть редактирование /etc/ppp/options не доказывает, что нужный вам туннель изменился. Когда соединение поднимается, pppd запускает скрипты уведомлений из диспетчера дистрибутива. Эти скрипты получают имя интерфейса первым аргументом, а маркер профиля — шестым.

Окружение несёт те же факты под именами вроде IFNAME и PPP_IPPARAM, но их доступность зависит от установленного диспетчера. Прочитайте диспетчер, прежде чем полагаться на переменную: одни дистрибутивы сохраняют порядок аргументов upstream, другие фильтруют окружение перед вызовом вашего скрипта. Скрипт, который использует только $1 и шестой аргумент, работает в обоих случаях.

Читайте интерфейс из вызова

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

ipparam office-vpn

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

Запрашивайте имя только если отказ правилен

Фиксированное имя выглядит проще чтения аргументов, но меняет поведение при сбое. Опция unit запрашивает номер для исходящего соединения, и pppd переходит к динамическому выделению, когда это устройство уже занято. Ничто в этом результате не резервирует ppp0 для вашего профиля.

ifname ppp-office

Опция ifname ведёт себя иначе: если запрошенное имя уже используется или не может быть назначено, pppd завершается, а не выбирает другое. Это выбор политики, а не косметическое переименование. Используйте её, когда второй одновременный экземпляр того же профиля должен быть отклонён, и убедитесь, что установленный pppd и ваш менеджер соединений передают эту опцию.

Так или иначе, имя, которое видит скрипт, — это то, по которому нужно действовать. Настроенное имя не отменяет необходимости читать вызов, потому что перезапущенная сессия всё ещё может представить другое имя, чем предыдущая.

Приведите разборку в соответствие с настроенной сессией

Маршруты и правила брандмауэра переживают создавший их скрипт, поэтому разборка должна удалять именно те объекты, которыми владеет сессия. Помечайте правила маркером профиля, а также интерфейсом, и удаляйте по этой метке. Если два туннеля могут быть активны, удаление всего, что упоминает ppp, — это способ, которым одно отключение ломает другое соединение.

Проверьте случай, который выявляет ошибку: поднимите вторую сессию PPP, пока первая ещё подключена, затем переподключите первую и посмотрите, какой интерфейс сообщает хук. Успешный запуск с одной сессией ничего не доказывает о выделении имён. Повторите при остановленном VPN, чтобы убедиться, что разборка не оставляет устаревший маршрут.

Храните маркер, интерфейс и путь к хуку в заметках о развёртывании. Когда после перезагрузки номер меняется, эти три значения объясняют, почему скрипт вёл себя иначе без каких-либо правок конфигурации.

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