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.
Pour toute question technique sur le contenu de ce guide, contactez l'auteur,
Daniel Robbins, à l'adresse suivante:
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.
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é.
Avant de commencer à bâtir le firewall, il faut faire deux choses. Tout d'abord,
il faut s'assurer que la commande
# emerge iptables
Une fois installée, vous devez avoir une commande
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
[ ] 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 :)
Pour construire un firewall, la commande
# 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.
La commande
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.
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
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.
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.
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.
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.
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
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
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.
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.
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).
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.
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
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é
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.
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.
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.
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
En utilisant ce script, vous pouvez désactiver le firewall en tapant
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
if [ -e /proc/sys/net/ipv4/tcp_ecn ] then echo 0 > /proc/sys/net/ipv4/tcp_ecn fi
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
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).
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
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.
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.
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.
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.
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
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
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
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.
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.
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.
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
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.
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
# 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:"
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.
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é.
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...
Visitez le site web du projet netfilter/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.
Le
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
Les développeurs Netfilter/iptables qui ont des questions, suggestions ou
contributions pour le developpement de Netfilter/iptables peuvent contacter
Vous pouvez aussi parcourir les archives de mailing-list sur ces URLs.
En juin 2000, O'Reilly a publié un excellent livre --
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.
Nous acceptons volontier vos remarques sur ce tutorial. De plus, n'hésitez pas
à contacter l'auteur, Daniel Robbins, à l'adresse