Netfilter et IPtables
09/02/2005
 Christian CALECA 
Liste des cours

iptables

Accueil ] [ Architecture ] [ Conntrack ] [ Filter ] [ NAT ] [ Et le reste ] [ 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. Mandrake 9 montée en passerelle, tel que décrit dans le chapitre "un routeur Linux".

manip 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 :

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 :

Mais...

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

firewall

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 :

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

ping www.grenouille.com (par exemple) se met à fonctionner.

Le chapeau magique

Maintenant que nous avons mis conntrack en oeuvre, 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 :

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.

Où en somme nous ?

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 :

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 :

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 :

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", c'est par exemple le cas actuellement entre Wanadoo et AOL. AOL refuse 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 :

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 :

# Accès SSH depuis le Net
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 sur TCP/IP.

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.

# Table Filter (table par défaut).
#---------------------------------
#Vidage des chaînes 
iptables -F
#Destruction des chaînes "personnelles"
iptables -X

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

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

#Stratégie par défaut: 
#INPUT et FORWARD sont DROP
iptables -P INPUT DROP
iptables -P FORWARD DROP
#OUTPUT est ACCEPT
iptables -P OUTPUT ACCEPT
# Init. 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.

# Création d'une chaîne personnelle: "SuiviConnexions"
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

Ca veut dire, plus clairement, 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

# Et les deux chaînes INPUT et FORWARD pointent 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 :

# Accès SSH depuis le Net
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, ip_nat_ftp et ip_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/2.4.19-16mdk/kernel/net/ipv4/netfilter, pour la Mandrake 9).

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 :

[root@linux root]# 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 :

iptable-restore < /root/maconfig.iptables

Pour restaurer intégralement votre configuration.

A noter, toujours sur les distributions Mandrake, un script de démarrage /etc/init.d/iptables qui permet plusieurs choses :

Vous pouvez donc facilement user de ce script pour sauvegarder vos règles et les restaurer à chaque redémarrage.

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 :

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 :)


Précédente ] [ Accueil ]