Когда программа хочет открыть соединение с хостом по имени, ей сначала нужно превратить это имя в IP-адрес. Этот процесс называется разрешением имён, и происходит он целиком на клиенте - ещё до того, как улетит первый пакет к серверу. Администратор должен понимать, кто и в каком порядке отвечает на вопрос "какой адрес у этого имени", уметь подсунуть локальную запись, переключить DNS-сервер и быстро отличить проблему резолвинга от проблемы сети. В этом уроке разбираем resolv.conf, systemd-resolved с утилитой resolvectl, nsswitch.conf, файл hosts и инструменты диагностики host, dig, getent, nslookup.

Как это работает
Ключевой момент: приложение почти никогда не ходит в DNS напрямую. Оно дёргает функцию libc getaddrinfo, а та смотрит в /etc/nsswitch.conf - файл, который описывает, из каких источников и в каком порядке брать данные для разных баз (hosts, passwd, group и других). Для имён хостов важна строка hosts. Типичное значение - files dns или files resolve dns: сперва проверяется локальный файл, потом сетевой резолвер. Порядок здесь решает всё: если files стоит первым, запись в /etc/hosts всегда победит реальный DNS.
Сам DNS-запрос отправляет резолвер. Классический путь - стаб-резолвер внутри glibc читает /etc/resolv.conf, где перечислены строки nameserver (адреса DNS-серверов), search (домены для дописывания коротких имён) и options (тонкая настройка, например timeout или ndots). Это простой механизм без кэша: каждый запрос уходит на сервер заново.
В современных дистрибутивах между приложением и сетью обычно стоит systemd-resolved. Он поднимает локальный кэширующий стаб-резолвер на адресе 127.0.0.53 (а в новых версиях ещё и 127.0.0.54 для обхода кэша). Тогда /etc/resolv.conf - это симлинк на файл, сгенерированный resolved, и в нём один nameserver 127.0.0.53. Запросы идут в resolved, тот кэширует ответы, уважает TTL, умеет работать с несколькими аплинками, разделять запросы по доменам (split-DNS на интерфейсах от NetworkManager или systemd-networkd) и при настройке - шифровать трафик через DNS-over-TLS. Управляют этим через resolvectl.
Ubuntu 24.04 и Fedora 41+ по умолчанию используют systemd-resolved. В Debian 13 он есть, но не всегда активен из коробки - там часто хватает обычного resolv.conf, который пишет NetworkManager или dhclient. RHEL 10 тоже опирается на NetworkManager, а resolved подключают по желанию. Поэтому первым делом всегда смотрите, чем является resolv.conf - реальным файлом или симлинком.
Команды и примеры
Проверяем, кто рулит резолвингом:
Код: Выделить всё
ls -l /etc/resolv.conf
# симлинк на ../run/systemd/resolve/stub-resolv.conf -> работает resolved
cat /etc/resolv.conf
cat /etc/nsswitch.conf | grep hosts
Код: Выделить всё
resolvectl status # серверы, домены, режим DNSSEC по интерфейсам
resolvectl statistics # размер кэша, попадания/промахи
resolvectl query forum.example.com
resolvectl flush-caches # сбросить кэш резолвера
Код: Выделить всё
192.168.10.5 git.local git
Код: Выделить всё
getent hosts forum.example.com
getent ahosts forum.example.com # и IPv4, и IPv6
Код: Выделить всё
host -v forum.example.com
dig forum.example.com A +short
dig @9.9.9.9 forum.example.com # спросить конкретный сервер
dig +trace forum.example.com # пройти делегирование от корня
dig -x 93.184.216.34 # обратный запрос PTR
Код: Выделить всё
# Debian/Ubuntu
apt install dnsutils bind9-host
# RHEL/Fedora
dnf install bind-utils
Частые грабли
- Правите /etc/resolv.conf руками, а через минуту его перезаписывает resolved, NetworkManager или dhclient. Если это симлинк - менять надо источник, а не сам файл.
- dig и host НЕ читают /etc/hosts и не проходят nsswitch. Запись в hosts работает, а dig её "не видит" - это нормально, проверяйте через getent hosts.
- Слишком большой ndots (по умолчанию 1) заставляет резолвер сперва приписывать домены из search ко всем именам с точками - лишние запросы и задержки, классическая боль в Kubernetes.
- Записали в /etc/hosts строку, а имена идут после адреса - если перепутать порядок, парсинг ломается. Адрес всегда первый.
- Локальный 127.0.0.53 в resolv.conf пугает новичков ("почему не 8.8.8.8?") - это стаб resolved, реальные серверы смотрите через resolvectl status.
- Кэш отдаёт старый адрес после смены DNS-записи. Ждите истечения TTL или делайте resolvectl flush-caches.
- nsswitch с порядком dns files прячет ваши локальные правки hosts за публичным DNS - проверяйте порядок источников.
- Выполните ls -l /etc/resolv.conf и определите, управляет ли резолвингом systemd-resolved или это обычный файл.
- Запустите resolvectl status и выпишите, какие DNS-серверы используются на вашем активном интерфейсе.
- Добавьте в /etc/hosts строку 203.0.113.77 lab.test и проверьте её через getent hosts lab.test, затем через dig lab.test - сравните результат и объясните разницу.
- Сделайте dig forum.example.com и dig forum.example.com второй раз подряд; через resolvectl statistics посмотрите, вырос ли счётчик попаданий в кэш.
- Выполните dig +trace example.com и проследите цепочку от корневых серверов до авторитативного.
- Сбросьте кэш через resolvectl flush-caches и убедитесь, что следующий запрос снова промахивается мимо кэша.
- Какой файл определяет порядок источников для разрешения имён хостов и какая строка в нём за это отвечает?
- Почему запись в /etc/hosts видна через getent hosts, но не через dig?
- На каком адресе слушает стаб-резолвер systemd-resolved и как через него узнать реальные вышестоящие DNS-серверы?
- Что делает параметр options ndots в /etc/resolv.conf и чем опасно большое значение?
- Какой командой сбросить кэш systemd-resolved и как проверить статистику попаданий в кэш?
- Чем dig принципиально отличается от getent hosts при диагностике резолвинга?