Чи повинен трафік IPv6 іти через VPN чи напряму?
Вирішіть, чи належить ::/0 до внутрішньої частини тунелю, за трьома умовами: підтримка виходу, доступність кінцевої точки й лише локальні мережі.
Минулого місяця двоє людей попросили в мене протилежних результатів: один хотів, щоб IPv6 покривався VPN, інший хотів, щоб офісний принтер продовжував працювати. Один маршрут ::/0 не може забезпечити обидва самотужки. Чи належить цей маршрут до внутрішньої частини тунелю, залежить від трьох умов, і перша виключає його для більшості комерційних виходів. Якщо вихід не несе IPv6, спрямування туди маршруту за замовчуванням ховає ваш трафік у тунелі, якому нікуди його надіслати.
Відповідь визначають три умови
Маршрут за замовчуванням — це один рядок, ::/0, і він відповідає будь-якому призначенню IPv6 без конкретнішого маршруту (RFC 4291). Встановити його легко. Рішення, чи варто це робити, зводиться до трьох умов.
Перша умова: вихід, до якого ви підключаєтеся, має робочий IPv6 і готовий його пересилати. Друга умова: ваш клієнт може зберігати шлях до кінцевої точки тунелю, яка зазвичай лежить у діапазоні, який ви збираєтеся маршрутизувати. Третя умова: ви можете назвати локальні призначення IPv6, які мусять залишитися поза тунелем.
Кожна умова зазнає невдачі по-своєму, тому вгадування коштує цілого вечора. Невдала перша умова дає вам тишу й таблицю маршрутизації, що виглядає правильно. Невдала друга умова вбиває рукостискання за кілька секунд після початку. Невдала третя умова залишає робочий тунель і незадоволеного колегу біля принтера.
| What you see | Decision |
|---|---|
| Exit answers IPv6 probes, no local IPv6 devices to protect | Route ::/0 into the tunnel |
| Exit answers IPv6 probes, printer or NAS reachable by a global address | Route ::/0, then give those prefixes a route of their own |
| Exit is IPv4-only inside the tunnel | Do not route ::/0; block IPv6 on the client |
Endpoint is reached over IPv6 and sits inside ::/0 | Install a host route for the endpoint first |
Чи справді вихід несе IPv6?
Інтерфейс тунелю з адресою IPv6 нічого не доводить про інший бік. Багато комерційних профілів усередині лише IPv4: сервер дає вам адресу v4 і відкидає все інше. Встановіть зверху маршрут за замовчуванням з AllowedIPs, і ядро охоче надішле IPv6 в інтерфейс, чий партнер ніколи його не бачить.
Перевірте з клієнта, поки тунель піднятий. ping -6 -c 3 2001:4860:4860::8888 і ip -6 route get 2001:4860:4860::8888 відповідають на різні питання: чи повертається відповідь і який пристрій вибрало ядро. Коли друге називає ваш тунель, а перше нічого не повертає, проблема у виході, а не в маршруті.
Якщо ви самі керуєте виходом, тест клієнта може пройти, а шлях усе одно впреться в глухий кут. Підтвердьте, що на шлюзі ввімкнено net.ipv6.conf.all.forwarding=1 і що його брандмауер приймає пакети, переслані з тунелю. Правильно маршрутизований пакет у вихід, який відмовляється пересилати, з боку клієнта виглядає точно як помилка маршрутизації.
Чи може клієнт зберегти шлях до кінцевої точки?
Це той випадок, що зловив мене на ноутбуці з кінцевою точкою WireGuard лише на IPv6. Адреса кінцевої точки — звичайна глобальна адреса, тож вона потрапляє всередину ::/0. Маршрутизуйте весь префікс в інтерфейс, і пакети рукостискання гнатимуть самі себе в тунель, який вони ще намагаються збудувати. Тунель так і не піднімається, і ніщо у виводі клієнта не каже чому.
wg-quick справляється з цим у Linux. Він виводить маршрути з AllowedIPs, встановлює їх у власну таблицю й додає правило політики, щоб трафік до кінцевої точки спершу розв'язувався через основну таблицю: правило suppress_prefixlength 0, яке ви знайдете в ip -6 rule. Тому wg-quick up вдається там, де написаний вручну ip -6 route add default dev wg0 відрізає вас.
Перевірте обидва стани за допомогою ip -6 route get <endpoint-v6>, до і після підняття тунелю. Якщо відповідь змінюється на ваш тунельний пристрій, ви видалили шлях, потрібний тунелю. Коли ви пишете маршрути самі, додайте маршрут до хоста через початковий шлюз або підключіться до кінцевої точки через IPv4 і залиште IPv6 корисному навантаженню.
Що має залишитися поза тунелем?
Конкретніші маршрути перемагають маршрут за замовчуванням, тож префікс на каналі або діапазон ULA з власним маршрутом продовжує працювати без додаткових зусиль. Це тиха причина, чому так багато повнотунельних налаштувань IPv4 виживає: префікси LAN конкретніші за маршрут за замовчуванням і ніколи не потрапляють у тунель.
Це ламається, коли локальний пристрій доступний через глобальну адресу, що нормально для принтера, якому той самий маршрутизатор видав публічний префікс, для NAS або телевізора. Ці адреси відповідають ::/0 і нічому більше, тож вони переїжджають у тунель разом з усім іншим і зникають.
Вирішуйте за призначенням, а не за протоколом. Якщо важливі два-три локальні хости, дайте їхнім префіксам маршрут назовні через фізичний інтерфейс або приберіть їх із узгодженого набору. Якщо список продовжує зростати, чесна відповідь — розділений тунель для IPv6 з письмовим списком винятків, а не маршрут за замовчуванням, який ви постійно латаєте.
Якщо відповідь ні, заблокуйте це
Залишити IPv6 без маршруту — не те саме, що залишити його в спокої. Хост із робочим маршрутом за замовчуванням для IPv6 продовжує ним користуватися, поки тунель несе IPv4, тож трафік виходить поряд із VPN, і кожна служба, що віддає перевагу IPv6, бачить вашу справжню адресу. Це витік, а не розділений тунель.
Виберіть одне і запишіть, що саме вибрали. Спрямуйте маршрут за замовчуванням і прийміть компроміси вище або вимкніть IPv6 на час роботи тунелю. Пропустити префікс із AllowedIPs саме по собі недостатньо, бо операційна система тримає власний маршрут за замовчуванням. У Linux грубий варіант — sysctl -w net.ipv6.conf.all.disable_ipv6=1; тонший скидає IPv6 поза тунелем правилом брандмауера. Телефонні клієнти мають явний перемикач блокування IPv6, який робить те саме.
Перевірте це як витік
Підніміть тунель і прочитайте стан замість того, щоб довіряти перемикачу. ip -6 route show default має показати один маршрут за замовчуванням, а ip -6 route get для призначення поза вашою LAN має назвати тунельний пристрій. Повторіть обидва після від'єднання: маршрут за замовчуванням, що переживає тунель, — це помилка, яку ви шукали.
Потім перевірте зворотний напрямок. З хоста в локальній мережі дістаньтеся клієнта за його локальною адресою IPv6. Якщо це перестає працювати, третя умова ніколи не виконувалася, хоч би що тоді стверджувала таблиця маршрутизації.
Запишіть результат там, де його знайде наступна людина: які префікси залишаються локальними, чому і що робить клієнт після від'єднання. Два рядки в runbook позбавляють наступного інженера повторного відкриття циклу кінцевої точки опівночі.