Аварийный выключатель блокирует только IPv4: почему IPv6 всё равно утекает
Набор правил межсетевого экрана для IPv4 ничего не говорит об IPv6. На устройстве с двойным стеком туннель может упасть, пока приложение сохраняет рабочий путь в обход.
Туннель падает, аварийный выключатель сообщает, что сработал, а загрузка продолжается. В правилах IPv4 ничего не сломано. Приложение просто перешло на путь, для которого эти правила никогда не писались.
Устройства с двойным стеком имеют два независимых выхода. Блокировка одного из них — половина блокировки.
Два набора правил, две политики по умолчанию
В Linux iptables и ip6tables — отдельные таблицы с отдельными политиками. Установка цепочек INPUT и OUTPUT таблицы IPv4 в DROP ничего не меняет в таблице IPv6, где политика по умолчанию обычно ACCEPT. Такое же разделение есть в nftables, где можно проверить одно семейство и обнаружить, что ваши правила несёт только одно из них. Эта асимметрия нормальна, и в ней вся проблема.
Вот почему аварийный выключатель может выглядеть основательно, а действовать частично. Скрипт, написавший правила IPv4, выполнился, счётчики растут, строка журнала появляется, а пакет IPv6 уходит через физический интерфейс совершенно нетронутым.
Читайте, что ваш клиент устанавливает на самом деле, а не что обещает маркетинговая страница. Одни клиенты направляют IPv6 в туннель, другие намеренно его блокируют, а третьи оставляют как есть, пока блокировка на уровне платформы применяет другое правило. Документация производителя — единственный источник, которому здесь стоит доверять.
Что вам говорит конфигурация интерфейса
Страница руководства wg-quick включает правила IPv6 в пример конфигурации, и причина — ровно этот пробел. Пример не украшение. Он существует потому, что одни правила IPv4 оставили бы второе семейство открытым.
Копирование половины примера даёт половину политики. Это самая частая причина этой утечки. Одна публикация в блоге сократила пример ради длины. Затем сокращённая версия стала шаблоном, который все использовали повторно.
# what is actually installed, per family?
sudo iptables -S OUTPUT | head -20
sudo ip6tables -S OUTPUT | head -20
# nftables: inspect each family separately
sudo nft list ruleset inet | head -40
# does this host even have a usable IPv6 path?
ip -6 route show default
Если вторая команда выводит разрешающую политику, а первая выводит DROP, вы нашли ответ, не трогая клиент. Эта асимметрия и есть ошибка.
Почему одного запроса недостаточно
Одно имя может вернуть и запись A, и запись AAAA, а приложения выбирают не все одинаково. Браузер может предпочесть IPv6, когда сеть его предлагает, и откатиться при сбое, тогда как фоновая синхронизация или программа обновления использует собственный резолвер и собственные предпочтения. Поэтому один успешный тест через IPv4 доказывает один путь, а не политику.
Переходы между сетями тоже меняют ответ. Подключение к другой сети Wi-Fi, пробуждение из сна или переключение на мобильную сеть может выдать устройству новый префикс IPv6, и политика, выглядевшая достаточной в офисной LAN, может его не покрывать.
Проверьте состояние, когда туннель выключен
Тестирование при подключении говорит, что туннель работает. Интересен тест в состоянии недоступности, потому что именно тогда аварийный выключатель должен держать. Остановите туннель намеренно, затем попробуйте важные адреса из приложения, которое вы защищаете.
# with the tunnel stopped, does anything still leave?
ip -6 route get 2606:4700:4700::1111
curl -6 -sS -o /dev/null -w '%{http_code}\n' --max-time 5 https://ipv6.example.net/
curl -4 -sS -o /dev/null -w '%{http_code}\n' --max-time 5 https://ipv4.example.net/
Оба семейства должны отказывать закрыто. Если запрос IPv4 завершается тайм-аутом, а запрос IPv6 возвращает код состояния, политика неполна, и никакое повторное тестирование туннеля это не изменит.
Сохраните в этом тесте и задокументированные исключения. Обнаружение локальной сети, продление DHCP или загрузочный путь к конечной точке VPN могут требовать оставаться доступными, и эти исключения следует называть в политике, а не обнаруживать во время сбоя. Тест на утечку, который проваливается потому, что туннель не может подняться снова, — это не находка в области безопасности, а находка в области связности.