Tengo un bind9
servidor DNS maestro y 2 servidores esclavos ejecutándose en IPv4 (Debian Jessie), usando /etc/bind/named.conf
:
listen-on-v6 { none; };
Cuando intento conectarme desde diferentes servidores, cada conexión tarda al menos 5 segundos (estoy usandoInformación del tiempo de Josépara depurar):
$ 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
Según curl
, la búsqueda lleva la mayor parte del tiempo, sin embargo, el estándar nslookup
es muy rápido:
$ time nslookup example.com > /dev/null 2>&1
real 0m0.018s
user 0m0.016s
sys 0m0.000s
Después de forzar curl
el uso de IPv4, se pone mucho mejor:
$ 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
He desactivado IPv6 en el host:
echo 1 > /proc/sys/net/ipv6/conf/eth0/disable_ipv6
aunque el problema persiste. Intenté ejecutar strace
para ver cuál es el motivo de los tiempos de espera:
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)
No parece ser un problema de firewall ya que nslookup
(o curl -4
) está usando los mismos servidores DNS. ¿Alguna idea de qué podría estar mal?
Esto es tcpdump
del anfitrión 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: En los registros de vinculación aparece con frecuencia este mensaje:
error sending response: host unreachable
Sin embargo, cada consulta finalmente se responde (solo se necesitan 5 segundos). Todas las máquinas son servidores físicos (no es culpa de NAT), es más probable que un enrutador bloquee los paquetes. Aquí hay una pregunta muy probablemente relacionada:Las búsquedas de DNS a veces tardan 5 segundos.
Respuesta1
Respuesta corta:
Una solución alternativa es obligar glibc
a reutilizar un socket para buscar registros AAAA
y A
agregando una línea a /etc/resolv.conf
:
options single-request-reopen
La verdadera causa de este problema podría ser:
- firewall o enrutador mal configurado (por ejemplo, unLa configuración del firewall de Juniper se describe aquí) lo que provoca la caída
AAAA
de paquetes DNS - error en el servidor DNS
Respuesta larga:
Programas como curl
o wget
usan la función de glibcobteneraddrinfo(), que intenta ser compatible tanto con IPv4 como con IPv6 buscando ambos registros DNS en paralelo. No devuelve resultado hasta que se reciben ambos registros (hayvarios problemas relacionados con tal comportamiento) - esto explica lo strace
anterior. Cuando se fuerza IPv4, como curl -4
internamente gethostbyname()
, que consulta A
solo para registros.
De tcpdump
podemos ver que:
-> A?
Se envían dos solicitudes al principio.-> AAAA?
(solicitando dirección IPv6)<- AAAA
responder-> A?
solicitando nuevamente la dirección IPv4<- A
obtuve respuesta-> AAAA?
solicitando IPv6 nuevamente<- AAAA
responder
Una A
respuesta se descarta por algún motivo; ese es este mensaje de error:
error sending response: host unreachable
Sin embargo, no me queda claro por qué es necesaria una segunda AAAA
consulta.
Para verificar que tienes el mismo problema, puedes actualizar el tiempo de espera en /etc/resolv.conf
:
options timeout:3
Primero cree un archivo de texto conconfiguración de informes de tiempo personalizados:
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
luego envía una solicitud:
$ 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
Hay otras dos opciones relacionadas en man resolv.conf
:
solicitud única (desde glibc 2.10)se establece
RES_SNGLKUP
en_res.options
. De forma predeterminada, glibc realiza búsquedas de IPv4 e IPv6 en paralelo desde la versión 2.9. Algunos servidores DNS de dispositivos no pueden manejar estas consultas correctamente y hacen que las solicitudes expiren. Esta opción desactiva el comportamiento y hace que glibc realice las solicitudes de IPv6 e IPv4 de forma secuencial (a costa de cierta ralentización del proceso de resolución).reapertura de solicitud única (desde glibc 2.9) El solucionador utiliza el mismo socket para las solicitudes A y AAAA. Algunos hardware envían por error sólo una respuesta. Cuando eso suceda, el sistema cliente se sentará y esperará la segunda respuesta. Activar esta opción cambia este comportamiento de modo que si dos solicitudes del mismo puerto no se manejan correctamente, se cerrará el socket y se abrirá uno nuevo antes de enviar la segunda solicitud.
Asuntos relacionados:
Respuesta2
Como dice @Tombart, el retraso se debe a la espera del tiempo de espera de resolución de IPv6.
Otro posible curso de acción es dar prioridad a IPv4 en /etc/gai.conf
De comentarios en /etc/gai.conf
# For sites which prefer IPv4 connections change the last line to # precedence ::ffff:0:0/96 100
Después de cambiar gai.conf
, debe reiniciar cualquier aplicación que utilice la biblioteca de resolución de DNS para que el cambio surta efecto.
Tenga en cuenta que si está utilizando un servidor BIND sin conectividad IPv6, le recomiendo deshabilitar IPv6 named
y tomar de la raíz las direcciones IPv6. Obviamente seguirá intentando resolver las direcciones AAAA.
Entonces, para la configuración BIND,
En /etc/default/bind9, agregue -4 para direcciones IPv4:
OPTIONS="-4 -u bind"
y en /etc/bind/db.root
, elimine todas las líneas con raíces DNS AAAA.
Respuesta3
Tuve un problema similar al usar BIND9. Para solucionar esto necesitaba agregar:
filter-aaaa-on-v4 yes;
opción a mi named.conf
.
Respuesta4
En caso de que alguien esté buscando el archivo curl-format.txt. Pega esto en tu shell y creará el archivo de formato por ti. El enlace original no funcionó para mí. encontré este ejemploaquí
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