Перейти к содержанию

Разрешение DNS и диагностика

«Это всегда DNS» — шутка, которая смешна потому, что обычно это правда. Эта статья о том, как хост Linux на самом деле разрешает имя в адрес, и какими инструментами найти, где этот процесс сломался.

Как это устроено

Цепочка разрешения

Когда приложение вызывает getaddrinfo("example.com") (то, что используют под капотом все DNS-зависимые утилиты), библиотека C обращается к /etc/nsswitch.conf:

$ grep ^hosts /etc/nsswitch.conf
hosts: files dns

Это означает: сначала проверить /etc/hosts, затем обратиться к DNS. Устаревшая или неверная запись в /etc/hosts молча перекрывает настоящий DNS и на удивление часто становится причиной «но DNS же настроен правильно!». В вашей строке могут быть дополнительные элементы (в Ubuntu, например, resolve или mdns4_minimal [NOTFOUND=return]); важно лишь, что files стоит перед dns.

На большинстве современных систем реальные DNS-запросы идут через systemd-resolved, а не напрямую к серверам, настроенным вашей сетью:

$ resolvectl status
Global
       Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub

Link 2 (eth0)
    Current Scopes: DNS
         Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: 192.0.2.53
       DNS Servers: 192.0.2.53 203.0.113.53

«resolv.conf mode: stub» означает, что /etc/resolv.conf на самом деле указывает на 127.0.0.53 — локальный stub-резолвер, которым управляет systemd-resolved — а не перечисляет реальные вышестоящие DNS-серверы напрямую. Это нормально и сделано намеренно, но означает, что прямое редактирование /etc/resolv.conf часто не даёт долговременного эффекта на таких системах — файл перегенерируется. Используйте resolvectl или настройки DNS вашего сетевого менеджера вместо этого.

Прямой запрос к DNS, минуя резолвер ОС

dig example.com                    # полный, подробный вывод
dig +short example.com             # только ответ
dig example.com @8.8.8.8           # запрос конкретному серверу напрямую, минуя /etc/resolv.conf
dig -x 203.0.113.10                # обратный запрос (PTR-запись)
dig example.com MX                 # другой тип записи

dig <name> @<server> — самый полезный приём диагностики DNS: он однозначно показывает, в чём проблема — в самом ответе DNS-сервера (неверен даже при прямом запросе) или в локальном пути разрешения (работает через @8.8.8.8, но не через обычный системный резолвер).

Чтение ответа dig

$ dig +short example.com
203.0.113.10

В подробной форме (dig example.com, без +short) смотрите на ANSWER SECTION:

;; ANSWER SECTION:
example.com.        300    IN    A    203.0.113.10

300 — это TTL в секундах — сколько времени резолверам разрешено кэшировать этот ответ. Изменение DNS, которое «не применяется» какое-то время после того, как вы его сделали, очень часто — это просто кэширование, работающее ровно так, как задумано, до истечения TTL старой записи.

Различия Ubuntu/Debian и RHEL-подобных систем

Ubuntu/Debian (современные) RHEL-подобные
Локальный резолвер systemd-resolved (stub на 127.0.0.53) по умолчанию /etc/resolv.conf, управляемый NetworkManager, часто без локального stub
Просмотр конфигурации resolvectl status nmcli dev show <iface> \| grep DNS или прямая проверка /etc/resolv.conf

На системах RHEL-семейства без systemd-resolved /etc/resolv.conf обычно действительно отражает реальные вышестоящие серверы напрямую, и ручное редактирование работает — но может быть перезаписано NetworkManager при следующем сетевом событии, если не помечено иначе.

Практическое задание

  1. Сравните dig +short example.com через резолвер системы по умолчанию и dig +short example.com @8.8.8.8 — убедитесь, что они возвращают один и тот же адрес (или разберитесь, почему нет).
  2. Проверьте TTL ответа через обычный dig example.com (без +short).
  3. Намеренно добавьте неверную запись в /etc/hosts для реального домена, убедитесь, что она перекрывает DNS (getent hosts <domain> отражает запись из hosts-файла), затем уберите её.

Как проверить, что всё сделано правильно

  • Шаг 3: getent hosts <domain> должен вернуть ваш фейковый IP, пока запись в /etc/hosts существует, и реальный IP, разрешённый через DNS, сразу же после её удаления — без кэширования (/etc/hosts перечитывается при каждом запросе, в отличие от ответов DNS).

Типичные ошибки

  • Сброс не того кэша. resolvectl flush-caches чистит только кэш systemd-resolved — если у вашего приложения есть собственный DNS-кэш (у некоторых рантаймов/браузеров есть), это его не затронет.
  • Диагностика через разрешение имён в ping вместо dig. ping делает разрешение и сразу говорит, сработало ли оно, но не даёт никаких диагностических деталей (какой сервер ответил, TTL, реальный тип записи), которые даёт dig.
  • Забыть, что /etc/hosts вообще существует, и потратить время на расследование «сломанных» DNS-серверов, пока устаревшая запись в hosts-файле молча их перекрывает.

⚠ Опасные команды / предостережения

  • Неправильное изменение строки hosts: в /etc/nsswitch.conf (например, полное удаление dns) может сломать разрешение имён на всём хосте целиком — затронув менеджеры пакетов, агенты мониторинга и всё остальное, что разрешает имена, а не только ваше приложение.

Связанные статьи

Контрольные вопросы

  1. Почему прямое редактирование /etc/resolv.conf может не иметь эффекта на системе с systemd-resolved?
  2. Что позволяет узнать dig example.com @8.8.8.8, чего не даёт обычный dig example.com?
  3. Почему изменение DNS-записи может казаться «не применившимся» сразу же, даже если вы подтвердили, что у авторитетного сервера уже новое значение?
  4. В каком порядке /etc/nsswitch.conf's hosts: files dns по умолчанию опрашивает источники, и что это значит для устаревшей записи в /etc/hosts?