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

Различие важно, потому что вторую ошибку дешевле организовать и намного легче не заметить. Она проявляется как запрос, ушедший через неверный интерфейс, пока клиент всё ещё сообщал об исправном соединении.

Два способа, которыми сеть может на вас повлиять

У пакета, который доходит до туннеля, полезная нагрузка скрыта от каждого узла на его пути, и эта защита держится даже тогда, когда маршрут вас удивляет. Пакет, который до туннеля не доходит, — обычный запрос с вашего адреса, отправленный туда, куда указала таблица маршрутизации. Первая ошибка требует сломанного шифра или скомпрометированного партнёра, а второй достаточно сообщения конфигурации, которому ваша машина решила доверять. Именно из-за этой асимметрии маршрутизации нужна отдельная проверка.

Оборудованию на пути не нужны ваши ключи, чтобы влиять на второй случай. Ему нужно лишь, чтобы ваша конечная точка приняла маршрут, резолвер или правило политики, которое такой порождает.

expected:  app -> tunnel device -> encapsulation -> internet
observed:  app -> wlan0        -> plaintext     -> internet

Откуда маршрут может появиться ещё до создания туннеля

DHCP выдаёт не только аренду адреса. Опция бесклассовых статических маршрутов может нести префиксы назначения и следующие переходы, а RFC 3442 обсуждает последствия неверного адреса маршрутизатора для безопасности: трафик, ушедший не туда, отказ в обслуживании или наблюдатель, устроившийся на пути. Клиент, который принимает такие маршруты до поднятия туннеля, может получить предпочтительный путь, не имеющий никакого отношения к вашему провайдеру.

Ничто из этого не делает внедрение маршрутов универсальным. Клиент должен принять опцию, префикс должен покрывать интересующий вас трафик, выбранный следующий переход должен быть достижим, а политика применения должна пропускать пакет этим путём. Уберите любое из условий — и тот же ответ безвреден. Вот почему две машины в одной сети могут вести себя по-разному: они запускают не один и тот же клиент, не одну и ту же политику и даже не одно и то же семейство адресов.

IPv6 заслуживает отдельного прохода, потому что объявления маршрутизатора несут маршрут по умолчанию через другой код, нежели опция DHCPv4. Тест, который проверяет только таблицу v4, этого не охватывает.

Проверьте путь, который ядро действительно выбирает

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

ip route get 203.0.113.10
ip route show table all | grep -E '^(default|203\.0\.113)'
ip rule show
resolvectl query example.com

Смотрите в выводе на две вещи: интерфейс, названный в маршруте, и выбранный адрес источника. Маршрут туннеля называет туннельное устройство, утёкший маршрут называет физическое, и разница видна без всякой расшифровки. Если ответ меняется между запусками, сохраните оба вывода и сравните правила, которые их породили.

Не останавливайтесь на маршруте по умолчанию. Исключение для приложения, префикс раздельного туннеля или второе правило политики могут провести конкретное назначение в обход туннеля, пока маршрут по умолчанию по-прежнему указывает внутрь.

Решите, где должно жить принуждение

Три условия решают, достаточно ли принуждения на стороне клиента или нужно что-то вне его. Если клиент устанавливает и защищает маршруты для каждого используемого вами семейства адресов, туннеля, владеющего маршрутом по умолчанию, обычно достаточно. Если машине нужен доступ к локальным ресурсам, пока всё остальное остаётся в туннеле, эти исключения нужно перечислить и взять на себя, а не оставлять на усмотрение того, что объявила сеть доступа. А если платформа умеет привязывать трафик к интерфейсу для каждого приложения, такая привязка — более сильная гарантия, чем маршрут, который может переопределить что угодно.

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

Повторяйте команды проверки после каждого обновления клиента и каждого изменения сети и сравнивайте с последним записанным выводом. Таблица маршрутизации — это граница принуждения, поэтому относитесь к ней именно так.

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