Escribí una interfaz de usuario de terminal para Mullvad VPN con Ruby
Publicado el Miércoles, 23 de octubre de 2024Desde hace un tiempo vengo usando Mullvad VPN como proveedor de VPN. Mullvad cuenta con una aplicación bastante práctica que funciona en Android, Linux y demás sistemas operativos populares. En su momento, no estaba disponible para Raspberry Pi (y creo que ahora tampoco).
Encontré que podía usar Mullvad con WireGuard. La aplicación usa el protocolo WireGuard por defecto. Cuando seguí las instrucciones en el enlace, me quedaron un montón de archivos de servidores en /etc/wireguard
. Los archivos son de la forma ie-dub-wg-101.conf
, cl-scl-wg-001.conf
, etc. Siguen el formato código de país, ciudad, interfaz (wg para WireGuard, pero podría ser OpenVPN), y el número de servidor.
Para empezar, hay que loguearnos a la terminal con la cuenta root, o ejecutar con sudo, el comando wg-quick up [SERVIDOR]
para conectarnos. Donde SERVIDOR
es el nombre del servidor en la forma del nombre de estos archivos. Esto hace que resulte un poco tedioso buscar el nombre del servidor. Buscar en /etc/wireguard
, cada archivo descargado tiene la configuración con tu clave de Mullvad. Y el nombre también nos sirve para elegir el servidor para wg-quick up
. Esto fue lo primero que se me ocurrió que quería automatizar.
Hacía tiempo que tenía vistas las herramientas TTY, un set de bibliotecas para desarrollar aplicaciones de línea de comando en Ruby. Terminé usando únicamente TTY::Prompt. Esta biblioteca nos provee un DSL para generar interfaces que piden entrada de usuario. Nos facilita mucho la creación de menúes de selección, como en mi caso un menú de países o el menú principal de la aplicación:
menu.choice name: 'Leonardo', value: 'leo'
menu.choice name: 'Donatello', value: 'donnie'
menu.choice name: 'Raphael', value: 'raph'
menu.choice name: 'Michelangelo', value: 'mikey'
end
Esto nos va a generar la siguiente interfaz:
El valor que elegimos va a ser guardado en la variable opcion
(en este caso leo
, donnie
, raph
o mikey
).
Así que esencialmente la app implementa a través de éstos menúes la navegación que haría para conectarme a una VPN por línea de comando. Implementé varias opciones:
- A veces simplemente quiero conectarme y no me importa a qué país. Para eso implementé la opción "Random", que elige un servidor al azar de los disponibles y se conecta.
- Otras veces quiero conectarme a un país en particular, para eso hice un menú donde elijo un país, y se conecta a un servidor al azar de ese país.
- Por último está la opción de listar todos los servidores disponibles, agrupados por país y ciudad, y seleccionar uno. TTY::Prompt provee la opción de filtrar, así que si empezamos a escribir el nombre de un país, nos va a mostrar los que coincidan para encontrarlo más rápido.
Después hago las llamadas al sistema con las apps. En el caso de WireGuard usa:
$ curl https://am.i.mullvad.net/connected # Chequear si está conectado
$ wg-quick down # Desconectarse de un servidor
Cuando se conecta, serializa y guarda en disco el servidor que usamos, para saber cómo desconectarse más adelante. Esto se podría mejorar accediendo a la conexión actual de repente.
En el caso de Mullvad, usa los comandos de mullvad cli. Al usarlo por primera vez, debemos ingresar nuestro número de cuenta. Para eso usé la opción ask
de TTY::Prompt, que imprime una pregunta y tenemos que ingresar una respuesta mediante teclado. Con la cli de Mullvad, tenemos acceso a la información de conexión actual así que los datos que tenemos que manejar o persistir son distintos.
Toda la parte de serializar o guardar es algo que podría mejorar. Una de las mejoras sería tomar en cuenta más opciones de sistema, porque estoy usando hardcodeado el valor de ~/.local/share/mullvadrb
como directorio para guardar las configuraciones.
Inicialmente el código usaba WireGuard a través de wg-up
. Después decidí reescribir la "arquitectura" (comillas para que no suene como que fue planeado y no que fui hackeando el código hasta que fue agarrando forma) sobre la aplicación de línea de comando mullvad
. Finalmente, reintegré el código de wg
para casos en los que no quiera (o no pueda) usar la aplicación de Mullvad (que fue la razón inicial por la que empecé a escribir este código).
Si bien inicié git en el código hace unos pocos días, lo vengo usando desde hace como un año. La Raspberry Pi 4 que compré tiene más de un año, y lo empecé a poco tiempo de haber empezado a usarla. Finalmente decidí compartirlo en caso de que sea útil para alguien más, y eso también me obligó a empaquetarlo y dejarlo un poco menos desprolijo de lo que era inicialmente. Como siempre, algo aprendí en el camino.
Hay varias mejoras posibles por hacerle, por ejemplo más funcionalidades soportadas por ambos "backends" como les llamé. Pero sería cuestión de agregarlos. También si resulta útil para más gente, le agregaría i18n, para tener al menos una versión en Español. Pero no creo que sea una herramienta muy requerida. Ya le agregué un toque de Gaélico Escocés por ahí.
No descarto una reescritura general más, ahora que tengo en la cabeza el modelo general de cómo funciona cada backend y qué necesito en cada uno. Es una base de código relativamente chica y lo escribí en principio "para que ande" y después ya por diversión, así que no le pongo mucha exigencia.
El código fuente está en GitHub, y ya publiqué dos versiones disponibles en RubyGems. Agregué un ejecutable cosa de que una vez instalada la gema, pueda ejecutar mullvadrb
desde cualquier terminal en mi sistema.
ar 24 octubre. 2024 - 14:00
¡Muy bueno!
Aprovecho para consultarte; esa imagen de la consola al estilo CRT ámbar de los 70/80, ¿es una consola de tu máquina configurada así? Me gustaría saber cómo hacerlo.
Fernando 30 octubre. 2024 - 06:42
Es cool-retro-term, “un emulador de terminal con la apariencia y sensación de las antiguas pantallas de tubos de rayos catódicos”. La descubrí allá por 2014, y si bien no la uso para trabajar todo el tiempo, para esta herramienta en particular me encanta usarla.