DNS Google больше не поддерживает Round Robin DNS / Southbridge corporate blog / Habr
Раньше, когда надо было распределить нагрузку на несколько серверов, мы прописывали несколько A-записей с одним именем в DNS-зоне, и все работало. Запросы клиентов распределялись примерно поровну. Особенно актуален такой способ балансировки был для раздачи статитического контента.
Недавно наш клиент обратился к нам с проблемой:
В ЧНН начинались проблемы с загрузкой различных флешек — файлы загружались по несколько минут.
Расследование выявило неравномерную загрузку одного из серверов раздачи статики — он отдавал в разы больше трафика в сеть, чем все остальные. Причем периодически нагрузка переходила от одного сервера к другому.
В DNS зоне было прописано что-то типа:
cdn.exampe.com IN A 192.168.10.1 cdn.exampe.com IN A 192.168.12.1 cdn.exampe.com IN A 192.168.15.1 cdn.exampe.com IN A 192.168.16.1 cdn.exampe.com IN A 192.168.11.1 cdn.exampe.com IN A 192.168.19.1
Раньше клиенты получали ответы от DNS-серверов по алгоритму round-robin, но поиск проблемы привел к совершенно неожиданному результату!
Запросы к DNS серверу по адресу 8.8.8.8 неизменно возвращали один и тот же адрес.
Никакого round-robin. Возвращаемый адрес мог смениться, если заканчивался TTL, а мог и не измениться.
Техподдержка корпорации добра ответила в стиле «мы лучше вас знаем, что именно вам надо».
DNS Round Robin has never been an effective means of load-balancing, and is less so today, as applications switch from gethostbyname to getaddrinfo for IPv6 support:homepage.ntlworld.com/jonathan.deboynepollard/FGA/dns-round-robin-is-useless.html
www.tenereillo.com/GSLBPageOfShame.htm
daniel.haxx.se/blog/2012/01/03/getaddrinfo-with-round-robin-dns-and-happy-eyeballs
RRDNS никогда хорошо не работало, а дальше будет еще хуже. И когда наступит IPv6, станет совсем плохо…
Вот такое мнение у корпорации добра, и никакие графики нагрузки переубедить ее не смогли.
Дальнейшее расследование проблемы показало, что проблема не только в Google, но и в Hetzner, в котором хостится зона.
Проблема номер раз:
Каждый из гугло-серверов передает ответы точно такими же, какими получил от DNS-серверов, обслуживающих зону, ничего не изменяя в них. Если каждый из серверов получает свой вариант последовательности, то при последовательных запросах складывается впечатление, что Google отдает адреса в случайном порядке, хотя на самом деле это ответы отдаются со случайно выбранного сервера.
Проблема номер два:
Хетцнер, в котором хостится проблемная DNS-зона, начал отдавать список адресов для хоста неизменным.
И в итоге на всех гугло-серверах оказалась одинаковая последовательность адресов.
Ответ от ТП Hetzner также не порадовал:
This function is not enabled on our DNS-resolvers. If you want to use that kind of loadbalancing, you have to setup and use your own servers.
Конечно, можно обратиться к платным поставщикам услуг CDN или сказать программистам, чтобы они генерировали ссылки на контент, которые указывают на конкретные сервера (естественно, для каждого запроса сервер в ссылке берется случайным образом, чтобы распределить нагрузку).
А уже потом можно будет поискать решение получше.
Возвращаем редирект на конкретный сервер средствами nginx:
Воспользуемся директивой split_clients, распределим проценты согласно мощности наших серверов и пропишем на каждом из них вот такой конфиг.
Естественно, в строке hostname cdn1.example.com; указываем свое уникальное имя для каждого из серверов.
http {
split_clients "${remote_addr}AAA" $variant {
15% 1;
15% 2;
15% 3;
15% 4;
15% 5;
15% 6;
* 7;
}
server {
listen 80;
server_name cdn.example.com;
return 302 http://cdn$variant.example.com/$request_uri;
}
server {
listen 80;
server_name cdn1.example.com;
location / {
root /srv/www/cdn.example.com/htdocs;
}
}
В итоге nginx возвращает пользователю редиректы на сервер, который определяется на основании хеша ip адреса клиента.
Вот такое вот распределение нагрузки.
PS: Перевели зону с Хетцнера в Яндекс
DNS балансировка
DNS сервер — это первый узел, который принимает запрос от посетителя и возвращает IP-адрес приложения. После этого браузер посетителя посылает HTTP запрос на сервер приложения и получает ответ.
IP адрес указывается в A записи домена, например так:
ruhighload.com IN A 188.226.228.90
Обычно указывается одна А запись, следовательно DNS всегда возвращает один и тот же IP адрес. Однако существует возможность изменять отдаваемый IP адрес. Это позволяет направлять разных посетителей на разные сервера с одного домена.
Round Robin
DNS позволяет указывать более одного IP адреса в А записях:
ruhighload.com IN A 188.226.228.90
ruhighload.com IN A x.x.x.x
ruhighload.com IN A y.y.y.y
В этом случае, разные клиенты будут получать разные IP адреса при обращении к нашему домену. Это позволит распределить нагрузку между несколькими серверами, которые обслуживают приложение. Round Robin предполагает, что IP адреса будут выдаваться по очереди (сначала первый, потом — второй и т.п.). Однако, это нигде не стандартизировано, поэтому не стоит на это полагаться.
IP адреса доменов кэшируются в локальных DNS’ах. При выходе из строя одного из серверов, будет длительная задержка перед тем, как обновятся все кэши. Поэтому схема Round Robin должна использоваться совместно с механизмами обеспечения отказоустойчивости.
Устанавливайте небольшой ttl для А записей, чтобы иметь возможность быстро их изменять. Оптимальные значения — несколько минут.
Geo DNS
DNS сервера также позволяют отдавать разные IP адреса для клиентов на основе их местоположения. Это очень полезно для сайтов с высоким разбросом географии посетителей.
Допустим у Вас есть существенное количество посетителей из США и Европы, а сервер приложения находится только в Европе. Тогда будет полезно сделать копию сервера в США. При обращении посетителей из США, отправлять их на сервер в США. Из Европы — на сервер в Европе.
Эту возможность используют при построении CDN.
Bind GeoDNS
...
view "usa" {
match-clients { country_US; country_CA; country_MX; };
recursion no;
zone "ruhighload.com" {
type master;
file "pri/ruhighload.usa.db";
};
};
view "other" {
match-clients { any; };
recursion no;
zone "ruhighload.com" {
type master;
file "pri/ruhighload.other.db";
};
};
Самое важное
Используйте DNS Round Robin для распределения нагрузки между несколькими серверами. Устанавливайте небольшой ttl, а также ознакомьтесь с балансировкой нагрузки на фронтенды.
#dns ID: 155
разделенная DNS (Split DNS) в инфраструктуре 3CX Phone System / 3CX Ltd. corporate blog / Habr
Введение
Для корректной работы 3CX Phone System рекомендуется настроить и использовать так называемую разделенную DNS (Split DNS). Split DNS единообразно представляет сетевые имена узлов (FQDN) во внутренней и внешней сети. Иными словами, сервер 3CX Phone System будет доступен в частной и публичной сети по единому FQDN имени. Такой подход предоставляет ряд преимуществ:
- обеспечивает единообразную настройку внутренних и внешних подключений к серверу
- ускоряет перерегистрацию пользователя при переходе из внутренней во внешнюю сеть и наоборот
- позволяет создать одинаковую конфигурацию для внутренних и внешних пользователей 3CXPhone
- позволяет администрировать систему, просматривать отчеты и слушать записи разговоров, независимо от расположения пользователя
- позволяет указывать в IP телефонах единый URL автонастройки, независимо от их расположения
Для успешной настройки Split DNS необходимо соблюдение ряда условий:
- создание самоподписанного SSL сертификата, либо приобретение доверенного сертификата у аккредитованной компании
- наличие зарегистрированного доменного имени у доменного регистратора
- наличие статического IP адреса
- в вашей внутренней сети должен работать DNS сервер. Это может быть DNS на базе Windows Server или DNS сервер, реализованный в сетевом экране.
Рекомендуется создавать Split DNS до установки сервера 3CX Phone System.
Split DNS создается в два этапа:
- Настраивается DNS зона на публичном DNS сервере у регистратора вашего доменного имени – публичное FQDN имя сервера 3CX Phone System
- Создается аналогичная зона на внутреннем DNS севере – частное FQDN имя сервера 3CX Phone System
Публичное FQDN имя сервера
Покажем настройку публичного имени сервера на примере регистратора EuroDNS. Для других регистраторов процедура принципиально не отличается.
- Зайдите в свою учетную запись
- Перейдите в Control Panel > Zone Profiles
- Нажмите Add Zone Profile
- Нажмите Rename Zone Profile и присвойте профилю имя. В этом примере мы использовали example.com. Нажмите Rename, чтобы сохранить имя профиля
- Нажмите Add DNS Record и в меню выберите A (IPv4 Address)
- В поле Host укажите желаемое имя сервера. В нашем примере это pbx
- В поле IP Address V4 укажите публичный IP адрес вашего сервера 3CX Phone System
- Поле TTL оставьте по умолчанию 3600
- Для сохранения настроек нажмите ✓. A-запись (ваше FQDN имя сервера) pbx.example.com будет создана. Через некоторое время, которое может занять до 24 часов, ваше публичное FQDN имя сервера будет преобразовываться в публичный IP адрес.
Чтобы протестировать корректность настройки публичного FQDN имени, в командной строке введите nslookup pbx.example.com. Команду нужно выполнять на компьютере, находящемся во внешней сети. В ответ вы должны получить внешний IP адрес сервера 3CX.
Частное FQDN имя сервера
Покажем, как настроить частное FQDN имя на DNS сервере, расположенном во внутренней сети вашей компании. Пример основан на DNS сервере Windows 2012 R2 и предполагает, что сервер настраивается с нуля.
Включение роли DNS
- Запустите Server Manager
- В правом верхнем углу окна Server Manager нажмите Manage и из выпадающего меню выберите Add Roles and Features
- В окне мастера Add Roles and Features Wizard нажмите Next
- Оставьте опцию по умолчанию Role-based or feature-based installation и нажмите Next
- Выберите сервер, которому нужно назначить новую роль и нажмите Next
- В списке выберите DNS Server. В появившемся диалоговом окне оставьте значения по умолчанию, нажмите Add Features и Next
- На странице Features нажмите Next
- На странице DNS Server нажмите Next
- Нажмите Install
- По окончании установки нажмите Close
После добавления роли DNS сервера создайте Split DNS зону и записи в ней.
Добавление новой зоны
Новая зона создается в оснастке Server Manager:
- В правом верхнем углу оснастки выберите Tools и в выпадающем меню DNS
- Откроется DNS manager. Кликните правой кнопкой мыши по имени сервера и выберите New Zone…
- В мастере New Zone Wizard нажмите Next
- Оставьте Primary zone по умолчанию и нажмите Next
- Выберите Forward lookup zone и нажмите Next
- Укажите имя зоны, в нашем примере, example.com, и нажмите Next
- На странице Zone File оставьте параметры по умолчанию и нажмите Next
- На странице Dynamic Update оставьте параметры по умолчанию, нажмите Next и Finish
Добавление нового хоста
Вновь созданная зона появится в разделе Forward Lookup Zones:
- Кликните правой кнопкой мыши по созданной зоне и выберите New Host (A or AAAA)…
- Укажите имя хоста, в нашем примере, pbx
- Укажите частный (локальный) IP адрес сервера 3CX Phone System
- Нажмите Add Host. Появится сообщение о том, что запись pbx.example.com создана. Нажмите OK и Done
Именно это FQDN имя вы указываете во время инсталляции сервера 3CX Phone System в разделе FQDN.
Чтобы протестировать корректность настройки частного FQDN имени, в командной строке введите nslookup pbx.example.com. Команду нужно выполнять на компьютере, находящемся во внутренней сети. В ответ вы должны получить внутренний IP адрес сервера.
Split DNS создана. С этого момента 3CX Phone System будет использовать единое FQDN имя в публичной и частной сети.
Возможные проблемы
В зависимости от используемого типа DNS сервера, вы можете столкнуться с тем, что другие ваши хосты, например, веб сервер www.example.com, станут недоступны из внутренней сети. Это связано с тем, что ваш локальный DNS сервер начнет использовать внутреннюю DNS зону, а не перенаправлять запросы локальных клиентов на внешний DNS сервер. В этом случае необходимо продублировать во внутренней DNS зоне A записи всех хостов, находящихся во внешней DNS зоне. A запись должна содержать доменное имя хоста и его публичный IP адрес.
Дополнительная информация
Как послать провайдера подальше, и включить DNS по HTTPS в любом браузере / Habr
Поддержка DoH уже встроена во все основные браузеры. Пользователям нужно её только включить и настроить.
Все шесть производителей основных браузеров планируют поддерживать протокол DNS по HTTPS (DoH), шифрующий DNS-трафик и помогающий усилить конфиденциальность пользователя в сети.
Этот протокол является одной из самых обсуждаемых тем этого года. Он позволяет браузеру прятать DNS-запросы и ответы внутри обычного на первый взгляд HTTPS-трафика.
Это делает DNS-трафик пользователя невидимым для сторонних наблюдателей за сетью, например, провайдеров. Однако если пользователи обожают DoH и считают его благом для конфиденциальности, провайдеры и производители средств кибербезопасности его ненавидят.
Британский провайдер назвал Mozilla «интернет-злодеем» за планы компании по внедрению DoH, а группу лоббистов от Comcast уличили в подготовке документа касательно DoH, который они планируют представить законотворцам Британии, надеясь предотвратить более широкое распространение протокола.
Однако, время уже может быть упущено. Редакция в течение недели связалась с производителями основных веб-браузеров, чтобы узнать об их будущих планах касательно DoH, и все они планируют внедрять протокол в том или ином виде.
Как включить DoH в любом браузере
Вот, что нам известно на сегодня по поводу планов производителей браузеров, связанных с DoH, и о том, как пользователи могут включить DoH в любом браузере.
Brave
«Мы очень хотим реализовать его», — сказал нам Том Лоуэнталь, менеджер продукта из Brave for Privacy & Security.
Однако у команды Brave пока нет точных сроков внедрения DoH. Они занимаются другими улучшениями, связанными с приватностью. К примеру, на этой неделе компания выпустила обновление, улучшающее распознавание скриптов, отслеживающих действия пользователей. На горизонте маячит версия Brave 1.0, и команде нужно сконцентрироваться на её выходе. Но DoH в Brave будет.
«Реализация DoH – это гораздо больше, чем простая техническая задача. Нам нужно решить, какие разумные и защитные установки мы можем включить по умолчанию для большинства людей, не задумывающихся о настройке DNS – но так, чтобы мы ничего не сломали у тех людей и организаций, что тщательно подошли к подстройке своих программ», — сказал Лоуэнталь.
Поскольку Brave основан на открытом проекте Chromium, в нём есть поддержка DoH. Однако команда пока не настроила эту поддержку. В коде она есть, но включается так, как это придумала команда авторов Google Chrome. Включить DoH в Brave можно, перейдя на следующий URL:
brave://flags/#dns-over-https
Chrome
Google Chrome стал вторым браузером после Firefox, добавившим поддержку DoH. Её можно включить, перейдя по следующему URL:
chrome://flags/#dns-over-https
По-умолчанию DoH не включено для всех. Сейчас Google проводит ограниченный эксперимент с небольшим количеством пользователей, чтобы проверить, как DoH покажет себя при реальном использовании.
Поддержка DoH в Chrome отличается от Firefox, по-умолчанию перенаправляющего DoH-трафик на Cloudflare. Браузер после включения протокола будет отправлять DNS-запросы на всё те же сервера, что и ранее. Если у выбранного сервера окажется интерфейс с поддержкой DoH, тогда Chrome зашифрует DNS-трафик и отправит его на тот же DNS-сервер по протоколу DoH.
Благодаря этому Chrome не перехватывает DNS-настройки ОС – это очень ответственный подход, поскольку браузер может использоваться в условиях больших предприятий.
На текущий момент DoH в Chrome работает так:
- Пользователь вводит URL сайта в браузере.
- Chrome получает данные по DNS-серверу ОС.
- Он проверяет, есть ли этот сервер в белом списке одобренных серверов с поддержкой DoH.
- Если да, Chrome отправляет зашифрованный DNS-запрос на интерфейс этого сервера.
- Если нет, Chrome отправляет обычный DNS-запрос к этому серверу.
Поэтому у пользователя существует риск так и не воспользоваться протоколом DoH. ОС пользователя обычно получает настройки DNS от авторитетного сетевого центра, коим обычно выступает провайдер. Если провайдер не хочет использовать DNS с поддержкой DoH, то у вас это и не будет работать.
Однако есть два способа обойти это и заставить Chrome использовать DoH постоянно и вне зависимости от настроек DNS вашего провайдера.
Во-первых, можно воспользоваться обучающим материалом по принудительному включению поддержки DoH в Chrome. Во-вторых, пользователь может настроить DNS-сервер с поддержкой DoH в своей ОС. Его можно выбрать из списка, и это гарантированно будет работать в Chrome.
Edge
В следующем году Microsoft планирует выпустить новую версию браузера Edge на основе кода Chromium. Представитель Microsoft сообщил нам, что компания поддерживает DoH, но точные планы не раскрывает. Однако, версия Edge на основе Chromium уже поддерживает DoH. Её можно включить, перейдя по URL:
edge://flags/#dns-over-https
Это включит поддержку DoH, но она будет работать только, если ваш компьютер использует DNS с поддержкой DoH – чего в 99% случаев не происходит. Чтобы принудительно включить DoH в Edge, вы можете воспользоваться инструкцией из следующего поста в блоге одного из программистов Edge. Адрес сервера Cloudflare можно заменить на любой другой сервер DoH, который можно выбрать по ссылке. После соответствующей настройки, Edge способен работать с DoH.
Firefox
Mozilla стала пионером этого протокола совместно с Cloudflare. Поддержка DoH уже есть в стабильных версиях Firefox. Её можно включить в настройках в разделе «Настройки сети».
Все критикуют реализацию DoH в Firefox потому, что браузер по умолчанию использует Cloudflare, перезаписывая настройки DNS.
Однако это значение можно поменять, прописав любой сервер с DoH. Из всех браузеров, поддержка протокола в Firefox реализована лучше всего, а настроить её легче всего – в основном потому, что разработчики имели с ней дело дольше остальных.
Сейчас браузер уже включает поддержку DoH по умолчанию для всех пользователей США. Поскольку британское правительство возражает против этого, для британских пользователей эта поддержка по умолчанию включена не будет.
В прошлом Mozilla не гарантировала включение DoH по умолчанию в других странах. Однако, поскольку поддержка протокола уже есть в стабильной версии браузера, пользователю остаётся лишь включить её, и всё будет работать.
Opera
Opera уже встроила поддержку DoH. По умолчанию она выключена, но её можно включить в любой момент, и всё будет работать без дополнительных шагов.
Разработчики Opera используют модуль для работы с DoH сходный с тем, что используется в Firefox, и не оставляют всё на откуп провайдерам, как Chrome. Весь трафик браузера сейчас идёт через резолвер 1.1.1.1 от Cloudflare.
Мы не нашли способа поменять его на другой, но, по крайней мере, DoH в Opera работает. Однако работать с VPN он не будет – если вам нужен DoH, то его придётся отключить.
Чтобы включить DoH в Opera, зайдите сюда:
opera://flags/opera-doh
Safari
Нет данных. Разработчики Safari обычно опаздывают на все вечеринки по добавлению новых возможностей, а Apple недавно вкладывалась в конфиденциальность пользователей, поэтому есть все шансы, что у Safari появится поддержка DoH.
Vivaldi
Представитель Vivaldi сказал, что поддержка DoH связана с реализацией Chrome. Пользователи могут включить её, перейдя по следующему URL:
vivaldi://flags/#dns-over-https
Однако поскольку DoH в Vivaldi работает так же, как в Chrome, он не будет шифровать DNS-запросы, если пользователь использует DNS-сервер, указанный в ОС, и не поддерживающий шифрование.
Скорее всего, придётся добавить в настройки DNS вашей ОС один из серверов, поддерживающий DoH, чтобы эта функция заработала в Vivaldi, и использовать его постоянно. Мы смогли добиться этого, прописав в настройках DNS-сервер 1.1.1.1.
Представитель Vivaldi сказал, что в будущем поддержка DoH в браузере может поменяться, в зависимости от того, как Google будет изменять поддержку протокола в Chromium.
Настройка EDNS0 в Windows Server
Привет.
Протокол DNS существует очень давно – с самой зари Интернета – и за время своего бытия оброс множеством дополнительных расширений и дополнений. Про одно из них – EDNS – мы и поговорим сегодня.
Я предполагаю, что на начало чтения статьи Вы знакомы с работой DNS и профильной терминологией хотя бы на уровне базового курса Microsoft 20410D. Настройки буду делать на Windows Server 2012 R2 со всеми патчами – хотя все эти опции идентично работают и реализуемы начиная с Windows Server 2008 R2, а некоторые и ещё раньше. Для настроек буду использовать ATcmd последней версии – Вы можете использовать как эту утилиту, так и любой другой способ/инструмент; способ выполнения действий некритичен.
Настройка EDNS0 в Windows Server
- Что такое и зачем нужен EDNS0
- Тестим EDNS0 с нашего хоста, используя nslookup
- Тестим EDNS0, используя автоматизированную утилиту ATcmd
- Включаем EDNS0 на Windows Server
- Настраиваем максимальный размер датаграммы EDNS0 на Windows Server
- Таблица поддержки EDNS0 у других серверов: настраиваем
- Если наш сервер не поддерживает новые расширения DNS
- Что внутри у OPT-поля
Что такое и зачем нужен EDNS0
Механизм DNS, спланированный и стандартизированный к 1987 году (RFC 1035), безусловно, не мог на момент создания учитывать все перспективные изменения в требованиях, использовании, безопасности и прочем, что неразрывно связано с развитием сети Интернет. Изначально возможностей расширения было заложено в него крайне немного (разве что свои типы RR), поэтому вполне логично, что со временем появилась необходимость в его расширении. EDNS0, появившийся в 1999 году (через 12 лет после стандартизации DNS, RFC 2671), был призван решить этот вопрос, с чем неплохо справляется до сегодняшнего дня – правда, вместо превращения в EDNS1 (драфт которого в природе есть, но вообще не особо кому-то нужен), начал развиваться в ширину, обрастая опциями и применениями – RFC 6891 – но данный процесс для рабочего стандарта вполне нормален.
Что же добавляет EDNS0? В принципе, основным нововведением в нём является добавление нового типа псевдо-записи – OPT. Это специфичный тип RR-записи, которая не несёт DNS-данные (поэтому и “псевдо”), а нужна исключительно для стандартизации обмена служебной информацией. В подавляющем большинстве случаев использования в ней передаётся один блок информации – запись о максимальном обрабатываемом размере DNS-датаграммы.
Данный пункт действительно является важнейшим по простой причине – так как на момент разработки DNS сети были ещё очень медленные, а также в них было множество устаревших на данный момент протоколов канального уровня (сильно различавшихся технически и логически), то датаграмма DNS, в целях повышения её выживаемости в ходе путешествия по Интернету, ограничена размером в 512 байт (чтобы вместе с заголовками транспортного и сетевого уровня не первышать 576 байт). По сути, всё сделано для того, чтобы датаграмма выжила в среде с самым мелким MTU и без поддержки фрагментации. Понятное дело, что в современной ситуации, когда в DNS-ответ может быть добавлена пачка адресов (одно имя теперь часто, для отказоустойчивости, разрешается в несколько адресов сетевого уровня), притом крупных в плане занимаемого места – например, IPv6, ну и всякие дополнительные данные, например DNSSEC’овские RRSIG и DSKEY, да или просто TXT, такое ограничение (“не более 512 байт DNS-данных а то вдруг не дойдёт”) крайне неудобным.
Неприятностей добавляет простая проблема, исходящая из природы UDP – дело в том, что в случае отправки запроса или ответа отправитель, в случае тишины после, никак не сможет понять, что произошло – был ли пакет потерян по случайной причине, или отброшен промежуточным узлом по причине несоответствия максимальному размеру MTU, или потерялся по причине необходимости фрагментации на каком-то отрезке пути, а фрагментация DNS-пакета не получилась, или какой-либо другой. Плюс не надо забывать, что датаграммы от клиента к серверу, а после – в обратном направлении, совершенно необязательно будут идти по одной и той же трассе. В результате возможно множество различных неприятных ситуаций, вида “клиент отправил запрос серверу – сервер отработал, отправив ответ – ответ не дошёл, потому что великоват в части MTU, а клиент ошибочно думает, что сервер технически недоступен”, или “сервер отправил запрос другому серверу – запрос не дошёл, потому что тот сервер не поддерживает EDNS0 – клиент, изначально отправивший запрос, предполагает, что ближайший к нему сервер не работает, т.к. прошёл тайм-аут ожидания ответа”, и многих других. Поэтому понимание и представление о том, как всё это работает, резко помогает понять множество “странных багов DNS”.
Давайте попробуем протестировать работу EDNS0.
Тестим EDNS0 с нашего хоста
Чтобы проверить работоспособность EDNS0, необязательно быть DNS-сервером. Это можно сделать и при помощи утилиты nslookup.
Первым делом – запустим nslookup и скажем, что нас будут интересовать только ответы TXT-типа. Это просто:
set type=TXT
Теперь запросим (я предполагаю, что Ваш nslookup уже нацелен на тот сервер, который Вы хотите тестировать – если нет, то настройте его явно командой server
) специальный хост – rs.dns-oarc.net
. В качестве ответа Вы должны получить что-то вида:
или
Изучим. По сути, каждый из ответов состоит из 6 строк, три последних из которых явно говорят, когда и откуда проводился тест, а также какой максимальный размер EDNS0-датаграммы заказывался. Хорошо заметно, что источником запроса является провайдерский сервер – т.е. тестовый сервер, который rs.dns-oarc.net
, фактически тестирует возможность отправки EDNS0-датаграмм до узла 218.77.159.18, являющегося адресом DNS-сервера провайдера – я даже, благодаря специфике китайской сети, в которой нахожусь, точно не могу сказать, где он, но где-то недалеко:
Теперь про первые три строки в ответе rs.dns-oarc.net
. Они, по сути, отображают цепочку CNAME вида rst.xAAAA.rs.dns-oarc.net -> rst.xBBBB.xAAAA.rs.dns-oarc.net -> rst.xCCCC.xBBBB.xAAAA.rs.dns-oarc.net, где AAAA BBBB CCCC – это размеры, в байтах, удачно обработанных DNS-ответов. По сути, это некое “пингование” EDNS0-запросами с игрой внутри RR OPT, по аналогии с пингом пакетами с запрещённой фрагментацией с целью методом проб и ошибок выяснить PMTU. На картинках заметно, что размер плавает очень сильно – так бывает в провайдерских сетях, где не всё настроено однотипно. В моём случае оба ответа, в общем, плохие – хорошим считается ответ, где будет показано, что отработала датаграмма в 4К. Очень плохим будет вариант, когда нет ни одного ответа более 1.4К – это значит, что где-то на пути банально не работает фрагментация и всё, что не влезает в стандартный MTU ethernet’а, не выживает – так что у меня просто плохо, а не очень.
Теперь попробуем тестировать более цивилизованным способом.
Тестим EDNS0, используя автоматизированную утилиту ATcmd
Для упрощения тестирования в ATcmd есть диагностический контекст – test, в котором поддерживается несколько типовых сценариев опроса DNS-серверов на предмет поддержки EDNS0:
Это режим local, когда утилита автоматически тестирует все DNS-сервера данного хоста, режим прямого указания одиночного IP-адреса сервера и режим, когда указывается FQDN домена Active Directory – и утилита последовательно подключается к NS-серверам и тестирует их. Данный режим очень удобен для больших предприятий, и позволяет увидеть работоспособность EDNS-обмена с различными серверами с точки зрения конкретного хоста.
В общем, думаю, Вы оценили количество потенциальных проблем, которые будут, если оставить данный вопрос на самотёк – поэтому пора приступать к настройкам работы EDNS0 в сети предприятия.
Включаем EDNS0 на Windows Server
Включение механизма EDNS0 не так очевидно, как кажется. Первое, что надо отметить – Ваш сервер, если это Windows Server 2003 и выше, умеет принимать и обрабатывать EDNS0-ответы – т.е. не пугается ни бОльшего размера датаграммы, ни наличия специфичной OPT-записи. А начиная с Windows Server 2008 R2, механизм EDNS включен по умолчанию. Включать же мы будем, фактически, добавление в запросы другим DNS-серверам дополнительной “тестовой” OPT-записи. Цель – чтобы по их ответу на этот запрос было понятно, поддерживают они EDNS0 или нет.
Для включения этого механизма, EDNS Probes, да и вообще работы с EDNS, у нас будет специальный субконтекст – edns:
Включим механизм командой ednsprobes
:
Совет по части этого параметра будет простым – включайте его со стороны своего сервера только убедившись, что “большие” EDNS-ответы технически могут добраться до него снаружи. Ключевое – разница между “наш сервер поддерживает и декларирует остальным серверам, что умеет” и “технически возможно прохождение датаграммы бОльшего размера, чем 576 байт”. Плохо, если Ваш сервер будет всем показывать, что может, но отправляемые ему датаграммы будут теряться, не доходя до него.
Настраиваем максимальный размер датаграммы EDNS0 на Windows Server
По стандарту EDNS0 мы добавляем в каждую DNS-датаграмму специальную RR, которая имеет тип OPT – добавляем в любое место, и только один раз. В этой RR и содержится информация о том, датаграммы какого размера мы можем “переваривать”. Понятное дело, что просто так выставлять этот параметр большИм не имеет смысла и даже вредно – в начале статьи мы выясняли, что фактический размер успешно принимаемой датаграммы зависит, скорее, не от нашего сервера, а от форвардера. Поэтому имеет смысл декларировать такой размер, который проверен экспериментально – я выставлю удвоенный размер стандартной DNS-датаграммы, 1280 байт (этот размер рекомендован в RFC 6891):
Замечу, что при комплексной настройке поддержки EDNS0 сетью, данный параметр, допустим, на сетевых устройствах, надо делать максимально возможным (рекомендуется 4096 байт). Их задача – просто не фильтровать “слишком большие пакеты”, поэтому не удивляйтесь, что корректная настройка будет выглядеть именно так – на промежуточных сетевых устройствах “чем больше, тем лучше”, а на конечном DNS-сервере – “только столько, сколько экспериментально доказано, что влезает, и не более”.
Таблица поддержки EDNS0 у других серверов: настраиваем
В памяти у каждого Windows DNS Server есть табличка, которая ведёт учёт – кто из других серверов поддерживает EDNS. Это нужно для оптимизации работы – ведь каждый раз выяснять перед форвардингом одиночного запроса клиента, поддерживает ли конкретный DNS-сервер EDNS или нет – и долго и накладно по трафику. Поэтому идея проста – если у нас работает механизм EDNS Probes, кэшируем результаты его работы в табличке, которую называем Remote Server Table. Она расположена в оперативной памяти и с её точки зрения у серверов будет 4 статуса:
- Unknown: поддержка EDNS не определена, стартовый статус у любого сервера-соседа в табличке.
- Not supported: EDNS в явном виде не поддерживается – мы ему тестовый пакет с OPT, он нам ответ без OPT в явном виде, и не более 576 байт в сумме.
- Ok: EDNS в явном виде поддерживается.
- Maybe not supported: Пока от этого сервера ни разу не было получено ответа, который можно разобрать (т.е. или ответов не было вообще, или они были malformed с точки зрения формата DNS).
Вот все статусы, кроме первого, будут держаться в табличке столько, сколько мы скажем в настройках параметра EDNS timeout. После истечения этого времени статус будет сброшен на Unknown и процесс определения поддерживаемости EDNS0 запустится снова.
Для настройки этого у нас есть параметр, который в современных ОС по умолчанию равен 15 минутам, называется он ednstimeout
. Мы выставим его в 86400 (это секунд в сутках), так как логично, что нет смысла слишком часто спрашивать у других серверов о том, поддерживается ли ими EDNS0 или нет:
Если наш сервер не поддерживает новые расширения DNS
Возможен такой вариант – наш сервер расположен за не управляемыми нами firewall’ами, которые в явном виде не любят, чтобы DNS-пакеты были больше 512 байт. Со своей стороны мы поддержку EDNS0 выключили и поэтому наши пакеты всегда нормально уходят наружу, но вот внешние сервера про такую особенность нашей сети не знают и пытаются присылать нам пакеты с дополнительными опциями. В случае, если наш сервер не понимает, что от него хотят, по умолчанию в нём включается механизм защиты от DoS-атаки “неправильными” DNS-запросами. Механизм работает просто – после приёма пакета, который не удаётся полностью обработать (допустим, в нём неизвестная RR), все другие запросы и ответы с IP-адреса, откуда пришёл этот пакет, не будут обрабатываться целую минуту. В общем-то, данный механизм иногда полезен – но чаще нет; например, если у большой организации на площадке у провайдера стоит свой DNS-сервер, который аккумулирует все форвардинги от внутренних серверов организации, и к нему придёт один такой запрос, то он откажется на минуту обрабатывать все запросы с этого же адреса, а в типовом сценарии этот адрес-источник – это адрес NAT-транслятора, за которым десятки, а то и сотни клиентов. В этом случае DoS сомнителен, и одиночный неправильный пакет можно и просто отбросить, отметив в логах, не останавливая обработку.
Для управления этим в Windows Server тоже есть опция – мы вынесли её в субконтекст EDNS. Выключим эту защиту, чтобы обработка запросов не останавливалась в случае разового malformed packet:
Что внутри у OPT-поля
Давайте посмотрим, что ещё полезного умеет делать EDNS, чтобы не запомнить случайно, что он может только декларировать максимальный обрабатываемый размер датаграммы.
У OPT RR есть двубайтовый заголовок, указывающий назначение OPT. Обычно используется нуль – именно в этой ситуации OPT несёт на себе информацию о максимальном размере датаграммы.
Единица и двойка заняты под черновики “невыстреливших” стандартов DNS Long-Lived Queries и DNS Update Leases, которые были призваны улучшить работу DNS, развивая механизм Service Discovery и улучшая работу динамических обновлений.
Тройка занята расширением NSID – описывается оно в RFC 5001, краткая суть применения – способ идентификации DNS-серверов в кластере (т.е. тот, кто работает с одним IP-адресом DNS-сервера, может добавить OPT RR с NSID и в ответ сервера добавят в таком же виде OPT RR с третьим кодом, где в payload напишут свои уникальные идентификаторы – например, реальные, а не кластерные IP-адреса). Этот стандарт, в отличии от предыдущей пары DNS-SD, принят.
Четвёрка в принципе не занята, но на неё претендует ещё один из механизмов DNS-SD – так называемый Sleep Proxy, механизм работы которого выглядит так – “пусть каждый сервер, который захочет вздремнуть в плане экономии электричества, вышлет на специальный сервер-будильник специальный EDNS-пакет, где укажет свой MAC, на который он готов принять пробуждающий сигнал Wake-on-Lan, и пароль для пробуждения, чтобы не будил кто попало”. Затейливая схема, притом застолблённая фирмой Apple (https://tools.ietf.org/html/draft-cheshire-dnsext-multicastdns-07), поэтому будем относиться к ней с осторожностью.
Значения с 5 до 7 используются новой модификацией DNSSEC (про связь DNSSEC и EDNS0 я напишу отдельно), решаемая задача – клиент, благодаря:
- OPT 5 – DNSSEC Algorithm Understood (DAU).
- OPT 6 – DS Hash Understood (DHU).
- OPT 7 – NSEC3 Hash Understood (N3U).
может информировать DNSSEC-сервер о том, какие алгоритмы он, клиент, поддерживает, что, в случае поддержки и кэширования этой информации на DNSSEC-сервере, во-первых резко снижает количество сбойных итераций (нет ситуации “отправляем клиенту всё слабее и слабее хэшированную запись, пока он не сможет переварить принятое”), от чего вырастает скорость работы, во-вторых снижает нагрузку на сервер.
Девятка в OPT отдана под новый стандарт RFC 7314, EDNS Expire, суть которого в том, чтобы помочь корректно отслеживать expire-таймеры в SOA-записях DNS-зон не только в случае двухуровневой иерархии, когда все secondary-сервера забирают зону с authoritative, но и когда существует граф secondary, забирающих зону у других secondary.
Остальные значения, с 10 по 65000 включительно, никак не обозначены – простор для расширений присутствует. В общем-то механизм действительно простой и удобный, поэтому, возможно, что-то ещё полезное сможет появиться в ближайшее время. Значения от 65001 до 0xFFFE будут, по сути, частными – можно свободно использовать их для своих локальных задач, либо каких-то экспериментальных. Например, Google использует их для работы механизма OPT Cookies. Ну а все единички – 0xFFFF – будут зарезервированны для будущих поколений.
Да, и ещё – есть перспективный стандарт по оптимизации работы цепочек DNS-форвардеров: https://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02, который развивают серьёзные парни из Google, Akamai и OpenDNS, но он уже тема для совсем другого разговора.
Заключение
Обычно изучение работы EDNS – например, на авторизованных курсах Microsoft – выглядит как упоминание на одном слайде, вида “это такая штука чтобы датаграммы больше были”. Остальное – почему, зачем, как применять, как тестировать, как анализировать работу, как связано с DNSSEC – остаётся в стороне. Надеюсь, что этой краткой экскурсией в данную технологию, количество “белых пятен” было немножко уменьшено.
Удач!
Дата последнего редактирования текста: 2014-12-16T10:46:24+08:00
Возможно, вам будет также интересно почитать другие статьи про DNS на нашей Knowledge Base
Google Public DNS тихо включили поддержку DNS over TLS / Habr
Внезапно, без предварительного анонса, на 8.8.8.8 заработал DNS over TLS. Ранее Google анонсировал только поддержку DNS over HTTPS.
Публичный резолвер от компании CloudFlare с IP-адресом 1.1.1.1 поддерживает DNS over TLS с момента запуска проекта.
Зачем это нужно
При использовании классической схемы DNS, провайдеры могут лезть своими грязными лапами в ваши DNS-пакеты, просматривать, какие домены вы запрашиваете, и подменять ответы как угодно. Этим же занимаются мошенники, подменяя резолверы на взломанных роутерах, чтобы направить пользователя на поддельный сервер.
C DNS over TLS/HTTPS запросы посылаются внутри зашифрованного тоннеля так, что провайдер не может подменить или просмотреть запрос.
А с приходом шифрования имени домена в сертификатах X.509 (ESNI) станут невозможны блокировки через DPI по SNI (Server Name Indication, специальное поле, в котором передается имя домена в первом TLS-пакете), которые сейчас применяются у некоторых крупных провайдеров.
Как это работает
На порт TCP:853 выполняется TLS-подключение, при этом проверка сертификата резолвера происходит с использованием системных корневых сертификатов, точно так же, как HTTPS в браузере. Это избавляет от необходимости добавлять какие-либо ключи вручную. Внутри тоннеля выполняется обычный DNS-запрос. Это создает меньше накладных расходов по сравнению с DNS over HTTPS, который добавляет HTTP-заголовки к запросу и ответу.
К сожалению, на текущий момент только в Android 9 (Pie) поддержка DNS over TLS встроена в системный резолвер. Инструкция по настройке для Android 9.
Для остальных систем предлагается использовать сторонний демон, а системный резолвер направлять на localhost (127.0.0.1).
Настройка на macOS
Разберем настройку DNS over TLS на последней версии macOS, на примере резолвера knot
Установка
brew install knot-resolver
По умолчанию knot будет работать как обычный рекурсивный резолвер, подобно dnsmasq.
Редактируем конфиг
nano /usr/local/etc/kresd/config
И добавляем в конец файла:
policy.add(
policy.all(
policy.TLS_FORWARD({
{'8.8.8.8', hostname='8.8.8.8'},
{'8.8.4.4', hostname='8.8.4.4'}
})))
В итоге мой конфиг выглядит так:
Раскрыть спойлер
-- Config file example useable for personal resolver.
-- The goal is to have a validating resolver with tiny memory footprint,
-- while actively tracking and refreshing frequent records to lower user latency.
-- Refer to manual: https://knot-resolver.readthedocs.io/en/latest/daemon.html#configuration
-- Listen on localhost (default)
-- net = { '127.0.0.1', '::1' }
-- Drop root privileges
-- user('knot-resolver', 'knot-resolver')
-- Auto-maintain root TA
trust_anchors.file = 'root.keys'
-- Load Useful modules
modules = {
'policy', -- Block queries to local zones/bad sites
'hints', -- Load /etc/hosts and allow custom root hints
'stats', -- Track internal statistics
'predict', -- Prefetch expiring/frequent records
}
-- Smaller cache size
cache.size = 10 * MB
policy.add(
policy.all(
policy.TLS_FORWARD({
{'8.8.8.8', hostname='8.8.8.8'},
{'8.8.4.4', hostname='8.8.4.4'}
})))
Подробнее про hostname и проверку подлинности TLS-сертификатаПараметр
hostname
в данном случае — Common Name (CN) или Subject Alt Name (SAN) сертификата. То есть, доменное имя, для которого выпущен сертификат. По нему проверяется подлинность сертификата сервера.Вот какие значения SAN у сертификата, который используется при подключении на 8.8.8.8:853
dns.google
8888.google
8.8.4.4
8.8.8.8
2001:4860:4860:0:0:0:0:64
2001:4860:4860:0:0:0:0:6464
2001:4860:4860:0:0:0:0:8844
2001:4860:4860:0:0:0:0:8888
Любое из этих значений можно использовать в качестве параметра hostname. Если же вы будете разворачивать собственный публичный рекурсивный резолвер, у вас вряд ли получится выпустить X.509-сертификат на IP-адрес, поэтому в параметре hostname придется указывать доменное имя.
Запуск демона
sudo brew services start knot-resolver
Проверить, успешно ли запустился демон, можно командой:
sudo lsof -i -P -n | grep kresd
процесс kresd должен слушать порт 53 на localhost.
Если что-то пошло не так, смотрим лог ошибок:
cat /usr/local/var/log/kresd.log
Проверка работы резолвера
dig @127.0.0.1 habr.com
Проверяем, что локальный резолвер отвечает корректно.
Установка в качестве системного резолвера
Если все работает правильно, можно назначить системный резолвер в свойствах сетевого адаптера:
UPD
В чем разница между DNSCrypt, DNSSEC, DNS over TLS/HTTPS.
DNSCrypt может работать по UDP и TCP. Подключение на порт 443. Для шифрования используется собственный протокол, который отличается от HTTPS. Может быть легко выделен с помощью DPI. Это скорее черновик, который тестировали до внедрения DNS over TLS/HTTPS, так как он не имеет RFC, то есть не является официальным стандартом интернета. Вероятнее всего, в скором, времени он будет полностью вытеснен последними.
DNS over TLS (DoT) — TCP-подключение происходит на порт 853, внутри тоннеля передается обычный DNS-запрос. Провайдер видит, что это DNS запрос но не может в него вмешаться. При прочих равных, в DNS over TLS должно быть чуть меньше накладных расходов на каждый запрос, чем в over HTTPS.
DNS over HTTP (DoH) — TCP-подключение на порт 443, подобно обычному HTTPS. Внутри другой формат запроса, с HTTP-заголовками. Однако для провайдера такой запрос будет виден как обычное HTTPS-подключение. Полагаю, этот протокол был придуман на случай, когда DNS-запросы к чужим серверам будут заблокированы, чтобы маскировать под обычный веб трафик. А также, чтобы браузеры могли сами резолвить домены и не создавать при этом аномальный трафик.
По сути, DNS over HTTPS и over TLS — одно и то же, с немного отличающемся форматом запросов. Оба эти протокола приняты в качестве стандартов и имеют RFC. Вероятнее всего, в ближайшее время мы увидим массовое распространение их обоих.
DNSSEC — протокол цифровой подписи DNS-записей. Не имеет отношения к шифрованию, так как все запросы передаются в открытом виде. Может работать как по старому классическому протоколу DNS, то есть UDP/TCP на порту 53, так и внутри DNS over TLS/HTTPS. Целью DNSSEC является подтверждение подлинности DNS-записи. Владелец домена может добавить публичный ключ на корневые сервера своей доменной зоны и подписывать все записи на мастер NS-серверах. По сути, к каждой DNS записи, например, A-записи или MX-записи, добавляется еще одна запись типа RRSIG, содержащая подпись. Процедура валидации DNSSEC на рекурсивном резолвере позволяет установить, действительно эта запись была создана владельцем домена.
Более подробное сравнение всех протоколов dnscrypt.info/faq (абзац Other protocols)
Составляем DNS-запрос вручную / Habr
Об авторе. Джеймс Рутли — бэкенд-разработчик в компании Monzo.В этой статье мы изучим двочиный формат сообщений Domain Name Service (DNS) и напишем вручную одно сообщение. Это больше, чем вам нужно для использования DNS, но я подумал, что для развлечения и в образовательных целях интересно посмотреть, что находится под капотом.
Мы узнаем, как:
- Написать запросы DNS в двоичном формате
- Отправить сообщение в теле датаграммы UDP с помощью Python
- Прочитать ответ от DNS-сервера
Писать в двоичном формате кажется сложным, но в реальности я обнаружил, что это вполне доступно. Документация DNS хорошо написана и понятна, а писать мы будем маленькое сообщение — всего 29 байт.
DNS используется для перевода человекочитаемых доменных имён (таких как
example.com
) в машиночитаемые IP-адреса (такие как 93.184.216.34). Для использования DNS нужно отправить запрос на DNS-сервер. Этот запрос содержит доменное имя, которое мы ищем. DNS-сервер пытается найти IP-адрес этого домена в своём внутреннем хранилище данных. Если находит, то возвращает его. Если не может найти, то перенаправляет запрос на другой DNS-сервер, и процесс повторяется до тех пор, пока IP-адрес не будет найден. Сообщения DNS обычно отправляются по протоколу UDP.Стандарт DNS описан в RFC 1035. Все диаграммы и бóльшая часть информации для этой статьи взята в данном RFC. Я бы рекомендовал обратиться к нему, если что-то непонятно.
В этой статье мы используем шестнадцатеричный формат для упрощения работы с бинарником. Ниже я добавил краткое пояснение, как они переводятся друг в друга [1].
У всех сообщений DNS одинаковый формат:
+---------------------+ | Заголовок | +---------------------+ | Вопрос | Вопрос для сервера имён +---------------------+ | Ответ | Ресурсные записи (RR) с ответом на вопрос +---------------------+ | Authority | Записи RR с указанием на уполномоченный сервер +---------------------+ | Дополнительно | Записи RR с дополнительной информацией +---------------------+
Вопрос и ответ находятся в разных частях сообщения. В нашем запросе будут секции «Заголовок» и «Вопрос».
Заголовок
У заголовка следующий формат:
0 1 2 3 4 5 6 7 8 9 A B C D E F +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ID | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QDCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ANCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | NSCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ARCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
На этой диаграмме каждая ячейка представляет единственный бит. В каждой строчке 16 колонок, что составляет два байта данных. Диаграмма поделена на строки для простоты восприятия, но реальное сообщение представляет собой непрерывный ряд байтов.
Поскольку у запросов и ответов одинаковый формат заголовка, некоторые поля не имеют отношения к запросу и будут установлены в значение 0. Полное описание каждого из полей см. в RFC1035, раздел 4.1.1.
Для нас имеют значение следующие поля:
- ID: Произвольный 16-битный идентификатор запроса. Такой же ID используется в ответе на запрос, так что мы можем установить соответствие между ними. Возьмём AA AA.
- QR: Однобитный флаг для указания, является сообщение запросом (0) или ответом (1). Поскольку мы отправляем запрос, то установим 0.
- Opcode: Четырёхбитное поле, которое определяет тип запроса. Мы отправляем стандартный запрос, так что указываем 0. Другие варианты:
- 0: Стандартный запрос
- 1: Инверсный запрос
- 2: Запрос статуса сервера
- 3-15: Зарезервированы для будущего использования
- TC: Однобитный флаг, указывающий на обрезанное сообщение. У нас короткое сообщение, его не нужно обрезать, так что указываем 0.
- RD: Однобитный флаг, указывающий на желательную рекурсию. Если DNS-сервер, которому мы отправляем вопрос, не знает ответа на него, он может рекурсивно опросить другие DNS-серверы. Мы хотим активировать рекурсию, так что укажем 1.
- QDCOUNT: 16-битное беззнаковое целое, определяющее число записей в секции вопроса. Мы отправляем 1 вопрос.
Полный заголовок
Совместив все поля, можно записать наш заголовок в шестнадцатеричном формате:
AA AA - ID 01 00 – Параметры запроса 00 01 – Количество вопросов 00 00 – Количество ответов 00 00 – Количество записей об уполномоченных серверах 00 00 – Количество дополнительных записей
Для получения параметров запроса мы объединяем значения полей от QR до RCODE, помня о том, что не упомянутые выше поля установлены в 0. Это даёт последовательность
0000 0001 0000 0000
, которая в шестнадцатеричном формате соответствует 01 00
. Так выглядит стандартный DNS-запрос.Вопрос
Секция вопроса имеет следующий формат:
0 1 2 3 4 5 6 7 8 9 A B C D E F +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | | / QNAME / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QTYPE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QCLASS | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
- QNAME: Эта секция содержит URL, для которого мы хотим найти IP-адрес. Она закодирована как серия надписей (labels). Каждая надпись соответствует секции URL. Так, в адресе
example.com
две секции: example и com.Для составления надписи нужно закодировать каждую секцию URL, получив ряд байтов. Надпись — это ряд байтов, перед которыми стоит байт беззнакового целого, обозначающий количество байт в секции. Для кодирования нашего URL можно просто указать ASCII-код каждого символа.
Секция QNAME завершается нулевым байтом (00).
- QTYPE: Тип записи DNS, которую мы ищем. Мы будем искать записи A, чьё значение 1.
- QCLASS: Класс, который мы ищем. Мы используем интернет, IN, у которого значение класса 1.
Теперь можно записать всю секцию вопроса:
07 65 – у 'example' длина 7, e 78 61 – x, a 6D 70 – m, p 6C 65 – l, e 03 63 – у 'com' длина 3, c 6F 6D – o, m 00 - нулевой байт для окончания поля QNAME 00 01 – QTYPE 00 01 – QCLASS
В секции QNAME разрешено нечётное число байтов, так что набивка байтами не требуется перед началом секции QTYPE.
Мы отправляем наше DNS-сообщение в теле UDP-запроса. Следующий код Python возьмёт наш шестнадцатеричный DNS-запрос, преобразует его в двоичный формат и отправит на сервер Google DNS по адресу 8.8.8.8:53.
import binascii
import socket
def send_udp_message(message, address, port):
"""send_udp_message sends a message to UDP server
message should be a hexadecimal encoded string
"""
message = message.replace(" ", "").replace("\n", "")
server_address = (address, port)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
sock.sendto(binascii.unhexlify(message), server_address)
data, _ = sock.recvfrom(4096)
finally:
sock.close()
return binascii.hexlify(data).decode("utf-8")
def format_hex(hex):
"""format_hex returns a pretty version of a hex string"""
octets = [hex[i:i+2] for i in range(0, len(hex), 2)]
pairs = [" ".join(octets[i:i+2]) for i in range(0, len(octets), 2)]
return "\n".join(pairs)
message = "AA AA 01 00 00 01 00 00 00 00 00 00 " \
"07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 01"
response = send_udp_message(message, "8.8.8.8", 53)
print(format_hex(response))
Можете запустить этот скрипт, скопировав код в файл
query.py
и запустив в консоли команду $ python query.py
. У него нет никаких внешних зависимостей, и он должен работать на Python 2 или 3.После выполнения скрипт выводит ответ от DNS-сервера. Разобьём его на части и посмотрим, что можно выяснить.
Заголовок
Сообщение начинается с заголовка, как и наше сообщение с запросом:
AA AA – Тот же ID, как и раньше 81 80 – Другие флаги, разберём их ниже 00 01 – 1 вопрос 00 01 – 1 ответ 00 00 – Нет записей об уполномоченных серверах 00 00 – Нет дополнительных записей
Преобразуем
81 80
в двоичный формат:8 1 8 0 1000 0001 1000 0000
Преобразуя эти биты по вышеуказанной схеме, можно увидеть:
- QR = 1: Это сообщение является ответом
- AA = 0: Этот сервер не является уполномоченным для доменного имени
example.com
- RD = 1: Для этого запроса желательна рекурсия
- RA = 1: На этом DNS-сервере поддерживается рекурсия
- RCODE = 0: Ошибки не обнаружены
Секция вопроса
Секция вопроса идентична такой же секции в запросе:
07 65 – у 'example' длина 7, e 78 61 – x, a 6D 70 – m, p 6C 65 – l, e 03 63 – у 'com' длина 3, c 6F 6D – o, m 00 - нулевой байт для окончания поля QNAME 00 01 – QTYPE 00 01 – QCLASS
Секция ответа
У секции ответа формат ресурсной записи:
0 1 2 3 4 5 6 7 8 9 A B C D E F +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | | / / / NAME / | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | TYPE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | CLASS | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | TTL | | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | RDLENGTH | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| / RDATA / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
C0 0C - NAME 00 01 - TYPE 00 01 - CLASS 00 00 18 4C - TTL 00 04 - RDLENGTH = 4 байта 5D B8 D8 22 - RDDATA
NAME
: Этой URL, чей IP-адрес содержится в данном ответе. Он указан в сжатом формате:0 1 2 3 4 5 6 7 8 9 A B C D E F +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | 1 1| OFFSET | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Первые два бита установлены в значение 1, а следующие 14 содержат беззнаковое целое, которое соответствует смещению байт от начала сообщения до первого упоминания этого имени.В данном случае смещение составляет c0 0c или двоичном формате:
1100 0000 0000 1100
То есть смещение байт составляет 12. Если мы отсчитаем байты в сообщении, то можем найти, что оно указывает на значение 07 в начале имени example.com.TYPE
иCLASS
: Здесь используется та же схема имён, что и в секцияхQTYPE
иQCLASS
выше, и такие же значения.TTL
: 32-битное беззнаковое целое, которое определяет время жизни этого пакета с ответом, в секундах. До истечения этого интервала результат можно закешировать. После истечения его следует забраковать.RDLENGTH
: Длина в байтах последующей секцииRDDATA
. В данном случае её длина 4.RDDATA
: Те данные, которые мы искали! Эти четыре байта содержат четыре сегмента нашего IP-адреса: 93.184.216.34.
Мы увидели, как составить DNS-запрос. Теперь можно попробовать следующее:
- Составить запрос для произвольного доменного имени
- Запрос на другой тип записи
- Отправить запрос с отключенной рекурсией
- Отправить запрос с доменным именем, которое не зарегистрировано
1. Шестнадцатеричные числа (base 16) часто используются как удобная краткая запись для 4 битов двоичных данных. Вы можете конвертировать данные между этими форматами по следующей таблице:
Десятичный | Hex | Двоичный | Десятичный | Hex | Двоичный |
---|---|---|---|---|---|
0 | 0 | 0000 | 8 | 8 | 1000 |
1 | 1 | 0001 | 9 | 9 | 1001 |
2 | 2 | 0010 | 10 | A | 1010 |
3 | 3 | 0011 | 11 | B | 1011 |
4 | 4 | 0100 | 12 | C | 1100 |
5 | 5 | 0101 | 13 | D | 1101 |
6 | 6 | 0110 | 14 | E | 1110 |
7 | 7 | 0111 | 15 | F | 1111 |
Как видите, можно представить любой байт (8 бит) двумя шестнадцатеричными символами. ↑