SIG 11 ARTICLES DOCUMENTS MEMBRES LIENS
Avec la mutiplication concomittante des apprentis pirates et du haut débit, des louveteaux et des agneaux en somme, le coupe-feu est devenu un outil indispensable à toute connexion Internet. Linux se montre particulièrement bien adapté à cette tâche, et se retrouve souvent à la base de solutions commerciales qui peuvent coûter, suivant la taille des sites et le nombre de clients à protéger, plusieurs milliers d'Euros. On lit parfois qu'un 486 avec 16 Mo de mémoire suffit pour fabriquer un pare-feu efficace. Encore faut-il trouver un 486, ce qui devient chaque jour plus difficile, et réussir l'exploit d'y installer une distribution récente avec le noyau 2.4 ; plus sérieusement, le pare-feu est un excellent moyen à peu près gratuit de fournir à une machine plus tout jeune mais pas trop vieille une occasion supplémentaire de servir la collectivité.
Un coupe-feu Linux comprend deux éléments associés et indispensables : des fonctions de filtrage intégrées, directement ou par l'intermédiaire de modules, au noyau, dites netfilter ou filtrage de paquets, et un programme chargé de l'accès à ces fonctions, au moyen d'un ensemble de règles que l'on doit écrire. Chaque nouvelle version majeure du noyau Linux a vu une évolution du code du pare-feu, et du programme qui leur est associé : le ipfwadm du noyau 2.0 est devenu ipchains dans le 2.2, et iptables avec le noyau 2.4, aujourd'hui stable et bien établi.
 
Construire un pare-feu implique donc trois étapes distinctes :
  • Installer le programme iptables : avec la SuSE 8.0, on dispose de la version 1.2.5.
  • Compiler son noyau avec les fonctions de filtrage que l'on désire utiliser.
  • Ecrire des règles adaptées à la configuration de son réseau. Cette tâche, relativement complexe mais fort instructive, sera détaillée dans ce document. Notons que l'on peut également utiliser pour ce faire des interfaces graphique, comme le remarquable fwbuilder, voire adapter des scripts tous faits, présents en nombre par exemple chez Linux Guruz.
  • Et avant tout, on lira avec profit une documentation abondante, en particulier l'excellent et très pédagogique Linux 2.4 packet filtering HOWTO de Rusty Russell, l'auteur du code de pare-feu dans le noyau 2.4, et le plus complexe mais très complet Iptables Tutorial d'Oskar Andreasson, document à l'origine déjà ancienne, constamment tenu à jour par son auteur mais qui, ces temps dernier, semble bien nomade.

les modules du noyau

Un paquet IP, comme son équivalent postal, comprend deux éléments essentiels : un contenu, alias charge utile, et un ensemble d'informations de service destinées à permettre son bon acheminement, lesquelles sont regroupées dans une en-tête. Le coupe-feu va examiner, avec plus ou moins de profondeur selon les fonctions compilées dans le noyau et les règles d'analyse mises à sa disposition, ces en-têtes, et décider en conséquence du destin du paquet concerné : celui-ci pourra, pour l'essentiel, être accepté, abandonné, auquel cas l'expéditeur ne sera pas informé de son sort, ou rejeté, avec envoi d'un message d'erreur à l'expéditeur.
 
Mais iptables ne se contente pas de son rôle de coupe-feu : le programme assure deux autres fonctions tout à fait disjointes :
  • la traduction d'adresses IP, alias NAT, que nous utiliserons en complément du proxy wwwoffle pour le racordement à Internet de notre réseau
  • la manipulation des en-têtes IP, connue sous le nom de mangle (charcutage), qui fait subir à celles-ci des manipulations bien peu orthodoxes.
Une fonction ne sera bien sûr disponible que si elle a été compilée dans le noyau ; certaines sont rigoureusement indispensables, et d'autres moins. Et n'oublions pas que, pour le bon fonctionnement de l'interface RNIS, l'utilisation des sources du noyau SuSE, le 2.4.18 dans la version 8.0, est obligatoire. On va donc choisir les valeurs suivantes dans la section des options réseau :
 
  • Packet Socket, pas directement utilisé par le pare-feu, mais indispensable pour des programmes annexes sur lesquels on aura l'occasion de revenir
  • Network Packet Filtering, la fonction de base, comme son nom l'indique
On passe ensuite à la configuration du filtrage lui-même, ou l'on trouve :
  • Connection Tracking, nécessaire pour effectuer la traduction d'adresses IP, alias NAT. Traditionnellement, et très simplement mise en place en même temps que le coupe-feu, cette fonction prendra le relais du proxy pour les clients style FTP et IRC, qui ne passent pas par celui-ci.
  • D'ailleurs, les particularités des protocoles FTP et, pour les amateurs de discussions oiseuses, IRC, impliquent d'ajouter ces modules au précédent.
  • Evidemment, le module le plus important est IP tables support
  • Tous les modules qui viennent ensuite et comprennent match dans leur intitulé permettront d'effectuer une analyse d'un élément particulier de l'en-tête en fonction d'une règle précise. Le plus important est Connection state match support qui permet la fameuse stateful inspection caractéristique des pare-feux très chers, l'outil de base du filtrage de paquets avec le noyau 2.4. On aura également, au minimum, besoin du limit match support, utile en particulier pour limiter le nombre d'entrées dans le fichier log.
Il nous reste une dernière série d'éléments à compiler : ceux qui nous permettront justement de créer ces tables qui conserveront les chaines dont le noyau aura besoin pour sa fonction de filtrage.
Packet Filtering nous permettra de créer la première d'entres elles, la table filter contenant les règles du pare-feu, laquelle nous est donc indispensable. Deux autres sont optionelles : Full NAT avec en complément les module MASQUERADE et REDIRECT, pour la traduction des adresses IP à l'aide de la table nat et la création d'un proxy transparent, et Packet mangling, qui sert donc à une manipulation assez complexe et un peu expérimentale de certains des éléments de l'en-tête IP, avec la table mangle.
Notons pour finir :
  • Que la présence de telle ou telle fonction dépend étroitement de la version du noyau utilisé.
  • Que rien n'empêche de compiler la totalité des éléments en tant que modules : nous verrons plus loin que ceux-ci seront chargés au démarrage de la machine, par le script que nous créerons.

le principe d'iptables

Nous avonc donc maintenant notre noyau nouveau, avec des fonctions de filtrage qui ne demandent qu'à être appelées par la commande iptables. Elle permet de manipuler les tables de filtrage en indiquant au noyau quelles sont les règles à suivre. Prenons un exemple simple :
 /usr/sbin/iptables -t filter -A FORWARD -p tcp -s 192.168.10.0/24 -d 0/0 -j
ACCEPT
Et décryptons :
  • iptables est donc la commande unique que nous utilisons pour toutes les manipulations de tables
  • -t précise la table à laquelle la règle est destinée ; trois choix sont donc possibles : filter, paramètre par défaut qu'il est donc superflu de préciser, nat, ou mangle
  • -A va ajouter la règle en question après celles qui existent déjà ; on pourrait également supprimer une règle existante avec -D, ou en insérer une à un endroit précis, avec par exemple -I OUTPUT 3.
  • ces règles s'appliquent à chaque fois à une chaîne précise, c'est à dire à l'un des trois parcours possibles, dans la machine abritant le coupe-feu, pour un paquet IP. Celui-ci peut en effet :
    • aller d'une interface réseau à l'autre, c'est à dire du réseau local vers Internet, et réciproquement : il est pris en charge par la chaîne FORWARD.
    • être destiné à la machine pare-feu elle-même, avec la chaîne INPUT.
    • ou encore avoir comme origine le coupe-feu : la chaîne OUTPUT s'en occupe alors.
  • -p permet d'indiquer le protocole concerné. Trois cas possibles : tcp, udp ou icmp
  • avec -s pour source et -d pour destination, on va matérialiser le trajet du paquet, ici du réseau local, pour lequel les syntaxes du type 192.168.10.0/24 ou 192.168.10.0/255.255.255.0 sont acceptées, vers n'importe quelle adresse externe, soit 0/0.
  • enfin, avec -J pour jump, on arrive à la cible ou target à mettre en oeuvre : les deux principales sont ACCEPT ou DROP, laquelle peut éventuellement être remplacée par REJECT, comme on l'a vu plus haut. D'autres choix existent, tels LOG
En d'autres termes, cette règle permet aux postes de notre réseau local utilisant le protocole tcp d'accéder à Internet. Ça n'a l'air de rien, mais en son absence le coupe-feu bloquerait aussi ces paquets là.
La commande une fois lancée, on peut voir comment elle a été prise en charge grâce à iptables -L -n ; -L pour list, et -n pour éviter une longue, infructueuse et coûteuse, puisqu'elle entraîne à chaque fois une connexion, tentative de résolution des noms..
Chain INPUT (policy ACCEPT)
target prot opt source destination

Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 192.168.10.0/24 anywhere

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

Il va sans dire :
  • que les règles peuvent être beaucoup plus complexes : -m ! -state --state INVALID va ainsi s'intéresser à la connexion établie par les paquets, et vérifier qu'elle est valide, c'est à dire que son origine n'est pas inconnue, le ! étant classiquement utilisé pour inverser le paramètre précisé.
  • qu'elles doivent également être beaucoup plus nombreuses, et peuvent prendre en compte bien d'autres valeurs, interfaces réseau, ports, paramètres des en-têtes IP tels le Time To Live alias TTL.
  • et que, naturellement, si elles sont entrées avec une ligne de commande, elles sont perdues à chaque redémarrage de la machine.
  • Pour remédier à ce dernier inconvénient, il est indispensable de conserver ses règles dans un script du répertoire init.d. On peut faire très compliqué : celui qui suit est fort simple, mais permet de bien comprendre le mécanisme d'iptables, et assure, tests à l'appui, une protection suffisante.

écrire son script

On n'en a pas vraiment conscience, sans doute parce qu'une règle tient bien souvent sur une seule ligne, mais iptables procède au fond d'une logique hiérarchique. À un premier niveau, il nous faut choisir la catégorie de la fonction à mettre en oeuvre, et donc le type de table : les trois choix possibles sont le filtrage des paquets, leur acheminement avec NAT, ou la réécriture de leur en-tête avec MANGLE. Commençont donc par l'essentiel : le fitrage.
Dans la table du filtrage, trois chaînes sont disponibles par défaut, comme on l'a vu plus haut : INPUT, OUTPUT et FORWARD. Si l'on crée une nouvelle chaîne avec, par exemple, iptables -N permis, elle fonctionnera en quelque sorte comme une dérivation : il faudra la relier avec iptables -A FORWARD -j permis à l'une des trois chaînes par défaut, ou à toutes les trois.
Il ne nous restera alors qu'à préciser deux séries d'éléments : les matches, paramètres qui définiront à quoi la règle s'applique, et le target, la cible qui précise l'action à entreprendre.

Dès lors, le script va s'organiser en un certain nombre de sections. On commence par attribuer, pour simplifier l'écriture des scripts complexes, des variables aux divers interfaces, adresses IP et réseaux qui fourniront les paquets à analyser. Cela peut donner un résultat comme celui-ci :
#Les variables pour les  
interfaces
#externe
isdn="ippp0"
#interne
eth_if="eth0"
eth_ip="192.168.10.21"
lan="192.168.10.0/24"
#locale
loc="lo"
loc_ip="127.0.0.1"
#
Rappellons que nous nous connectons à Internet avec une carte RNIS, donc avec l'interface ippp0, et qu'elle est installée sur bravek6, alias 192.168.10.21, lequel fait office de coupe-feu.
On charge ensuite, par précaution, les différents modules du noyau :
#Si on veut utiliser la cible REJECT
insmod ipt_REJECT
#Pour le FTP
insmod ip_conntrack_ftp
#Pour IRC
insmod ip_conntrack_irc
#modules NAT pour MASQUERADE
insmod ip_nat_ftp
insmod ip_nat_irc
insmod ipt_MASQUERADE
#module pour le proxy
insmod ipt_REDIRECT
#module pour le log
insmod ipt_LOG
lesquels dépendent, bien sûr, des choix faits lors de la compilation. Enfin, il est utile, avant d'écrire les chaînes, d'enregistrer les commandes suivantes :
#Tout remettre a zero
#
iptables -F
iptables -X
iptables -Z
A chaque lancement du script, toutes les règles mémorisées par le noyau sont effacées : on peut ainsi y apporter des modifications sans craindre d'effets secondaires.
Contrairement à l'usage courant, iptables, par défaut, accepte tout ce qui n'est pas spécifiquement interdit. C'est pourquoi l'on commence par inverser ce comportement de la façon suivante :
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
Le -P majuscule désigne la politique à adopter, et ne doit pas être confondu avec le -p minuscule qui spécifie un protocole.
Il nous faudra ensuite réglementer le trafic entre les diverses interfaces, en ajoutant avec iptables -A des règles aux trois chaînes définies par défaut. D'abord, ne surtout pas oublier l'hôte local ; par définition, seules les chaînes INPUT et OUTPUT ont ici un sens :
#Une regle pour localhost
iptables -A INPUT -i $loc -j ACCEPT
iptables -A OUTPUT -o $loc -j ACCEPT
Puis, régler le problème de la machine coupe-feu :
#Une regle pour bravek6
iptables -A OUTPUT -o $isdn -j ACCEPT
iptables -A INPUT -s $lan -j ACCEPT
iptables -A OUTPUT -d $lan -j ACCEPT
On accepte donc d'une part les paquets destinés à l'interface Internet, et de l'autre les paquets des machines du réseau, soit en entrée avec -s pour source et INPUT, soit en sortie avec -d pour destination et OUTPUT. Enfin, il nous reste à autoriser le transit des paquets du réseau local vers Internet :
iptables -A FORWARD -s $lan -d 0/0 -j ACCEPT
On offre donc aux données venant du réseau local le libre passage vers une adresse IP par définition inconnue, puisque dynamique.
Reste à régler la question de fond : comment permettre le trafic aller-retour normal de notre réseau vers Internet, tout en repoussant les inconnus qui s'intéressent avec une insistance suspecte à nos humbles machines ? C'est là qu'entre en scène la grande nouveauté du noyau 2.4, l'analyse de l'état des connexions. Celui-ci peut connaître quatre valeurs distinctes :
  • La connexion peut être initialisée, classiquement lorsqu'un navigateur demande la page d'accueil d'un nouveau site. L'état de ce premier paquet est NEW.
  • Dès lors, tous les paquets échangés entre ce serveur et notre navigateur seront en l'état ESTABLISHED. Quelques cas particuliers, comme les transferts FTP, pourront générer des paquets en liaison avec cette connexion principale, qui seront dits RELATED.
  • Enfin, les paquets dont l'état ne pourra pas être identifié seront INVALID.
Il est dès lors assez simple de comprendre comment va fonctionner notre règle : il faudra autoriser les connexions lancées depuis notre réseau, permettre le trafic qui en découle, et interdire le reste. On peut procéder ainsi :
 
#The state machine 
iptables -N ok 
iptables -A ok -i $isdn -m state --state ESTABLISHED,RELATED -j ACCEPT 
iptables -A ok -i ! $isdn -m state --state NEW -j ACCEPT 
iptables -A ok -i $isdn -m state --state NEW,INVALID -j DROP 
 
      
On commence donc par créer une nouvelle chaîne appelée ok. On accepte tout le trafic venant de l'extérieur, donc par l'interface ippp0, à condition qu'il soit ESTABLISHED ou bien RELATED. On accepte également que des connexions soit initialisées par toutes les interfaces, sauf ippp0. Et enfin, on refuse tout le reste.
state, contrairement aux paramètres tels le protocole ou l'interface, doit être précisé de manière explicite. La syntaxe est donc d'abord -m state, puis --state et le ou les états associés. Notons également le -i ! $isdn : usage classique du point d'exclamation comme élément de négation, séparé par un espace de ce à quoi il s'applique, et rôle dont on aura saisi l'importance : en son absence, on autorise ce que l'on cherche précisément à interdire.
Enfin, pour rendre active cette nouvelle règle, il nous reste à la relier aux règles par défaut de la façon suivante :
 
iptables -A INPUT -j ok 
iptables -A OUTPUT -j ok 
iptables -A FORWARD -j ok 
 
      
Voilà, nous sommes désormais dotés d'un filtre de paquets. Avant de tester son efficacité, il faudra y ajouter quelques fonctions annexes.

LOG, MASQUERADE et REDIRECT

ACCEPT, DROP ou REJECT sont des cibles terminales : l'analyse prend fin quand elle sont atteintes. Tel n'est pas le cas de LOG qui, on l'aura compris, va inscrire, par défaut dans /var/log/messages, des informations que l'on peut paramètrer précisément. Pour notre script, on utilisera dans un premier temps les règles suivantes :

#Creer un log raisonnable
iptables -A INPUT -m limit --limit 4/minute --limit-burst 1 -j LOG --log-level info
iptables -A OUTPUT -m limit --limit 4/minute --limit-burst 1 -j LOG --log-level info
iptables -A FORWARD -m limit --limit 4/minute --limit-burst 1 -j LOG --log-level info
Le trafic généré dans chacune des trois règles principales est donc enregistré dans /var/log/messages. Le niveau de sévérité est précisé avec --log-level info : celui-ci est très bas, et servira essentiellement à vérifier que tout va bien. Il faudra ensuite le remplacer par notice ou bien warning.
Pour ne pas être malgré tout accablé d'informations, on va en limiter la quantité avec -m limit --limit 4/minute --limit-burst 1 : on permet ainsi l'enregistrement d'une information toutes les quinze secondes, et d'une seule. Voilà qui termine la partie filtrage du script.

Passons maintenant à la seconde table, NAT. Elle va nous servir à réaliser deux opérations du plus haut intérêt. Il est d'abord indispensable, même avec notre proxy, d'utiliser la cible MASQUERADE, qui permet de remplacer l'adresse IP des machines de notre réseau par celle qui a été attribuée lors de la connexion à Internet ; cette cible permet de réaliser cette opération avec une adresse IP inconnue à l'avance, et s'applique donc exclusivement à l'utilisation d'interfaces commutées, comme notre connexion RNIS. Elle permettra aux clients qui ne passent pas par le proxy, FTP et IRC en l'occurrence, d'accèder à Internet, et se présente très simplement comme ceci :

iptables -t nat -A POSTROUTING -o $isdn -j MASQUERADE
Il est désormais obligatoire avec -t nat de spécifier la table utilisée ; on va donc ajouter à la chaîne POSTROUTING, chaîne, avec sa collègue PREROUTING, propre à la table nat, une règle MASQUERADE appliquée aux paquets qui quittent le coupe-feu par l'interface ippp0.
Il y a plus fort : la cible REDIRECT redirige, comme son nom l'indique, des paquets entrant sur le coupe-feu et à destination d'un certain port vers un ou plusieurs autres ports qu'il nous faudra préciser. En d'autre termes, la règle :
iptables -t nat -A PREROUTING -i $eth_if -p tcp --dport 80 -j REDIRECT --to-ports 8080
va intercepter les requêtes que les navigateurs de nos clients envoient aux serveurs Web, et les diriger vers le port 8080 du coupe-feu : on sait que c'est là que le proxy wwwoffle attend les connexions. On réalise ainsi l'opération dite transparent proxying, grâce à laquelle il n'est plus nécessaire de paramétrer individuellement chaque client, comme on l'a fait plus haut : l'adresse de la passerelle, inscrite dans leur configuration réseau, suffit désormais au navigateur pour atteindre automatiquement le proxy. Et en plus, ça marche. Attention toutefois à la syntaxe, --to-ports est bien au pluriel.

Il faut enfin dire quelques mots de la table mangle, qui permet de trafiquer les valeurs d'en-tête des paquets ip, comme par exemple le TTL ou time to live, c'est à dire le nombre de routeurs qu'un paquet est autorisé à traverser avant d'être abandonné. Pour parapharser l'excellent Oskar Andreasson, une règle de ce type :

iptables -t mangle -A PREROUTING -i $eth_if -j TTL --ttl-set 64
permet de donner une même valeur de TTL à tous les paquets quittant le coupe-feu. Or des valeurs différentes pour des données sensées provenir d'une seule et même machine trahissent l'existence en amont d'un réseau dont les paquets on déjà un peu vécu. Les fournisseurs d'accès fouineurs peuvent ainsi repérer la présence de réseaux là où leur contrat autorise la connexion d'une machine unique. Malin. Et quand même trop particulier pour qu'il soit nécessaire d'en dire plus. Voilà, c'est terminé.
Enfin, presque. Généralement, on sait que le noyau Linux fournit nombre d'informations sur son fonctionnement par l'intermédiaire du répertoire /proc, un pseudo système de fichiers grâce auquel on peut prendre connaissance de celles-ci avec une simple commande, comme cat. On sait moins que, à l'inverse, on peut modifier les paramètres du noyau de manière similaire ; on trouve quelques textes à ce sujet dans la documentation des sources du noyau, proc.txt, une introduction globale, dans le répertoire filesystems, et, dans le répertoire networking, ip-sysctl.txt, qui explique quelles valeurs donner à quels paramètres.
Or il est indispensable d'activer une fonction que le noyau n'exécute pas par défaut, la transmission des paquets entre les deux interfaces réseau qui caractérisent notre coupe-feu. On rajoute donc la ligne suivante à la fin du script :
 
/bin/echo "2" > /proc/sys/net/ipv4/ip_forward 
 
      
echo 2 et pas 1 permet d'inscrire un message dans les logs. On peut activer d'autres paramètres de la même manière, l'allocation d'adresse dynamique avec /proc/sys/net/ipv4/ip_dynaddr, ou les syncookies.

l'épreuve du feu

Voilà, maintenant on peut y aller. On lance le script depuis une console, et on peut ensuite afficher le résultat avec iptables -L -nv, le -v rendant comme toujours la commande plus prolixe :
 
Chain INPUT (policy DROP 0 packets, 0 bytes) 
 pkts bytes target     prot opt in     out     source               destination          
    2   108 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  *      *       192.168.10.0/24     0.0.0.0/0 
    0     0 LOG        all  --  *      *       192.168.10.0/24     0.0.0.0/0          limit: avg 
4/min burst 1 LOG flags 0 level 6  
    0     0 ok         all  --  *      *       0.0.0.0/0            0.0.0.0/0           
 
Chain FORWARD (policy DROP 0 packets, 0 bytes) 
 pkts bytes target     prot opt in     out     source               destination          
    0     0 ACCEPT     all  --  *      *       192.168.10.0/24     0.0.0.0/0 
    0     0 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0          limit: avg  
4/min burst 1 LOG flags 0 level 6  
    0     0 ok         all  --  *      *       0.0.0.0/0            0.0.0.0/0           
 
Chain OUTPUT (policy DROP 0 packets, 0 bytes) 
 pkts bytes target     prot opt in     out     source               destination          
    2   108 ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  *      ippp0   0.0.0.0/0            0.0.0.0/0           
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            192.168.10.0/24 
    0     0 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0          limit: avg  
4/min burst 1 LOG flags 0 level 6  
    0     0 ok         all  --  *      *       0.0.0.0/0            0.0.0.0/0           
 
Chain ok (3 references) 
 pkts bytes target     prot opt in     out     source               destination          
    0     0 ACCEPT     all  --  ippp0  *       0.0.0.0/0            0.0.0.0/0          state  
RELATED,ESTABLISHED  
    0     0 ACCEPT     all  --  !ippp0 *       0.0.0.0/0            0.0.0.0/0          state NEW  
    0     0 DROP       all  --  ippp0  *       0.0.0.0/0            0.0.0.0/0          state  
INVALID,NEW  
 
      
La présentation en tableau est fort claire : d'abord les chaînes par défaut INPUT, FORWARD et OUTPUT, puis notre chaîne ok. Nombre et taille des paquets, cibles et protocoles, interface et adresses d'origine et de destination : tout y est répertorié.
Mais comment être sûr que ça marche ? On peut déjà faire quelque chose de très simple et de gratuit : interdire l'accès au coupe-feu depuis le réseau local. Il suffit de changer une cible dans le script :
 
iptables -A INPUT -s $lan -j REJECT 
      
puis de le relancer. Un simple ping vers un des postes du réseau fournit une indication, les réponses étant bloquées par le filtre, et la cible REJECT entraînant l'envoi d'une réponse : "host unreachable".

Mais on obtiendra un diagnostic plus complet avec un outil servant à ça, comme le célèbre et redouté nmap. On trouvera sur le site de son auteur toute la documentation nécessaire à la compréhension de son outil, ainsi qu'un tas d'articles d'une lecture fascinante. Cet utilitaire dispose d'une interface graphique, xnmap alias nmpafe, qui nous permet d'entrer l'adresse ip de la machine cible, et dans laquelle on cochera les options don't resolve, fast scan et don't ping, qui permettront à cette vaine tentative d'ouvrir une porte hermétiquement close de prendre un peu moins de temps. Ensuite, il ne restera qu'à essayer les diverses méthodes proposées, connect(), SYN et FIN stealth en particulier. Et dans la mesure où le proxy participe à la sécurité de l'hôte, on n'oubliera pas, pour un résultat plus probant, de désactiver au préalable wwwoffle.
Il faudra quand même un temps parfois considérable avant que nmap ne s'avoue vaincu. Evidemment, la règle rejetant sans nuance tous les paquets envoyés depuis notre réseau local, le test est trop facile, et permet juste de s'assurer que le fitrage marche : mais pour éprouver son efficacité, il faudrait travailler en conditions réelles, avec des données qui arrivent par l'interface RNIS. Pour cela, la meilleure solution est de disposer d'un complice équipé de RNIS, câble ou ADSL : une fois connecté à Internet, on lui communique par téléphone l'adresse ip dont on dispose, et on peut ensuite suivre en temps réel ses tentatives d'effraction.
Á défaut, on peut toujours simuler le fonctionnement du filtre à partir de notre réseau local. Pour se retrouver dans une situation crédible, il faudra que le coupe-feu permette la réception des pages web demandées par notre navigateur, tout en bloquant les autres connexions : on aura besoin desrègles suivantes :
 
 
#iptables -A INPUT -s $lan -j ACCEPT 
iptables -A OUTPUT -d $lan -j ACCEPT 
 
iptables -N ok 
iptables -A ok -i $eth_if -m state --state ESTABLISHED,RELATED -j ACCEPT 
iptables -A ok  -i $eth_if -m state --state NEW,INVALID  -m limit --limit 4/minute --limit-burst 1\ 
 -j LOG --log-prefix "Nmap attaque ! " --log-level debug 
iptables -A ok -i $eth_if -m state --state NEW,INVALID -j DROP 
 
On remarque :
  • que l'on ne doit pas oublier de fermer la porte au réseau local : le # devant la règle appropriée suffit.
  • que l'on contrôle le flux des paquets avec les deux lignes de la règle ok.
  • que l'on pourra suivre les tentatives de nmap grâce au log, dont on prendra soit de limiter la taille pour éviter l'inondation, et que l'on identifiera plus facilement en commençant chaque ligne par un nom, du style :
     
    --log-prefix "chaîne de caractères libres mais quand même plus courte " 
    
  • et que l'on autorise l'envoi de paquets vers le réseau depuis le coupe-feu dans la table OUTPUT.
Dès lors, il ne reste plus qu'à demander, côté client, une page web au serveur de notre réseau local, tout en lançant, côté serveur, un ping depuis cette machine, puis une analyse plus détaillée avec nmap. On vérifie que la navigation se déroule sans problème, mais que le coupe-feu bloque toute tentative du serveur visant à établir une nouvelle connexion. Les logs, ainsi que la commande iptables -L -nv permettent de dresser un constat tout à fait conforme à nos attentes :
 
 
Chain INPUT (policy DROP 0 packets, 0 bytes) 
 pkts bytes target     prot opt in     out     source               destination          
    2   100 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
72218   68M ok         all  --  *      *       0.0.0.0/0            0.0.0.0/0           
 
Chain FORWARD (policy DROP 0 packets, 0 bytes) 
 pkts bytes target     prot opt in     out     source               destination          
  136  6456 ok         all  --  *      *       0.0.0.0/0            0.0.0.0/0           
 
Chain OUTPUT (policy DROP 0 packets, 0 bytes) 
 pkts bytes target     prot opt in     out     source               destination          
    2   100 ACCEPT     all  --  *      lo      0.0.0.0/0            0.0.0.0/0           
   16  1040 ACCEPT     all  --  *      ippp0   0.0.0.0/0            0.0.0.0/0           
17221  958K ACCEPT     all  --  *      *       0.0.0.0/0            192.168.200.0/24    
    0     0 ok         all  --  *      *       0.0.0.0/0            0.0.0.0/0           
 
Chain ok (3 references) 
 pkts bytes target     prot opt in     out     source               destination          
54968   67M ACCEPT     all  --  eth0   *       0.0.0.0/0            0.0.0.0/0 
state RELATED,ESTABLISHED  
  219 12553 LOG        all  --  eth0   *       0.0.0.0/0            0.0.0.0/0 
state INVALID,NEW limit: avg 4/min burst 1 LOG flags 0 level 7 prefix `Nmap attaque ! '  
17386  941K DROP       all  --  eth0   *       0.0.0.0/0            0.0.0.0/0 
state INVALID,NEW  
 
 
On aura remarqué que les paquets qui transitent par la chaîne ok se décomposent en 54968 paquets en l'état RELATED ou ESTABLISHED, réponses à nos demandes comptabilisées dans la chaîne OUTPUT, et 17386 paquets NEW ou INVALID, que le pare-feu a rejetés. En bref, ça marche.

Notons pour finir que certains sites Internet comme AuditMyPC proposent ce type d'analyses, lesquelles semblent cependant essentiellement consacrées à la recherche de ports NetBios sur un poste Windows, ce qui ne nous aide guère.
Voilà, notre protection est opérationnelle. On n'oubliera pas de rendre à notre script ses paramètres d'origine, en gardant une ligne comme :

 
 
iptables -A ok -i $isdn -m state --state NEW,INVALID -j LOG\ 
--log-prefix "INTRUS ! " --log-level debug 
 
avant la règle finale de la chaîne ok, pour collecter dans /var/log/messages les tentatives d'intrusions qui ne manqueront pas de se produire, avec toutes les saletés comme OpaServe qui circulent de nos jours sur Internet. ; un grep INTRUS /var/log/messages permettra d'en dresser la liste. En voici un petit extrait :
INTRUS ! IN=ippp0 OUT= MAC= SRC=33.30.1.153 DST=212.43.198.213
LEN=78 TOS=0x00 PREC=0x00 TTL=108 ID=39430 PROTO=UDP SPT=1650 DPT=137 LEN=58 
 
INTRUS ! IN=ippp0 OUT= MAC= SRC=208.35.253.134 DST=212.43.198.213 
LEN=48 TOS=0x00 PREC=0x00 TTL=113 ID=1633 DF PROTO=TCP SPT=4774 DPT=1433 WINDOW=16384 RES=0x00 SYN URGP=0 
Avec le proxy, le coupe-feu, et surtout la certitude que ce qui importe vraiment, c'est d'avoir une serrure un peu plus grosse que celle du voisin, on peut dormir tranquille.

Denis Berger, 15 novembre 2002

SIG 11 DOCUMENTS LA CONFIGURATION LES PARAMÈTRES LE PROXY L'INDEX

info@sig-11.org