Servidores DNS cacheados

Puede que en algún momento necesites cambiar los servidores DNS que utiliza una máquina y en esos casos puede que te importe lo que vas a leer a continuación. La forma habitual de hacer eso es editar /etc/resolv.conf y cambiar el valor de los nameserver. Sin embargo debes de tener en cuenta el funcionamiento del resolver de (g)libc porque tiene unas serias implicaciones si quieres cambiar los nameservers a utilizar.

Una de las peculiaridades del resolver de Unix es que cuando un proceso se inicia lee la configuración de /etc/resolv.conf (es una simplifación) y no vuelve a leerlo. Eso se hace con la función res_init() que inicializa las variables al leer /etc/resolv.conf y no se actualiza al cambiar el contenido. Esto signfica que si cambiamos los nameservers los procesos seguirán usando los antiguos y no aplicarán los nuevos cambios. Esto significa que al cambiar los nameservers si queremos que todo el sistema utilice la nueva configuración lo más práctico será reiniciar el sistema al completo ¡al más puro estilo Windows 98!

Evidentemente no es necesario reiniciar todo el sistema, lo anterior sólo era una generalización ¡sólo necesitamos reiniciar todos los servicios y aplicaciones que tengamos corriendo! ;-) La verdad es que para sufrir esa clase de downtime lo mejor en esos casos al final es reiniciar todo el sistema, y ya puedes aprovechar para otro tipo de actualizaciones o configuraciones.

Sé que cuesta creer un comportamiento tan primitivo, pero creedme que podéis encontrar varias referencias (desde la descripción de res_init) a varios artículos de gente que lo ha vivido como en el caso de http://myhowto.org/java/42-understanding-host-name-resolution-and-dns-behavior-in-java/

However, there is one more aspect of the name resolution – updating the system configuration. Interesting thing about the resolver library in UNIX is that it reads its configuration once upon the first resolution attempt and then never re-reads it. As result, if you change the IP address(es) of the DNS server(s), or the suffix, or any other parameters in /etc/resolv.conf file (the same applies to all resolver configuration files but now we will concentrate on the DNS configuration) the application will not notice the difference. The same applies to all other programs in the system.

There is no standard way to refresh the resolver configuration in Java. However, there is at least two ways to do it from C:
· Call res_init() function of the resolver library
· (more elegant way): reset the RES_INIT flag of the global _res.options variable

This means that those JBoss and Tomcat apps will be using the old DNS servers until you restart them. And that’s trouble.

No me lo creo, eso tiene que ser algo primitivo

Aún así puedes estar pensando que es imposible que Linux sea así, que no tienes que reiniciar todo el sistema para aplicar un cambio de red ¡si nisiquiera Windows se comporta así hoy en día. Pero la triste realidad es que es así, es como está documentado y es como funciona. Si quieres comprobar cómo se comporta tu máquina cuando cambias los nameservers, puedes hacerlo con el siguiente script en Python:


from time import sleep
import socket
while True:
  print(socket.gethostbyname_ex("www.google.com"))
  sleep(3)

Ejécutalo en background o en otra terminal y mientras puedes usar tcpdump para ver el tráfico de red. El script intentará resolver cada 3 segundos, así que si corres como root tcpdump podrás ver las peticiones al nameserver que tengas configurado en /etc/resolv.conf

# tcpdump -i any -n -p port 53

Si en ese momento, mientras tienes corriendo tcpdump y el script Python puedes editar tu fichero resolv.conf y poner un único nameserver distinto al que tienes configurado actualmente (pon 8.8.8.8 o 127.0.0.1 o cualquier IP de tu subred). Verás como las peticiones a de red siguen yendo a la antigua dirección IP.

¡Pero en mi máquina no pasa eso!

Ese comportamiento además de estar documentado se ha pedido su cambio en muchas ocasiones (por ejemplo en http://www.mailinglistarchive.com/fedora-devel-list@redhat.com/msg39340.html pero hasta ahora los desarrolladores de glibc no quieren aplicar ninguno de los parches disponibles que permiten actualizar la configuración, y parece que tanto Fedora como RedHat (y CentOS) quieren mantener la compatibilidad con ese comportamiento

Sin embargo en otras distribuciones, como las descendientes de Debian, primero utilizaron un parche de glibc que hace que la configuración de red de los procesos se actualice al cambiar la configuración de /etc/resolv.conf. Posteriormente Debian paso a utilizar eglibc que incluye esos parches como puede leerse en http://www.eglibc.org/archives/patches/msg00772.html y http://www.eglibc.org/archives/patches/msg00901.html.

Otras aplicaciones

Aparte de que algunas distribuciones corrijan el problema bien parcheando glibc o bien usando eglibc hay aplicaciones como Firefox o Chrome que intentan resolver ese problema observando /etc/resolv.conf y actualizando ellos mismos la configuración (por ejemplo en http://codereview.chromium.org/118061/). Incluso en Python han discutido si
http://www.linux-archive.org/fedora-development/231425-python-etc-resolv-conf-changes.html cambiar ese comportamiento, pero lo han dejado estar ya que es un comportamiento de libc.

Deja un comentario

Tu dirección de correo electrónico no será publicada.