Cuando una de tus tareas es encargarte de gestionar un servidor web (o de cualquier otro tipo), más temprano que tarde acabas teniendo verdaderos quebraderos de cabeza con determinadas IPs que se conectan a tu servidor, llegando a tomar la decisión de que necesitas banear una serie de IPs. Partiendo de la base de que eres un auténtico kamikaze y que te has atrevido a gestionar un servidor LINUX con muy pocos conocimientos de este sistema operativo, es en este momento cuando decides buscarte un buen firewall para Linux.
Github: https://github.com/rolando-caldas/myOwnFirewall
Youtube: https://youtu.be/-vkbyvRA9fo
IPTABLES: El Firewall de LINUX y el banear IPs
Lo primero con que te encuentras buscando un firewall para Linux es algo llamado «IPTABLES». Pues sí, IPTABLES es el firewall de linux, todas las distribuciones tienen este genial firewall incluido por defecto. Como IPTABLES funciona a base de comandos, cuando se busca un firewall para linux, es normal encontrar resultados que hablen de APF o CSF. Tanto APF como CSF son programas encargados de proporcionar al usuario una «interfaz amigable» para gestionar las reglas IPTABLES, o sea, el firewall. Así pues, este tipo de software permite el baneo de IPs, por lo que podríamos instalar uno de los programillas de marras y olvidarnos del tema. Sin embargo, queremos ir un paso más allá y crear nuestro propio programa que se encargue de bloquear un listado de IPs.
Funcionamiento general de IPTABLES
IPTABLES es un sistema de firewall que funciona en base a una serie de reglas indicadas que se añaden como si un documento de texto con varias líneas se tratase. Cuando el sistema encuentra una regla que se ajusta a lo que está buscando, la ejecuta y deja de leer más reglas. Esto significa que una regla excesivamente permisiva al inicio puede hacer que reglas en «líneas posteriores» no se lean, por lo tanto el orden de las reglas es muy importante.
También, con IPTABLES lo que hacemos es «filtrar» todo el tráfico en el equipo dónde se ejecuta… esto significa que con IPTABLES podemos cerrar todos los puertos y dejar abierto, por ejemplo, el puerto 80 (htttp) para una determinadas IP’s… o dejar abierto el puerto del MySQL sólo en local, etc etc. IPTABLES es muy amplio y prácticamente todo queda fuera del alcance de este artículo, puesto que la finalidad de este artículo es, simplemente, tener un sistema que permita banear IPs.
Como banear IPs utilizando IPTABLES
Para poder banear una IP, debemos ejecutar un comando de consola. Lo que hacemos al banear una IP es bloquearle el tráfico, podemos bloquear sólo el tráfico de entrada (de esa IP a la máquina) o el de salida (de la máquina a esa IP), para ello son los siguientes comandos:
iptables -I INPUT -s [la ip] -j DROP iptables -I OUTPUT -s [la ip] -j DROP
Así de sencillo! Lo siguiente que debemos hacer es decidir cómo será nuestro «automáticamente». He utilizado la opción -I (i mayúscula) para añadir la regla, aunque podemos usar tanto la -I como la -A. El motivo de utilizar la -I es que, de esta forma, la regla se inserta de primera (rulenum 1) mientras que, con append, se inserta al final.
Lo que vamos a hacer es un script que lea un fichero de texto dónde tendremos un listado de IPs (una por línea) que queremos bloquear en nuestro equipo, o sea, nuestra lista de banear IPs.
Nuestro fichero de texto con la lista de banear IPs
Nada más sencillo que crear un fichero de texto, que llamaremos banList.txt con, por ejemplo, una serie de IP’s locales que queremos bloquear:
192.168.0.123 192.168.0.124 192.168.0.125 192.168.0.126 192.168.0.127
Decidimos almacenarlo en el directorio /etc/myOwnFirewall/ por lo que nos conectamos como root ya sea con su o sudo y creamos el directorio:
rolando@rolando-interaccion:~$ sudo su [sudo] password for rolando: root@rolando-interaccion:/home/rolando# mkdir /etc/myOwnFirewall/ root@rolando-interaccion:/home/rolando#
una vez estamos como root, utilizamos nuestro editor favorito (en mi caso el vim) para crear el fichero banList.txt y pegar el contenido. Si usas el vim, una vez abierto debes pulsar la tecla «i» para entrar en modo de escritura y, una vez estén las IPs escritas, pulsar la tecla ESC para salir del modo de edición, escribir :wq para guardar y cerrar el fichero y pulsar enter para ejecutar la instrucción.
root@rolando-interaccion:/home/rolando# vim /etc/myOwnFirewall/banList.txt
Este fichero será leído por un script bash que ejecutará los comandos IPTABLES para banear la IP por cada línea del fichero de texto. Como no deja de ser una tarea crítica y peligrosa… nuestro script bash debería ejecutarse con un usuario concreto que sólo tuviese permisos de lectura para este fichero de texto. Al mismo tiempo, sólo el autor del fichero de texto debería poder modificarlo y sólo los usuarios bajo los cuales corren los scripts que utilicen este fichero deberán tener permisos de lectura. De esta forma, sólo el dueño del fichero de texto podrá añadir nuevas IPs y sólo el usuario bajo el cual se ejecuta el script que banea podrá leer el fichero de texto. Por ahora, como vamos a estar trabajando con el usuario root, dejaremos que le fichero sea sólo lectura/escritura para el dueño (root) y para nadie más, por lo que entramos en nuestro directorio del firewall y le ponemos los permisos adecuados:
root@rolando-interaccion:/home/rolando# cd /etc/myOwnFirewall/ root@rolando-interaccion:/etc/myOwnFirewall# chmod 600 banList.txt
Podemos ver las diferencias en las siguientes imágenes:
Creando un pequeño script para leer nuestro listado de IPs a banear
Con nuestro fichero de texto con el listado para banear IPs, lo que necesitamos es que, de alguna forma, podamos leer el fichero y ejecutar los comandos de iptable para banear cada ip.
Esto lo hacemos creando un fichero que llamaremos «myOwnFirewall» en la misma ruta que nuestro fichero de texto y ponemos el siguiente código:
# myOwnFirewall v0.1 # # Script para banear IPs # # Author: Rolando Caldas # http://rolandocaldas.com # # https://github.com/rolando-caldas/myOwnFirewall BANNED_IPS="/etc/myOwnFirewall/banList.txt" for i in `cat $BANNED_IPS`; do iptables -I INPUT -s $i -j DROP iptables -I OUTPUT -s $i -j DROP done
Lo que hacemos es declarar una variable «$BANNED_IPS» que tiene por valor la ruta a nuestro fichero banList.txt, es buena idea utilizar la ruta absoluta, por eso aunque mi script está en el mismo directorio que el fichero, he utilizado la ruta absoluta. Así, podré mover mi script de lugar sin preocuparme de si dejará de funcionar o no.
Luego, utilizamos un bucle for para recorrer las líneas de nuestro fichero de texto. La condición del bucle lo que hace es asignar a «i» el valor de una línea de nuestro txt. Para leer el fichero de texto, se utiliza el comando cat que lo que hace es mostrar el contenido del fichero indicado (en nuestro caso $BANNED_IPS.
Por último, dentro de nuestro bucle for, sólo tenemos que lanzar los comandos para bloquear la IP.
Ejecutando nuestro script para banear ips
Con nuestro script inicial terminado, lo podemos lanzar con la siguiente orden
sh ./myOwnFirewall
Ponemos sh para que sea el «programa» sh quien ejecute nuestro script y, así, pueda ser interpretado correctamente.
Antes de lanzarlo, debemos es comprobar las reglas IPTABLES que tenemos actualmente en el equipo:
root@rolando-interaccion:/etc/myOwnFirewall# iptables -nL
Bueno, en mi caso no hay ninguna regla, así que lanzo mi script y, luego, compruebo si hubo cambios o no en mis reglas iptables.
root@rolando-interaccion:/etc/myOwnFirewall# sh myOwnFirewall root@rolando-interaccion:/etc/myOwnFirewall# iptables -nL
Con esto ya tendríamos el listado de banear IPs aplicado tal y como se puede ver en la captura. Sin embargo, lanzar el script llamándolo desde sh no es cómodo, lo mejor es que se pudiese lanzar simplemente con:
/etc/myOwnFirewall/myOwnFirewall
Para lograr eso necesitamos dos cosas:
1. Que el fichero tenga permisos de ejecución.
2. Que en el fichero se indique que debe ser ejecutado con sh.
Dando permisos de ejecución a nuestro script para banear IPs
Para dar permisos de ejecución, podemos hacerlo con:
chmod +x /etc/myOwnFirewall/myOwnFirewall
Con esto conseguimos que cualquier usuario pudiera ejecutar nuestro script, tal y como se puede ver en la captura:
Vemos cómo el fichero pasa a tener permisos -rwxr-xr-x o sea… tenemos tres grupos de info:
- rwx: Que significa que el usuario dueño (root) puede leer, escribir y ejecutar.
- r-x: Que significa que el grupo dueño (root) puede leer y ejecutar, pero no escribir
- r-x: Que significa que otro usuario/grupo puede leer y ejecutar, pero no escribir.
Esto es un poco inseguro, porque permitimos que cualquiera ejecute nuestro script. Lo suyo sería, al menos por ahora, que sólo el usuario root pudiese leer, escribir y ejecutar, de forma que nadie más pueda hacerlo. Así que, lo que tenemos que ejecutar es:
chmod 700 /etc/myOwnFirewall/myOwnFirewall
y ya tenemos el resultado deseado:
Incorporando a nuestro script para banear IPs la cabecera para indicar que es un bash-script
Además, incorporamos una cabecera a nuestro script para banear IPs de forma que quede así:
#!/bin/bash # myOwnFirewall v0.1 # # Script para banear IPs # # Author: Rolando Caldas # http://rolandocaldas.com # # https://github.com/rolando-caldas/myOwnFirewall BANNED_IPS="/etc/myOwnFirewall/banList.txt" for i in `cat $BANNED_IPS`; do iptables -I INPUT -s $i -j DROP iptables -I OUTPUT -s $i -j DROP done
De esta forma, ya podemos lanzar nuestro script sólo con:
/etc/myOwnFirewall/myOwnFirewall
Parando y reiniciando nuestro script para banear ips
Ya tenemos nuestro script base listo, aunque no tenemos todo el trabajo terminado, ni mucho menos. Tal y como lo tenemos, sólo podemos ejecutarlo para incorporar reglas. Esto quiere decir, que nosotros lo lanzamos y ale! lee el fichero y banea a todos. Pero… ¿Y si queremos banear una IP tras lanzarlo la primera vez? ¿Y si queremos eliminar nuestras reglas de bloqueo? ¿Y si queremos desbanear una IP?
Bien, bien… necesitamos mejorar nuestro script. Lo primero que vamos a hacer es permitir a nuestro script las siguientes acciones:
1. start para iniciarse y lanzar la orden de banear ips
2. stop para pararse y parar la orden de banear ips
Para lograr nuestro nuevo objetivo, tenemos que agregar al script banear IPs el «soporte» a parámetros, para que se pueda ejecutar de la siguiente manera:
/etc/myOwnFirewall/myOwnFirewall start /etc/myOwnFirewall/myOwnFirewall stop /etc/myOwnFirewall/myOwnFirewall restart
Por lo tanto, tenemos que «encapsular» nuestro código en una función, que se ejecutará cuando se lance el script con el parámetro start:
#!/bin/bash # myOwnFirewall v0.1 # # Script para banear IPs # # Author: Rolando Caldas # http://rolandocaldas.com # # https://github.com/rolando-caldas/myOwnFirewall BANNED_IPS="/etc/myOwnFirewall/banList.txt" function startScript { for i in `cat $BANNED_IPS`; do iptables -I INPUT -s $i -j DROP iptables -I OUTPUT -s $i -j DROP done }
Para completarlo, creamos las funciones stopScript y restartScript, aunque por ahora vacías:
#!/bin/bash # myOwnFirewall v0.1 # # Script para banear IPs # # Author: Rolando Caldas # http://rolandocaldas.com # # https://github.com/rolando-caldas/myOwnFirewall BANNED_IPS="/etc/myOwnFirewall/banList.txt" function restartScript { echo "TODO" } function startScript { for i in `cat $BANNED_IPS`; do iptables -I INPUT -s $i -j DROP iptables -I OUTPUT -s $i -j DROP done } function stopScript { echo "TODO" }
Ya sólo nos queda informar al script de qué function cargar en base al parámetro enviado (start | restart | stop), para lo cual utilizamos un switch:
#!/bin/bash # myOwnFirewall v0.1 # # Script para banear IPs # # Author: Rolando Caldas # http://rolandocaldas.com # # https://github.com/rolando-caldas/myOwnFirewall BANNED_IPS="/etc/myOwnFirewall/banList.txt" function restartScript { echo "TODO" } function startScript { for i in `cat $BANNED_IPS`; do iptables -I INPUT -s $i -j DROP iptables -I OUTPUT -s $i -j DROP done } function stopScript { echo "TODO" } case "$1" in restart) restartScript exit ;; start) startScript exit ;; stop) stopScript exit ;; esac
Bien, bien… ahora ya podemos lanzar el «comando» con el parámetro deseado!!
/etc/myOwnFirewall/myOwnFirewall start
Podemos ver cómo se ejecuta nuestro firewall y como se añaden las reglas. Como ya teníamos unas (de la primera ejecución), se incorporan de nuevo todas, por lo que tendremos las reglas duplicadas (importante detalle).
Primer objetivo conseguido puesto que así se ejecutaría la función para banear ips. Con todo, todavía tenemos que mejorar este punto de nuestro script. No estamos dando ninguna opción por defecto, ni pensando que al escribir el comando podemos poner como parámetro algo no contemplado, de forma que cualquiera de estas líneas no haría nada:
/etc/myOwnFirewall/myOwnFirewall /etc/myOwnFirewall/myOwnFirewall inicia
Para evitar esto, sólo tenemos que incluir en nuestro switch una opción por defecto, lo que haremos será crear una función de ayuda que imprima las opciones a usar a modo de pequeña ayuda:
#!/bin/bash # myOwnFirewall v0.1 # # Script para banear IPs # # Author: Rolando Caldas # http://rolandocaldas.com # # https://github.com/rolando-caldas/myOwnFirewall BANNED_IPS="/etc/myOwnFirewall/banList.txt" function restartScript { echo "TODO" } function showHelp { echo "Usage: myOwnFirewall {start|stop|restart}" } function startScript { for i in `cat $BANNED_IPS`; do iptables -I INPUT -s $i -j DROP iptables -I OUTPUT -s $i -j DROP done } function stopScript { echo "TODO" } case "$1" in restart) restartScript exit ;; start) startScript exit ;; stop) stopScript exit ;; *) showHelp exit ;; esac
Probamos que funciona bien y se muestra el mensaje de ayuda:
/etc/myOwnFirewall/myOwnFirewall inicia
Ya tenemos nuestro script banear IPs alterado para que se pueda iniciar utilizando el parámetro 1 como start… ahora nos toca ver cómo pararlo y reiniciarlo.
Para pararlo, tenemos que escribir el código que elimine todos los bloqueos, en nuestra función stopScript. Para ello podemos recorrer el fichero de texto y eliminar cada una de las reglas de bloqueo creadas para la IP dada, o bien eliminar todas las reglas.
Para eliminar todas las reglas se hace un flush:
iptables -F
Sin embargo, esto elimina todas las reglas, no sólo las que nuestro script ha incorporado. Si tenemos, por ejemplo, un fail2ban funcionando para bloquear intentos de ataques por fuerza bruta, al hacer un flush eliminaríamos también las reglas que este programa incorporó al iptables, por lo que salvo que todo el control de nuestras reglas iptables esté en nuestro script, no es buena idea hacer un flush. ¿Que nos queda pues? eliminar las reglas creadas una a una, algo que es sencillo, puesto que para eliminar una regla, en vez de -I usamos -D
iptables -D INPUT -s [la ip] -j DROP iptables -D OUTPUT -s [la ip] -j DROP
De esta forma, buscará la regla y la eliminará. También podemos usar el -D con el número de la regla en vez de la regla en sí, pero eso significa que tenemos que saber cual es el número que ocupa en «la pila» cosa que no sabemos así queeee nuestro script quedaría así:
#!/bin/bash # myOwnFirewall v0.1 # # Script para banear IPs # # Author: Rolando Caldas # http://rolandocaldas.com # # https://github.com/rolando-caldas/myOwnFirewall BANNED_IPS="/etc/myOwnFirewall/banList.txt" function restartScript { echo "TODO" } function showHelp { echo "Usage: myOwnFirewall {start|stop|restart}" } function startScript { for i in `cat $BANNED_IPS`; do iptables -I INPUT -s $i -j DROP iptables -I OUTPUT -s $i -j DROP done } function stopScript { for i in `cat $BANNED_IPS`; do iptables -D INPUT -s $i -j DROP iptables -D OUTPUT -s $i -j DROP done } case "$1" in restart) restartScript exit ;; start) startScript exit ;; stop) stopScript exit ;; *) showHelp exit ;; esac
Perfecto! nos falta reiniciar no? bueno, eso es tan sencillo como hacer que la function restart llame primero a stop y luego a start 😉
#!/bin/bash # myOwnFirewall v0.1 # # Script para banear IPs # # Author: Rolando Caldas # http://rolandocaldas.com # # https://github.com/rolando-caldas/myOwnFirewall BANNED_IPS="/etc/myOwnFirewall/banList.txt" function restartScript { stopScript startScript } function showHelp { echo "Usage: myOwnFirewall {start|stop|restart}" } function startScript { for i in `cat $BANNED_IPS`; do iptables -I INPUT -s $i -j DROP iptables -I OUTPUT -s $i -j DROP done } function stopScript { for i in `cat $BANNED_IPS`; do iptables -D INPUT -s $i -j DROP iptables -D OUTPUT -s $i -j DROP done } case "$1" in restart) restartScript exit ;; start) startScript exit ;; stop) stopScript exit ;; *) showHelp exit ;; esac
Probamos a detener nuestro script:
root@rolando-interaccion:/etc/myOwnFirewall# /etc/myOwnFirewall/myOwnFirewall stop root@rolando-interaccion:/etc/myOwnFirewall# iptables -nL
Vemos como el script se lanza y se para correctamente. Sin embargo, las reglas siguen estando ahí! Hagamos un poco de memoria… como lanzamos dos veces el script, las reglas se insertaron dos veces… y al principio de todo comentamos, de pasada, que iptables leía las reglas por orden y cuando encontraba una que se ajustaba dejaba de leer, algo que parecía tan «tonto» tiene esta consecuencia 😉
Nada, por ahora lanzamos otra ver la parada del script y comprobamos que ya tenemos todo limpio.
Bien, bien… vamos a evitar entonces que podamos lanzar dos veces el script para evitar este error. ¿como lo evitamos? Lo más sencillo es crear un fichero oculto que llamaremos .lock en el directorio /etc/myOwnFirewall de forma que al iniciar el firewall si ese fichero existe, no se lanza y al parar el firewall eliminamos el fichero. Sencillo y rápido 😉
#!/bin/bash # myOwnFirewall v0.1 # # Script para banear IPs # # Author: Rolando Caldas # http://rolandocaldas.com # # https://github.com/rolando-caldas/myOwnFirewall BANNED_IPS="/etc/myOwnFirewall/banList.txt" LOCK="/etc/myOwnFirewall/.lock" function restartScript { stopScript startScript } function showHelp { echo "Usage: myOwnFirewall {start|stop|restart}" } function startScript { if [ -f ${LOCK} ] then echo "myOwnFirewall is already running" exit else ` > ${LOCK}` for i in `cat $BANNED_IPS`; do iptables -I INPUT -s $i -j DROP iptables -I OUTPUT -s $i -j DROP done echo "myOwnFirewall started" fi } function stopScript { if [ -f ${LOCK} ] then for i in `cat $BANNED_IPS`; do iptables -D INPUT -s $i -j DROP iptables -D OUTPUT -s $i -j DROP done rm ${LOCK} echo "myOwnFirewall stopped" else echo "myOwnFirewall is not running" fi } case "$1" in restart) restartScript exit ;; start) startScript exit ;; stop) stopScript exit ;; *) showHelp exit ;; esac
¿Qué hemos hecho?
Bien, por un lado hemos declarado una nueva variable «LOCK» que es la ruta al fichero .lock que usaremos para saber si el script está funcionando o no.
Luego, tanto en startScript como en stopScript hemos creado una nueva condición, para que cada función haga una cosa u otra en función de si existe nuetro .lock o no.
En el caso de startScript, si el fichero existe lo que hacemos es mostrar un aviso de que el firewall ya está funcionando. En caso contrario, lo que hacemos es crear el fichero .lock vacío para luego leer nuestro fichero de listado banear ips y les bloqueamos el acceso.
En el caso del stopScript, la situación es la misma, si el fichero .lock existe, desbanea las ips y elimina el fichero .lock… si por el contrario no existe, avisa de que el firewall no se está ejecutando.
¿funcionará?
Perfecto! Hemos lanzado dos veces nuestro myOwnFirewall start, la primera vez se ha ejecutado e incluido las reglas. Las segunda vez nos ha avisado de que ya se está ejecutando y no ha incluido nuevamente las reglas.

Paramos el firewall, las reglas se eliminal, volvemos a parar el firewall y esta vez nos dice que no se está ejecutando
Maravilloso!! Ya nos aseguramos que sólo se va a iniciar/parar el firewall una vez.
Esto empieza a coger forma! Vamos a por más!
Permitir al script incluir/excluir una ip en nuestro listado de bannear ips
Bien, es muy bonito tener un fichero con IPs a banear, pero «de poco nos sirve» si tenemos que ir modificando a mano nuestro fichero de texto y reiniciando el script cada vez que cambiamos el listado de IPs. Lo que necesitamos es permitir a nuestro script que pueda incluir/excluir cualquier ip y que, además, al mismo tiempo añada o quite la regla de baneo. De esta forma podremos gestionar todo lo relacionado con el bloqueo de IPs desde nuestro script.
Así pues, tenemos que permitir pasar por parámetro dos opciones nuevas: ban y unban. Las incorporamos al switch y creamos funciones para ejecutar en cada caso:
#!/bin/bash # myOwnFirewall v0.1 # # Script para banear IPs # # Author: Rolando Caldas # http://rolandocaldas.com # # https://github.com/rolando-caldas/myOwnFirewall BANNED_IPS="/etc/myOwnFirewall/banList.txt" LOCK="/etc/myOwnFirewall/.lock" function banIP { echo "TODO" } function restartScript { stopScript startScript } function showHelp { echo "Usage: myOwnFirewall {start|stop|restart}" } function startScript { if [ -f ${LOCK} ] then echo "myOwnFirewall is already running" exit else ` > ${LOCK}` for i in `cat $BANNED_IPS`; do iptables -I INPUT -s $i -j DROP iptables -I OUTPUT -s $i -j DROP done echo "myOwnFirewall started" fi } function stopScript { if [ -f ${LOCK} ] then for i in `cat $BANNED_IPS`; do iptables -D INPUT -s $i -j DROP iptables -D OUTPUT -s $i -j DROP done rm ${LOCK} echo "myOwnFirewall stopped" else echo "myOwnFirewall is not running" fi } function unbanIP { echo "TODO" } case "$1" in ban) banIP exit ;; restart) restartScript exit ;; start) startScript exit ;; stop) stopScript exit ;; unban) unbanIP exit ;; *) showHelp exit ;; esac
Para la función de banIP lo que vamos a hacer es que se recorra nuestro fichero de texto buscando la IP, si no la encuentra, la incorporará y la baneará, si la encuentra informará de que ya está en el listado, por supuesto, sólo si nuestro firewall está iniciado 😉
#!/bin/bash # myOwnFirewall v0.1 # # Script para banear IPs # # Author: Rolando Caldas # http://rolandocaldas.com # # https://github.com/rolando-caldas/myOwnFirewall BANNED_IPS="/etc/myOwnFirewall/banList.txt" LOCK="/etc/myOwnFirewall/.lock" function banIP { if [ -f ${LOCK} ] then if [ $# -eq 0 ] then echo "You must enter an ip address" else ip=$1 exists=false for i in `cat $BANNED_IPS`; do if [ $i = $ip ] then exists=true fi done if [ $exists = false ] then echo $ip >> $BANNED_IPS iptables -I INPUT -s $ip -j DROP iptables -I OUTPUT -s $ip -j DROP echo "IP ${ip} banned" else echo "IP ${ip} already in the list" fi fi else echo "myOwnFirewall is not running" fi } function restartScript { stopScript startScript } function showHelp { echo "Usage: myOwnFirewall {start|stop|restart}" } function startScript { if [ -f ${LOCK} ] then echo "myOwnFirewall is already running" exit else ` > ${LOCK}` for i in `cat $BANNED_IPS`; do iptables -I INPUT -s $i -j DROP iptables -I OUTPUT -s $i -j DROP done echo "myOwnFirewall started" fi } function stopScript { if [ -f ${LOCK} ] then for i in `cat $BANNED_IPS`; do iptables -D INPUT -s $i -j DROP iptables -D OUTPUT -s $i -j DROP done rm ${LOCK} echo "myOwnFirewall stopped" else echo "myOwnFirewall is not running" fi } function unbanIP { echo "TODO" } case "$1" in ban) banIP $2 exit ;; restart) restartScript exit ;; start) startScript exit ;; stop) stopScript exit ;; unban) unbanIP exit ;; *) showHelp exit ;; esac
Ahora toca hacer lo mismo para unbanIP, o sea, eliminar el baneo y eliminar la IP de la lista si existe:
#!/bin/bash # myOwnFirewall v0.1 # # Script para banear IPs # # Author: Rolando Caldas # http://rolandocaldas.com # # https://github.com/rolando-caldas/myOwnFirewall BANNED_IPS="/etc/myOwnFirewall/banList.txt" LOCK="/etc/myOwnFirewall/.lock" function banIP { if [ -f ${LOCK} ] then if [ $# -eq 0 ] then echo "You must enter an ip address" else ip=$1 exists=false for i in `cat $BANNED_IPS`; do if [ $i = $ip ] then exists=true fi done if [ $exists = false ] then echo $ip >> $BANNED_IPS iptables -I INPUT -s $ip -j DROP iptables -I OUTPUT -s $ip -j DROP echo "IP ${ip} banned" else echo "IP ${ip} already in the list" fi fi else echo "myOwnFirewall is not running" fi } function restartScript { stopScript startScript } function showHelp { echo "Usage: myOwnFirewall {start|stop|restart}" } function startScript { if [ -f ${LOCK} ] then echo "myOwnFirewall is already running" exit else ` > ${LOCK}` for i in `cat $BANNED_IPS`; do iptables -I INPUT -s $i -j DROP iptables -I OUTPUT -s $i -j DROP done echo "myOwnFirewall started" fi } function stopScript { if [ -f ${LOCK} ] then for i in `cat $BANNED_IPS`; do iptables -D INPUT -s $i -j DROP iptables -D OUTPUT -s $i -j DROP done rm ${LOCK} echo "myOwnFirewall stopped" else echo "myOwnFirewall is not running" fi } function unbanIP { if [ -f ${LOCK} ] then if [ $# -eq 0 ] then echo "You must enter an ip address" else ip=$1 exists=false for i in `cat $BANNED_IPS`; do if [ $i = $ip ] then exists=true else echo $i >> $TEMP fi done if [ $exists = false ] then echo "IP ${ip} doesn't in the list" else cp $TEMP $BANNED_IPS && rm $TEMP iptables -D INPUT -s $ip -j DROP iptables -D OUTPUT -s $ip -j DROP echo "IP ${ip} unbanned" fi fi else echo "myOwnFirewall is not running" fi } case "$1" in ban) banIP $2 exit ;; restart) restartScript exit ;; start) startScript exit ;; stop) stopScript exit ;; unban) unbanIP exit ;; *) showHelp exit ;; esac
Como se puede ver, he creado una variable TEMP asociado a un fichero temporal, esto es así para que a al hora de desbanear una ip, lo que haga sea recorrer el listado de IPS y que vaya incorporando al fichero temporal todas las que no sean la IP a eliminar, una vez terminado el bucle, copia el contenido del fichero temporal al fichero del listado de IPS, de forma que en nuestra lista de banear IPs ya no tenemos la IP que hemos desbaneado. Seguro que hay soluciones más elegantes, pero ésta funciona 😉
Vamos a probarlo! Como siempre, lo primero es comprobar las reglas existentes, iniciarlo y ver que bloqueó bien la lista de banear ips
root@rolando-interaccion:/etc/myOwnFirewall# iptables -nL root@rolando-interaccion:/etc/myOwnFirewall# /etc/myOwnFirewall/myOwnFirewall start root@rolando-interaccion:/etc/myOwnFirewall# iptables -nL
Vamos a añadir una nueva IP, la 192.168.0.128
root@rolando-interaccion:/etc/myOwnFirewall# /etc/myOwnFirewall/myOwnFirewall ban 192.168.0.128
Vemos que la IP se banea sin problemas… vamos a parar el firewall y luego iniciarlo para ver si esta nueva IP también se banea al reiniciar.
root@rolando-interaccion:/etc/myOwnFirewall# /etc/myOwnFirewall/myOwnFirewall stop root@rolando-interaccion:/etc/myOwnFirewall# iptables -nL root@rolando-interaccion:/etc/myOwnFirewall# /etc/myOwnFirewall/myOwnFirewall start root@rolando-interaccion:/etc/myOwnFirewall# iptables -nL
Todo funciona como es debido al banear vía script. ¿y al desbloquear?
Vamos a desbanear la IP 192.168.0.125
root@rolando-interaccion:/etc/myOwnFirewall# /etc/myOwnFirewall/myOwnFirewall unban 192.168.0.125
Vemos que la IP se desbanea sin problemas… vamos a parar el firewall y luego iniciarlo para ver si esta IP no se bloquea al reiniciar.
root@rolando-interaccion:/etc/myOwnFirewall# /etc/myOwnFirewall/myOwnFirewall stop root@rolando-interaccion:/etc/myOwnFirewall# iptables -nL root@rolando-interaccion:/etc/myOwnFirewall# /etc/myOwnFirewall/myOwnFirewall start root@rolando-interaccion:/etc/myOwnFirewall# iptables -nL
Genial! Ya tenemos un script completito, ya podemos iniciarlo, pararlo, reiniciarlo, incorporar IPs y eliminarlas. Nos quedarían varias tareas para perfeccionar nuestro script:
- Que el bloqueo de una ip pueda ser temporal no sólo definitivo.
- Que se bloqueen los accesos a los diferentes servicios/puertos.
- Activar el acceso a una IP a un servicio/puerto concreto (www, mysql, ssh)
- Administración a través de una interfaz web.
- etc
Pero todo esto se irá atacando en futuros artículos, para ir poco a poco perfeccionando el firewall hasta que sea una opción completa 😉
¿Alguna tarea a incorporar que me haya dejado y sea interesante?
Github: https://github.com/rolando-caldas/myOwnFirewall
Youtube: https://youtu.be/-vkbyvRA9fo
Felicitaciones por la guía! No podría estar mas claro y está hecho a la medida!! Donde puedo ver la continuación del artículo?
Muchas gracias!, por ahora no tengo la continuación terminada, a ver si relativamente pronto cae!
Beztial el script Felicidades!!
felicidades, y gratitud a quien se gasto tanto tiempo explicando, como se nota cuando alguien hace algo con cariño.
Ni te imaginas como ayuda encontrarse con ejemplos paso a paso, explicados por puntos separados.
Llegue aquí buscando una cosa y me quede siguiendo el tema de script en bash, 😀 genial!!!!
requetecontra super.
Felicitaciones. Más claro el agua, y las técnicas sencillas que usas. He hecho varios scripts bash pero tu enfoque limpio me agrada. Me gustaría añadirle una interfaz tipo Newt o ncurses.
Excelente artículo muy bueno, felicitaciones
Excelente explicación, mejor imposible
Tremendo !! Muy Bueno!! Gracias por la Ayuda,
Maravillosoooo el script!!!
no se si la gente ha probado la opción unban, a mi no me funciona
iptables -I INPUT -s $i -j DROP
iptables -I OUTPUT -d $i -j DROP
no tendria que ser
iptables -I INPUT -s $i -j DROP
iptables -I OUTPUT -d $i -j DROP
Buenas…
Falta definir la variable TEMP:
BANNED_IPS=»/etc/myOwnFirewall/banList.txt»
LOCK=»/etc/myOwnFirewall/.lock»
TMP=»/etc/myOwnFirewall/banList.tmp
Y también añadir en la opción «unban» hay que añadirle la variable ($2) con la IP que se le pasa desde Consola, si no, lo toma como que no se le pasa parámetro:
unban)
unbanIP $2
exit
;;
Saludos y gracias