Túneles con OpenVPN

29 Oct 2009

Siempre me ha gustado el término “road-warrior”, que es aquel empleado/usuario que se conecta a la red de la empresa, a través de una red segura, desde cualquier lado. La utilidad en mi caso no es mucha, pero era uno de esos “retos a montar”. Y qué mejor para desempolvar los conocimientos de enrutamiento en Linux. Y es que todos mis conocimientos de redes los adquirí con FreeBSD, y las cosas cambian un poco.

Tenía ganas de probar un software que te da mucho hecho, pero no todo, para montar una VPN. Es el caso de OpenVPN, que soporta scripts post-conexión en cliente, uso de una PKI para autenticar, y demás etcéteras que se pueden ver en su web.

Conseguir crear el túnel fue bastante sencillo, no hay que hacer mucho más allá de abrir los puertos necesarios y (en el caso de usar una clave simétricacon  >openvpn –genkey –secret clave.txt), copiar la clave. El cliente para Windows que instalé no viene con interfaz gráfica (en mi Asus EEE 701 cada mega de su disco duro de 4GB es un tesoro), pero crear un acceso directo que llame al fichero de configuración no es nada complicado.

El esquema de la red, por si a alguien le sirve esto (las IPs públicas son ficticias), es:

Servidor            Router bajo control                  Router externo         Road Warrior
192.168.2.3---192.168.2.1/80.34.216.120---Internet---80.23.213.24/192.168.1.1---192.168.1.66
10.8.0.1=========================================================================10.8.0.2


Aquí se ve cómo se establece un túnel IP (no es a nivel de enlace, como Ethernet), entre los dos equipos. Hasta aquí todo perfecto. Para hacer conexiones al resto de la red podríamos utilizar túneles SSH como expliqué hace tiempo, pero es más cómodo que el Road Warrior pueda conectarse directamente al resto de la red. ¿Y cómo hacemos esto? Pues configurando a nuestro Linux para que se comporte como un router, es decir, para que pase paquetes de datos de una red (el túnel) a la otra. Y lo que es muy importante: también a la inversa.

Para hacer esto, básicamente basta con ejecutar, dada la estructura de red anterior, un script como el siguiente:

iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
iptables -A FORWARD -i tun0 -o eth1 -m state –state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i eth0 -o tun0 -j ACCEPT
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE

iptables -A FORWARD -i tun0 -o eth1 -m state --state ESTABLISHED,RELATED -j ACCEPT

iptables -A FORWARD -i eth0 -o tun0 -j ACCEPT

echo 1 > /proc/sys/net/ipv4/ip_forward


Con lo que conseguimos:

Que se haga un “cambio de dirección” de los paquetes que salgan enrutados por eth1 (la interfaz de red que conecta a “Servidor” con “Router bajo Control”)

Que se reenvíen los paquetes que lleguen por tun0 (el túnel) hacia eth1 .

Que se reenvíen los paquetes que lleguen por eth1 con destino tun0.

Y a continuación los ficheros de configuración del servidor:

dev tun

ifconfig 10.8.0.1 10.8.0.2

proto tcp-server

port 1194

push "dhcp-option DNS 192.168.2.1"

secret openvpnkey.txt

verb 2

Que indica que se use un tunel IP (tun), define las direcciones de ambos extremos, que se use TCP (en muchos casos es recomendable UDP, para conseguir una menor latencia en el túnel, pero creo que en el caso de usar redes wifi abiertas, donde se pueden perder muchos paquetes ya sea por la poca potencia o por los muchos clientes simultáneos es mejor usar TCP ¿opiniones?), por el puerto 1194 (que tendremos que abrir en el router). Las opciones “push” se ejecutarán en el cliente como si estuvieran en su fichero de configuración. Y openvpnkey.txt es donde se guarda “el tesoro”.

Y en el cliente nada raro:

remote 80.34.216.120

dev tun
ifconfig 10.8.0.2 10.8.0.1
route 192.168.2.0 255.255.255.0
proto tcp-client
secret secreto.txt
verb 2


Tras un par de días de rascarme la cabeza en ratos sueltos, conseguí que funcionara… Lo siguiente: crear un pool de direcciones, que sea todo más automático y lo que se me vaya ocurriendo. ¿Se te ocurre algo? ¿Alguna mejora? ¿No te funcionó?