Как отключить поиск AAAA?

35

... чтобы компенсировать сломанные DNS-серверы, которые находятся вне нашего контроля.

Наша проблема: мы внедряем встроенные устройства, которые собирают данные датчиков на различных сайтах, в основном только для IPv4. Некоторые сайты имеют плохо обслуживаемые сети, например, неправильно настроенные или иным образом поврежденные кэши DNS и / или брандмауэры, которые либо полностью игнорируют запросы AAAA, либо отвечают на них с поврежденными ответами (например, неверный IP-адрес источника!). Как внешний поставщик для отдела оборудования, мы почти не влияем на (иногда неохотно) ИТ-отделы. Вероятность того, что они исправят свои DNS-серверы / брандмауэры в ближайшее время, ничтожна.

Влияние на наше устройство состоит в том, что с каждым gethostbyname () процессы должны ждать, пока не истечет время ожидания запросов AAAA, после чего некоторые процессы уже полностью отключили свои попытки подключения.

Я ищу решения, которые ...

  • общесистемный. Я не могу перенастроить десятки приложений по отдельности
  • непостоянный и настраиваемый. Нам нужно (повторно) включить IPv6, где / когда он будет исправлен / развернут. Перезагрузка в порядке.
  • Если для решения требуется замена базовой библиотеки, такой как glibc, пакет библиотеки для замены должен быть доступен из хорошо поддерживаемого репозитория (например, Debian Testing, Ubuntu Universe, EPEL). Самостоятельное строительство не является вариантом по многим причинам, поэтому я даже не знаю, с чего начать, поэтому я просто не перечисляю их вообще ...

Самое очевидное решение было бы настроить библиотеку распознавателя , например , с помощью / и т.д. / { Резо , NSSwitch , гаи } .conf не запрос AAAA записей. Вариант resolv.conf, no-inet6предложенный здесь , будет именно тем , что я ищу. К сожалению, это не реализовано, по крайней мере, в наших системах (libc6-2.13-38 + deb7u4 в Debian 7; libc6-2.19-0ubuntu6.3 в Ubuntu 14.04)

Так как же тогда? Можно найти следующие методы, предложенные на SF и в других местах, но ни один из них не работает:

  • Отключение IPv6 в целом, например путем внесения в черный список ipv6 LKM в /etc/modprobe.d/ или 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-запросы, только на то, как обрабатывается несколько ответов.
  • Использование внешних распознавателей (или запуск демона локального распознавателя, который обходит неработающие DNS-серверы) может помочь, но, как правило, запрещено политиками брандмауэра компании. И это может сделать внутренние ресурсы недоступными.

Альтернативные уродливые идеи:

  • Запустите кеш DNS на локальном хосте. Сконфигурируйте его для пересылки всех не-AAAA-запросов, но для ответа на AAAA-запросы с помощью NOERROR или NXDOMAIN (в зависимости от результата соответствующего A-запроса). Я не знаю, кэш DNS, способный сделать это, хотя.
  • Используйте какое-нибудь умное соответствие iptables u32 или DNS-модуль Ондрея Калетки iptables DNS для сопоставления запросов AAAA, чтобы либо отклонить их icmp (как отреагирует на это lib lib resolver), либо перенаправить их на локальный DNS-сервер, который отвечает на запросы. все с пустым NOERROR.

Обратите внимание, что есть похожие вопросы по SE. Мой вопрос отличается тем, что он раскрывает реальную проблему, которую я пытаюсь решить, поскольку в нем перечислены явные требования, так как в нем перечислены некоторые часто предлагаемые нерабочие решения, и поскольку он не относится к конкретному приложению. После этого обсуждения я разместил свой вопрос.

Нильс Тёдтманн
источник
13
PS: Вопреки распространенному мнению о SF, есть несколько веских причин для отключения IPv6 / AAAA на машине в сети, поддерживающей только IPv4, даже там, где работает DNS: снижение широковещательной нагрузки; Снизить нагрузку на распознаватели DNS почти на 50%; Сократить время запуска соединения (значительно там, где DNS-кэши отстают); Следуйте рекомендациям, чтобы отключить нефункциональные функции для повышения безопасности и стабильности. По общему признанию, если я забуду повторно включить IPv6, как только он станет доступным, тогда моя система станет устаревшим балластом IPv4, который препятствует развертыванию IPv6. Нужно позволить взвесить перечисленные плюсы против этого мошенничества.
Нильс Тёдтманн
Любая причина, почему вы не запускаете полный распознаватель на localhost? Таким образом вы полностью исключаете зависимость от (казалось бы) ненадежных распознавателей DNS других людей.
Сандер Стеффанн,
@SanderSteffann Политики брандмауэра компании обычно запрещают это. Но в другом месте это вариант. Я добавлю это к моему вопросу позже.
Нильс Тёдтманн
3
@joeqwerty Мы не делаем никаких предположений о том, поддерживается ли IPv6 на сайте. Мы предполагаем, что DNS-серверы соответствуют стандартам. Кроме того, некоторым ИТ-отделам, к сожалению, не хватает навыков для правильной настройки своей инфраструктуры. Извините за грубость по этому поводу.
Нильс Тёдтманн
4
Я понимаю, что вы говорите. Вы должны заставить свою коробку работать в их сети, а не наоборот, и это то, о чем вы здесь спрашиваете. Я просто немного раздражаюсь, когда мы в области ИТ обвиняем наших клиентов и не уважаем их. Они наш хлеб с маслом. Хорошо это или плохо, мы должны уважать это и уважать их. Наши клиенты не являются помехой для нашего бизнеса, они являются причиной нашего бизнеса.
Joeqwerty

Ответы:

9

Прекратите использовать gethostbyname(). Вы должны использовать getaddrinfo()вместо этого, и должно было быть в течение многих лет. Страница man даже предупреждает вас об этом.

Функции gethostbyname * (), gethostbyaddr * (), herror () и hstrerror () устарели. Приложения должны использовать getaddrinfo (3), getnameinfo (3) и gai_strerror (3).

Вот быстрый пример программы на C, который демонстрирует поиск только записей A по имени, и захват Wireshark, показывающий, что только поиск записей A проходил по сети.

В частности, вам нужно установить ai_familyзначение, AF_INETесли вы только хотите, чтобы был произведен поиск записей. Этот пример программы печатает только возвращенные IP-адреса. См. getaddrinfo()Справочную страницу для более полного примера того, как устанавливать исходящие соединения.

В перехвате Wireshark 172.25.50.3 - локальный преобразователь DNS; захват был сделан там, так что вы также видите исходящие запросы и ответы. Обратите внимание, что была запрошена только запись А. Поиск 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);
}
Майкл Хэмптон
источник
Интересный! Я буду исследовать, какие приложения вызывают запросы AAAA. Если это только наше, тогда я передам ваше предложение нашим разработчикам. Но у меня есть сильное предчувствие, что от этого страдает много программного обеспечения, упакованного в Debian / Ubuntu, и мы не собираемся их исправлять.
Нильс Тёдтманн
Ваша заявка, вероятно, самая важная. Даже если вы не можете исправить все остальное, это может улучшить ситуацию.
Майкл Хэмптон
4

Если вы сомневаетесь, обратитесь к исходному коду! Итак, давайте посмотрим ... gethostbyname () выглядит интересно; это точно описывает то, что мы видим: сначала попробуйте IPv6, а затем вернитесь к IPv4, если вы не получили ответ, который вам нравится. Что это за RES_USE_INET6флаг? Возвращаясь к нему, это происходит из res_setoptions () . Это где resolv.confчитается в.

И .... это я вне идей. Мне совершенно непонятно, как это происходит, RES_USE_INET6если не в resolv.conf.

BMDan
источник
RES_USE_INET6 может быть установлен с помощью options inet6в resolv.conf. Я предполагаю, что моя проблема в том, что он не может быть сброшен после того, как он был установлен во время компиляции, что все основные дистрибутивы, кажется, делают в эти дни (правильно?). Поэтому запрос функции для options no_inet6этого я упомянул выше.
Нильс Тёдтманн
1
К сожалению, как вы можете видеть из кода, здесь, похоже, нет no_inet6опции res_setoptions(). Однако, как вы можете видеть из (нет) ip6-dotint, это легко изменить. Чтобы проверить теорию, что она устанавливается по умолчанию вашим дистрибутивом, я бы взял исходные файлы пакета и скомпилировал его один раз «virgin» (чтобы убедиться, что пакет повторяет поведение), а затем добавил: { STRnLEN ("no-inet6"), 1, ~RES_USE_INET6 },в options[]массив и посмотрел, проблема исчезнет, ​​когда вы установите эту опцию в resolv.conf.
BMDan
1
И наконец: для чего бы это ни стоило, я бы решил это, запустив кеш DNS на localhost (как вы упомянули выше). Было бы намного проще поддерживать свой собственный взломанный DNS-прокси / кеш, чем поддерживать взломанную версию базовой системной библиотеки.
BMDan
3

Вы можете использовать BIND в качестве локального распознавателя, у него есть опция для фильтрации AAAA:

https://kb.isc.org/article/AA-00576/0/Filter-AAAA-option-in-BIND-9-.html

Роберт Керр
источник
2
Это довольно тяжелый вес для встроенного устройства.
Майкл Хэмптон
Спасибо, я не знал о фильтре AAAA Бинд. Как упоминает Майкл, это, вероятно, не решение для нас из-за большого присутствия Бинд. Но для тех, кто хочет отфильтровать ответы AAAA в других сценариях, это может быть жизнеспособным способом. Ubuntu на самом деле создает связывание с "--enable-filter-aaaa", по крайней мере, 14.04. Не уверен насчет Debian. - См. Также ipamworldwide.blogspot.co.uk/2011/09/…
Нильс Тёдтман
1
У меня 14.04, и не похоже, что эта опция фильтрации доступна.
Цитракс
0

Вы пытались настроить PDNS-рекурсор, установить его в /etc/resolv.conf и запретить поиск в нем "AAAA"? Используя что-то вродеquery-local-address6=

Glueon
источник
1
query-local-address6=делает что-то другое (с какого IPv6-адреса отправлять запросы - обратите внимание, что даже если IPv6 отключен, запросы AAAA по-прежнему будут обрабатываться через IPv4). Также я не могу определить другие параметры, которые бы фильтровали запросы AAAA ( doc.powerdns.com/html/built-in-recursor.html ). Без этой информации ваш ответ не очень полезен :(
Nils Toedtmann