Разрешение DNS и диагностика¶
«Это всегда DNS» — шутка, которая смешна потому, что обычно это правда. Эта статья о том, как хост Linux на самом деле разрешает имя в адрес, и какими инструментами найти, где этот процесс сломался.
Как это устроено¶
Цепочка разрешения¶
Когда приложение вызывает getaddrinfo("example.com") (то, что используют под капотом все DNS-зависимые утилиты), библиотека C обращается к /etc/nsswitch.conf:
Это означает: сначала проверить /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 example.com, без +short) смотрите на ANSWER SECTION:
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 при следующем сетевом событии, если не помечено иначе.
Практическое задание¶
- Сравните
dig +short example.comчерез резолвер системы по умолчанию иdig +short example.com @8.8.8.8— убедитесь, что они возвращают один и тот же адрес (или разберитесь, почему нет). - Проверьте TTL ответа через обычный
dig example.com(без+short). - Намеренно добавьте неверную запись в
/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) может сломать разрешение имён на всём хосте целиком — затронув менеджеры пакетов, агенты мониторинга и всё остальное, что разрешает имена, а не только ваше приложение.
Связанные статьи¶
Контрольные вопросы¶
- Почему прямое редактирование
/etc/resolv.confможет не иметь эффекта на системе с systemd-resolved? - Что позволяет узнать
dig example.com @8.8.8.8, чего не даёт обычныйdig example.com? - Почему изменение DNS-записи может казаться «не применившимся» сразу же, даже если вы подтвердили, что у авторитетного сервера уже новое значение?
- В каком порядке
/etc/nsswitch.conf'shosts: files dnsпо умолчанию опрашивает источники, и что это значит для устаревшей записи в/etc/hosts?