Тема 15

Система доменных имён DNS

Система доменных имён DNS

В предыдущих темах курса узлы сети обращались друг к другу по IP-адресам: маршрутизация (темы 8–10) доставляет пакет к адресу назначения, транспортные протоколы (темы 12–13) различают приложения по номерам портов, DHCP (тема 14) сообщает хосту его адрес, шлюз и адреса DNS-серверов. Человек же пользуется именами: в адресной строке браузера набирают www.nsu.ru, почту отправляют на адрес вида user@nsu.example. Между именем и адресом нужен посредник, и этим посредником в Интернете служит система доменных имён (англ. Domain Name System, DNS) — распределённая база данных, которая по имени возвращает адреса и другие сведения о нём.

DNS решает задачу, на первый взгляд простую: хранить таблицу «имя — значение». Сложность создают масштаб и требования. Имён сотни миллионов, их владельцы — независимые организации по всему миру, каждая из которых хочет менять свои записи сама и немедленно; запросов к системе — миллионы в секунду, и каждая загрузка веб-страницы начинается с одного или нескольких из них; отказ DNS означает фактическую недоступность сервиса, даже если сам сервис работает. Ответом на эти требования стали три идеи: иерархическое пространство имён, разделённое на зоны с независимым управлением; делегирование полномочий от родительской зоны к дочерней; кеширование ответов с ограниченным сроком жизни.

Изложение построено следующим образом. Сначала рассматриваются пространство имён, зоны и делегирование, затем — процесс разрешения имени от корня до конечного ответа и роль кеша. Третий раздел посвящён формату сообщения и типам записей, четвёртый — транспорту: UDP, TCP, расширение EDNS(0) и шифрование. Пятый раздел рассматривает атаки на DNS и средства защиты, включая DNSSEC, шестой — использование DNS для распределения нагрузки и порядок регистрации доменов. Протокол HTTP, который обычно следует за DNS-запросом, рассматривается в теме 16, а криптографические основы — в теме 17.

Пространство имён, зоны и делегирование

От файла HOSTS.TXT к распределённой базе данных

В сети ARPANET 1970-х годов соответствие имён узлов и адресов хранилось в одном текстовом файле HOSTS.TXT, который вёл сетевой информационный центр SRI-NIC. Администраторы присылали в центр изменения, а узлы периодически скачивали файл целиком. Пока узлов было несколько сотен, схема работала; к началу 1980-х годов она перестала справляться по трём причинам. Во-первых, объём файла и нагрузка на единственный сервер, с которого его скачивали, росли пропорционально квадрату числа узлов: каждый из N узлов скачивал файл из N записей. Во-вторых, изменения вносились вручную и с задержкой в дни, а сеть уже переходила к модели, в которой каждая организация сама управляет своими компьютерами. В-третьих, плоское пространство имён требовало глобальной уникальности каждого имени, и конфликты имён приходилось разрешать централизованно.

Пол Мокапетрис предложил в 1983 году систему доменных имён, а в 1987 году её спецификация была переиздана в виде RFC 1034 и RFC 1035, которые остаются основой стандарта до сих пор 12. Первый документ описывает понятия и устройство системы, второй — реализацию: формат сообщений, формат файла зоны, правила для серверов. Многие неоднозначности исходного текста позже устранены в RFC 2181 3. Требования, сформулированные в RFC 1034, сохраняют силу: согласованное пространство имён, не зависящее от сетевых адресов и маршрутизации; распределённое управление, при котором каждая организация ведёт свою часть данных сама; локальное кеширование, позволяющее не обращаться к источнику при каждом запросе; независимость от транспорта и от типа хранимых данных 1.

Наследие HOSTS.TXT сохранилось в файле /etc/hosts, который есть в каждой Unix-подобной системе и обычно проверяется раньше, чем выполняется DNS-запрос; об этом — в разделе о разрешении имён в операционной системе.

Дерево имён: метки, домены, полностью определённые имена

Пространство имён DNS — дерево. Каждый узел дерева имеет метку (англ. label) — строку длиной от 1 до 63 байт; у корня метка пустая. Доменное имя узла — последовательность меток на пути от этого узла к корню, записываемая через точку: www.nsu.example. — это узел с меткой www, родитель которого nsu, родитель того — example, а последний, пустой элемент после завершающей точки обозначает корень. Длина имени в двоичном представлении ограничена 255 байтами 2. Сравнение меток не зависит от регистра букв ASCII: WWW.NSU.Example и www.nsu.example — одно имя 1.

Имя, доведённое до корня и оканчивающееся точкой, называется полностью определённым (англ. Fully Qualified Domain Name, FQDN). В повседневной записи завершающую точку опускают, но в файлах зон и в выводе dig она существенна: имя без точки считается относительным и дополняется текущим суффиксом. Классическая ошибка в файле зоны — записать mail.nsu.example без точки там, где ожидается абсолютное имя; сервер превратит его в mail.nsu.example.nsu.example..

Доменом (англ. domain) называется поддерево с вершиной в некотором узле: домен nsu.example включает сам узел nsu.example и все имена под ним, в том числе www.nsu.example и git.lab.nsu.example. Узлы первого уровня под корнем — домены верхнего уровня (англ. Top-Level Domain, TLD): общие (com, org, net), национальные двухбуквенные (ru, de), инфраструктурный arpa. Для документации и учебных примеров зарезервированы имена example, example.com, example.org, example.net, а также test и invalid; учебная организация курса «Северный узел» пользуется доменом nsu.example.

Метка — это последовательность байтов, но ради совместимости с почтой и старым программным обеспечением имена узлов исторически ограничены буквами латиницы, цифрами и дефисом. Имена на национальных алфавитах (например, в зоне рф) кодируются в ASCII по правилам IDNA: метка рф хранится в DNS как xn--p1ai. Таким образом, сам протокол о кириллице ничего не знает, перекодированием занимается приложение.

Зоны, делегирование и авторитетные серверы

Если бы всё дерево хранилось на одном сервере, вернулись бы проблемы HOSTS.TXT. Поэтому дерево разрезано на зоны (англ. zone). Зона — связная часть дерева, данные которой управляются одной организацией и хранятся на её серверах. Разрез проходит по точкам делегирования (англ. delegation point): родительская зона объявляет, что за имя-потомок и всё под ним отвечают другие серверы, и указывает их имена записями типа NS (англ. name server). Схема на рисунке ниже показывает учебное дерево курса: корневая зона делегирует домен example., зона example. делегирует nsu.example., а та, в свою очередь, делегирует подзону lab.nsu.example. отдельному серверу.

Дерево имён DNS и его разбиение на зоны
Домен — поддерево имён; зона — часть домена до точек делегирования

Различие между доменом и зоной — первая типичная ошибка понимания. Домен nsu.example включает lab.nsu.example, а зона nsu.example. — нет: записи для www.lab.nsu.example хранятся только на сервере подзоны, родитель о них не знает. Зато родитель хранит у себя записи NS для lab.nsu.example, и точно такие же NS-записи хранит сама подзона. Записи NS в родительской зоне не авторитетны, они лишь указывают дорогу; авторитетными являются копии в дочерней зоне 3.

Сервер, хранящий данные зоны и отвечающий на вопросы о ней от первого лица, называется авторитетным (англ. authoritative name server). В ответе он устанавливает флаг AA (англ. Authoritative Answer). У каждой зоны должно быть не менее двух авторитетных серверов, по возможности в разных сетях: RFC 1034 требует этого для устойчивости к отказам 1. Традиционно один из них — первичный (англ. primary), на котором редактируется файл зоны, а остальные — вторичные (англ. secondary), получающие копию передачей зоны (англ. zone transfer, запросы AXFR и IXFR). Для клиента первичный и вторичный неразличимы: оба авторитетны.

Каждая зона начинается записью SOA (англ. Start of Authority), содержащей служебные параметры: имя первичного сервера, адрес ответственного лица (с точкой вместо @), серийный номер версии зоны и таймеры для вторичных серверов. Последнее поле SOA, исторически названное MINIMUM, по RFC 2308 задаёт срок отрицательного кеширования, о котором пойдёт речь ниже 4.

Особого внимания заслуживает случай, когда имя сервера зоны лежит внутри самой зоны. Зона example. объявляет: «за nsu.example. отвечает ns1.nsu.example.». Чтобы узнать адрес ns1.nsu.example., нужно спросить сервер зоны nsu.example., адрес которого как раз и неизвестен, — возникает замкнутый круг. Его разрывают связующие записи (англ. glue records): родительская зона хранит не только NS, но и адрес этого сервера и отдаёт его в дополнительной секции ответа. Ниже — фрагмент учебной зоны example. из лабораторной работы:

; Делегирование зоны nsu.example. («Северный узел») её серверу.
nsu      IN NS  ns1.nsu.example.
ns1.nsu  IN A   10.15.0.13          ; связующая запись (glue)

Если же имя сервера лежит в чужой зоне (например, зона nsu.example. обслуживается сервером ns.provider.example.), связующая запись не нужна и не должна публиковаться: резолвер разрешит имя сервера отдельным запросом.

Корневые серверы и anycast

Вершина иерархии — корневая зона, содержащая делегирования всех доменов верхнего уровня, а их около полутора тысяч. Корневую зону обслуживают 13 логических корневых серверов с именами от a.root-servers.net до m.root-servers.net, которыми управляют 12 независимых организаций (две буквы, A и J, у компании Verisign). Число 13 — следствие ограничения размера UDP-ответа в 512 байт: список из 13 имён с адресами IPv4 укладывался в один ответ на вопрос «кто серверы корня».

Однако 13 — это число адресов, а не машин. Каждый корневой адрес объявляется по BGP из сотен точек по всему миру, и пакет, отправленный на него, доставляется в ближайшую по маршрутизации точку. Такой способ адресации называется anycast: один адрес — много экземпляров сервиса; механизм рассматривался в теме 10. Сейчас корневая система насчитывает более полутора тысяч экземпляров, и именно поэтому запрос из Новосибирска к j.root-servers.net в приведённом ниже выводе dig занимает 11 мс, а не сотни миллисекунд до США.

Адреса корневых серверов резолвер знает заранее из файла подсказок (англ. root hints), поставляемого вместе с программой; первое, что делает резолвер при запуске, — запрашивает у одного из них актуальный список (англ. priming query). Корневые серверы не выполняют рекурсию и не знают ответов на конечные вопросы: на вопрос о www.nsu.ru корень отвечает только «спросите серверы ru».

Разрешение имён

Участники: stub-резолвер, рекурсивный резолвер, авторитетный сервер

Разрешение имени (англ. name resolution) — процесс получения записей по имени. В нём участвуют три вида программ. Stub-резолвер (англ. stub resolver, «резолвер-заглушка») — библиотека в операционной системе приложения, которая сама ничего не разыскивает: она отправляет вопрос с флагом RD (англ. Recursion Desired, «желательна рекурсия») рекурсивному резолверу и ждёт окончательного ответа. Рекурсивный резолвер (англ. recursive resolver), он же кеширующий сервер, — программа, которая выполняет поиск от имени клиента, обходя авторитетные серверы, и хранит полученные ответы в кеше; её запускает провайдер, организация или публичный сервис (8.8.8.8, 1.1.1.1). Авторитетные серверы, как уже сказано, отвечают только о своих зонах.

Различают два режима запроса. Рекурсивный запрос (флаг RD=1) — «найди ответ целиком и верни его»; так stub обращается к резолверу. Итеративный запрос — «скажи, что знаешь»; так резолвер обращается к авторитетным серверам, и те в ответ либо дают окончательный ответ, либо направление (англ. referral) — список серверов зоны, расположенной ближе к искомому имени. Рекурсивный резолвер сообщает о готовности выполнять рекурсию флагом RA (англ. Recursion Available) в ответе. Авторитетный сервер, не предназначенный для рекурсии, флаг RA не ставит, и dig, отправивший ему вопрос с RD=1, предупреждает: recursion requested but not available.

Распространённая ошибка понимания — считать, что «DNS-сервер провайдера» и «DNS-сервер, на котором размещён домен» выполняют одну функцию. Первый — рекурсивный резолвер, работающий для клиентов и не обладающий собственными данными; второй — авторитетный сервер, работающий для всего Интернета и не выполняющий поиск. Совмещать обе роли на одном сервере не рекомендуется: открытый для всех рекурсивный резолвер используется в атаках с усилением (англ. amplification), а кеш, общий с авторитетными данными, усложняет диагностику.

Итеративное разрешение шаг за шагом

Рассмотрим, как рекурсивный резолвер с пустым кешем находит адрес www.nsu.example в учебной иерархии лабораторной работы. Временная диаграмма на рисунке ниже показывает обмен сообщениями.

Итеративное разрешение имени рекурсивным резолвером
Разрешение www.nsu.example: клиент задаёт один рекурсивный вопрос, резолвер — три итеративных

Шаг 1: stub-резолвер клиента отправляет рекурсивному резолверу вопрос «www.nsu.example, тип A» с RD=1. Шаги 2–3: резолвер, зная только адрес корневого сервера, спрашивает его и получает направление: «зона example. — у сервера a.nic.example, его адрес 10.15.0.12» (запись NS в секции полномочий и связующая запись A в дополнительной секции). Шаги 4–5: сервер example. направляет к ns1.nsu.example с адресом 10.15.0.13. Шаги 6–7: сервер зоны nsu.example. отвечает с флагом AA адресом 10.15.0.80 и сроком жизни 3600 с. Шаг 8: резолвер возвращает ответ клиенту и сохраняет в кеше все полученные записи — не только конечный ответ, но и направления. Журнал учебного резолвера из лабораторной работы фиксирует ровно эту последовательность:

12:44:14 == запрос от клиента: www.nsu.example. A
12:44:14   -> 10.15.0.11 (корневой сервер (подсказка)), зона .: вопрос www.nsu.example. A
12:44:14   <- направление: зона example., серверы a.nic.example.; glue a.nic.example.=10.15.0.12
12:44:14   -> 10.15.0.12 (a.nic.example.), зона example.: вопрос www.nsu.example. A
12:44:14   <- направление: зона nsu.example., серверы ns1.nsu.example.; glue ns1.nsu.example.=10.15.0.13
12:44:14   -> 10.15.0.13 (ns1.nsu.example.), зона nsu.example.: вопрос www.nsu.example. A
12:44:14   <- ответ от 10.15.0.13 (AA=1): 10.15.0.80
12:44:14 == ответ клиенту: NOERROR, 1 записей, 4.4 мс

Тот же путь в реальном Интернете показывает команда dig +trace. Она не пользуется рекурсией резолвера: получив у него только список корневых серверов, dig сам выполняет итеративные запросы и печатает каждое полученное направление. Ниже — реальный вывод (октябрь 2026 г., ключ -4 ограничивает обмен протоколом IPv4, +nodnssec убирает подписи; список корневых серверов сокращён):

dig -4 +trace +nodnssec @8.8.8.8 www.nsu.ru
.			87203	IN	NS	a.root-servers.net.
.			87203	IN	NS	b.root-servers.net.
...
;; Received 239 bytes from 8.8.8.8#53(8.8.8.8) in 63 ms

ru.			172800	IN	NS	a.dns.ripn.net.
ru.			172800	IN	NS	b.dns.ripn.net.
ru.			172800	IN	NS	c.tld-servers.ru.
ru.			172800	IN	NS	d.dns.ripn.net.
ru.			172800	IN	NS	e.dns.ripn.net.
ru.			172800	IN	NS	f.dns.ripn.net.
;; Received 437 bytes from 192.58.128.30#53(j.root-servers.net) in 11 ms

nsu.ru.			345600	IN	NS	ns.nsu.ru.
nsu.ru.			345600	IN	NS	ns2.nsu.ru.
;; Received 106 bytes from 194.85.252.62#53(b.dns.ripn.net) in 12 ms

www.nsu.ru.		3600	IN	A	84.237.49.123
nsu.ru.			3600	IN	NS	ns.nsu.ru.
nsu.ru.			3600	IN	NS	ns2.nsu.ru.
;; Received 150 bytes from 84.237.50.45#53(ns.nsu.ru) in 55 ms

В выводе видны три уровня делегирования: корень → ru. → nsu.ru.. Заметим, что NS-записи nsu.ru. в направлении от сервера ru имеют TTL 345 600 с (четверо суток), а те же записи в авторитетном ответе самого ns.nsu.ru — 3600 с: родитель и потомок хранят свои копии с разными параметрами, и по RFC 2181 резолвер должен предпочесть авторитетные данные потомка 3. Ответ от корня занимает 437 байт, поскольку содержит связующие записи A и AAAA для шести серверов ru.

Время в этом примере складывается из четырёх обменов. Если бы резолвер каждый раз проходил весь путь, разрешение одного имени стоило бы сотни миллисекунд. На практике путь проходится полностью редко: направления к ru. и nsu.ru. уже лежат в кеше резолвера, и ему остаётся один запрос — или ни одного.

Кеширование, TTL и отрицательное кеширование

Каждая запись ресурса имеет срок жизни (англ. Time To Live, TTL) — 32-битное число секунд, в течение которого получатель может хранить запись в кеше и отдавать её без обращения к источнику. RFC 2181 ограничивает значение TTL диапазоном от 0 до 2^31 − 1 секунд и требует, чтобы все записи одного набора — одного имени, класса и типа (англ. RRset) — имели одинаковый TTL 3. Отдавая запись из кеша, резолвер уменьшает её TTL на время, прошедшее с получения: так клиент узнаёт, сколько ещё запись будет действительна.

Числовой пример. Резолвер получил запись www.nsu.example. 3600 IN A 10.15.0.80 в 12:00:00. Запрос клиента в 12:00:04 получит ту же запись с TTL 3596, запрос в 12:59:59 — с TTL 1, а в 13:00:00 запись удаляется, и следующий запрос снова пойдёт к авторитетному серверу. Если в 12:10 администратор изменил адрес на 10.15.0.81, клиенты этого резолвера будут получать старый адрес до 13:00, то есть до 50 минут. Отсюда практическое правило миграции: за сутки до переезда сервиса уменьшить TTL записи, например до 300 с, дождаться истечения старого TTL, затем сменить адрес — тогда переходный период займёт не более пяти минут. Выбор TTL — компромисс между скоростью распространения изменений и нагрузкой на авторитетные серверы, а также задержкой клиентов: с TTL 60 с почти каждый пользователь будет ждать полного разрешения.

Кешируются и отрицательные ответы. Код NXDOMAIN (англ. Non-Existent Domain) означает, что имени не существует вовсе; ответ NODATA — что имя существует, но записей запрошенного типа у него нет (код NOERROR при пустой секции ответа). Без кеширования таких ответов опечатка в имени или запрос AAAA к домену без IPv6 порождали бы поток бесполезных обращений к авторитетным серверам. RFC 2308 предписывает авторитетному серверу вкладывать в отрицательный ответ запись SOA своей зоны в секцию полномочий, а резолверу — хранить отрицательный ответ в течение меньшего из двух значений: TTL самой записи SOA и поля MINIMUM в ней 4. В учебной зоне SOA имеет TTL 3600 и MINIMUM 300, поэтому NXDOMAIN кешируется на 300 с. Повторный запрос к резолверу через две секунды показывает уменьшающийся счётчик:

;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 34588
nsu.example.		299	IN	SOA	ns1.nsu.example. hostmaster.nsu.example. 2026100101 7200 900 1209600 300
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 34589
nsu.example.		297	IN	SOA	ns1.nsu.example. hostmaster.nsu.example. 2026100101 7200 900 1209600 300

Отрицательное кеширование объясняет часто наблюдаемый эффект: администратор проверил имя до того, как добавил его в зону, получил NXDOMAIN, добавил запись — а резолвер ещё несколько минут продолжает отвечать «имени нет». Это не ошибка сервера: резолвер выполняет предписание RFC 2308. В лабораторной работе этот эффект воспроизводится при делегировании подзоны.

Разрешение имён в операционной системе

Приложение обычно не формирует DNS-запросы само, а вызывает функцию библиотеки — в Linux это getaddrinfo() из glibc. Библиотека обращается к источникам в порядке, заданном строкой hosts: файла /etc/nsswitch.conf (англ. Name Service Switch). В настольной версии Ubuntu 24.04 эта строка выглядит так (в серверной — files dns):

hosts:          files mdns4_minimal [NOTFOUND=return] dns

Здесь files — файл /etc/hosts, mdns4_minimal — многоадресный DNS для имён в локальном домене .local, dns — обычное разрешение. Порядок означает, что запись в /etc/hosts перекрывает DNS: этим пользуются разработчики для подмены имени на тестовый сервер, и это же — частая причина «необъяснимых» расхождений между ping имя и dig имя. Команда dig работает только с DNS и /etc/hosts не читает, а getent hosts имя проходит тот же путь, что и приложение.

Адреса рекурсивных резолверов stub-резолвер glibc берёт из файла /etc/resolv.conf: строки nameserver (используются не более трёх), search со списком суффиксов и options (тайм-аут, число попыток, ndots). Параметр ndots, по умолчанию равный 1, определяет, когда имя считать относительным: имя, содержащее меньше ndots точек, сначала дополняется суффиксами из search. При search nsu.example запрос ping www превращается в запрос www.nsu.example. В Kubernetes ndots по умолчанию равен 5, из-за чего запрос имени внешнего сайта сначала порождает несколько безуспешных запросов с внутренними суффиксами — классический источник лишней задержки.

В современных дистрибутивах Linux с systemd между приложением и сетью стоит ещё один посредник — служба systemd-resolved. Она слушает адрес 127.0.0.53, и в /etc/resolv.conf (символической ссылке на /run/systemd/resolve/stub-resolv.conf) указан именно он, а настоящие резолверы, полученные по DHCP, служба хранит у себя и показывает командой resolvectl status. Служба кеширует ответы, выбирает резолвер для каждого сетевого интерфейса отдельно и может использовать DNS over TLS. Поэтому при диагностике полезно помнить о двух уровнях: dig @127.0.0.53 спрашивает локальную службу, dig @адрес_резолвера — резолвер провайдера напрямую.

Сообщение DNS и ресурсные записи

Формат сообщения

Запрос и ответ DNS имеют один формат 2: заголовок длиной 12 байт и четыре секции переменной длины — вопрос (англ. question), ответ (англ. answer), полномочия (англ. authority) и дополнительная (англ. additional). Схема на рисунке ниже показывает поля заголовка и структуру записи ресурса.

Формат заголовка сообщения DNS и записи ресурса
Заголовок DNS (12 байт), секции сообщения и формат записи ресурса

Поля заголовка:

  • ID (16 бит) — идентификатор, выбираемый запрашивающей стороной и копируемый в ответ; по нему клиент сопоставляет ответ с запросом;
  • QR (1 бит) — 0 для запроса, 1 для ответа; OPCODE (4 бита) — вид запроса, обычный запрос имеет код 0;
  • AA — ответ авторитетный; TC (англ. TrunCation) — ответ усечён и не поместился в датаграмму; RD и RA — рекурсия желательна и доступна;
  • Z — зарезервированный бит; AD (англ. Authentic Data) и CD (англ. Checking Disabled) добавлены DNSSEC: первый означает, что резолвер проверил подписи, второй просит проверку не выполнять 8;
  • RCODE (4 бита) — код результата: 0 NOERROR, 1 FORMERR, 2 SERVFAIL (сбой на стороне сервера, в том числе неудачная проверка DNSSEC), 3 NXDOMAIN, 4 NOTIMP, 5 REFUSED (сервер отказался отвечать, например на вопрос о чужой зоне);
  • QDCOUNT, ANCOUNT, NSCOUNT, ARCOUNT (по 16 бит) — число записей в каждой из четырёх секций.

Секция вопроса содержит имя QNAME, тип QTYPE и класс QCLASS (почти всегда 1 — IN, Интернет). Остальные секции состоят из записей ресурса (англ. Resource Record, RR) с полями NAME, TYPE, CLASS, TTL (32 бита), RDLENGTH (16 бит) и данными RDATA указанной длины. Имя кодируется последовательностью меток, каждой из которых предшествует байт длины, и завершается нулевым байтом — меткой корня.

Разберём побайтно реальный обмен из лабораторной работы: вопрос о записи A имени www.nsu.example к авторитетному серверу 10.15.0.13 без рекурсии и без EDNS. Вывод получен учебной утилитой dnsmsg.py:

;; запрос, 33 байт:
  0000  ca c0 00 00 00 01 00 00 00 00 00 00 03 77 77 77  .............www
  0010  03 6e 73 75 07 65 78 61 6d 70 6c 65 00 00 01 00  .nsu.example....
  0020  01                                               .

Байты ca c0 — идентификатор 51904. Байты 00 00 — все флаги нулевые: запрос (QR=0), обычный (OPCODE=0), рекурсия не запрошена. Далее 00 01 — один вопрос, и три пары 00 00 — пустые секции. С смещения 12 (0x0c) начинается имя: 03 77 77 77 — метка длиной 3 байта «www», 03 6e 73 75 — «nsu», 07 65 78 61 6d 70 6c 65 — «example», 00 — корень; всего 17 байт. Завершают вопрос 00 01 (тип A) и 00 01 (класс IN). Итого 12 + 17 + 4 = 33 байта.

;; ответ от 10.15.0.13, 49 байт:
  0000  ca c0 84 00 00 01 00 01 00 00 00 00 03 77 77 77  .............www
  0010  03 6e 73 75 07 65 78 61 6d 70 6c 65 00 00 01 00  .nsu.example....
  0020  01 c0 0c 00 01 00 01 00 00 0e 10 00 04 0a 0f 00  ................
  0030  50                                               P

В ответе тот же ID, а флаги 84 00 в двоичном виде — 1000 0100 0000 0000: старший бит QR=1 (это ответ), OPCODE=0, затем бит AA=1 (ответ авторитетный), TC, RD, RA равны нулю, RCODE=0. Сервер повторяет вопрос, ANCOUNT равен 1. Запись ответа начинается со смещения 0x21: c0 0c — имя, 00 01 — тип A, 00 01 — класс IN, 00 00 0e 10 — TTL 0x0e10 = 3600 с, 00 04 — длина данных 4 байта, 0a 0f 00 50 — адрес 10.15.0.80. Вся запись занимает 16 байт, и ответ — 33 + 16 = 49 байт.

Сжатие имён

Имя в записи ответа закодировано двумя байтами c0 0c вместо семнадцати. Это механизм сжатия (англ. message compression) из RFC 1035 2: если два старших бита байта длины равны 11, то этот байт вместе со следующим образует указатель, а оставшиеся 14 бит — смещение от начала сообщения, где имя (или его окончание) уже встречалось. Значение 0xc00c даёт смещение 0x000c = 12, то есть ссылку на имя в секции вопроса. Метка не может быть длиннее 63 байт именно потому, что два старших бита байта длины отведены под признак указателя.

Сжатие позволяет уместить больше записей в ограниченный размер датаграммы: в ответе с десятью записями одного имени экономия составляет более сотни байтов. Указатель может стоять и в конце имени: имя mail.nsu.example в том же сообщении кодируется как 04 6d 61 69 6c c0 10 — метка «mail» и ссылка на nsu.example по смещению 16. Разбор указателей — классическое место ошибок в реализациях DNS: цепочка указателей, ссылающаяся сама на себя, без проверки приводит к зацикливанию, а указатель за пределы сообщения — к чтению чужой памяти.

Типы записей

Тип записи определяет смысл и формат её данных. Основные типы, встречающиеся в практике, сведены в таблицу.

ТипКодСодержимоеПример данных
A1адрес IPv410.15.0.80
AAAA28адрес IPv62001:db8:15::80
NS2имя авторитетного сервера зоныns1.nsu.example.
CNAME5каноническое имя: данное имя — псевдонимwww.nsu.example.
SOA6параметры зоныns1… hostmaster… 2026100101 7200 900 1209600 300
PTR12имя по адресу (обратная зона)www.nsu.example.
MX15приоритет и имя почтового сервера10 mail.nsu.example.
TXT16произвольные строки"v=spf1 mx -all"
SRV33приоритет, вес, порт, имя сервера службы0 10 389 dc1.nsu.example.
HTTPS65параметры подключения к веб-сервису1 . alpn="h3,h2"
CAA257какие удостоверяющие центры могут выпускать сертификаты0 issue "letsencrypt.org"

Запись CNAME (англ. Canonical Name) объявляет имя псевдонимом другого. Получив CNAME, резолвер продолжает поиск уже для канонического имени и возвращает клиенту цепочку: portal.nsu.example. CNAME www.nsu.example. и затем www.nsu.example. A 10.15.0.80. Важное ограничение: если у имени есть CNAME, других записей у него быть не может 13. Поэтому CNAME нельзя поставить на вершину зоны (англ. zone apex, имя самой зоны nsu.example.), где обязательно присутствуют SOA и NS. Провайдеры DNS обходят это ограничение нестандартными «плоскими» псевдонимами (ALIAS, ANAME), которые разворачиваются на стороне сервера; стандартным решением для веба стала запись HTTPS. Кроме того, RFC 2181 запрещает указывать в NS и MX имя, являющееся псевдонимом 3.

Запись MX (англ. Mail Exchanger) сообщает, какой сервер принимает почту для домена; из нескольких записей отправитель выбирает сервер с наименьшим числом предпочтения. Например, у nsu.ru три записи: 1 zimbra.nsu.ru., 3 mxt.nsu.ru., 10 mx2.nsu.ru., и почта сначала направляется на zimbra. Запись SRV (RFC 2782) обобщает идею MX на любые службы: имя вида _ldap._tcp.nsu.example указывает сервер, порт, приоритет и вес для службы LDAP по TCP. Записи TXT содержат строки и используются для политик почты SPF, DKIM, DMARC (тема 16) и для подтверждения владения доменом перед внешними сервисами.

Записи SVCB и HTTPS (RFC 9460) позволяют в одном ответе сообщить клиенту, какие прикладные протоколы поддерживает сервис и на каких адресах 14. Реальный ответ для cloudflare.com:

cloudflare.com.		300	IN	HTTPS	1 . alpn="h3,h2" ipv4hint=104.16.132.229,104.16.133.229 ipv6hint=2606:4700::6810:84e5,2606:4700::6810:85e5

Приоритет 1 означает рабочую запись (0 — режим псевдонима), точка — «то же имя», параметр alpn сообщает, что сервер поддерживает HTTP/3 и HTTP/2, а подсказки адресов позволяют браузеру начать соединение, не дожидаясь отдельных запросов A и AAAA. Таким образом, браузер может сразу установить соединение по QUIC, о котором пойдёт речь в теме 16. Запись CAA (RFC 8659) ограничивает круг удостоверяющих центров, которым разрешено выпускать сертификаты для домена; например, у google.com это 0 issue "pki.goog". Её проверка обязательна для публичных удостоверяющих центров; подробнее о сертификатах — в теме 17.

Файл зоны и обратные зоны

Данные зоны на авторитетном сервере традиционно хранятся в текстовом файле зоны (англ. master file, zone file), формат которого определён в RFC 1035 2. Строка файла — запись ресурса: имя, необязательный TTL, класс, тип и данные. Директива $ORIGIN задаёт суффикс для относительных имён, $TTL — TTL по умолчанию, символ @ обозначает само имя зоны, пустое поле имени означает «то же, что в предыдущей строке», скобки позволяют продолжить запись на следующих строках, точка с запятой открывает комментарий. Фрагмент учебной зоны nsu.example.:

$ORIGIN nsu.example.
$TTL 3600
@         IN SOA ns1.nsu.example. hostmaster.nsu.example. (
                 2026100101 ; serial: ГГГГММДДNN, увеличивать при каждом изменении
                 7200       ; refresh: как часто вторичный сервер проверяет serial
                 900        ; retry: повтор при неудаче
                 1209600    ; expire: через сколько вторичный перестаёт отвечать
                 300 )      ; minimum: TTL отрицательного кеширования (RFC 2308)
@         IN NS    ns1
ns1       IN A     10.15.0.13
www       IN A     10.15.0.80
www       IN AAAA  2001:db8:15::80
portal    IN CNAME www                  ; псевдоним
mail      IN A     10.15.0.25
@         IN MX    10 mail              ; почта для адресов @nsu.example
short     60 IN A  10.15.0.81           ; запись с коротким TTL (60 с)

Серийный номер SOA — номер версии зоны; вторичный сервер раз в refresh секунд сравнивает его со своим и запрашивает передачу зоны, только если номер вырос. Забытое увеличение серийного номера — классическая ошибка: первичный сервер уже отдаёт новые данные, а вторичные — старые, и клиенты получают разные ответы в зависимости от того, к какому серверу попали. Распространённое соглашение — записывать номер как дату и порядковый номер правки: 2026100101.

Обратное разрешение — получение имени по адресу — использует тот же механизм в специальном домене in-addr.arpa. Адрес IPv4 записывается в обратном порядке октетов, потому что иерархия имён растёт справа налево, а иерархия адресов — слева направо: адресу 10.15.0.80 соответствует имя 80.0.15.10.in-addr.arpa., и за сеть 10.15.0.0/24 отвечает зона 0.15.10.in-addr.arpa., которую можно делегировать владельцу сети. Запись в ней имеет тип PTR (англ. pointer). Для IPv6 используется домен ip6.arpa с разбиением адреса на полубайты: адрес 2001:db8::1 превращается в имя из 32 шестнадцатеричных цифр в обратном порядке. Команда dig -x 8.8.8.8 сама строит такое имя:

8.8.8.8.in-addr.arpa.	18635	IN	PTR	dns.google.

Обратные записи ведёт владелец блока адресов, то есть, как правило, провайдер, а не владелец домена. Поэтому прямое и обратное разрешение часто расходятся, и проверка их согласованности (англ. forward-confirmed reverse DNS) — один из признаков, по которым почтовые серверы оценивают отправителя.

Транспорт DNS

UDP, TCP и ограничение размера ответа

Основной транспорт DNS — UDP, порт 53. Запрос и ответ укладываются в одну датаграмму каждый, и разрешение не требует установления соединения: для протокола, на котором клиент ждёт каждый ответ, экономия рукопожатия TCP заметна. Платой за это стала необходимость самому обрабатывать потери (клиент повторяет запрос по тайм-ауту) и ограничение размера: RFC 1035 ограничил сообщение DNS поверх UDP 512 байтами, чтобы датаграмма гарантированно проходила по любому пути без фрагментации 2.

Если ответ не помещается в этот размер, сервер отправляет столько записей, сколько помещается, и устанавливает флаг TC. Получив усечённый ответ, клиент повторяет тот же вопрос по TCP на тот же порт 53. В TCP сообщению DNS предшествует двухбайтовое поле длины, поскольку TCP — поток байтов без границ сообщений (тема 13). Долгое время TCP считался для DNS второстепенным и использовался в основном для передачи зон; RFC 7766 изменил это положение: поддержка TCP обязательна для всех реализаций, а клиент может отправлять по одному соединению несколько запросов и получать ответы не по порядку 6. Межсетевой экран, пропускающий только UDP-порт 53, нарушает работу DNS — такая конфигурация считается ошибочной.

В лабораторной работе этот механизм наблюдается на имени big.nsu.example, у которого семь записей TXT общим размером более 600 байт. Запрос с dig +noedns получает усечённый ответ, и dig автоматически повторяет его по TCP; итоговая строка вывода показывает транспорт и размер:

;; SERVER: 10.15.0.13#53(10.15.0.13) (TCP)
;; MSG SIZE  rcvd: 705

Расширение EDNS(0)

Ограничение 512 байт стало серьёзным препятствием, когда в ответы потребовалось включать адреса IPv6 и подписи DNSSEC. Расширение EDNS(0) (англ. Extension Mechanisms for DNS) решает задачу без изменения формата заголовка 5. Клиент добавляет в дополнительную секцию запроса псевдозапись OPT (тип 41), не относящуюся ни к какому имени. Её поля переопределены: поле CLASS содержит размер UDP-ответа в байтах, который клиент готов принять, а поле TTL — расширенный код результата (8 бит), версию EDNS (8 бит, сейчас 0) и флаги, из которых определён один — DO (англ. DNSSEC OK), просьба включить в ответ записи DNSSEC. Данные OPT могут содержать дополнительные параметры — например, подсеть клиента (англ. EDNS Client Subnet, RFC 7871) или «cookie» для защиты от подделки.

Сервер, понимающий EDNS, отвечает с собственной записью OPT и может отправить ответ до объявленного размера. В выводе dig это видно в псевдосекции:

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232

Число 1232 не случайно. Большой UDP-ответ, превышающий MTU пути, фрагментируется на уровне IP, а фрагменты часто теряются на межсетевых экранах и, хуже того, открывают возможность подмены ответа через подложный фрагмент. Сообщество операторов DNS в рамках согласованной акции DNS Flag Day 2020 рекомендовало размер 1232 байта: он получен из минимального MTU IPv6 1280 байт за вычетом 40 байт заголовка IPv6 и 8 байт заголовка UDP и гарантирует отсутствие фрагментации. Если ответ больше — устанавливается флаг TC, и клиент переходит на TCP. Числовой пример: ответ для big.nsu.example в 705 байт не помещается в 512 байт, но помещается в 1232, поэтому с EDNS он приходит по UDP с первой попытки, а без EDNS требует повторного запроса по TCP — лишний обмен и рукопожатие TCP, то есть два-три дополнительных RTT.

Шифрование: DoT, DoH, DoQ

Классический DNS передаётся открытым текстом. Любой узел на пути между клиентом и резолвером — точка доступа Wi-Fi, провайдер, оборудование в магистральной сети — видит, какие имена запрашивает пользователь, и может подменить ответ. Для защиты участка «клиент — резолвер» разработаны три способа шифрования, различающиеся транспортом.

DNS поверх TLS (англ. DNS over TLS, DoT) — сообщения DNS в формате TCP-транспорта (с двухбайтовой длиной) внутри TLS-сессии на выделенном порту 853 9. Отдельный порт упрощает администрирование, но и позволяет легко заблокировать или выделить такой трафик. DNS поверх HTTPS (англ. DNS over HTTPS, DoH) — сообщение DNS в двоичном формате передаётся как тело HTTP-запроса с типом application/dns-message методом POST или как параметр dns в URL методом GET (в кодировке base64url) 10. DoH идёт на порт 443 и внешне неотличим от другого веб-трафика; браузеры реализуют его сами, минуя системный резолвер. DNS поверх QUIC (англ. DNS over QUIC, DoQ) использует транспорт QUIC (тема 16) на UDP-порту 853: каждый запрос — отдельный поток QUIC, поэтому потеря пакета одного ответа не задерживает другие 11.

Утилита dig версии 9.18 умеет и DoT, и DoH:

dig @1.1.1.1 +https nsu.ru A
;; ANSWER SECTION:
nsu.ru.			3600	IN	A	84.237.49.123

;; Query time: 63 msec
;; SERVER: 1.1.1.1#443(1.1.1.1) (HTTPS)

Шифрование канала защищает от наблюдателя на пути, но не от самого резолвера: он по-прежнему видит все запросы клиента. Кроме того, шифрование не подтверждает подлинность данных — если резолвер получил от авторитетного сервера подделку, он передаст её по зашифрованному каналу. Эту задачу решает DNSSEC, рассмотренный в следующем разделе. Наконец, централизация DoH на немногих публичных резолверах, встроенных в браузеры, вызывает споры: она обходит корпоративные политики и перераспределяет сведения о пользователях от провайдеров к нескольким крупным компаниям.

Безопасность DNS

Отравление кеша и атака Каминского

Классический резолвер принимает ответ, если тот пришёл с адреса сервера, которому был отправлен вопрос, на порт, с которого вопрос ушёл, и содержит тот же ID и тот же вопрос. Злоумышленник, не находящийся на пути пакетов (англ. off-path attacker), может отправить резолверу поддельный ответ с подменённым адресом отправителя. Если подделка придёт раньше настоящего ответа и совпадёт по всем проверяемым полям, резолвер сохранит её в кеше и будет раздавать всем клиентам до истечения TTL. Такая атака называется отравлением кеша (англ. cache poisoning).

Единственное, что злоумышленник не знает заранее, — 16-битный ID и, в старых реализациях, порт: многие резолверы отправляли все запросы с одного фиксированного порта. Шанс угадать ID одним пакетом — 1/65 536. До 2008 года атака считалась малопрактичной: удачная попытка возможна только при отсутствии ответа в кеше, а после неудачи настоящий ответ кешировался на TTL, и следующая попытка становилась возможной лишь через часы. Дэн Каминский показал в 2008 году, как снять это ограничение. Злоумышленник заставляет резолвер спрашивать каждый раз новое, несуществующее имя — a1.bank.example, a2.bank.example и так далее, — которого заведомо нет в кеше, и в каждом поддельном ответе вместо адреса отправляет направление: «зона bank.example обслуживается сервером ns.bank.example, его адрес — адрес злоумышленника». Попытки можно повторять без ожидания, по сотне поддельных ответов на каждый вопрос, и при фиксированном порте атака успевает за секунды или минуты, после чего злоумышленник контролирует уже не одно имя, а всю зону.

Немедленной защитой стала рандомизация порта источника, зафиксированная в RFC 5452 12: резолвер выбирает для каждого запроса случайный порт, и злоумышленнику приходится угадывать не 16, а около 32 бит. Числовой пример: в Linux диапазон эфемерных портов по умолчанию — 32 768–60 999, то есть 28 232 значения; вместе с ID это 65 536 · 28 232 ≈ 1,85 · 10^9 вариантов. Если злоумышленник успевает отправить 100 подделок в окно между вопросом и настоящим ответом, вероятность успеха одной попытки — около 5 · 10^-8, и для вероятности успеха в 50 % потребуется порядка 10^7 попыток, то есть сотни миллиардов поддельных пакетов. Тот же RFC требует проверять, что записи в ответе относятся к зоне опрашиваемого сервера (правило «в пределах полномочий», англ. bailiwick): сервер зоны example. не может сообщить ничего достоверного о bank.test.. Дополнительно часть резолверов случайно меняет регистр букв в вопросе (так называемая техника 0x20) и проверяет, что ответ повторяет его в точности, — это добавляет по биту энтропии на каждую букву.

Рандомизация повышает стоимость атаки, но не устраняет её принципиально: в 2020 году атака SAD DNS показала, как по побочному каналу — ограничению частоты сообщений ICMP в ядре Linux — определить открытый порт резолвера и вновь свести перебор к 16 битам. Полностью проблему подлинности ответов решает только криптографическая подпись данных.

DNSSEC: подпись данных и цепочка доверия

Расширения безопасности DNS (англ. DNS Security Extensions, DNSSEC) описаны в RFC 4033–4035 78. Их цель — подлинность и целостность данных: резолвер может проверить, что запись создана владельцем зоны и не изменена по дороге. Конфиденциальности DNSSEC не обеспечивает — данные остаются открытыми; для неё служат DoT, DoH и DoQ. DNSSEC вводит новые типы записей:

  • DNSKEY — открытый ключ зоны;
  • RRSIG — подпись набора записей (RRset) одного имени и типа, с указанием алгоритма, срока действия и ключа, которым она сделана;
  • DS (англ. Delegation Signer) — хеш ключа дочерней зоны, хранящийся в родительской зоне рядом с NS-записями делегирования;
  • NSEC и NSEC3 — доказательство отсутствия: подписанная запись «между именами X и Y других имён нет», позволяющая подписать и ответ NXDOMAIN.

Подписывается не каждая запись, а набор записей целиком. Подписи вычисляются заранее, при подготовке зоны, поэтому авторитетному серверу не нужен закрытый ключ: он раздаёт готовые RRSIG. Реальный ответ с флагом DO для ietf.org:

dig @8.8.8.8 +dnssec +multiline ietf.org A
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
...
ietf.org.		300 IN A 104.16.44.99
ietf.org.		300 IN A 104.16.45.99
ietf.org.		300 IN RRSIG A 13 2 300 (
				20261013104522 20261011084522 34505 ietf.org.
				5SQECAsDw+cOEor7tqYTnKlBvBx+xwO7h41BTAm3lZs8
				h3gllG0NDRA0grUS+hXzBJF3L0SrPnhz6vFLEIc4rw== )

Поля RRSIG читаются так: подписан набор записей типа A; алгоритм 13 — ECDSA на кривой P-256 с SHA-256; в имени владельца 2 метки; исходный TTL 300; подпись действительна с 11 по 13 октября 2026 года (UTC); сделана ключом с тегом 34505 зоны ietf.org.; далее — сама подпись. Короткий срок действия подписи — двое суток — ограничивает время, в течение которого перехваченный устаревший ответ можно воспроизвести.

Как убедиться, что ключ 34505 действительно принадлежит ietf.org? Схема на рисунке ниже показывает цепочку доверия (англ. chain of trust). В зоне обычно два вида ключей: ключ подписи зоны (англ. Zone Signing Key, ZSK, флаги DNSKEY 256) подписывает все наборы записей зоны, а ключ подписи ключей (англ. Key Signing Key, KSK, флаги 257) подписывает только набор DNSKEY. Хеш KSK публикуется в родительской зоне в записи DS, которая подписана ZSK родителя, и так далее до корня. У ietf.org в родительской зоне org. лежит DS 2371 13 2 B1AE88AF…, где 2371 — тег KSK зоны ietf.org., 13 — алгоритм, 2 — тип хеша SHA-256. Корневой KSK резолвер знает заранее: это якорь доверия (англ. trust anchor), поставляемый с программой.

Цепочка доверия DNSSEC от корня до записи A
Цепочка доверия DNSSEC: DS в родительской зоне ручается за KSK дочерней

Проверяющий резолвер последовательно проверяет подпись RRset A ключом ZSK 34505; подпись набора DNSKEY ietf.org ключом KSK 2371; совпадение хеша KSK 2371 с DS в зоне org.; подпись этой DS ключом ZSK org.; и далее до корня. Если все проверки прошли, резолвер устанавливает в ответе клиенту флаг AD — он виден в выводе выше. Если проверка не удалась, резолвер возвращает SERVFAIL, а не данные. Это можно увидеть на специально испорченном тестовом домене dnssec-failed.org: проверяющий резолвер 8.8.8.8 отвечает SERVFAIL, а с флагом CD (dig +cd), отключающим проверку, — возвращает адрес.

Разделение ключей на KSK и ZSK практично: ZSK можно часто менять, не затрагивая родителя, а KSK меняется редко, с публикацией новой DS у регистратора. Самая ответственная операция — смена KSK корня, которую должны принять все проверяющие резолверы мира. Корень подписан с 2010 года; первая смена ключа (переход на KSK-2017 с тегом 20326) прошла в 2018 году. На момент подготовки текста, в октябре 2026 года, набор DNSKEY корня подписывается новым ключом KSK-2024 с тегом 38696, а прежний KSK-2017 ещё опубликован в зоне для плавного перехода — это видно по запросу dig . DNSKEY.

Ограничения DNSSEC тоже важны. Подписи увеличивают ответы и делают их удобными для атак с усилением. Ошибка оператора — просроченная подпись, несогласованная DS после смены ключа — делает весь домен недоступным для проверяющих резолверов, тогда как без DNSSEC он продолжал бы работать. Записи NSEC позволяют перечислить все имена зоны, проходя по цепочке «следующее имя»; NSEC3 хеширует имена, затрудняя такой обход. Наконец, проверку выполняет резолвер, и между ним и приложением остаётся незащищённый участок; приложение доверяет флагу AD, только если доверяет резолверу и каналу до него.

Приватность и минимизация QNAME

Помимо подлинности данных, DNS ставит вопрос приватности. Список запрошенных имён раскрывает, какие сайты посещает человек, какими сервисами и устройствами он пользуется. Сведения утекают в трёх местах: на канале между клиентом и резолвером (это закрывают DoT, DoH и DoQ), у самого резолвера и на пути от резолвера к авторитетным серверам.

Классический резолвер отправляет полное имя всем серверам цепочки: корневой сервер узнаёт, что кто-то запрашивает secret-project.nsu.example, хотя ему достаточно знать только example. Минимизация QNAME (англ. QNAME minimisation, RFC 9156) устраняет этот избыток: резолвер спрашивает у каждого сервера только на одну метку больше, чем уже известная зона, — у корня «A для example.», у сервера example. — «A для nsu.example.», и только авторитетному серверу зоны nsu.example. сообщает полное имя 13. Тип A для промежуточных вопросов рекомендует RFC 9156; в первой версии механизма (RFC 7816) использовался тип NS, но такие вопросы выделялись среди обычных и хуже обрабатывались некоторыми серверами. Минимизация включена по умолчанию в современных резолверах Unbound, BIND и Knot Resolver. Связанная мера — расширение EDNS Client Subnet: оно, наоборот, передаёт авторитетному серверу часть адреса клиента ради более точной географической балансировки и потому отправляется только тем серверам, которые этого явно требуют.

DNS как инструмент управления трафиком

Балансировка нагрузки и GeoDNS

Поскольку авторитетный сервер сам выбирает, что ответить, DNS стал простейшим средством распределения нагрузки. Если у имени несколько записей A, многие серверы меняют их порядок от ответа к ответу (англ. round robin), и клиенты, берущие первый адрес, распределяются между серверами. Этот способ груб: резолвер и клиент кешируют ответ, клиенты одного резолвера получают одинаковый порядок, а отказ одного из серверов клиенты замечают только по тайм-ауту соединения.

Более развитая техника — ответ, зависящий от того, кто спрашивает, называемая GeoDNS. Авторитетный сервер определяет по адресу источника запроса (то есть по адресу рекурсивного резолвера) или по подсети клиента из EDNS Client Subnet примерное местоположение и возвращает адрес ближайшего центра обработки данных. Так работают сети доставки контента (англ. Content Delivery Network, CDN): имя www.example.com через CNAME указывает на имя внутри CDN, а авторитетный сервер CDN выдаёт адрес узла, близкого к пользователю и не перегруженного. Короткий TTL, обычно 20–300 с, позволяет быстро уводить трафик с отказавшего узла. Видно и ограничение способа: при использовании далёкого публичного резолвера пользователь может получить адрес узла CDN, близкого к резолверу, а не к себе.

Альтернатива DNS-балансировке — anycast, при котором один адрес объявляется из многих мест и выбор делает маршрутизация BGP; так устроены корневые серверы и большинство публичных резолверов. Оба способа часто сочетаются, а внутри одной площадки нагрузку распределяет балансировщик уровня L4 или L7, о котором пойдёт речь в теме 16.

Регистрация доменов

Управление пространством имён разделено между несколькими ролями. Корпорация ICANN через функцию IANA ведёт корневую зону и определяет, какие домены верхнего уровня существуют. Каждым TLD управляет реестр (англ. registry) — организация, которая ведёт базу данных доменов второго уровня и эксплуатирует авторитетные серверы зоны: например, Verisign для com и net, Координационный центр доменов .RU/.РФ для ru и рф (технически серверы этих зон эксплуатируются операторами, имена которых видны в выводе dig +trace: a.dns.ripn.net и другие). Конечный пользователь — администратор домена (англ. registrant) — обращается к регистратору (англ. registrar), аккредитованному реестром. Регистратор передаёт в реестр сведения о домене: срок регистрации, контакты и, главное, список NS-серверов и, при необходимости, записи DS.

С технической точки зрения регистрация домена — это и есть делегирование: реестр добавляет в зону TLD записи NS (и связующие записи), указывающие на серверы владельца. Отсюда типичные ошибки. Если серверы, указанные у регистратора, не обслуживают зону или отвечают о ней неавторитетно, получается «хромое» делегирование (англ. lame delegation); резолверы получают ошибки и тайм-ауты. Если владелец сменил DNS-провайдера, но забыл обновить NS у регистратора, домен продолжает работать на старых серверах до их отключения. Если при отключении DNSSEC запись DS у регистратора не удалена, проверяющие резолверы отвергают неподписанные ответы, и домен становится недоступным.

Сведения о зарегистрированных доменах исторически предоставлялись по протоколу WHOIS — простому текстовому протоколу на TCP-порту 43 с неформализованным форматом ответа. Ему на смену пришёл протокол RDAP (англ. Registration Data Access Protocol) — запросы по HTTPS с ответами в формате JSON; для общих доменов верхнего уровня ICANN сделала RDAP основным способом доступа к регистрационным данным с 2025 года. Персональные данные владельцев в обоих случаях обычно скрыты в соответствии с законодательством о защите данных.

Итоги темы

Система доменных имён — распределённая иерархическая база данных, отвечающая на вопрос «что известно об этом имени». Иерархия имён позволяет распределить управление: дерево разрезано на зоны, каждая из которых ведётся своим владельцем на своих авторитетных серверах, а связь между зонами устанавливается делегированием — записями NS и связующими записями в родительской зоне. Вершину иерархии обслуживают 13 логических корневых серверов, размноженных с помощью anycast на более чем полторы тысячи экземпляров.

Разрешение имени выполняет рекурсивный резолвер, который по направлениям спускается от корня к авторитетному серверу нужной зоны. Масштаб системы обеспечивается кешированием: каждая запись снабжена сроком жизни, и большинство запросов обслуживается из кеша, а отрицательные ответы кешируются на срок, заданный записью SOA. Со стороны клиента в разрешении участвует целый стек: приложение, библиотека с nsswitch.conf и /etc/hosts, локальная служба вроде systemd-resolved и, наконец, резолвер, адрес которого получен по DHCP.

Сообщение DNS имеет компактный двоичный формат: 12-байтовый заголовок с флагами и четыре секции записей, имена в которых сжимаются указателями. Основной транспорт — UDP с исторически ограниченным размером ответа; расширение EDNS(0) поднимает предел, а при усечении клиент переходит на TCP. Шифрование канала DoT, DoH и DoQ защищает запросы от наблюдателя на пути к резолверу, DNSSEC — подлинность данных от подделки, в том числе от отравления кеша, которое в форме атаки Каминского показало слабость 16-битного идентификатора. Минимизация QNAME уменьшает утечку сведений к серверам верхних уровней.

DNS — не только справочник, но и инструмент управления трафиком: от него зависят балансировка нагрузки, работа CDN и выбор протокола подключения через записи HTTPS. Почти каждое действие в Вебе начинается с DNS-запроса и продолжается HTTP-запросом к полученному адресу. Протокол HTTP, его версии HTTP/2 и HTTP/3 и транспорт QUIC рассматриваются в следующей теме.

Литература

  1. Mockapetris P. Domain Names — Concepts and Facilities. — RFC 1034, IETF, 1987. https://www.rfc-editor.org/rfc/rfc1034
  2. Mockapetris P. Domain Names — Implementation and Specification. — RFC 1035, IETF, 1987. https://www.rfc-editor.org/rfc/rfc1035
  3. Elz R., Bush R. Clarifications to the DNS Specification. — RFC 2181, IETF, 1997. https://www.rfc-editor.org/rfc/rfc2181
  4. Andrews M. Negative Caching of DNS Queries (DNS NCACHE). — RFC 2308, IETF, 1998. https://www.rfc-editor.org/rfc/rfc2308
  5. Damas J., Graff M., Vixie P. Extension Mechanisms for DNS (EDNS(0)). — RFC 6891, IETF, 2013. https://www.rfc-editor.org/rfc/rfc6891
  6. Dickinson J., Dickinson S., Bellis R., Mankin A., Wessels D. DNS Transport over TCP — Implementation Requirements. — RFC 7766, IETF, 2016. https://www.rfc-editor.org/rfc/rfc7766
  7. Arends R., Austein R., Larson M., Massey D., Rose S. DNS Security Introduction and Requirements. — RFC 4033, IETF, 2005. https://www.rfc-editor.org/rfc/rfc4033
  8. Arends R., Austein R., Larson M., Massey D., Rose S. Protocol Modifications for the DNS Security Extensions. — RFC 4035, IETF, 2005. https://www.rfc-editor.org/rfc/rfc4035
  9. Hu Z., Zhu L., Heidemann J., Mankin A., Wessels D., Hoffman P. Specification for DNS over Transport Layer Security (TLS). — RFC 7858, IETF, 2016. https://www.rfc-editor.org/rfc/rfc7858
  10. Hoffman P., McManus P. DNS Queries over HTTPS (DoH). — RFC 8484, IETF, 2018. https://www.rfc-editor.org/rfc/rfc8484
  11. Huitema C., Dickinson S., Mankin A. DNS over Dedicated QUIC Connections. — RFC 9250, IETF, 2022. https://www.rfc-editor.org/rfc/rfc9250
  12. Hubert A., van Mook R. Measures for Making DNS More Resilient against Forged Answers. — RFC 5452, IETF, 2009. https://www.rfc-editor.org/rfc/rfc5452
  13. Bortzmeyer S., Dolmans R., Hoffman P. DNS Query Name Minimisation to Improve Privacy. — RFC 9156, IETF, 2021. https://www.rfc-editor.org/rfc/rfc9156
  14. Schwartz B., Bishop M., Nygren E. Service Binding and Parameter Specification via the DNS (SVCB and HTTPS Resource Records). — RFC 9460, IETF, 2023. https://www.rfc-editor.org/rfc/rfc9460