Files
hse-2026/materials/07-naming-lookup/seminar/dns/readme.md
T
2026-10-21 23:03:28 +03:00

11 KiB
Raw Blame History

DNS: делегирование, кэширование и ошибки

В Consul мы получали адрес из реестра сервисов. Теперь рассмотрим DNS: как найти сервер, который знает нужную запись, и почему разные клиенты могут получать разные адреса одного имени.

Авторитетный сервер хранит записи обслуживаемой зоны. Резолвер получает ответы для клиента и может сохранять их в кэше. В опытах мы будем обращаться к обоим и сравнивать результаты.

Все команды выполняются из каталога seminar; подготовка стенда.

1. Прочитать DNS-ответ

В стенде подготовлена отдельная учебная иерархия:

Сервер Роль
root-dns Обслуживает учебный корень . и делегирует зону test.
tld-dns Обслуживает зону верхнего уровня (TLD) test. и делегирует lab.test.
auth Хранит записи зоны lab.test.
resolver Получает записи учебной зоны у auth и кэширует их

Делегировать зону — значит указать серверы, отвечающие за неё. Учебная иерархия работает внутри Docker и не меняет публичный DNS.

docker compose up -d --wait auth resolver root-dns tld-dns
docker compose run --rm -T tools dig "@resolver" orders.lab.test A
docker compose run --rm -T tools dig "@auth" www.lab.test A +norecurse

В команде dig аргумент @сервер выбирает получателя запроса, далее идут имя и тип записи. Параметр +norecurse отключает запрос рекурсивного поиска: сервер отвечает сведениями, которыми уже располагает.

В первом ответе найдите A-запись — IPv4-адрес orders.lab.test. Во втором имя www.lab.test связано с orders.lab.test записью CNAME, за которой следует A-запись целевого имени.

При чтении вывода обращайте внимание на:

  • SERVER — какой сервер ответил;
  • status — код результата;
  • ANSWER — записи, отвечающие на запрос;
  • число перед IN в строке записи — TTL — сколько секунд запись ещё можно использовать из кэша.

Адреса 192.0.2.10 и 192.0.2.20 используются как учебные значения записей. Приложений по этим адресам в стенде нет.

2. Пройти цепочку делегирований

Вопрос: если корневой сервер не хранит адрес orders.lab.test, как его ответ помогает продолжить поиск?

docker compose run --rm -T tools python3 dns/delegation.py

Скрипт выводит команды и ответы: сначала трассировку dig +trace, затем отдельные запросы к корню, TLD-серверу и авторитетному серверу.

В отдельных ответах корня и TLD-сервера секция ANSWER пуста. В секции AUTHORITY находятся NS-записи — имена серверов делегированной зоны. В ADDITIONAL даны их адреса, или glue-записи, чтобы можно было обратиться к следующему серверу. Последний ответ содержит искомую A-запись.

При +trace утилита сама выполняет итеративный поиск: переходит от одного сервера к следующему по делегированиям. Обычный запрос к резолверу может целиком обслужиться из кэша. В нашем опыте resolver настроен пересылать запросы учебной зоны сразу к auth; трассировка отдельно показывает путь через корень и TLD.

Что означают флаги в ответе
  • aa — ответ авторитетен.
  • ra — сервер поддерживает рекурсивные запросы.
  • rd — клиент запросил рекурсию. Сам по себе этот флаг не означает, что сервер действительно выполнял такой поиск.

Сравнение с публичным DNS

docker compose run --rm -T tools dig wikipedia.org A
docker compose run --rm -T tools dig "@1.1.1.1" wikipedia.org A +trace +time=2 +tries=1

В конце полной трассировки должна появиться A-запись wikipedia.org. Если вывод заканчивается раньше, поиск не завершён, даже если команда вернула код 0. Публичные записи меняются, а сеть может ограничивать прямые обращения к внешним DNS-серверам. Для разбора делегирований в таком случае используйте локальную иерархию.

3. Изменить адрес и наблюдать старый TTL

Предскажите: если одновременно изменить адрес и уменьшить TTL с 60 до 5 секунд, когда изменится ответ уже заполненного кэша?

Верните исходную запись командой reset, очистите кэш командой flush и запросите адрес:

docker compose exec -T auth python3 dns/control.py reset
docker compose exec -T resolver python3 dns/control.py flush
docker compose run --rm -T tools dig "@resolver" orders.lab.test A +noall +answer

Параметры +noall +answer оставляют в выводе только записи ответа. Получим 192.0.2.10 с TTL около 60. Отсчитывая время от этого запроса, примерно через 20 секунд измените запись и сравните ответы:

docker compose exec -T auth python3 dns/control.py update --address 192.0.2.20 --ttl 5
docker compose run --rm -T tools dig "@auth" orders.lab.test A +noall +answer
docker compose run --rm -T tools dig "@resolver" orders.lab.test A +noall +answer

Авторитетный сервер уже выдаёт 192.0.2.20 с TTL 5. Резолвер продолжает возвращать 192.0.2.10 с остатком прежних 60 секунд. Уменьшение TTL на авторитетном сервере не меняет срок ранее сохранённой записи. Повторный запрос к кэшу тоже не начинает отсчёт заново.

Дождитесь истечения TTL старого ответа и повторите запрос:

docker compose run --rm -T tools dig "@resolver" orders.lab.test A +noall +answer

Теперь ожидаем 192.0.2.20 с TTL не больше 5. Если при выполнении предыдущих команд прошла минута и старый адрес уже исчез, повторите опыт с reset и flush. Для более длинного опыта можно задать reset --ttl 120.

Здесь кэш настроен без предварительного обновления и выдачи просроченных записей. После истечения TTL следующий запрос клиента заставляет резолвер получить запись заново.

Вопросы для самопроверки: когда уменьшать TTL перед переездом сервиса? Почему старый адрес нужно поддерживать некоторое время? Где ещё, кроме резолвера, могут кэшироваться адреса?

Восстановите исходную запись и очистите кэш:

docker compose exec -T auth python3 dns/control.py reset
docker compose exec -T resolver python3 dns/control.py flush

4. Различить отсутствие записи и ошибку поиска

Отсутствие адреса в ответе может означать разные вещи. Сравните четыре результата:

docker compose run --rm -T tools python3 dns/errors.py
Запрос / условие Результат Что можно заключить
missing.lab.test A NXDOMAIN Запрошенного имени нет
orders.lab.test AAAA NOERROR, пустая секция ANSWER Имя существует, но IPv6-адреса для него нет
name.broken.test A через резолвер SERVFAIL Резолвер не смог получить пригодный ответ
На запрос никто не отвечает Тайм-аут Ответ не получен за отведённое время

NODATA — название ситуации, когда имя существует, но записи нужного типа нет; отдельного кода DNS с таким именем нет. В нашем примере запрос AAAA возвращает именно такой результат.

SERVFAIL в опыте возникает из-за пересылки запроса серверу, который не обслуживает нужную зону. Ни SERVFAIL, ни тайм-аут не доказывают отсутствия имени.

Вопрос: почему недавно созданное имя может некоторое время оставаться недоступным клиентам, которые запрашивали его до создания? Учтите, что ответы об отсутствии имени тоже могут кэшироваться.

Исходники: настройка серверов, изменение записи и сброс кэша, делегирование, ошибки. Справочник: BIND 9.