Iptables
IpTables par l'exemple
Contact : chez apinc point org duracell chez apinc point org
révision par Jice <chez lea-linux point org jice chez lea-linux point org>
révision par Fred <chez lea-linux point org fred chez lea-linux point org>
Introduction
Cet article présente de façon pratique la mise en place d'un firewall / proxy sur une machine Linux tournant avec un noyau 2.4.
Pour des informations plus théoriques sur les firewall/proxies, vous pouvez lire l'article firewall.
* Présentation d'IpTables
IpTables est une solution complète de firewall (noyau 2.4) remplaçant ipchains (noyau 2.2) tournant sous le système GNU/Linux. IpTables permet de faire du firewalling stateful (à états), de la translation de port et d'adresse, du filtrage au niveau 2 et beaucoup d'autres choses que nous n'allons pas aborder comme le "Mangle" ou modification des paquets à la volée (atchoum).
IpTables est fiable et dispose de très nombreuses options qui permettent de faire du filtrage très fin.
* Licence de cet article
Cette documentation est sous licence LDP
* Licence de NetFilter
NetFilter est sous licence libre GPL, i.e. gratuit et modifiable du moment que les modifications et améliorations apportées soit rendues publiques.
1/ Installation
1.1/ Prérequis
IpTables est installé en standard sur de nombreuses distributions Linux récentes. En particulier, il est installé sur Linux RedHat 7.1 et sur la plupart des distributions basées sur un kernel 2.4.x.
IpTables a besoin d'un kernel de génération 2.4 compilé avec des options spéciales. Ceci ne pose pas de problèmes avec les noyaux 2.4 génériques des principales distributions basées sur cette génération de kernel.
1.2/ Options de compilation du kernel
Si vous désirez re-compiler votre kernel, il faut spécifier les options nécessaires au fonctionnement d'iptables.
Les options suivantes doivent êtres activées en module (M) ou dans le kernel (Y) :
CONFIG_PACKET
CONFIG_NETFILTER
CONFIG_IP_NF_CONNTRACK
CONFIG_IP_NF_FTP
CONFIG_IP_NF_IRC
CONFIG_IP_NF_IPTABLES
CONFIG_IP_NF_FILTER
CONFIG_IP_NF_NAT
CONFIG_IP_NF_MATCH_STATE
CONFIG_IP_NF_TARGET_LOG
CONFIG_IP_NF_MATCH_LIMIT
CONFIG_IP_NF_TARGET_MASQUERADE
et éventuellement :
CONFIG_IP_NF_COMPAT_IPCHAINS pour garder la compatibilité avec ipchains.
CONFIG_IP_NF_COMPAT_IPFWADM pour garder la compatibilité avec ipfwadm.
CONFIG_IP_NF_TARGET_REDIRECT indispensable, pour les proxies transparents par exemple.
CONFIG_IP_NF_MATCH_MAC permet de matcher avec les adresses MAC.
Ne pas oublier le support réseau et TCP/IP et compiler le kernel comme d'habitude :
make dep && make clean && make bzImage && make modules && make modules_install
1.3/ Installation
Sur une RedHat 7.1, récupérer le package netfilter et l'installer comme d'habitude avec rpm -Uvh netfilter-x.y.z.rpm.
Sur les versions inférieures a la 7.1, il faut compiler un kernel 2.4 car iptables ne supporte pas les kernels 2.2.x. La compilation de iptables est complexe. Le mieux est de lire le fichier INSTALL du package des sources.
1.4/ Chargement des modules
Dans le cas ou les options iptables du kernel ont étés compilées en modules, il est nécessaire de charger ces modules avant de pouvoir utiliser iptables :
# modprobe ip_tables
selon les besoins, on peut éventuellement charger les modules suivants :
# modprobe ip_nat_ftp
# modprobe ip_nat_irc
# modprobe iptable_filter
# modprobe iptable_mangle
# modprobe iptable_nat
Si on a besoin de pouvoir rediriger (forward) les paquets IP arrivant sur un interface réseau (connectée par exemple à Internet) vers une autre interface réseau (connectée par exemple au réseau local), il sera nécessaire, dans la plupart des cas, d'exécuter cette commande :
# echo 1 > /proc/sys/net/ipv4/ip_forward
afin de l'indiquer au noyau.
Nota Bene : tous les modprobe semblent inutiles car le kernel les chargent automatiquement si l'on se sert de l'une des fonctionnalités d'iptables.
2/ Présentation
2.1/ Les tables
- Table NAT (Network Address Translation) : Table utilisée pour la translation d'adresse ou la translation de port.
Il a 2 types de chaînes# : PREROUTING qui permet de spécifier "à l'arrivée du firewall" et la chaîne POSTROUTING qui permet de spécifier "à la sortie du firewall". Il existe 3 targets (ou cibles) : DNAT*, SNAT* et MASQUERADE*. - Table FILTER : C'est la table par défaut lorsque l'on en spécifie pas.
Cette table contient toutes les règles de filtrage, il existe 3 types de chaînes : FORWARD pour les paquets passant par le firewall, INPUT pour les paquets entrant et OUTPUT pour les paquets sortants. Les cibles disponibles sont : ACCEPT, DENY, DROP, REJECT °. - Table Mangle : C'est la table qui contient les règles pour la modification de paquets.
Elle est peu utilisée et ne sera pas décrite dans cet article.
A noter : Les règles sont évaluées dans l'ordre, par défaut la table FILTER est vide et donc accepte tout. Aucune règle de translation d'adresse n'est présente par défaut.
- # chaîne
- une chaîne est une suite de règles, qui sont prises dans l'ordre ; dès qu'une règle matche un paquet, elle est déclenchée, et la suite de la chaîne est ignorée.
- * SNAT
- permet de modifier l'adresse source du paquet.
- * DNAT
- permet de modifier l'adresse destination du paquet.
- * MASQUERADE
- Une gateway transforme les paquets sortants passant par elle pour donner l'illusion qu'ils sortent de la gateway elle-même par un port alloué dynamiquement ; lorsque la gateway recoit une réponse sur ce port, elle utilise une table de correspondance entre le port et les machines du réseau privé qu'elle gère pour lui faire suivre le paquet.
- ° policy ACCEPT
- permet d'accepter un paquet grâce à la règle vérifiée.
- ° policy DROP
- Rejet d'un paquet sans message d'erreur si la règle est vérifiée ("non ! j'en veux pas mais je dis rien à l'expediteur").
- ° policy REJECT
- Rejet avec un retour de paquet d'erreur à l'expediteur si la la règle est verifiée ("un paquet recommandé de La Poste refusé par son destinataire").
2.2/ Les commandes
IpTables n'est pas livré avec une interface graphique ; les commandes et les règles sont passées en ligne de commande. Le mieux est d'écrire des scripts (à rajouter dans /etc/rc.d/init.d) qui permettent d'appliquer toutes les règles d'un seul coup, dès le démarrage du Linux.
2.2.1/ Commandes principales
-A --append : Ajoute la règle à la fin de la chaîne spécifiée
Exemple :
# iptables -A INPUT ...
-D --delete : Permet de supprimer une chaîne. On peut la matcher de 2 manières, soit en spécifiant le numéros de la chaîne a supprimer, soit en
spécifiant la règle à retirer.
Exemples :
# iptables -D INPUT --dport 80 -j DROP
# iptables -D INPUT 1
-R --replace : Permet contrairement à --delete de remplacer la chaîne spécifiée.
Exemple :
# iptables -R INPUT 1 -s 192.168.0.1 -j DROP
-I --insert : Permet d'ajouter une chaîne dans un endroit spécifié de la chaîne.
Exemple :
# iptables -I INPUT 1 --dport 80 -j ACCEPT
-L --list : Permet d'afficher les règles.
Exemples :
# iptables -L # Affiche toutes les règles des chaînes de FILTER
# iptables -L INPUT # Affiche toutes les règles de INPUT (FILTER)
-F --flush : Permet de vider toutes les règles d'une chaîne.
Exemple :
# iptables -F INPUT
-N --new-chain : Permet de créer une nouvelle chaîne.
Exemple :
# iptables -N LOG_DROP
-X --delete-chain : Permet d'effacer une chaîne.
Exemple :
# iptables -X LOG_DROP
-P --policy : Permet de spécifier au kernel la target par défaut d'une chaîne DENY, ACCEPT, REJECT, DROP ...
Exemple :
# iptables -P INPUT DROP
2.2.2/ Commandes pour matcher
Remarques :
Le "!" peut être utilisé pour certaines commandes afin de spécifier le contraire (on peut le traduire par "sauf"). Par exemple une commande qui doit refuser tout trafic TCP sauf ce qui provient de l'adresse IP 10.42.42.42 sera traduite par la commande suivante :
Exemple :
# iptables -A INPUT -p tcp --source ! 10.42.42.42 -j DROP
Les adresses IP peuvent optionnellement être spécifiées avec le masque associé sous la forme [adresse ip]/[masque].
-p --protocol : Spécifier un protocole : tcp, udp, icmp, all (tous)
Exemple :
# iptables -A INPUT -p icmp -j DROP
-s --source : Spécifier une adresse source à matcher
Exemple :
# iptables -A INPUT -p tcp -s 192.168.42.42 -j ACCEPT
-d --destination : Spécifier une adresse destination
Exemple :
# iptables -A FORWARD -p tcp -d 10.1.0.1 -j ACCEPT
-i --in-interface : Spécifier une interface d'entrée
Exemple :
# iptables -A INPUT -p icmp -i eth0 -j DROP
-o --out-interface : Spécifier une interface de sortie
Exemple :
# iptables -A OUTPUT -p icmp -o eth0 -j DROP
-f --fragment : Paquet fragmenté
Exemple :
# iptables -A INPUT -p icmp -f -j DROP
--sport --source-port : Spécifier le port source ou une plage de ports, fonctionne aussi en udp, -m multiport permet de
spécifier plusieurs ports à matcher.
Exemples :
# iptables -A INPUT -p tcp --sport 80 -j ACCEPT
# iptables -A INPUT -p udp --sport 80 -j DROP
# iptables -A OUTPUT -p tcp -m multiport --sport 3128,21,1000 -j DROP
# iptables -A OUTPUT -p tcp --sport 1024:2042 -j ACCEPT
--dport --destination-port : Spécifier le port destination ou une plage de ports, fonctionne aussi en udp, -m multiport
permet de spécifier plusieurs ports a matcher.
Exemples :
# iptables -A INPUT -p tcp --dport 110 -j DROP
# iptables -A INPUT -p udp --dport 110 -j DROP
# iptables -A INPUT -p tcp -m multiport --dport 110,4242,119 -j DROP
# iptables -A INPUT -p tcp --sport 4925:4633 -j ACCEPT
--tcp-flags : Spécifier un flag tcp à matcher : SYN ACK FIN RST URG PSH ALL NONE
Exemple :
# iptables -A INPUT -p tcp --dport 42 --tcp-flags SYN,ACK -j ACCEPT
--icmp-type : Spécifier un type de paquet icmp à matcher
Exemple :
# iptables -A INPUT -p icmp --icmp-type 8 -j DROP
--mac-source : Spécifier l'adresse MAC à matcher
Exemple :
# iptables -A INPUT --mac-source 42.42.AA.42.42.AA -j DROP
--state : Permet de spécifier l'état du paquet à matcher parmi les états suivants :
ESTABLISHED : paquet associé à une connexion déjà établie
NEW : paquet demandant une nouvelle connexion
INVALID : paquet associé à une connexion inconnue
RELATED : Nouvelle connexion mais liée, idéal pour les connexions FTP
Exemples :
# iptables -A INPUT -i eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -A OUTPUT -o eth0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT
Spécificités NAT :
--to-destination : Utilisé en target pour le DNAT, permet de spécifier l'adresse de destination de la translation, on peut également spécifier un port s'il est différent du port source.
Exemples :
# iptables -t nat -A PREROUTING -d 42.12.42.12 -p tcp --dport 110 -j DNAT --to-destination 192.168.1.2:6110
# iptables -t nat -A PREROUTING -d ! 42.12.42.12 -p tcp --dport 80 -j DNAT --to-destination 192.168.2.1:3128
--to-source : Utilisé pour en target pour le SNAT, permet de spécifier l'adresse source de la translation.
Spécificités pour les LOGS :
--log-level : Level, niveau de log
Exemple : Cf. chapitre 3
--log-prefix : Permet de spécifier un préfixe pour les logs.
Exemple : Cf. chapitre 3
2.2.3/ Quelques exemples :
Les exemples qui suivent supposent que vous êtes reliés à internet par modem via l'interface ppp0 (mais en remplaçant ppp0 par eth0 - par exemple, on peut adapter les exemples pour d'autres type de liaisons) et que votre réseau local est 192.168.1.0/24 (classe C).
- Pour fixer les politiques par défaut (cad: ce qui se passe quand aucune règle ne correspond - ne matche pas), ici, on refuse tout (normal, on fait un firewall, oui ou non ?) :
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP - Pour logguer tout ce qu'on jette :
Et ensuite, plutôt que de mettre -j DROP, il faut mettre -j LOG_DROP et les trois dernières règles doivent être :iptables -N LOG_DROP
iptables -A LOG_DROP -j LOG --log-prefix '[IPTABLES DROP] : '
iptables -A LOG_DROP -j DROPiptables -A FORWARD -j LOG_DROP
iptables -A INPUT -j LOG_DROP
iptables -A OUTPUT -j LOG_DROP - Pour accepter tout ce qui se passe sur l'interface lo (sinon ce n'est pas la peine d'activer le réseau !) :
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT - Pour accepter tout ce qui se passe sur le réseau local 192.168.1.0 :
iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT
iptables -A OUTPUT -d 192.168.1.0/24 -j ACCEPT
iptables -A FORWARD -s 192.168.1.0/24 -j ACCEPT - Pour accepter les résolutions de nom (ie: le dns) :
iptables -A INPUT -i ppp0 --protocol udp --source-port 53 -j ACCEPT
iptables -A OUTPUT -o ppp0 --protocol udp --destination-port 53 -j ACCEPT
iptables -A INPUT -i ppp0 --protocol tcp --source-port 53 -j ACCEPT
iptables -A OUTPUT -o ppp0 --protocol tcp --destination-port 53 -j ACCEPT - Pour accepter le traffic web (on veut surfer!) :
La première ligne pour accepter ce qui entre sur notre interface ppp0 sur le port 80 (le port http) si c'est une connexion déjà établie, la seconde pour accepter ce qui sort sur ppp0 sur le port 80 si c'est une nouvelle connexion ou si c'est une connexion déjà établie.iptables -A INPUT -i ppp0 --protocol tcp --source-port 80 -m state --state ESTABLISHED -j LOG_ACCEPT
iptables -A OUTPUT -o ppp0 --protocol tcp --destination-port 80 -m state --state NEW,ESTABLISHED -j LOG_ACCEPT
Pour autoriser le ssh, il faut préciser le port 22; pour autoriser l'irc, le port 6667 (ou celui que vous utilisez pour vous connecter à votre serveur); pour le smtp (envoi d'emails), le port 25; pour le pop3 (réception d'emails), le port 110; pour le imap (réception d'emails), les ports 143 et 220 (imap3) ; pour le cvs, le port 2401 ; pour le https, le port 443. De manière générale, le numéros de port se trouvent dans /etc/services.
- Pour le ftp c'est un peu plus complexe. D'abord, il faut charger le module : ip_conntrack_ftp (c'est lui qui suit - track en anglais - les connexions ftp) et, si vous natez (en utilisant le masquerading par exemple) vos connexions ftp vers d'autres postes le module : ip_nat_ftp :
Ensuite, il faut taper les commandes suivantes :modprobe ip_conntrack_ftp
# éventuellement : modprobe ip_nat_ftp
Cela pour que la connexion puisse s'établir. Ensuite (et c'est la qu'on a besoin de ip_conntrack_ftp) :iptables -A INPUT -i ppp0 -p tcp --sport 21 -m state --state ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o ppp0 -p tcp --dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT
Pour que serveur puisse établir la connexion pour les données (en mode actif). Et enfin :iptables -A INPUT -i ppp0 -p tcp --sport 20 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -o ppp0 -p tcp --dport 20 -m state --state ESTABLISHED -j ACCEPT
Pour que le serveur puisse établir la connexion pour les données (en mode passif). Ici aussi ip_conntrack_ftp est nécessaire.iptables -A INPUT -i ppp0 -p tcp --sport 1024:65535 --dport 1024:65535 -m state --state ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o ppp0 -p tcp --sport 1024:65535 --dport 1024:65535 -m state --state ESTABLISHED,RELATED -j ACCEPT - Pour partager une connexion, il faut que le forwarding soit activé dans le noyau (echo 1 > /proc/sys/net/ipv4/ip_forward), puis il faut autoriser iptable à faire le forwarding :
et enfin, cacher les machines forward-ées par le firewall :iptables -F FORWARD
iptables -A FORWARD -j ACCEPT
Sur chaque machine devant être cachée par le firewall (ou devant partager la connexion avec la machine qui est connectée à internet), il faut ajouter une route par defaut :iptables -A POSTROUTING -t nat -o ppp0 -j MASQUERADE
Si la machine connectée à internet a comme ip : 192.168.1.1. Il suffit avec une redhat/mandrake d'éditer :route add default gw 192.168.1.1
et d'ajouter dedans :/etc/sysconfig/network
puis de redémarer le réseau :GATEWAY=192.168.1.1
/etc/rc.d/init.d/network restart
3/ Application par l'exemple
Nous allons mettre en place un firewall / proxy.
Pour cet exemple, le firewall aura la connexion à Internet (interface eth2) et disposera de 2 pattes sur des réseaux privés (eth0 et eth1) :
- il fait office de proxy sur le port 3128 pour un réseau qui aura ainsi un accès internet
- et une DMZ* ("zone démilitarisée") sur laquelle il y a un ensemble de serveurs disponibles de l'extérieur dont un serveur web qui a pour adresse 192.168.1.2 écoutant sur le port 80 en TCP.
____ eth1 .-> ---+------+------+---
_/ \_ ____ 3128/ [PC1] [PC2] [PC3]
( ) eth2| |<--' réseau local 198.168.2.0
(INTERNET)<--->|Fire|
(_ _) ppp0|wall|
\____/ |____|<--. DMZ serveurs 198.168.1.0
eth0\ [WEB] [NEWS] [FTP]
'-> ---+------+------+---
ASCIIArt (c) Jice
La classe d'adresse IP 192.168.2.0 correspond au réseau interne sur l'interface eth1.
La classe d'adresse IP 192.168.1.0 correspond a la DMZ sur l'interface eth0.
L'interface de la connexion Internet est ppp0 sur l'interface eth2.
- * DMZ, ou zone démilitarisée
- Sous-réseau dans lequel des serveurs accessibles depuis internet sont en adressage privé (classe d'adresse IP réservée comme 192.168.x.x) derrière un firewall.
3.1/ Le script init.d
Nous allons écrire un script qui permettra de charger automatiquement au démarrage de la machine ou sur demande les règles du firewall qui seront stockées dans le fichier /etc/firewall.sh.
Le script de démarrage sera nommé /etc/init.d/firewall. Bien sûr, on n'oubliera pas d'exécuter un chmod +x sur les 2 scripts que nous allons créer au long de ce chapitre.
Go !
Fichier de chargement /etc/init.d/firewall :
#!/bin/bash . /etc/init.d/functions RETVAL=0 # Fonction pour le lancement du firewall # Fonction pour arrêter le firewall (on flush) case $1 in exit |
C'est tout simple non ?
3.2/ Le script pour flusher (vider) les règles
Et maintenant : /etc/flush_iptables.sh.
#!/bin/sh # # # # iptables -X # Message de fin |
Bon, on va enfin commencer les choses sérieuses : le script du firewall :)
3.3/ Les prérequis pour le script du firewall et création des tables pour les logs
Le script sera commenté au fur et à mesure, afin de décrire chaque étape.
#!/bin/sh # script /etc/firewall.sh # Firewall d'exemple a but pédagogique # Activation du forwarding echo 1 > /proc/sys/net/ipv4/ip_forward # Alors la, on va appliquer quelques astuces # Je veux pas de spoofing if [ -e /proc/sys/net/ipv4/conf/all/rp_filter ] # pas de icmp echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all # On va utiliser iptables. Si on l'a compilé en module modprobe ip_tables # on va charger quelques modules supplémentaires pour modprobe ip_nat_ftp # Pour faire bien, on va vider toutes les règles iptables -F # On va rajouter 2 nouvelles chaînes. # La on logue et on refuse le paquet, # ici, on logue et on accepte le paquet, # On veut faire un firewall efficace, iptables -P INPUT DROP # Pour éviter les problèmes, on va tout accepter sur iptables -A INPUT -i lo -j ACCEPT # Bon, la partie initialisation et préparation est iptables -A OUTPUT -o ppp0 -m state \ # Maintenant, on va faire en sorte que le iptables -t nat -A PREROUTING -i eth1 -p tcp \ # Bon, c'est pas trop compliqué ! Maintenant iptables -t nat -A PREROUTING -d 42.42.42.42 \ # C'est bien tout ça ! mais le problème c'est # On va quand même accepter les connexions ssh iptables -A INPUT -i eth1 -s 192.168.2.42 -m state \ # On veut que le LAN connecté à l'interface iptables -A FORWARD -i eth1 -o ppp0 -j ACCEPT # Maintenant on donne le droit au LAN de iptables -A FORWARD -i eth1 -o eth0 -p tcp \ # Maintenant il n'y a plus qu'à dire au firewall iptables -A FORWARD -i ppp0 -o eth0 -p tcp \ # Maintenant il ne reste plus grand chose à faire ! # Il faut permettre à l'ensemble du LAN de dialoguer iptables -t nat -A POSTROUTING \ # Il faut également que le serveur web de la DMZ iptables -t nat -A POSTROUTING \ # Toutes les règles qui n'ont pas passé les iptables -A FORWARD -j LOG_DROP # Pour faire zoli # c'est enfin fini |
Et voilà ! le firewall de compèt' est prêt et fonctionnel.
Ceci était bien évidemment un exemple, vous pouvez dès à présent préparer votre propre firewall personnalisé !
Vous pouvez l'adapter à vos besoins, votre connexion vers internet (par ADSL par exemple), etc.
Copyright
© 12/11/2001 Arnaud de Bermingham
Ce document est publié sous licence Creative Commons Attribution, Partage à l'identique, Contexte non commercial 2.0 : http://creativecommons.org/licenses/by-nc-sa/2.0/fr/ |
Autres ressources
Le partage de connexion facile.
Tester votre firewall là.
Cliquez sur 'ShieldsUP!', puis sur l'un des boutons : 'Test My Shields !" et "Probe My Ports !". Ça vaut pas un bon nmap fait par un ami, mais ça permet de voir ou on en est.