Nos han dicho tantas veces que no quedan direcciones IPv4 como que el petroleo se va a acabar en los próximos años. No nos lo hemos creído nunca. Ocurrirá, pero no será pronto. Y cuando ocurra, confiamos en que siempre habrá alguien que nos dirá lo que tenemos que hacer.

Por eso mismo es tan importante que los que estamos en el mundillo sepamos IPv6: para ser ese alguien al que los demás recurrirán cuando llegue el momento. Hoy, y en las siguientes entregas de esta serie (de periodicidad totalmente irregular, no prometo nada), os voy a hablar de cómo funciona una red local, como la que podríamos tener en casa o en el trabajo, pero con IPv6.

Requisitos

La mejor manera de abordar este problema es con máquinas virtuales. Yo voy a usar Virtualbox, que permite configurar varios interfaces de red en cada máquina virtual.

Linux tiene soporte de IPv6 desde hace mucho tiempo, pero vamos a necesitar software que no instalamos habitualmente. En concreto, radvd, que es algo ligeramente parecido a un servidor DHCP para IPv6. Ojo, que no es lo mismo: también hay servidores DHCP para IPv6, pero esto es diferente. El cambio a IPv6 no significa sólo que las direcciones IP son un tocho hexadecimal incomprensible, sino que también cambian varios conceptos a los que estábamos habituados en IPv4.

El plan

Voy a configurar una red privada con tres máquinas virtuales:

  • Un firewall que conectará la red IPv6 a la red IPv4, para poder salir a Internet
  • Una máquina virtual sencilla, que simulará un equipo de escritorio cualquier y configurará su red automáticamente
  • Un servidor interno, con varios servicios en una de sus direcciones IPv6

Los equipos (menos el firewall) no tendrán direcciones IPv4, sino que usarán IPv6 para todas sus necesidades. Habrá que configurar un "convertidor IPv6 a IPv4" (tiene otro nombre mucho menos divertido en realidad: túnel 6to4) en el firewall, y más cosas que ahora mismo, sin haberme metido en harina, no conozco.

Sobre IPv6

Puedes leer los detalles sobre IPv6 en muchos sitios, como aquí. En la práctica, IPv6 significa tres cosas:

  • Más direcciones IP. ¿Cuántas más? 10^23 por metro cuadrado, o 4.8x10^28 por persona en el mundo. Todo esto suponiendo un reparto equitativo y un uso similar al de IPv4, que no es el caso. Aún así, son "una jartá" de direcciones IP.
  • Una dirección IP pública (o mejor dicho, "rutable") para todo. Visto de otra forma, el fin de las redes privadas y el NAT.
  • Autoconfiguración. Que llegues a cualquier entorno IPv6, tanto público como privado, y no tengas que hacer nada para que tu dispositivo se conecte a la red.

Otra novedad es que en IPv6 hay varios tipos de direcciones: link-local, site-local (obsoletas, pero las verás en muchos sitios), global, anycast, multicast, 6to4 ... y creo que me he dejado alguna más. Da igual: para empezar, sólo te tienes que preocupar por las direcciones link-local y las direcciones globales (global address type).

De las otras mejoras de IPv6 (soporte de IPSec, QoS, rutado por jerarquía, etc.), ni caso. Te las encontrarás cuando haga falta, no antes. Y además, lo bueno y lo malo de IPv6 es que se trata de un estándar que aún está poco probado en el mundo real; "huele a nuevo", como se suele decir. Muchas de sus especificaciones son teóricamente perfectas porque no las usa nadie. En un tiempo, con unos años a las espaldas y varias implementaciones distintas en uso, acumulará parches e incompatibilidades; y entonces será un estándar de verdad.

El primer ping

Cada interfaz de red configura automáticamente una dirección IPv6 en cuanto se activa. Por ejemplo: en el interfaz eth1 de mis máquinas virtuales visix1 y visix2 no he configurado nada, y los he levantado a pelo con "ip":

# ip link set up dev eth1

Si ahora miro la dirección de red de eth1 en visix1:

# ip -6 a l dev eth1

3: eth1: mtu 1500 qlen 1000
    inet6 fe80::a00:27ff:fe5a:f5f/64 scope link 
       valid_lft forever preferred_lft forever

Eso que parece una dirección MAC precedido por "inet6" ("fe80::a00:27ff:fe5a:f5f/64") es la dirección link-local de eth1, incluyendo su máscara de red ("/64"). link-local significa que sólo sirve para comunicarse con los equipos que estén conectados al mismo segmento de red. Haciendo lo mismo en visix2 obtenemos la dirección fe80::a00:27ff:feba:f05d/64. Todas las direcciones link-local empiezan por el prefijo fe80::, los dobles dos puntos incluídos. Lo demás es una versión codificada de la dirección MAC del interfaz.

Con todo esto podemos hacer nuestro primer ping, desde la dirección de visix1 a la de visix2. Para eso usamos ping6, y además tenemos que indicar el interfaz de red por el que va a salir el tráfico:

# ping6 -c1 -I eth1 fe80::a00:27ff:feba:f05d
PING fe80::a00:27ff:feba:f05d(fe80::a00:27ff:feba:f05d) from fe80::a00:27ff:fe5a:f5f eth1: 56 data bytes
64 bytes from fe80::a00:27ff:feba:f05d: icmp_seq=1 ttl=64 time=1.44 ms

--- fe80::a00:27ff:feba:f05d ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.446/1.446/1.446/0.000 ms

Podemos indicar el interfaz a usar dentro de la misma dirección, añadiendo "%". O sea, que el comando de antes también podría haberlo tecleado así:

# ping6 -c1 fe80::a00:27ff:feba:f05d%eth1
PING fe80::a00:27ff:feba:f05d%eth1(fe80::a00:27ff:feba:f05d) 56 data bytes
64 bytes from fe80::a00:27ff:feba:f05d: icmp_seq=1 ttl=64 time=0.965 ms

--- fe80::a00:27ff:feba:f05d%eth1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.965/0.965/0.965/0.000 ms

Así es más fácil usar la dirección con servicios en los que no podemos indicar por qué interfaz salir, o simplemente por comodidad.

¿Por qué hace falta indicar el interfaz? Si lo piensas un poco, tiene sentido: todas las direcciones link-local tienen el mismo prefijo, que es lo que podrías intentar usar para rutarlas, por lo que no hay forma de saber cuál va a estar disponible en uno u otro interfaz.

Tu siguiente pregunta debería ser: "¿y por qué no mandas un who-has ARP por broadcast, y contestas por el interfaz en el que recibes la respuesta?" (que es lo que haríamos en IPv4). Pues porque no hay ARP en IPv6. Para lo que hacíamos con ARP se usará ICMPv6.

El Gran Principio Universal de IPv6

Llegados a este punto, tenemos que hacer un breve inciso teórico.

Ya has visto lo que son las direcciones link-local. Puedes usarlas para cualquier cosa que usarías una dirección "normal" IPv6 (aunque todavía no sepas bien qué es una dirección "normal" IPv6): para hacer ping, para conectarte a servicios TCP o UDP configurados en esa dirección, etc. Y además, como dependen de la MAC de la tarjeta, que no es algo que cambie frecuentemente, puedes usarlas como direcciones IP fijas. Podrías configurar toda una red local con estas direcciones. Podrías ponerlas en una zona DNS para no tener que recordarlas, y ya está. Tu LAN en IPv6, sin hacer nada. Puedes dejar de leer el artículo aquí mismo.

Esta facilidad para crear una red con direcciones IPv6 no es casual. Una parte muy importante de su diseño fue maximizar las posibilidades de autoconfiguración de los dispositivos que estuvieran conectados a una red con IPv6. No es algo nuevo: lo que hemos visto con direcciones IPv6 es, más o menos, lo mismo que hay en IPv4 con direcciones APIPA (169.254/16).

Pero estas direcciones no son rutables. No puedes salir con ellas a otras redes como, por ejemplo, Internet. Tu mente contaminada con IPv4 pensará: "puedo usar NAT". Pero no hay NAT en IPv6 (en teoría). Eso iría contra el Gran Principio Universal de IPv6: todas las direcciones deben ser rutables. Dicho de otra forma, todo dispositivo conectado a Internet debe tener una dirección única alcanzable por el resto de dispositivos de la red. ¿Significa eso que un pirata informático adolescente que vive en una habitación de 2x2 metros en Kowloon puede hacerle ping a tu impresora desde su ordenador? Idealmente, sí. Se espera que haya ciertos controles para que eso no pase salvo que tú quieras, pero los tiros van por ahí.

Este Gran Principio Universal es lo que tiró abajo uno de los tipos de direcciones que había hasta hace poco, las direcciones site-local. Si las direcciones link-local están restringidas a un segmento de red, las site-local están restringidas a la red de un site (una organización). Son el equivalente directo de las redes RFC 1918. Si ves por ahí alguna dirección que empieza por fec0::, sabrás que quien la usa no está a la última. Puedes señalarle con el dedo y reírte de él, o trolear su zona de comentarios.

Que tú puedas tener en casa una dirección site-local que, por ejemplo, una PYME en Chequia está usando para su LAN, va en contra del Gran Principio Universal. Habría dos direcciones IPv6 repetidas, y por lo tanto no rutables. Si un paquete IPv6 llegara a un router para esa IP, ¿cómo sabría a dónde mandarla? ¿A tu casa, o a la oficina del contable checo?

Por supuesto, esta decisión tiene sus inconvenientes. Si tienes que cambiar de proveedor de Internet, y estás usando direcciones site-local, sólo tienes que cambiar el NAT que haces en el firewall y ya está. Sin NAT, tendrías que cambiar todo tu direccionamiento IP para que encajara con el suyo. Hay atenuantes: la parte del proveedor sería sólo una parte de la dirección, y podrías mantener el resto; y las herramientas de autoconfiguración IPv6 se encargarían de que no tuvieras que hacer nada a mano. Aún así, muchos han protestado, diciendo que les quitarán sus redes privadas de sus fríos dedos muertos. No sé todavía en qué acabará el asunto, pero de momento las direcciones site-local siguen deprecated.

En resumen: lo ideal es que tu equipo tenga una dirección IPv6 única en el mundo, con la que pueda llegar tanto al equipo de la habitación de al lado como a un ordenador de Nueva Zelanda. Al mismo tiempo, también tendrá una dirección link-local que podrá` usar para comunicarse con los equipos de su mismo segmento de red. Tener varias direcciones IP es lo normal en el mundo IPv6.

Siguiente entrega: más allá de las direcciones link-local


En la siguiente entrega vamos a configurar un servidor radvd y, por el mismo precio, también un servidor DHCPv6 para dar servicio a nuestra red. Vamos a ver qué diferencias hay, a ver si entendemos por qué existen dos cosas tan parecidas. Atento a tu lector RSS.


Ésta es una de esas entradas rápidas que le pegan más a Javier. Pero como me he pasado un día entero preguntándome por qué no funcionaba, y ahora al menos sé cómo hacer que funcione de forma más o menos limpia, lo pongo por aquí para que Google lo encuentre y les ahorre el trabajo a otros.

DHCP


No hace falta que explique qué es DHCP, ¿verdad? Todos hemos configurado algún servidor DHCP, sea para una red casera o para algo más serio. Lo típico es configurar una sección subnet para asignar direcciones IP en una red determinada. Un ejemplo sacado de la documentación del ISC DHCP Server (el servidor DHCP estándar):


subnet 10.254.239.0 netmask 255.255.255.224 {
  range 10.254.239.10 10.254.239.20;
  option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org;
}

Definimos la red 10.254.239.0/27 y asignamos direcciones IP entre la 10 y la 20 de ese rango. Como "bonus", también les decimos a nuestros clientes que los routers de la red son rtr-239-0-1.example.org y rtr-239-0-2.example.org. Personalmente pondría las direcciones IP y no los nombres DNS, porque no le hemos dicho a los clientes dónde está el servidor DNS; pero esto es sólo un ejemplo, y yo estoy divagando.

Aparte de esta definición, otra menos frecuente es la de host, con la que asignamos una dirección IP concreta a un dispositivo identificado por su MAC. Por ejemplo:

host pruebita {
  hardware ethernet 08:00:27:9c:28:77;
  fixed-address 192.168.1.198;
}

Que es lo mismo que decir: al dispositivo con MAC 08:00:27:9c:28:77 le das siempre la dirección IP 192.168.1.198. Yo lo he usado sobre todo para dispositivos como impresoras, en los que es más fácil dejar DHCP y asignar la IP en la configuración del servidor que pelearse con los menúes en miniatura que traen en el panel de control. También es práctico para otros equipos de gestión incómoda, como controladoras de cabinas de discos y similares.

Asignando nombres


Una opción adicional que podemos añadir al ejemplo anterior es la de host-name, con la que (en teoría) el equipo se pondrá el nombre que le indiquemos.



host pruebita {
  hardware ethernet 08:00:27:9c:28:77;
  fixed-address 192.168.1.198;
  option host-name "pruebita";
}

Casos de uso: si tenemos varios equipos que han sido instalados con una imagen genérica, y queremos darle a cada uno un nombre distinto. Por ejemplo, los equipos de un laboratorio, varias máquinas virtuales, etc.

Pues bien. Resulta que en Debian y Ubuntu esto no funciona. Para no ofender a nadie, voy a decirlo de otra forma: yo no conseguí hacerlo funcionar, y todos los comentarios que vi en Internet decían lo mismo.

La solución es hacer lo que pone en este artículo de Debian Administration: un script en /etc/dhcp/dhclient-exit-hooks.d que actualiza el hostname cuando dhclient obtiene una dirección IP. Pero el script que pone de ejemplo aquí no es muy limpio. Si se fijan, para obtener el nombre del equipo hace un host de la dirección IP y parsea la salida. Sucio. Feo. Poco elegante.

Así que, henchido de vanidad y con la inmodestia que me caracteriza, propongo una alternativa mucho más sencilla:

#!/bin/sh
h=$new_host_name
if [ "$h" ]; then hostname $h && echo $h > /etc/hostname; fi

(que iría como /etc/dhcp/dhclient-exit-hooks.d/hostname)

La variable "$new_host_name" es el nombre que ha asignado el servidor DHCP para el cliente, proporcionada por dhclient a los scripts que ejecuta como hooks. No hace falta recurrir al DNS, y de hecho ni siquiera tendría por qué estar funcionando (aunque es muy recomendable; os ocurrirán cosas horribles si tenéis un DNS mal configurado).

Y con eso quedaría solucionado el problema ... si no fuera por NetworkManager.

NetworkManager


Todo lo anterior sirve cuando hemos configurado el interfaz de red en /etc/network/interfaces. Nuestra configuración será algo así:

auto eth0
iface eth0 inet dhcp

En ese caso, todo funcionará como decía: se ejecutará dhclient y se actualizará el hostname con los datos de servidor. Pero en los equipos que instalan una Ubuntu o Debian moderna, "para escritorio", la configuración de red no se hace ahí: se hace mediante NetworkManager.

Este engendro programa no ejecuta los hooks de dhclient, aunque sea lo que usa "por debajo". Tiene su propio (e incompatible) sistema para acciones que se llevan a cabo tras la configuración de un interfaz de red en /etc/NetworkManager/dispatcher.d.

Los scripts ejecutados en ese directorio reciben ciertas variables de entorno de NetworkManager, incluyendo las relativas a DHCP. Éstas tienen la forma DHCP4_*, y en concreto la del nombre del equipo es DHCP4_HOST_NAME. Por lo tanto, tenemos que hacer una versión del script anterior para NetworkManager, y usando esta variable. Yo lo he puesto en /etc/NetworkManager/dispatcher.d/99hostname, con esto:

#!/bin/sh

case "$2" in
    up)
        hostname $DHCP4_HOST_NAME && echo $DHCP4_HOST_NAME > /etc/hostname
        ;;
esac

Esto, por fin, funciona. Es posible que al equipo no le guste mucho arrancar con un hostname y que luego, cuando ya hay servicios funcionando, cambie a otro. Aunque me duele decirlo, lo mejor en estos casos es un reinicio para que todo arranque con el nuevo hostname. A lo mejor llega con reiniciar lightdm o su equivalente, pero no puedo asegurarlo.