Документации split-tunnel нужно правило DNS рядом с каждым маршрутом
Маршрут решает по адресу, резолвер решает по имени. Задокументируйте оба селектора для каждого потока, каждый с одним тестом, иначе заметка не выдержит смены DNS.
Заметка о split-tunnel, которая гласит «офисный трафик идёт через VPN», задокументировала одно решение и подразумевала ещё три. На уровне пакетов таблица маршрутизации выбирает интерфейс по адресу назначения; на уровне имён резолвер выбирает сервер по запросу, и эти два выбора делаются независимо. Поэтому правильно задокументированный префикс всё ещё может дать машину, которая разрешает внутреннее имя в публичный адрес, или не разрешает ничего, пока маршрут выглядит идеально.
Два селектора, одна попытка соединения
Когда приложение подключается к files.corp.example, до появления пакета происходит два поиска. Резолвер решает, какой сервер получит запрос, используя домены поиска, домены маршрутизации для каждого канала или явное правило профиля. Затем таблица маршрутизации решает, куда пойдёт полученный адрес, используя самое длинное совпадение префикса с назначением.
Ничто не связывает эти два решения. Частная зона может ответить 10.20.4.11, пока таблица маршрутизации отправляет 10.20.0.0/16 в туннель, и соединение работает. Переверните любое из них, и оно сломается так, что будет похоже на другое: правильная политика DNS плюс отсутствующий маршрут дают разрешённое имя и тайм-аут, а правильный маршрут плюс публичный резолвер дают адрес, который чисто маршрутизируется не туда.
DNS с разделённым горизонтом делает это резче. Одно и то же имя может вернуть частный адрес от внутреннего резолвера и публичный адрес от обращённого в интернет, поэтому заметка, фиксирующая только префикс, не может предсказать, какой адрес клиент реально использует. Запишите путь резолвера, иначе адрес — догадка.
Что упускает заметка только о маршруте
Запись только о маршруте бесполезна для самой частой неисправности split-tunnel: имён. Пользователь сообщает, что внутренняя сеть не загружается, туннель поднят и префикс присутствует. У того, кто возьмёт заявку, нет записи, какой резолвер должен был ответить, нет способа отличить неверный суффикс поиска от заблокированного сервера и нет базовой линии для сравнения.
Второй пропуск — список исключений. Дизайн split-tunnel определяется в равной мере тем, что остаётся вне туннеля, и тем, что в него входит, а исключённые диапазоны обычно ломаются первыми, потому что более конкретный локальный маршрут или фильтр на стороне клиента может переопределить замысел, не трогая профиль.
Третий — дальняя сторона туннеля. Клиентский маршрут только кладёт пакет на провод; шлюз всё ещё должен его пересылать и иметь обратный путь. Руководство strongSwan по пересылке напоминает, что правила пересылки и брандмауэра на шлюзе — часть функции, а не сантехника, которую можно предполагать.
Поля, которые делают заметку исполнимой
Одна строка на поток, а поток — это назначение плюс имя плюс владелец. Вот поля, которые выдерживают соприкосновение с реальным инцидентом:
| Field | Why it has to be written down |
|---|---|
| Destination prefix and address family | The route is per family; an IPv4 note says nothing about a AAAA answer |
| Selected tunnel or direct path | Names the decision, not the symptom |
| Private namespace and resolver | Which domain, which server, which search suffix |
| Public name path | Confirms public names do not accidentally use the private resolver |
| Where the rule lives | Client profile, server push, OS policy or management tool |
| Owner and review date | Namespaces change owner more often than routes change |
Строка «где это живёт» — та, которую люди пропускают. Префикс, продвигаемый сервером, маршрут, добавленный профилем клиента, и маршрут, набранный в оболочке, различаются тем, кто может их изменить и переживут ли они переподключение. Без этого поля следующий инженер не скажет, на какой из трёх он смотрит.
Один тест на правило, а не один на туннель
Каждой строке нужны две безобидные проверки: одна упражняет маршрут, другая — имя. Для маршрута запросите то, что должно пройти через туннель, и подтвердите путь, а не доступность, например tracert -d 10.20.4.11 в Windows или ip route get 10.20.4.11 в Linux. Для имени запросите частное имя и запишите, какой сервер ответил, используя resolvectl query files.corp.example или dig files.corp.example против резолвера, который называет заметка.
Добавьте и отрицательное ожидание: что должно произойти, когда туннель опущен. Исключённое приложение на устройстве Android или iOS с включённой блокировкой без VPN может вообще не иметь связи, а настольный клиент может оставить то же приложение работающим, пока туннель переподключается. Запись предполагаемого ответа превращает «VPN сломал моё приложение» в проверяемое утверждение.
Держите запись вместе с конфигурацией
Храните заметку рядом с профилем, который она описывает, и версионируйте её вместе с этим профилем. Документ в вики, который никто не обновляет, — слух; таблицу в том же репозитории, что и продвигаемые маршруты с политикой резолвера, можно проверить в том же изменении.
Когда что-то ломается, сравните применённый маршрут и действующий резолвер с записью, прежде чем добавлять ещё одно исключение. Две из трёх частых причин — старое правило пространства имён и вспомогательный процесс вне политики приложения — выглядят точно как сбой VPN и невидимы, если заметка перечисляет только префиксы.
Прежде чем назвать заметку готовой, подтвердите, что она письменно отвечает на это: какой префикс, для какого семейства адресов; какое частное пространство имён, каким резолвером обслуживается; какие имена намеренно остаются публичными; где настроено каждое правило и кто им владеет; и одна команда, доказывающая маршрут, и та, что доказывает имя. Если чего-то не хватает, следующий инцидент будет диагностирован с нуля.