Рукопожатие WireGuard проходит, но интернета нет: проследите путь пакета
Рукопожатие доказывает только ключи и достижимость. Проследите один пакет от AllowedIPs через пересылку, NAT и обратный маршрут, чтобы увидеть, где он останавливается.
Туннель поднят, wg show сообщает о недавнем рукопожатии, пинг до туннельного адреса сервера проходит, а дальше ничего не отвечает. Первый порыв — перегенерировать ключи или заново поделиться конфигурацией. Это меняет именно ту часть пути, которая уже доказанно работает.
Завершённое рукопожатие говорит, что стороны согласовали ключи, что UDP доходит до конечной точки и что криптографическая маршрутизация принимает пакет. Оно ничего не говорит о том, может ли пакет после этого покинуть сервер.
Поэтому проследите один пакет вместо догадок. Есть четыре места, где он может погибнуть, и каждое оставляет свой след.
Что на самом деле доказывает рукопожатие
WireGuard — это протокол UDP, который устанавливает сеанс рукопожатием Noise, а затем шифрует пакеты для собеседника. Если wg show показывает рукопожатие давностью в несколько секунд и растущий счётчик передачи, то конечная точка, ключи и открытый ключ собеседника все верны.
Чего оно не доказывает: что клиент вообще отправляет интернет-трафик в интерфейс, что сервер готов его пересылать и что ответ найдёт обратный путь. Это решения маршрутизации ядра и межсетевого экрана, и принимаются они вне туннеля.
Именно поэтому пинг до туннельного адреса сервера — такой обманчивый тест. Этот пакет адресован самому серверу, поэтому он завершается локально. Ему никогда не нужна пересылка, никогда не нужен перевод и никогда не нужен обратный маршрут из интернета.
AllowedIPs — это решение о маршрутизации
На клиенте AllowedIPs выполняет две задачи. Это таблица криптоключевой маршрутизации, которая решает, какие адреса назначения уходят в туннель этого собеседника, и это список адресов источника, которые собеседник примет от вас. Если в конфигурации клиента указан только 10.8.0.0/24, публичные назначения никогда не попадают в интерфейс, и ваш обычный маршрут по умолчанию уводит их мимо туннеля. Тогда туннель работает идеально и не делает ничего из того, что вы хотели.
Смотрите на то, что клиент действительно установил, а не на то, что написано в файле конфигурации:
wg show wg0 allowed-ipsip route get 1.1.1.1
Вторая команда — решающая. Если в ответе названы ваш физический интерфейс и обычный шлюз, пакет не идёт через туннель, и никакое изменение на стороне сервера это не исправит. Добавьте 0.0.0.0/0 для IPv4 и ::/0 для IPv6 отдельно; правило, охватывающее всё для одного семейства, оставляет другое на прежнем пути, и это частая причина работающего туннеля IPv4 и застрявшего поиска IPv6.
Где пакет погибает на шлюзе
Если маршрут верен, а пакет всё равно никуда не идёт, он доходит до сервера и останавливается там. Четыре проверки охватывают большинство шлюзов.
Пересылка. sysctl net.ipv4.ip_forward с ответом 0 — классический случай, и многие дистрибутивы до сих пор по умолчанию стоят на 0. Должно быть 1, и задавать это нужно постоянно в файле sysctl, а не командой, которая исчезает при перезагрузке. Пересылка IPv6 — отдельный переключатель.
Политика фильтрации. Цепочка FORWARD с политикой по умолчанию на сброс будет выбрасывать туннельный трафик, но пропускать трафик к самому хосту, и это точно совпадает с симптомом. Читайте живой набор правил, а не сохранённый файл: nft list ruleset или iptables -S.
Трансляция или маршрутизация. Клиентам с частными туннельными адресами нужен либо NAT источника на выходном интерфейсе сервера, либо маршрутизируемый префикс, который вышестоящая сеть умеет возвращать. Выбор между ними следует плану адресов. Добавить MASQUERADE в сеть, которая уже маршрутизирует ваш префикс назад, безвредно, но бессмысленно, а пропуск там, где маршрута нет, оставляет ответы с адресом в недостижимом частном диапазоне.
Обратный путь. В маршрутизируемых схемах вышестоящему маршрутизатору нужен маршрут, указывающий на ваш сервер. Сеть провайдера тоже может это блокировать: несколько облаков включают проверку источника и назначения на инстансе, которая молча отбрасывает пакеты, чей источник не является собственным адресом инстанса, пока эта проверка не отключена.
DNS отказывает иначе, чем маршрутизация
Пакет на известный адрес и поиск имени — две разные неисправности, и сообщения об ошибках вводят в заблуждение в противоположных направлениях. Если ping 1.1.1.1 работает, а браузер ничего не загружает, маршрут в порядке, а разрешение имён — нет. Если сам пинг не проходит, DNS ни при чём, и вы вернулись к предыдущему разделу.
wg-quick может задать резолвер из строки DNS = в конфигурации, а у systemd-resolved своё поведение для каждого соединения. VPN, который перезаписывает резолвер адресом, доступным только внутри туннеля, провалит каждый запрос в момент падения туннеля, и это выглядит так, будто туннель ломает интернет.
| Symptom | Layer to inspect |
|---|---|
| Tunnel address pings, nothing else does | Client route, then gateway forwarding |
| Public IP pings, hostnames fail | Resolver selection and reachability |
| Handshake completes, no reply ever | FORWARD policy or missing NAT on the server |
| Small requests work, large transfers stall | MTU and TCP MSS clamping |
Порядок, который даёт доказательства
Сначала выполните проверку на стороне клиента, потому что это одна команда и она исключает половину возможностей. Затем подтвердите, предназначен ли сервер вообще быть выходом в интернет; шлюз, построенный для частного доступа, не сломан, когда публичные назначения недоступны.
На сервере следите за интерфейсом, пока отправляете пинг с клиента: tcpdump -ni wg0 icmp должен показать запрос, а tcpdump -ni eth0 icmp — что он уходит, переведённый или нет. Если он появляется на первом и никогда на втором, остановка локальна на сервере. Если он уходит, а ответ не возвращается, проблема выше, и это другой разговор.
В конце сделайте так, чтобы исправление пережило перезагрузку. Пересылка относится к файлу sysctl, правила межсетевого экрана — к службе, которая их загружает, а маршруты клиента — к конфигурации, поднимающей интерфейс, а не к оболочке, которую вы забудете. Переподключитесь, повторите те же два теста и убедитесь, что счётчики двигаются.