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 :
00netfilter/
Tests généraux du canevas netfilter.
01iptables/
Tests d'iptables.
02conntrack/
Les tests couvrant le suivi de connexions.
03NAT/
Les test couvrant la NAT.
04ipchains-compat/
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.
gen_ip
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 :
FRAG=offset,length
Génère le paquet, et ensuite le transforme en un fragment à
l'offset donné avec la longueur donnée.
MF
Met le bit `More Fragments' sur le paquet.
MAC=xx:xx:xx:xx:xx:xx
Définit la MAC adresse source du paquet.
TOS=tos
Définit le 'TOS' du paquet (0 <= TOS <= 255).
Ensuite viennent les arguments obligatoires :
source ip
Adresse IP source du paquet.
dest ip
Adresse IP destination du paquet.
length
Longueur totale du paquet, en comptant les headers.
protocol
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.
rcv_ip
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 :
wait time
Le temps (en secondes) maximum pour attendre le paquet à partir
de l'entrée standard.
iterations
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
gen_err
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.
local_ip
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.