Полный туннель WireGuard: AllowedIPs 0.0.0.0/0 недостаточно
0.0.0.0/0 и ::/0 лишь выбирают, что несёт пир. Менеджер клиента, пересылка на шлюзе, DNS и политика отказа всё ещё требуют настройки.
Записать 0.0.0.0/0, ::/0 в AllowedIPs пира — это шаг, который помнят все, и он решает только то, какой трафик пиру разрешено нести. Эти префиксы не создают маршрутов, ничего не пересылают на другой стороне и оставляют резолвер каждого приложения ровно там, где он был. Четыре отдельные вещи должны выполняться одновременно, чтобы полный туннель был действительно полным, и проверять их лучше в порядке ниже, потому что более поздняя проверка не может спасти более раннюю. Каждая проверка ниже — это факт, который можно прочитать с машины, а не настройка, на применение которой вы надеетесь.
Что выбирает префикс пира, а что нет
AllowedIPs одновременно является селектором и разрешением. Он сообщает локальной стороне, какие назначения можно отправлять этому пиру, и сообщает принимающей стороне, какие адреса источника этот пир может представлять. Это вся работа. Ничто в этом описании не создаёт маршрут на хосте, не включает пересылку на удалённой стороне и не касается разрешения имён.
Поэтому конфигурация может выглядеть полной и вести себя как раздельный туннель. Префикс говорит, что пир примет всё; таблица маршрутов хоста решает, что туда действительно попадает, а шлюз решает, выходит ли что-то. Ни одно из этих трёх решений не живёт в секции пира.
Маршрутизировать клиента, а не только список пиров
Менеджеры вроде wg-quick программируют таблицу маршрутов хоста за вас, поэтому два одинаковых файла конфигурации ведут себя по-разному в зависимости от того, как поднялся интерфейс. Минимальный профиль достаточно короток, чтобы прочитать его за один раз:
[Interface]
Address = 10.8.0.2/32
DNS = 10.8.0.1
[Peer]
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = vpn.example.net:51820
Работу несут две детали. Поле Address — это один префикс хоста, а не подсеть, которую клиент считает своей, и именно менеджер превращает AllowedIPs по умолчанию в настоящий маршрут по умолчанию. Поднимите тот же файл с помощью ip link и wg setconf и не появится ни одного маршрута, что выглядит как сломанный туннель, а на деле здоровый туннель с пропущенным шагом маршрутизации. Руководство wg-quick документирует маршрутизацию и Table поведение, которое добавляют эти менеджеры.
Читайте результат, а не файл: ip route get 1.1.1.1 должен назвать интерфейс туннеля, а wg show должен сообщить о недавнем рукопожатии со счётчиком передачи, который движется. Рукопожатие без маршрута означает, что менеджер не запускался, и повторное редактирование профиля это не исправит. Запускайте интерфейс так, как его запустит пользователь, иначе тест измеряет вашу оболочку вместо развёртывания.
Держать конечную точку вне туннеля
Полный туннель захватывает каждое назначение, включая то, с которым должен говорить, чтобы существовать. Менеджеры решают это, добавляя маршрут хоста для конечной точки через исходный шлюз, поэтому правильная конфигурация почти всегда содержит одно намеренное исключение. Применение половины конфигурации менеджером, а другой половины вручную — обычный способ, которым это исключение теряется.
Если конечная точка — это имя хоста, которое разрешается в несколько адресов или в семейство, которое вы не несёте, исключение плохо стареет, и туннель может отказать после переподключения, выглядевшего рутинным. Прикрепите конечную точку к адресу, который вы контролируете, или подтвердите, что менеджер переоценивает его, и после каждого изменения сети перечитывайте маршрут хоста.
Тот же механизм объясняет, почему полный туннель и перехватывающий портал воюют. Портал ожидает перехватить трафик, который ваш туннель теперь захватывает, поэтому в гостиничных и аэропортовых сетях туннель поднимают после входа в портал и никогда до него.
Пересылка и обратный путь на шлюзе
На шлюзе включите пересылку для семейства, которое несёте, разрешите цепочку forward в обоих направлениях, когда транслируете, и подтвердите обратный путь поиском, специфичным для источника. Ничто из этого не следует из успешного рукопожатия, потому что рукопожатие доказывает лишь то, что два пира могут обмениваться UDP. Оно ничего не говорит о том, что происходит потом с декапсулированным пакетом.
sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding
ip route get 1.1.1.1 from 10.8.0.2
Поиск выполняется на шлюзе, а не на клиенте, иначе вы прочитаете другую таблицу маршрутов. Если он назовёт не тот интерфейс или сообщит, что маршрута нет, то никакое изменение на стороне клиента не даст выхода в интернет. Когда шлюз транслирует адреса клиентов на выходе, ответ зависит от этого состояния трансляции, поэтому правило должно существовать для обоих направлений потока, а не только для исходящего.
DNS и состояние отказа, проверенные отдельно
Сам протокол не настраивает резолвер ни одного приложения. wg-quick применяет строку DNS через интеграцию резолвера дистрибутива, контейнеры и браузеры со своими стеками могут её игнорировать, и поэтому имя может отказать, пока туннель идеально несёт пакеты. Проверяйте по имени хоста, а не по адресу, и записывайте, какой сервер ответил, вместо того чтобы предполагать, что это сделал сервер из профиля.
Семейства адресов — это отдельная проверка с отдельным ответом. Маршрут по умолчанию для v4 ничего не говорит о том, что сделает соединение v6 какого-либо приложения, а туннель, который молча утекает второе семейство, хуже того, который громко отказывает. Спрашивайте имя через каждое семейство, читайте интерфейс, использованный каждым запросом, и проверяйте счётчики трансляции до и после, потому что правило, не совпадающее ни с чем, выглядит так же, как отсутствующее правило.
Наконец, проверьте состояние, которое хотите, когда туннель останавливается. Полный туннель должен отказывать закрыто для трафика, на который он претендует: если интерфейс падает, а приложения тихо продолжают через физический канал, то дизайн — это раздельный туннель с лишними шагами. Запишите предполагаемое поведение при отказе, проверьте его намеренно и закончите фиксацией четырёх ответов — какой менеджер поднимает интерфейс, какой маршрут несёт маршрут по умолчанию, кто пересылает и транслирует на шлюзе и какой резолвер отвечает.