Разрешение имени хоста занимает 5 секунд

Разрешение имени хоста занимает 5 секунд

У меня есть главный bind9DNS-сервер и 2 подчиненных сервера, работающих на IPv4 (Debian Jessie), использующих /etc/bind/named.conf:

listen-on-v6 { none; };

Когда я пытаюсь подключиться с разных серверов, каждое соединение занимает не менее 5 секунд (я используюИнформация о времени Джозефадля отладки):

$ curl -w "@curl-format.txt" -o /dev/null -s https://example.com
            time_namelookup:  5.512
               time_connect:  5.512
            time_appconnect:  5.529
           time_pretransfer:  5.529
              time_redirect:  0.000
         time_starttransfer:  5.531
                            ----------
                 time_total:  5.531

По данным curl, поиск занимает большую часть времени, однако стандартный вариант nslookupочень быстрый:

$ time nslookup example.com > /dev/null 2>&1

real    0m0.018s
user    0m0.016s
sys     0m0.000s

После принудительного curlиспользования IPv4 становится намного лучше:

$ curl -4 -w "@curl-format.txt" -o /dev/null -s https://example.com

            time_namelookup:  0.004
               time_connect:  0.005
            time_appconnect:  0.020
           time_pretransfer:  0.020
              time_redirect:  0.000
         time_starttransfer:  0.022
                            ----------
                 time_total:  0.022

Я отключил IPv6 на хосте:

echo 1 > /proc/sys/net/ipv6/conf/eth0/disable_ipv6

хотя проблема осталась. Я попробовал запустить, straceчтобы узнать, в чем причина тайм-аутов:

write(2, "*", 1*)                        = 1
write(2, " ", 1 )                        = 1
write(2, "Hostname was NOT found in DNS ca"..., 36Hostname was NOT found in DNS cache
) = 36
socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = 4
close(4)                                = 0
mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f220bcf8000
mprotect(0x7f220bcf8000, 4096, PROT_NONE) = 0
clone(child_stack=0x7f220c4f7fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f220c4f89d0, tls=0x7f220c4f8700, child_tidptr=0x7f220c4f89d0) = 2004
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 4)                           = 0 (Timeout)
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 8)                           = 0 (Timeout)
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 16)                          = 0 (Timeout)
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 32)                          = 0 (Timeout)
rt_sigaction(SIGPIPE, NULL, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [PIPE], SA_RESTORER|SA_RESTART, 0x7f22102e08d0}, NULL, 8) = 0
poll(0, 0, 64)                          = 0 (Timeout)

Похоже, это не проблемы с брандмауэром, так как nslookup(или curl -4) использует те же DNS-серверы. Есть идеи, в чем может быть проблема?

Вот что tcpdumpговорит ведущий tcpdump -vvv -s 0 -l -n port 53:

tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
20:14:52.542526 IP (tos 0x0, ttl 64, id 35839, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.1.1.59163 > 192.168.1.2.53: [bad udp cksum 0xf9f3 -> 0x96c7!] 39535+ A? example.com. (35)
20:14:52.542540 IP (tos 0x0, ttl 64, id 35840, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.1.1.59163 > 192.168.1.2.53: [bad udp cksum 0xf9f3 -> 0x6289!] 45997+ AAAA? example.com. (35)
20:14:52.543281 IP (tos 0x0, ttl 61, id 63674, offset 0, flags [none], proto UDP (17), length 158)
    192.168.1.2.53 > 192.168.1.1.59163: [udp sum ok] 45997* q: AAAA? example.com. 1/1/0 example.com. [1h] CNAME s01.example.com. ns: example.com. [10m] SOA ns01.example.com. ns51.domaincontrol.com. 2016062008 28800 7200 1209600 600 (130)
20:14:57.547439 IP (tos 0x0, ttl 64, id 36868, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.1.1.59163 > 192.168.1.2.53: [bad udp cksum 0xf9f3 -> 0x96c7!] 39535+ A? example.com. (35)
20:14:57.548188 IP (tos 0x0, ttl 61, id 64567, offset 0, flags [none], proto UDP (17), length 184)
    192.168.1.2.53 > 192.168.1.1.59163: [udp sum ok] 39535* q: A? example.com. 2/2/2 example.com. [1h] CNAME s01.example.com., s01.example.com. [1h] A 136.243.154.168 ns: example.com. [30m] NS ns01.example.com., example.com. [30m] NS ns02.example.com. ar: ns01.example.com. [1h] A 136.243.154.168, ns02.example.com. [1h] A 192.168.1.2 (156)
20:14:57.548250 IP (tos 0x0, ttl 64, id 36869, offset 0, flags [DF], proto UDP (17), length 63)
    192.168.1.1.59163 > 192.168.1.2.53: [bad udp cksum 0xf9f3 -> 0x6289!] 45997+ AAAA? example.com. (35)
20:14:57.548934 IP (tos 0x0, ttl 61, id 64568, offset 0, flags [none], proto UDP (17), length 158)
    192.168.1.2.53 > 192.168.1.1.59163: [udp sum ok] 45997* q: AAAA? example.com. 1/1/0 example.com. [1h] CNAME s01.example.com. ns: example.com. [10m] SOA ns01.example.com. ns51.domaincontrol.com. 2016062008 28800 7200 1209600 600 (130)

РЕДАКТИРОВАТЬ: В журналах привязки часто появляется следующее сообщение:

error sending response: host unreachable

Хотя на каждый запрос в конечном итоге дается ответ (это занимает всего 5 секунд). Все машины являются физическими серверами (это не вина NAT), более вероятно, что пакеты блокируются маршрутизатором. Вот вполне вероятный связанный вопрос:Поиск DNS иногда занимает 5 секунд.

решение1

Короткий ответ:

Обходной путь — принудительное glibcповторное использование сокета для поиска записей AAAAи Aпутем добавления строки /etc/resolv.conf:

options single-request-reopen

Реальной причиной этой проблемы может быть:

Длинный ответ:

Программы, подобные curlили wgetиспользующие функцию glibcgetaddrinfo(), который пытается быть совместимым как с IPv4, так и с IPv6, параллельно просматривая обе записи DNS. Он не возвращает результат, пока не будут получены обе записи (естьнесколько вопросов, связанных с таким поведением) - это объясняет straceвышесказанное. Когда IPv4 принудительно используется, например, curl -4внутренне gethostbyname(), что запрашивает Aтолько запись.

Из этого tcpdumpмы видим, что:

  • -> A?В начале отправляются два запроса
  • -> AAAA?(запрашивается адрес IPv6)
  • <- AAAAотвечать
  • -> A?запрашиваю снова адрес IPv4
  • <- Aполучил ответ
  • -> AAAA?повторный запрос IPv6
  • <- AAAAотвечать

Один Aответ по какой-то причине теряется, появляется следующее сообщение об ошибке:

error sending response: host unreachable

Однако мне непонятно, зачем нужен второй AAAAзапрос.

Чтобы убедиться, что у вас та же проблема, вы можете обновить время ожидания в /etc/resolv.conf:

options timeout:3

Сначала создайте текстовый файл спользовательская конфигурация отчета о времени:

cat >./curl-format.txt  <<-EOF
   time_namelookup: %{time_namelookup}\n
      time_connect: %{time_connect}\n
   time_appconnect: %{time_appconnect}\n
     time_redirect: %{time_redirect}\n
  time_pretransfer: %{time_pretransfer}\n
time_starttransfer: %{time_starttransfer}\n
                    ----------\n
time_total: %{time_total}\n
EOF

то отправьте запрос:

$ curl -w "@curl-format.txt" -o /dev/null -s https://example.com

            time_namelookup:  3.511
               time_connect:  3.511
            time_appconnect:  3.528
           time_pretransfer:  3.528
              time_redirect:  0.000
         time_starttransfer:  3.531
                            ----------
                 time_total:  3.531

Есть еще два связанных варианта man resolv.conf:

одиночный запрос (начиная с glibc 2.10)устанавливает RES_SNGLKUP в _res.options. По умолчанию glibc выполняет поиск IPv4 и IPv6 параллельно, начиная с версии 2.9. Некоторые серверы DNS-устройств не могут правильно обрабатывать эти запросы и заставляют запросы истекать по тайм-ауту. Эта опция отключает поведение и заставляет glibc выполнять запросы IPv6 и IPv4 последовательно (за счет некоторого замедления процесса разрешения).

single-request-reopen (начиная с glibc 2.9) Резолвер использует один и тот же сокет для запросов A и AAAA. Некоторое оборудование ошибочно отправляет только один ответ. Когда это происходит, клиентская система будет сидеть и ждать второго ответа. Включение этой опции изменяет это поведение так, что если два запроса с одного и того же порта не обрабатываются правильно, он закроет сокет и откроет новый перед отправкой второго запроса.

Связанные вопросы:

решение2

Как говорит @Tombart, задержка вызвана ожиданием тайм-аута разрешения IPv6.

Другой возможный вариант действий — отдать приоритет IPv4 в /etc/gai.conf.

Из комментариев в /etc/gai.conf

#   For sites which prefer IPv4 connections change the last line to
#
precedence ::ffff:0:0/96  100

После изменения gai.confнеобходимо перезапустить любое приложение, использующее библиотеку DNS-распознавателя, чтобы изменения вступили в силу.

Обратите внимание, что если вы используете сервер BIND без подключения IPv6, я советую отключить IPv6 namedи брать адреса IPv6 из корневых ссылок. Очевидно, что он все равно будет пытаться разрешить адреса AAAA.

Итак, для конфигурации BIND,

В /etc/default/bind9 добавьте -4 для адресов IPv4:

OPTIONS="-4 -u bind"

и в /etc/bind/db.root, удалите все строки с корнями DNS AAAA.

решение3

У меня была похожая проблема при использовании BIND9. Чтобы исправить это, мне нужно было добавить:

filter-aaaa-on-v4 yes;

вариант для моего named.conf.

(Больше информации)

решение4

На случай, если кто-то ищет curl-format.txt. Вставьте это в свою оболочку, и она создаст для вас файл формата. Оригинальная ссылка у меня не работает. Нашел этот примерздесь

cat >./curl-format.txt  <<-EOF
   time_namelookup: %{time_namelookup}\n
      time_connect: %{time_connect}\n
   time_appconnect: %{time_appconnect}\n
     time_redirect: %{time_redirect}\n
  time_pretransfer: %{time_pretransfer}\n
time_starttransfer: %{time_starttransfer}\n
                    ----------\n
time_total: %{time_total}\n
EOF

Связанный контент