Аварійний вимикач блокує лише 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 можуть потребувати залишатися доступними, і ці винятки слід називати в політиці, а не виявляти під час збою. Тест на витік, який провалюється тому, що тунель не може піднятися знову, — це не знахідка в безпеці, а знахідка в зв’язності.