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 — ежедневные материалы о бизнес-процессах, операционном управлении и повышении эффективности
💬 Подписаться на канал→ Оригинальная статья