Blacklist con IPTABLES e IPSET en Debian 9

Introducción

Para poder unificar los bloqueos de IPs o rangos en un único punto del Firewall IPTABLES podemos crear una lista en donde especificar estos orígenes no deseados.

Para ello haremos uso de la heramienta IPSET y agregaremos la entrada correspondiente en el Firewall.


Instalación

La herramienta IPSET ya viene instalada en el sistema Debian, pero si no la tuvieras puedes instalarla con el comando:

apt-get install ipset

Esta herramienta combina perfectamente con el Firewall IPTABLES, con un buen rendimiento a la hora de identificar si una IP, rango, puerto figura en la lista para bloquear.

La información la almacena en memoria, de tal forma que ante un reinicio esta se perdería, por lo que si queremos tenerla de manera persistente tendremos que guardarla periódicamente y configurar su carga al inicio, como veremos más adelante.


Crear la lista

Primero creamos la lista que llamaremos blacklist, pudiendo trabajar tanto con rangos o como con IPs:

  • Rangos:
ipset create blacklist hash:net
  • IPs:
ipset create blacklist hash:ip

Esto quiere decir que si queremos bloquear redes usaremos el primero y si queremos bloquear IPs independientes usaremos el segundo, aunque si agregamos un rango a la lista nos agregará todas sus IPs una a una.

Nosotros usaremos la lista de tipo IP, la segunda opción de las anteriores, pero siéntete libre de usar cualquiera de las dos, teniendo en cuenta que en la segunda tendrás que indicar rangos y no IPs independientes.


Configurar la lista en IPTABLES

Una vez creada nuestra lista, llamada blacklist, configuramos el FW para que bloquee cualquier IP incluida en el listado que acabamos de crear. Aplicaremos el filtrado para cualquier comunicación entrante, ejecutando los siguientes comandos:

iptables -I INPUT -m set --match-set blacklist src -j DROP
iptables -I FORWARD -m set --match-set blacklist src -j DROP

Estos comandos agregan la regla en primera posición para el tráfico INPUT y FORWARD en el sistema.

# iptables  -L -n --line-num
Chain INPUT (policy DROP)
num  target     prot opt source               destination
1    DROP       all  --  0.0.0.0/0            0.0.0.0/0            match-set blacklist src
...
Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination
1    DROP       all  --  0.0.0.0/0            0.0.0.0/0            match-set blacklist src
...

Esto nos permitirá bloquear cualquier comunicación no deseada, incluso antes de ser procesada por cualquier mecanismo de seguridad como, por ejemplo, Fail2ban.


Administrar la lista creada

Ahora solo nos queda alimentar nuestra lista de direcciones a bloquear.

Podemos administrar las listas de la siguiente forma.

Agregar IP

Podemos indicar la IP concreta:

ipset add blacklist x.x.x.x

O agregar todas las IPs de un rango concreto, lo cual nos agregara cada IP independiente en a la lista:

ipset add blacklist x.x.x.x/24

La primera opción nos agrega la IP indicada:

# ipset list blacklist -t
Name: blacklist
Type: hash:ip
Revision: 4
Header: family inet hashsize 4096 maxelem 65536
Size in memory: 552
References: 2
Number of entries: 1

Y la segunda 255 IPs:

# ipset list blacklist -t
Name: blacklist
Type: hash:ip
Revision: 4
Header: family inet hashsize 4096 maxelem 65536
Size in memory: 11976
References: 2
Number of entries: 256

Error al agregar IP

Si intentamos agregar un rango en la lista que ya contiene una IP perteneciente a este se agregarán solo las IPs anteriores a esta que ya existe, descartando el resto y mostrando un error. Por ejemplo, imaginemos que ya existe la IP 87.246.7.74, si agregamos el rango 87.246.7.0/24 solo se agregarán 75 IPs, de la .0 a la que ya tenemos cargada .74, descartando el resto:

# ipset add blacklist 87.246.7.0/24
ipset v6.30: Kernel support protocol versions 6-7 while userspace supports protocol versions 6-6
Element cannot be added to the set: it's already added

# ipset list blacklist -t
Name: blacklist
Type: hash:ip
Revision: 4
Header: family inet hashsize 4096 maxelem 65536
Size in memory: 3864
References: 2
Number of entries: 75

Para evitar este tipo de problemas existe una opción en el comando -! que ignora cualquier error que se produzca, como este que indicamos. Ejecutamos de nuevo el comando con esta opción y vemos como se agregan las 256 IPs correctamente:

# ipset add blacklist 87.246.7.0/24 -!

# ipset list blacklist -t
Name: blacklist
Type: hash:ip
Revision: 4
Header: family inet hashsize 4096 maxelem 65536
Size in memory: 11976
References: 2
Number of entries: 256

Confirmar IP en listado

Podemos confirmar si una IP se encuentra en un alista con el siguiente comando:

# ipset test blacklist 87.246.7.74
87.246.7.74 is in set blacklist.

# ipset test blacklist 87.246.7.7
87.246.7.7 is NOT in set blacklist.

Información de las listas

Podemos obtener las listas que tenemos creadas y su información de capacidad, memoria utilizada, total de entradas, IPs bloqueadas, … con el comando:

# ipset list
Name: blacklist
Type: hash:ip
Revision: 4
Header: family inet hashsize 4096 maxelem 65536
Size in memory: 552
References: 2
Number of entries: 1
Members:
87.246.7.74

Abreviando la información, podemos obtener solo los nombres de las listas creadas con la opción -n:

# ipset list -n
blacklist

O la información general de cada lista con la opción -t:

# ipset list -t
Name: blacklist
Type: hash:ip
Revision: 4
Header: family inet hashsize 4096 maxelem 65536
Size in memory: 552
References: 2
Number of entries: 1

Borrar IP

Podemos borrar una IP concreta o un rango de IPs del listado con el siguiente comando:

ipset del blacklist x.x.x.x
ipset del blacklist x.x.x.x/x

Si por ejemplo tenemos un rango /30 agregado a la lista pero indicamos un /24 a la hora de borrar nos podría dar un error, pero con la opción que vimos en el apartado anterior -! lo evitaríamos:

ipset del blacklist x.x.x.x/x -!

Vaciar la lista

Para dejar la lista sin ninguna IP configurada podemos ejecutar el siguiente comando, en lugar de ir IP a IP o rango a rango, indicando el nombre de nuestra lista:

ipset flush blacklist

Eliminar lista y configuración en IPTABLES

Si queremos dar de baja la lista y la configuraicón en IPTABLES primero eliminaremos las entradas en el Firewall que habíamos creado en la primera posición de INPUT y FORWARD:

iptables -D INPUT 1
iptables -D FORWARD 1

Luego eliminaremos la lista indicando su nombre:

ipset destroy blacklist

Configuración persistencia para lista e IPTABLES

Ante un reinicio perderíamos toda esta configuración, tanto la de IPTABLES como la de la lista creada con IPSET, por lo es recomendable dejar ambos persistentes en el sistema.

IPTABLES

Para hacer persistente IPTABLES te dejo un enlace de este mismo blog en donde se explica de forma muy sencilla como configurar IPTABLES y carga al inicio.

IPSET

Para hacer persistente la lista o listas con sus entradas creadas primero guardamos su configuración actual en un archivo nuevo que llamaremos /etc/ipset.conf, con el comando:

ipset save > /etc/ipset.conf

Lo cual nos generará el archivo indicado con el contenido de nuestras listas y sus IPs en el momento de su ejecución:

# cat /etc/ipset.conf
create blacklist hash:ip family inet hashsize 4096 maxelem 65536
add blacklist 87.246.7.74

La configuramos en el Cron para que se ejecute diariamente a las 0:30, por ejemplo:

# crontab -e
....
# IPSET para blacklist diario
30 0 * * * ipset save > /etc/ipset.conf

Cramos un archivo para que cargue al inicio los datos de la blacklist:

touch /etc/network/if-pre-up.d/ipset
chmod +x  /etc/network/if-pre-up.d/ipset

Y agregamos el siguiente contenido al archivo creado /etc/network/if-pre-up.d/ipset:

#!/bin/sh
ipset restore -f /etc/ipset.conf -!

Precaución, si cambiamos manualmente el nombre de cualquier lista en el archivo /etc/ipset.conf y este es chequeado por IPTABLES no arrancará nuestro sistema ante un reinicio, ya que esta lista es usada por otro proceso del kernel.

De esta forma tendremos nuestra blacklist persistente ante cualquier reinicio.


ENLACES DE INTERÉS

Web oficial.
Wiki Archlinux sobre IPSET.
Enlace relacionado.