Tunel ipv6: montando un tunel 6in4 en Linux

Publicado por Diego Córdoba en

Hoy les traigo una pequeña pero interesante prueba de concepto para los amantes del networking y las redes TCP/IP. Cómo montar un tunel IPv6 6in4 para poder enviar tráfico IPv6 sobre una red IPv4.

Hace un tiempo estuve dando unas charlas sobre introducción teórica y práctica a IPv6 para CLA, pueden ver los videos en https://juncotic.com/webinars-introduccion-a-ipv6/

Como todos sabemos, IPv6 es el futuro de las comunicaciones en Internet, IPv4, el estandar IP que utilizamos todo el tiempo en la actualidad tiene sus días contados, y en breve los ISP’s comenzarán a implementar mecanismos de migración a ipv6.

Los sistemas operativos de la actualidad soportan, en general, dual-stack, lo que significa que poseen tanto soporte para IPv4 como IPv6. Nuestro querido Linux, por supuesto, soporta dual stack por defecto.

Suponiendo que tenemos equipos en nuestra red, o en Internet, que están conectados vía IPv4, como seguramente ocurrirá, es una limitación si queremos conectarnos y probar herramientas diseñadas para IPv6, o que tengan soporte.

Para ello, en esta pequeña prueba de concepto vamos a montar un túnel 6in4 entre dos equipos Linux que, en mi caso particular, son máquinas virtuales, pero que tranquilamente puede funcionar entre dos direcciones IPv4 públicas en la red.

Prueba de concepto: tunel ipv6 6in4

El siguiente esquema ilustra el caso:

6in4 tunel ipv6

Disponemos de un host con dirección 10.0.0.30/24 en un extremo, y otro con dirección 10.0.0.60/24 en el otro, comunicados por ipv4 naturalmente.

Como se apreciará, también cada host dispone de su dirección de link global ipv6 que, al no tener una red ipv6 configurada con routers intermedios que encaminen el tráfico, no podrán conectarse entre si.

Lo que haremos es montar un túnel SIT entre los dos hosts, y enrutaremos el tráfico ipv6 que viaje entre ellos por medio de la interfaz del túnel.

Manos a la obra

Analicemos los siguientes comandos ejecutados en el host 10.0.0.30:

ip tunnel add net6tun mode sit remote 10.0.0.60 local 10.0.0.30
ip link set net6tun up
ip addr add 2a01:d0:ffff:451e::30/64 dev net6tun
ip route add ::/0 dev net6tun

En la línea 1 creamos el túnel, llamado net6tun a elección, de tipo sit, con direccionamiento público ipv4, es decir, indicamos cuál es la dirección del host local y la del host remoto.

En la línea 2 levantamos la interfaz net6tun recién salida del horno.

En la línea 3 asociamos la dirección IPv6 de nuestro host a la interfaz del túnel.

Y finalmente en la línea 4 enrutamos todo el tráfico ipv6 con salida a la red por medio de la interfaz del túnel.

Por supuesto, es una prueba de concepto, algunos parámetros pueden cambiar en la realidad según las necesidades que tengamos.

Si nos fijamos ahora en la salida del comando «ip a» veremos algo similar a esto:

root@debian3:~# ip a
[...]
7: net6tun: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN
    link/sit 10.0.0.30 peer 10.0.0.60
    inet6 2a01:d0:ffff:451e::30/64 scope global
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:1e/128 scope link
       valid_lft forever preferred_lft forever

root@debian3:~# ip -6 r
2a01:d0:ffff:451e::/64 via :: dev net6tun  proto kernel  metric 256  mtu 1480 advmss 1420 hoplimit 0
fe80::/64 dev eth2  proto kernel  metric 256  mtu 1500 advmss 1440 hoplimit 0
fe80::/64 via :: dev net6tun  proto kernel  metric 256  mtu 1480 advmss 1420 hoplimit 0
default dev net6tun  metric 1024  mtu 1480 advmss 1420 hoplimit

Vemos que tenemos configuración de red con la interfaz net6tun con los direccionamientos de túnel, y el direccionamiento ipv6 seteado, mientras que en la tabla de enrutamiento vemos que tódo el tráfico ipv6 por defecto (default) se enruta en la interfaz net6tun.

Hecho esto, repitamos los pasos en el host 10.0.0.60 cambiando, por supuesto, las direcciones ip de lugar. Aquí los comandos:

ip tunnel add net6tun mode sit remote 10.0.0.30 local 10.0.0.60
ip link set net6tun up
ip addr add 2a01:d0:ffff:451e::60/64 dev net6tun
ip route add ::/0 dev net6tun

Y veamos la configuración final, tanto de direccionamiento como de enrutamiento:

root@curso:~# ip a
[...]
5: net6tun: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1480 qdisc noqueue state UNKNOWN
    link/sit 10.0.0.60 peer 10.0.0.30
    inet6 2a01:d0:ffff:451e::60/64 scope global
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:3c/128 scope link
       valid_lft forever preferred_lft forever

root@curso:~# ip -6 r
2008:db9:fe:19::/68 dev eth1  proto kernel  metric 256
2a01:d0:ffff:451e::/64 via :: dev net6tun  proto kernel  metric 256
fe80::/64 dev eth0  proto kernel  metric 256
fe80::/64 dev eth1  proto kernel  metric 256
fe80::/64 via :: dev net6tun  proto kernel  metric 256
default via 2008:db9:fe:19:: dev eth1  metric 1024
default dev net6tun  metric 1024

Probando el túnel

Ahora la prueba de fuego, el ping6.

ping es la herramienta de testeo universal (siempre que el tráfico ICMP no esté filtrado xD).

Ping6 es el comando que nos va a permitir enviar tráfico por dentro del tunel.

Lo que haremos, en el host 10.0.0.30, ejecutaremos un comando ping que envíe mensajes echo-request en ICMPv6, es decir, icmp encapsulado en IPv6, que a su vez, irá encapsulado en IPv4, no es emocionante? :’)

root@debian3:~# ping6 -I 2a01:d0:ffff:451e::30 2a01:d0:ffff:451e::60
PING 2a01:d0:ffff:451e::60(2a01:d0:ffff:451e::60) from 2a01:d0:ffff:451e::30 : 56 data bytes
64 bytes from 2a01:d0:ffff:451e::60: icmp_seq=1 ttl=64 time=0.251 ms
64 bytes from 2a01:d0:ffff:451e::60: icmp_seq=2 ttl=64 time=0.265 ms
[...]

Al parecer el ping funciona!

Vayamos ahora al host 10.0.0.60 y veamos qué pasa por el cable. Veamos qué trafico podemos capturar en la interfaz del tunel:

root@curso:~# tcpdump -nni net6tun
tcpdump: WARNING: net6tun: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on net6tun, link-type RAW (Raw IP), capture size 65535 bytes
20:12:38.798558 IP6 2a01:d0:ffff:451e::30 > 2a01:d0:ffff:451e::60: ICMP6, echo request, seq 1, length 64
20:12:38.798607 IP6 2a01:d0:ffff:451e::60 > 2a01:d0:ffff:451e::30: ICMP6, echo reply, seq 1, length 64
20:12:39.797967 IP6 2a01:d0:ffff:451e::30 > 2a01:d0:ffff:451e::60: ICMP6, echo request, seq 2, length 64
20:12:39.798011 IP6 2a01:d0:ffff:451e::60 > 2a01:d0:ffff:451e::30: ICMP6, echo reply, seq 2, length 64

Efectivamente, viaja tráfico direccionado en IPv6, que dentro lleva mensajes ICMPv6 de echo-request y sus respuestas, echo-reply. Nótese las direcciones ipv6 de origen y destino y compárelas con las de las configuraciones.

Y finalmente, lo más interesante, capturemos tráfico en la interfaz eth0, la interfaz física que conecta nuestro equipo 10.0.0.60 a la red, o a Internet:

root@curso:~# tcpdump -nni eth0 not port 22 and host 10.0.0.30 -vv
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
20:10:45.948421 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto IPv6 (41), length 124)
    10.0.0.30 > 10.0.0.60: IP6 (hlim 64, next-header ICMPv6 (58) payload length: 64) 2a01:d0:ffff:451e::30 > 2a01:d0:ffff:451e::60: [icmp6 sum ok] ICMP6, echo request, seq 1
20:10:45.948463 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto IPv6 (41), length 124)
    10.0.0.60 > 10.0.0.30: IP6 (hlim 64, next-header ICMPv6 (58) payload length: 64) 2a01:d0:ffff:451e::60 > 2a01:d0:ffff:451e::30: [icmp6 sum ok] ICMP6, echo reply, seq 1
20:10:46.947208 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto IPv6 (41), length 124)
    10.0.0.30 > 10.0.0.60: IP6 (hlim 64, next-header ICMPv6 (58) payload length: 64) 2a01:d0:ffff:451e::30 > 2a01:d0:ffff:451e::60: [icmp6 sum ok] ICMP6, echo request, seq 2
20:10:46.947256 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto IPv6 (41), length 124)
    10.0.0.60 > 10.0.0.30: IP6 (hlim 64, next-header ICMPv6 (58) payload length: 64) 2a01:d0:ffff:451e::60 > 2a01:d0:ffff:451e::30: [icmp6 sum ok] ICMP6, echo reply, seq 2
[...]

He filtrado algunas salidas de puerto 22 y otras yerbas para que no me ensucie de basura lo que realmente me interesa, lo que se ve en pantalla. Como se aprecia, tenemos tráfico IPv4 direccionado entre los hosts 10.0.0.30 y 10.0.0.60, que adentro lleva paquetes de protocolo número 41, es decir, IPv6. De esta forma se aprecia que tenemos en el stack tcp/ip paquetes de IPv4 que encapsulan paquetes de IPv6.

Los paquetes IPv6 son los mismos que vimos antes, pero ahora «metidos» dentro de paquetes IPv4. El paquete IPv6 a su vez encapsula los mensajes ICMPv6.

Gráficamente, podríamos dibujarlo así:

6in4scheme tunel ipv6

Espero que les sirva! Compartan si les pareció interesante!!

Hasta la próxima!!


Diego Córdoba

- Ingeniero en Informática - Mg. Teleinformática - Tesis pendiente - Docente universitario - Investigador