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 IP
s 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 IP
s 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 ;).
Hay 1 comentario
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.
por Felipe, en 2005-11-26 16:08:23 ∞