Creación de túneles en Linux

Publicado el 15 marzo 2017 por Drassill
La comunicación entre diferentes equipos para, ya sea mandar un mensaje, o acceder a una página web, se ha vuelto indispensable hoy en día, hasta el punto de que nadie puede conferir un ordenador sin acceso al resto de equipos de la red o a Internet. La cuestión está en que el mundo de las redes, al igual que todo en esta vida, ha ido evolucionando y adaptándose a las necesidades de hoy en día... El cambio más significativo que se ha realizado en este área, es sin lugar a dudas la implantación de IPv6, protocolo que ha ido ganando peso con el paso de los años debido a la necesidad de usarla... Aún así, el formato de IP más usado en la actualidad sigue siendo IPv4; tanto por su facilidad a nivel de gestión como por que a nivel tecnológico hay muchísimos equipos que no soportan IPv6. Esta imposibilidad de adoptar este nuevo protocolo hace que a veces sea imposible establecer una comunicación entre dos equipos, pues una IPv4 no puede comunicarse con una IPv6 ni viceversa, y debido a ello hay que encontrar soluciones que puedan lograr dicha comunicación; y es ahí donde entra en escena el concepto sobre el que os quiero hablar hoy: Los túneles.

Un túnel es una técnica que encapsula un protocolo dentro de otro, haciendo que una comunicación, que de por sí no es posible, se haga realidad. Por ejemplo podemos hacer que dos equipos que funcionan bajo IPv4 e IPv6, puedan comunicarse entre ellos con ambos protocolos, aún cuando están separados por un router que es capaz de enrutar únicamente IPv4. Existen tres tipos de túneles:
  • IPIP: Únicamente puede encapsular tráfico unicast, y además solamente permite "tunelizar" IPv4 sobre IPv4. 
  • SIT: Este tipo de túnel encapsula tráfico IPv6 sobre IPv4 además permite transmitir tanto en unicast como multicast.
  • GRE: Este es el tipo de túnel más "dinámico" y más completo, ya que permite encapsular tanto IPv4 como IPv6 sobre IPv4: permitiendo además también transmitirlo tanto en unicast como en multicast.

Teniendo en cuenta que el túnel GRE es el más completo, nos centraremos sobre éste, si bien hay que tener en cuenta que la creación de los otros dos túneles sería muy similar a la de uno del tipo GRE, con la diferencia de que en estos dos casos habría que tener en cuenta las limitaciones de dichos túneles.
Antes de crear el túnel en cuestión, veamos el siguiente diagrama con el fin de ponernos en situación;

Lo que tendríamos serían dos equipos, comunicados entre sí por un router que únicamente enruta IPv4, con lo que ambos equipos se comunican vía IPv4 pero no vía IPv6. Con el túnel lo que haríamos sería enviar el paquete con una cabecera IPv4 que sí que sería reconocida por el router haciendo que la comunicación IPv6 sea válida.
Para crear un túnel, sea del tipo que sea, tendremos que recurrir a la utilidad ip; utilidad estándar que está instalada por defecto en el sistema. En el equipo A escribiríamos lo siguiente:
  1. ip tunnel add tunel1 mode gre remote 192.168.2.10 local 192.168.1.10
  2. ip link set tunel1 up
  3. ip addr add fe80::d0:ffff:351e:1/64 dev tunel1
  4. ip route add ::/0 dev tunel1

Los comandos introducidos harían lo siguiente:
  • Con el primer comando estaríamos creando un túnel de tipo GRE entre nuestra IP local 192.168.1.10 y la IP remota 192.168.2.10.
  • Con el segundo comando, activamos dicho túnel, ya que por defecto estaría desactivado. Tras levantar dicho túnel, podríamos verlo como si fuese una interfaz de red más con el comando ifconfig.
  • El tercer comando asigna una IP al túnel en cuestión; IP que sería nuestra IPv6.
  • Por último, le pondríamos un gateway al túnel en cuestión.

En el equipo B, habría que hacer lo mismo, pero realizando el túnel a la inversa y asignando la IP correspondiente a la interfaz del túnel en cuestión.
  1. ip tunnel add tunel1 mode gre remote 192.168.1.10 local 192.168.2.10
  2. ip link set tunel1 up
  3. ip addr add fe80::d0:ffff:351e:2/64 dev tunel1
  4. ip route add ::/0 dev tunel1

Gracias a esta configuración, tendríamos un túnel GRE completamente operativo, pudiendo hacer ping (o cualquier otra acción) entre ambas IPv6 sin impedimento alguno, cosa que sin dicho túnel no habría sido posible.
En caso de querer eliminar nuestro túnel tendríamos que primero deshabilitar dicho túnel, para después borrarlo, lo cual se realizaría tal que así:
  1. ip routedel ::/0dev tunel1
  2. ip addrdel fe80::d0:ffff:351e:2/64dev tunel1
  3. ip link set tunel1 down
  4. ip tunnel del tunel1

Como podéis ver, los túneles son un recurso que pueden resultarnos de gran utilidad, ya que pueden hacer que conexiones "imposibles" puedan hacerse realidad; en caso de querer tener un túnel permanente, simplemente habría que realizar un script de arranque con las ordenes atrás mostradas; algo tan sencillo como (por ejemplo) crear el script tunelling.sh en /etc/init.d,/ con el siguiente contenido:
  1. #!/bin/bash
  2. # Inicia o para el tunel
  3. ### BEGIN INIT INFO
  4. # Provides:          tunel
  5. # Required-Start:    $network $remote_fs $syslog $time
  6. # Required-Stop:     $network $remote_fs $syslog $time
  7. # Default-Start:     2 3 4 5
  8. # Default-Stop:      0 1 6
  9. # Short-Description: Iniciador/parador tuneles
  10. # Description:       Script para arrancar o parar un tunel que se incluye en el arranque
  11. ### END INIT INFO
  12. case "$1" in
  13. start)  echo "Iniciando tunel"
  14.         ip tunnel add tunel1 mode gre remote 192.168.1.10 local 192.168.2.10
  15.         ip link set tunel1 up
  16.         ip addr add fe80::d0:ffff:351e:2/64 dev tunel1
  17.         ip route add ::/0 dev tunel1
  18.         ;;
  19. stop)  echo "Eliminando tunel"
  20.         ip route del ::/0 dev tunel1
  21.         ip addr del fe80::d0:ffff:351e:2/64 dev tunel1
  22.         ip link set tunel1 down
  23.         ip tunnel del tunel1
  24.         ;;
  25. *)      echo "Uso: /etc/init.d/tunelling.sh {start|stop|}"
  26.         exit 2
  27.         ;;
  28. esac
  29. exit 0

Dicho script tendría que tener permisos de ejecución y estar incluido en el arranque, cosa que haríamos mediante el uso del comando chmod (para darle dichos permisos) e insserv (para el arranque):
  1. chmod +x /etc/init.d/tunelling.sh
  2. innserv tunelling.sh

Gracias a esto no tendríamos un script que automatizaría el hecho de crear o destruir el túnel, sino que haríamos que dicho script se arrancase por defecto en el arranque, ahorrándonos la tediosa tarea de tener que "levantar" dicho túnel en cada arranque. Obviamente, el otro extremo del túnel tendría que tomar una medida similar con el fin de que el túnel se realice con éxito.
Espero que os haya resultado útil.
Saludos.