Encapsulando tráfico

Thursday, 13 de August de 2015

"IP over…" da para muchas cosas. Por ejemplo, el maravilloso protocolo de IPoAC. Pero hoy voy a hablar de otra cosa. IP sobre DNS, y de IP sobre ICMP.

¿Motivo? Viajar. Y la necesidad de tener un mínimo de comunicación, aunque sea navegación web reducida a mínimos, Telegram y poco más. Porque a menudo los precios resultan inabarcables… y porque algo bueno tendrá que tener ser un tecnofriki.

Dos cosas, por lo tanto: iodine para encapsular vía DNS, y hans para hacerlo a través de ICMP. En mi caso, he escogido la configuración más sencilla: una máquina en DigitalOcean dedicada exclusivamente para la tarea (dado que interferir con DNS e ICMP puede resultar complicado si no), y un dominio propio con control sobre la zona DNS.

Instalando iodine

Lo primero es crear la zona DNS. Asumiendo que tenemos un dominio h4x0r.com, y la IP de nuestro servidor es 123.123.123.123, bastaría con crearlo de tal manera que iodine.h4x0r.com fuese una entrada A apuntando a la IP, y tunnel.h4x0r.com fuese una entrada NS apuntando a iodine.h4x0r.com. como nombre cánonico. Muy importante el punto al final para que no sea relativo.

Después, en el servidor, hay que instalar iodine. En la última Debian es muy fácil: apt-get install iodine y listo. Con ello, sólo queda configurar bien iodine editando el fichero /etc/default/iodine:

START_IODINED="true"
IODINED_ARGS="10.0.0.1 tunnel.h4x0r.com"    
IODINED_PASSWORD="h4x0r"        

La primera línea hace que el daemon se llegue a ejecutar (si no, el script init.d no se ejecutaría). Después, los argumentos: primero, la IP —privada— que tomaría el servidor una vez establecido un túnel, y después, el dominio público que apunta al túnel (ojo: la entrada NS aquí). Y por último, la contraseña en texto plano del túnel que deberán conocer tanto cliente como servidor. Cámbiala.

Llegados hasta aquí, basta con lanzar iodine como un servicio normal, haciendo /etc/init.d/iodined start y listos.

Cosas a tener en cuenta: primero, que iodined actúa en el puerto 53 así que no debe haber ninguna instancia servidor de bind o de dnsmasq corriendo. De ahí el interés de tener un servidor (virtual) y una IP dedicada únicamente para esta tarea. Después, que realmente iodine lleva dos procesos: iodine que es el cliente, y iodined que es el servidor. Ambos usan argumentos casi idénticos así que puede dar lugar a confusión.

Instalando hans

En Debian esto es un pelín más complicado, porque no viene en los repositorios. Pero no es mucho más complicado. Lo primero: tener todas las herramientas para poder compilar, y git también, por comodidad. Si no lo tienes: apt-get install build-essential git y listo. Luego, basta con compilar y moverlo al $PATH, en mi caso, por elección personal, /usr/sbin que es donde está iodine (puedes verlo usando whereis).

git clone https://github.com/friedrich/hans.git
cd hans
make
sudo mv hans /usr/sbin/

Y ya está. Si ejecutas hans en cualquier directorio debería darte la versión.

Siguiente paso: hacer que se comporte como un demonio. Del sistema. Para eso me he limitado a copiar los ficheros de default de iodine y el init.d también, ajustándolo a las necesidades de hans. Luego con insserv se configura como servicio y se lanza al arranque. Aquí están los ficheros que he usado: el primero se debe copiar a /etc/default/hans y el segundo a /etc/init.d/hans. Luego:

chmod +x /etc/init.d/hans
insserv hans

El fichero de defaults es muy similar al de iodine. En la primera línea, dejar que el script de init.d pueda correr (forma fácil de desactivarlo). Después, la IP privada en la que se situará el servidor host (he usado un rango distinto al de iodine para evitar posibles conflictos). El flag -r hace que hans responda también a los paquetes de ping normales, lo cual puede ser útil para saber fácilmente si el proceso está corriendo. Aunque al no responderse desde la capa kernel, es normal que la latencia percibida en el ping se dispare. No pasa nada. Y finalmente, la contraseña del túnel (no olvides cambiarla y recordarla).

Finalmente, un último detalle: hay que hacer que el sistema no responda a los paquetes ICMP, para que hans pueda hacerlo. Muy sencillo. Basta con editar el fichero /etc/sysctl.conf y añadir una línea al final:

net.ipv4.icmp_echo_ignore_all = 1

Aquí es recomendable reiniciar el sistema. No es necesario realmente: con sysctl -p se pueden refrescar los ajustes del kernel sobre ignorar ICMP, y se pueden levantar ambos servicios a mano, pero así veremos si los servicios se levantan a la vez sin problemas. Y para comprobarlo, ejecuta ps aux como root, y tanto hans como iodine deberían figurar en la lista.

Usando iodine y hans desde OSX

Asumo que a estas alturas cualquier persona ya conoce brew en OSX. Así es muy fácil: brew install iodine y tendremos iodine instalado. Puede que dé algún error con la instalación de tun/tap, pero basta con seguir las instrucciones que ofrece el error para instalar ese componente y listo.

Para hans, se puede compilar (muy fácil en OSX si se tienen las herramientas instaladas) o directamente usar el binario compilado oficial y copiarlo al $PATH de tu elección (en mi caso, /usr/local/sbin, porque es donde están los orígenes de los binarios instalados por brew).

Una vez terminada la instalación de ambos componentes, podremos ejecutar iodine y hans en cualquier directorio con éxito. Y como se están ejecutando en el servidor, ya basta con atacar la parte cliente.

El principio de todo esto es de establecer un túnel. Así, si ejecutamos hans en el cliente con todos los parámetros necesarios, establecerá un túnel mediante ICMP de tal manera que en la dirección 10.0.1.1 tengamos al servidor remoto (pero no acceso a internet puramente dicho). Es exactamente lo mismo con iodine, solo que con la IP 10.0.0.1. En ambos casos, son las IP especificadas en los ficheros de default donde se configuran los argumentos de ejecución de servidor.

Desde el cliente, se lanza así:

# Para iodine
sudo iodine -f -P h4x0r tunnel.h4x0r.com
# Para hans
sudo hans -f -c 123.123.123.123 -p h4x0r

Lógicamente, hay que cambiar tanto la IP, como la contraseña y la ubicación de la entrada NS para corresponderse con lo configurado. Aquí sigue los ejemplos. El parámetro -f hace que se mantengan en primer plano. Se pueden ejecutar en segundo plano quitando ese parámetro.

Si todo funciona con éxito, podremos hacer SSH a la IP remota (que varía según usemos hans o iodine, como explico arriba) y conectarnos con el servidor (y nada más). Así que todo lo que queramos hacer pasa a través del servidor.

Aquí entran en juego varias posibilidades. Por ejemplo, montar un proxy SOCKS (que viene directamente con SSH):

ssh -D 1080 root@10.0.x.1

Y así, en 127.0.0.1:1080 tendremos un proxy SOCKS con acceso a internet. Luego basta con configurarlo en las opciones de red de OSX para que lo usen la mayoría de programas, o en los ajustes avanzados de red en el caso de Firefox, especificando la IP del proxy como 127.0.0.1 (local) y el puerto 1080 (el especificado en el argumento -D de SSH). Y así tendremos internet.

Otra opción más avanzada, basada en la misma, es usar sshuttle, que es una especie de "VPN de mentira" sobre SSH que no requiere nada instalado en el servidor remoto y es mucho más liviano. Basta con instalarlo en OSX y ejecutarlo:

brew install sshuttle
sshuttle --dns -r root@10.0.x.1 0/0

Así, tendremos un túnel entre nuestro ordenador y el servidor (con una IP privada que será 10.0.0.1 o bien 10.0.1.1, según qué tipo de túnel sea), y dentro de ese túnel, todo el tráfico (es decir, el de la subred 0.0.0.0/0) estará enrutado mediante sshuttle.

Hay un montón de opciones más. Por ejemplo, si tenemos OpenVPN montado en el mismo servidor, bastará con lanzar el cliente de OpenVPN y especificar la IP privada del servidor al otro lado del túnel, y debería tener acceso completo a internet entonces. O si tenemos OpenVPN en otro servidor, el mismo cliente (por ejemplo, Viscosity) se puede configurar para emplear un proxy SOCKS.

También existen otras opciones más complicadas como configurar el servidor como router, y una vez establecido el túnel, modificar nuestra tabla de enrutado para configurar al servidor remoto al otro lado del túnel como gateway.

Pero dado el limitadísimo ancho de banda que se suele obtener con un túnel, la opción más sencilla suele ser la mejor… y en este caso, yo creo que usar SOCKS con únicamente un navegador es suficientemente satisfactorio (y además, evitas que otros procesos y programas saturen el poco ancho de banda que tienes, porque no pueden salir a internet al desconocer el proxy). Y si SOCKS se queda corto, entonces sshuttle puede ser el combo ideal. ¡Y con unas pocas líneas de terminal!