Firewall stateful sous Linux 2.4 Daniel Robbins Ce guide va vous apprendre à batir un puissant firewall stateful en utilisant NetFilter sous Linux. 1.3 2005-10-09 A propos de ce guide
A qui s'adresse ce guide ?

Ce guide vous montre comment utiliser NetFilter pour configurer un puissant firewall stateful. Tout ce dont vous aurez besoin est d'un système Linux existant utilisant une version 2.4 ou supérieure du noyau Linux. Un portable, PC de bureau, routeur ou serveur avec un Linux 2.4 ou plus fera l'affaire.

Vous devez être assez familier avec le vocabulaire réseau, comme les adresses IP, les ports source et destination, TCP, UDP ou ICMP, etc. Après avoir suivi ce guide jusqu'au bout, vous aurez compris le fonctionnement d'un firewall stateful sous Linux. De nombreux exemples de configurations vous seront également exposés.

A propos de l'auteur

Pour toute question technique sur le contenu de ce guide, contactez l'auteur, Daniel Robbins, à l'adresse suivante: drobbins@gentoo.org.

Résidant à Albuquerque, dans le Nouveau Mexique, Daniel Robbins a été le PDG de Gentoo Technologies, Inc., le créateur de Gentoo Linux, un système d'exploitation Linux moderne pour PC, et du système Portage, un gestionnaire de ports nouvelle génération pour Linux. Il a également été un des auteurs contributeurs pour les livres Caldera OpenLinux Unleashed, SuSE Linux Unleashed, et Samba Unleashed, parus aux éditions Macmillan. Daniel a été au contact de l'informatique depuis l'école élémentaire, quand il fut confronté au langage de programmation Logo, ainsi qu'à une dose potentiellement dangereuse de Pac Man. Celà explique sans doute pourquoi il a depuis été employé en tant que Chef Infographiste chez SONY Electronic Publishing/Psygnosis. Daniel aime passer son temps libre avec sa femme, Mary, et sa fille, Hadassah.

Premières étapes
Le but du jeu

Dans ce guide, nous allons bâtir un firewall stateful Linux. Notre firewall va s'exécuter sur un ordinateur portable, de bureau, serveur ou routeur sous Linux; son but principal est d'autoriser seulement certains types de traffic réseau à le traverser. Pour augmenter la sécurité, nous allons configurer le firewall pour ignorer ou rejeter le traffic qui ne nous interesse pas, ainsi que le traffic potentiellement dangereux pour la sécurité.

Les outils nécessaires

Avant de commencer à bâtir le firewall, il faut faire deux choses. Tout d'abord, il faut s'assurer que la commande iptables est disponible sur la machine. Pour celà, en tant que super-utilisateur, tapez iptables et vérifiez ce que vous répond le shell. Si la commande n'existe pas, alors il nous faut l'installer. Voilà comment faire :

# emerge iptables
Configuration du noyau

Une fois installée, vous devez avoir une commande iptables disponible, ainsi que la page de manuel qui lui correspond (man iptables). Bien; maintenant il faut nous assurer que les fonctionnalités nécessaires sont bien activées dans le noyau. Ce guide suppose que vous compilez vos propres noyaux. Dans le répertoire /usr/src/linux, tapez make menuconfig ou make xconfig; nous allons choisir certaines fonctionnalités pour notre noyau.

Dans la section "Networking options" (dans le menu "Networking->Networking Options" pour le noyau 2.6), assurez-vous d'activer au moins les options suivantes:

<*> Packet socket
[*] Network packet filtering (replaces ipchains)
<*> Unix domain sockets
[*] TCP/IP networking
[*]   IP: advanced router
[*]   IP: policy routing
[*]    IP: use netfilter MARK value as routing key
[*]    IP: fast network address translation
[*]   IP: use TOS value as routing key

Ensuite, dans le menu "IP: Netfilter Configuration ->", activez toutes les options, afin d'avoir toutes les fonctionnalités NetFilter disponibles pour votre firewall. Nous n'aurons pas besoin de toutes, mais vous pourrez ainsi plus tard mener quelques expériences avec ces options.

Il y a une fonctionnalité dans la section "Networking options" que vous ne devriez pas activer: la notification explicite de congestion. Laissez cette option décochée.

[ ]   IP: TCP Explicit Congestion Notification support

Si cette option est activée, votre machine Linux ne sera pas capable de supporter des communications réseau avec environ 8% de l'Internet. Quand l'ECN est activée, certains paquets envoyés par votre machine Linux auront le bit ECN valué à 1. En pratique, ce bit engendre des comportements bizarres sur certains routeurs Internet, aussi vaut-il mieux garder l'ECN désactivée.

Maintenant que le noyau est configuré correctement, compilez-le, installez-le et rebootez. Nous pouvons maintenant nous amuser avec NetFilter :)

Premiers pas

Pour construire un firewall, la commande iptables sera votre meilleure alliée. Elle permet d'interagir avec les règles de filtrage de paquets au niveau du noyau. Nous utiliserons la commande iptables pour créer de nouvelles règles, afficher les règles existantes, en supprimer, et choisir la politique de filtrage par défaut. Ce qui signifie que la création d'un firewall se résume à entrer une série de commandes iptables, comme par exemple (ATTENTION, ne pas la taper tout de suite !)

# iptables -P INPUT DROP

Si vous voulez créer un firewall "quasiment" parfait, et que vous entrez cette commande, vous serez absolument bien protégé contre toutes formes d'attaques malicieuses. En effet, cette commande ordonne au noyau d'ignorer tous les paquets réseau entrants. Cependant, même si ce firewall est extrêmement sécurisé, il est également un peu mauvais. Mais avant de continuer, essayons de comprendre comment cette commande peut faire ce qu'elle fait.

Modifier la politique par défaut

La commande iptables -P est utilisée pour selectionner la politique par défaut pour une chaine de filtrage de paquets. Dans cet exemple, iptables -P est utilisée pour changer la politique par défaut de la chaine INPUT, une chaine préinstallée qui est appliquée à chaque paquet entrant. En sélectionnant la potique par défaut DROP, on indique au noyau que chaque paquet qui atteint la fin de la chaine INPUT doit être droppé (c'est à dire ignoré, supprimé de la mémoire). Et comme nous n'avons pas encore ajouté de règles dans la chaine INPUT, tous les paquets atteignent la fin de la chaine, et donc tous les paquets sont ignorés.

Encore une fois, à elle seule, cette commande est totalement inutile. Cependant, elle montre une bonne stratégie pour la construction d'un firewall. On commence par ignorer tous les paquets par défaut, puis on ouvre au fur et à mesure les ports dont on a besoin. Celà garantit que le firewall est aussi sécurisé que possible.

Definir ses règles
Une (petite) amélioration

Dans cet exemple, nous supposerons que nous construisons un firewall pour une machine avec deux interfaces réseau, nommées eth0 et eth1. L'interface eth0 est connectée sur notre LAN, tandis que eth1 est branchée sur notre routeur DSL, qui mène vers Internet. Dans une telle situation, nous améliorerons notre "firewall ultime" en rajoutant une ligne:

# iptables -P INPUT DROP
# iptables -A INPUT -i ! eth1 -j ACCEPT

Cette ligne supplémentaire iptables -A ajoute une nouvelle règle de filtrage de paquets à la fin de la chaine INPUT. Après avoir rajouté cette règle, la chaine INPUT consiste en une règle unique et une règle DROP par défaut. Maintenant, voyons ce que fait notre firewall désormais à moitié terminé.

Le long de la chaine INPUT...

Quand un paquet arrive sur l'une des interfaces (lo, eth0, ou eth1), le code de NetFilter l'envoie sur la chaine INPUT et vérifie s'il correspond à la première règle. Si c'est le cas, est accepté, et le traitement de ce paquet est terminé. Sinon, la règle par défaut de INPUT est appliquée, et le paquet est effacé (DROP).

Voilà pour le point de vue conceptuel. Plus concrétement, la première règle correspond à tous les paquets arrivant sur les interfaces eth0 et lo, et les laisse passer. Tous les paquets arrivant sur l'interface eth1 sont droppés. Donc, si nous activons ce firewall sur notre machine, il pourra intéragir avec notre LAN mais ne pourra pas communiquer avec Internet. Voyons comment autoriser le traffic Internet, et ce de deux manières différentes.

Firewalls traditionnels

Evidemment, pour que notre firewall serve à quelque chose, il nous faut sélectionner quels paquets seront autorisés à atteindre notre machine en passant par Internet. Il y a deux approches pour faire celà: l'une utilise des règles statiques, tandis que l'autre utilise des règles dynamiques, avec suivi d'état (stateful).

Prenons pour exemple le cas du téléchargement de pages Web. Si nous voulons que notre machine soit capable de recevoir les paquets correspondants au téléchargement, nous pouvons ajouter une règle statique qui sera toujours vraie pour les paquets HTTP entrants, quelle que soit leur origine:

# iptables -A INPUT --sport 80 -j ACCEPT

Comme tout le traffic Web standard provient d'un serveur avec port source 80, cette règle permet effectivement à votre machine de télécharger des pages Web. Cependant, cette approche traditionnelle, bien qu'acceptable dans certains cas, engendre de nombreux problèmes.

Problèmes des firewalls traditionnels

Voilà le premier problème: bien que la plupart du traffic Web a pour origine un port 80, ce n'est quelquefois pas vrai. Donc, cette règle marche, mais seulement la plupart du temps. Par exemple, vous avez peut-être déjà vu une URL du genre "http://www.foo.com:81". Cette URL pointe vers un serveur Web hébergé sur un serveur écoutant sur le port 81 plutôt que le port 80 par défaut, et est donc invisualisable derrière notre firewall. Prendre en compte toutes les exceptions de ce genre va vite faire de notre firewall sécurisé un sac de noeuds et remplira notre chaine INPUT avec un tas de règles pour gérer chaque cas particulier.

Cependant, le problème majeur de ce genre de règle est lié à la sécurité. Evidemment, il est vrai que seulement le traffic avec un port source 80 sera autorisé à passer notre firewall. Mais le port source d'un paquet est un élément facilement manipulable par un attaquant. Par exemple, si un intrus connait la façon dont notre firewall est conçu, il peut le contourner simplement en s'assurant que toutes ses connexions entrantes viennent d'un port 80 de l'une de ses machines ! Puisque cette règle statique est trop facile à contourner, il nous faut une approche plus sécurisée et dynamique. Heureusement, iptables et le noyau 2.4 et supérieurs incluent tout ce dont nous avons besoin pour construire un firewall dynamique et à suivi d'états.

Firewalls stateful
Quelques mots sur les états

Plutôt que de creuser des trous dans notre firewall en se basant sur des caractéristiques statiques des protocoles, on peut utiliser les nouvelles fonctionnalités de suivi de connexion de Linux pour baser les décisions du firewall sur l'état dynamique des paquets par rapport à la connexion. Conntrack fonctionne en associant chaque paquet avec une et une seule communication bidirectionnelle, ou connexion.

Par exemple, imaginons ce qui se passe lorsque vous utilisez telnet ou ssh pour vous connecter sur une machine distante. Si vous regarder le traffic réseau au niveau paquets, tout ce que vous verez sera un tas de paquets passant d'une machine sur l'autre. Cependant, à un niveau d'abstraction plus élevé, cette échange de paquets est en fait une communication bidirectionelle entre votre machine locale et la machine distante. Les firewalls traditionnels ne font que regarder chaque paquet indépendemment les uns des autres, sans se soucier qu'ils fassent en réalité partie d'un tout, d'une connexion.

Conntrack en détails

C'est là que la technologie de suivi de connexion entre en jeu. La fonctionnalité conntrack de Linux peut "voir" les connexions de haut niveau lorsqu'elles ont lieu, reconnaissant votre session SSH comme une seule entité logique. Conntrack peut aussi reconnaître les échanges de paquets UDP et ICMP comme des "connexions" logiques, même si UDP et ICMP sont sans connexion par nature; celà est très utile puisque sela permet d'utiliser conntrack pour gérer des échanges de paquets ICMP et UDP.

Si vous avez déjà redémarré avec votre nouveau noyau avec NetFilter activé, vous pouvez voir une liste des connexions réseau actives auquelles votre machine participe en entrant cat /proc/net/ip_conntrack. Même sans firewall configuré, conntrack fonctionne en arrière-plan, en gardant trace des connexions établies ou reçues par votre machine.

Etat de connexion NEW

Conntrack ne fait pas que reconnaitre les connexions, il classe également chaque paquet qu'il voit dans l'un des quatres états de connexion. Le premier état dont nous allons parler est appelé NEW (nouveau). Quand vous tapez ssh hote.distant.com, le premier paquet ou la première rafale de paquets qui sortent de votre machine et sont destinés à hote.distant.com sont dans l'état NEW. Cependant, dès que vous aurez reçu ne serait-ce qu'un seul paquet de hote.distant.com, tous les futurs paquets que vous enverrez à hote.distant.com dans cette connexion ne seront plus considérés comme des packets NEW. Pour résumer, un paquet est considéré NEW lorsqu'il sert à établir une nouvelle connexion, et qu'aucun trafic n'a été reçu de l'hôte distant en retour (dans le cadre de cette connexion précise, évidemment).

J'ai décris les paquets NEW sortants, mais il est également tout à fait possible (et normal) d'avoir des paquets NEW entrants. Les paquets NEW entrants viennent généralement d'une machine distante, et servent à établir une connexion avec vous. Le(s) premier(s) paquet(s) que votre serveur Web reçoit pour une requête HTTP sont considérés comme des paquets NEW entrants; cependant, une fois que vous aurez répondu à un seul de ces paquets, tous les autres paquets que vous recevrez ne seront plus considérés dans l'état NEW.

Etat de connexion ESTABLISHED

Une fois qu'une connexion a vue du trafic dans les deux sens, tous les nouveaux paquets de cette connexion sont considérés dans l'état ESTABLISHED (établi). La distinction entre les états NEW et ESTABLISHED est très importante, comme nous le verrons dans un instant.

Etat de connexion RELATED

Le troisième état de connexion est appelé RELATED (en rapport avec). Les paquets RELATED sont ceux qui établissent une nouvelle connexion, mais qui sont en rapport avec une connexion déjà existante. L'état RELATED peut être utilisé pour filtrer des connexions qui font partie d'un protocole multi-connexion, comme FTP, ainsi que les paquets d'erreur en rapport avec des connexions existantes (comme les paquets d'erreur ICMP).

Etat de connexion INVALID

Pour terminer, il existe aussi les paquets INVALID: ce sont ceux qui ne peuvent être classés dans aucune des trois précédentes catégories. Il est important de noter qu'un paquet considéré comme INVALID n'est pas automatiquement ignoré; c'est à vous de choisir les règles appropriées et d'ajuster les politiques pour que ces paquets soient gérés de la manière que vous préférez.

Ajout d'une règle stateful

Bien, maintenant que nous avons compris le suivi de connexion, il est temps de jeter un oeil à une simple règle supplémentaire qui va transformer notre firewall non-fonctionnel en quelque chose de plutôt utile.

# iptables -P INPUT DROP
# iptables -A INPUT -i ! eth1 -j ACCEPT
# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
Fonctionnement de cette règle

Cette simple règle, insérée à la fin de votre chaine INPUT existante, va nous permettre d'établir des connexions avec des machines distantes. Elle fonctionne comme ceci: disons que l'on veuille faire du ssh vers hote.distant.com. Après avoir lancé ssh hote.distant.com, notre machine envoie un paquet pour établir la connexion. Ce paquet particulier est dans l'état NEW, et notre firewall le laisse passer, puisque nous bloquons seulement les paquets qui entrent dans notre firewall, pas qui en sortent.

Quand nous recevons une réponse de hote.distant.com, ce paquet passe par notre chaine INPUT. Il ne correspond pas à la première règle (puisqu'il arrive de eth1), donc il passe à la seconde et dernière règle. Si il correspond à cette règle, il sera accepté, et sinon, il arrivera à la fin de la chaine INPUT et la politique par défaut lui sera appliquée (DROP). Alors, ce paquet entrant sera-t'il accepté ou droppé ?

Réponse: accepté. Quand le noyau examine ce paquet entrant, il reconnait en premier qu'il fait partie d'une connexion existante. Ensuite, le noyau doit décider s'il s'agit d'un paquet NEW ou ESTABLISHED. Puisqu'il s'agit d'un paquet entrant, il vérifie si cette connexion a déjà eu du trafic sortant, et trouve que c'est le cas (le paquet NEW initial que nous avons envoyé). Ensuite, le paquet entrant est classé ESTABLISHED, comme le seront tous les futurs paquets reçus ou envoyés qui seront associés avec cette connexion.

Paquets NEW entrants

Maintenant, considérons ce qui ce passe si quelqu'un sur une machine distante essaie de se connecter en ssh chez nous. Le premier paquet que nous recevons est marqué NEW, et ne correspond pas à la règle 1, donc il passe à la règle 2. Puisque ce paquet n'est pas dans l'état ESTABLISHED ou RELATED, il arrive à la fin de la chaine INPUT et la politique par défaut, DROP, est appliquée. Notre demande d'établissement de connexion ssh entrante est donc ignorée sans même une réponse (ou un paquet TCP reset) de notre part.

Un firewall proche de la perfection

Alors, quel genre de firewall avons-nous jusqu'à présent ? Un excellent choix pour un portable ou un poste de travail si vous voulez que personne ne puisse se connecter depuis Internet vers vous, mais avec lequel vous pouvez quand même vous connecter à des sites sur Internet. Vous pourrez utiliser Netscape, Konqueror, ftp, ping, faire des recherches DNS, et bien plus. Toutes les connexions dont vous êtes l'initiateur pourront passer votre firewall. Cependant, les connexions non sollicitées qui viennent depuis Internet seront ignorées, à moins d'être en relation avec une connexion existante que vous avez initiée. Tant que vous ne devez pas fournir un service réseau vers l'extérieur, c'est un firewall pratiquement parfait.

Un script de firewall simple

Voilà un script simple qui peut être utilisé pour configurer notre premier firewall de station de travail:

#!/bin/bash
# Un script de firewall simple pour une station de travail ou un
portable
# qui ne fournit aucun service réseau, comme un  serveur web, ftp,
smtp, etc.

if [ "$1" = "start" ]
then
        echo "Démarrage du firewall..."
        iptables -P INPUT DROP
        iptables -A INPUT -i ! eth1 -j ACCEPT
        iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
elif [ "$1" = "stop" ]
then
        echo "Arrêt du firewall..."
        iptables -F INPUT
        iptables -P INPUT ACCEPT
fi
Utilisation du script

En utilisant ce script, vous pouvez désactiver le firewall en tapant ./firewall stop, et le relancer en tapant ./firewall start. Pour désactiver le firewall, on supprime les règles de la chaine INPUT en faisant iptables -F INPUT, puis reprenons la politique par défaut de INPUT en ACCEPT avec la commande iptables -P INPUT ACCEPT. Maintenant, voyons tout un tas d'améliorations que nous pouvons faire sur notre firewall. Après avoir expliqué chaque amélioration, je présenterai un script avancé pour un poste de travail. Ensuite, nous commencerons à modifier notre firewall pour des serveurs.

Améliorations au suivi d'états
Désactication explicite de l'ECN

J'ai parlé plus haut de l'importance de désactiver l'ECN (explicit congestion notification) pour que les communications Internet fonctionnent correctement. Même si vous avez désactivé l'ECN dans le noyau en suivant ma suggestion, il est possible que vous l'oubliez dans le futur. Ou, comme c'est possible, vous allez paser votre script de firewall à quelqu'un qui a l'ECN activé. Pour ces raisons, c'est une bonne idée d'utiliser l'interface /proc pour désactiver explicitement l'ECN, comme ceci:

if [ -e /proc/sys/net/ipv4/tcp_ecn ]
then
        echo 0 > /proc/sys/net/ipv4/tcp_ecn
fi
Forwarding

Si vous utilisez votre machine Linux comme un routeur, alors vous voudrez activer l'IP forwarding, ce qui donnera la permission au noyau de transmettre des paquets de l'interface eth0 à eth1, et inversement. Dans notre exemple de configuration, ou eth0 est connectée à notre LAN, et eth1 à Internet, activer l'IP forwarding est une étape nécessaire pour permettre à notre LAN de se connecter à Internet en passant par notre machine Linux. Pour activer l'IP forwarding, utilisez cette ligne:

# echo 1 > /proc/sys/net/ipv4/ip_forward
Gestion des rejets

Jusqu'à présent, nous avons ignoré tout le trafic non solicité venant d'Internet. Bien que celà soit un moyen efficace pour contrer l'activité réseau non désirable, celà engendre également quelques inconvénients. Le plus gros problème avec cette approche est qu'il est facile pour un intrus de détecter que nous utilisons un firewall, puisque notre machine ne répond pas avec les réponses standards TCP reset et ICMP port-unreachable, c'est à dire les réponses qu'une machine normale devrait renvoyer pour indiquer une tentative de connexion échouée vers un service non existant.

Plutôt que de laisser des intrus potentiels savoir que nous utilisons un firewall (ce qui peut leur laisser penser que nous fournissons des services précieux auquels ils ne peuvent pas accéder), il serait à notre avantage de faire croire que nous n'utilisons pas de firewall. En ajoutant ces deux règles à la fin de la chaine INPUT, on peut facilement accomplir cette tâche:

# iptables -A INPUT -p tcp -i eth1 -j REJECT --reject-with tcp-reset
# iptables -A INPUT -p udp -i eth1 -j REJECT --reject-with
icmp-port-unreachable

La première règle s'occupe de rejeter correctement les connexions TCP, alors que la seconde s'occupe de l'UDP. Avec ces deux règles, il devient difficile pour un intrus de détecter que nous sommes derrière un firewall; avec de la chance, l'intrus se détournera de notre machine pour chercher d'autres cibles potentiellement plus intérressantes.

En plus de rendre notre firewall plus "discret", ces règles éliminent aussi le délai lors de la connection à certains serveurs FTP et IRC. Ce délai est dû au serveur qui tente de faire une requête ident sur votre machine (en se connectant sur le port 113), qui échoue après un timeout d'environ 15 secondes. Maintenant, notre firewall va renvoyer un TCP reset et la requête ident va échouer immédiatement plutôt que de réssayer pendant 15 secondes (alors que vous attendez patiemment une réponse du serveur).

Protection contre le Spoof

Dans plusieurs distributions, quand une interface réseau est activée, plusieurs vieilles règles ipchains sont également ajoutées au système. Ces règles spéciales avaient été ajoutées par les créateurs de la distribution pour contrer un problème appelé spoofing, dans lequel les adresses sources des paquets ont été traffiqués pour contenir une valeur invalide (c'est une des choses que les script kiddies font). Bien que l'on pourrait créer des règles iptables similaires pour bloquer ces paquets spoofés, il y a une manière de faire plus facile. De nos jours, le noyau a la fonctionnalité intégrée d'ignorer les paquets spoofés; il suffit de l'activer par le biais de l'interface /proc. Voilà comment.

for x in lo eth0 eth1
do
        echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
done

Ce script shell va indiquer au noyau d'ignorer tous les paquets spoofés sur les interfaces lo, eth0 et eth1. Vous pouvez soit ajouter ces lignes à votre script de firewall, soit dans le script qui active vos interfaces lo, eth0, et eth1.

Masquerading

Le NAT (network address translation) et l'IP masquerading, bien que non directement en rapport avec les firewalls, sont souvent utilisés en complément. Nous allons voir deux configurations répandues de NAT/Masquerading que vous pourrez avoir à utiliser. La première règle servira dans les situations où vous utilisez un lien non permanent vers Internet (ppp0) avec une adresse IP dynamique.

# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

Si vous êtes dans cette situation, vous voudrez également convertir mes scripts de firewall pour que les références à "eth1" (le routeur DSL dans notre exemple) soient changées en "ppp0". Et il est tout à fait possible d'ajouter des règles qui font références à "ppp0" alors que cette interface n'existe pas encore. Dès que ppp0 est activée, tout fonctionnera à merveille. Vérifiez quannd même que vous avez activé l'IP forwarding.

SNAT

Si vous utilisez une ligne DSL pour vous connecter à Internet, vous avez probablement une des deux configurations suivantes. Dans la première, votre routeur DSL ou modem a sa propre adresse IP et s'occupe de la translation d'adresse pour vous. Si vous êtes dans cette situation, vous n'avez pas besoin de faire du NAT puisque votre routeur DSL le fait déjà.

Cependant, si vous voulez avoir plus de contrôle sur vos fonctionnalités NAT, vous pouvez eventuellement, si votre fournisseur d'accès le permet, configurer votre routeur DSL en mode "bridge" (pont). Dans ce mode, votre firewall devient un élément officiel du réseau de votre fournisseur d'accès, et le routeur DSL s'occupe de relayer le trafic de et vers votre machine Linux de manière transparente. Il n'a plus besoin d'une adresse IP; à la place, eth1 (dans notre exemple) en a une. Si quelqu'un pingue votre adresse IP depuis Internet, il recevra une réponse de votre machine Linux, et pas de votre routeur.

Avec ce genre de configuration, vous aurez à utiliser SNAT (source NAT) plutôt que le Masquerading. Voici la ligne que vous devriez rajouter à votre firewall:

# iptables -t nat -A POSTROUTING -o eth1 -j SNAT --to 1.2.3.4

Dans cet exemple, remplacez eth1 par l'interface Ethernet connectée sur votre routeur DSL, ainsi que 1.2.3.4 par votre adresse IP statique (l'IP de votre interface Ethernet). Encore une fois, n'oubliez pas l'IP forwarding.

Problèmes avec le NAT

Heureusement pour nous, le NAT et le masquerading s'entendent bien sur notre firewall. Quand vous écrivez vos règles de firewall, ignorez simplement que vous utilisez du NAT. Vos règles doivent accepter, ignorer ou rejeter les paquets en se basant sur leur "véritables" adresses source et destination. Le code de filtrage du firewall prend en compte l'adresse source d'origine et l'adresse de destination finale. C'est tant mieux pour nous, puisque celà permet à notre firewall de fonctionner correctement même si on désactive temporairement le NAT ou le masquerading.

Comprendre les tables

Dans les exemples de NAT/masquerading précédents, on a ajouté des règles à une chaine, mais nous avons également fait des choses un peu différemment. Remarquez l'option "-t". L'option "-t" permet de choisir la table à laquelle appartient notre chaine. Quand cette option n'est pas spécifiée, la table par défaut est la table "filter". Par conséquent, toutes les commandes précédentes sans rapport avec le NAT ont modifié la chaine INPUT qui fait partie de la table "filter". La table "filter" contient toutes les règles associées à l'acceptation/rejet de paquets, tandis que la table "nat" (comme vous pouvez le deviner) contient les règles concernant la translation d'adresse. Il existe d'autres chaines iptables qui sont décrites en détail dans la page de manuel iptables, ainsi que dans les HOWTO de Rusty Russel (cf. dans la section Ressources plus bas pour les liens).

Notre script amélioré

Maintenant que nous avons vu tout un tas d'améliorations possibles, il est temps de voir un second script plus souple d'activation/désactivation du firewall:


#!/bin/bash

# Un firewall statefull amélioré pour une station de travail, portable
ou routeur
# qui ne fourni aucun service réseau (comme serveur web, smtp, ftp,
etc.)

# Changez cette variable pour le nom de l'interface qui sert d'"uplink"

# (connexion à Internet)

UPLINK="eth1"

# Si vous êtes un routeur, (et donc souhaitez forwarder les paquets IP
entre les interfaces),
# mettez ROUTER="yes"; sinon, ROUTER="no"

ROUTER="yes"

# Changez la prochaine ligne pour mettre l'adresse IP statique de votre
interface
# uplink pour faire du SNAT statique, ou "dynamic" si vous avez une IP
dynamique
# Si vous n'avez pas besoin de NAT, laissez NAT="" pour le désactiver.


NAT="1.2.3.4"

# Changez cette variable pour lister toutes vos interfaces réseau, y
compris lo

INTERFACES="lo eth0 eth1"

if [ "$1" = "start" ]
then
        echo "Demarrage du firewall..."
        iptables -P INPUT DROP
        iptables -A INPUT -i ! ${UPLINK} -j ACCEPT
        iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
        iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset
        iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with
icmp-port-unreachable

        # Desactivation explicite de l'ECN
        if [ -e /proc/sys/net/ipv4/tcp_ecn ]
        then
                echo 0 > /proc/sys/net/ipv4/tcp_ecn
        fi

        # Désactiver le spoofing sur toutes les interfaces
        for x in ${INTERFACES}
        do
                echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
        done

        if [ "$ROUTER" = "yes" ]
        then
                # Activation de l'IP forwarding pour le routage

                echo 1 > /proc/sys/net/ipv4/ip_forward
                if [ "$NAT" = "dynamic" ]
                then
                        # Adresse IP dynamique, utilisation du
masquerading
                        echo "Activation du masquerading (IP dynamique)..."
                        iptables -t nat -A POSTROUTING -o ${UPLINK} -j
MASQUERADE
                elif [ "$NAT" != "" ]
                then
                        # IP statique, utilisation du SNAT
                        echo "Activation SNAT (IP statique)..."
                        iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to
${UPIP}
                fi
        fi

elif [ "$1" = "stop" ]
then
        echo "Arret du firewall..."
        iptables -F INPUT
        iptables -P INPUT ACCEPT
        # Désactive le NAT/masquerading
        iptables -t nat -F POSTROUTING
fi
Servers statefuls
Voir ses règles

Avant de commencer à modifier notre firewall pour pouvoir l'utiliser sur un serveur, je dois vous montrer comment afficher les règles actives sur votre firewall. Pour voir les règles dans la chaine INPUT de la table filter, tapez:

# iptables -v -L INPUT

L'option -v nous donne une sortie verbeuse, afin que l'on puisse voir le nombre total de paquets et d'octets transférés par règle. On peut aussi voir la chaine POSTROUTING de la table nat avec la commande suivante:

# iptables -t nat -v -L POSTROUTING
Chain POSTROUTING (policy ACCEPT 399 packets, 48418 bytes)
pkts bytes target     prot opt in     out     source               destination
2728  170K SNAT       all  --  any    eth1    anywhere             anywhere
to:215.218.215.2
Prêts pour le service

A l'heure actuelle, notre firewall ne permet pas au "public" de se connecter aux services sur notre machine car il accepte seulement les paquets entrants dans l'état ESTABLISHED ou RELATED. Comme il ignore tous les paquets NEW entrants, toutes les tentatives de connexion sont systématiquement rejetées. Cependant, en autorisant sélectivement certains paquets à traverser notre firewall, on peut permettre au "public" de se connecter aux services que nous voudrons.

HTTP stateful

Bien que l'on veuille accepter quelques connexions entrantes, on ne souhaite tout de même pas les accepter toutes. Il est préférable de partir d'une politique "rejet par défaut" (comme nous l'avons configuré actuellement) et d'ouvrir l'accès aux seuls services que l'on souhaite rendre publics. Par exemple, si nous avons un serveur Web, nous allons autoriser les paquets NEW vers notre machine, mais seulement s'ils sont destinés au port 80 (HTTP). C'est tout ce qu'il suffit de faire. Dès que nous autorisons le paquet NEW à passer, on autorise l'établissement de connexion. Une fois la connexion établie, la règle existante qui autorise les paquets entrants ESTABLISHED et RELATED entre en scène, laissant se dérouler la connexion HTTP sans accrocs.

Exemple d'HTTP stateful

Jetons un oeil au "coeur" de notre firewall et à la nouvelle règle qui autorise les connexion HTTP entrantes:

iptables -P INPUT DROP
iptables -A INPUT -i ! ${UPLINK} -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Notre nouvelle règle
iptables -A INPUT -p tcp --dport http -m state --state NEW -j ACCEPT
iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset
iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with
icmp-port-unreachable

Cette nouvelle règle autorise les paquets TCP NEW entrants destinés au port 80 (HTTP) de notre machine à entrer. Remarquez la place de cette règle. Il est important qu'elle soit placée avant notre règle REJECT. Comme iptables applique seulement la première règle qui correspond, la mettre derrière les lignes REJECT engendrerai qu'elle n'ai aucun effet.

Notre script de firewall avancé

Maintenant, voyons notre dernier script de firewall, qui peut être utilisé sur un portable, station de travail, routeur ou serveur (ou une quelconque combinaison !)


#!/bin/bash

# Notre script de firewall complement stateful. Ce firewall peut
être adapté
# pour un portable, station de travail, routeur ou même un serveur. :)


# Changez cette variable pour le no de l'interface "uplink"
# (connexion vers Internet)

UPLINK="eth1"

# Si vous êtes routeur (et donc souhaitez forwarder les paquets IP
entre les
# interfaces), mettez ROUTER="yes"; sinon, ROUTER="no"

ROUTER="yes"

# Changez la prochaine ligne vers l'adresse IP statique de votre
interface
# uplink pour du SNAT statique, ou "dynamic" si vous avez une IP
dynamique.
# Si vous ne voulez pas de NAT, mettez NAT="" pour le désactiver.


NAT="1.2.3.4"

# Changez cette ligne pour lister toutes vos interfaces réseaux, y
compris lo

INTERFACES="lo eth0 eth1"

# Changez cette ligne pour lister les numéros de ports ou noms
symboliques
# (de /etc/services) de tous les services que vous souhaiter rendre
publics.
# Si vous ne souhaitez publiez aucun service, laissez ""

SERVICES="http ftp smtp ssh rsync"

if [ "$1" = "start" ]
then
        echo "Démarrage du firewall..."
        iptables -P INPUT DROP
        iptables -A INPUT -i ! ${UPLINK} -j ACCEPT
        iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

        # Activer l'accès publics aux services
        for x in ${SERVICES}
        do
                iptables -A INPUT -p tcp --dport ${x} -m state --state NEW -j
ACCEPT
        done

        iptables -A INPUT -p tcp -i ${UPLINK} -j REJECT --reject-with tcp-reset
        iptables -A INPUT -p udp -i ${UPLINK} -j REJECT --reject-with
icmp-port-unreachable

        # Désactivation explicite de l'ECN
        if [ -e /proc/sys/net/ipv4/tcp_ecn ]
        then
                echo 0 > /proc/sys/net/ipv4/tcp_ecn
        fi

        # Protection anti-spoofing
        for x in ${INTERFACES}
        do
        echo 1 > /proc/sys/net/ipv4/conf/${x}/rp_filter
        done

        if [ "$ROUTER" = "yes" ]
        then
                # Activation de l'IP forwarding
                echo 1 > /proc/sys/net/ipv4/ip_forward
                if [ "$NAT" = "dynamic" ]
                then
                # IP dynamique => masquerading
                echo "Activation du masquerading (ip dynamique)..."
                        iptables -t nat -A POSTROUTING -o ${UPLINK} -j
MASQUERADE
                elif [ "$NAT" != "" ]
                then
                        # IP statique => SNAT
                        echo "Activation du SNAT (ip statique)..."
                        iptables -t nat -A POSTROUTING -o ${UPLINK} -j SNAT --to
${UPIP}
                fi
        fi

elif [ "$1" = "stop" ]
then
        echo "Arrêt du firewall..."
        iptables -F INPUT
        iptables -P INPUT ACCEPT
        # Arrêt du masquerading
        iptables -t nat -F POSTROUTING
fi
Construire un meilleur firewall pour serveur
Améliorations

Il est souvent possible de rendre son firewall toujours un peu "mieux". Bien sûr, la signification de "mieux" dépend de vos besoins spécifiques. Notre script existant peu combler exactement les vôtres, ou peut-être que quelques retouches seront nécessaires. Cette section est sensée servir de livre à idées, pour vous montrer plusieurs moyens d'améliorer notre firewall stateful existant.

Techniques de log

Jusqu'à présent, nous n'avons pas vu comment logger des evenements. Il y a une cible spéciale appelée LOG que vous pouvez utiliser pour celà. Associée à LOG, il y a une option spéciale appelée --log-prefix qui permet de choisir le texte qui apparaîtra devant le descriptif du paquet dans les logs du système. Voilà un exemple de règle LOG:

#  iptables -A INPUT -j LOG --log-prefix "Anomalie INPUT:"

Vous ne voudrez certainement pas ajouter cette règle en premier dans votre chaine INPUT, car celà entraînerait qu'une entrée dans les logs soit créée pour chaque paquet que vous recevez ! A la place, placez cette règle assez bas dans la chaine INPUT pour logguer uniquement les paquets bizarres et autres anomalies.

Une remarque importante sur la cible LOG. Normalement, quand une règle correspond à un paquet, ce paquet est soit accepté, rejeté ou ignoré, et les règles suivantes ne sont pas vérifiées. Cependant, quand une règle LOG correspond, ce paquet est loggué. Il n'est ni accepté, ni rejeté, ni ignoré. A la place, le paquet est confronté à la règle suivante, ou bien la règle par défaut est appliquée s'il n'y a pas de règle suivante.

La cible LOG peut également être combinée avec le module "limit" (décrit dans la page de manuel iptables) pour éviter d'avoir trop d'entrées dupliquées. Voilà un exemple:

# iptables -A INPUT -m state --state INVALID -m limit --limit 5/minute -j LOG
--log-prefix "Etat INVALID:"
Créer vos propres chaines

iptables vous permet de créer vos propres chaines qui peuvent être ensuite spécifiée comme cibles dans vos règles. Pour en apprendre plus à ce sujet, étudiez le Packet filtering HOWTO hebergé sur le site du projet netfilter/iptables (http://www.netfilter.org/).

Politique de restriction d'usages

Les firewalls offrent une grande puissance à ceux qui veulent restreindre les usages d'un réseau dans une entreprise ou un réseau académique. Vous pouvez contrôler quels paquets votre machine relait en ajoutant des règles dans la chaine FORWARD. En ajoutant des règles à la chaine OUTPUT, vous pouvez également contrôler ce qui arrive aux paquets générés localement, par les utilisateurs sur la machine Linux elle-même. iptables a aussi l'incroyable capacité de filtrer les paquets générés localement en fonction de leur propriétaire (UID ou GID). Pour plus d'informations à ce sujet, cherchez "owner" (propriétaire) dans la page de manuel iptables.

Autres angles de la sécurité

Dans notre exemple de firewall, nous avons supposé que tout le trafic du LAN interne est digne de confiance, et que seul le trafic Internet devait être filtré avec soin. Selon votre réseau interne, celà peut être ou ne pas être le cas. Rien ne vous empêche de configurer votre firewall pour se protéger également du coté du LAN. Envisagez les autres "angles" de votre réseau que vous voulez protéger. Il peut être aussi approprié de configurer deux zones de sécurité différentes dans votre LAN, chacune avec sa propre politique de sécurité.

Ressources
tcpdump

Dans cette section, je vous mets des pointeurs vers des ressources variées que vous trouverez certainement utiles pour vous aider à mettre au point votre firewall. Commençons par un outil important...

tcpdump est un outil essentiel pour l'exploration bas niveau des echanges de paquets et pour vérifier que votre firewall fonctionne correctement. Si vous ne l'avez pas, téléchargez le. Si vous l'avez, commencez à l'utiliser.

netfilter.kernelnotes.org

Visitez le site web du projet netfilter/iptables (http://www.netfilter.org). You'll find many resources at this site, including the iptables sources and a netfilter FAQ. Also Rusty's Remarkably Guides are excellent, and include a basic networking concepts HOWTO, a netfilter (iptables) HOWTO, a NAT HOWTO, and a netfilter hacking HOWTO for developers.

La page de manuel iptables

Heureusement, il y a beaucoup de ressources disponibles en ligne sur Netfilter; cependant, n'oubliez pas les bases. La page de manuel iptables est très détaillée et est un excellent exemple de ce à quoi une page de manuel devrait ressembler. C'est une lecture passionnante.

Advanced Linux routing and traffic control HOWTO

Le Advanced Linux Routing and Traffic Control HOWTO est disponible (également en français). Il contient tout un chapitre sur l'utilisation d'iptables pour le marquage de paquets, puis sur l'utilisation des fonctionnalités de routage de Linux pour router les paquets en fonction de ces marques.

Ce guide contient des références vers la fonction de contrôle de trafic (qualité de service) de Linux (accessible via la commande tc). Cette nouvelle fonctionnalité, bien que très puissante, est très peu documentée, et essayer de cerner tous les aspects du contrôle de trafic peut être une tache très frustrante pour le moment.
Mailing lists

Les utilisateurs qui ont des questions sur l'utilisation, l'installation ou la configuration de Netfilter/iptables, ou qui veulent aider les autres utilisateurs en partageant leurs experience et connaissances, peuvent contacter la mailing-list des utilisateurs de Netfilter.

Les développeurs Netfilter/iptables qui ont des questions, suggestions ou contributions pour le developpement de Netfilter/iptables peuvent contacter la mailing-list des développeurs de Netfilter.

Vous pouvez aussi parcourir les archives de mailing-list sur ces URLs.

Building Internet Firewalls, Second Edition

En juin 2000, O'Reilly a publié un excellent livre -- Building Internet Firewalls, Second Edition. C'est un bon manuel de référence, en particulier dans les cas où vous voulez configurer votre firewall pour accepter (ou rejeter) un protocole peu connu avec lequel vous n'êtes pas familier.

Voilà, c'était la liste de nos ressources, et ce guide est terminé. J'espère qu'il vous a été utile, et j'attends vos remarques.

Vos remarques

Nous acceptons volontier vos remarques sur ce tutorial. De plus, n'hésitez pas à contacter l'auteur, Daniel Robbins, à l'adresse drobbins@gentoo.org.