Когда маршруты раздельного туннелирования пересекаются: какой префикс побеждает
Совпадение самого длинного префикса, метрика и правила политики решают, какой туннель обслуживает пересекающийся адрес назначения. Сначала проверьте адрес источника и разрешённое имя.
Два профиля раздельного туннелирования, два частных префикса и один хост, на который претендуют оба. Симптом редко бывает чистой ошибкой: сервис работает в понедельник, перестаёт отвечать после повторного подключения второго клиента и снова работает после перезагрузки. Порядок, в котором вы подключали клиентов, не решает исход, как и порядок строк в интерфейсе клиента. Выполняйте эти проверки по порядку и остановитесь на первой, которая не выполняется, потому что последующие имеют смысл только тогда, когда предыдущие верны.
1. Запишите назначение и источник
Начните с точного адреса, к которому идёт неудачный запрос, а не с имени хоста и не с имени приложения. Разрешите имя один раз, запишите каждый ответ и выберите тот, который действительно использует проблемный поток. Затем запишите локальный адрес того же потока, потому что адрес источника может изменить, какое правило политики совпадёт и, следовательно, какая таблица будет просмотрена.
Запрос к одной из нескольких записей A может завершиться неудачей, пока соседний адрес отвечает успешно, и это выглядит как нестабильный туннель, а на деле представляет собой два разных пути. Если назначение — имя с несколькими ответами, проверьте каждый ответ отдельно, прежде чем что-то менять.
2. Спросите у ядра, какой маршрут оно выбрало
Не читайте таблицу маршрутов и не делайте вывод из неё. Задайте тот же вопрос, который задаёт стек, с тем же адресом источника: ip route get 10.20.4.10 from 10.8.0.2 в Linux или Find-NetRoute -RemoteIPAddress 10.20.4.10 в PowerShell. Вывод называет маршрут, который действительно будет использован, и часто это не тот, который вы ожидали, читая таблицу.
Среди совпадающих маршрутов обычно побеждает более конкретный префикс: /24 обыгрывает /16 для адреса, который находится в обоих. Между совпадениями одинаковой длины побеждает меньшая метрика, а маршрут, установленный на отключённом интерфейсе, пропускается. Два туннеля, которые объявляют один и тот же /24 с одинаковой метрикой, — это другой случай: ядро сохраняет оба маршрута и выбирает между ними, поэтому результат может чередоваться вместо того, чтобы следовать порядку подключения клиентов. Именно эта ситуация порождает схему в понедельник работает, во вторник нет, и повторное подключение в другом порядке её не меняет.
3. Проверьте, не перенаправило ли поиск правило политики
Прежде чем таблица маршрутов будет просмотрена, ядро проходит по своим правилам политики. Правило может отправить трафик от заданного источника, пользователя или метки межсетевого экрана в совершенно другую таблицу, поэтому побеждающий префикс в основной таблице может никогда не просматриваться для этого потока. ip rule show перечисляет их в порядке оценки, а ip route show table 100 показывает, что на самом деле содержит выбранная таблица.
Здесь прячутся две ловушки. Правило, указывающее на пустую таблицу, создаёт поиск, который проваливается к следующему правилу, поэтому правило как будто ничего не делает. Вторая — сам номер приоритета: правила читаются по возрастанию, а встроенные значения — 0 local, 32766 main и 32767 default. Правило с номером меньше 32767 просматривается до правила по умолчанию, которое перехватывает всё. Правило с номером больше 32767 стоит за ним и достигается только тогда, когда ни одна предыдущая таблица не отвечает, чему препятствует обычный маршрут по умолчанию в main, поэтому на практике оно никогда не достигается и молча ничего не делает, выглядя установленным. Если клиент записал правило и маршрут, проверьте оба и проверьте их снова после повторного подключения, потому что переписанный профиль может добавить второе правило с другим приоритетом.
4. Отделите равенство маршрутов от дублированного плана адресов
Иногда префикс вовсе ни при чём. Два узла, которые оба используют 192.168.1.0/24, означают, что один и тот же адрес обозначает два разных хоста, и ни один маршрут не может их различить. Маршрут к хосту на один из двух ответов работает только до тех пор, пока второй узел не ответит на то же имя, и тогда исключение молча становится самой ошибкой.
Признак в том, что адрес назначения одинаков на обоих путях и различается только предполагаемый владелец. Это решение по плану адресов, а не настройка маршрутизации: перенумеруйте одну сторону, поставьте одну сторону за шлюз, который транслирует, или доберитесь до второго узла через прокси, который сам разрешает свои имена. Понижение маршрута по умолчанию или нагромождение исключений для хостов только переносит конфликт.
5. Убедитесь, что преобразователь имён согласен с маршрутом
Имя, разрешаемое в неправильный частный адрес, даёт все симптомы конфликта маршрутизации и ни одной из его причин. Сравните ответ, который получает хост, с адресом, который назначение действительно использует, и проверьте, какой преобразователь ответил. Если туннель передаёт преобразователь, клиент должен установить его для потоков, использующих туннель; если нет, хост продолжает спрашивать локальный преобразователь, который может ответить из домена поиска или из кэшированной записи.
Обратитесь к преобразователю напрямую и запишите сервер, который ответил. Кэшированный ответ с коротким TTL тоже может объяснить, почему первый запрос после повторного подключения ведёт себя иначе, чем пятый.
6. Подключитесь заново, осмотрите применённое состояние, затем проверьте оба потока
После исправления подключитесь заново и посмотрите, что клиент действительно установил, вместо того чтобы доверять редактору профиля. Перечитайте правила, таблицы и полученный ответ ip route get. Второй клиент может при подключении заново установить свой маршрут и воссоздать конфликт, поэтому проверка состояния должна выполняться после подключения последнего клиента, а не до него.
Проверяйте два потока, а не один: запрос, который раньше завершался неудачей, и ресурс, который должен использовать другой туннель. Перенос всего частного трафика на одно подключение заставит первый тест пройти, но сломает второй, и поймать это может только парный тест. Записывайте каждое сохраняемое исключение с указанием назначения и причины, чтобы следующий человек мог отличить намеренный маршрут к хосту от оставшегося.