Почему ваше правило split tunnel перестало соответствовать сервису
Правило закрепляет префикс, а сервис переехал. Прочитайте пункт назначения, который приложение действительно использует, и затем исправьте механизм вместо расширения исключения.
Раздельное туннелирование обычно отказывает одним из двух способов. Либо трафик, который должен быть внутри туннеля, его обходит, либо трафик, который должен оставаться снаружи, втягивается внутрь. Отказ из-за устаревшего правила — это первый случай, и он запутаннее, потому что правило применяется в точности так, как записано. Изменился пункт назначения: сервис теперь отвечает по адресу, который правило никогда не называло, а в туннеле всё в порядке.
Что закрепляет правило и что возвращает DNS
Правило раздельного туннелирования — это статическое утверждение о назначениях, обычно выраженное префиксом, маршрутом или списком адресов. Оно оценивается по пункту назначения пакета в момент отправки. Имя хоста — это запрос, который возвращает набор адресов со временем жизни и кешем, и ответ может различаться в зависимости от resolver, типа запроса и минуты.
Эти два объекта никогда не договариваются друг с другом. Правило продолжает совпадать с выданным ему префиксом, сервис продолжает менять адрес, который выдаёт, а разрыв между ними молча растёт. Поэтому симптом появляется после миграции провайдера или обновления сертификата, а не после изменения конфигурации. Никто не редактировал туннель, значит, никто не смотрит на туннель, и диагностика уходит в сторону приложения, а не политики.
Три способа, которыми ломается совпадение
Очевидный случай — переехавший сервис: оператор дал ему новый адрес, DNS последовал, а исключение нет. Второй — семейство адресов, которое правило никогда не покрывало, что бывает, когда имя начинает возвращать записи AAAA, которые исключение только для IPv4 игнорирует. Третий — различие resolver: внутренний и публичный вид могут возвращать разные адреса для одного имени, поэтому адрес, который использует приложение, не тот, с которым вы тестировали.
Кешированное соединение — четвёртый вариант, и его легко пропустить. Приложение может до сих пор говорить с адресом, который разрешило час назад, а значит, свежий запрос и его открытый socket расходятся в том, где живёт сервис.
Прочитайте пункт назначения, который приложение действительно использует
Спросите операционную систему и таблицу socket, а не вкладку браузера. Запрос отвечает, во что имя разрешается прямо сейчас, а таблица socket показывает адрес, к которому подключён процесс, и он может быть старее. Выполните оба до того, как строить теорию, потому что разница между ними примерно в половине случаев сама и есть ответ.
getent ahosts api.example.com
dig +short api.example.com A
dig +short api.example.com AAAA
ss -tnp | grep -F api
ip route get 203.0.113.40
Затем сравните с тем, что покрывает правило. Если текущий адрес выходит за пределы исключения и запрос всё ещё не проходит, вы нашли причину, не трогая конфигурацию туннеля. Если приложение подключено к адресу, совпадающему с правилом, и запрос всё ещё не проходит, проблема где-то за туннелем, и это неверное расследование.
Почините механизм, а не симптом
Если продукт поддерживает обслуживаемое управление на основе доменов, используйте его и следуйте его документированному поведению обновления и области действия. Это заменяет статическое предположение обслуживаемым ответом ценой зависимости от того, что функция работает, как описано.
Если проект опирается на статический список, дайте ему владельца и план обновления. В плане должно быть сказано, как обнаруживается адрес, кто утверждает изменение и как быстро список должен последовать за миграцией провайдера. Список без владельца — это будущий сбой с известной причиной.
Не расширяйте исключение на большую соседнюю сеть только ради того, чтобы захватить каждый адрес, который вы видели в коротком тесте. Это не исправление; это постоянное изменение границы безопасности, и оно тихо позволит посторонним сервисам обходить туннель, пока правило существует.
Проверьте обе половины замысла
Проект раздельного туннелирования имеет два замысла, и исправление должно сохранить оба. Защищённый сервис должен идти через туннель, а исключённые категории должны продолжать его обходить. Проверьте новое соединение с исправленным назначением, а затем проверьте что-то, что должно оставаться снаружи.
curl -sv --max-time 5 https://api.example.com/ -o /dev/null 2>&1 | grep -E 'Trying|Connected to'
curl -sS --max-time 5 https://public.example/ -o /dev/null -w '%{http_code}\n'
Запишите новый адрес, выбранный механизм и дату. Именно эта заметка не даёт следующему человеку решить, что VPN случайно проигнорировал собственную конфигурацию.