TL;DR


Telefónica ha hecho un uso "creativo" del DNS, que implica que quien tenga soporte IPv6 podría no acceder a www.agenciatributaria.es.

El problema


Imagínate esto: quieres consultar algún dato para hacer la declaración de la renta 2013/2014, o quizás confirmar tu borrador. Lanzas tu navegador favorito y pones www.agenciatributaria.es en la barra de navegación. Para tu sorpresa, pasa una de estas cosas:


  • Da un error de "conexión rechazada"
  • Sale una página por defecto de Apache, nginx o algún otro servidor web
  • Una tercera opción que desvelaré luego, para no estropear la historia

Lo más probable es que te pase esto si usas Linux. Puede que tengas algún amigo o compañero al que no le pase, y que usa OSX o Windows. Desde tu móvil tampoco pasa. ¿Por qué? ¿Es por usar Linux?

La explicación


En parte, sí. Es por usar Linux, pero no por algún tipo de discriminación fascista o conspiración judeo-masónica, sino por una cuestión tecnológica: Linux prefiere conectarse a sitios accesibles por IPv6 antes que por IPv4. Un ejemplo práctico: mi otro blog está en un VPS con IPv6, y cuando haces una consulta DNS obtienes dos resultados: un registro A con la IP en IPv4 y un registro AAAA con IPv6. Así, si sólo tienes IPv4, te conectas a la IP indicada por el registro A; pero si tienes conexión a Internet con IPv6, te conectas a la IP indicada por el registro AAAA.

"¡Pero yo no tengo conexión a Internet con IPv6!", exclamas. Es cierto, pero sí que tienes conexión a ciertas IPs IPv6. Como mínimo, dos:


  • La IP link-local de tu interfaz de red (la que empieza por fe80). Vete un momento al primer artículo sobre IPv6 que escribí para ver cuál es.
  • La IP ::1, que es la IP en IPv6 del interfaz "lo". O, dicho de otra forma, el equivalente de 127.0.0.1 en IPv6.


Veamos ahora qué pasa cuando le preguntas a un servidor DNS por www.agenciatributaria.es. Esto es lo que sale con el comando host www.agenciatributaria.es:

www.agenciatributaria.es is an alias for b7123.cdn.telefonica.com.
b7123.cdn.telefonica.com is an alias for b7123.1.cdn.telefonica.com.
b7123.1.cdn.telefonica.com has address 81.45.8.14
b7123.1.cdn.telefonica.com has address 81.45.8.8
b7123.1.cdn.telefonica.com has IPv6 address ::

www.agenciatributaria.es es un CNAME (un alias) que apunta a b7123.cdn.telefonica.com, que por el nombre es una parte de la Content Delivery Network (CDN) de Telefónica. Para entendernos, la versión de Telefónica de lo que hace Akamai. A su vez, este registro es un CNAME que apunta a b7123.1.cdn.telefonica.com. El registro b7123.1.cdn.telefonica.com apunta a dos direcciones IP, 81.45.8.14 y 81.45.8.8. Cada vez que preguntes, te dirá una de ellas. Es una forma fácil y común de repartir carga.

Lo interesante viene en la última línea: el registro b7123.1.cdn.telefonica.com también tiene una entrada AAAA (IPv6), apuntando a  ... ¿"::"? ¿Qué es "::"?

Lo mismo que ::1. Es decir: localhost. Telefónica tiene un registro IPv6 apuntando a localhost.

Cuando lanzas el navegador y te conectas a www.agenciatributaria.es, el navegador resuelve el nombre y eso le lleva primero a b7123.cdn.telefonica.com y luego a b7123.1.cdn.telefonica.com. Si no tienes soporte de IPv6, irás a una de las dos IPs apuntadas por este registro. Pero si tienes IPv6, irás a la IP "::", que es lo mismo que "::1". O sea, que te conectarás al servidor web de tu equipo.

Ahora podrás imaginarte la tercera opción que no desvelé antes: puede que cuando te conectas a www.agenciatributaria.es aparezca en tu navegador la página web que tengas configurada en tu servidor local (si existe). Puede que aparezca la página por defecto del servidor. O puede que no tengas ningún servidor web y te dé un error de "Conexión rechazada". He ahí nuestras tres posibilidades.

Todo porque alguien en Telefónica configuró mal un registro DNS.

La solución


La solución, obviamente, es que Telefónica corrija ese registro. Es más: sólo con quitar el registro AAAA ya se arreglaría el problema. Así no habría respuestas IPv6, y todo el mundo iría a las dos IPs balanceadas por el registro b7123.1.cdn.telefonica.com. Si realmente quieren usar IPv6, que pongan una IP de verdad, y no el equivalente de "localhost". Si tu equipo recibe una IP IPv6, seguirá intentando conectarse a ella antes que a la de IPv4; pero como no tienes conexión a Internet con IPv6, la conexión no funcionará y Linux intentará la conexión IPv4. Todo de forma transparente, sin que te enteres.

La chapuza


La forma más chapucera y sencilla de arreglar este problema es añadir una entrada en /etc/hosts para www.agenciatributaria.es con una de las dos IPs a las que resuelve b7123.1.cdn.telefonica.com. Es decir, algo así:

81.45.8.8    www.agenciatributaria.es

De esa forma, no pasarás por los servidores DNS de Telefónica para resolver el nombre, evitando el problema.

Otra solución es que el servidor DNS que usas no te devuelva registros AAAA. Si sólo tienes IPv4, no te hacen falta. Si no controlas el servidor DNS (porque usas el de tu ISP, por ejemplo), no es una solución válida. Pero si es tuyo, y usas Bind, y ha sido compilado con la opción --enable-filter-aaaa , puedes añadir esto a la sección options:

filter-aaaa-on-v4 yes;

De esta forma, Bind no devolverá registros AAAA a clientes que hayan hecho la consulta usando IPv4.

Conclusión


Niños, no dejéis a un becario configurar vuestro DNS. De este servicio dependen cosas importantes, y si no podéis pagar a alguien con conocimientos para que lo administre, es mejor que no os dediquéis a esto.



Volvemos con IPv6, después de demasiado tiempo sin decir nada sobre el tema. Hoy, redes privadas. O dicho de otra forma, la respuesta a la pregunta: ¿qué red escojo para mis pruebas?

RFC 1918: redes privadas en IPv4

El RFC 1918 define las redes privadas que todos conocemos. En orden de menor a mayor tamaño, son:

  • 192.168.0.0/16 (65 mil IPs)
  • 172.16.0.0/12 (un millón de IPs)
  • 10.0.0.0/8 (16 millones de IPs)

Los números no son exactos por eso de que trabajamos con 1024 y no con 1000, pero sirven para ilustrar las cantidades de las que estamos hablando.

En IPv6 existieron un tipo de direcciones llamadas site-local, destinadas a las redes de una organización (un site). Pero como explicaba en el anterior artículo sobre IPv6, fueron marcadas como "deprecated" por la dificultad de definir qué era un site. El verdadero equivalente de las redes privadas IPv4 en IPv6 son las unique local addresses (RFC 4193).

Las unique local addresses son direcciones no rutables globalmente en IPv6. Eso significa que un router no las mandará a Internet, sino que las descartará y te mirará extrañado preguntándose por qué le estás enviando esa porquería. Luego le contará al resto de routers lo patoso que eres. Los routers, por definición, son unos cotillas de cuidado.

El espacio asignado para estas direcciones es fc00::/7, que a su vez se divide en dos redes con máscara de 8 bits: fc00::/8 (pendiente de definición, y reservada) y fd00::/8, que es la que podemos usar.

Uso de la red fd00::/8

La red fd00::/8 nos da chorrocientos miles de millones de direcciones IP (millón arriba, millón abajo). Debería llegar para cualquier red privada del mundo. De hecho, toda la red IPv4 cabría varias veces dentro de ésta: en IPv4 podemos usar 2^32 direcciones IP, y en una red IPv6 con máscara de 8 bits podemos usar 2^(128-8)  = 2^120 direcciones IP.

Si siguiéramos las reglas de asignación de IPs que usamos en IPv4, podríamos definir una subred dentro de fd00::/8 para nuestra LAN casera, y asignar secuencialmente las direcciones para nuestros dispositivos. Por ejemplo: fd00::/120 equivaldría a una clase C en IPv4 (máscara 24, 256 IPs); o, si tuviéramos una red corporativa, podríamos usar fd00::/112 para tener las mismas IPs que en una clase B (máscara 16, 65536 IPs). La dirección de red sería la fd00::0, la primera IP sería la fd00::1 y la IP de broadcast sería la fd00::00ff para la máscara 120 y fd00::ffff para la 112. Pero no es así cómo se hace en IPv6.

En IPv4 podíamos dividir cada dirección IP en dos partes: un prefijo (o "identificador de red") y un sufijo (o "identificador de host"). Ejemplo: en la dirección 192.168.1.50, asumiendo que está en una clase C, el prefijo sería 192.168.1 y el sufijo 50. Una dirección IPv6, en cambio, se divide en más partes:

  • Un prefijo de 8 bits (7+1, en realidad)
  • Un identificador global de 40 bits (que podría ser el ISP)
  • Un identificador de red de 16 bits
  • Un identificador de interfaz de 64 bits

El primer campo son las letras "fd", y no podemos tocarlos (nos saldríamos de la red fd00::/8). Éste y el siguiente campo (los primeros 48 bits) forman lo que se llama el "prefijo de rutado". En algunos sitios verás que se le llama identificador de red a los primeros 64 bits, no sólo los 16 que he puesto aquí; y en otros verás que se llama "prefijo de rutado" a esos mismos 64 bits. Tengan el nombre que tengan, son los que se van a usar para rutar el paquete hasta el dispositivo final.

El identificador único del dispositivo final es la parte de "identificador de interfaz". Puede ser generado de varias formas (a partir de la MAC del dispositivo, por ejemplo), y sólo importa que sea único. Podría repetirse en otra red, pero entonces los primeros 64 bits serían distintos y se mantendría su exclusividad.

En una dirección privada como la que buscamos podemos asignar nosotros los identificadores globales y de red. Podemos generarlos aleatoriamente para cada dispositivo, si queremos. El rutado no será un problema: si hemos definido fd00::/8 como nuestra red casera, cualquier cosa que esté ahí valdrá como dirección IP.

Sin embargo, sin darnos cuenta acabamos de responder a la pregunta inicial de "qué red uso". Podemos mantener la fd00::/8 como red local y generar todo menos los primeros 8 bits aleatoriamente, pero sería como usar la red 10.0.0.0/8 para la red de tu casa. Una opción mejor es buscar unos valores que nos gusten para los primeros 64 bits (teniendo en cuenta que los primeros 8 serán "fd"), y usarlos como nuestro "identificador de red". Tendríamos así una red privada con máscara de 64 bits, en la que cada dispositivo sería identificado por 64 bits generados como nos venga en gana.

Un ejemplo

Una ventaja de las direcciones IPv6 es que puedes usar unas pocas letras, lo que permite cierta creatividad. ¿Qué prefijos de red podríamos crear empezando por "fd" y añadiendo 6 bytes más? Para ver qué ha hecho otra gente en casos parecidos, buscad en Google "funny ipv6 addresses".

Personalmente, como soy un tío aburrido, voy a usar fded:dead::/64, porque se parece a "Red Dead" y así no me olvido de ella.

Próximamente: Asignación de direcciones públicas

Las direcciones IPv6 públicas se dividen en las mismas partes que las privadas: 48 bits de rutado, 16 de identificador de red, y 64 de identificador de dispositivo. Los ISPs tendrán asignadas redes con máscaras de 32 bits, y asignarán a sus usuarios redes con máscaras de 48 bits, que podrán dividirlas hasta en 65536 redes con máscara de 64 bits.

Es un lío, pero un lío interesante que queda para el siguiente artículo. Hasta entonces, espero haberte dejado suficiente para que juegues en casa durante un rato.



Aquí estoy otra vez, para hacer honor a mi impredecible agenda de publicación. Hoy voy a escribir algo muy cortito, y con una novedad: ¡benchmarks! A todo el mundo le gustan los benchmarks. Son como porno con números.

Éste en concreto viene de mi adquisición de un disco duro SSD para casa. Cada vez que cambio de disco tengo que copiar los datos viejos de un disco a otro, y siempre me pregunto cuál es la forma más eficiente. He usado varias a lo largo de los años, pero nunca me había puesto a comprobar cuál era la mejor. Hoy, aprovechando que tenía que mover unos GB de un sitio a otro (para reorganizar los datos de mis varios discos duros; tengo síndrome de Diógenes digital), lo he hecho, y pongo por aquí los resultados.

Antes de nada, aclarar que esto no ha sido un benchmark "de laboratorio". He probado varias formas de copiar los mismos datos y he puesto un "time" antes de cada comando para ver qué tiempos salían. No he reiniciado antes de cada prueba, ni usado sistemas de ficheros distintos por si algún comando era más rápido en uno que en otro, ni nada parecido. Ha sido una prueba de andar por casa. Para pruebas serias, id a otro sitio.

Escenario


Los ficheros que he copiado son los que están en mi directorio "incoming", que es donde pongo todo lo que me descargo de Internet y ficheros que luego borraré o moveré a otro sitio. En total, 12GB con una distribución de tamaños que pongo a continuación:

0KB-128KB:    154
128KB-512KB:  50
512KB-1MB:    77
1MB-10MB:     344
10MB-100MB:   340
100MB-1GB:    2
>1GB:         1

Tuve que hacer un script para sacar esos datos. Fijaos cuánto trabajo me dais.

Los datos los moví de un disco duro de 1TB a otro que tengo de 200GB, un viejo luchador que sigue dando guerra a pesar de que lo tengo desde hace muchos años y ha pasado por cuatro o cinco ordenadores diferentes. Un día de éstos morirá, así que no pongo en él nada que sea demasiado importante.

Resultados


Todos los resultados se hicieron entrando primero en el directorio origen. Primero usé lo más fácil, cp. Ésta fue la línea de comandos y los tiempos:

# time cp -a * /destino/
real    4m4.478s
user    0m0.186s
sys     0m41.427s

A continuación usé tar, que es lo que había leído por ahí que era más rápido. Los datos se pasan por un pipe de un proceso que lee a otro que escribe. Comando y resultados:

# time tar c . | (cd /destino/ ; tar x)
real    3m34.715s
user    0m2.209s
sys     1m25.936s

Unos 30 segundos de diferencia, que aunque no es mucho, podría ser más si hubiera más datos a copiar. El tiempo de sistema es bastante más alto: tardamos menos a base de exprimir un poco más el equipo.

Ahora veamos rsync:

# time rsync -av . /destino/
real    6m3.746s
user    3m56.847s
sys     2m11.127s

Mucho peor que tar, y bastante peor que cp. Además, fijaos en que no sólo tarda más en total, sino que el tiempo de sistema es más alto que el de tar. La gran ventaja de rsync es que nos permitiría interrumpir la copia y retomarla donde la habíamos dejado, algo que no podemos hacer ni con tar ni con cp. Y también podríamos usarlo para sincronizar un directorio con otro, por si hubiéramos actualizado el origen pero no el destino. En resumen: malo si tenemos que copiar todos los datos, bueno si sólo queremos copiar las diferencias.

El último contendiente es cpio:

# time find . -xdev | cpio -pvmd /destino
real    4m46.775s
user    0m6.575s
sys     1m15.035s

Los resultados están entre los de cp y los de rsync, aunque por debajo de los de tar. Puede que este comando no sea el más óptimo, porque dependemos de lo que tarde find en generar un listado de ficheros. Para comprobar si este factor era importante, pasé el resultado a un fichero y luego usé otra vez cpio, pasándole los datos de ese fichero en lugar de la salida de find. Es decir, esto:

# find . -xdev > /tmp/list.txt
# time cat /tmp/list.txt | cpio -pvmd /destino
real    4m6.589s
user    0m7.111s
sys     1m20.305s

Y sí, la cosa mejora bastante. El tiempo es como el de cp, más o menos. Moraleja: cuidado con los comandos que dependen de otros.

Veredicto


tar es el ganador de este benchmark. Una herramienta hecha hace 30 años sigue siendo la mejor después de tanto tiempo. O al menos, la mejor en este caso. Sería interesante repetir la prueba con más datos: 12 GB no es tanto, en los tiempos que corren.

Nada más por hoy. La próxima vez que tengáis que pasar datos de un sitio a otro, ya sabéis qué podéis usar.