System DNS Cache en Linux

12 Junio 2013 at 19:02 by Adrián Pérez

cache DNSEste fin de semana casi nos cargamos a un pobre servidor DNS por un exceso de consultas al realizar un envío de varios miles de mails. En algunos servidores Linux, no hay una caché DNS a nivel de sistema operativo, y por tanto, cada envío de mail requiere de su correspondiente resolución DNS, a pesar de que se estén enviando 1.000.000 de mails todos al mismo dominio @miempresa.com. [fuente, otra fuente, y más fuentes].

Ésto  lo podemos comprobar, por ejemplo desde mi portátil con Fedora, monitorizando con tcpdump las peticiones DNS y ejecutando en paralelo un "ping google.com":

[root@AdriPC sh]# tcpdump -vvv -s 0 -l port 53
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
16:44:09.480324 IP (tos 0x0, ttl 64, id 14684, offset 0, flags [DF], proto UDP (17), length 59)
AdriIPC.36193 > google-public-dns-a.google.com.domain: [udp sum ok] 14321+ A? www.google.es. (31)
16:44:09.509206 IP (tos 0x0, ttl 64, id 14713, offset 0, flags [DF], proto UDP (17), length 66)
AdriIPC.51444 > google-public-dns-a.google.com.domain: [udp sum ok] 64003+ PTR? 8.8.8.8.in-addr.arpa. (38)
16:44:09.520190 IP (tos 0x0, ttl 48, id 61176, offset 0, flags [none], proto UDP (17), length 91)
google-public-dns-a.google.com.domain > AdriIPC.36193: [udp sum ok] 14321 q: A? www.google.es. 2/0/0 www.google.es. [3m28s] A 173.194.34.247, www.google.es. [3m28s] A 173.194.34.248 (63)
16:44:09.533873 IP (tos 0x0, ttl 64, id 14738, offset 0, flags [DF], proto UDP (17), length 73)
AdriIPC.50336 > google-public-dns-a.google.com.domain: [udp sum ok] 27187+ PTR? 247.34.194.173.in-addr.arpa. (45)

[...]

Si ejecutamos "ping google.com" una segunda vez, veremos como vuelve a capturarse la consulta DNS mediante tcpdump, confirmando así que no hay ningún tipo de caché DNS.

En la mayoría de escenarios, no necesitaremos una caché DNS, pero si tenemos un servidor que ofrece un servicio que hace un uso intensivo de resolución de nombres, seguramente nos merezca la pena buscar una solución.

"Nscd": A Name Service Caching Daemon

Prácticamente copio del "man": nscd es un demonio que proporciona una caché para la mayoría de peticiones DNS. Nscd ofrece una caché para las bases de datos passwd, group y hosts, configurando para cada una de ellas, un TTL (time-to-live) separado para sus datos.

Además, nscd mantiene dos cachés, una donde cachea los resultados positivos y otra para los resultados negativos (las consultas DNS a dominios que no existen, ya sea por qué se ha escrito mal el dominio de consulta o porqué efectivamente ese dominio no tiene una entrada DNS). Ésto puede provocar algunos problemas, si por ejemplo, un host que no existe, se marca en la caché de entradas negativas y posteriormente se crea. En este caso, la caché no se refrescará y por tanto, nscd continuará diciéndonos que el host no existe.  Lo mismo pasa cuando una entrada positiva cambia el valor de su registro DNS, lo cual puede ser un problema.

Lo primero que podemos hacer para conseguir tener una caché DNS a nivel de sistema, es instalar el propio nscd, que ya puede venir instalado con el SO pero que por lo menos, que yo haya visto, no viene con la instalación mínina de CentOS 6, y tampoco con mi Fedora 17 con KDE.

[root@AdriPC sh]# yum install nscd.x86_64

A continuación podemos iniciarlo y probarlo:

[root@AdriPC sh]# service nscd start

Lo probaremos de igual forma. Iniciaremos tcpdump para capturar el tráfico, haremos un primer ping que veremos que captura el tcpdump, pararemos el ping, y posteriormente haremos otro ping que esta vez no veremos en nuestro tcpdump, indicando así que la caché funciona correctamente.

Podremos ver estadísticas de uso de nscd con:

[root@AdriPC sh]# nscd -g

Y con grep, podemos centrarnos en el porcentaje de aciertos, que tras la instalación será 0:

[root@AdriPC sh]# nscd -g | grep -i hit
0 cache hits on positive entries
0 cache hits on negative entries
0% cache hit rate
0 cache hits on positive entries
0 cache hits on negative entries
0% cache hit rate
0 cache hits on positive entries
0 cache hits on negative entries
0% cache hit rate
0 cache hits on positive entries
0 cache hits on negative entries
0% cache hit rate

También podremos ver el listado de dominios cacheados con el siguiente comando [fuente]:

[root@AdriPC sh]# strings /var/db/nscd/hosts | grep -P '[\w-]+\.\w+' | sort -u

Si como en mi caso, te interesa que postfix use la caché, será necesario hacer algo de trabajo adicional, tal y como explican aquí. Básicamente deberemos ir al fichero de configuración de postfix y añadir las siguientes líneas:

[root@AdriPC sh]# vi /etc/postfix/main.cf
[...]
# Use nscd for DNS cache
lmtp_host_lookup = native
smtp_host_lookup = native

Para aplicar los cambios, será necesario reiniciar postfix:

[root@AdriPC sh]# /usr/sbin/postfix -c /etc/postfix/ stop
[root@AdriPC sh]# /usr/sbin/postfix -c /etc/postfix/ start

Una vez hecho ésto, podremos ver como va aumentando la lista de hosts cacheados, y como empezamos a tener estadísticas de acierto en la caché.

Nscd tiene, además, la opción de iniciarse con el parámetro "-d" lo cual no llevará a background el proceso, si no que lo dejará en primer plano, en modo debug, y nos permite así ir viendo cómo va trabajando la caché.

Bind 9 como caché

Otra opción, seguramente más profesional, sea usar bind. Bind es EL servidor DNS, y permite configurarse únicamente como caché, de tal manera que cada vez que se realiza una petición DNS, ésta se consulta en el servidor bind local y en caso de no tenerla, se la traiga para las siguientes consultas. Para configurar este entorno en un servidor Fedora, he seguido los pasos, tal cual están, en este fantástico enlace, que paso a resumir a continuación (todo el mérito para el autor original).

Instalaremos y copiaremos los ficheros de configuración de ejemplo:

[root@myServer]# yum install bind bind-chroot
[root@myServer]# cd /var/named/chroot/etc
[root@myServer]# cp /usr/share/doc/bind-9.7.3/sample/etc/named.conf .
[root@myServer]# cp /usr/share/doc/bind-9.7.3/sample/etc/named.rfc1912.zones .

Modificaremos el fichero de configuración, named.conf y lo dejaremos tal y como sigue (destaco en negrita los cambios que he tenido que hacer):

[root@myServer]# cat /var/named/chroot/etc/named.conf
options {
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";

listen-on port 53 { 127.0.0.1; any; };
listen-on-v6 port 53 { ::1; };

allow-query { localhost; any; };
allow-query-cache { localhost; any; };
recursion yes;

dnssec-enable yes;
dnssec-validation yes;
dnssec-lookaside auto;

/* Path to ISC DLV key */
bindkeys-file "/etc/named.iscdlv.key";
managed-keys-directory "/var/named/dynamic";
};

logging {
channel default_debug {
file "data/named.run";
severity dynamic;
};
};

include "/etc/named.rfc1912.zones";

Todo el resto del fichero de configuración por defecto, lo eliminaremos, y posteriormente, daremos permisos (con bind, se nos creará el usuario de sistema y grupo "named"):

[root@myServer]# cd  /var/named/chroot/etc/
[root@myServer]# chown root:named named.conf named.rfc1912.zones

A continuación, verificaremos que el fichero de configuración no tenga errores, e iniciaremos el servicio (y lo configuraremos para que se arranque automáticamente con el sistema):

[root@myServer]# named-checkconf named.conf
[root@myServer]# service named restart
[root@myServer]# chkconfig named on

Para usar el servidor dns local, a modo de caché, necesitaremos modificar el fichero resolv.conf para consultar el servidor DNS local en primer lugar:

[root@myServer]# cat /etc/resolv.conf
nameserver 127.0.0.1

Ahora ya estaremos usando el servidor local para la resolución DNS. Podremos verificarlo, ejecutando algunas consultas DNS con nslookup. Veremos como tras unas dos o tres consultas seguidas a un mismo dominio, ya pasaremos a usar el servidor local para la resolución (las primeras resoluciones se harán con el servidor DNS especificado en segundo lugar en el fichero /etc/resolv.conf):

[root@myServer]# nslookup opendns.com
Server: 8.8.8.8
Address: 8.8.8.8#53

Non-authoritative answer:
Name: opendns.com
Address: 67.215.92.210

[root@myServer]# nslookup opendns.com
Server: 127.0.0.1
Address: 127.0.0.1#53

Non-authoritative answer:
Name: opendns.com
Address: 67.215.92.210

Como guinda, podremos refrescar la caché de base de datos para repasar las entradas DNS que está cacheando, ejecutando los siguientes dos comandos (en orden):

[root@myServer]# rndc dumpdb -cache
[root@myServer]# vi /var/named/data/cache_dump.db

Si estás enviando mails o en definitiva haciendo uso intensivo de consultas DNS, con el servidor de caché DNS  local pegarás una gran mejora en cuanto a rendimiento, y de paso reducirás consumo de ancho de banda.

Fuentes nscd

Fuentes bind

Flickr! Foto por cm195902