Comment utiliser ipset sur Linux

IPset est une extension d'iptables qui vous permet de créer des règles de pare-feu correspondant à des "ensembles" d'adresses à la fois. Contrairement aux chaînes IPTABLES normales, qui sont stockées et traversées de manière linéaire, des jeux IP sont stockés dans des structures de données indexées, ce qui rend les recherches très efficaces, même lorsqu'il s'agit de grands ensembles.

IPSet permet donc de gagner en rapidité surtout lorsque l'on doit bloquer énormément d'adresses IP ou blocs d'adresses IP.
On peut très facilement créer des listes noires (blacklist) ou listes blanches (whitelist) grâce à ipset.

Dans ce tutoriel, après avoir rapidement discuté des exigences de l'installation d'ipset, je passe un peu de temps sur les principes fondamentaux et les concepts de l'iptables. Ensuite, je couvre l'utilisation et la syntaxe de ipset et montrez comment il s'intègre à IPTABLES pour accomplir diverses configurations.
Enfin, je fournis des exemples de monde réels détaillés et assez avancés de la manière dont ipset peut être utilisé pour résoudre toutes sortes de problèmes.

Comment utiliser ipset sur Linux

Pourquoi utiliser ipset à la place d'iptables ?

Comme expliqué dans l'introduction, ipset utilise une indexation afin de parcourir une liste de blocage conséquente.

Outre les situations évidentes où vous pourriez imaginer que cela serait utile, comme le bloquant de longues listes de "mauvais" hôtes sans soucier de tuer des ressources système ni de causer une congestion réseau, des ensembles IP ouvrent également de nouvelles façons d'aborder certains aspects de la conception du pare-feu et de simplifier de nombreux scénarios de configuration.

Avec des gains de performances significatifs et des fonctionnalités supplémentaires puissantes - comme la possibilité d'appliquer des règles de pare-feu unique à des groupes entiers d'hôtes et de réseaux à une fois.

Étant donné que Ipset est juste une extension d'IPTABLES, cet article est autant sur IPTABLES, car il s'agit d'un Ipset, bien que l'accent soit mis sur les caractéristiques pertinentes pour la compréhension et l'utilisation de l'IPSET.

Comment utiliser ipset avec iptables sur Linux

Principe de fonctionnement d'ipset

IPset est utilisé pour configurer, maintenir et inspecter des ensembles IP dans le noyau Linux. Selon le type de jeu, un ensemble IP peut stocker des adresses IPv4, IPv6, TCP, UDP, numéros de port réseau, paires d'adresse IP et Mac, adresse IP
et des paires de numéro de port, etc.
Ensuite on utilise l'option match pour cibler des chaînes ipset dans des règles iptables.

Tout d'abord, on créé des chaînes ipset en lui attribuant un nom.
Celle-ci est configurée par type pouvant être une liste d'adresse IP, de masque de sous-réseau, adresse ip par ports, masque de réseau par ports, etc.
Puis on alimente cette chaîne, par exemple une liste d'adresse IP ou de blocs d'IP.
Enfin on applique une ou plusieurs règles Iptables correspondant à cette chaîne ipset.
Ainsi, cela est très flexible puis que l'on peut appliquer n'importe quelle règles iptables au bloc ipset.

CommandesDescription
create SETNAME TYPENAME [type-specific-options]
Create a new set
Créer une chaîne ipset
add SETNAME ENTRYAjouter des entrées dans une chaîne ipset
del SETNAME ENTRYSupprimer une entrée dans une chaîne ipset
test SETNAME ENTRYTester une entrée dans une chaîne ipset
destroy [SETNAME]Détruire une chaîne ipset
list [SETNAME]Lister les chaînes ipset
save [SETNAME]Enregistrer une chaîne ou tous les ensembles sur stdout
restoreRestaurer l'état d'ipset
flush [SETNAME]Vider le contenu d'une chaîne ipset
rename FROM-SETNAME TO-SETNAMERenommer une chaîne ipset
swap FROM-SETNAME TO-SETNAMEPermuter deux chaînes ipset
Les commandes ipset

Créer une chaîne ipset avec le type

Pour créer une chaîne, on utilise la commande ipset create suivi du nom et du type de chaînes.
Par exemple pour créer une chaîne d'adresse IP sous le nom de blacklist_ip :

ipset create blacklist_ip hash:ip

Pour créer une chaîne de blocs d'adresses de réseau sous le nom blacklist_netname :

ipset create blacklist_netname hash:net

IPset propose un large éventails de type de chaînes dont la description se trouve dans le man.
Voici quelques exemples.

Type de chaînesDescription
bitmap:ipLe type de jeu Bitmap:IP utilise une plage de mémoire pour stocker des adresses réseau IPv4 (par défaut) ou IPv4.
Par exemple : [proto:]port | [proto:]fromport-toport
Un bitmap: type IP de jeu peut stocker jusqu'à 65536 entrées.
hash:ipLe type de jeu Hash:IP utilise un hachage pour stocker des adresses hôtes IP (par défaut) ou des adresses réseau. L'adresse IP de valeur zéro ne peut pas être stockée dans un hachage: type IP de jeu.
hash:ip,portLa HASH: IP, le type de jeu de ports utilise un hachage pour stocker une adresse IP et des paires de numéro de port. Le numéro de port est interprété avec un protocole (TCP par défaut) et un numéro de protocole zéro ne peut pas être utilisé.
hash:ip,port,netLe type hash:ip,port,net utilise un HASH pour stocker l'adresse IP, le numéro de port et l'adresse réseau IP triple. Le numéro de port est interprété avec un protocole (TCP par défaut) et un numéro de protocole zéro ne peut pas être utilisé. L'adresse réseau avec zéro préfixe la taille ne peut pas être stockée non plus.
hash:net,porthash:net,port est un type de jeu net se comporte de la même manière que le hachage: IP, Port, Net mais accepte une valeur CIDR pour le premier et le dernier paramètre. Soit sous-réseau est autorisé à être A / 0 si vous souhaitez correspondre au port entre toutes les destinations.
hash:ip,markLe type de hachage: IP, le type de jeu utilise un hachage pour stocker l'adresse IP et les paires de paquets.
hash:net:ifaceLe type de jeu de hachage utilise un HASH pour stocker des paires de noms de réseau IP différentes et de noms d'interface.
Exemples de type de chaînes ipset

A noter qu'il est possible de créer une chaîne avec une entrée avec une durée de vie défini par timeout.
Timeout prend un délai en secondes.
Par exemple ci-dessous, on créé une chaîne temp_hosts avec une une durée de vie d'1 heure.

ipset create temp_hosts hash:ip timeout 3600

Ajouter/supprimer des éléments dans une chaîne ipset

Une fois que la chaîne ipset est créée, on alimente celle-ci avec la commande ipset add.
Par exemple pour ajouter une IP dans la chaîne blacklist_ip :

ipset add blacklist_ip 185.31.175.226

On peut aussi utiliser l'option timeout pour ajouter une IP ou un réseau temporairement à une chaîne.

ipset add blacklist_ip 192.168.2.123 timeout 3600
ipset add blacklist_ip 192.168.1.0/24 timeout 3600

Pour supprimer un élément d'une chaîne, on utilise ipset del suivant le même principe :

ipset del blacklist_ip 185.31.175.226

Utiliser Iptables avec Ipset

Une fois que l'on a créé la chaîne ipset, on fait correspondre une règle Iptables à cette dernière.
Pour cela, on utilise l'option -m set pour --match-set.
Par exemple pour créer une chaîne ipset blacklist_ip, puis ajoutez deux adresses IP 1.1.1.1 et 2.2.2.2 et enfin créez une règle DROP correspondant à cette chaîne.

ipset -N blacklist_ip hash:ip
ipset -A blacklist_ip 1.1.1.1
ipset -A blacklist_ip 2.2.2.2
iptables -A INPUT -m set --set blacklist_ip src -j DROP

Ainsi ici on bloque les connexions provenant des adresses IP 1.1.1.1 et 2.2.2.2.

Si à l'inverse, vous souhaitez définir une condition de pare-feu qui correspondrait à tout sauf des paquets de 1.1.1.1 ou 2.2.2.2.2 et poursuivez le traitement dans MaChaine, utilisez la syntaxe suivante :

ipset -N whitelist_ip hash:ip
ipset -A whitelist_ip 1.1.1.1
ipset -A whitelist_ip 2.2.2.2
iptables -A INPUT -m set ! --set whitelist_ip src -g machaine

Bannir automatiquement une IP avec iptables et ipset

Ipset est utilisé par fail2ban pour bannir des IP.

Mais Ipset fournit également une "extension cible" aux iptables qui fournit un mécanisme permettant d'ajouter et de supprimer de manière dynamique des entrées définies en fonction de toute règle d'IPTABLES. Au lieu d'avoir à ajouter des entrées manuellement avec la commande Ipset, vous pouvez avoir des iptables les ajouter à votre vol à la volée.

Par exemple, si un hôte distant tente de se connecter au port 25, mais vous n'exécutez pas de serveur SMTP, il n'est probablement pas bon. Pour nier que l'hébergée l'occasion d'essayer toute autre chose de manière proactive, utilisez les règles suivantes:

ipset -N banned_hosts iphash
iptables -A INPUT \
         -p tcp --dport 25 \
         -j SET --add-set banned_hosts src
iptables -A INPUT \
         -m set --set banned_hosts src \
         -j DROP

Si un paquet arrive sur le port 25, dites-le avec l'adresse source 1.1.1.1, il est instantanément ajouté à banned_hosts.

Lister les chaînes Ipset

Lorsque l'on gère des chaînes ipset, on peut être amené à connaître les chaînes configurées et leurs contenus.
La commande ipset list permet de lister les chaînes ipset avec leurs configurations et les éléments.

ipset list
ipset list pour lister les jeu ipset et leurs éléments

Mais si vous ne voulez que les chaînes brutes sans aucune information, utilisez l'option -n :

ipset -n list
Lister les jeux ipset seulement

Supprimer une chaîne Ipset

Enfin pour détruire un jeu ipset, on utilise l'option ipset destroy.
Par exemple pour détruire le jeu blacklist_ip :

ipset destroy blacklist_ip

Si le message ipset v6.38: Set cannot be destroyed: it is in use by a kernel component s'affiche, c'est que vous avez encore une règle iptables pointant sur le jeu ipset.
Supprimez les règles iptables, puis utilisez la commande destroy d'ipset.

Vider les règles iptables et ipset

Voici comment vider l'intégralité des règles iptables et ipset.
En général, on utilise celle-ci en début de script pour ensuite créer les chaînes et règles.

iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -t filter -F
iptables -t raw -F
iptables -t nat -F
iptables -t mangle -F
ipset -F
ipset -X

Exemples d'utilisations ipset

Autoriser que les IP Cloudflare sur le port 80,443

Dans cet exemple, on autorise que les IP Cloudflare, pour cela on créé une chaîne cf4, puis on télécharge la liste des blocs d'IP CloudFlare en IPv4, enfin on autorise les connexions sur les ports 80, 443, 2408 pour les protocoles TCP et UDP.
On répète l'opération pour l'IPv6.

ipset destroy cf4
ipset create cf4 hash:net family inet

for ip in $(curl https://www.cloudflare.com/ips-v4); do ipset add cf4 $ip; done
iptables -A INPUT -m set --match-set cf4 src -p tcp -m multiport --dports 80,443,2408 -j ACCEPT
iptables -A OUTPUT -m set --match-set cf4 dst -p tcp -m multiport --sports 80,443,2408 -j ACCEPT

iptables -A INPUT -m set --match-set cf4 src -p udp -m multiport --dports 443 -j ACCEPT
iptables -A OUTPUT -m set --match-set cf4 dst -p udp -m multiport --sports 443 -j ACCEPT


ipset destroy cf6
ipset create cf6 hash:net family inet6
for ip in `curl https://www.cloudflare.com/ips-v6`; do ipset add cf6 $ip ; done
ip6tables -A INPUT -m set --match-set cf6 src -p tcp -m multiport --dports 80,443 -j ACCEPT
ip6tables -A OUTPUT -m set --match-set cf6 dst -p tcp -m multiport --sports 80,443 -j ACCEPT

ip6tables -A INPUT -m set --match-set cf6 src -p udp -m multiport --dports 443 -j ACCEPT
ip6tables -A OUTPUT -m set --match-set cf6 dst -p udp -m multiport --sports 443 -j ACCEPT

Ajouter plusieurs routeurs pour faire du masquerade

Dans cette exemples, on créé un jeu routed_nets avec la liste des routeurs.
Puis on créé une règle iptables afin de faire du masquerade dessus.

ipset -N routed_nets nethash
ipset -A routed_nets 10.30.30.0/24
ipset -A routed_nets 10.40.40.0/24
ipset -A routed_nets 192.168.4.0/23
ipset -A routed_nets 172.22.0.0/22
iptables -t nat -A POSTROUTING \
         -s 10.0.0.0/24 \
         -m set ! --set routed_nets dst \
         -j MASQUERADE

Bannir des pays avec ipset

Dans ce tutoriel, je vous explique comment bannir des pays avec ipset et iptables.

Bloquer TOR avec ipset

On créé une chaîne tor et on bloque les connexions entrantes sur celle-ci.

/usr/sbin/ipset -N tor iphash --hashsize 4096 --probes 2 --resize 50
/sbin/iptables -I INPUT -m set --match-set tor src -j DROP

Puis utilisez ce script suivant qui télécharge laliste d'IP tor dans ipset.

#!/bin/sh
#curl -s https://check.torproject.org/exit-addresses| grep -i ExitAddress | cut -f 2 -d ' ' > /tmp/tor.txt
curl -L -s https://www.dan.me.uk/torlist/|egrep "([0-9]{1,3}\.){3}[0-9]{1,3}" > /tmp/tor.txt
/usr/sbin/ipset list tor|egrep "([0-9]{1,3}\.){3}[0-9]{1,3}" |sort -n> /tmp/toripset.txt

lignes=$(wc -l /tmp/tor.txt)
echo "il y $lignes IPs dans /tmp/tor.txt"
j=0
for ip in `cat /tmp/tor.txt`
do
	if [[ ! `egrep $ip /tmp/toripset.txt` ]]
	then
		j=`expr $j + 1`
		/usr/sbin/ipset add tor $ip
	fi
done
echo "$j nouvelle IPs"

j=0
for ip in `cat /tmp/toripset.txt`
do
        if [[ ! `egrep $ip /tmp/tor.txt` ]]
        then
		/usr/sbin/ipset del tor $ip
                j=`expr $j + 1`
        fi
done

echo "$j IPs retirees"
rm -f /tmp/tor*txt