Resolver o nome do host leva 5 segundos

Resolver o nome do host leva 5 segundos

Eu tenho um bind9servidor DNS mestre e 2 servidores escravos rodando em IPv4 (Debian Jessie), usando /etc/bind/named.conf:

listen-on-v6 { none; };

Quando tento me conectar de servidores diferentes, cada conexão leva pelo menos 5 segundos (estou usandoInformações de tempo de Josephpara depuração):

$ 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

De acordo com curl, a pesquisa leva a maior parte do tempo, porém o padrão nslookupé muito rápido:

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

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

Depois de forçar curlo uso do IPv4, fica muito melhor:

$ 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

Desativei o IPv6 no host:

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

embora o problema persista. Eu tentei correr stracepara ver qual é o motivo dos tempos limite:

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)

Não parece ser um problema de firewall, pois nslookup(ou curl -4) está usando os mesmos servidores DNS. Alguma ideia do que pode estar errado?

Aqui está tcpdumpo anfitrião 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)

EDITAR: Nos logs de bind frequentemente aparece esta mensagem:

error sending response: host unreachable

Porém, cada consulta é eventualmente respondida (leva apenas 5s). Todas as máquinas são servidores físicos (não é culpa do NAT), é mais provável que os pacotes estejam sendo bloqueados por um roteador. Aqui está uma pergunta provavelmente relacionada:As pesquisas de DNS às vezes levam 5 segundos.

Responder1

Resposta curta:

Uma solução alternativa é forçar glibca reutilização de um soquete para pesquisa dos registros AAAAe A, adicionando uma linha a /etc/resolv.conf:

options single-request-reopen

A verdadeira causa deste problema pode ser:

Resposta longa:

Programas gostam curlou wgetusam a função da glibcgetaddrinfo(), que tenta ser compatível com IPv4 e IPv6 pesquisando ambos os registros DNS em paralelo. Ele não retorna resultado até que ambos os registros sejam recebidos (hávárias questões relacionadas a tal comportamento) - isso explica o straceacima. Quando o IPv4 é forçado, como curl -4internamente gethostbyname(), que consulta Aapenas para registro.

A partir disso tcpdumppodemos ver que:

  • -> A?duas solicitações são enviadas no início
  • -> AAAA?(solicitando endereço IPv6)
  • <- AAAAresponder
  • -> A?solicitando novamente endereço IPv4
  • <- Arecebi resposta
  • -> AAAA?solicitando IPv6 novamente
  • <- AAAAresponder

Uma Aresposta foi descartada por algum motivo, é esta mensagem de erro:

error sending response: host unreachable

No entanto, não está claro para mim por que há necessidade de uma segunda AAAAconsulta.

Para verificar se você está tendo o mesmo problema, atualize o tempo limite em /etc/resolv.conf:

options timeout:3

Primeiro crie um arquivo de texto comconfiguração de relatório de tempo personalizado:

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

então envie uma solicitação:

$ 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

Existem duas outras opções relacionadas em man resolv.conf:

solicitação única (desde glibc 2.10)se RES_SNGLKUP instala _res.options. Por padrão, a glibc realiza pesquisas IPv4 e IPv6 em paralelo desde a versão 2.9. Alguns servidores DNS do dispositivo não conseguem lidar com essas consultas adequadamente e fazem com que as solicitações expirem. Esta opção desativa o comportamento e faz com que a glibc execute as solicitações IPv6 e IPv4 sequencialmente (ao custo de alguma lentidão no processo de resolução).

reabertura de solicitação única (desde glibc 2.9) O resolvedor usa o mesmo soquete para as solicitações A e AAAA. Alguns hardwares enviam de volta por engano apenas uma resposta. Quando isso acontecer, o sistema cliente irá aguardar pela segunda resposta. Ativar esta opção altera esse comportamento para que, se duas solicitações da mesma porta não forem tratadas corretamente, o soquete será fechado e um novo será aberto antes de enviar a segunda solicitação.

Assuntos relacionados:

Responder2

Como diz o @Tombart, o atraso se deve à espera pelo tempo limite de resolução do IPv6.

Outro curso de ação possível é dar precedência ao IPv4 em /etc/gai.conf

Dos comentários em /etc/gai.conf

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

Depois de alterar gai.conf, você precisa reiniciar qualquer aplicativo usando a biblioteca de resolução de DNS para que a alteração tenha efeito.

Lembre-se de que se você estiver usando um servidor BIND sem conectividade IPv6, aconselho desabilitar o IPv6 namede obter endereços IPv6 das dicas de raiz. Obviamente ainda tentará resolver endereços AAAA.

Então, para a configuração do BIND,

Em /etc/default/bind9, adicione -4 para endereços IPv4:

OPTIONS="-4 -u bind"

e em /etc/bind/db.root, exclua todas as linhas com raízes DNS AAAA.

Responder3

Eu tive um problema semelhante ao usar o BIND9. Para corrigir isso, precisei adicionar:

filter-aaaa-on-v4 yes;

opção para o meu named.conf.

(Mais Informações)

Responder4

Caso alguém esteja procurando o curl-format.txt. Cole isso em seu shell e ele criará o arquivo de formato para você. O link original não funcionou para mim. encontrei este exemploaqui

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

informação relacionada