Nel CVS è presente una suite per i test: più test la suite gestisce, e maggiore sarà la certezza che dei cambiamenti al codice non abbiano silenziosamente corrotto qualcosa. Test banali sono importanti quanto quelli più ingegnosi: sono i test banali che semplificano i test complessi (ci si assicuri che le basi funzionino correttamente prima di eseguire i test complessi).
I test sono semplici: sono giusto degli script shell presenti nella sotto-directory testsuite/ che si suppone abbiano successo. Gli script sono eseguiti in ordine alfabetico, quindi `01test' sarà eseguito prima di `02test'. Correntemente ci sono 5 directory di test:
test generali riguardanti il framework netfilter
test riguardanti iptables
test riguardanti il connection tracking
test riguardanti il NAT
test riguardanti la compatibilità ipchains/ipfwadm
All'interno della directory testsuite/ è presente uno script `test.sh'. Esso configura due semplici interfacce (tap0 e tap1), abilita il forwarding, e rimuove tutti i moduli di netfilter. Quindi esegue da ciascuna directory ogni script test.sh fino a quando uno fallisce. Questo script ha due argomenti opzionali: `-v' che specifica di visualizzare ogni test processato e un nome opzionale di test: se è fornito, lo script salterà tutti i test fino a trovare quello specificato.
Si crei un nuovo file in una directory appropriata: si provi a numerare il proprio test così sarà eseguito al momento opportuno. Ad esempio, allo scopo di effettuare il test del tracciamento delle risposte ICMP (02conntrack/02reply.sh) è necessario innanzitutto controllare che i pacchetti ICMP uscenti siano tracciati correttamente (02conntrack/01simple.sh).
Solitamente è meglio creare più file di piccole dimensioni, ciascuno dei quali si occupi di una sola area, ciò aiuta le persone che eseguono la testsuite ad isolare immediatamente i problemi.
Se qualcosa non funziona durante il test, semplicemente si effettui un `exit 1', il quale causa un fallimento; se riguarda qualcosa che si aspettava fallisse, si potrebbe stampare un messaggio unico. I propri test dovrebbero concludersi con `exit 0' se tutto è stato eseguito correttamente. E' necessario controllare che tutti i comandi siano stati eseguiti con successo, utilizzando `set -e' all'inizio dello script oppure appendendo `|| exit 1' alla fine di ciascun comando.
Le funzioni di aiuto `load_module' e `remove_module' possono essere utilizzate per caricare i moduli: con la testsuite non si dovrebbe mai contare sull'auto-caricamento a meno che non sia proprio quello che si desidera specificatamente verificare.
Si hanno due interfacce in gioco: tap0 e tap1.
I loro indirizzi sono rispettivamente nelle variabili $TAP0
e
$TAP1
. Entrambe hanno netmask 255.255.255.0; le loro reti sono
rispettivamente in $TAP0NET e $TAP1NET.
E' presente un file temporaneo vuoto in $TMPFILE. Esso è cancellato al termine del proprio test.
Lo script sarà eseguito dalla directory testsuite/, se presente. Quindi si può accedere ai tool (quali iptables) utilizzando un path che cominci con `../userspace'.
Lo script può visualizzare maggiori informazioni se $VERBOSE è impostata (si intende che l'utente specifichi `-v' dalla linea comandi).
Ci sono parecchi tool utili nella sotto-directory "tools": ciascuno esce ritornando uno stato non zero se ha riscontrato un problema.
Si possono generare pacchetti IP utilizzando `gen_ip', il quale emette un pacchetto IP verso lo standard input. Si possono alimentare di pacchetti tap0 e tap1 inviando lo standard output verso /dev/tap0 e /dev/tap1 (questi sono creati subito dopo la prima esecuzione della testsuite, se non già esistenti).
gen_ip è un programma semplice che è al momento piuttosto pignolo riguardo l'ordine degli argomenti. Prima di tutto richiede gli argomenti generali opzionali:
Genera il pacchetto, quindi lo converte in un frammento utilizzando i parametri offset e lenght forniti.
Imposta il bit `More Fragments'.
Imposta l'indirizzo sorgente MAC.
Imposta il campo TOS del pacchetto (da 0 a 255).
Seguono gli argomenti obbligatori:
Indirizzo IP sorgente del pacchetto.
Indirizzo IP destinazione del pacchetto.
Lunghezza totale del pacchetto, intestazioni incluse.
Numero del protocollo del pacchetto, es. 17 = UDP.
Poi gli argomenti dipendono dal protocollo: nel caso UDP (17), essi consistono nei numeri di porta sorgente e destinazione. Nel caso ICMP (1), essi consistono nel tipo e nel codice del messaggio ICMP: se il tipo è 0 oppure 8 (ping-reply o ping) allora sono richiesti altri due argomenti (i campi ID e sequence). Nel caso TCP sono richiesti la porta sorgente, la porta destinazione e i flag ("SYN", "SYN/ACK", "ACK", "RST" oppure "FIN"). Ci sono tre argomenti opzionali: "OPT=" seguito da una lista di opzioni separate da virgole, "SYN=" seguito da un numero di sequenza e "ACK" seguito anch'esso da un numero di sequenza. Infine, l'argomento opzionale "DATA" specifica che il "carico" del pacchetto TCP è da riempire con il contenuto dello standard input.
Si possono vedere i pacchetti IP utilizzando `rcv_ip', il quale visualizza la linea comandi il più possibile corrispondente con i valori originali dati a gen_ip (i frammenti sono l'eccezione).
Ciò è estremamente utile per l'analisi dei pacchetti. Richiede due argomenti obbligatori:
Il tempo massimo di attesa, espresso in secondi, per un pacchetto proveniente dallo standard input.
Numero di pacchetti da ricevere.
C'è inoltre un argomento opzionale "DATA" che causa la visualizzazione, dopo l'intestazione del pacchetto, del contenuto di un pacchetto TCP sullo standard output.
La modalità di utilizzo di `rcv_ip' in uno script shell è la seguente:
# Imposta il controllo, in questo modo si può utilizzare & negli script shell set -m # Attendi due secondi per un pacchetto proveniente da tap0 ../tools/rcv_ip 2 1 < /dev/tap0 > $TMPFILE & # Assicurati che rcv_ip sia in funzione sleep 1 # Invia un ping ../tools/gen_ip $TAP1NET.2 $TAP0NET.2 100 1 8 0 55 57 > /dev/tap1 || exit 1 # Attendi rcv_ip, if wait %../tools/rcv_ip; then : else echo rcv_ip failed: cat $TMPFILE exit 1 fi
Questo programma prende un pacchetto (come generato da gen_ip, ad esempio) dallo standard input e lo rigira in un errore ICMP.
Richiede tre argomenti: un indirizzo IP sorgente, un tipo e un codice. L'IP di destinazione sarà impostato utilizzando l'indirizzo IP sorgente del pacchetto dato allo standard input.
Questo prende un pacchetto dallo standard input e lo immette nel sistema da un raw socket. Ciò consente di dare l'apparenza di un pacchetto generato localmente (come separato dal pacchetto fornito ad uno dei dispositivi ethertap, sembra quindi un pacchetto generato in remoto).
Tutti i tool assumono di poter fare qualsiasi cosa in una lettura o scrittura: ciò è vero per i dispositivi ethertap, ma potrebbe non essere vero se si sta facendo qualcosa di complicato con le pipe.
dd può essere utilizzato per "tagliare" i pacchetti: dd ha un'opzione obs (output block size) che può essere usata per produrre in output il pacchetto in una singola scrittura.
Si effettui prima di tutto il test per "successo": ad esempio per verificare se i pacchetti sono bloccati con successo, prima si testi se i pacchetti passano normalmente poi che alcuni siano bloccati. In caso contrario un problema non correlato potrebbe fermare i pacchetti ...
Si cerchi di scrivere test corretti, non del tipo `provare in modo casuale e vedere cosa accade'. Se un test corretto fallisce, ciò rappresenta un'ottima cosa da sapere. Se invece un test casuale fallisce non è di grande aiuto.
Se un test fallisce senza ritornare un messaggio, si può aggiungere un `-x' alla prima riga dello script (es. `#! /bin/sh -x') per vedere quali comandi sono stati eseguiti.
Se un test fallisce di tanto in tanto, si controllino eventuali interferenze casuali nel traffico di rete (si provi a "disabilitare" tutte le proprie interfacce esterne). Stando nella stessa rete di Andrew Tridgell, ad esempio, tendo ad essere assillato dai broadcast di Windows.