iptables

Encore une fois,  il n'est pas question de reprendre toute la documentation d'IPtables. Nous allons simplement examiner quelques règles simples d'un usage courant. Pour étudier la syntaxe, consultez:

Les pages de man, bien que pas toujours très agréables à lire, sont essentielles, pour la simple raison que Netfilter/IPtables sont des outils en pleine évolution et que d'une version à l'autre, de nouvelles fonctionnalités peuvent apparaître.

Manipulations diverses

Pour ce qui suit, nous allons faire de la pratique. Debian Etch montée en passerelle, tel que décrit dans le chapitre « Partage de connexion ».

Le masquage d'adresses Rappelons-le, il s'agit de masquer tous les clients d'un réseau privé (par exemple 192.168.0.0) derrière l'unique adresse officielle attribuée par le fournisseur d'accès, et d'assurer un minimum de sécurité sur la totalité de l'installation.

Initialisation des tables

Pour commencer, nous allons tout fermer au niveau de la passerelle dans la table filter.

Nous vidons les chaînes :

iptables -F

Nous supprimons d'éventuelles chaînes personnelles :

iptables -X 

Nous les faisons pointer par défaut sur DROP

iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

Nous faisons de même avec toutes les autres tables, à savoir nat et mangle, mais en les faisant pointer par défaut sur ACCEPT. Ca ne pose pas de problèmes puisque tout est bloqué au niveau filter :

iptables -t nat -F
iptables -t nat -X
iptables -t nat -P PREROUTING ACCEPT
iptables -t nat -P POSTROUTING ACCEPT
iptables -t nat -P OUTPUT ACCEPT
iptables -t mangle -F
iptables -t mangle -X
iptables -t mangle -P PREROUTING ACCEPT
iptables -t mangle -P INPUT ACCEPT
iptables -t mangle -P OUTPUT ACCEPT
iptables -t mangle -P FORWARD ACCEPT
iptables -t mangle -P POSTROUTING ACCEPT

Notez que dans tout ça, on n'a pas changé grand chose par rapport à l'état de ces tables tel qu'on le trouve après un boot de la machine, sans modifications particulières des scripts de démarrage, hormis la cible par défaut des règles de la table filter que l'on a passé à DROP. Tout de même, cette manipulation préliminaire a eu pour conséquences :

  • Que l'on est parfaitement sûr de l'état de Netfilter,
  • Que l'on a commencé à se familiariser un peu avec le langage IPtables.

Où en sommes-nous ?

Normalement, plus rien ne doit passer nulle part. Essayez des pings dans tous les sens, entre la passerelle et votre réseau privé ou vers le Net, entre un poste de votre réseau privé et la passerelle, rien ne devrait passer.

Ouvrons quelques portes

Nous considérons que la machine elle même est sûre et que les processus locaux peuvent communiquer entre eux via l'interface locale :

iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

Nous considérons que notre réseau local est également sûr (ce qui n'est pas forcément vrai, d'ailleurs).

iptables -A INPUT -i eth0 -j ACCEPT
iptables -A OUTPUT -o eth0 -j ACCEPT

A ce stade, nous avons la situation suivante :

  • Si, sur votre passerelle, vous faites ping 127.0.0.1, ça répond,
  • si, sur votre passerelle, vous faites un ping sur un hôte du réseau privé, ça répond,
  • si, sur un hôte du réseau privé, vous faites un ping sur la passerelle, ça répond aussi.

Mais…

  • Si, depuis la passerelle, on fait des pings n'importe où sur le Net, ça ne répondra pas, à cause du DROP sur OUTPUT par défaut,
  • si, depuis n'importe où sur le Net, on fait des pings sur votre passerelle, ça ne répondra pas non plus, à cause du DROP sur INPUT par défaut,
  • si, depuis un hôte de votre réseau, on fait un ping n'importe où sur le Net, ça ne répondra encore pas, pour deux raisons :
    • Nous n'avons pas placé de règle de NAT entre le réseau local et le Net,
    • FORWARD fait DROP sur tout ce qui passe.

Faisons maintenant du NAT :

Translation d'adresses pour tout ce qui traverse la passerelle en sortant par ppp0

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

Nous pourrions ici restreindre le NAT à une plage d'IPs du réseau local :

iptables -t nat -A POSTROUTING -s 192.168.0.0/255.255.255.0 -o ppp0 -j MASQUERADE

Ou même à une liste d'IP bien définies :

iptables -t nat -A POSTROUTING -s 192.168.0.10 -o ppp0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 192.168.0.11 -o ppp0 -j MASQUERADE

Ceci peut être utile, surtout en sachant que vous pouvez détruire une règle et une seule :

iptables -t nat -D POSTROUTING -s 192.168.0.11 -o ppp0 -j MASQUERADE

Ainsi, si vous avez, par exemple, des enfants qui usent de votre connexion permanente de façon un peu trop permanente, vous pourrez aisément, avec l'aide du démon cron n'accorder l'accès au Net que pour certaines plages horaires.

Mais ça ne suffit pas encore pour fonctionner, les pings depuis le réseau local vers le Net ne passent toujours pas. Normal, FORWARD fait toujours DROP sur tout ce qui passe. Nous devons accorder des autorisations de passage sur FORWARD.

Utilisation de « conntrack »

Mur pare-feu Le suivi de connexion est intéressant, bien qu'il consomme un peu plus de ressources sur votre passerelle. Nous l'avons vu, son avantage est qu'il permet d'obtenir des informations sur toute connexion en cours. Ces informations sont principalement :

  • NEW
    Une nouvelle connexion est établie ;
  • ESTABLISHED
    La connexion analysée a déjà été établie ;
  • RELATED
    La connexion est en relation avec une autre connexion déjà établie (par exemple, dans le FTP actif) ;
  • INVALID
    Le paquet n'appartient à aucune des trois catégories précédentes. Il est possible, par exemple, de n'accepter dans les deux sens (vers et depuis l'Internet) que les connections déjà établies ou en relation avec des connexions déjà établies et de n'accepter des nouvelles connexions que depuis notre installation vers l'Internet. De cette manière, notre réseau local pourra se connecter sur tout serveur Internet, mais aucune nouvelle connexion ne pourra être créée depuis le Net vers notre installation.

En français, nous allons faire :

  • Toutes les connexions : nouvelles, établies et associées à une connexion établie qui entrent par eth0 (réseau local) et veulent sortir par ppp0 (le Net), peuvent passer,
  • Toutes les connexions : établies et associées à une connexion établie qui entrent par ppp0 et veulent aller vers eth0 pourront également passer.

En langage iptables : Toutes les connexions qui sortent du LAN vers le Net sont acceptées

iptables -A FORWARD -i eth0 -o ppp0 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

Nous aurions aussi bien pu écrire :

iptables -A FORWARD -i eth0 -o ppp0 -m state ! --state INVALID -j ACCEPT

Seules les connexions déjà établies ou en relation avec des connexions établies sont acceptées venant du Net vers le LAN

iptables -A FORWARD -i ppp0 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

irp.nain-t.net (par exemple) se met à fonctionner.

Le chapeau magique

Maintenant que nous avons mis conntrack en œuvre, nous aimerions bien voir un peu comment il opère… Il se trouve qu'il est possible d'observer la table de suivi de connexions qui se présente sous la forme d'un fichier virtuel en /proc/net/ip_conntrack.

Pour interpréter plus facilement ce qu'il suit, il faut savoir plusieurs choses :

  • Un client du LAN dispose de l'IP 192.168.0.10,
  • la passerelle dispose de l'IP 192.168.0.253 sur le LAN
  • la passerelle dispose de l'IP 80.8.130.97 sur le Net
  • le client navigue sur le serveur HTTP d'IP 213.186.35.33
tcp 6 14 CLOSE_WAIT 
            src=192.168.0.10 dst=213.186.35.33 sport=1102 dport=80 
            src=213.186.35.33 dst=80.8.130.97 sport=80 dport=1102 [ASSURED] use=1 

tcp 6 431991 ESTABLISHED 
            src=192.168.0.10 dst=213.186.35.33 sport=1103 dport=80 
            src=213.186.35.33 dst=80.8.130.97 sport=80 dport=1103 [ASSURED] use=1 

tcp 6 73 TIME_WAIT 
            src=192.168.0.10 dst=213.186.35.33 sport=1104 dport=80 
            src=213.186.35.33 dst=80.8.130.97 sport=80 dport=1104 [ASSURED] use=1 

tcp 6 82 SYN_SENT 
            src=192.168.0.10 dst=213.186.35.33 sport=1105 dport=80 [UNREPLIED] 
            src=213.186.35.33 dst=80.8.130.97 sport=80 dport=1105 use=1 

tcp 6 51 CLOSE_WAIT 
            src=192.168.0.10 dst=213.186.35.33 sport=1106 dport=80 
            src=213.186.35.33 dst=80.8.130.97 sport=80 dport=1106 [ASSURED] use=1

Le troisième champ est un « timer », l'entrée est effacée de la table lorsque le timer tombe à zéro. Bien entendu, cette table est en mémoire, ce n'est pas un vrai fichier, son contenu évolue donc perpétuellement au cours du temps.

  • Vous ne pourrez pas visualiser efficacement son contenu avec l'outil tail ;
  • cette table prend de la place en mémoire, d'autant plus que le nombre de clients sur le LAN est important et leur activité grande. Sur un petit réseau domestique, ce sera rarement un problème, mais sur un réseau d'entreprise, il faudra rester attentif à la mémoire disponible.

Où en somme nous ?

  • Depuis le réseau local, nous accédons à la passerelle,
  • depuis le réseau local, nous accédons au Net,
  • depuis la passerelle, nous accédons au réseau local,
  • depuis la passerelle, nous n'accédons pas au Net
  • depuis le Net, nous n'accédons pas à la passerelle (nous avons toujours un DROP en INPUT sur ppp0)
  • depuis le net, nous ne pouvons accéder aux hôtes du réseau local que sur des connexions qu'ils ont établies et dont ils sont clients. Autrement dit, aucun serveur, éventuellement placé sur le réseau local ne sera accessible depuis le Net

Amélioration possibles

Un DNS local

Si vous installez sur votre passerelle un serveur DNS, il faudra qu'il puisse envoyer ses requêtes sur le Net, ce qui n'est actuellement pas possible. Il faut ouvrir une voie en UDP conforme aux besoins d'une requête DNS :

  • Votre serveur envoie une requête UDP à destination du port 53 d'un serveur DNS
  • il attend une réponse sur un port supérieur ou égal à 1025, venant d'un port 53.

En langage IPtables :

Autorisation des requêtes DNS locales

iptables -A OUTPUT -o ppp0 -p udp --sport 1024: --dport 53 -m state --state ! INVALID -j ACCEPT
iptables -A INPUT -i ppp0 -p udp --sport 53 --dport 1024: -m state --state RELATED,ESTABLISHED -j ACCEPT

Voilà des syntaxes qui commencent à être sympathiques…

Lorsque l'on veut définir, non pas un port mais une plage de ports, les écritures suivantes sont autorisées :

  • –dport 1024:1999 autorisera la plage de ports [1024,1999] en destination (ça marche aussi avec –sport) ;
  • –dport 1024: veut dire que tous les ports supérieurs où égaux à 1024 seront acceptés en destination.

Un SMTP local

Vous pouvez désirer implanter un SMTP sur votre passerelle, pour envoyer votre courrier depuis le LAN sans vous préoccuper des disponibilités ou des lenteurs du SMTP de votre FAI. Voir le chapitre SMTP à ce sujet.

Deux options sont possibles :

  • Votre SMTP enverra vos courriers directement aux destinataires,
  • votre SMTP enverra tous vos courriers au SMTP de votre FAI qui effectuera lui-mêmes les livraisons.

La première option est la plus rapide. Malheureusement, à cause de nombreux débordements, la tendance actuelle consiste à refuser les messages provenant de serveurs SMTP non officiels, ce fut un temps par exemple le cas entre Wanadoo et AOL. AOL refusait tout message en provenance de wanadoo.fr autre que ceux qui lui arrivent des SMTP officiels de wanadoo. Comme il est clair que cette tendance n'ira qu'en s'accentuant, il demeure plus sage d'utiliser la seconde méthode. Vous serez tributaire du bon fonctionnement du SMTP de votre FAI, mais ça ne se verra pas au niveau de vos clients du LAN. Ce sera votre SMTP local qui assurera les éventuelles attentes.

Sachant qu'un serveur SMTP écoute sur le port 25 et utilise tcp :

Autorisation des envois SMTP locaux

iptables -A OUTPUT -o ppp0 -p tcp --sport 1024: --dport 25 -m state --state ! INVALID -j ACCEPT
iptables -A INPUT -i ppp0 -p tcp --sport 25 --dport 1024: -m state --state RELATED,ESTABLISHED -j ACCEPT

Et vous pouvez même restreindre encore d'avantage, si vous avez adopté la seconde stratégie d'envoi :

Autorisation des envois SMTP locaux vers le SMTP du FAI

iptables -A OUTPUT -o ppp0 -p tcp --sport 1024: -d smtp.wanadoo.fr --dport 25 -m state --state ! INVALID -j ACCEPT
iptables -A INPUT -i ppp0 -p tcp -s smtp.wanadoo.fr --sport 25 --dport 1024: -m state --state RELATED,ESTABLISHED -j ACCEPT

Si, si, ça fonctionne, à condition bien entendu que votre passerelle soit en mesure de résoudre les noms au moment où vous écrivez la règle. Attention donc, si vous faites tout ça lors de l'initialisation de la machine, il faudra que :

  • Les services réseaux soient montés,
  • la connexion PPPoE établie,
  • le service DNS démarré.

Vous pouvez, plus simplement, indiquer non pas le nom du serveur mais son IP.

Un accès SSH depuis le Net

Vous pouvez souhaiter pouvoir accéder à votre passerelle depuis le Net, pour peu que vous ayez un moyen de connaître à tout moment son adresse IP. Sachant que ssh utilise tcp sur le port 22 :

iptables -A INPUT -p tcp --dport ssh -i ppp0 -j ACCEPT
iptables -A OUTPUT -p tcp --sport ssh -o ppp0 -j ACCEPT

Nous pouvons effectivement définir un port par le service qui lui est normalement associé (ici ssh).

Si vous devez accéder à votre passerelle depuis une IP fixe sur le Net, vous pouvez largement restreindre cette règle en n'acceptant les connexions ssh que depuis et vers cette IP.

ICMP, c'est parfois utile

Le protocole ICMP, même s'il présente quelques dangers, rend tout de même quelques services appréciables, dans le cas d'erreurs de transmission et aussi dans la découverte du MTU.  Pour plus de détails, voyez le chapitre « TCP/IP(v4) ».

Il se trouve que, pour les messages d'erreur ICMP, l'en-tête du paquet qui a généré l'erreur est reproduite dans le message. Le suivi de connexion ICMP s'en sert pour déclarer ce paquet RELATED.

En ce qui concerne les clients du LAN, avec les règles que nous avons écrites, il ne devrait pas y avoir de problèmes, puis qu'on laisse passer tout paquet RELATED sans distinction de protocole.

En revanche, pour la passerelle elle-même,  si l'on a activé SMTP et DNS, il peut s'avérer intéressant d'ajouter la ligne :

iptables -A INPUT -p icmp  -m state --state RELATED -j ACCEPT

De cette manière, une erreur ICMP passera, mais votre passerelle ne répondra pas aux pings, ni à aucune autre interrogation ICMP.

Encore une dernière recette

Vous pouvez faire quelque chose de très simple, mais qui reste tout de même moins sûr. Nous sommes dans la table Filter (table par défaut).

Vidage des chaînes

iptables -F

Destruction des éventuelles chaînes personnelles :

iptables -X

Changement de stratégie par défaut: Nous n'acceptons plus rien

  • ni en entrée
  • ni en traversée de la passerelle

Mais nous acceptons tout ce qui sort (localement) de la passerelle :

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

Initialisation des tables NAT et MANGLE :

iptables -t nat -F
iptables -t nat -X
iptables -t nat -P PREROUTING ACCEPT
iptables -t nat -P POSTROUTING ACCEPT
iptables -t nat -P OUTPUT ACCEPT
iptables -t mangle -F
iptables -t mangle -X
iptables -t mangle -P PREROUTING ACCEPT
iptables -t mangle -P OUTPUT ACCEPT

Mise en place du NAT :

iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o ppp0 -j MASQUERADE

Maintenant, nous allons créer une chaîne particulière, que nous allons appeler SuiviConnexions et qui va gérer ce suivi :

iptables -N SuiviConnexions

Filtrage de suivi dans cette chaîne : Seules les nouvelles connexions qui ne viennent pas du Net sont acceptées :

iptables -A SuiviConnexions -m state --state NEW -i ! ppp0 -j ACCEPT

Ceci veut dire plus clairement que toutes les connexions qui n'entrent pas par ppp0 c'est à dire dans notre cas, qui entrent par eth0, mais aussi par l'interface locale (lo).

Toutes les connexions établies et relatives sont acceptées :

iptables -A SuiviConnexions -m state --state ESTABLISHED,RELATED -j ACCEPT

Cette chaîne va maintenant servir de cible commune pour les deux chaînes standard INPUT et FORWARD, les deux chaînes INPUT et FORWARD vont pointer sur SuiviConnexions :

iptables -A INPUT -j SuiviConnexions
iptables -A FORWARD -j SuiviConnexions

Et le tour est joué, puisque OUTPUT accepte tout. Il faut faire beaucoup confiance au bon fonctionnement de conntrack et ne pas trop se poser de questions sur les coups tordus qui peuvent arriver à passer quand même là dedans, mais au premier coup d'oeil, votre machine paraîtra invisible sur le Net.

Enfin, pour ssh :

iptables -A INPUT -p tcp --dport ssh -j ACCEPT

Le FTP actif

Très souvent, les clients du LAN derrière un routeur NAT ne peuvent accéder à des serveurs FTP sur le Net qu'en mode passif. Sans précautions particulières, ce sera également le cas ici.

Cependant, Netfilter permet de s'affranchir de cette limitation, en exploitant les modules spécialisés, nf_nat_ftp et nf_conntrack_ftp. Ceci nous amène à dire quelques mots du chargement de ces modules, à propos desquels nous ne nous sommes pas beaucoup posé de questions.

Netfilter est capable de charger dynamiquement la plupart des modules qui lui sont nécessaires, en fonction des règles écrites. Faites un lsmod et voyez les modules impliqués dans Netfilter (ils sont tous dans /lib/modules/<version du kernel utilisé>/kernel/net/ipv4/netfilter et dans /lib/modules/<version du kernel utilisé>/kernel/net/netfilter).

Cependant, les modules nécessaires au FTP actif ne se chargent pas automatiquement. Vous pourrez les monter avec modprobe pour faire les tests. Si vous voulez les rendre automatiquement disponibles à chaque démarrage, référencez-les par exemple dans le fichier /etc/modules.

Pour conserver tout ce beau travail

C'est le moment d'utiliser un outil fourni avec iptables : le script iptables-save. Ce script envoie sur le flux de sortie par défaut, normalement l'écran, le contenu des chaînes de toutes les tables, dans un format relativement lisible pour l'être humain :

# iptables-save

# Generated by iptables-save v1.2.6a on Mon Dec  2 18:22:31 2002
*mangle
:PREROUTING ACCEPT [4110:906437]
:INPUT ACCEPT [113562:22595477]
:FORWARD ACCEPT [2160:709057]
:OUTPUT ACCEPT [2308:208513]
:POSTROUTING ACCEPT [68746:14733820]
COMMIT
# Completed on Mon Dec  2 18:22:31 2002
# Generated by iptables-save v1.2.6a on Mon Dec  2 18:22:31 2002
*filter
:INPUT DROP [392:38736]
:FORWARD DROP [20:944]
:OUTPUT DROP [616:25100]
-A INPUT -i lo -j ACCEPT 
-A INPUT -i eth0 -j ACCEPT 
-A FORWARD -i eth0 -o ppp0 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT 
-A FORWARD -i ppp0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT 
-A OUTPUT -o lo -j ACCEPT 
-A OUTPUT -o eth0 -j ACCEPT 
COMMIT
# Completed on Mon Dec  2 18:22:31 2002
# Generated by iptables-save v1.2.6a on Mon Dec  2 18:22:31 2002
*nat
:PREROUTING ACCEPT [781:63004]
:POSTROUTING ACCEPT [331:18116]
:OUTPUT ACCEPT [1028:49802]
-A POSTROUTING -o ppp0 -j MASQUERADE 
COMMIT
# Completed on Mon Dec  2 18:22:31 2002

Nous retrouvons bien là dedans tout ce que nous avons défini plus haut. Mais cette commande a un autre avantage. En dirigeant sa sortie vers un fichier, vous obtenez un fichier de configuration qui sera exploitable par un autre script : iptables-restore

En d'autres termes, si vous faites :

iptables-save  > /root/maconfig.iptables

vous pourrez refaire ensuite :

iptables-restore < /root/maconfig.iptables

Pour restaurer intégralement votre configuration.

Sur Debian, il est possible d'invoquer des commandes lors de l'activation et de la désactivation d'une interface réseau, dans le fichier /etc/network/interfaces. Voyez le chapitre « Partage de connexion » et plus particulièrement la page « Passerelle simple » pour plus de détails.

Conclusions

Beaucoup de choses n'ont pas été dites, Netfilter nécessiterait un livre entier. Parmi ce dont nous n'avons pas parlé et qui peut s'avérer utile, même pour un réseau domestique :

  • Comment placer, par exemple, un serveur HTTP sur le LAN et s'arranger pour qu'il soit visible depuis le Net ? C'est possible en utilisant du NAT de destination (PREROUTING). Je vous laisse chercher…
  • Nous n'avons que survolé l'utilisation de la cible LOG, pour tracer des paquets indésirables, ou simplement pour déverminer des règles qui ne fonctionnent pas comme on le souhaiterait. La cible LOG est un peu spéciale, dans la mesure où elle n'affecte pas la destination du paquet tracé. Ainsi, vous devrez écrire des règles pour les logs en plus de votre filtrage et de votre NAT.
  • L'utilisation de la table mangle conjointement avec le QoS pour exploiter au mieux votre bande passante.

Je ne suis pas un expert en sécurité. Ne comptez pas sur moi pour vous donner toutes les ficelles de sécurisation de votre installation. D'ailleurs, rien n'est définitif dans ce domaine.

D'autres sources d'informations

Reprenons quelques liens qui vous en apprendront d'avantage :

Et probablement beaucoup d'autres que je ne connais même pas.