Le paquet iptables fournit une collection de commandes permettant de configurer netfilter, le pare-feu intégré au noyau Linux. Cet article contient toutes les notes que j'ai prises lorsque j'ai voulu savoir réellement configurer le pare-feu sur mes serveurs Debian, autrement qu'en appliquant au hasard des règles en espérant qu'elles conviennent à mon besoin.

Installation

Sous Debian, il suffit d'installer le paquet iptables.

$ sudo apt-get install --no-install-recommends iptables

Note : Pour bénéficier d'une persistance des règles, il est possible d'installer aussi le paquet iptables-persistent. Ce paquet ajoute un script d'init qui charge les règles sauvegardées dans les fichiers /etc/iptables/rules.v4 et /etc/iptables/rules.v6.

Définitions

Cette section donne les définitions des termes spécifiques à iptables. Savoir à quoi correspond chaque terme est indispensable pour comprendre la suite de l'article.

Cible

Une cible correspond à une action exécutée sur un paquet (acceptation, rejet, enregistrement dans les journaux, etc.).

Certaines cibles interrompent l'évaluation des règles.

Règle

Une règle définit deux éléments : des critères, et une cible.

Dans le cas où le paquet examiné correspond à tous les critères de la règle, la cible est exécutée pour ce paquet. Sinon, le paquet est directement soumis à la règle suivante de la chaîne.

Politique

Une politique doit être définie pour toutes les chaînes standard de chaque table.

Elle définit la cible qui sera exécutée par défaut pour cette chaîne, si aucune cible exécutée sur le paquet n'interrompt l'évaluation des règles.

Chaîne

Une chaîne consiste en une liste de règles, qui seront évaluées dans l'ordre où elles sont définies.

Chaque chaîne correspond à une étape du processus de filtrage des paquets. netfilter définit cinq chaînes standard : PREROUTING, INPUT, OUTPUT, FORWARD et POSTROUTING.

Table

Les tables correspondent chacune à une étape de l'évaluation des chaînes.

netfilter définit quatre tables : raw, mangle, nat et filter.

Outils

Chacun des outils fournis par ce paquet existe en deux versions : IPv4 et IPv6.

L'utilisation et la syntaxe sont identiques pour les deux versions, mais certains paramètres peuvent avoir des valeurs autorisées différentes. Par exemple, pour la version IPv4, le protocole ICMP est désigné par le paramètre icmp, alors que la version IPv6 n'acceptera que le paramètre icmpv6 à la place.

Configuration et affichage des règles

Les commandes iptables (IPv4) et ip6tables (IPv6) permettent de modifier la configuration de manière interactive, et d'afficher les règles en vigueur.

Les paramètres de ces commandes sont détaillés plus loin dans cet article.

Sauvegarde de la configuration

Les commandes iptables-save (IPv4) et ip6tables-save (IPv6) écrivent la configuration de netfilter sur la sortie standard, dans un format prévu pour être restauré. Les politiques par défaut et les règles de toutes les tables sont incluses dans la sortie de ces commandes.

Il est possible de passer le paramètre -t tablename pour restreindre la sortie à une table spécifique.

Restauration d'une configuration enregistrée

Pour charger une liste de règles définie, l'utilisation d'un script contenant des appels aux commandes iptables et ip6tables est à proscrire.

Les commandes iptables-restore (IPv4) et ip6tables-restore (IPv6) permettent de restaurer une configuration sauvegardée, en les appliquant de manière atomique. De cette manière, si une commande est erronée (erreur de syntaxe, valeur hors des bornes autorisées, etc.), toutes les modifications sont annulées, évitant ainsi de laisser le système dans un état incohérent. De plus, dans le cas où des données sont stockées par les règles établies, elles ne sont pas supprimées. Par exemple, les listes d'IP stockées par le module recent ne sont pas vidées lors de l'utilisation de la commande iptables-restore si la règle associée n'a pas été supprimée.

Les commandes iptables-apply (IPv4) et ip6tables-apply (IPv6) appliquent des règles iptables en utilisant respectivement les commandes iptables-restore et ip6tables-restore, puis attendent une confirmation de l'utilisateur. En l'absence de confirmation, l'état précédent est restauré, permettant d'éviter de bloquer la connexion par laquelle la configuration est effectuée. Il est donc fortement conseillé de les utiliser, lors de la modification de la configuration sur une machine distante.

Les tables

Cette section décrit les différentes tables utilisées par le pare-feu netfilter. Il n'est pas possible de créer d'autres tables que celles présentées ici par une simple configuration, mais des modules complémentaires peuvent en ajouter, comme SELinux, qui ajoute une table security.

La table Raw

La table raw permet d'agir sur les paquets avant tout autre traitement. Actuellement, elle sert essentiellement à exécuter la cible NOTRACK.

La table Mangle

La table mangle permet de modifier les paquets (TOS, TTL, MARK, SECMARK, CONNSECMARK).

La table Nat

Comme son nom l'indique, cette table est utilisée pour la traduction d'adresse réseau (NAT, Network Address Translation).

Note : Seul le premier paquet d'un flux traversera cette table. Les autres paquets du flux subiront ensuite automatiquement les mêmes traitements, sans évaluation des critères des règles.

La table Filter

La table filter est utilisée pour le filtrage des paquets, qui ne doit normalement pas être effectué dans les autres tables.

En effet, même si des règles de filtrage peuvent être ajoutées à d'autres tables, elles ne seront alors pas forcément évaluées au bon moment. Par exemple, un paquet qui doit être re-routé par une règle de la table nat ne le sera pas s'il est filtré au préalable par la table mangle.

Chaînes

Je décris ici les différentes chaînes standard existant dans netfilter. Ce sont les chaînes exécutées initialement par chaque étape de filtrage des paquets.

PREROUTING

Cette chaîne est utilisée sur les paquets provenant de l'extérieur de la machine locale, quelle que soit leur destination.

INPUT

Cette chaîne est utilisée sur les paquets à destination de la machine locale.

OUTPUT

Cette chaîne est utilisée sur les paquets provenant de la machine locale.

FORWARD

Cette chaîne est utilisée sur les paquets provenant de l'extérieur de la machine locale, mais à destination d'une autre machine.

POSTROUTING

Cette chaîne est utilisée sur les paquets à destination d'une autre machine.

Chaînes personnalisées

Il est possible de déclarer d'autres chaines que PREROUTING, INPUT, FORWARD, OUTPUT et POSTROUTING, qui sont génériques. Il faut ensuite définir des règles dans les chaînes existantes, qui sauteront vers la chaîne personnalisée. Si le paquet ne correspond aux critères d'aucune règle de cette nouvelle chaîne, le traitement continuera dans les règles de la chaîne qui l'a invoquée. Une chaîne personnalisée peut elle-même sauter vers une autre chaîne personnalisée.

Ordre d'évaluation des règles

Les règles évaluées avant une décision de routage peuvent modifier les informations d'un paquet (destination, etc.), ce qui peut influer sur la décision de routage. L'ordre d'évaluation a donc une importance.

Paquet provenant de l'extérieur, à destination de l'hôte local

Paquet provenant de l'hôte local, à destination de l'extérieur

Paquet provenant de l'extérieur, à destination de l'extérieur

Les politiques

Une politique définit la cible à appliquer par défaut, lorsque le paquet ne correspond aux critères d'aucune règle définie dans la configuration.

Seules les cibles de la table filter peuvent être utilisées comme politiques des chaînes, même pour les autres tables.

Cibles communes à toutes les tables

Cible RETURN

Quitte la chaîne actuelle, et retourne à la chaîne précédente. Lorsqu'elle est exécutée dans la chaîne principale, la cible définie par la politique de la chaîne est exécutée.

Cibles de la table raw

Cible NOTRACK

Cette cible permet de marquer les paquets à ne pas tracer par le module conntrack, souvent dans un but d'économie de ressources.

Cibles de la table filter

Cible ACCEPT

Accepte le paquet.

Cible DROP

Rejette le paquet sans en avertir l'émetteur.

Cible REJECT

Rejette le paquet, mais en informe l'émetteur.

Cible LOG

Inscrit des informations sur le paquet dans le journal du pare-feu, puis continue l'évaluation des règles.

Cibles de la table nat

Cible SNAT

Cette cible permet la modification de l'adresse source du paquet avant le routage. Cela inclut la transformation inverse automatique sur les paquets arrivant en réponse. Elle n'est utilisable que dans la chaîne POSTROUTING.

Cible MASQUERADE

Cette cible fonctionne comme la cible SNAT, mais en sélectionnant automatiquement l'adresse IP de remplacement, plutôt qu'une adresse IP définie dans la configuration, et en changeant le port aléatoirement. Cela permet de masquer la réelle adresse source du paquet, en la remplaçant par celle du pare-feu.

Le cas d'utilisation le plus courant est probablement le routage de paquets provenant d'un réseau local vers internet, puisque les adresses locales (plages d'adresses IPv4 privées) ne sont pas routables sur internet.

Cible DNAT

Cette cible permet la modification de l'adresse destination du paquet, avant le routage. Elle n'est utilisable que dans la chaîne PREROUTING.

Cible REDIRECT

Cette cible permet la redirection du paquet vers un autre port de l'interface source, équivalent à DNAT vers cette interface.

Cibles supplémentaires

Le paquet xtables-addons-dkms permet d'installer des modules complémentaires, pour ajouter le support de nouvelles cibles.

Cible TARPIT

Cette cible accepte la connexion, et définit la taille de la fenêtre TCP à 0, ce qui empêche la machine distante de communiquer via cette connexion, sans la fermer. Cela permet de maintenir la connexion ouverte, jusqu'à son expiration, en utilisant pas (ou très peu) de ressources sur le serveur qui l'exécute.

L'effet recherché est de ralentir le programme exécuté sur la machine distante, en l'obligeant à attendre l'expiration de la connexion, sans pouvoir envoyer ses données. De cette manière, la bande passante utilisée est négligeable, et les tentatives de nouvelles connexions sont limitées.

Lors d'une attaque par déni de service, un pic d'utilisation de la bande passante sera tout de même observé lors de l'expiration des connexions. En effet, les connexions étant ouvertes au même moment expireront en même temps, ce qui provoquera probablement l'ouverture d'une nouvelle connexion pour chaque connexion expirée.

Cependant, la cible TARPIT n'est pas une solution idéale à tous les problèmes d'attaques par déni de service (DoS). Même si chaque connexion n'utilise pas de ressource, il faut bien faire attention à ne pas saturer le nombre de connexions de notre propre machine. Elle est donc plus adaptée pour contrer les attaques visant à saturer la bande passante d'une machine avec un nombre limité de connexions, et aide au contraire les attaques visant à saturer le nombre de connexions de la machine.

Note: Si le module conntrack est activé, il faut aussi appliquer la cible NOTRACK, afin d'éviter que chaque connexion conservée de cette manière ne consomme des ressources. Dans le cas contraire, cela peut vite saturer les ressources utilisées sur le serveur protégé, et provoque donc l'inverse de l'effet voulu.

Les états

Les paquets sont liés aux connexions tracées dans iptables. Les connexions peuvent avoir l'un de ces états :

  • NEW : Le paquet est le premier d'un flux.
  • ESTABLISHED : Le paquet est une réponse à un paquet déjà transmis dans l'autre direction.
  • RELATED : Le paquet est le premier d'un nouveau flux, correspondant à une autre connexion déjà établie (exemple : FTP control > data, IRC > DCC), selon des informations basées sur le module conntrack.
  • INVALID : État invalide, ou inconnu.
  • UNTRACKED : Paquet marqué volontairement dans cet état par la table raw, souvent dans le but d'économiser des ressources ou de limiter la quantité de journaux produits.

La définition des états permet au pare-feu d'accepter les réponses, sans devoir ouvrir tous les ports sur lesquels ces réponses pourraient arriver. La plupart des ports restent donc bloqués, sauf si une connexion y est établie.

Commandes

Les commandes iptables et ip6tables acceptent des paramètres suivant ce format :

$ iptables [-t table] command chain [criteria] [target [arguments]]

La table utilisée par défaut est filter.

Les différentes commandes utilisables sont :

  • -A : Ajoute une règle à la fin d'une chaîne.
  • -D : Supprime une règle d'une chaîne.
  • -R : Remplace une règle d'une chaîne.
  • -I : Ajoute une règle dans une chaîne, à un endroit précis.
  • -L : Affiche les règles présentes dans une chaîne.
  • -F : Supprime toutes les règles d'une chaîne. Toutes, si aucune chaîne n'est précisée.
  • -N : Crée une chaîne personnalisée.
  • -E : Renomme une chaîne personnalisée.
  • -X : Supprime une chaîne personnalisée.
  • -P : Définit la politique par défaut d'une chaîne (valide uniquement pour les chaînes génériques).

Note : Comme je travaille toujours avec un fichier de configuration, et la commande iptables-restore, je n'utilise que la commande -A dans le fichier de configuration, et la commande -L en utilisation interactive.

Paramètres

Critères de correspondance

Il est possible d'utiliser ces critères de correspondance :

  • -p : Définit à quel(s) protocole(s) s'applique la règle (par exemple, tcp, udp, icmp, icmpv6, igmp, all).
  • -s : Adresse source à laquelle correspond la règle, qui peut être une adresse exacte (par exemple, 192.168.1.10), ou un groupe d'adresses (par exemple, 192.168.1.0/25).
  • -d : Adresse destination à laquelle correspond la règle, qui peut être une adresse exacte (par exemple, 192.168.1.10), ou un groupe d'adresses (par exemple, 192.168.1.0/25).
  • -i : Interface source à laquelle correspond la règle.
  • -o : Interface destination à laquelle correspond la règle.
  • -m : Définit une règle de correspondance pour un module spécifique. Certains modules sont détaillés plus loin dans cet article.
  • -f : Paquet fragmenté, c'est à dire découpé en plusieurs parties, pour ne pas dépasser le MTU du réseau traversé.
  • --sport : Port source du paquet, qui peut être un port unique (par exemple, 80), ou une liste de ports (par exemple, 22,80,443).
  • --dport : Port destination du paquet, qui peut être un port unique (par exemple, 80), ou une liste de ports (par exemple, 22,80,443).
  • -j : Définit la cible à appliquer, ou la chaîne personnalisée vers laquelle sauter, si le paquet correspond à tous les critères de la règle.
  • -g : Saute vers une chaîne personnalisée, mais ne revient pas à la chaîne courante après, contrairement au paramètre -j.

Paramètre spécifique à la cible SNAT, de la table nat

Le paramètre --to-source remplace l'adresse source du paquet. Cette adresse peut contenir un numéro de port (par exemple, 192.168.1.10:80).

Paramètre spécifique à la cible DNAT, de la table nat

Le paramètre --to-destination remplace l'adresse destination du paquet. Cette adresse peut contenir un numéro de port (par exemple, 192.168.1.10:80).

Paramètre spécifique à la cible REDIRECT, de la table nat

Le paramètre --to-port remplace le port destination du paquet.

Paramètres spécifiques à la cible LOG

Le paramètre --log-level définit le niveau de journalisation généré par cette règle ( debug, info, notice, warning, error, crit, etc.).

Le paramètre --log-prefix ajoute un préfixe pour les lignes ajoutées au journal par cette règle.

Règles de correspondance explicites

Il existe un bon nombre de règles de correspondance explicites. J'en explique quelques-unes ici.

Note : La liste de toutes les extensions est disponible avec la commande ls /lib/modules/$(uname -r)/kernel/net/netfilter/xt_*. Les explications de certaines sont disponibles sur le site de netfilter.

Règle connmark

Cette règle permet de vérifier si un paquet est lié à une connexion marquée par la cible CONNMARK.

Règle iprange

Cette règle permet la correspondance avec une plage d'IP, en donnant des IP directement.

Elle accepte ces paramètres :

  • --src-range : Plage d'IP source.
  • --dst-range : Plage d'IP destination.

Exemple

Correspondance uniquement sur les paquets provenant des IP comprises entre 192.168.1.100 et 192.168.3.200 :

-m iprange --src-range 192.168.1.100-192.168.3.200.

Règle limit

Cette règle permet de ne sélectionner qu'un nombre limite de paquets, dans une durée définie. Il est aussi possible de l'inverser, avec l'opérateur !, pour, au contraire, ne sélectionner que les paquets qui dépassent la limite.

Elle accepte ces paramètres :

  • --limit : Nombre de paquets maximum par unité de temps.
  • --limit-burst : Nombre de paquets maximum en salve par unité de temps.

La limite fonctionne comme une machine à jetons :

  • Le paramètre --limit-burst définit le nombre de jetons initialement disponibles.
  • Chaque paquet qui passe retire un jeton.
  • Le paramètre --limit définit la fréquence de réapprovisionnement des jetons (par exemple, 3/minute ajoute un nouveau jeton toutes les 20 secondes).
  • Si aucun jeton n'est disponible, la correspondance échoue, et la cible de la règle n'est pas exécutée.

Exemple

Autoriser un paquet par seconde, avec une limite de cinq en salve :

-m limit --limit 1/second --limit-burst 5.

Exemple de déroulement : Trois paquets arrivent, puis cinq autres paquets après deux secondes.

  • Les trois premiers paquets déclencheront la cible.
  • Pour les cinq paquets qui arrivent ensuite, quatre paquets pourront encore déclencher la cible : les deux crédits qui restaient du compteur de salve, plus les deux supplémentaires, ajoutés à chacune des deux secondes écoulées.
  • Ensuite, plus aucun paquet ne déclenchera la cible avant une seconde, le cinquième de la seconde salve ne déclenchera donc pas la cible.

Règle mac

Cette règle permet simplement de tester la correspondance d'une adresse mac.

Elle accepte ce paramètre :

  • --mac-source : Adresse MAC source du paquet.

Règle mark

Cette règle permet de vérifier si un paquet est lié à une connexion marquée par la cible MARK.

Règle multiport

De la même manière que la règle iprange, la règle multiport permet de spécifier plusieurs ports, ou plages de ports.

Elle modifie le fonctionnement des paramètres --sport et --dport, et ajoute ce paramètre :

  • --port : Équivalent au cumul de --sport et --dport sur le même port, les ports doivent correspondre à la fois à la source et à la destination.

Règle recent

Cette règle permet de sélectionner des paquets, selon les événements récents.

Elle accepte ces paramètres :

  • --name : Nom de la liste d'événements utilisée.
  • --set : Crée une nouvelle entrée, liée à l'adresse IP source du paquet, dans la liste d'événements.
  • --rcheck : Vérifie si l'adresse IP source du paquet apparaît dans la liste d'événements.
  • --update : Met à jour l'horodatage de l'entrée liée à l'adresse IP source du paquet, dans la liste d'événements. Ce paramètre n'a aucun effet si l'adresse IP n'est pas déjà présente dans la liste d'événements.
  • --remove : Supprime l'horodatage de l'entrée liée à l'adresse IP source du paquet, dans la liste d'événements. Ce paramètre n'a aucun effet si l'adresse IP n'est pas déjà présente dans la liste d'événements.
  • --seconds : Vérifie le temps écoulé depuis la dernière mise à jour de l'entrée liée à l'adresse IP source du paquet, dans la liste d'événements.
  • --hitcount : Vérifie le nombre de paquets vus, liés à l'adresse IP source du paquet. Utilisé en conjonction avec --seconds, ce paramètre vérifie le nombre de paquets dans le délai spécifié.
  • --rttl : Vérifie que la valeur du TTL est la même que pour les précédents paquets liés à l'IP source du paquet.
  • --rsource : Comportement par défaut, sauvegarde l'adresse IP source et le port source du paquet dans la liste d'événements.
  • --rdest : Sauvegarde l'adresse IP destination et le port destination du paquet dans la liste d'événements.
  • --mask : Applique un masque à toutes les adresses IP de la liste, ce qui peut être utile pour appliquer des règles à un réseau ou sous-réseau complet, plutôt que par machine.
  • --reap : Utilisé uniquement avec --seconds pour nettoyer la liste automatiquement, en supprimant les entrées dont l'âge est supérieur au délai spécifié.

Note : Lors de l'utilisation simultanée d'IPv4 et d'IPv6, il faut bien faire attention à ce que chaque liste d'événements ne contienne que l'un des deux types d'adresses IP. En effet, lorsqu'une liste contient des adresses IPv4, netfilter applique un masque /32 à toutes les adresses IP de la liste, ce qui casse les adresses IPv6 qui s'y trouvent.

Note : Il est possible de lire la liste d'événements dans le fichier /proc/net/xt_recent/<rule_name>.

Note : Il est possible de manipuler manuellement les listes d'événements. Il faut pour cela écrire dans le fichier /proc/net/xt_recent/<rule_name> :

  • / : Vide la liste d'événements.
  • +IP : Ajoute l'IP spécifiée dans la liste d'événements. Si elle était déjà présente, le compteur est incrémenté, et la date de dernière mise à jour est modifiée.
  • -IP : Retire l'IP spécifiée de la liste d'événements.

Note : Les valeurs présentes dans les fichiers du répertoire /proc/net/xt_recent/ correspondent au nombre de ticks depuis le démarrage de la machine. Pour les convertir en dates, il est possible d'utiliser ce script.

Paramétrage du noyau

Cette règle dispose aussi de paramètres définis directement au niveau du noyau, lors du chargement du module correspondant. Pour modifier ces paramètres, il est nécessaire de les écrire dans un fichier placé dans le répertoire /etc/modprobe.d/, par exemple :

options xt_recent ip_list_tot=1024 ip_pkt_list_tot=25

La valeur courante des paramètres peut être lue dans les fichiers /sys/module/xt_recent/parameters/<nom_du_parametre>. Ces paramètres sont les suivants :

  • ip_list_tot : Nombre maximum d'IPs à retenir par liste d'événements
  • ip_pkt_list_tot : Nombre maximum de paquets à retenir par IPs pour chaque liste d'événements
  • ip_list_hash_size : Taille de la table de hachage utilisée pour vérifier les IPs
  • ip_list_uid : Utilisateur propriétaire des fichiers de listes d'événements
  • ip_list_gid : Groupe propriétaire des fichiers de listes d'événements
  • ip_list_perms : Permissions appliquées aux fichiers de listes d'événements

Règle state

Cette règle permet de vérifier l'état de la connexion liée au paquet.

Elle définit ce paramètre :

  • --state : État de la connexion d'où provient le paquet.

Règle time

Cette règle permet de détecter les paquets selon les heures ou jours de transmission.

Elle définit ces paramètres :

  • --timestart : Heure de début de correspondance, au format HH:MM.
  • --timestop : Heure de fin de correspondance, au format HH:MM.
  • --days : Liste des jours de correspondance, séparés par une virgule. Les valeurs autorisées sont : Mon (lundi), Tue (mardi), Wed (mercredi), Thu (jeudi), Fri (vendredi), Sat (samedi) et Sun (dimanche).

Exemples de mise en oeuvre

Rediriger une IP vers un service spécifique

Exemples de cas concrets :

  • Sur un serveur qui contient plusieurs containers, et qui est accessible via plusieurs IP, il est possible de rediriger tous les paquets à destination d'une des IP de la machine vers un des containers.
  • Lors de la modification d'un enregistrement DNS, il est possible de rediriger tous les paquets de certains services vers la nouvelle adresse IP, en attendant que les informations DNS utilisées par tous les clients soient à jour.

Cet exemple utilise la cible DNAT, dans la table nat.

# In the *nat table

# Reroute all packets arriving on port 2222 to 10.10.10.1 on port 22
-A PREROUTING -p tcp --dport 2222 -j DNAT --to-destination 10.10.10.1:22

# Reroute all packets for 10.0.0.1 on port 22 to 10.10.10.1 on port 22
-A PREROUTING -p tcp --dport 22 --destination 10.0.0.1 -j DNAT --to-destination 10.10.10.1

# Reroute all HTTP packets for 10.0.0.1 on port 80 to 10.10.10.1 on port 80
-A PREROUTING -p tcp --dport 80 --destination 10.0.0.1 -j DNAT --to-destination 10.10.10.1

Limiter les attaques par force brute sur SSH

Mise à jour : Le contenu de ce paragraphe a été déplacé dans un article complet dédié à la limitation des attaques par force brute sur le service SSH.