Au sein du dépôt CVS vit une suite de tests : plus la liste la suite de tests couvre de points, plus vous avez l'assurance que le changement apporté ne casse pas autre chose. Les tests triviaux sont au moins aussi importants que les tests difficiles : ce sont les tests triviaux qui simplifient les tests complexes (puisque vous savez que le test trivial fonctionne avant même de lancer le test complexe).
Les tests sont simples : ce sont juste des scripts shell dans le répertoire `testsuite/' qui sont supposés réussir. Les tests sont lancés par ordre alphabétiques, donc `01test' serait lancé avant `02test'. Pour l'instant il y a 5 répertoires de tests :
Tests généraux du canevas netfilter.
Tests d'iptables.
Les tests couvrant le suivi de connexions.
Les test couvrant la NAT.
Les tests couvrant la compatibilité avec ipchains/ipfwadm
A l'intérieur du répertoire `testsuite/' il y a un script appelé `test.sh'. Il configure 2 interfaces bidons (`tap0' et `tap1'), allume la fonction de forwarding, et enlève tous les modules netfilter du kernel. Ensuite il parcours les répertoires décrit au dessus, et lance chacun de leur script `test.sh' jusqu'à ce que l'un d'entre eux rate.`-v' veut dire d'afficher chaque test au moment ou il est effectué, et optionnellement le nom du test : si ce dernier est donne en paramètre, il va passer tous les tests pour arriver directement au test demandé.
Créez un nouveau fichier dans le répertoire approprié : essayez de donner un nombre à votre script pour qu'il soit lancé au bon moment. Par exemple, avant de tester si le suivi de ICMP-reply fonctionne, on doit d'abord tester que les paquets ICMP sortant sont suivis correctement.
Il est habituellement mieux de créer plus de petit tests atomiques plutôt qu'un gros test qui couvre tout. Chaque test peut alors couvrir un aspect particulier, et mieux isoler le problème immédiatement pour le gens qui lancent la suite de tests.
Si quelque chose ne se passe pas bien, faite simplement un `exit 1' qui va causer le ratage du test. Si il s'agit de quelque chose attendu à rater exprès, vous devriez imprimer un message unique. Votre test doit terminer par `exit 0' si tout ce passe bien. Vous devez vérifier le succès de chaque commande, soit en utilisant `set -e' au début du script, ou en ajoutant `|| exit 1' à la fin de chaque commande.
Les fonctions d'aide `load_module' et `remove_module' peuvent être utilisées pour charger des modules : vous ne devriez jamais vous appuyer sur la fonction d'auto chargement des modules dans la suite de tests, à moins que ce ne soit ce que vous cherchez à tester.
Vous avez 2 interfaces pour jouer : tap0 et tap1. L'adresse
IP des interfaces sont dans $TAP0
et $TAP1
respectivement.
Elles ont toutes les deux un netmask de `255.255.255.0', et leur adresse
network sont dans $TAP0NET
and $TAP1NET
respectivement.
Il y a un fichier temporaire vide dans $TMPFILE. Il sera effacé à la fin de votre test.
Votre script sera lancé du répertoire `testsuite', où qu'il soit. Et donc, vous devez accéder aux utilitaires (comme iptables) en utilisant un chemin commençant pas `../userspace'
Votre script peut imprimer plus d'information si $VERBOSE est mis (ce qui veut dire que l'utilisateur a spécifié `-v' sur la ligne de commande)
Il y a quelques outils de la suite de tests qui sont utiles dans le répertoire "tools" : chacun d'entre eux retourne une valeur non nulle si il y a eu un problème.
Vous pouvez générer un paquet IP en utilisant `gen_ip', qui sort un paquet IP vers la sortie standard. Vous pouvez donc envoyer ces paquet IP en redirigeant la sortie standard vers /dev/tap0 ou /dev/tap1 (ces fichiers seront créer après le 1er lancement de la suite de tests si ils n'existaient pas déjà).
gen_ip est un programme simpliste qui est très très rigoureux sur l'ordre des paramètres que vous lui donnez :
Génère le paquet, et ensuite le transforme en un fragment à l'offset donné avec la longueur donnée.
Met le bit `More Fragments' sur le paquet.
Définit la MAC adresse source du paquet.
Définit le 'TOS' du paquet (0 <= TOS <= 255).
Ensuite viennent les arguments obligatoires :
Adresse IP source du paquet.
Adresse IP destination du paquet.
Longueur totale du paquet, en comptant les headers.
Numéro du protocole encapsulé dans le paquet, ex: 17=UDP.
Ensuite, les argument dépendent du protocole : pour UDP (17), il y a le port source et le port destination. Pour ICMP (1), il u a le type et le code ICMP du paquet. Si le type est 0 ou 8 (pong ou ping) alors deux paramètres additionnels (l'ID et le champs de séquence) sont requis. Pour TCP (6), le port source et le port destination, et les flags TCP ("SYN", "SYN/ACK", "ACK", "RST" or "FIN") sont requis. Il y a 3 arguments optionnels : "OPT=" suivi d'une liste (les éléments sont séparés par une virgule) d'options, "SYN=" suivi d'un numéro de séquence, et "ACK=" suivi par un numéro de séquence. Finalement, l'argument optionnel "DATA" indique que les données du paquet sont à remplir avec le contenu de l'entrée standard.
Vous pouvez voir les paquets IP en utilisant `rcv_ip', qui imprime la ligne de commande aussi proche que possible de la commande qui a servit à générer le paquet (les fragments sont une bonne exception).
C'est extrêmement utile pour analyser les paquets. Elle prend 2 arguments obligatoires :
Le temps (en secondes) maximum pour attendre le paquet à partir de l'entrée standard.
Le nombre de paquets à recevoir.
Il y a un argument optionnel, "DATA" qui force les données du paquets à être imprimées sur la sortie standard, après le header du paquet.
La façons standard d'utiliser `rcv_ip' dans un script shell est la suivante :
# Mets en place le contrôle des taches, pour que l'on puisse utiliser # '&' dans le script set -m # Attend 2 secondes un paquet sur tap0 ../tools/rcv_ip 2 1 < /dev/tap0 > $TMPFILE & # Soyons sûr que rcv_ip a été démarré. sleep 1 # Envoyer un paquet ICMP ping ../tools/gen_ip $TAP1NET.2 $TAP0NET.2 100 1 8 0 55 57 > /dev/tap1 || exit 1 # Attend rcv_ip if wait %../tools/rcv_ip; then : else echo rcv_ip failed: cat $TMPFILE exit 1 fi
Ce programme prend un paquet (comme généré par gen_ip, par exemple sur l'entrée standard, et en fait une erreur ICMP)
Il prend 3 arguments : un adresse IP source, un type et un code. L'adresse IP destination va être remplies avec l'adresse IP source du paquet donné sur l'entrée standard.
Ce programme prend un paquet à partir de l'entrée standard et l'injecte dans le système à partir d'une `raw socket'. Cela fait semblant d'être un paquet généré localement (comparé à un paquet passé par une des interfaces ethertap qui semble être des paquets générés par une interface étrangère).
Tous les utilitaires assument qu'ils peuvent tout faire en lecture ou écriture : c'est tout à fait vrai avec les interfaces ethertap, mais n'est pas forcement vrai si vous faites des bidouilles avec les pipes.
`dd' peut être utilisé pour couper des paquets, dd a une option `obs' ("output block size"=taille de bloc de sortie) qui peut être utilisé pour écrire les paquets en une seule écriture.
Vérifier les tests de succès d'abord, ex : testez que les paquets sont bien bloqués. Testez d'abord que les paquets passent bien d'abord, et ensuite testez que les paquets que vous voulez voir être bloqués sont bel et bien bloqués. Sinon, une erreur quelconque aurait tres bien pu bloquer le paquet...
Essayez d'écrire des tests exacts, et ne pas faire des `tests aléatoires et voir ce qui arrive'. Si un test exact ne marche pas, c'est toujours bon à savoir. Si un test aléatoire ne marche pas une fois, ça n'aide peut à trouver l'erreur.
Si le test plante sans message d'erreur, vous pouvez ajouter un `-x' à la première ligne du script (ex: `#! /bin/sh -x') pour voir quelles commandes sont lances.
Si un test plante de manière aléatoire, vérifier qu'il n'y ai pas d'interférences avec d'autres interfaces. Éteignez toutes vos interfaces externes. Étant sur le même réseau que Andrew Tridgell, j'ai l'habitude d'être inondé avec des paquets broadcast de Windows par exemple.