📱 Подписаться
IT и цифровая трансформация

DNS‑петля: как сервер смотрит сам в себя и не находит выхода

📰 Habr 👁️ 0 просмотров

Andrey_Biryukov3 часа назад

DNS‑петля: как сервер смотрит сам в себя и не находит выхода

Уровень сложностиСреднийВремя на прочтение9 минОхват и читатели4.9KБлог компании OTUSDevOps*Сетевые технологии*Системное администрирование*ТуториалПривет, Хабр! Меня зовут Андрей Бирюков. Я — независимый эксперт в области ИТ и ИБ, преподаю в учебных центрах и пишу статьи и книги. 

Проблемы с DNS могут сделать жизнь системного администратора намного «интереснее». Например, представим ситуацию: вы открываете браузер, вбиваете привычный адрес внутреннего портала — и видите бесконечную загрузку. Страница не открывается, вы пробуете другой внутренний сайт — тот же результат. При этом пинг до внешних ресурсов работает, доступ по IP напрямую тоже есть. Но доменные имена не резолвятся.

В такой ситуации вы логично идете смотреть логи DNS‑сервера. Но они чисты, процесс BIND также работает. Казалось бы, всё нормально. Но каждая попытка разрешить внешнее имя занимает десятки секунд, а иногда и вовсе заканчивается таймаутом.

И вы начинаете копать глубже…

Как forwarder указывает на самого себя

В конфигурации BIND (named.conf) есть раздел options, где можно определить список forwarders — DNS‑серверов, которым локальный сервер будет пересылать запросы для доменов, которые он не обслуживает авторитативно.

Типичная конфигурация выглядит так:

options {

    recursion yes;

    forward first;

    forwarders {

        8.8.8.8;

        8.8.4.4;

    };

};Здесь всё правильно. Сервер, не найдя ответа в своих зонах и кэше, отправляет запрос на публичные DNS Google и ждёт ответа. Если forwarders не отвечают, он (при forward first) попытается выполнить рекурсию самостоятельно, обратившись к корневым серверам.

Проблема возникает, когда в списке forwarders оказывается он сам.

Например, в таком варианте:

forwarders {

    127.0.0.1;

};Или если в файле /etc/resolv.conf, который сервер читает через forwarder, первой строчкой указан nameserver 127.0.0.1.

Что происходит дальше, напоминает классический «У попа была собака»: сервер получает запрос, не находит ответа в своих зонах, смотрит в список forwarders, видит там себя, отправляет запрос себе же. Тот же сервер получает этот запрос и снова запускает процедуру поиска. В результате петля замкнулась.

В документации CoreDNS эта проблема описывается так: «Чаще всего forwarding loop вызывается тем, что CoreDNS отправляет запросы напрямую самому себе — например, на адрес 127.0.0.1 или 127.0.0.53».

Почему это не обнаруживается сразу

Вы спросите: если сервер отправляет запрос сам себе, почему я этого не вижу? В конце концов, tcpdump должен показывать кучу трафика на loopback‑интерфейсе.

И будете правы, но только частично.

Дело в том, что современные версии BIND и других DNS‑серверов содержат элементарную защиту от таких петель. Ещё в BIND 8 была реализована логика, при которой сервер не использует forwarder с тем же адресом, с которого пришёл исходный запрос. Это означает, что прямой цикл «я → я» часто блокируется.

Но защита не распространяется на два других сценария.

• Сценарий первый: петля из двух серверов. Сервер А указывает forwarder'ом на сервер Б. Сервер Б указывает forwarder'ом на сервер А. Теперь запрос от клиента путешествует туда‑обратно, пока не истечёт TTL или не случится таймаут.
• Сценарий второй, более коварный: петля с подменой исходного адреса. Если DNS‑сервер сконфигурирован так, что отправляет запросы с одного IP‑адреса, а принимает на другом (например, из‑за настроек query‑source или использования разных интерфейсов), механизм loop detection не срабатывает. Сервер видит, что запрос пришёл с адреса, отличного от того, на который он отправляет, и спокойно генерирует новый запрос.Именно поэтому проблема может существовать годами и проявиться только после изменения конфигурации или обновления программного обеспечения.

Сценарии, при которых петля убивает производительность

• Сценарий 1:Сам себе forwarder (явный)Вы явно указали 127.0.0.1 или IP‑адрес самого сервера в списке forwarders. Запрос на внешнее имя уходит в бесконечный цикл. Сервер шлёт запрос сам себе, тот же сервер обрабатывает его, снова не находит ответа и снова отправляет сам себе.

Этот сценарий — самый простой для диагностики. В логах BIND появятся сообщения о том, что превышено максимальное количество шагов рекурсии. А через некоторое время — жалобы на нехватку памяти, потому что каждый запрос в петле потребляет ресурсы, не освобождая их до таймаута.

• Сценарий 2: systemd‑resolved и симбиотическая петляЭтот сценарий особенно популярен в дистрибутивах Linux, использующих systemd‑resolved, например, в Ubuntu и некоторых версиях CoreOS.

Схема такая. На хосте запущен systemd‑resolved, который слушает на 127.0.0.53. В файле /etc/resolv.conf прописан nameserver 127.0.0.53. В контейнере или поде с CoreDNS настроен forwarder, который читает системный /etc/resolv.conf.

Теперь посмотрим, что происходит. CoreDNS получает запрос, смотрит в /etc/resolv.conf, видит 127.0.0.53 и отправляет запрос на этот адрес. systemd‑resolved получает запрос и, в свою очередь, отправляет его на upstream‑сервер. Но если upstream‑сервером почему‑то оказался сам CoreDNS (например, из‑за неправильной конфигурации сетевых мостов или firewall‑правил), запрос вернётся обратно.

Или ещё проще: если CoreDNS слушает на 127.0.0.53, а система настроена так, что все DNS‑запросы с хоста идут на этот же адрес, петля обеспечена.

• Сценарий 3: tsuNAME — когда петля рождается на уровне зонЭто отдельный класс проблем, обнаруженный исследователями из SIDN Labs и TU Delft в 2021 году. Проблема, получившая название tsuNAME, возникает не из‑за ошибки в конфигурации forwarder'ов, а из‑за циклических зависимостей в самих DNS‑зонах.

Представьте зону .com, где есть запись:

• example.com NS cat.example.nlИ зону .nl, где есть запись:

• example.nl NS dog.example.comРезолвер, пытаясь разрешить example.com, отправляется к .nl‑серверам, чтобы найти cat.example.nl. Но для этого ему нужно разрешить example.nl, что отправляет его обратно к .com‑серверам. Получаем цикл.

В этом случае узел, который выступает forwarder'ом, может начать генерировать лавину запросов, потому что он получает SERVFAIL от upstream‑сервера и повторяет попытку снова и снова. Исследователи обнаружили, что в некоторых случаях это приводило к десятикратному увеличению трафика на authoritative‑серверах целых TLD‑зон.

Диагностика: как обнаружить петлю

Метод 1: tcpdump на loopback

Самый простой способ заподозрить петлю — посмотреть, что происходит на интерфейсе loopback.

$ sudo tcpdump -i lo -n port 53

В нормальной ситуации на lo вы увидите только запросы от локальных процессов к вашему DNS‑серверу. Если же вы видите, что одни и те же запросы уходят и приходят снова, причём TTL в ответах не увеличивается, это признак петли.

Как правильно организовать захват для диагностики DNS‑проблем, рекомендует инженер из списка рассылки BIND‑users: используйте -i any, чтобы видеть весь трафик на всех интерфейсах, и обязательно добавляйте -c 10000, чтобы capture не рос бесконечно.

$ sudo tcpdump -i any -n -c 10000 port 53 -w dns-debug.pcap 

Метод 2: Анализ RTT и таймаутов

Когда сервер пытается использовать forwarder, который ведёт в петлю, время ответа резко возрастает. При forward first BIND сначала пробует forwarder'ов, и только после их исчерпания (или таймаута) переходит к рекурсии.

Если таймаут настроен на стандартные 2–5 секунд, и у вас несколько forwarder'ов (часть из которых ведёт в петлю), общее время ожидания может составлять десятки секунд.

Диагностический признак: в логах или при использовании dig +trace вы видите, что запрос сначала долго висит, а потом внезапно выполняется (потому что сработал fallback на корневые серверы).

Метод 3: Проверка конфигурации на петли

Для выявления циклических зависимостей между forwarder'ами подойдёт простой скрипт, анализирующий named.conf и его include‑файлы. Ищите:

• Упоминания 127.0.0.1 или ::1 в секциях forwarders
• Упоминания IP‑адресов, принадлежащих этому же серверу (проверьте ip addr show)
• Ситуации, когда BIND одновременно является и сервером, и клиентом для одних и тех же зонДля выявления tsuNAME‑петель на уровне зон исследователи разработали инструмент CycleHunter, доступный в открытом виде.

Исправление и профилактика

Немедленное исправление

Если вы обнаружили петлю, первое и самое очевидное действие — убрать из forwarders адрес самого сервера. Замените 127.0.0.1 на реальный IP вышестоящего DNS‑сервера вашего провайдера или на публичные DNS (8.8.8.8, 1.1.1.1).

Если проблема в том, что сервер читает /etc/resolv.conf, где первым nameserver'ом указан он сам, есть два пути:

• Изменить /etc/resolv.conf, убрав локальный адрес из списка или переместив его в конец (тогда он будет использоваться только если все остальные недоступны).
• Настроить CoreDNS или BIND так, чтобы игнорировать локальные адреса при чтении resolv.conf. В CoreDNS, например, для этого предлагалось добавить опцию ignore_localhost в forward‑плагин.Если вы используете systemd‑resolved

В системах с systemd‑resolved проблема решается передачей kubelet (или другому оркестратору) альтернативного пути к resolv.conf:

--resolv-conf /run/systemd/resolve/resolv.conf

Этот файл содержит «оригинальный» /etc/resolv.conf, без локального адреса. Или, как более радикальный вариант, отключить systemd‑resolved полностью и вернуться к классическому resolv.conf.

Настройка политик forwarding

В документации Red Hat чётко описаны две политики forwarding, влияющие на поведение при ошибках:

• forward first (по умолчанию) — запрос отправляется forwarder'у. Если forwarder не отвечает (таймаут или серверная ошибка), BIND пытается выполнить рекурсию самостоятельно. Именно этот режим может маскировать проблему — сервер всё равно рано или поздно найдёт ответ, просто с большой задержкой.
• forward only — запрос отправляется только forwarder'у. Если forwarder не отвечает, возвращается ошибка клиенту. В режиме forward only петля проявится мгновенно и в явном виде.Для диагностики проблем с петлями полезно временно переключиться на forward only — тогда вы сразу увидите, что запросы не проходят, и поймёте, в чём дело.

Профилактика: что проверять регулярно

• Во‑первых, настройки forwarders. В крупной организации, где несколько DNS‑серверов, легко ошибиться и создать циклическую зависимость второго типа (А→Б, Б→А). Ведите документацию и регулярно сверяйте конфигурации.
• Во‑вторых, следите за обновлениями. Проблема tsuNAME была исправлена в публичных DNS‑серверах Google и Cisco в 2021 году, но если вы используете собственные резолверы, убедитесь, что они обновлены до версий, содержащих патчи.
• В‑третьих, используйте инструменты валидации. Для BIND это named-checkconf и named-checkzone. Для обнаружения tsuNAME — CycleHunter.
• И последнее, самое простое и часто игнорируемое правило: никогда не указывайте в качестве forwarder'а адрес, на котором этот же сервер принимает запросы. Кажется очевидным, но, судя по обсуждениям в технических форумах, именно эта ошибка остаётся одной из самых распространённых.

Итог: магия DNS требует внимания

DNS — это протокол, который работает незаметно, пока всё правильно. Но одна неправильная строчка в конфигурации способна превратить ваш сервер в машину по производству сетевых петель, где каждый запрос умножается сам на себя, пожирая CPU и терпение пользователей.

Петля из‑за forwarder'а, указывающего на самого себя, — это классика. Но есть и более тонкие варианты: петли между двумя серверами, проблемы с systemd‑resolved и tsuNAME‑петли на уровне целых TLD‑зон.

Главный вывод:не доверяйте конфигурации, которая «просто работает». Проверяйте forwarders. Используйте tcpdump для диагностики. И помните: сервер, который смотрит сам в себя, видит не ответы — он видит бесконечность.Если хотите глубже разобраться, почему инфраструктура начинает «ходить по кругу» и как такие проблемы искать до того, как они превращаются в таймауты и простои, приходите на открытые уроки OTUS по сетям и инфраструктуре.

• 1 июля в 20:00 — «Что нужно знать для настройки стабильного интернета? OSPF и протоколы динамической маршрутизации»
• 7 июля в 20:00 — «Особенности балансировки трафика ЦОД, чтобы не случилось „все упало, все пропало“»
• 20 июля в 20:00 — «Проектирование адресного пространства. Основы сетей ЦОД»Разберём, как строятся маршруты, распределяется трафик и проектируется адресное пространство — то есть те самые базовые вещи, из‑за которых одна ошибка в конфигурации может неожиданно повлиять на всю сеть.

А если хотите продолжить разбор инфраструктурных тем, посмотрите наш дайджест с материалами про сети, администрирование, DevOps и отказоустойчивость.Теги:• DNS
• BIND
• CoreDNS
• forwarders
• DNS-петля
• systemd-resolved
• tcpdump
• сетевая диагностика
• маршрутизация
• таймаутыХабы:• Блог компании OTUS
• DevOps
• Сетевые технологии
• Системное администрирование

Получайте больше инсайтов о систематизации бизнеса

Подписывайтесь на Telegram-канал Business Operations — ежедневные материалы о бизнес-процессах, операционном управлении и повышении эффективности

💬 Подписаться на канал