Administration réseau sous Linux/Netfilter

Netfilter est un module qui permet de filtrer et de manipuler les paquets réseau qui passent dans le système.

Il fournit à Linux :

  • des fonctions de pare-feu et notamment le contrôle des machines qui peuvent se connecter, sur quels ports, de l’extérieur vers l’intérieur, ou de l’intérieur vers l’extérieur du réseau ;
  • de traduction d'adresse (NAT) pour partager une connexion internet (masquerading), masquer des machines du réseau local ou rediriger des connexions ;
  • et d'historisation du trafic réseau.

iptables est la commande qui permet de configurer Netfilter. Dans les dernières versions de Linux il existe aussi une nouvelle commande qui s'appelle nft (pour nftables).

Fonctionnement

modifier

Netfilter intercepte les paquets réseau à différents endroits du système (à la réception, avant de les transmettre aux processus, avant de les envoyer à la carte réseau, etc.). Les paquets interceptés passent à travers des chaînes qui vont déterminer ce que le système doit en faire. En modifiant ces chaînes on va pouvoir bloquer certains paquets et en laisser passer d'autres.

Filtrage

modifier
 
Principal cheminement des paquets à travers Netfilter

Dans son fonctionnement le plus simple, Netfilter permet de jeter ou de laisser passer les paquets qui entrent et qui sortent.

Il fournit pour cela trois chaînes principales :

  • une chaîne INPUT pour filtrer les paquets à destination du système,
  • une chaîne OUTPUT pour filtrer les paquets émis par les processus du système,
  • et une chaîne FORWARD pour filtrer les paquets que le système doit transmettre.

En ajoutant des règles dans ces chaînes on pourra laisser passer ou jeter les paquets suivant certains critères.

Chaînes

modifier

Une chaîne est un ensemble de règles qui indiquent ce qu'il faut faire des paquets qui la traversent.

Lorsqu'un paquet arrive dans une chaîne :

  • Netfilter regarde la 1ère règle de la chaîne,
  • puis regarde si les critères de la règle correspondent au paquet.
  • Si le paquet correspond, la cible est exécutée (jeter le paquet, le laisser passer, etc.).
  • Sinon, Netfilter prend la règle suivante et la compare de nouveau au paquet. Et ainsi de suite jusqu'à la dernière règle.
  • Si aucune règle n'a interrompu le parcours de la chaîne, la politique par défaut est appliquée.

Règles

modifier

Une règle est une combinaison de critères et une cible. Lorsque tous les critères correspondent au paquet, le paquet est envoyé vers la cible.

Les critères disponibles et les actions possibles dépendent de la chaîne manipulée.

Syntaxe

modifier

La syntaxe d'iptables et toutes les options sont décrites dans la page de man.

Pour chaque paramètre il existe généralement une forme longue avec deux tirets (par exemple --append) et une forme courte avec un seul tiret (par exemple -A). Utiliser l'une ou l'autre n'a pas d'importance, elles sont équivalentes. Les deux possibilités sont souvent représentées dans la documentation sous la forme --append|-A.

Les paramètres indiqués entre crochets (par exemple [-t <table>]) sont facultatifs.

Ce qui se trouve entre inférieur et supérieur (par exemple <table>) doit être remplacé par une valeur.

La forme générale pour utiliser iptables est la suivante :

iptables [-t <table>] <commande> <options>

La table par défaut est la table filter.

Commandes

modifier

Les commandes principales sont les suivantes :

--list|-L [<chaîne>]

Affiche les règles contenues dans les chaînes ou seulement dans la chaîne sélectionnée.

Si le paramètre -v est placé avant cette commande, le nombre de paquets ayant traversé chaque règle sera également affiché.

--append|-A <chaîne> <critères> -j <cible>

Ajoute une règle à la fin de la chaîne <chaine>. Si tous les critères correspondent au paquet, il est envoyé à la cible. Voir plus bas pour une description des critères et des cibles possibles.

--insert|-I <chaîne> <critères> -j <cible>

Comme --append mais ajoute la règle au début de la chaîne.

--delete|-D <chaîne> <critères> -j <cible>

Supprime la règle correspondante de la chaîne.

--flush|-F [<chaîne>]

Efface toutes les règles de la chaîne. Si aucune chaîne n'est indiquée, toutes les chaînes de la table seront vidées.

--policy|-P <chaîne> <cible>

Détermine la cible lorsqu'aucune règle n'a interrompu le parcours et que le paquet arrive en fin de chaîne.

Critères

modifier

Les critères possibles sont nombreux. En voici quelques-uns :

--protocol|-p [!] <protocole>

Le protocole est <protocole>. Les protocoles possibles sont tcp, udp, icmp, all ou une valeur numérique. Les valeurs de /etc/protocols sont aussi utilisables. Si un point d'exclamation se trouve avant le protocole, le critère correspondra au paquet seulement s'il n'est pas du protocole spécifié.

--source|-s [!] <adresse>[/<masque>]

L'adresse source est <adresse>. Si un masque est précisé, seules les parties actives du masque seront comparées. Par exemple, lorsqu'on écrit -s 192.168.5.0/255.255.255.0, toutes les adresses entre 192.168.5.0 et 192.168.5.255 correspondront. On peut aussi écrire le masque sous la forme d'un nombre de bits (/8 correspond à 255.0.0.0, /24 à 255.255.255.0, etc.) Le masque par défaut est /32 (/255.255.255.255), soit l'intégralité de l'adresse.

Un point d'exclamation ne fera correspondre le paquet que s'il n'a pas cette adresse source.

--destination|-d [!] <adresse>[/<masque>]

Comme --source mais pour l'adresse destination.

--dport [!] <port>

Le port destination est <port>. Il est obligatoire de préciser le protocole (-p tcp ou -p udp) car dans les autres protocoles il n'y a pas de notion de port.

--sport [!] <port>

Comme --dport mais pour le port source.

-i <interface>

L'interface réseau d'où provient le paquet. N'est utilisable que dans les chaînes INPUT et FORWARD.

-o <interface>

L'interface réseau de laquelle va partir le paquet. N'est utilisable que dans les chaînes OUTPUT et FORWARD.

--icmp-type <type>

Si le protocole choisi est icmp, permet de spécifier un type précis. exemples de types: echo-request pour l'envoi d'un "ping", echo-reply pour la réponse à "ping"

Les cibles principales sont les suivantes :

-j ACCEPT

Autorise le paquet à passer et interrompt son parcours de la chaîne.

-j DROP

Jette le paquet sans prévenir l'émetteur. Le parcours de la chaîne est interrompu.

-j REJECT

Comme DROP mais prévient l'émetteur que le paquet est rejeté. La réponse envoyée à l'émetteur est également un paquet qui devra satisfaire les règles de sortie pour pouvoir passer.

-j LOG [--log-level <level>] [--log-prefix <prefix>]

Enregistre le paquet dans les logs systèmes. Au <level> par défaut, le paquet est affiché sur la console principale du système.

Cette cible est utile pour voir certains paquets qui passent (pour débugger ou pour alerter).

Utilisation simple

modifier

Le principe est assez simple à comprendre : un paquet IP arrive sur votre machine, vous devez alors choisir ce que vous en faites. Vous pouvez l’accepter (ACCEPT), le rejeter (REJECT) ou le dénier (DROP). La différence entre les deux derniers modes qu'avec REJECT on prévient l’envoyeur que son paquet a été refusé, mais pas avec DROP.

Trois types de paquets peuvent passer par le firewall. Les paquets sortant (OUTPUT), entrant (INPUT) ou « passant », c’est-à-dire qui ne font que rebondir sur le routeur qui doit les rediriger FORWARD).

Pour organiser les règles d’acceptation/rejet, on procède de la façon suivante : – INPUT, OUTPUT, FORWARD, sont appelés des chaînes – une règle est un ensemble d’attributs auxquels correspond (ou non) un paquet : IP source, IP destination, port source, port destination, protocole . . . – quand un paquet passe par le firewall, il est aiguillé vers la chaîne correspondante – ensuite, les règles de la chaîne sont testées une par une, dans l’ordre, sur le paquet. Dès que le paquet correspond à une règle, on s’arrête. Si la règle stipule ACCEPT, le paquet est accepté. Si elle stipule DROP, il est ignoré. Si elle stipule REJECT, il est refusé avec acquittement. Les règles suivantes ne sont pas testées. – si aucune règle ne correspond au paquet, la politique par défaut est appliquée. Elle peut être positionnée à ACCEPT, DROP ou REJECT.

Il est plus sécurisant (mais plus long à mettre en place) d’utiliser une politique par défaut DROP et de créer des règles ACCEPT.

La syntaxe d’iptables est la suivante :

iptables -A|I chaîne -i (ou -o) interface -p protocole
--sport [port_début[:port_fin][,autre_port...]]
--dport [port_début[:port_fin][,autre_port]]
-s adresse_source -d adresse_dest -j politique

Il y a bien sûr de nombreuses autres options.

Créer et appliquer des règles

modifier

Toutes les commandes iptables sont tapées directement sur la ligne de commande du terminal. Il est plus pratique de les inscrire dans un fichier script et de rendre ce script exécutable (chmod +x). Ne donnez que les droits minimums à ce fichier pour qu’il ne puisse pas être lu et modifié par tout le monde. Exemple de fichier :

#!/bin/sh
# Effacer toutes les règles avant toute chose, afin de partir d’une base
# propre et de savoir exactement ce que vous faites
iptables -F

# Définir une politique par défaut : le plus normal est de tout interdire par
# défaut et de n’autoriser que certains paquets.
# "DROP" ignore les paquets, "REJECT" les refuse avec acquittement pour l’envoyeur
# on met souvent "DROP" pour l’INPUT (on ne donne pas d’informations à un
# éventuel pirate) et "REJECT" pour l’OUTPUT et le FORWARD (on peut ainsi
# récupérer des infos pour soi) mais iptables n’autorise pas REJECT
# comme politique par défaut
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

# Autoriser le trafic sur l’interface loopback :
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# Ensuite, c’est à vous d’ajouter les règles permettant de faire fonctionner
# les services que vous souhaitez utiliser sur votre machine.

Quelques exemples

modifier

Pour vider la chaine INPUT de la table filter (la table par défaut) :

iptables --flush INPUT

La politique par défaut est d'accepter tous les paquets, ce qui est généralement un mauvais choix pour la sécurité. Pour changer cette règle sur la chaine FORWARD de la table filter :

iptables -P FORWARD DROP

Pour laisser passer les paquets sur le port telnet qui viennent d'un réseau local (forme longue) :

iptables --append INPUT --protocol tcp --destination-port telnet --source 192.168.13.0/24 --jump ACCEPT

Pour ignorer les autres paquets entrants sur le Port (logiciel)|port telnet (forme courte) :

iptables -A INPUT -p tcp --dport telnet -j DROP

Pour rejeter les paquets entrants sur le port 3128, souvent utilisé par les proxies :

iptables -A INPUT -p tcp --dport 3128 -j REJECT

Pour autoriser telnet vers votre machine (serveur telnet) :

iptables -A INPUT -p tcp --dport telnet -j ACCEPT
iptables -A OUTPUT -p tcp --sport telnet -j ACCEPT

Pour autoriser telnet depuis votre machine (client telnet) :

iptables -A OUTPUT -p tcp --dport telnet -j ACCEPT
iptables -A INPUT -p tcp --sport telnet -j ACCEPT

Destination NAT :

iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 192.168.0.1

Le cas FTP

modifier

Le protocole FTP est difficile à gérer avec un firewall car il utilise plusieurs connexions. Lorsqu'on se connecte par FTP sur un serveur, on créé une connexion dite de contrôle qui permet d'envoyer les commandes au serveur. Ensuite pour chaque transfert de fichier et chaque listage de répertoire, une nouvelle connexion de données sera créée.

Le firewall peut très bien gérer la connexion de contrôle, mais pas celles de transfert car elles sont faites sur des ports indéterminés. Sur certains serveurs FTP il est possible de fixer une plage de ports à utiliser, et dans ce cas on peut faire du NAT simple.

Il est également possible d'utiliser le "conntrack ftp". C'est un module pour Netfilter qui inspecte les connexions FTP de contrôle pour détecter les connexions de données. Il indique alors au noyau que ces connexions sont liées à une autre connexion (RELATED). Pour autoriser ces connexions avec iptables on utilise le module state.

Pour cela il faut charger le module ip_conntrack_ftp :

modprobe ip_conntrack_ftp

Et autoriser les connexions RELATED en entrée et en sortie :

iptables -A INPUT -m state --state RELATED -j ACCEPT
iptables -A OUTPUT -m state --state RELATED -j ACCEPT