И теперь он нестабилен (ошибки "не могу найти хост")
Откуда/как?
Все правильно настроенные резолверы, как вы заметили, получат флаг Truncated при первом же запросе по UDP, а затем переключатся на TCP, и все будет в порядке.
Вы, конечно, помните, что DNS находится поверх UDP. И TCP (вопреки популярному мифу), поэтому вам нужно убедиться, что ваши авторитетные серверы имен могут запрашиваться по TCP, и все будет в порядке.
После некоторых поисков в Google я обнаружил, что запрос с несколькими IP-адресами должен иметь не более 512 байт, чтобы гарантировать использование UDP.
Это зависит. Иногда вы можете превысить 1000. Но самое главное, все возвращается к TCP, поэтому не должно быть проблем (возможно, просто небольшая потеря производительности).
и избегайте лишнего запроса (или проблем с DNS-клиентами или провайдерами без TCP, старым DNS-программным обеспечением и т. д.).
«DNS-клиенты или провайдеры без TCP» не должны существовать, поскольку это не имеет смысла и противоречит спецификациям DNS, написанным ... более 40 лет назад!
Или у вас есть конкретные доказательства тех случаев?
Не пытайтесь обойти такие вещи. Если эти части программного обеспечения существуют, они сломаны и будут иметь массу других проблем, например, для защищенных доменов DNSSEC.
Итак, как я могу узнать, сколько IP-адресов v4 я могу иметь в одной записи DNS, чтобы гарантировать максимальный ответ UDP размером 512 байт?
На это невозможно ответить в общем (потому что это зависит от имени), но самое главное, бесполезно пытаться оптимизировать вещи таким образом.
В любом случае вы можете легко выполнить вычисление:
- пакет UDP имеет 8-байтовый заголовок перед данными (RFC 768)
- DNS-пакет, см. RFC 1035, имеет заголовок (12 байт), затем вопрос (переменное количество байтов, см. далее), затем ответ (см. далее), и мы будем считать дополнительный и раздел полномочий пустыми.
Итак, мы уже на 512-8-12 = 492 байта для DNS вопрос + ответ.
В ответ А
запись будет иметь имя (переменной длины) + тип (2 байта) + класс (2 байта) + TTL (4 байта) + длину (2 байта), а затем данные. За А
данные составляют 4 байта (адрес IPv4).
Вопрос: имя (переменная длина) + тип (2 байта) + класс (2 байта).
Имена в DNS-пакетах имеют следующие два свойства:
- они кодируются как список меток с префиксом длины
- могут быть сжаты так, что данное имя или часть имени появляется только один раз.
Так например пример.com
кодируется в DNS как 7,e,x,a,m,p,l,e,3,c,o,m,0
где каждая длина равна одному байту, но если имя потребуется позже, оно будет заменено указателем, использующим только 2 байта.
Если мы возьмем это имя:
- размер рассматриваемой части имени будет: 13 байт, поэтому общий размер вопроса: 13 + 2 + 2 = 17
- в ответе каждое имя может быть указателем из 2 байтов, ссылающимся на имя в вопросе, поэтому каждая запись в ответе будет иметь длину 2 байта для имени, а затем остальные выше, то есть 16 байтов.
Следовательно, полный DNS-пакет будет иметь размер 12 (заголовок) + 17 (вопрос) + x умножить на 16, где x — количество А
записи.
Итак, мы должны решить: 512 = 8 + 12 + 17 + 16х
для x, что дает х=29
или так.
Помните, что это возможно при наилучших обстоятельствах (без дополнительных/авторитетных записей и полного использования сжатия имени) и для определенного имени (но при использовании сжатия имя появляется полностью только один раз, поэтому изменяется только этот размер).
[Кстати, не попадайтесь в ловушку наследия Интернета прошлого века; в настоящее время IPv6 должен быть нормой; конечно ставишь еще меньше АААА
типы записей в DNS-пакете фиксированного размера, чем IPv4 :-) ]
Можно ли настроить ISC Bind для возврата только одного IP-адреса в запросе с несколькими IP-адресами?
Я так не думаю, и если бы он существовал, как bind выбирал бы, какой IP возвращать? Если вы находитесь здесь, вы можете указать только один IP-адрес в файле зоны. Или, если вы действительно привязаны к этой идее (но опять же, все время, которое вы теряете в этом, не предотвратит другие проблемы, потому что клиенты глючат, поэтому вы все равно пытаетесь сражаться с бесконечным холмом), вы можете попробовать dnsdist
это что-то вроде швейцарского армейского ножа и позволяет точно настроить.
PS: также помните, что у DNS есть расширение, позволяющее одной стороне указать размер буфера (UDP), который она может получить. См. RFC 6891. Недавний копать землю
использует 1232
там по умолчанию. Вам может быть интересно в целом посмотреть на https://kb.isc.org/docs/aa-01219 или день флага DNS 2020 г. в https://dnsflagday.net/2020/ именно об этом и было.