Туннель работает, брандмауэр разрешает порт 53, AdGuard Home запущен, но имена всё ещё не разрешаются для клиента WireGuard. Запрос обычно приходит, а ответ обычно уходит, поэтому счётчики пакетов на резолвере выглядят нормально, и служба кажется невиновной. Проблема в исходном адресе этого ответа: он уходит с локального адреса, который клиент никогда не запрашивал, и встроенный резолвер клиента игнорирует его. Один список в настройках AdGuard Home определяет это, и его обычная настройка по умолчанию передаёт решение ядру.

Запрос приходит, ответ уходит откуда-то ещё

Клиент, настроенный с 10.6.0.1 в качестве своего резольвера, отправляет UDP-запрос на 10.6.0.1 порт 53. Этот пакет проходит через туннель и попадает на хост, и AdGuard Home на него отвечает. На линии передачи ответа, однако, это новый пакет, у которого исходный адрес выбирается стеком хоста, а не ожидаемым клиентом.

Когда резольвер клиента является подключенным сокетом, что используется systemd-resolved, dnsmasq и большинством stub-резольверов, он принимает только ответы с точного адреса, на который отправлен запрос. Ответ, исходящий с 192.168.1.10 на запрос, отправленный на 10.6.0.1, отбрасывается до того, как произойдет любое разбор. Резольвер регистрирует успешный ответ, клиент регистрирует таймаут, и оба говорят правду.

Итак, счетчики не лгут, и клиент тоже не лжет. Доказательства, которые вам нужны, находятся в трех местах, в следующем порядке: адрес, к которому привязан слушатель, маршрут, который ядро использует, чтобы вернуться к клиенту, и исходный адрес в самом ответном пакете.

Как ядро выбирает исходный адрес ответа

UDP-сокет, привязанный к0.0.0.0не имеет собственного исходного адреса, поэтому каждый исходящий ответ вызывает поиск маршрута для назначения. Ядро затем берет исходный адрес из этого маршрута: адрес, закрепленный маршрутом, или основной адрес исходящего интерфейса. Ничего о адресе назначения запроса не сохраняется.

На хосте с одной сетевой картой это незаметно, потому что возможен только один правдоподобный ответ. На машине с LAN-адресом, адресом WireGuard и адресом для управления несколько ответов могут быть правдоподобными, и победитель зависит от таблицы маршрутизации в данный момент. Добавьте дополнительный маршрут, второй адрес на том же интерфейсе, перенаправление NAT перед резолвером или запустите AdGuard в контейнере с собственным namespace, и выбранный источник может отличаться от того, на который клиент делал запрос.

ss -lunp | grep :53показывает, в какой игре вы находитесь. Слушатель на0.0.0.0:53является случаем универсального значения; слушатель на10.6.0.1:53уже закрепил ответ. Чтение сокета быстрее, чем чтение YAML, и оно отражает то, что фактически выполняется, а не то, что было сохранено последним.

Что на самом деле контролирует bind_hosts

AdGuard Homedns.bind_hosts— это список локальных адресов, которые использует DNS-слушатель. По умолчанию используется универсальный адрес (wildcard), что означает приём на любом локальном адресе и выбор ядром исходного адреса для каждого ответа. Замена универсального адреса на адрес, запрашиваемый клиентами, изменяет сокет и, соответственно, исходный адрес каждого ответа.

Список может содержать несколько записей, что важно для резольвера, обслуживающего две сети. Перечисление10.6.0.1и192.168.1.10даёт два привязанных сокета, и запрос, поступивший на любой из них, получает ответ с того адреса, на который пришёл. Это поведение, которое большинство людей полагает обеспечиваемым универсальным адресом.

YAML простой, и адрес в нём — это тот, который вашим клиентам туннеля сказали использовать, а не основной адрес хоста:

dns:
  bind_hosts:
    - 10.6.0.1
  port: 53

Почему два экземпляра одного резольвера дают разные результаты

В данном контексте управляемый плагином означает, что резолвер был установлен и контролируется другим пакетом: пакетом прошивки маршрутизатора, пакетом NAS или дополнением для домашней автоматизации. Обычно этот пакет поставляется со своей собственной копией YAML AdGuard Home и перезапускает процесс по своему собственному расписанию, тогда как автономный экземпляр — это бинарный файл производителя или контейнер, который вы настраиваете самостоятельно. В любом случае вы имеете дело с двумя независимыми процессами с отдельными конфигурационными файлами и отдельными вариантами привязки, даже если оба используют один и тот же список источников и одни и те же фильтрующие списки. Один может привязываться к конкретному адреса туннеля, а другой наследует универсальный, и веб-интерфейс выглядит одинаково с обеих сторон.

Вот почему «тот же резольвер работал до миграции» ничего не доказывает относительно текущей привязки. Проверьте сокет, затем проверьте конфигурационный файл, который фактически загружен работающим процессом. Устаревшая копия в другом каталоге — частая причина, по которой изменение кажется неэффективным.

Закрепите его, затем протестируйте со стороны туннеля

Изменитеbind_hostsна адрес туннеля, перезапустите сервис и убедитесь, что сокет переместился:ss -lunp | grep :53теперь должен показывать10.6.0.1:53и никаких универсальных записей. Если он всё ещё показывает0.0.0.0,работающий процесс не читает файл, который вы редактировали.

Затем протестируйте со стороны клиента, потому что это единственная сторона, которая имеет значение. Запрос сdig @10.6.0.1 example.comпроверяет путь, которым пользуется пользователь, а перехват на хосте сtcpdump -ni wg0 udp port 53показывает исходный адрес ответа в сети. Сравните его с адресом в настройках резольвера клиента; когда они совпадают, тайм-аут перестает быть загадкой.

ip route get 10.6.0.2объясняет любую остающуюся странность, так как выводит интерфейс и источник, которые хост использовал бы для ответа клиенту. Если в этом выводе указан LAN-интерфейс, изменение привязки не является полным решением, и следующей вещью для проверки становится таблица маршрутизации.

Что настройка привязки не может исправить

Закрепление слушателя не исправляет список доступа, в котором отсутствует подсеть туннеля, правило брандмауэра, которое разрешает запрос, но не ответ, или отсутствующий маршрут обратно к пулу WireGuard. Эти проблемы проявляются раньше или позже, чем исходный адрес, и каждая из них имеет своего владельца.

Оно также не изменяетк какому вышестоящему серверу резольвер пересылает запросыбудь то защита повторного связывания отвергает приватный ответ для приватного имени, или как клиент применяет свои собственные поисковые домены. Это отдельные элементы управления. Измените адрес привязки, когда источник ответа неверен, и измените что-то другое, когда это не так.

Похожие статьи