... чтобы компенсировать неисправность DNS-серверов, находящихся вне нашего контроля.
Наша проблема: мы развертываем встроенные устройства, которые собирают данные датчиков на различных сайтах, в основном поддерживающих только IPv4. Некоторые сайты имеют плохо обслуживаемые сети, например неправильно настроенные или иным образом сломанные кеши DNS и / или брандмауэры, которые либо полностью игнорируют запросы AAAA, либо отвечают на них неверными ответами (например, неправильный IP-адрес источника!). Как внешний поставщик для отдела оборудования, мы практически не имеем влияния на ИТ-отделы (иногда неохотно). Шансы на то, что они исправят свои DNS-серверы / брандмауэры в ближайшее время, ничтожны.
Эффект на нашем устройстве заключается в том, что с каждым gethostbyname () процессы должны ждать, пока не истечет время ожидания запросов AAAA, и в этот момент некоторые процессы уже полностью отключили свои попытки подключения.
Я ищу решения, которые ...
Наиболее очевидным решением было бы настроить библиотеку преобразователя, например. через / etc / {разрешить,nsswitch,гаи} .conf, чтобы не запрашивать записи AAAA. Параметр resolv.conf no-inet6
как было предложено Вот было бы именно то, что я ищу. К сожалению, это не реализовано, по крайней мере, в наших системах (libc6-2.13-38 + deb7u4 в Debian 7; libc6-2.19-0ubuntu6.3 в Ubuntu 14.04)
Так как же тогда? Можно найти следующие методы, предложенные в SF и других источниках, но ни один из них не работает:
sysctl -w net.ipv6.conf.all.disable_ipv6=1
. (Из любопытства: почему преобразователь запрашивает AAAA, если IPv6 отключен?)options inet6
из /etc/resolv.conf. Во-первых, его там не было, inet6
в наши дни просто включен по умолчанию.options single-request
в /etc/resolv.conf. Это только гарантирует, что запросы A и AAAA выполняются последовательно, а не параллельно.precedence
в /etc/gai.conf. Это не влияет на запросы DNS, только на то, как обрабатываются несколько ответов.Альтернативные уродливые идеи:
Обратите внимание, что есть похожие вопросы по SE. Мой вопрос отличается постольку, поскольку он описывает реальную проблему, которую я пытаюсь решить, поскольку в нем перечислены явные требования, поскольку он заносит в черный список некоторые часто предлагаемые неработающие решения и поскольку он не относится к одному приложению. Следующий это обсуждение, Я разместил свой вопрос.
Прекратить использовать gethostbyname()
. Вы должны использовать getaddrinfo()
вместо этого, и должно было быть в течение многих лет. Страница руководства даже предупреждает вас об этом.
Функции gethostbyname * (), gethostbyaddr * (), herror () и hstrerror () устарели. Вместо этого приложения должны использовать getaddrinfo (3), getnameinfo (3) и gai_strerror (3).
Вот небольшой пример программы на C, демонстрирующий поиск только Записи для имени и снимок Wireshark, показывающий, что только Поиск записей прошел по сети.
В частности, вам нужно установить ai_family
к AF_INET
если вам нужен только поиск A-записи. Этот пример программы печатает только возвращенные IP-адреса. Увидеть getaddrinfo()
справочную страницу для более полного примера того, как устанавливать исходящие соединения.
в Wireshark захват, 172.25.50.3 - локальный преобразователь DNS; захват был сделан там, поэтому вы также видите его исходящие запросы и ответы. Обратите внимание, что только Запрошена запись A. Поиск AAAA никогда не выполнялся.
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <stdio.h>
int main(void) {
struct addrinfo hints;
struct addrinfo *result, *rp;
int s;
char host[256];
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
s = getaddrinfo("www.facebook.com", NULL, &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
printf("%s\n", host);
}
freeaddrinfo(result);
}
В случае сомнений обращайтесь к исходному коду! Итак, посмотрим ... gethostbyname () выглядит интересно; это точно описывает то, что мы наблюдаем: сначала попробуйте IPv6, а затем вернитесь к IPv4, если вы не получите ответа, который вам нравится. Что это RES_USE_INET6
флаг? Отслеживая его, он исходит от res_setoptions (). Это где resolv.conf
читается в.
И .... это у меня нет идей. Я совершенно не понимаю, как это RES_USE_INET6
устанавливается, если не в resolv.conf
.
Вы можете использовать BIND как локальный преобразователь, у него есть возможность фильтровать AAAA:
https://kb.isc.org/article/AA-00576/0/Filter-AAAA-option-in-BIND-9-.html
Вы пытались установить PDNS-рекурсор, установить его в /etc/resolv.conf и запретить в нем поиск "AAAA"? Используя что-то вроде query-local-address6=