9.4. Pare-feu et partages de connexion à Internet

Supposons qu'une machine située sur un réseau local ait accès à Internet. Il peut être intéressant de faire en sorte que les autres machines du réseau puissent également y accéder, en utilisant cette machine comme passerelle. Cela est parfaitement réalisable et ne pose aucun autre problème que la définition des règles de routage si toutes les machines ont une adresse IP attribuée par l'IANA. Cependant, cela est rarement le cas, car les réseaux locaux utilisent normalement les adresses réservées à cet usage, qui ne sont pas routables sur Internet. Dans ce cas, il est évident que les machines du réseau local ne pourront pas envoyer de paquets sur Internet, et qu'a fortiori elles ne recevront jamais de paquets provenant d'Internet. Heureusement, il existe une technique nommée masquerading, basée sur un mécanisme de translation d'adresse (« NAT » en anglais, abréviation de « Network Address Translation »), qui permet de modifier les paquets émis à destination d'Internet à la volée afin de pouvoir partager une connexion Internet même avec des ordinateurs qui utilisent des adresses locales. Comme nous allons le voir, partager une connexion à Internet avec d'autre ordinateurs d'un réseau local est un jeu d'enfant sous Linux grâce à cette technique.

Il faut toutefois bien se rendre compte que le fait de fournir un accès à Internet à un réseau local pose des problèmes de sécurité majeurs. Pour des réseaux locaux familiaux, les risques de piratages sont bien entendu mineurs, mais lorsque la connexion à Internet est permanente ou lorsque les données circulant sur le réseau local sont sensibles, il faut tenir compte des risques d'intrusion. Lorsqu'on utilise des adresses IP dynamiques, il est relativement difficile d'accéder à des machines du réseau local, sauf si la passerelle expose des services internes au reste du réseau. En revanche, si les adresses utilisées sont fixes et valides sur Internet, le risque devient très important. Par ailleurs, une machine Linux connectée sur Internet ouvre toujours des ports indésirés, même si elle est bien configurée. Par exemple, il est impossible d'empêcher le serveur X d'écouter les demandes de connexion provenant d'Internet, même s'il est configuré pour toutes les refuser. La configuration d'un ordinateur connecté à Internet doit donc se faire avec soin dans tous les cas, et l'installation d'un pare-feu est plus que recommandée (un « pare-feu », ou « firewall » en anglais, est un dispositif qui consiste à protéger un réseau local du « feu de l'enfer » d'Internet, sur lequel tous les crackers sont supposés grouiller).

Les paragraphes suivants exposent les mécanismes de filtrage de paquets réseau de Linux, qui sont utilisées tant pour définir les règles de protection contre les intrusions indésirables sur un réseau par l'intermédiaire d'une passerelle que pour effectuer des traitements sur les paquets. Cependant, de tous ces traitements, nous ne verrons que la translation d'adresse, car c'est sans doute celui que la plupart des gens cherchent à utiliser.

9.4.1. Mécanismes de filtrage du noyau

Linux est capable de filtrer les paquets circulant sur le réseau et d'effectuer des translations d'adresses depuis la version 2.0. Cependant, les techniques utilisées ont été profondément remaniées dans la version 2.4.0 du noyau, et une architecture extensible a été mise en place et semble répondre à tous les besoins de manière simple : Netfilter.

Netfilter est simplement une série de points d'entrée dans les couches réseau du noyau au niveau desquels des modules peuvent s'enregistrer afin d'effectuer des contrôles ou des traitements particuliers sur les paquets. Il existe une entrée en chaque point clé du trajet suivi par les paquets dans les couches réseau du noyau, ce qui permet d'intervenir de manière souple et à n'importe quel niveau. Un certain nombre de modules permettant d'effectuer les traitements les plus courants sont fournis directement dans le noyau, mais l'architecture Netfilter est suffisamment souple pour permettre le développement et l'ajout des modules complémentaires qui pourraient être développés par la suite.

Les fonctionnalités fournies par ces modules sont regroupées par domaines fonctionnels. Ainsi, les modules permettant de réaliser des pare-feu se chargent spécifiquement de donner les moyens de filtrer les paquets selon des critères bien définis, et les modules permettant d'effectuer des translations d'adresses ne prennent en charge que la modification des adresses source et destination des paquets à la volée. Afin de bien les identifier, ces fonctionnalités sont regroupées dans ce que l'on appelle des tables. Une table n'est en fait rien d'autre qu'un ensemble cohérent de règles permettant de manipuler les paquets circulant dans les couches réseau du noyau pour obtenir une fonctionnalité bien précise. Les tables les plus couramment utilisées sont les tables « filter », « mangle » et « nat », qui permettent respectivement de réaliser des pare-feu, de marquer les paquets pour leur appliquer un traitement ultérieur, et d'effectuer des translations d'adresses.

Les différentes tables de NetFilter s'abonnent chacune aux points d'entrée qui sont nécessaires pour implémenter leur fonctionnalité, et les paquets qui passent au travers de ces points d'entrée doivent traverser les règles définies dans ces tables. Afin de faciliter la définition des règles stockées dans les tables, les règles sont regroupées dans des listes de règles que l'on appelle communément des chaînes. Chaque table dispose donc toujours d'une chaîne de règles prédéfinie pour chacun des points d'entrée de Netfilter qu'elle utilise. L'utilisateur peut bien entendu définir de nouvelles chaînes et les utiliser dans les chaînes prédéfinies, ces chaînes apparaissent alors simplement comme des sous-programmes des chaînes prédéfinies.

Les règles des tables de Netfilter permettent de spécifier les paquets qui les vérifient, selon des critères précis, comme par exemple leur adresse source ou le type de protocole qu'ils transportent. Les règles indiquent également les traitements qui seront appliqués à ces paquets. Par exemple, il est possible de détruire purement et simplement tous les paquets provenant d'une machine considérée comme non sûre si l'on veut faire un pare-feu. On pourra aussi envoyer ces paquets dans une autre chaîne, qui peuvent indiquer d'autres règles et d'autres traitements.

Les critères de sélection de paquets des règles de filtrage se basent sur les informations de l'en-tête de ces paquets. Rappelez-vous que chaque paquet de données émis sur le réseau transporte avec lui des informations nécessaires au fonctionnement du dit réseau, entre autres les adresses source et destination du paquet. Ce sont sur ces informations que la sélection des paquets est effectuée dans Netfilter. Dans le cas d'un protocole encapsulé dans un autre protocole, comme par exemple un paquet TCP dans un paquet IP, les informations du protocole encapsulé peuvent également être utilisées, si l'on a chargé des modules complémentaires dans NetFilter. Par exemple, le numéro de port TCP peut faire partie des critères de sélection d'une règle et donc de différencier le trafic des différents services réseau.

Les traitements que l'on peut appliquer à un paquet sont également fournis par des modules de Netfilter. Les traitements les plus simples sont bien entendus fournis en standard avec le noyau. En général, on peut chercher à réaliser les opérations suivantes sur un paquet :

De plus, les statistiques tenues par le noyau pour la règle ainsi vérifiée sont mises à jour. Ces statistiques comprennent le nombre de paquets qui ont vérifié cette règle ainsi que le nombre d'octets que ces paquets contenaient.

Lorsqu'un paquet arrive à la fin d'une chaîne (soit parce qu'il n'a pas été rejeté ou détruit par une règle de filtrage de pare-feu, soit parce qu'il ne correspond aux critères d'aucune règle, ou soit parce qu'il est arrivé à ce stade après avoir subi des modifications), le noyau revient dans la chaîne appelante et poursuit le traitement du paquet. Si la chaîne au bout de laquelle le paquet arrive est une chaîne prédéfinie, il n'y a plus de chaîne appelante, et le sort du paquet est déterminé par ce qu'on appelle la politique de la chaîne prédéfinie. La politique (« policy » en anglais) des chaînes prédéfinies indique donc ce que l'on doit faire avec les paquets qui arrivent en fin de chaîne. En général, on utilise une politique relativement stricte lorsqu'on réalise un pare-feu, qui rejette par défaut tous les paquets qui n'ont pas été acceptés explicitement par une règle de la chaîne.

Note : Certains paquets peuvent être découpés en plusieurs paquets plus petits lors de la traversée d'un réseau. Par exemple, un paquet TCP un peu trop gros et initialement encapsulé dans un seul paquet IP peut se voir éclaté en plusieurs paquets IP. Cela peut poser quelques problèmes aux règles de filtrage, puisque dans ce cas les données spécifiques à TCP (par exemple les numéros de ports) ne sont disponibles que sur le premier paquet IP reçu, pas sur les suivants. C'est pour cette raison que le noyau peut effectuer une « défragmentation » des paquets lorsque cela est nécessaire, et que les paquets transmis par la passerelle ne sont pas toujours strictement identitiques aux paquets qu'elle reçoit.

9.4.2. Translations d'adresses et masquerading

Nous avons vu que grâce aux mécanismes de filtrage du noyau, il est possible de modifier les paquets à la volée. Il peut être intéressant de modifier un paquet pour diverses raisons, les trois plus intéressantes étant sans doute de le marquer à l'aide d'un champ spécial dans son en-tête afin de le reconnaître ultérieurement, de modifier sa priorité pour permettre un traitement privilégié ou au contraire placer en arrière plan ce type de paquet (libérant ainsi les ressources réseau pour d'autres types de connexion), et de modifier ses adresses source et destination, pour effectuer une translation d'adresse. Nous allons nous intéresser plus particulièrement aux différentes formes de translations d'adresses dans la suite de cette section.

Une translation d'adresse n'est en fait rien d'autre qu'un remplacement contrôlé des adresses source ou destination de tous les paquets d'une connexion. En général, cela permet de détourner les connexions réseau ou de simuler une provenance unique pour plusieurs connexions. Par exemple, les connexions à Internet peuvent être détournées vers un proxy fonctionnant sur la passerelle de manière transparente, en modifiant les adresses destination des paquets émis par les clients. De même, il est possible de simuler un seul serveur en remplaçant à la volée les adresses source des paquets que la passerelle envoie sur Internet.

On distingue donc deux principaux types de translations d'adresses : les translations d'adresse source et les translations d'adresse destination. Parmi les translations d'adresse source se trouve un cas particulier particulièrement intéressant : le « masquerading ». Cette technique permet de remplacer toutes les adresses source des paquets provenant des machines d'un réseau local par l'adresse de l'interface de la passerelle connectée à Internet, tout en conservant une trace des connexions réseau afin d'acheminer vers leur véritable destinataire les paquets de réponse. Ainsi, une seule connexion à Internet peut être utilisée par plusieurs machines distinctes, même si elles ne disposent pas d'adresses IP fournies par l'IANA.

Lorsqu'une machine du réseau local envoie un paquet à destination d'Internet, ce paquet est acheminé vers la passerelle, qui est la route par défaut. Celle-ci commence par modifier l'adresse source de ce paquet et mettre sa propre adresse à la place, puis le transfère vers la machine du fournisseur d'accès. Tous les paquets émis par les machines du réseau local semblent donc provenir de cette passerelle, et seront acheminés normalement à destination. En fait, la complication provient des paquets de réponse, puisque les machines situées sur Internet croient que la machine avec laquelle elles communiquent est la passerelle. Ces paquets sont donc tous envoyés à la passerelle directement, et celle-ci doit retrouver la machine du réseau local à laquelle ils sont destinés. Cette opération est réalisée de différentes manières selon les protocoles utilisés, et elle suppose que la passerelle conserve en permanence une trace des connexions réseau effectuées par les machines du réseau local.

Pour TCP, ce suivi de connexion est réalisé en modifiant également le port source des paquets provenant des machines locales. La passerelle utilise un port unique pour chaque connexion, qui va lui permettre de retrouver la machine à laquelle un paquet est destiné lorsqu'elle en reçoit un provenant d'Internet. Par exemple, si une machine locale fait une connexion à Internet, la passerelle alloue un nouveau numéro de port pour cette connexion et modifie tous les paquets sortants comme ayant été émis par la passerelle elle-même, sur ce port. Lorsque l'autre machine prenant part à la connexion, située sur Internet, envoie un paquet de réponse, celui-ci sera à destination de la passerelle, avec comme port destination le port alloué à cette connexion. La passerelle peut donc retrouver, à partir de ce port, l'adresse de la machine destination réelle, ainsi que le port source que cette machine utilisait initialement. La passerelle modifie donc ces deux champs du paquet, et le renvoie sur le réseau local. Finalement, la machine destination reçoit le paquet sur son port, et ce paquet semble provenir directement d'Internet, comme si la connexion avait été directe. Notez bien que la passerelle ne modifie pas les adresses source des paquets provenant d'Internet, elle ne fait que les réacheminer vers la bonne destination.

Figure 9-7. Translation d'adresses avec suivi de port TCP

Ainsi, le masquerading est un mécanisme complètement transparent pour les machines du réseau local. En revanche, pour les machines de l'Internet, il ne semble y avoir qu'un seul interlocuteur : la passerelle. Celle-ci utilise des numéros de ports variés, mais cela ne les regarde pas. Les machines du réseau local sont donc complètement « masquées » par la passerelle, d'où le nom de masquerading.

Tout ce travail effectué par la passerelle nécessite un traitement spécifique sur chaque paquet qu'elle achemine, et consomme bien entendu des ressources système. Cependant, les débits utilisés pour les connexions à Internet, même les plus rapides, sont très loin de mettre à genoux une passerelle sous Linux, même sur les plus petites machines (386 et 486). Vous voilà rassurés, et peut-être aurez-vous trouvé d'ici peu une utilité à l'un de ces dinosaures qui traînent encore dans votre garage...

9.4.3. Trajet des paquets dans le code de Netfilter

Il existe cinq points d'entrée au total pour les modules de Netfilter dans le code des couches réseau IP de Linux. À chacun de ces points d'entrée, les paquets sont soumis aux différentes chaînes des tables qui s'y intéressent. Comme on l'a déjà dit plus haut, chaque table dispose d'une chaîne prédéfinie pour chacun des points d'entrée auxquels elle s'intéresse. Le nom de ces chaînes prédéfinies est le nom du point d'entrée au niveau duquel elles sont appelées. Les paragraphes suivants décrivent ces cinq points d'entrée, ainsi que l'ordre dans lequel les chaînes des différentes tables sont traversées par les paquets.

Les paquets réseau provenant de l'extérieur sont d'abord contrôlés par le noyau afin de détecter les erreurs les plus simples. Les paquets mal formés ou corrompus sont systématiquement éliminés à ce niveau, avant même d'atteindre le code de Netfilter. Les autres paquets commencent alors leur trajet dans les couches de plus haut niveau. C'est à ce moment là qu'ils rencontrent le point d'entrée PREROUTING. Les règles des chaînes PREROUTING des tables mangle et nat sont appliquées à ce moment. Ces chaînes précèdent le code de routage, qui est en charge de déterminer le trajet que le paquet devra suivre par la suite à partir de l'adresse destination des paquets. C'est donc dans ces chaîne que l'on pourra entre autres modifier l'adresse destination des paquets, si l'on veut faire une translation d'adresse destination. Cette opération se fait typiquement dans la table nat.

Les paquets qui passent le point d'entrée PREROUTING sont ensuite orientés par le code de routage de Linux. S'ils sont à destination de la machine locale, ils rencontrent un autre point d'entrée : le point d'entrée INPUT. Les règles des chaînes INPUT des tables mangle et filter sont exécutées à ce moment. C'est donc à ce niveau que l'on peut empêcher un paquet d'entrer dans le système, ce qui se fait naturellement dans la table filter.

Les autres paquets doivent être transférés vers une autre machine, souvent par une autre interface réseau. Ils atteignent donc le point d'entrée FORWARD. Ce point d'entrée permet de contrôler les paquets qui transitent au travers d'une passerelle. Les paquets y traversent les chaînes FORWARD des tables mangle et filter, cette dernière étant justement dédiée au filtrage des paquets qui transitent par la passerelle.

Les paquets qui sont acceptés par les chaînes FORWARD retournent ensuite dans le code de routage du noyau, afin de déterminer l'interface réseau par laquelle ils doivent être réémis. Une fois cela réalisé, ils sont prêts à être réémis, mais ils doivent auparavant traverser les chaînes des tables abonnées au point d'entrée POSTROUTING. Il s'agit bien sûr des chaînes POSTROUTING des tables mangle et nat. C'est dans cette dernière chaîne que se font les translations d'adresse source.

Enfin, les paquets émis par la machine locale à destination de l'extérieur doivent impérativement passer par le point d'entrée OUTPUT, qui exécute les chaînes OUTPUT des tables mangle, nat et filter. C'est donc à ce niveau que l'on pourra modifier les adresses destination des paquets de la machine locale avant leur routage et effectuer le filtrage des paquets sortants, dans les chaînes OUTPUT des tables nat et filter. Les paquets qui se révèlent avoir le droit de sortir traversent alors de code de routage, puis, tout comme les paquets qui ont été transférés, passent par le point d'entrée POSTROUTING.

Figure 9-8. Trajet des paquets dans le code de filtrage

9.4.4. Configuration du noyau et installation des outils

Les fonctionnalités de Netfilter sont toutes fournies par le noyau lui-même, aussi leur configuration doit-elle se faire au niveau du noyau. La manière de procéder pour configurer le noyau a été indiquée dans le paragraphe traitant de la compilation du noyau. Les options à activer pour mettre en place les fonctionnalités de filtrage des paquets et de translation d'adresse sont les suivantes :

Vous devrez ensuite compiler le noyau et les modules, et les installer comme indiqué dans la partie traitant de la compilation du noyau.

Note : Le noyau de Linux dispose d'un paramètre global permettant de contrôler le routage des paquets IP d'une interface réseau à une autre. Par défaut, ce paramètre est à 0, ce qui implique que la transmission des paquets ne sera pas autorisée. Il faut donc activer ce paramètre à chaque démarrage afin de pouvoir utiliser votre passerelle Linux. Cela peut être réalisé en écrivant la valeur 1 dans le fichier /proc/sys/net/ipv4/ip_forward du système de fichiers virtuel /proc/ :

echo "1" > /proc/sys/net/ipv4/ip_forward

La manipulation des chaînes et la manipulation des règles de Netfilter se fait grâce à l'outil iptables. Cette commande doit normalement avoir été installée par votre distribution. Toutefois, si ce n'est pas le cas, vous pouvez la compiler manuellement. Pour cela, il vous faudra récupérer l'archive des sources d'iptables. Cette archive peut être trouvée sur Internet. La version courante est la 1.2.9, aussi l'archive se nomme-t-elle iptables-1.2.6a.tar.bz2.

L'installation d'iptables ne pose pas de problème particulier en soi. Vous devrez d'abord décompresser l'archive avec les deux commandes suivantes :

bunzip2 iptables-1.2.9.tar.bz2
tar xf iptables-1.2.9.tar
puis modifier le fichier Makefile pour définir les répertoires d'installation dans les variables LIBDIR, BINDIR et MANDIR. En général, les répertoires utilisés seront respectivement les répertoires /usr/lib/, /usr/bin/ et /usr/man/. Une fois cela fait, il ne restera plus qu'à compiler le tout avec la commande make et à faire l'installation avec la commande make install.

9.4.5. Utilisation d'iptables

Il est possible, grâce à iptables, d'effectuer toutes les opérations d'administration désirées sur les chaînes des tables de Netfilter. Vous pourrez donc créer des nouvelles chaînes, les détruire, définir les politiques par défaut, ainsi que manipuler les règles de ces chaînes (en ajouter, en supprimer ou en remplacer une). En fait, iptables dispose d'un grand nombre d'options, et seules les options les plus importantes seront présentées ici. Vous pouvez lire la page de manuel iptables si vous désirez plus de renseignements sur la manipulation des chaînes et des règles de filtrage du noyau.

9.4.5.1. Manipulation des chaînes

Toutes les options peuvent être utilisées avec toutes les tables gérées par le noyau. La table sur laquelle une commande s'applique peut être précisée à l'aide de l'option -t. Si cette option n'est pas fournie, la table utilisée par défaut sera la table filter, qui est celle qui est normalement utilisée pour définir des règles de filtrage des paquets dans un pare-feu.

La création d'une nouvelle chaîne se fait simplement avec l'option -N :

iptables [-t table] -N chaîne
chaîne est le nom de la chaîne à créer. Il est interdit d'utiliser un des mots clés réservés par iptables. En pratique, il est recommandé d'utiliser des noms de chaînes en minuscules, car les chaînes prédéfinies sont en majuscules.

Une chaîne peut être détruite avec l'option -X :

iptables [-t table] -X chaîne

Une chaîne ne peut être détruite que lorsqu'elle ne contient plus de règle. De plus, il est impossible de détruire les chaînes prédéfinies d'une table.

Vous pouvez lister l'ensemble des règles d'une chaîne avec l'option -L :

iptables [-t table] -L chaîne

Enfin, il est possible de supprimer toutes les règles d'une chaîne avec l'option -F :

iptables [-t table] -F chaîne
chaîne est le nom de la chaîne dont on veut supprimer les règles.

9.4.5.2. Manipulation des règles

La syntaxe générale pour ajouter une règle dans une chaîne est la suivante :

iptables [-t table] -A chaîne [-s source] [-d destination] [-p protocole]
    [-i itfsource] [-o itfdest] [-j cible]
où :

  • table est la table dans laquelle se trouve la chaîne manipulée (par défaut, il s'agit de la table filter) ;

  • chaîne est le nom de la chaîne à laquelle la règle doit être ajoutée ;

  • source est l'adresse source du paquet ;

  • destination est l'adresse destination du paquet ;

  • protocole est le protocole du paquet (spécifié avec son numéro de port ou par le nom du protocole tel qu'il est déclaré dans le fichier /etc/services) ;

  • itfsource est le nom de l'interface réseau source par laquelle le paquet doit arriver ;

  • itfdest est le nom de l'interface destination par laquelle le paquet doit sortir ;

  • et cible est la cible des paquets qui vérifient les critères de sélection de la règle.

Chacun des paramètres placé entre crochets dans la syntaxe est facultatif, mais il faut au moins qu'un critère de sélection soit donné (sur les adresses source ou destination, ou sur le port ou l'interface).

Les adresses source et destination peuvent être indiquées directement par le nom des machines (comme par exemple « www.monrezo.com ») ou par leurs adresses IP. Vous pouvez spécifier directement toutes les adresses d'un réseau avec la syntaxe « réseau/masque ». Il est également possible d'utiliser la syntaxe « réseau/n », où « n » est le nombre de bits mis à 1 dans le masque de sous-réseau. Ainsi, réseau/24 est équivalent à réseau/255.255.255.0, réseau/16 à réseau/255.255.0.0, etc. Par extension, « réseau/0 » peut être utilisé pour spécifier toutes les adresses possibles (dans ce cas, l'adresse donnée pour le réseau n'est pas prise en compte).

La cible détermine les opérations qui seront appliquées à ces paquets. Les cibles autorisées dépendent de la chaîne dans laquelle la règle est ajoutée, ainsi que des modules de Netfilter qui ont été compilés. Les principales cibles sont les suivantes :

  • ACCEPT, pour accepter le paquet qui vérifie le critère de sélection de la règle ;

  • DROP, pour éliminer purement et simplement le paquet ;

  • REJECT, pour rejeter le paquet (en signalant l'erreur à la machine émettrice). Cette cible n'est utilisable que dans les chaînes INPUT, FORWARD et OUTPUT, ainsi que dans les chaînes utilisateurs appelées à partir de ces chaînes ;

  • QUEUE, pour envoyer le paquet à un programme utilisateur capable de communiquer avec NetFilter ;

  • RETURN, pour sortir de la chaîne immédiatement, ou appliquer la règle de la politique par défaut pour les chaînes prédéfinies ;

  • REDIRECT, pour rediriger le paquet sur une autre machine, souvent la machine locale. Cette cible n'est utilisable qu'avec la table nat, car il s'agit d'une translation d'adresse. On ne peut l'utiliser que dans les chaînes PREROUTING et OUTPUT et les chaînes utilisateur appelées à partir de ces chaînes ;

  • SNAT, pour permettre la modification de l'adresse source du paquet. Cette cible n'est bien entendu accessible qu'au niveau de la table nat. Comme la modification de l'adresse source n'a de signification que pour les paquets devant sortir de la passerelle, cette cible ne peut être utilisée que dans la chaîne POSTROUTING et les chaînes utilisateur appelées à partir de cette chaîne ;

  • DNAT, pour effectuer la modification de l'adresse destination du paquet, afin par exemple de le détourner vers une autre machine que celle vers laquelle il devait aller. Cette cible n'est accessible que dans la table nat, et n'est utilisable que dans les chaînes PREROUTING et OUTPUT ainsi que dans les chaînes utilisateur appelées à partir de ces chaînes ;

  • MASQUERADE, pour effectuer une translation d'adresse sur ce paquet, dans le but de réaliser un partage de connexion à Internet. Cette cible n'est accessible que dans la chaîne POSTROUTING de la table nat, ainsi que dans les chaînes utilisateur appelées à partir de cette chaîne.

Toute autre spécification de destination doit être le nom d'une chaîne utilisateur, avec les règles de laquelle le paquet devra être testé. Si aucune cible n'est spécifiée, aucune action n'est prise et la règle suivante est traitée. Cependant, les statistiques de la règle sont toujours mises à jour.

La suppression d'une règle d'une chaîne se fait avec la commande suivante :

iptables -D chaîne numéro
chaîne est la chaîne dont on veut supprimer la règle, et numéro est le numéro de la règle à supprimer dans cette chaîne. Il est également possible d'utiliser l'option -D avec les mêmes options que celles qui ont été utilisées lors de l'ajout de la règle, si l'on trouve cela plus pratique.

Enfin, la politique d'une chaîne, c'est-à-dire la cible par défaut, peut être fixée avec l'option -P :

iptables -P chaîne cible
chaîne est l'une des chaînes prédéfinie, et cible est l'une des cibles ACCEPT ou DROP. Remarquez que l'on ne peut pas définir de politique pour les chaînes créées par l'utilisateur, puisque les paquets sont vérifiés avec les règles restantes de la chaîne appelante lorsqu'ils sortent de la chaîne appelée.

9.4.6. Exemple de règles

Ce paragraphe a pour but de présenter quelques-unes des règles les plus classiques. Le but est ici de présenter les principales fonctionnalités d'iptables et de réaliser un pare-feu simpliste.

9.4.6.1. Exemple de règles de filtrage

Les règles de filtrage peuvent être utilisées pour mettre en place un pare-feu afin de protéger votre réseau. La définition des règles de filtrage constitue bien souvent l'essentiel du problème, et nécessite bien entendu de parfaitement savoir ce que l'on veut faire. De manière générale, la règle d'or en matière de sécurité informatique est de tout interdire par défaut, puis de donner les droits au compte-gouttes. C'est exactement ce que permet de faire la politique des chaînes. On définira donc toujours la politique par défaut des chaînes pour utiliser la cible DROP. Cela peut être réalisé simplement avec les trois commandes suivantes :

# Définition de la politique de base :
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

# Suppression des règles existantes :
iptables -F INPUT
iptables -F FORWARD
iptables -F OUTPUT

Ces règles commencent par définir les politiques de base pour toutes les tables en blindant la machine pour qu'elle ne laisse rien entrer, ne rien passer et ne rien sortir. Toutes les règles des tables sont ensuite détruites. Dans ce cas, on ne craint plus rien, mais on ne peut plus rien faire non plus (pas même en local). Aussi faut-il redonner les droits nécessaires pour permettre l'utilisation normale de votre système. Le minimum est d'autoriser la machine à communiquer avec elle-même, ce qui implique d'autoriser les paquets provenant de l'interface loopback à entrer et à sortir :

# Communications locales :
iptables -A INPUT  -d 127.0.0.0/8 -i lo -j ACCEPT
iptables -A OUTPUT -s 127.0.0.0/8 -o lo -j ACCEPT

Si l'on dispose d'un réseau local, il peut également être utile d'autoriser toutes les connexions avec les machines de ce réseau :

# Connexions au réseau local :
iptables -A INPUT  -s 192.168.0.0/24 -i eth0 -j ACCEPT
iptables -A OUTPUT -s 192.168.0.1    -o eth0 -j ACCEPT

Comme vous pouvez le constater, ces règles ne permettent l'entrée des paquets prétendant provenir du réseau local (c'est-à-dire les paquets ayant comme adresse source une adresse de la forme 192.168.0.0/24) que par l'interface réseau connectée au réseau local (dans notre exemple, il s'agit de l'interface réseau eth0). De même, seule la machine locale (à laquelle l'adresse 192.168.0.1 est supposée être affectée) peut émettre des paquets sur le réseau local.

Notez que ces règles sont beaucoup trop restrictives pour permettre un accès à Internet (et, a fortiori une intrusion provenant d'Internet...). Il est donc nécessaire d'autoriser les connexions vers les principaux services Internet. Pour cela, il faut ajouter les lignes suivantes :

# Autorise les communications sortantes
# pour DNS, HTTP, HTTPS, FTP, POP, SMTP, SSH et IPSec :
iptables -A OUTPUT -o ppp0 -p UDP --dport domain -j ACCEPT
iptables -A OUTPUT -o ppp0 -p TCP --dport domain -j ACCEPT
iptables -A OUTPUT -o ppp0 -p TCP --dport http   -j ACCEPT
iptables -A OUTPUT -o ppp0 -p TCP --dport https  -j ACCEPT
iptables -A OUTPUT -o ppp0 -p TCP --dport ftp    -j ACCEPT
iptables -A OUTPUT -o ppp0 -p TCP --dport pop3   -j ACCEPT
iptables -A OUTPUT -o ppp0 -p TCP --dport smtp   -j ACCEPT
iptables -A OUTPUT -o ppp0 -p TCP --dport ssh    -j ACCEPT
iptables -A OUTPUT -o ppp0 -p AH  -j ACCEPT
iptables -A OUTPUT -o ppp0 -p ESP -j ACCEPT

Il est supposé ici que la connexion Internet se fait via le démon pppd, et que l'interface réseau que celui-ci a créé se nomme ppp0.

Vous pouvez constater que les règles présentées jusqu'ici se basaient uniquement sur les adresses source et destination des paquets, ainsi que sur les interfaces réseau par lesquelles ils entraient et ressortaient. Vous voyez à présent que l'on peut réaliser des règles beaucoup plus fines, qui se basent également sur les protocoles réseau utilisés (que l'on peut sélectionner avec l'option -p) et, pour chaque protocole, sur des critères spécifiques à ces protocoles (comme les ports source et destination, que l'on peut sélectionner respectivement avec les options --sport et --dport). Vous pouvez consulter la page de manuel d'iptables pour plus de détails à ce sujet.

Certains protocoles requièrent plusieurs connexions TCP/IP pour fonctionner correctement. La connexion est amorcée avec une première connexion, puis une deuxième connexion est établie après négociation. C'est en particulier le cas pour le protocole FTP, qui utilise une connexion de contrôle et une connexion pour le transfert des données. De plus, le protocole FTP peut fonctionner dans deux modes distinct (respectivement le mode dit « actif » et le mode dit « passif »), selon que c'est le serveur contacté qui établit la connexion de données ou que c'est le client qui l'établit vers le serveur. Ces connexions additionnelles ne doivent bien entendu pas être filtrées, pour autant, on ne sait pas avec précision le port qui sera choisi pour elles, car ce port fait partie de la négociation lors de l'établissement de la connexion. Heureusement, Netfilter dispose d'un mécanisme de suivi de connexions capable d'analyser les données protocolaires (si le protocole n'est pas chiffré, bien entendu). La solution est donc de lui indiquer qu'il doit laisser les paquets relatifs aux connexions établies au niveau protocolaire. La règle à utiliser est la suivante :

# Autorise l'établissement des connexions protocolaires additionnelles :
iptables -A OUTPUT -o ppp0 -m state --state ESTABLISHED,RELATED -j ACCEPT

Vous découvrez ici l'option --match, qui permet de sélectionner des paquets selon certains critères. Le critère choisi ici est bien entendu l'état des connexions. Des options complémentaires peuvent être fournis à ce critère à l'aide de l'option --state. Dans le cas présent, nous acceptons tous les paquets sortants qui appartiennent à une connexion établie (paramètre « :ESTABLISHED ») ou qui a été amorcée à partir d'une autre connexion déjà établie (paramètre « RELATED »).

Les règles précédentes permettent à la machine locale de se connecter à Internet, mais la connexion ne s'établira malgré tout pas, car aucun paquet réponse n'a le droit d'entrer. Il est donc nécessaire d'autoriser l'entrée des paquets réponse provenant des serveurs auxquels on se connecte. Toutefois, il ne faut pas tout autoriser. Seuls les paquets relatifs aux connexions dont la machine locale est initiatrice doivent être autorisés. Cela est réalisable encore une fois grâce au mécanisme de suivi de connexions de Netfilter. Pour notre exemple, la simple règle suivante suffit :

# Autorise les paquets entrants pour les connexions
# que l'on a établies :
iptables -A INPUT -i ppp0 --match state --state ESTABLISHED,RELATED -j ACCEPT

Elle dit que les paquets entrants des connexions établies et des connexions relatives aux autres connexions sont autorisés. Tous les autres paquets seront refusés.

Si vous désirez laisser un service ouvert vers Internet, vous devrez ajouter des règles complémentaires qui autorisent les paquets entrant et sortant à destination du port de ce service. Par exemple, si vous voulez laisser un accès SSH ouvert, vous devrez ajouter les deux règles suivantes :

# Autorise les connexions SSH entrantes :
iptables -A INPUT  -i ppp0 -p TCP --dport ssh -j ACCEPT
iptables -A OUTPUT -o ppp0 -p TCP --sport ssh -j ACCEPT

Enfin, il peut être utile d'accepter certains paquets du protocole ICMP, qui permet de contrôler l'état des liaisons. En particulier, il faut pouvoir recevoir les paquets indiquant qu'une machine n'est pas accessible, faute de quoi certaines connexions impossibles risqueraient d'être très longues à détecter. De plus, il peut être intéressant de pouvoir envoyer des demandes de réponse aux machines pour vérifier leur présence. Les règles suivantes pourront donc être ajoutées :

# Autorise les paquets ICMP intéressants :
iptables -A OUTPUT -p ICMP --icmp-type echo-reply -j ACCEPT
iptables -A INPUT  -p ICMP --icmp-type echo-request -j ACCEPT
iptables -A OUTPUT -p ICMP --icmp-type echo-request -j ACCEPT
iptables -A INPUT  -p ICMP --icmp-type echo-reply -j ACCEPT
iptables -A INPUT  -p ICMP --icmp-type destination-unreachable -j ACCEPT

Notez qu'il n'est théoriquement pas nécessaire de répondre aux paquets echo-request. Je vous ai toutefois laissé les deux règles pour le cas où le fournisseur d'accès utiliserait ces requêtes pour déterminer si la liaison reste correcte.

9.4.6.2. Exemple de partage de connexion à Internet

Le masquerading est un cas particulier de translation d'adresse source. En effet, celle-ci est couplée à un suivi des connexions afin d'effectuer la translation d'adresse destination des paquets de réponse renvoyés par les serveurs sur Internet pour les acheminer vers la machine du réseau local qui a initié la connexion.

En pratique, seule la chaîne POSTROUTING de la table nat sera utilisée pour le masquerading, parce que c'est à ce niveau que la translation d'adresse est effectuée. La mise en œuvre du masquerading se fait extrêmement simplement, puisqu'il suffit de spécifier que tous les paquets du réseau local sortant de l'interface réseau connectée sur Internet doivent subir le masquerading. En général, l'interface de la connexion à Internet est une interface PPP, aussi la règle à utiliser est-elle simplement la suivante :

# Effectue la translation d'adresses :
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o ppp0 -j MASQUERADE

Cette règle permet de réaliser la translation des adresses des machines du réseau local et à destination d'Internet. Remarquez que les paquets provenant de la machine locale ne subissent pas le masquerading, car c'est complètement inutile.

Il faut ensuite autoriser les paquets provenant des machines du réseau local à traverser la passerelle. Cela se fait avec des règles similaires à celles vues dans la section précédente, mais adaptées pour être utilisées dans la chaîne FORWARD de la table filter :

# Autorise le trafic DNS, HTTP, HTTPS,
# FTP, POP, SMTP et SSH au travers de la passerelle :
iptables -A FORWARD -s 192.168.0.0/24 -i eth0 -o ppp0 -p UDP --dport domain -j ACCEPT
iptables -A FORWARD -s 192.168.0.0/24 -i eth0 -o ppp0 -p TCP --dport domain -j ACCEPT
iptables -A FORWARD -s 192.168.0.0/24 -i eth0 -o ppp0 -p TCP --dport http -j ACCEPT
iptables -A FORWARD -s 192.168.0.0/24 -i eth0 -o ppp0 -p TCP --dport https -j ACCEPT
iptables -A FORWARD -s 192.168.0.0/24 -i eth0 -o ppp0 -p TCP --dport ftp -j ACCEPT
iptables -A FORWARD -s 192.168.0.0/24 -i eth0 -o ppp0 -p TCP --dport pop3 -j ACCEPT
iptables -A FORWARD -s 192.168.0.0/24 -i eth0 -o ppp0 -p TCP --dport smtp -j ACCEPT
iptables -A FORWARD -s 192.168.0.0/24 -i eth0 -o ppp0 -p TCP --dport ssh -j ACCEPT

# Autorise l'établissement des connexions protocolaires additionnelles :
iptables -A FORWARD -s 192.168.0.0/24 -i eth0 -o eth0 --match state \
	--state ESTABLISHED,RELATED -j ACCEPT

# Autorise le trafic en retour pour les connexions établies par les clients :
iptables -A FORWARD -i ppp0 -d 192.168.0.0/24 --match state \
	--state ESTABLISHED,RELATED -j ACCEPT

# Autorise le trafic ICMP :
iptables -A FORWARD -p ICMP --icmp-type echo-request -j ACCEPT
iptables -A FORWARD -p ICMP --icmp-type echo-reply -j ACCEPT
iptables -A FORWARD -p ICMP --icmp-type destination-unreachable -j ACCEPT

Enfin, le routage des paquets étant, par défaut, désactivé sous Linux, il faut le réactiver. Si votre distribution ne le fait pas, vous aurez donc également à ajouter une ligne telle que celle-ci :

# Activation du routage :
echo "1" > /proc/sys/net/ipv4/ip_forward

dans vos scripts de démarrage de votre système.

Certains routeurs et certaines passerelles d'Internet sont bogués et ne répondent pas correctement aux messages ICMP. Cela a pour conséquence, entre autres, que la taille maximum des paquets transmis via la passerelle peut ne pas être déterminée correctement. En effet, les clients de la passerelle utiliseront généralement la taille maximum utilisable pour communiquer avec la passerelle, et cette taille peut malheureusement être supérieure à la taille maximum des paquets pour atteindre certains sites Web. Les messages d'erreurs ICMP étant filtrés, personne ne peut s'en apercevoir, et certaines connexions peuvent rester bloquées ad vitam eternam. Pratiquement parlant, cela se traduit par l'impossibilité, pour certains clients bénéficiant du partage de connexion à Internet, d'accéder à certains sites Web ou à certains gros fichiers d'une page (images par exemple).

Pour pallier ce problème Linux propose une technique approximative, dont le but est de fixer une option des paquets TCP d'établissement de connexion, afin de limiter la taille des paquets suivants de la connexion à la taille maximum déterminée pour la route vers les ordinateurs cibles. Ainsi, les clients se limitent d'eux-même, pourvu que la taille maximum des paquets de la route soit correctement déterminée, bien entendu. Il est recommandé d'activer cette fonctionnalité, ce qui se fait à l'aide de la commande suivante :

# Restreint la taille des paquets des connexions TCP
# lors de leur établissement :
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS -o ppp0 \
    --clamp-mss-to-pmtu

Cette règle un peu compliquée permet de modifier le champ MSS (« Maximum Segment Size ») des paquets d'établissement des connexions TCP (paquets disposant des flags TCP SYN ou RST) qui traversent la passerelle, et de forcer ce champ à la valeur de la taille maximum des paquets sur le chemin (« Path Maximum Transmission Unit » dans l'option --clamp-mss-to-pmtu).

Note : Les chaînes et leurs règles ne sont pas enregistrées de manière permanente dans le système. Elles sont perdues à chaque redémarrage de la machine, aussi faut-il les redéfinir systématiquement. Cela peut être réalisé dans les scripts de démarrage de votre système. Vous pouvez également utiliser les commandes iptables-save et iptables-restore pour sauvegarder toutes les chaînes et leurs règles dans un fichier et les restaurer au démarrage.

N'oubliez pas que votre passerelle doit définir une route par défaut pour que tous les paquets qui ne sont pas destinés au réseau local soient envoyés par l'interface réseau connectée à Internet. Cette route par défaut est établie automatiquement lorsque vous vous connectez à Internet à l'aide de PPP. Dans les autres cas, vous aurez à la définir manuellement.

9.4.7. Configuration des clients

La configuration des autres machines du réseau est très simple. Vous devrez tout d'abord définir la machine possédant la connexion à Internet comme passerelle par défaut de tous vos postes clients. Cette opération peut se réaliser de différentes manière selon le système d'exploitation utilisé par ces machines. Sous Linux, il suffit d'utiliser la commande suivante :

route add default gw passerelle eth0
passerelle est l'adresse de votre passerelle vers Internet sur le réseau local. Cette commande suppose que l'adaptateur réseau utilisé est eth0

La deuxième étape est ensuite de donner accès aux postes clients au DNS de votre fournisseur d'accès. Cela permettra en effet d'utiliser les noms de machines autres que ceux de votre réseau local. Encore une fois, la manière de procéder dépend du système utilisé. Sous Linux, il suffit d'ajouter les adresses IP des serveurs de noms de domaine de votre fournisseur d'accès dans le fichier de configuration /etc/resolv.conf.

Si les clients ont des difficultés à accéder à certaines pages Web, c'est que le MTU (« Maximum Transmission Unit », taille maximum des paquets réseau) est trop élevé. Ceci se corrige généralement tel qu'on l'a indiqué dans la définition des règles de la passerelle. Toutefois, si les ordinateurs qui bénéficient du partage de connexion à Internet continuent d'avoir des problèmes, c'est que le MTU de la route permettant d'accéder aux sites Web posant problème n'a pas pu être déterminé correctement. Dans ce cas, il faut le trouver soi-même, et le fixer dans la configuration réseau des clients. Pour cela, le plus simple est d'utiliser la commande ping avec son option -s sur les clients, avec plusieurs tailles de paquets possible. La taille maximum est de 1500 octets sur Ethernet. En général, une taille de 1400 octets convient :

ping -s 1400 adresse

Une fois le MTU correctement déterminé, il suffit de fixer cette valeur lors de la configuration des interfaces réseau des clients :

ifconfig interface mtu taille

interface représente ici l'interface à configurer, et taille la taille maximum trouvée à l'aide de ping.

Note : La taille effective du MTU est en réalité la taille fournie à la commande ping plus vingt-huit octets, car les paquets utilisés contiennent toujours l'en-tête ICMP en plus des données générées par ping.