Вопрос или проблема
Команда dig +short
(например, описанная в “dig show only answer“) отлично подходит для пакетной обработки имен в IP-адреса. Она выполняет простую задачу и делает это хорошо.
К сожалению, когда есть CNAME, даже +short
недостаточно коротка. Например:
$ dig +short docs.sbonds.org
ghs.google.com.
173.194.69.121
Я пробовал +noall
, но это не похоже на то, что изменяет поведение +short
. Я также пробовал указать -t a
, чтобы убедиться, что он не считает, что я имел в виду запись A или CNAME, но это (неудивительно) ничего не меняет.
$ dig +noall +short docs.sbonds.org
ghs.google.com.
173.194.69.121
Я использую dig
на RedHat 7:
# dig -v
DiG 9.9.4-RedHat-9.9.4-73.el7_6
Я могу отфильтровать CNAME с помощью надежного grep
, но кажется, что dig должен иметь какой-то способ выдавать “Только IP, мэм”.
Какой это способ?
dig
— это инструмент для устранения неполадок, поэтому он отправляет DNS-запросы и получает DNS-ответы, и, как сказал Андреас, ответом являются как записи CNAME, так и A, как это было задумано. Ваше желание — получить “Только IP, мэм”, так что это не диагностика DNS, это “просто” разрешение, для которого dig
избыточен.
nslookup
nslookup
уступает dig
, но все равно даст вам слишком много информации:
$ nslookup docs.sbonds.org
Server: 192.0.2.254
Address: 192.0.2.254#53
Non-authoritative answer:
docs.sbonds.org canonical name = ghs.google.com.
Name: ghs.google.com
Address: 172.217.4.179
host
host
проще, но все равно вернет вам “слишком много” (но обратите внимание, что он также возвращает адрес IPv6, что хорошо):
$ host docs.sbonds.org
docs.sbonds.org is an alias for ghs.google.com.
ghs.google.com has address 172.217.15.83
ghs.google.com has IPv6 address 2607:f8b0:4004:815::2013
getent
В зависимости от вашей системы Unix, getent
может быть использован. Однако обратите внимание, что это может или не может делать DNS-запрос, так как вы настраиваете в /etc/nsswitch.conf
источник данных для каждой службы, и для hosts
это, вероятно, будет смесь files
(что есть venerable /etc/hosts
) и DNS.
$ getent hosts docs.sbonds.org
2607:f8b0:4007:801::2013 ghs.google.com docs.sbonds.org
Обратите внимание также, что в правильной настройке Unix предпочтение будет отдаваться IPv6 перед IPv4, так что это может быть для вас проблемой (это должно зависеть от конфигурации в /etc/gai.conf
)
На самом деле hosts
не учитывает /etc/gai.conf
, вам нужно использовать ahosts
вместо этого, который использует getaddrinfo
и, следовательно, gai.conf
. Обратите внимание, что вы получаете список (чей порядок зависит от настройки gai.conf
):
$ getent ahosts docs.sbonds.org
172.217.4.179 STREAM ghs.google.com
172.217.4.179 DGRAM
172.217.4.179 RAW
2607:f8b0:4007:801::2013 STREAM
2607:f8b0:4007:801::2013 DGRAM
2607:f8b0:4007:801::2013 RAW
Perl
Если вам разрешено написать простой скрипт, у вас есть много решений, например:
$ perl -MSocket -E 'say inet_ntoa(inet_aton("docs.sbonds.org"))'
172.217.4.179
DOH
Или используйте любой DOH (DNS поверх HTTPS) endpoint (или подобное) с любым HTTP-клиентом. Примеры:
$ curl --silent 'https://dns.google.com/resolve?name=docs.sbonds.org&type=A' | jq -cr '.Answer[] | select(.type == 1) | .data'
172.217.3.83
$ curl --silent -H 'accept: application/dns-json' 'https://cloudflare-dns.com/dns-query?name=docs.sbonds.org&type=A' | jq -cr '.Answer[] | select(.type == 1) | .data'
172.217.12.147
Systemd
Systemd имеет собственное приложение для резолвера:
$ systemd-resolve docs.sbonds.org
docs.sbonds.org: 172.217.9.51
2607:f8b0:4009:801::2013
(ghs.google.com)
-- Information acquired via protocol DNS in 239.1ms.
-- Data is authenticated: no
Вам все равно нужно как-то его обработать, но он дает конечные IP-адреса напрямую (есть флаг при его вызове, чтобы он не следовал записям CNAME
для случаев использования, которым это требуется)
Как CNAME, так и соответствующая A-запись (или любой тип, который вы запросили) принадлежат к секции ответа. Таким образом, нет опции dig (по крайней мере, в RHEL7’s dig), которая могла бы отфильтровать ответ CNAME.
Я думаю, что вам придется полагаться на dig +short [...] | grep -v '\.$'
, чтобы удалить ответы CNAME.
Ответ или решение
Вопрос о том, как заставить утилиту dig
возвращать только IP-адрес из CNAME-записи, весьма актуален для многих администраторов сетей и специалистов по информационным технологиям, которые стремятся оптимизировать процессы получения данных. В этом контексте, прежде чем углубляться в детали, необходимо понять, почему dig
работает именно так и какие есть альтернативные подходы к решению этой задачи.
Теория
Утилита DNS (Domain Name System
) под названием dig
используется для диагностики сетевых проблем и проверки различных аспектов настройки DNS. Когда запрашивается информация о домене, у которого есть CNAME-запись, dig
возвращает как саму CNAME
, так и связанный с ней записанный IP-адрес. Такая структура ответа является стандартом для работы с DNS и позволяет получить полную картину возможных маршрутов до конечного адреса.
Однако, задача иногда требует получения только конечного IP-адреса, игнорируя посреднические записи типа CNAME. Это особенно важно при массовой обработке данных, где необходимо минимизировать количество выдаваемой информации для повышения эффективности процессов.
Пример
Предположим, пользователь хочет получить только IP-адрес домена docs.sbonds.org
, используя следующую команду:
$ dig +short docs.sbonds.org
Ответ будет следующим:
ghs.google.com.
173.194.69.121
Ответ включает как CNAME, так и IP-адрес, что избыточно для целей получения исключительно IP-адреса.
Применение
Прямого способа выполнить эту задачу с помощью только dig
версии, доступной в RHEL 7, не существует, но есть несколько обходных маневров и альтернативных инструментов, которые могут помочь:
-
Использование фильтрации в команде
grep
:Используйте команду
grep
для сокрытия строк, содержащих финальную точку, которая обычно характерна для CNAME записей:$ dig +short docs.sbonds.org | grep -v '\.$'
Это отфильтрует CNAME из вывода, оставив только IP-адреса.
-
Применение утилиты
nslookup
:Она предоставляет похожую функциональность, хотя и тоже вернет избыточную информацию, но может быть полезной в сочетании с дальнейшей обработкой:
$ nslookup -type=A docs.sbonds.org | grep "Address:" | tail -n1
Здесь идет акцент на поиск строки, начинающейся с
Address:
, и выводе последней такой строки. -
Использование
host
:Утилита
host
предоставляет более упрощенный формат ответа:$ host docs.sbonds.org | grep "has address" | awk '{print $4}'
Эта команда извлечет только часть с IP-адресом.
-
Программирование с помощью Perl или Python:
Если разрешено использование скриптов, Perl или Python могут стать мощным инструментом:
На Perl:
$ perl -MSocket -e 'print inet_ntoa(inet_aton("docs.sbonds.org")), "\n"'
На Python:
import socket print(socket.gethostbyname('docs.sbonds.org'))
Эти скрипты напрямую возвращают только IP-адрес домена.
-
Использование DNS через HTTPS (DOH):
Эта методика позволяет обращаться к DNS-серверам через HTTPS, используя curl и jq для фильтрации данных:
$ curl --silent 'https://dns.google.com/resolve?name=docs.sbonds.org&type=A' | jq -r '.Answer[] | select(.type == 1) | .data'
Инструмент
jq
здесь выступает как мощный синтаксический анализатор JSON, позволяющий извлечь исключительно интересующие данные. -
Системные решения с использованием
getent
:В зависимости от настроек системы,
getent
может предоставить необходимую информацию:$ getent ahosts docs.sbonds.org | grep STREAM | awk '{print $1}' | head -n 1
При правильной настройке это будет предпочтение IPv4-адресов.
-
Решения с использованием
systemd-resolve
:Решатель от
systemd
вновь предоставляет возможность работы с DNS, где вы можете выбрать подходящий уровень детализации:$ systemd-resolve --no-pager --status docs.sbonds.org | grep "Address" | head -n 1
Чтобы избежать домен-названия, используйте комбинацию с фильтрацией вывода.
В заключение, указанные методы представляют собой очевидные альтернативы решению задачи извлечения только IP-адреса с использованием dig
. Выбор подходящего инструмента или техники множества доступных зависит от конкретных условий задачи, предпочтений администратора, наличных утилит в системе и необходимых в будущем уровней автоматизации.