Пасхалки в DNS
Сетевой стек TCP/IP не в одночасье стал паутиной, соединившей интернет от края до края. Вся система развивалась довольно бурно, противоречиво, но в целом через инкрементальные усовершенствования в разных местах. Не было какого-то единого плана создания глобальной коммуникационной сети и подходящего под эти цели стека протоколов. Из-за этого вместо сферической семиэтажной OSI в вакууме в наличие у нас есть причудливое смешение технологий и протоколов, где стандарты, написанные в 1970-х всё ещё живы, лягаются и даже обеспечивают нагрузкой ваши боевые сервера.
Figure 1. Комикс xkcd на злобу дня
Всё это в полной мере относится к подсистеме разрешения имён, aka name resolving, и DNS, как современной и наиболее полноценной реализации этой ключевой технологии. В качестве такового DNS пережил разнообразных саблезубых тигров и археоптериксов вроде YP/NIS/NIS+ эпохи накопления битов, вследствие чего в нём набралось немало артефактов и пасхальных яиц. Иногда их обнаруживают случайно при раскопках с помощью dig
, но есть также и новые, нестандартные применения старого механизма.
▍ Шпаргалка DNS
Ресурсная запись DNS, aka RR, содержит следующие поля:
- Name — доменное имя, к которому относится запись;
- TTL — срок годности хранения записи со стороны не ответственного сервера;
- Type — тип записи в поле данных, её назначение и формат;
- Class — класс сети передачи данных, возможность работать также с архитектурой, отличной от TCP/IP;
- Rdlen — длина поля данных;
- Rdata — содержание и формат данного поля зависит от значения поля
type
.
Наиболее распространённые типы RR:
- A — адресная запись, связывающая доменное имя и IPv4 адрес;
- AAAA — адресная запись, связывающая доменное имя и IPv6 адрес;
- CNAME — Canonical Name, каноническая запись для перенаправления на иное доменное имя;
- NS — ссылка на DNS-сервер, ответственный за данный домен;
- MX — Mail Exchange, ссылка на почтовый сервер домена;
- PTR — Point to Reverse, связывает IP-адрес с доменным именем узла, служит для обратного разрешения в DNS с помощью специального домена
in-addr.arpa
; - TXT — произвольное текстовое описание домена, зачастую используется для SPF, DKIM проверок со стороны почтовых серверов;
- SOA — запись содержит необходимую информацию для домена DNS: минимальный TTL, срок истечения, контактный адрес электронной почты, частота обновления данных в зоне DNS и исходный узел;
Для целей разрешения доменных имён в IP-адреса и обратно обычно используются программы:
- nslookup # самый древний, был deprecated, но теперь снова жив, вывод не дружествен скриптам;
- host # золотая середина, полноценный, но не избыточный набор опций и результат запроса;
- dig # наиболее тяжеловесный инструмент, обилие опций и детальный вывод;
- ping # опрашивает не только DNS-сервер, но и читает файл
/etc/hosts
.
У всех четырёх команд синтаксис выстроен одинаково: command [options] hostname_or_ip. Следует, однако, помнить о том, что разрешение имён это больше, чем обращение к DNS-серверу. Например, вы распаковали новый WiFi-маршрутизатор и прописали в файле /etc/hosts
запись следующего вида.
192.168.10.1 asus.local
После этого в браузер можно вбивать https://asus.local
и страница административной консоли будет успешно открываться. Тем временем команды nslookup asus.local
, host asus.local
и тем более dig asus.local
ничего не найдут и вернут ошибку. Только ping asus.local
выдаст IP адрес и покажет, что хостнейм доступен. Всё же, использовать ping
для разрешения имён идея не из лучших из-за того, что утилита для этого не предназначена, и в первую очередь её задача проверить связность сети на уровне IP адресации. Обратное разрешение имён при ping ip_address
может сработать, или нет. Кроме того, из-за обилия сценариев ICMP echo/reply
вывод и время исполнения команды могут сильно отличаться, что не идёт на пользу автоматизации проверки.
Как ни странно, не только BIND, но и пакеты сетевых средств iputils или nettools не имеют средства целостной проверки разрешения имён. Наиболее полноценную проверку осуществляет команда getent
из пакета glibc. Если просмотреть man getent
, то можно увидеть, что команда getent ahosts
использует системный вызов getaddrinfo
для нахождения IP-адреса узла, а getent hosts
использует устаревшие, но всё ещё используемые gethostbyname / getaddrbyname
. Почему это является преимуществом, по сравнению с nslookup / host / dig
? Очень просто, указанные системные вызовы читают поле hosts
в файле /etc/nsswitch.conf
и смотрят не только в источник dns
, но также и в files
, причём в порядке, указанном в файле.
|15:58:47|adm@redeye:[~] > grep hosts /etc/nsswitch.conf
hosts: files dns
Источник dns
не требует объяснения, а files
означает проверку записей /etc/hosts
, в данном случае сперва проверяется файл, и только затем уходит запрос на DNS-сервер, в случае отсутствия нужных данных. Утилиты же BIND попросту игнорируют источник files
. И теперь немного креатива с помощью DNS.
▍ Пасхалка № 1 — курс валюты и погода без СМС
Есть такой проект DNS Toys, в котором дополнительные функции по запросу времени в разных часовых поясах, погоды, курсов валют и прочего, реализованы в привычных командах из штатного набора dnsutils / bind-utils
. Например, с помощью такой команды мы узнаем время в городе N.
|21:23:29|adm@redeye:[~]> dig tbilisi.time @dns.toys +short
"Tbilisi (Asia/Tbilisi, GE)" "Tue, 19 Jul 2022 22:23:26 +0400"
Для Москвы, Парижа и других крупнейших мегаполисов надо будет фильтровать американские «города-побратимы», либо указывать также код страны.
|21:27:28|adm@redeye:[~]> dig moscow.time @dns.toys +short
"Moscow (Europe/Moscow, RU)" "Tue, 19 Jul 2022 21:27:34 +0300"
"Moscow (America/Los_Angeles, US)" "Tue, 19 Jul 2022 11:27:34 -0700"
|21:31:355adm@redeye:[~]>
|21:32:00|adm@redeye:[~]> dig moscow/ru.time @dns.toys +short
"Moscow (Europe/Moscow, RU)" "Tue, 19 Jul 2022 21:31:59 +0300"
Так же, с помощью запроса на сервер dns.toys
узнаем и погоду.
|21:43:57|adm@redeye:[~]> dig sochi.weather @dns.toys +short
"Sochi (RU)" "23.00C (73.40F)" "66.80% hu." "fair_day" "15:00, Sun"
"Sochi (RU)" "22.70C (72.86F)" "68.50% hu." "clearsky_day" "17:00, Sun"
"Sochi (RU)" "21.90C (71.42F)" "71.80% hu." "clearsky_day" "19:00, Sun"
"Sochi (RU)" "20.10C (68.18F)" "80.30% hu." "clearsky_night" "21:00, Sun"
"Sochi (RU)" "19.10C (66.38F)" "87.40% hu." "clearsky_night" "23:00, Sun"
Так как выдача идёт с удалённого сервера dns.toys
, настройки LC_*=ru_RU.utf8, LANG=ru_RU.utf8
не меняют локализацию выдачи результата. Заказывать выдачу обменных курсов валют, в том числе криптовалют, проще простого.
|12:04:40|adm@redeye:[~]> dig 1EUR-RUB.fx @dns.toys +short
"1.00 EUR = 56.80 RUB" "2022-07-20"
|12:09:30|adm@redeye:[~]> dig 1BTC-USD.fx @dns.toys +short
1.00 BTC = 23259.23 USD" "2022-07-20"
Курсы валют берутся из API https://exchangerate.host/. Обратите внимание, что рекомендуется всегда использовать параметр +short
, чтобы избежать лишних деталей канонического ответа команды dig
. Стоит ещё отметить конвертацию различных единиц измерения.
|12:51:40|adm@redeye:[~]> dig 1kg-oz.unit @dns.toys +short # перевести килограмм в унции
"1.00 Kilogram (kg) = 35.27 Ounce (oz)"
|12:56:39|adm@redeye:[~]> dig 1st-kg.unit @dns.toys +short # перевести короткие тонны в килограммы
"1.00 Short ton (st) = 907.19 Kilogram (kg)"
Список всех доступных конвертаций можно просмотреть командой dig unit @dns.toys
. В качестве проверки, попробуйте перевести унции в граммы, работает? Довольно занятно выглядит результат запроса числа пи: dig pi @dns.toys
. Остальные возможности проекта DNS toys можно увидеть в опции help
.
|13:05:39|adm@redeye:[~]> dig help @dns.toys +short
get time for a city" "dig mumbai.time @dns.toys"
"convert currency rates" "dig 99USD-INR.fx @dns.toys"
"get your host's requesting IP." "dig ip @dns.toys"
"get weather forecast for a city." "dig berlin.weather @dns.toys"
"convert between units." "dig 42km-cm.unit @dns.toys"
"convert numbers to words." "dig 123456.words @dns.toys"
"convert cidr to ip range." "dig 10.100.0.0/24.cidr @dns.toys"
"return digits of Pi as TXT or A or AAAA record." "dig pi @dns.toys"
"convert numbers from one base to another" "dig 100dec-hex.base @dns.toys"
На самом деле довольно полезный проект, можно результаты использовать для домашней бухгалтерии, или настольных виджетов.
▍ Пасхалка №2 — хаос в домене Швейцарии
Если вы из чистого любопытства начнете простукивать dig
-ом домены верхнего уровня для каждой страны, то ничего интересного не увидите. Выглядит это незатейливо, каждый домен указывает свои сервера имён.
|13:27:02|adm@redeye:[~]> dig ru +noall +answer
dig ru NS +noall +answer
ru. 2390 IN NS a.dns.ripn.net.
ru. 2390 IN NS e.dns.ripn.net.
ru. 2390 IN NS f.dns.ripn.net.
ru. 2390 IN NS b.dns.ripn.net.
ru. 2390 IN NS d.dns.ripn.net.
|13:28:40|adm@redeye:[~]> dig su +noall +answer
su. 16068 IN NS a.dns.ripn.net.
su. 16068 IN NS b.dns.ripn.net.
su. 16068 IN NS d.dns.ripn.net.
su. 16068 IN NS e.dns.ripn.net.
su. 16068 IN NS f.dns.ripn.net.
Однако для Швейцарии это не работает. Кстати, код Швейцарии ch
получается из названия Confoederatio Helvetica. Естественно, возникает вопрос: «А в чём причина сбоя системы именно для родины дырявого сыра?».
|13:36:06|adm@redeye:[~]> dig ch +noall +answer
|13:36:06|adm@redeye:[~]>
Может возникнуть вопрос о необходимости третьего поля, так ли нам важно знать, что мы в интернете? Оказывается, для DNS в 2022 это по-прежнему очень даже актуальная информация. Как знать, что это не Chaosnet? Это и есть та самая вторая пасхалка, привет из 1970-х, не взлетевший альтернативный проект локальных сетей, канувший в /dev/null истории, где покоятся цеппелины и смартфоны Meego.
Когда мы запускаем команду dig ch NS +noall +answer
, на корневой сервер имён поступает запрос на запись в сети Chaosnet на непонятно что, в то время как нам нужно получить запись TLD Швейцарии. Программное обеспечение BIND-а трактует в данном случае ch
, как обращение к сети Chaosnet. Для того, чтобы получить требуемые данные достаточно в конце поставить точку ch.
, тем самым указывая Fully Qualified Domain Name.
|13:36:06|adm@redeye:[~]> dig ch. NS +noall +answer
ch. 20891 IN NS a.nic.ch.
ch. 20891 IN NS b.nic.ch.
ch. 20891 IN NS d.nic.ch.
ch. 20891 IN NS e.nic.ch.
ch. 20891 IN NS f.nic.ch.
|13:37:05|adm@redeye:[~]> man host |grep -B1 -i chaos
-c class
This option specifies the query class, which can be used to lookup HS (Hesiod) or CH (Chaosnet) class resource records. The default class is IN (Internet).
Оказывается, man pages утилит dig
, host
и nslookup
содержат в себе упоминание о Chaosnet. Оттуда же мы узнаём, что есть ещё один диковинный протокол обмена данными в альтернативной сети — Hesiod с кодом HS. Благодаря тому, что нет страны с двухбуквенным кодом HS, подобной коллизии не случится. Ниже пример конфигурационного файла Chaosnet.
view "chaos" CH {
match-clients { any; };
zone "my.do.ma.in" CH {
type master;
file "mydomain.zone";
};
};
view "default" IN {
match-clients { internalnets; };
include "named.conf.default-zones";
};
Для справки, DNS запрос на запись Chaosnet выглядит следующим образом.
|13:39:13|adm@redeye:[~]> dig ch txt @ddns1.bbc.com version.bind +short
"133b57568"
▍ Пасхалка №3 — Гугл расставил приоритеты
В txt
записи домена dns.google
ссылка на комикс с бородатой шуткой на тему будущего проектов Гугл.
|14:02:15|adm@redeye:[~] > dig txt dns.google +noall +answer
dns.google. 300 IN TXT "v=spf1 -all"
dns.google. 300 IN TXT "https://xkcd.com/1361/"
▍ Пасхалка №4 — прокрастинируй профессионально
Небольшой и ненавязчивый психотренинг для владеющих английским спрятался в txt
записях X.maybethiscould.work
, где X число от 0 до 50.
|13:56:11|adm@redeye:[~] > dig txt 10.maybethiscould.work +noall +answer
20.maybethiscould.work. 900 IN TXT "Think of the last thing that made you truly happy. Can you have more of that thing? Is it a thing that is healthy to have in unfettered abundance? If so, how can you pull it into more of your days?"
|14:02:19|adm@redeye:[~] > dig txt 25.maybethiscould.work +noall +answer
20.maybethiscould.work. 900 IN TXT "What if the perceived defect is what makes it special?"