Iptables bénéficie d'une page de manuel bien détaillée (man iptables
)
si vous avez besoin de détails particuliers. Pour ceux qui sont familiers d'Ipchains,
vous devriez simplement aller voir
Différences entre Iptables et Ipchains car ils sont vraiment similaires.
Différentes choses peuvent être réalisées avec Iptables
.
Pour commencer, travaillons avec les trois chaînes pré-définies INPUT
, OUTPUT
et FORWARD
que vous ne pouvez pas effacer. Et analysons les opérations pour
administrer les chaînes :
Il y a plusieurs manières de manipuler une règle à l'intérieur d'une chaîne :
Iptables peut être utilisé sous forme d'un module, appelé (`iptable_filter.o'), qui devrait
être automatiquement chargé lorsque vous exécutez la commande iptables
. Il peut
également être compilé de façon permanente dans le noyau.
Avant qu'aucune commande n'ait été exécutée (attention : certaines distributions lanceront Iptables dans leurs scripts d'initialisation), il n'y a de règles dans aucune des chaînes pré-définies (`INPUT', `FORWARD' et `OUTPUT'); toutes les chaînes ont une règle par défaut de type ACCEPT. Vous pouvez modifier la règle par défaut de la chaîne FORWARD en spécifiant l'option `forward=0' au module iptable_filter.
C'est le gagne-pain du filtrage de paquets ; manipuler des règles. Dans la plupart des cas, vous utiliserez les commandes d'ajout (-A) et d'effacement (-D). Les autres (-I pour insérer et -R pour remplacer) sont de simples extensions de ces concepts.
Chaque règle spécifie un ensemble de conditions que le paquet doit remplir et ce qui sera fait si le paquet les remplit (une `cible'). Par exemple, vous voudriez détruire tous les paquets ICMP qui proviennent de l'adresse IP 127.0.0.1. Dans ce cas, les conditions sont que le protocole est ICMP et que l'adresse source est 127.0.0.1. Notre cible est de type `DROP'.
127.0.0.1 est l'interface de bouclage (`loopback'), que vous posséderez même si vous n'avez pas de réelle connexion réseau. Vous pouvez utiliser la commande `ping' pour générer de tels paquets. Elle envoie simplement un ICMP de type 8 (echo request) auquel tous les hôtes coopératifs devraient répondre aimablement avec un ICMP de type 0 (echo reply). En cela, il est très utile pour le test.
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.2 ms
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.2/0.2/0.2 ms
# iptables -A INPUT -s 127.0.0.1 -p icmp -j DROP
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
#
Vous pouvez constater que le 1er ping a fonctionné (le `-c 1' signale à ping de n'envoyer qu'un seul paquet).
Ensuite, nous ajoutons (-A) à la chaîne `INPUT', une règle spécifiant que pour les paquets issus de 127.0.0.1 (`-s 127.0.0.1') avec le protocole ICMP (`-p icmp'), nous devons sauter vers la cible DROP (`-j DROP').
Ensuite, nous testons notre règle en utilisant le second ping. Il y aura une pause avant que le programme ne stoppe parce qu'il attendra une réponse qui ne viendra jamais.
Nous pouvons effacer une règle de deux façons. Premièrement, comme nous savons que c'est la seule règle dans la chaîne INPUT, nous pouvons utiliser un effacement par numérotation :
# iptables -D INPUT 1
#
pour effacer la règle numéro 1 dans la chaîne INPUT.
La seconde façon correspond au reflet de la commande -A, mais en substituant -A à -D. C'est pratique quand votre chaîne de règles devient complexe et que vous ne souhaitez pas les compter pour découvrir que c'est la règle 37 que vous voulez supprimer. Dans ce cas, on utiliserait :
# iptables -D INPUT -s 127.0.0.1 -p icmp -j DROP
#
La syntaxe de la commande -D doit avoir exactement les mêmes options
que celles de -A (ou -I, ou -R). S'il y a plusieurs règles identiques
dans la même chaîne, la première seulement sera effacée.
Nous avons vu l'utilisation de `-p' pour spécifier le protocole et de `-s' pour spécifier l'adresse source, mais il y a d'autres options que vous pouvez utiliser pour spécifier les caractéristiques d'un paquet. Ce qui suit en est un inventaire exhaustif.
Les adresses IP source (`-s', `--source' ou `--src') et destination (`-d', `--destination' ou `--dst') peuvent être spécifiées de 4 façons. La plus courante est d'utiliser le nom complet, comme `localhost' ou `www.linuxhq.com'. La seconde façon est de spécifier l'adresse IP comme `127.0.0.1'.
Les troisième et quatrième façons permettent de spécifier un groupe d'adresses IP, comme `199.95.207.0/24' ou `199.95.207.0/255.255.255.0'. Toutes deux spécifient toutes les adresses de 199.95.207.0 à 199.95.207.255 inclus; les chiffres après le `/' précisent la partie signifiante des adresses IP. `/32' ou `/255.255.255.255' correspondent au cas par défaut (soit à toutes les adresses IP). Pour spécifier absolument toutes les adresses IP, `/0' peut être utilisé, comme dans :
[ NOTE: `-s 0/0' est ici redondant. ]
# iptables -A INPUT -s 0/0 -j DROP
#
Ceci est rarement utilisé, puisque l'effet de la commande ci-dessus est le même que de ne pas spécifier du tout l'option `-s'.
De nombreuses options, dont `-s' (ou `--source' ) et `-d' (ou `--destination'), peuvent voir leurs arguments précédés de `!' (indiquant la négation) pour coïncider avec les adresses DIFFÉRENTES de celles indiquées. Par exemple `-s ! localhost' correspond à tout paquet qui ne provient pas de localhost.
Le protocole peut être désigné avec l'option `-p' (ou `--protocol'). Un protocole est soit un nombre (si vous connaissez les valeurs numériques des protocoles IP), soit un nom pour les cas particuliers comme `TCP', `UDP' ou `ICMP'. La casse n'a pas d'importance, donc `tcp' marche aussi bien que `TCP'.
Le nom du protocole peut être préfixé d'un `!' pour l'inverser, comme `-p ! TCP' pour spécifier les paquets qui ne sont pas issus de TCP.
Les options `-i' (ou `--in-interface') et `-o' (ou `--out-interface')
précisent le nom d'une interface à laquelle le paquet doit
correspondre. Une interface représente le dispositif matériel par lequel le paquet
est entré (`-i') ou sortira (`-o'). Grâce à la commande ifconfig
, vous pouvez lister
les interfaces actives (ou `up').
Les paquets traversant la chaîne INPUT
n'ont pas encore
d'interface de sortie, donc toute règle utilisant `-o' dans cette
chaîne ne coïncidera jamais. De la même manière, les paquets traversant la chaîne OUTPUT
n'ont pas d'interface d'entrée, donc toute règle utilisant `-i' dans cette
chaîne ne coïncidera jamais.
Seuls les paquets traversant la chaîne FORWARD
ont à la fois une interface
d'entrée et de sortie.
Il est parfaitement autorisé de spécifier une interface qui n'existe pas à cet instant ;
la règle ne coïncidera pas jusqu'à ce que l'interface soit active (ou `up').
C'est particulièrement utile pour les accès par ligne commutée avec PPP (habituellement l'interface
ppp0
) et ses semblables.
Comme cas particulier, un nom d'interface se terminant par un `+' coïncidera avec
toutes les interfaces qui commencent par ce nom (qu'elles existent déjà ou non).
Par exemple, pour spécifier une règle qui concorde avec toutes les interfaces PPP,
on utilisera l'option -i ppp+
.
Le nom de l'interface peut être précédé par un `!' (avec des espaces autour), pour concorder avec un paquet
qui n'appartient pas à l'interface spécifiée, par exemple -i ! ppp+
.
Parfois, un paquet est trop volumineux pour être transmis en une fois sur la ligne. Quand ça arrive, il est divisé en fragments et envoyé en plusieurs paquets. L'autre extrémité réassemble ces fragments pour reconstruire le paquet entier.
Le problème avec les fragments, c'est que le fragment initial possède l'en-tête complet (IP + TCP, UDP et ICMP) à examiner, mais que les paquets suivants ont seulement un morceau de l'en-tête (IP sans les champs additionnels de protocole). Donc il est impossible de rechercher à l'intérieur des fragments suivants les en-têtes de protocoles (comme c'est fait pour les extensions TCP, UDP et ICMP).
Si vous faîtes du traçage de connexion (ou NAT), alors tous les fragments seront fusionnés avant qu'ils n'atteignent le code de filtrage de paquets, par conséquent vous n'aurez pas à vous soucier des fragments.
Attention, notez également que la chaîne INPUT de la table `filter' (ou toute autre table du `hook' NF_IP_LOCAL_IN) n'est traversée qu'après défragmentation du coeur de la pile IP.
Autrement, il est important de comprendre comment les fragments sont traités
par les règles de filtrage. Toute règle de filtrage qui demande des informations
indisponibles ne concordera pas. Cela signifie que le premier fragment est
traité comme tout autre paquet, mais que le second et les suivants ne le seront pas.
Donc une règle -p TCP --sport www
(qui spécifie le port source `www')
ne coïncidera jamais avec un fragment (autre que le premier fragment).
Il en est de même de la règle inverse -p TCP --sport ! www
.
Cependant, vous pouvez spécifier une règle pour les fragments au-delà du premier, à l'aide de l'option `-f' (ou `--fragment'). Il est aussi valide de spécifier une règle qui ne s'applique pas aux fragments autres que le premier, en faisant précéder `-f' de `!'.
Habituellement, accepter les fragments suivant le premier est considéré comme sûr, parce que le filtrage étant effectif sur le premier fragment, on empêche donc le réassemblage sur la machine cible; mais des bogues ont été trouvés qui permettent de planter des machines simplement en leur envoyant des fragments. Vous êtes prévenus.
Note pour les experts en réseaux : les paquets malformés (les paquets TCP, UDP et ICMP trop courts pour que le code du pare-feu ne puisse lire les ports, le code ICMP ou son type) sont détruits quand de telles combinaisons sont tentées, comme les fragments TCP qui commencent en position 8.
À titre d'exemple, la règle suivante va détruire tous les fragments à destination de 192.168.1.1 :
# iptables -A OUTPUT -f -d 192.168.1.1 -j DROP
#
Iptables
est extensible, ce qui veut dire que
le noyau et le programme Iptables peuvent être étendus pour avoir de nouvelles
fonctionnalités.
Quelques-unes de ces extensions sont normalisées, et d'autres sont plus exotiques. Elles peuvent être réalisées par quiconque et distribuées séparément à la demande d'utilisateurs.
Les extensions du noyau se situent normalement dans le sous-répertoire des modules du noyau comme /lib/modules/2.4.0-test10/kernel/net/ipv4/netfilter. Elles sont chargées à la demande si votre noyau a été compilé avec CONFIG_KMOD, donc vous ne devriez pas avoir à les insérer à la main.
Les extensions au programme Iptables sont des bibliothèques partagées qui se situent généralement dans /usr/local/lib/iptables/, bien qu'une distribution puisse les mettre dans /lib/iptables ou /usr/lib/iptables.
Les extensions sont de deux types : nouvelles correspondances et nouvelles cibles (nous aborderons les nouvelles cibles plus tard). Quelques protocoles offrent aussi de nouveaux tests : pour le moment TCP, UDP et ICMP.
Pour ceux-ci, vous pourrez spécifier de nouveaux tests en ligne de commande après l'option `-p', qui chargera implicitement l'extension. Pour spécifier explicitement de nouveaux tests, utilisez l'option `-m' pour charger l'extension, après quoi, ses options seront disponibles.
Pour obtenir de l'aide sur une extension, utilisez l'option pour la charger (`-p', `-j' ou `-m') suivie de `-h' ou `--help', par exemple :
# iptables -p tcp --help
#
Les extensions de TCP sont automatiquement chargées si `-p tcp' est spécifié. Elles offrent les options suivantes (aucune d'entre-elles ne convient aux fragments).
suivi d'un `!' optionnel, puis 2 chaînes de caractères pour les fanions, vous permet de filtrer sur des fanions TCP spécifiques. La première chaîne correspond au masque : la liste de fanions que vous désirez examiner. La deuxième chaîne précisent lesquels doivent être présents. Par exemple :
# iptables -A INPUT --protocol tcp --tcp-flags ALL SYN,ACK -j DROP
Ceci indique que tous les fanions doivent être examinés (`ALL' est synonyme de `SYN,ACK,FIN,RST,URG,PSH'), mais seulement SYN et ACK doivent être présents. Il y a aussi l'argument `NONE' signifiant aucun fanion.
précédé optionnellement d'un `!', c'est un raccourci pour `--tcp-flags SYN,RST,ACK SYN'.
suivi d'un `!' optionnel, puis soit un port TCP seul ou une plage de ports. Les ports peuvent être des noms, tels qu'ils sont listés dans `/etc/services', ou des nombres. Les plages sont soit 2 noms de ports séparés par `:' (pour exprimer un intervalle), un port suivi d'un `:' (pour exprimer supérieur ou égal à), ou un port précédé de `:' (pour exprimer inférieur ou égal à).
est synonyme de `--source-port'.
et
correspondent aux mêmes options qu'au-dessus, si ce n'est qu'elles spécifient le port de destination au lieu du port de source.
suivi d'un `!' optionnel et d'un nombre, correspond à un paquet avec une option TCP égale à ce nombre. Un paquet qui n'a pas un en-tête TCP complet est automatiquement détruit lors d'une tentative pour examiner ses options TCP.
Il est parfois utile d'autoriser les connexions TCP dans un sens mais pas dans l'autre. Par exemple, vous pourriez vouloir autoriser les connexions vers un serveur WWW externe, mais pas les connexions à partir de ce serveur.
Une approche naïve serait de bloquer les paquets TCP venant du serveur. Malheureusement, les connexions TCP nécessitent des paquets évoluant dans les deux sens pour fonctionner.
La solution est de bloquer seulement les paquets utilisés pour demander une connexion. Ces paquets sont appelés des paquets SYN (d'accord, techniquement, ce sont des paquets avec le fanion SYN et pas de fanions FIN et ACK, mais nous les appelons des paquets SYN pour simplifier). En disqualifiant uniquement ces paquets, nous pouvons stopper les tentatives de connexions.
Le fanion `--syn' est utilisé pour cela : il est valide seulement pour les règles qui spécifient TCP comme protocole. Par exemple, pour spécifier une tentative de connexion à partir de l'adresse 192.168.1.1 :
-p TCP -s 192.168.1.1 --syn
Ce fanion peut être inversé en le faisant précéder de `!', qui signifie alors tous les paquets sauf ceux d'initiation d'une connexion.
Ces extensions sont automatiquement chargées si `-p udp' est spécifié. Elles procurent les options `--source-port', `--sport', `--destination-port' et `--dport' comme explicité ci-dessus pour le protocole TCP.
Cette extension est automatiquement chargée si `-p icmp' est spécifié. Elle ne fournit qu'une seule nouvelle option :
suivi d'un `!' optionnel, puis un nom de type ICMP (par exemple `host-unreachable'), ou un type sous forme numérique (par exemple `3'), ou encore un type et un code numériques séparés par un `/' (par exemple `3/3'). Une liste des types ICMP disponibles est fournie avec `-p icmp --help'.
Les autres extensions du paquetage Netfilter sont des extensions de démonstration qui, une fois installées, peuvent être invoquées avec l'option `-m'.
Ce module doit être spécifié explicitement avec `-m mac' ou `--match mac'. Il est utilisé pour correspondre avec des adresses Ethernet (MAC) de paquets entrants, et il est donc seulement utile pour des paquets traversant les chaînes INPUT et PREROUTING. Il ne propose qu'une seule option :
suivi d'un `!' optionnel, puis d'une adresse Ethernet en octets (notation hexadécimale) séparés par des `:', par exemple `--mac-source 00:60:08:91:CC:B7'.
Ce module doit être spécifié explicitement avec `-m limit' ou `--match limit'. Il est utilisé pour limiter le taux de correspondances, typiquement pour réduire des messages de journalisation (ou `log'). Il prendra en compte les correspondances seulement un certain nombre de fois pas seconde (par défaut, 3 correspondances par heure, avec une réserve de 5). Il possède deux arguments optionnels :
suivi d'un nombre, pour spécifier (en moyenne) le nombre maximum de correspondances acceptées par seconde. On peut spécifier son unité explicitement, en utilisant `/second', `/minute', `/hour' ou `/day', ou en abrégé (ainsi `5/second' est identique à `5/s').
suivi d'un nombre, indique la réserve maximale (ou la salve) avant que la limite ci-dessus n'entre en jeu.
Cette correspondance peut souvent être employée avec la cible LOG pour limiter les occurences de journalisation. Pour comprendre comment cela fonctionne, examinons la règle suivante, qui journalise les paquets avec les paramètres de limite par défaut :
# iptables -A FORWARD -m limit -j LOG
La première fois que cette règle est satisfaite, le paquet est journalisé. En fait, avec une réserve de 5, seuls les 5 premiers paquets seront journalisés. Ensuite, 20 minutes doivent passer avant qu'un nouveau paquet ne soit journalisé par cette règle, sans tenir compte du nombre de paquets qui correspondent. Aussi, chaque fois que 20 minutes s'écoulent sans constater de correspondance, un paquet de la réserve est récupéré (sa valeur est incrémentée). Si aucun paquet ne satisfait la règle pendant 100 minutes, la réserve est complètement rechargée et on est revenu au point de départ.
Note : vous ne pouvez actuellement créer de règle avec un temps de recharge de plus de 59 heures, donc si vous configurez un débit moyen de 1 par jour, alors le débit de réserve doit être inférieur à 3.
Vous pouvez aussi utiliser ce module pour éviter les diverses attaques engendrant un déni de service (DoS) et avec un débit supérieur pour augmenter la vitesse de réaction.
Protection contre les inondations de requêtes de connexions (`syn-flood') :
# iptables -A FORWARD -p tcp --syn -m limit --limit 1/s -j ACCEPT
Balayage de ports furtif :
# iptables -A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT
Ping de la mort :
# iptables -A FORWARD -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
Ce module fonctionne comme une porte à hystérésis, comme le montre l'illustration ci-dessous.
Débit (pqts/s)
^ .---.
| / DoS \
| / \
Limite de DoS -|.....:.........\.......................
= (limit * | /: \
limit-burst) | / : \ .-.
| / : \ / \
| / : \ / \
Fin de DoS -|/....:..............:.../.......\..../.
= limit | : :`-' `--'
---------------+-----+--------------+------------------> Temps (s)
LOGIQUE => Concord.| Non concord. | Concordance
On mentionne un paquet par seconde avec une réserve de 5 paquets, mais ici, les paquets commencent à arriver avec un débit de 4/s pendant 3 secondes puis recommencent après 3 autres secondes.
<-Inond. 1 -> <- Inond. 2 ->
Nb total
de ^ Maximum __-- YNNN
paquets| Débit __-- YNNN
| de __-- YNNN
10 | Ligne __-- Y
| __-- Y
| __-- Y
| __-- YNNN
|- YNNN
5 | Y
| Y Key: Y -> La règle concorde
| Y N -> La règle ne concorde pas
| Y
|Y
0 +--------------------------------------------------> Temps (secondes)
0 1 2 3 4 5 6 7 8 9 10 11 12
Vous constatez que les 5 premiers paquets sont autorisés à dépasser la limite d'un paquet par seconde, puis la limitation entre en jeu. Si une pause intervient, une autre rafale est autorisée, mais pas au-delà du débit maximum fixée par la règle (1 paquet par seconde après épuisement de la réserve).
Ce module essaie de faire correspondre les diverses caractéristiques du créateur du paquet, pour les paquets générés localement. Il est uniquement valide dans la chaîne OUTPUT, et même dans ce cas, certains paquets sans propriétaire (comme les réponses ICMP d'un ping) ne corresponderont jamais.
Concorde si le paquet a été créé par un processus avec l'identifiant d'utilisateur (numérique) indiqué.
Concorde si le paquet a été créé par un processus avec l'identifiant de groupe (numérique) indiqué.
Concorde si le paquet a été créé par un processus avec le numéro de processus indiqué.
Concorde si le paquet a été créé par un processus appartenant au groupe de session indiqué.
Ce module expérimental doit être spécifié explicitement avec `-m unclean ou `--match unclean'. Il effectue des vérifications diverses et variées sur la bonne constitution des paquets. Ce module n'a pas été vérifié et ne devrait pas être utilisé comme dispositif de sécurité (il pourrait rendre les choses plus dangereuses s'il contient lui-même des bogues). Il ne dispose d'aucune option.
Le critère de correspondance le plus utile est fourni par l'extension `state', qui interprète l'analyse de traçage de connexion du module `ip_conntrack'. Il est fortement recommandé.
Spécifier `-m state' permet d'accéder à l'option supplémentaire `--state', qui évalue la correspondance avec une liste d'états séparés par des virgules (les `!' indiquent les états qui ne correspondent pas). Ces états sont :
Le paquet démarre une nouvelle connexion.
Le paquet est lié à une connexion existante (c'est-à-dire un paquet de réponse ou un paquet envoyé vers l'extérieur appartenant à une connexion qui a déjà répondu).
Le paquet est associé à une connexion existante sans faire partie de cette connexion, comme une erreur ICMP ou (avec le module FTP chargé) un paquet établissant une connexion de données FTP.
Le paquet ne peut pas être identifié pour une raison quelconque : ceci comprend un manque de mémoire et des erreurs ICMP décorrélées d'une connexion connue. Généralement, ces paquets devraient être détruits.
Un exemple de cette puissante extension de correspondance pourrait être :
# iptables -A FORWARD -i ppp0 -m state ! --state NEW -j DROP
Maintenant que nous connaissons les tests réalisables sur un paquet, nous avons besoin de déterminer ce qu'il convient de faire des paquets sélectionnés par nos tests. C'est ce qu'on appelle la cible d'une règle.
Les deux cibles pré-définies sont simples : DROP et ACCEPT. Nous les avons déjà abordées. Si une règle correspond à un paquet et que la cible est une de ces deux-là, aucune autre règle ne sera consultée : le sort du paquet est déjà décidé.
Il existe deux types de cibles différentes des cibles pré-définies : les extensions et les chaînes créées par l'utilisateur.
Une propriété puissante d'Iptables
(héritée d'Ipchains
)
est la possibilité pour l'utilisateur de créer de nouvelles chaînes, en
plus de celles existantes (INPUT, FORWARD et OUTPUT). Par convention,
les chaînes utilisateur sont en minuscule pour les différencier (nous décrirons
comment créer de nouvelles chaînes utilisateur dans
Opérations sur une Chaîne Entière ci-dessous).
Quand un paquet correspond à une règle dont la cible est une chaîne utilisateur, le paquet commence à traverser les règles de cette chaîne. Si cette chaîne utilisateur ne décide pas du sort du paquet, alors une fois la traversée terminée, le test reprend sur la règle suivante de la chaîne courante.
Le temps est venu pour un peu plus d'art ASCII. Considérons deux chaînes rudimentaires : INPUT
(la chaîne pré-définie) et test
(une chaîne définie par l'utilisateur).
`INPUT' `test'
---------------------------- ----------------------------
| Règle1: -p ICMP -j DROP | | Règle1: -s 192.168.1.1 |
|--------------------------| |--------------------------|
| Règle2: -p TCP -j test | | Règle2: -d 192.168.1.1 |
|--------------------------| ----------------------------
| Règle3: -p UDP -j DROP |
----------------------------
Considérons un paquet TCP venant de 192.168.1.1 et à destination de 1.2.3.4. Il
pénètre dans la chaîne INPUT
, et est évalué par la Règle1 - il n'y a pas de correspondance.
Par contre, la Règle2 concorde et sa cible s'avère être la chaîne test
, par conséquent, la règle suivante examinée
est le début de cette nouvelle chaîne. La Règle1 de test
concorde mais ne
spécifie pas de cible, donc la règle suivante est examinée, soit la Règle2.
Elle ne concorde pas et nous avons atteint la fin de la chaîne test
.
Nous retournons donc à la chaîne INPUT
, dont nous venons d'examiner la Règle2.
Nous passons alors à la Règle3, qui ne concorde pas davantage.
On peut schématiser ainsi l'itinéraire du paquet :
v __________________________
`INPUT' | / `test' v
------------------------|--/ -----------------------|----
| Règle1 | /| | Règle1 | |
|-----------------------|/-| |----------------------|---|
| Règle2 / | | Règle2 | |
|--------------------------| -----------------------v----
| Règle3 /--+___________________________/
------------------------|---
v
Les chaînes utilisateur peuvent sauter dans d'autres chaînes utilisateur (mais ne faîtes pas de boucle : vos paquets seraient irrémédiablement détruits).
L'autre type d'extension est une cible. Une extension de
cible est constituée d'un module du noyau et d'une extension optionnelle
d'Iptables
pour permettre de nouvelles options en ligne
de commande. À l'origine, plusieurs extensions existent déjà dans la distribution de Netfilter :
Ce module permet de journaliser les paquets qui correspondent. Il propose des options supplémentaires :
Suivi d'un nombre de niveaux ou d'un nom. Les noms valides (insensibles à la casse) sont `debug', `info', `notice', `warning', `err', `crit', `alert' et `emerg'. Ils correspondent respectivement aux nombres 7 à 0. Lisez la page de manuel de syslog.conf pour connaître leur signification. Le niveau par défaut est `warning'.
Suivi d'une chaîne de 29 caractères maximum; ce message est envoyé au début du message de journalisation, pour rendre son identification unique.
Ce module est surtout utile lors du dépassement d'une limite de correspondance, pour ne pas submerger les journaux.
Ce module se comporte comme `DROP', excepté que l'expéditeur du paquet reçoit en plus un message d'erreur ICMP `port unreachable'. Notez que le message d'erreur ICMP n'est pas envoyé si (voir RFC 1122) :
REJECT peut aussi recevoir une option `--reject-with' qui change le type du paquet de réponse utilisé : consultez la page de manuel.
Il y a deux cibles spéciales pré-définies : RETURN
et
QUEUE
.
RETURN
a le même effet que d'atteindre la fin d'une chaîne :
pour une règle dans une chaîne pré-définie, le comportement par défaut de la chaîne est
exécuté; pour une règle dans une chaîne utilisateur, l'analyse se poursuit
dans la chaîne précédente, immédiatement après la règle qui a bifurqué sur cette chaîne utilisateur.
QUEUE
est une cible spéciale, qui met les paquets en file d'attente pour les
traiter dans l'environnement de l'utilisateur. Pour que ça fonctionne, deux éléments
supplémentaires sont requis :
Voici un exemple rapide de l'utilisation d'Iptables pour mettre des paquets en file d'attente afin de les traiter dans un environnement utilisateur :
# modprobe iptable_filter
# modprobe ip_queue
# iptables -A OUTPUT -p icmp -j QUEUE
Avec cette règle, les paquets ICMP sortants générés en local (par exemple
créés avec ping) sont transmis au module ip_queue, qui tente ensuite de les délivrer
à une application utilisateur. Si aucune application n'est prête à
recevoir ces paquets, ils sont détruits.
Pour écrire une application utilisateur, utilisez l'API libipq. Elle est distribuée avec Iptables. Des exemples de code peuvent être trouvés dans les outils "testsuite" (par exemple redirect.c) accessibles via CVS.
Le statut de ip_queue peut être vérifié via :
/proc/net/ip_queue
La longueur maximale de la file d'attente (c'est-à-dire le nombre maximal de paquets
sans verdict délivrés à l'espace utilisateur) peut être contrôlée via :
/proc/sys/net/ipv4/ip_queue_maxlen
La valeur par défaut de cette longueur maximale est 1024. Une fois
cette limite atteinte, les nouveaux paquets seront détruits
jusqu'à ce que la longueur de la file redescende sous la limite.
Les protocoles bien conçus comme TCP interprètent une destruction de paquets
comme une congestion, et se limiteront lorsque la file se remplit.
Cependant, des expériences sont nécessaires pour déterminer idéalement la
longueur maximale de file d'attente pour une situation donnée, si la valeur par
défaut est trop faible.
Une propriété utile d'Iptables
est la possibilité de
rassembler des règles apparentées dans des chaînes. Vous pouvez appeler les chaînes
comme vous le souhaitez, mais je vous recommande les minuscules pour éviter la confusion
avec les chaînes pré-définies et les cibles. Les noms de chaînes peuvent
aller jusqu'à 31 caractères maximum.
Créons une nouvelle chaîne. Comme je suis quelqu'un d'imaginatif, je l'appelle
test
. Nous lui appliquons l'option `-N' ou `--new-chain' :
# iptables -N test
#
C'est aussi simple que ça. Maintenant, vous pouvez lui ajouter des règles comme expliqué précédemment.
Effacer une chaîne est également très simple, grâce à l'option `-X' ou `--delete-chain'. Pourquoi `-X' ? Et bien, toutes les lettres satisfaisantes étaient déjà prises.
# iptables -X test
#
Il y a des restrictions à la suppression d'une chaîne : elle doit être vide (voir Vider une Chaîne ci-dessous) et elle ne doit pas être la cible d'une autre règle. Et vous ne pouvez pas supprimer une des trois chaînes pré-définies.
Si vous ne spécifiez pas de chaîne, alors toutes les chaînes définies par l'utilisateur seront effacées, si possible.
Il y a une façon simple de vider une chaîne de toutes ses règles, en utilisant la commande `-F' (ou `--flush').
# iptables -F FORWARD
#
Si vous ne spécifiez pas de chaîne, alors toutes les chaînes seront vidées.
Vous pouvez lister toutes les règles d'une chaîne en utilisant la commande `-L' (ou `--list').
Le paramètre `refcnt' listé pour chaque chaîne utilisateur correspond au nombre de règles ayant cette chaîne pour cible. Il doit être à zéro (et la chaîne doit être vide) avant qu'elle ne soit effacée.
Si le nom de la chaîne est omis, toutes les chaînes sont listées, même les chaînes vides.
Trois options peuvent accompagner `-L'. L'option `-n' (numérique)
est vraiment utile car elle évite à Iptables
d'essayer de résoudre
les adresses IP, ce qui (si vous utilisez des DNS comme la plupart des gens)
génèrera des temps d'attente si votre DNS n'est pas configuré convenablement,
ou si vous avez filtré les requêtes DNS. Cette option force aussi l'affichage des ports TCP et UDP
avec leur numéro plutôt qu'avec leur nom.
L'option `-v' vous montre tous les détails des règles, tels que les compteurs de paquets et d'octets, les comparaisons de types de service (TOS) et les interfaces. Sinon ces paramètres sont omis.
Notez que les compteurs de paquets et d'octets sont écrits avec les suffixes `K', `M' ou `G', respectivement pour 1.000, 1.000.000 et 1.000.000.000. L'option `-x' (pour `expand') écrit les nombres intégralement, quelle que soit leur taille.
Il est pratique de pouvoir remettre les compteurs à zéro. Ceci peut être accompli avec l'option `-Z' (ou `--zero').
Considérons les commandes suivantes :
# iptables -L FORWARD
# iptables -Z FORWARD
#
Dans l'exemple ci-dessus, quelques paquets pourraient traverser, juste entre les commandes `-L' et `-Z'. Pour cette raison, vous pouvez utiliser les commandes `-L' et `-Z' ensemble, pour simultanément lister les chaînes et réinitialiser les compteurs.
Auparavant, quand nous avons abordé le cheminement des paquets à travers les chaînes,
nous avons considéré le sort d'un paquet atteignant la fin d'une chaîne pré-définie.
Dans un telle situation, le comportement par défaut de la chaîne détermine
le sort du paquet. Seules les chaînes pré-définies (INPUT
, OUTPUT
et
FORWARD
) possèdent un comportement par défaut. En effet, lorsqu'un paquet atteint la fin
d'une chaîne utilisateur, la progression reprend à la chaîne précédente.
Le comportement par défaut peut être soit ACCEPT
, soit DROP
. Par exemple :
# iptables -P FORWARD DROP
#