Tuto Netfilter2

De Page Personnelle de Cédric Blancher.

Sommaire

[modifier] Introduction

Dans la première fiche, je vous ai présenté la syntaxe d'iptables avec quelques petits exemples très proches de ce qu'il était possible de faire avec ipchains. De fait, nous n'avons pas réellement vu les apports de Netfilter, et c'est donc ce que nous allons faire dans cette 2e fiche, ainsi que dans la suivante. Au programme cette fois-ci, les modules, le filtrage à état (stateful filtering pour les anglophiles) et les chaînes utilisateur.


[modifier] Les concordances

Une concordance (ou match en anglais) est un élément qui permet, par son chargement, de rajouter des capacités supplémentaires dans la construction du motif de reconnaissance. Techniquement, une concordance est un module du noyau Linux, chargeable et déchargeable à souhait. Son chargement permet de différencier les paquets selon des paramètres très spécifiques.

Pour le moment, ce n'est pas très parlant, nous allons donc passer à un exemple. Supposons que vous vouliez vous protéger contre les SYN floods. Une attaque en SYN flood consiste à effectuer un grand nombre d'initiations de connexion (paquets SYN) vers une machine pour remplir sa table de connexions et ainsi interdire ne nouvelles connexions. Pour s'en protéger, on va vouloir limiter le rythme d'arrivée de ces paquets. Une concordance, appelée limit, a été créée pour cela. Elle permet de considérer, en plus des paramètres classiques, le rythme d'arrivée des paquets.

Exemple : limiter les paquets SYN à 1 par seconde

	iptables -A INPUT -m limit --limit 1/s -p tcp --syn -j ACCEPT

De même, on pourra filtrer les paquets selon les adresses MAC de machines qui les ont envoyés avec la concordance mac"" :

	iptables -A INPUT -m mac --mac-source FF:FF:FF:FF:FF:FF -j ACCEPT

Pour avoir de l'aide, il suffit de taper :

	iptables -m <concordance> --help

On pourrait citer de nombreux exemples, mais l'essentiel à retenir sur les concordances est qu'elles permettent d'accroitre les capacités de Netfilter au delà des critères classiques de filtrage (source, destination, etc...).

Certaines concordances sont spécifiques à certains protocoles, en particulier TCP, UDP et ICMP pour lesquelles elles sont implicitement chargées : le fait d'entrer un protocole à l'aide du drapeau -p vous y donne accès. Par exemple, regarder des paquets TCP (-p tcp) permet d'avoir accès aux concordances sur les drapeaux TCP à l'aide de --tcp-flags ou aux options TCP avec --tcp-options. Les options --sport ou encore --dport font partie de ces concordances, puisqu'elles ne sont accessibles qu'en précisant un protocole. L'option --syn est aussi une concordance TCP.

UDP possède les concordances --sport et --dport. ICMP possède --icmp-type qui permet de différencier les différent messages ICMP (echo request, echo reply, etc.).

Pour plus d'aide sur les concordances associées à ces trois protocoles, faites simplement :

	iptables -p <protocole> --help


[modifier] La gestion des états

S'il est un module sur lequel on doit se pencher tout particulièrement, c'est bien le module ip_conntrack. Ce module permet de réaliser le filtrage à état. Nous allons le charger.

	modprobe ip_conntrack

Le filtrage à état ? Cékoidonkecet'bêtela ? Un filtre de paquets comme ipchains, filtre les paquets un par un, de manière totalement indépendante. De fait, quand il voit un paquet, il est incapable de savoir si ce paquet fait partie d'un flux existant ou non. Cette capacité est appelé filtrage à état.

Le fait d'être capable de caractériser les paquets selon le critère d'appartenance à des flux existants permet en outre au filtre de mettre en place dynamiquement des règles pour autoriser les paquets de retour ou des flux en relation avec des flux existants. Bref, c'est super puissant, et en plus, ça simplifie la vie ! Donc, stateful rulez.

Le module de gestion des états s'appelle avec -m state. Il nécessite l'insertion d'un module appelé ip_conntrack (modprobe ip_conntrack). Il permet de caractériser l'état des paquets, en fonction d'une table des flux existants constamment mise à jour par le noyau. L'état des paquets est spécifié avec le drapeau --state qui peut prendre 4 valeurs :

  • NEW : le paquet correspond à un nouveau flux
  • ESTABLISHED : le paquet correspond à un flux existant
  • RELATED : le paquet correspond à un flux nouveau, mais en relation avec un flux existant
  • INVALID : l'état du paquet n'a pu être découvert

Vous aurez remarqué que je n'ai pas utilisé le terme de connexion, mais le terme de flux. En effet, le module ip_conntrack travaille sur des flux. Ainsi, il s'applique aussi bien à TCP qu'à UDP, même à certains ICMP. Le fait qu'un paquet ait l'état NEW veut dire qu'il ne correspond à aucune entrée dans la table des flux, mais pas forcément qu'il initie une nouvelle connexion. La différence est subtile, mais de taille, nous verrons plus loin pourquoi.

Reprenons donc l'exemple de la fiche 1. Nous voulions autoriser les gens à se connecter en HTTP et en FTP à notre machine. Nous n'avions pas établi de règle pour filtrer les paquets en sortie. Aujourd'hui, nous allons blinder la machine en passant la chaîne OUTPUT à la politique DROP et en gérant les états. Donc déjà :

	iptables -P OUTPUT DROP

Considérons les commandes suivantes :

	iptables -A INPUT -m state --state NEW -p tcp --sport 1024: --dport 80 -j ACCEPT

Cette règle nous dit d'accepter le paquets ouvrant un flux HTTP sur notre machine. Pour accepter les paquets de retour, il nous suffira de faire :

	iptables -A INPUT -m state --state ESTABLISHED -p tcp --sport 1024: --dport 80 -j ACCEPT

Et de même pour les paquets sortants :

	iptables -A OUTPUT -m state --state ESTABLISHED -p tcp --sport 80 --dort 1024: -j ACCEPT

En effet, l'état d'un paquet n'est pas spécifique à une règle : il est global, c'est à dire qu'il s'applique à toutes les chaînes, dans toutes les tables.

Considérons le FTP à présent. Nous avions pour le gérer inséré trois règles, dont l'une d'elle ouvrait la machine de façon importante :

	iptables -A INPUT -p tcp --sport 1024: --dport 1024: -j ACCEPT

Appliquons à présent la gestion des états :

	iptables -A INPUT -m state --state NEW -p tcp --sport 1024: --dport 21 -j ACCEPT
	iptables -A INPUT -m state --state ESTABLISHED -p tcp --sport 1024: --dport 21 -j ACCEPT
	iptables -A OUTPUT -m state --state ESTABLISHED -p tcp --sport 21 --dport 1024: -j ACCEPT

Là déjà, nous avons fait un grand pas pour la connexion de commandes. Occupons nous à présent de la connexion de données (ftp-data). Cette connexion est intimement liée au fonctionnement de FTP. Il y a donc un module spécial, appelé helper qui permet de la gérer au mieux. Nous l'insérons en faisant modprobe ip_conntrack_ftp. Ce module ira reconnaître la connexion FTP et en déduira les paramètres de la connexion de données. Celle-ci sera attendue avec l'état RELATED. Donc :

	iptables -A INPUT -m state --state RELATED -p tcp --sport 20 --dport 1024: -j ACCEPT

L'état RELATED ne concerne que le premier paquet de cette connexion. Les suivants seront ESTABLISHED :

	iptables -A INPUT -m state --state ESTABLISHED -p tcp --sport 20 --dport 1024: -j ACCEPT
	iptables -A OUTPUT -m state --state ESTABLISHED -p tcp --sport 1024: --dport 20 -j ACCEPT

Et nous gérerons le FTP passif à l'aide de :

	iptables -A OUTPUT -m state --state RELATED -p tcp --sport 1024: --dport 1024: -j ACCEPT
	iptables -A OUTPUT -m state --state ESTABLISHED -p tcp --sport 1024: --dport 1024: -j ACCEPT
	iptables -A INPUT -m state --state ESTABLISHED -p tcp --sport 1024: --dport 1024: -j ACCEPT

Pfiouh ! C'est fini. A ce niveau là, forcement, ça ne parait pas vraiment plus simple. Par contre, on est assuré que les paquets qu'on laisse passer correspondront bien à des connexions établies.

Vous aurez remarqué qu'on voit souvent du RELATED et de l'ESTABLISHED. On pourra se dire qu'au fond, on voudrait autoriser une bonne fois pour toutes les paquets RELATED ou ESTABLISHED. C'est ce qui va nous permettre de simplifier notre jeu de règle de manière sensible.

Remettons INPUT et OUTPUT à zéro :

	iptables -F INPUT
	iptables -F OUTPUT

Et considérons ceci :

	iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
	iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

En faisant cela, nous avons réglé le sort de tous les paquets de retour ou des connexions connexes comme pour le FTP. Il ne nous reste plus qu'à gérer les paquets ouvrant les connexions :

	iptables -A INPUT -m state --state NEW -p tcp --sport 1024: --dport 21 -j ACCEPT
	iptables -A INPUT -m state --state NEW -p tcp --sport 1024: --dport 80 -j ACCEPT

Pour que le FTP marche correctement, nous avons cependant besoin de charger un module spécialisé appelé helper (cf. supra) comme nous l'avions fait pour notre exemple de partage de connexion (cf. fiche 1) :

        modprobe ip_conntrack_ftp

Et comme nous ne voulons pas restreindre notre machine en sortie :

	iptables -A OUTPUT -m state --state NEW -j ACCEPT

Et c'est tout. Admirons le travail en lisant les chaînes INPUT et OUTPUT :

	Chain INPUT (policy DROP)
	target     prot opt source               destination         
	ACCEPT     all  --  anywhere             anywhere           state RELATED,ESTABLISHED 
	ACCEPT     tcp  --  anywhere             anywhere           state NEW tcp spts:1024:65535 dpt:ftp 
	ACCEPT     tcp  --  anywhere             anywhere           state NEW tcp spts:1024:65535 dpt:www 

	Chain OUTPUT (policy DROP)
	target     prot opt source               destination         
	ACCEPT     all  --  anywhere             anywhere           state RELATED,ESTABLISHED 
	ACCEPT     all  --  anywhere             anywhere           state NEW 

Evidemment, la gestion des états peut s'appliquer à la chaîne FORWARD :

	iptables -F FORWARD
	iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
	iptables -A FORWARD -m state --state NEW -s 192.168.1.0/24 -j ACCEPT

On voit la simplicité atteinte !

[modifier] Les helpers

Je vous ai introduit les helpers. Un helper permet au module ip_conntrack de suivre certains protocoles tordus comme le FTP, l'IRC ou le H323 (Netmeeting). Il lit le contenu des paquets pour y repérer les commandes qui négocient de nouvelles connexions de manière à préparer un contexte pour un paquet RELATED. Ces modules se nomment ip_conntrack_<protocole>. Ces helpers existent aussi pour le NAT, ils s'appellent ip_nat_, mais nous y reviendront dans la fiche 3. Ce qu'il faut savoir, c'est qu'ils dépendent les uns des autres : ip_nat_ftp dépend de ip_conntrack_ftp qui dépend de ip_conntrack. C'est pourquoi je vous conseille d'insérer ces modules à l'aide de la commande modprobe, qui permet d'insérer aussi les modules desquels on dépend.

Je vous disais précédemment qu'un paquet NEW ne correspond pas forcément à une ouverture de connexion. Supposons que vous vouliez reconnaître les ACK scan. Un ACK scan est un scan de ports à l'aide de paquets ACK, donc sans ouverture de connexion préalable à l'aide d'un paquet SYN. Avec la gestion des états, on repère facilement ce type de paquet : c'est un flux nouveau, dont le premier paquet (qui ouvre le flux) est un paquet TCP qui n'est pas un paquet SYN.

	iptables -I INPUT 1 -m state --state NEW -p tcp ! --syn -j DROP

De même, on pourrait vouloir éviter que des pirates essayent de profiter d'un flux existant pour faire passer une nouvelle connexion TCP. Le paquet serait alors un paquet SYN, mais dans un flux ESTABLISHED :

	iptables -I INPUT 2 -m state --state ESTABLISHED -p tcp --syn -j DROP

Ces règles permettent de fortement augmenter votre niveau de sécurité. Si vous décidez de loguer les paquets correspondants (-j LOG), vous en verrez beaucoup. Ces paquets résultent la plus souvent de connexions mal fermées ou de paquets perdus.

Vous voilà accrocs de la gestion de états j'en suis sûr. Alors résumons :

  • on accepte les paquets ESTABLISHED et RELATED sur nos trois chaînes de base :
	iptables -A <chaîne> -m state --state ESTABLISHED,RELATED -j ACCEPT
  • on autorise les paquets NEW pour les flux qui nous intéressent :
	iptables -A <chaîne> -m state --state NEW <motif> -j ACCEPT
  • on passe toutes les politiques à DROP :
	iptables -P  DROP

D'autres produits de filtrage à état réalisent le stateful de manière automatique. Ce n'est pas le cas avec Netfilter pour lequel vous devez spécifier l'état des paquets que vous voulez traiter. Si c'est plus fastidieux, c'est infiniment plus puissant puisque ça permet comme je vous l'ai montre tout à l'heure de gérer certains "états bizarres".


[modifier] Les chaînes utilisateur

Dans la première partie, nous avons vu que les cibles d'une règle pouvaient être ACCEPT ou DROP (cibles précompilées ou intégrées), des extensions, que nous verrons dans la prochaine fiche, ou des chaînes utilisateurs.

Une chaîne utilisateur est une chaîne que vous créez vous-même à l'aide de la commande :

	iptables -N <ma_chaîne>

On la supprimerait avec :

	iptables -X <ma_chaîne>

On notera qu'une chaîne ne peut être supprimée que si elle ne contient plus aucune règle, et si aucune règle d'une autre chaîne n'y fait référence.

Voyons cela de plus près :

	iptables -N MA_CHAINE
	iptables -L MA_CHAINE
	Chain MA_CHAINE (0 references)
	target     prot opt source               destination

On a ici la liste des règles (celle-ci est vide) et le nombre de références à cette chaînes (0 puisque personne ne l'appelle encore).

Une fois crée, une chaîne utilisateur se comporte comme une chaîne standard à deux différences près :

  • les paquets ne passent dedans que si vous les y envoyez explicitement
  • une chaîne utilisateur n'a pas de politique

Pour envoyer des paquets dans une chaîne, pas de problème :

	iptables -A <chaîne> <motif> -j <ma_chaîne>

A partir de là, tous les paquets correspondant à mon motif vont quitter la chaîne courante pour aller dans ma chaîne utilisateur. Le paquet sera alors comparé aux règles que cette chaîne contiendra (iptables -A <ma_chaîne> <motif> -j <cible>). S'il correspond, la cible de la règle est appliquée, sinon, la paquet continue son chemin. Cette cible peut être n'importe quelle cible normale, donc même une nouvelle chaîne ! Toutes les opérations que nous avons vues sur les chaînes sont possibles (sauf -P). Les chaînes peuvent être appelées depuis n'importe quelle chaîne, de n'importe quelle table. Elle peuvent être créées depuis n'importe quelle table, mais ne seront visible que depuis la table dans laquelle on les a créées (cf fiche 3). Donc, si vous créez une chaîne dans une table, seules les règles de cette table peuvent envoyer des paquets vers votre chaîne.

Si le paquet traverse la chaîne sans avoir été reconnu, il est renvoyé à la chaîne précédente (celle d'où il a été envoyé dans celle-ci), à la règle qui suit celle qui l'avait envoyé dans notre chaîne. Pour "émuler" une politique, il suffira de rajouter à la fin de notre chaîne la règle. Si nous voulons (et ce sera souvent le cas), placer une politique de rejet, nous faisons donc :

	iptables -A <ma_chaîne> -j DROP

Vu comme cela, le concept de chaîne ne semble pas présenter d'intérêt. Mais supposons que vous vouliez faire un traitement lourd sur les ICMPs par exemple. Il est nettement plus simple de le faire dans une chaîne dédiée que de la faire dans toutes les autres. On créera donc une chaîne relative aux ICMPs :

	iptables -N ICMP

On y enverra tous les ICMPs :

	iptables -I INPUT 1 -p icmp -j ICMP
	iptables -I OUTPUT 1 -p icmp -j ICMP
	iptables -I FORWARD 1 -p icmp -j ICMP

Ensuite, on ajoute nos règles :

	iptables -A ICMP -p icmp --icmp-type echo-request -j ACCEPT
	iptables -A ICMP -p icmp --icmp-type echo-reply -j ACCEPT
	...

Ainsi, vous n'aurez écrit vos règles ICMP qu'une seule fois, mais vous pourrez les appliquer tout de même à toutes vos chaînes en redirigeant simplement les paquets. En outre, les paquets qui ne seraient pas des ICMPs n'y seront pas envoyés, ce qui évitera à Netfilter des comparaisons inutiles. On peut penser à énormément d'autres applications :

  • flux spécifique à une machine
  • flux spécifiques à un protocole
  • machines à 3, 4 interfaces voire plus
  • etc.

Les chaînes utilisateurs vous permettent dans des cas compliqués d'alléger votre jeu de règles et d'éviter à votre machine des opérations inutiles en créant un arbre de filtrage. Vous accélérez donc votre firewall, et vous simplifiez la maintenance de vos règles.


[modifier] Conclusion

Vous disposez à présent du savoir nécessaire à la mise en place d'un filtre IP très puissant à l'aide de Netfilter. Il ne vous manque que la maîtrise des tables et des extensions que nous verrons en fiche 3.

Si tout ceci vous paraît un peu obscur, c'est un peu normal. Ca viendra avec la pratique : rien ne remplace l'expérience. Je ne veux pas vous donner ici de recette miracle, parce qu'il n'y en a pas. Je veux vous donner les outils qui vous permettrons de vous construire vos propres recettes, parce qu'il y a autant de besoins que d'individus, et de nombreuses façons de traiter les mêmes besoins.

Pour la syntaxe, je vous renvoie vers la documentation de Netfilter, http://netfilter.samba.org/unreliable-guides/fr/packet-filtering-HOWTO.html, et vers l'aide d'iptables :

  • man iptables
  • iptables <option> --help

Et enfin, je vous conseille de pratiquer un maximum :)

Navigation
autres
Locations of visitors to this page

No software patents !

Valid XHTML 1.0 Transitional

Valid CSS 2.1