26 de Noviembre, 2005

Mi primera aplicación Ruby: ssh_blocker

Anoche tuve un rato libre para echarle un vistazo otra vez a Ruby.

Para programar hay que tener algo para programar, un problema que resolver, sino es complicado ;). He ojeado lo que había por el servidor y que quizás pudiera ser un reto para empezar con este lenguaje, y he encontrado un buen objetivo: ssh_blocker.sh.

La idea era reescribir esa herraminenta en Ruby, y de paso comprobar qué tal queda el rendimiento, más que nada porque no es demasiado útil el bloqueo de estos ataques.

He implentado exáctamente las mismas características del script shell:

$ ssh_blocker.rb --help
ssh_blocker for OpenBSD and Packet Filter (1.0 Nov 2005)
Copyright (C) 2005 Juan J. Martinez <jjm*at*usebox*dot*net>

usage: ssh_blocker.rb [<options>]
options:
        --table         <packet filter table>
        --authlog       <authlog path>
        --whitelist     <comma-separated IP list>
        --verbose
        --logpath       <log path>
        --help

Podemos indicar la tabla dentro de Packet Filter a la que se añadirán la direcciones IP, dónde se encuentra el log de sshd, indicar una lista de IPs que nunca serán bloqueadas (whitelist), si queremos una salida detallada, si deseamos que se procese el propio log del programa para volver a bloquear direcciones ya bloqueadas (por ejemplo después de reiniciar, cuando la tabla de PF queda vacía), y bueno... la ayuda :).

Por ejemplo en mi crontab hay algo como:

# ssh_blocker
5 * * * * /root/bin/ssh_blocker.rb --whitelist 127.0.0.1,192.168.0.1 \
 >> /var/log/ssh_blocker.log
@daily cat /var/log/ssh_blocker.log | \
 mail -s "`hostname` - ssh_blocker daily report" reidrac
@reboot /root/bin/ssh_blocker.rb --logpath /var/log/ssh_blocker.log \
 --whitelist 127.0.0.1,192.168.0.1 > /dev/null
# Nota: he partido las lineas solo por claridad para el blog

Cada hora busco nuevos atacantes y los añado al bloqueo, diariamente mando el log por correo para ojear como va la cosa, y finalmente proceso el propio log de la herramienta en cada aranque.

Respecto a lo que hacía la implementación en shell no hay muchos cambios. Las opciones tienen formato largo y los logs registran la fecha/hora de forma más adecuada, pero poco más (en la documentación explico como convertir los logs viejos al nuevo formato).

Veamos que tal el rendimiento:

# time ssh_blocker.sh
    2.61s real     2.45s user     0.12s system
    
# time ssh_blocker.rb
    1.01s real     0.86s user     0.13s system

En efecto, la solución con Ruby es más rápida (y a logs más grandes, más se notará). No es ninguna sorpresa si ojeamos el código de cada aplicación: ssh_bloquer.sh y ssh_blocker.rb.

No voy a detallar todo el código de la nueva versión, pero sí puedo comentar alguna cosa. Por ejemplo, obtenemos la lista de IPs ya bloqueadas por Packet Filter:

# ejecutamos pfctl con variables:
#	pfctl y pftable (se pueden cambiar)
blockList = `#{pfctl} -t#{pftable} -T show 2>&1`
# si hay un error (por ejemplo se indica mal la tabla)
if $? != 0
        printf("%s: error %s", Time.now, blockList)
        exit
end

# convertimos la salida de pfctl en un vector
# (separando por saltos de linea)
block = blockList.split("\n")
# quitamos repetidos (no debe haber)
block.uniq!
# quitamos los espacios en blanco que pone pfctl delante
# de cada dirección IP
block.each{ |item| item.strip! }

La versión shell del mismo código es más sucia y mucho menos efectiva :P (aunque funciona, claro).

Lo único que me ha costado es consultar la documentación, lo que he encontrado es mejorable, y lo que no... como la documentación de parseArgs ¿no existe?

Ha sido entretenido, aunque confieso que me ha faltado agilidad porque estoy aprendiendo, y podría haber hecho casi lo mismo con Python o Perl (lo de programar sin conocer el lenguaje).

Cuando haya programado un par de cosas más y vaya consiguiendo soltura, ya podré sacar conclusiones reales sobre este lenguaje. Por ahora ssh_blocker.rb ya está funcionando ;).

Anotación por Juan J. Martínez, clasificada en: ruby, scripting, openbsd.

Hay 1 comentario

Gravatar

Me picaste ayer al decirmelo, y me he puesto con algo un poco + complicado: la aplicación de recepcion para las jornadas, con GTK+Ruby.

La única diferencia es que la estoy implementando con DBI/SQLite en vez de con Mysql (mas que nada porque programo en un P200, y Mysql es un poco pesado), ya te avisaré cualdo la tenga lista.

por Felipe, en 2005-11-26 16:08:23

Los comentarios están cerrados: los comentarios se cierran automáticamente una vez pasados 30 días. Si quieres comentar algo acerca de la anotación, puedes hacerlo por e-mail.

Algunas anotaciones relacionadas: