====== 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 man (man iptables) * [[http://netfilter.samba.org/unreliable-guides/|Rusty's Remarkably Unreliable Guides]] 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 « [[110masquerade:start]] ». {{:netfilter:masquerade.png?400 |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 » ==== {{:netfilter:firewall1.gif |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 [[../smtp/|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 « [[070tcpip:start]] ». 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///