07 abril 2014

Watchdog para Router WAN 3G con Nagios



Hace ya tiempo que publiqué en SbD cómo me deshice del Router de Telefónica, haciendo que la máquina que hace de firewall tenga la IP pública en un interfaz de tipo PPP. Sin embargo, y aunque la probabilidad de que falle es baja, ha habido veces (Murphy suele acompañar mucho en esto cuando estoy en la otra punta del mundo) en que la conexión PPP se ha muerto en algún punto que no permite una recuperación automática. 

Es decir, que o estás delante de la máquina para restaurar esa entrada o le pegas botonazo o desde fuera aquello nunca reinicia correctamente. 

Desde que tengo la infraestructura de Securízame ahí montada, así como la plataforma que usamos para los cursos de formación, la necesidad de minimizar el tiempo de caída es aún mayor.

Así que me propuse configurar un segundo acceso de backup para poder acceder a la máquina principal, y reiniciar dicha conexión a mano.

Para ello había pocas opciones legales (sin usar un acceso inalámbrico de un vecino):
  • Opción cara: Contratar otra línea de fibra/ADSL para backup
  • Opción asequible: Comprar un router WAN que permita conectar un modem con un chip 3G.   
Teniendo además un contrato con la operadora que me incluye fijo + móvil, por sólo 3 euros al mes dispongo de 1 GB de datos a través de 3G.

El router que compré era un Netgear mbrn3000 y aproveché un antiguo modem 3G de Movistar que tenía en un cajón.

El siguiente paso es: ¿a qué máquina accedo?, le pongo una IP privada al firewall? Entonces voy a tener dos gateways por defecto, tendré que montar un watchdog que dependiendo de si tiene IP pública en el interfaz ppp0 o no, levante el otro interfaz con direccionamiento privado y añada la ruta por defecto al router 3G….Uffff qué lío! Casi que mejor voy a utilizar un Raspberry Pi que tengo aquí, y NATeo el puerto SSH o monto OpenVPN contra él…. Vaya pero entonces tengo otro problema, el Raspberry Pi sólo tiene una interfaz IP, por lo que igualmente tengo que asignar un direccionamiento privado en otra interfaz al firewall. Además el Raspberry PI, es menos fiable que el Windows 95 y el Windows Millenium juntos… Casi que mejor monto una máquina virtual en la máquina principal, conecto un interfaz contra el router 3G y una interfaz virtual aparte, contra el firewall. Así hay que acceder contra esta máquina por OpenVPN y de ahí salto al firewall por dentro, pudiendo levantar el servicio a mano.

Por si os habéis perdido hasta aquí, os pongo un dibujo de lo que os he explicado anteriormente:



Una vez configurado OpenVPN y el IPTables de esa máquina virtual, un script para actualizar un dominio DynDNS (recordemos que el interfaz 3G no me da una dirección IP fija), varias rutas estáticas a mano,…. podía decirse que estaba todo hecho. Ya puestos, monté Nagios en esa máquina virtual, para poder monitorizar la IP fija principal (la de fibra óptica) desde Internet, a través del módem 3G, y notificarme por correo electrónico si se ha caído la principal.

Los X primeros días, todo "funcionaba" de escándalo, o eso creía yo, hasta que por curiosidad un día me conecté a la máquina de salto virtual, desde la red local, y ví que no tenía acceso a Internet. Me tocó subirme encima de la estantería y reiniciar el router via hardware (botón o quitando el cable de corriente) y todo volvió a funcionar. Será algo aislado, pensé. Pero a los dos días me vuelvo a conectar y el mismo problema. Entonces, de qué me sirve tener una línea extra si es aún menos confiable que la primaria? 

A partir de aquí se me pasaron varias cosas por la cabeza: 
  • Volver a poner el router de Telefonica y dejar que negocie solo la IP pública (se supone que esto no falla)
  • Opción más freak: ¿Y si monto con arduino/raspberry pi una salida que corte la corriente del router 3G y así se reinicie?
  • Veamos qué permite el router 3G y pensemos….

Así, me entretuve en ver qué opciones me daba el router 3G y qué tipo de interacción remota podría llevar a cabo. Para empezar actualicé el firmware que traía. En las release notes de la nueva versión no ví nada que me iluminase la cara, pero… me conozco la vida en fabricantes, y en algunos, una versión soluciona un problema sin estar especificado en las Release Notes, “para no dar mala imagen”. En este caso, la GUI seguía igual. Me di cuenta que para el acceso a este router, como para la gran mayoría, el único mecanismo de autenticación era pasar como cabecera HTTP una autenticación de tipo Basic. Es decir, que no hay una cookie temporal enviada por el servidor web implementado en el router ni nada de nada. Así que busqué el CGI que permitía hacer el reboot del router, aprovechando lo más parecido a un CSRF del servidor web del Router, y fue muy sencillo hacer un programita que lo reiniciara de forma remota.


#!/usr/bin/perl

use LWP::UserAgent;

my $routerIP='192.168.7.1';

my $Auth='YWRtaW46bm9jcmVlcmFzcXVlbGF2b3lhcG9uZXIsdmVyZGFkPw==';

my $browser=LWP::UserAgent->new;

my $url="http://".$routerIP."/reboot.cgi";

my $browser = LWP::UserAgent->new ();

$browser->post($url, "Authorization" => "Basic $Auth", "Content" => [button=>Reboot]);

Es decir, que ahora sólo me queda saber cuando se ha quedado frita la conexión a Internet por 3G y reaccionar en consecuencia. Un momento, tengo montado Nagios en esa máquina virtual. Si monitorizo algo que “nunca” deje de responder, como por ejemplo la IP 4.2.2.1, un DNS de Cisco,  podría hacer que en determinadas condiciones, se reinicie el router en remoto, y adquiera una nueva dirección IP, que refrescará el dominio DynDNS, para permitir el acceso al servicio OpenVPN cuando sea necesario.

Teniendo en cuenta la latencia de la línea por 3G, en Nagios, sólo había que indicar la ejecución del comando restart_router, y dejar la definición del objeto algo como que así:


define service{
        use                             generic-service         ; Name of service template to use
        host_name                       Outside
        service_description             PING
        check_command                   check_ping!2000.0,30%!7000.0,60%
        notifications_enabled           1
        normal_check_interval           1
        max_check_attempts              4
        event_handler                   restart_router
        }

El comando restart_router se define en el fichero /etc/nagios/objects/commands.cfg

# 'restart_router' command definition
define command{
        command_name    restart_router
        command_line    $USER1$/check_debug.sh $USER1$/restart_router $SERVICESTATE$ $SERVICESTATETYPE$ $SERVICEATTEMPT$
        }

Y el fichero restart_router, es el script ya descrito, con ciertas secuencias de control, de manera que sólo haya que controlar cuándo hacer efectivo el reinicio. Como Nagios me permite pasar como argumento el estado (OK, WARNING o CRITICAL), el tipo de estado (SOFT o HARD) y el número de intentos que lleva, definimos que se ejecute cuando sea un estado de tipo CRITICAL y que el tipo de estado sea HARD, o SOFT pero lleve 4 intentos así (es decir, que hay una mala calidad de conexión) 

#!/usr/bin/perl
use LWP::UserAgent;
#USAGE $0 $SERVICESTATE$ $SERVICESTATETYPE$ $SERVICEATTEMPT$
if ($ARGV[0] eq "CRITICAL")
{
          if ( (($ARGV[1] eq "SOFT") && ($ARGV[2] == 4)) || ($ARGV[1] eq "HARD"))
          {
                  my $routerIP='192.168.7.1';
                  my $Auth='YWRtaW46bm9jcmVlcmFzcXVlbGF2b3lhcG9uZXIsdmVyZGFkPw==';
                  my $browser=LWP::UserAgent->new;
                  my $url="http://".$routerIP."/reboot.cgi";
                  my $browser = LWP::UserAgent->new ();
                  $browser->post($url, "Authorization" => "Basic $Auth", "Content" => [button=>Reboot]);
                  system ('logger "Reinicio Router 3G"');
         }
}
exit 0;

Como he dicho en más ocasiones: con que a uno de nuestros lectores le resulte útil este artículo, habrá tenido sentido. 
   





6 comments :

masticover dijo...

¡Espectacular Lorenzo! ¡Crack!

salvades dijo...

excelente

Bruno Cardenas Cyberoff dijo...

pero para que serviria ?

Filipe Polido dijo...

LOL! Loved the base64 decoded string!

Lorenzo_Martinez dijo...

:) No pensarías que iba a ser tan fácil, verdad? jeje

Dracot dijo...

Excelentes ideas y un curro genial....pero con algun pero....
Dejando claro que todo lo que has hecho me parece que tiene un merito enorme, me parece una solución a un problema de comunicaciones enfocado demasiado desde sistemas.
Por ejemplo,¿que la raspberry solo tiene una interfaz IP? Utilizando vlans puedes utilizar varias ips. Además, muchos routers (que no el que pone por defecto telefónica) implementan facilidades para la redundancia, activando una u otra interfaz en función de parámetros como el estado de una interfaz,la falta de recepción de una ruta, la falta de respuesta de una ip....y la mayoría de equipos 3g, accediendo a la configuración del módem GSM por comandos AT, permiten ordenar una reconexion por perdida de cobertura o ausencia de tráfico.

En definitiva, como caso de estudio está genial, pero hay formas mas "elegantes" de proveer redundancia al escenario.