Dentro del repositorio CVS reside una batería de pruebas: cuando más cubra la batería, más confianza se puede tener en que los cambios en el código no han roto algo silenciosamente. Las pruebas triviales son como poco tan importantes como las pruebas concienzudas: son las pruebas triviales las que simplifican las pruebas complejas (ya sabe que las bases tienen que funcionar bien antes de que se realicen las pruebas complejas).
Las pruebas son sencillas: tan sólo son shell scripts dentro del subdirectorio testsuite/. Se espera de ellos que se ejecuten sin dar error. Los scripts se ejecutan en orden alfabético, por lo que `01test' se ejecuta antes que `02test2'. Actualmente existen 5 directorios:
Pruebas generales del sistema netfilter.
Pruebas de iptables.
Pruebas del seguimiento de conexiones.
Pruebas del NAT.
Pruebas de compatibilidad ipchains/ipfwadm.
Dentro del directorio testsuite/ hay un script llamado `test.sh'. Configura dos interfaces falsas (tap0 y tap1), activa el redireccionamiento, y elimina todos los módulos de netfilter. Luego entra en todos los directorios de arriba y ejecuta uno a uno los scripts test.sh hasta que uno falla. Este script recibe dos argumentos opcionales: `-v', que imprime los tests al ejecutarse, y el nombre de un script (si se especifica uno, se omitirán todos los scripts hasta que se encuentre éste).
Cree un fichero nuevo en el directorio apropiado: intente numerar su script de manera que se ejecute en el momento adecuado. Por ejemplo, para probar el seguimiento de las respuestas ICMP (02conntrack/02reply.sh), primero necesitamos comprobar que los paquetes ICMP de salida tienen un seguimiento correcto (02conntrack/01simple.sh).
Normalmente es mejor crear muchos ficheros pequeños, cada uno cubriendo un área, porque así el que ejecute la batería de pruebas puede aislar el problema inmediatamente.
Si algo va mal en la prueba, haga simplemente un `exit 1', que causa error; si es algo que usted espera que vaya a fallar, debería imprimir un mensaje. Si todo va bien, la prueba debe acabar con un `exit 0'. Debe comprobar que todos los comandos se ejecutan con éxito, bien poniendo `set -e' al principio del script, o añadiendo `|| exit 1' al final de cada comando.
Se pueden utilizar las funciones de ayuda `load_module' y `remove_module' para cargar módulos: nunca debe fiarse de la auto carga en la batería de pruebas, a menos que sea eso lo que está probando.
Dispone de dos interfaces con las que jugar: tap0 y tap1. Sus
direcciones de interfaz están en las variables $TAP0
y
$TAP1
respectivamente. Ambas tienen máscaras de red
255.255.255.0; sus redes están en $TAP0NET y $TAP1NET respectivamente.
Existe un archivo temporal vacío en $TMPFILE. Es borrado al final de la prueba.
Su script se ejecutará desde el directorio testsuite/, esté donde esté. Por tanto debe acceder a las herramientas (como iptables) utilizando una ruta que empiece por `../userspace'.
Su script puede imprimir más información si $VERBOSE está activado (lo que significa que el usuario especificó `-v' en la línea de comandos).
Hay varias herramientas útiles para la batería de pruebas en el subdirectorio "tools": todas acaban con un status de salida distinto de cero si hubo algún problema.
Puede generar paquetes IP utilizando `gen_ip', que imprime un paquete IP en la salida estándar. Puede alimentar a las interfaces tap0 y tap1 redireccionando la salida estándar a /dev/tap0 y /dev/tap1 (si no existen, se crean la primera vez que se ejecuta la batería de pruebas si).
gen_ip es un programa simplista que actualmente es muy quisquilloso con el orden de los argumentos. Primero están los argumentos opcionales:
Genera el paquete y luego lo convierte en un fragmento con el offset y la longutud especificados.
Activa el bit `More Fragments' del paquete.
Especifica la dirección MAC de origen del paquete.
Especifica el campo TOS del paquete (de 0 a 255).
Ahora vienen los argumentos obligatorios:
La dirección IP de origen del paquete.
La dirección IP de destino del paquete.
Longitud total del paquete, incluyendo las cabeceras.
Número de protocolo del paquete, p.ej. 17 = UDP.
Además, los argumentos dependen del protocolo: para UDP (17), están los puertos de origen y destino. Para ICMP (1), están el tipo y código del mensaje ICMP: si el tipo es 0 u 8 (ping-reply o ping), se requieren dos argumentos adicionales (los campos ID y secuencia). Para TCP, se requieren los puertos de origen y destino, y los flags ("SYN", "SYN/ACK", "ACK", "RST" o "FIN"). Hay tres argumentos opcionales: "OPT=" seguido de una lista de opciones separadas por comas, "SYN=" seguido de un número de secuencia, y "ACK=" seguido de un número de secuencia. Finalmente, el argumento opcional "DATA" indica que el cuerpo del paquete TCP tiene que llenarse con los contenidos de la entrada estándar.
Puede ver los paquetes IP utilizando `rcv_ip', que imprime la línea de comandos lo más parecidamente posible al valor original que se le pasó a gen_ip (los fragmentos son una excepción).
Esto es extremadamente útil para analizar paquetes. Recibe dos argumentos obligatorios:
El tiempo máximo en segundos que se esperará a un paquete por la entrada estándar.
El número de paquetes a recibir.
Hay un argumento especial, "DATA", que hace que el cuerpo de un paquete TCP se imprima en la salida estándar después de la cabecera.
La manera estándar de usar `rcv_ip' en un script es como sigue:
# Activa el control de trabajos para poder utilizar & en los scripts. set -m # Espera un paquete desde tap0 durante dos segundos ../tools/rcv_ip 2 1 < /dev/tap0 > $TMPFILE & # Se asegura de que rcv_ip ha comenzado a ejecutarse. sleep 1 # Envía un paquete ping ../tools/gen_ip $TAP1NET.2 $TAP0NET.2 100 1 8 0 55 57 > /dev/tap1 || exit 1 # Espera a rcv_ip, if wait %../tools/rcv_ip; then : else echo rcv_ip failed: cat $TMPFILE exit 1 fi
Este programa toma un paquete (generado con gen_ip, por ejemplo) de la entrada estándar, y lo convierte en un error ICMP.
Recibe tres argumentos: una dirección IP de origen, un tipo y un código. La dirección IP de destino será la IP de origen del paquete recibido desde la entrada estándar.
Éste toma un paquete de la entrada estándar y lo inyecta dentro del sistema mediante un socket raw. Esto da la apariencia de un paquete generado localmente (a diferencia de alimentar un paquete mediante uno de los dispositivos ethertap, que aparentan ser paquetes generados remotamente).
Todas las herramientas asumen que pueden hacerlo todo en una sola lectura o escritura: esto es cierto para los dispositivos ethertap, pero podría no serlo si está haciendo cosas delicadas con tuberías.
Puede utilizar dd para cortar paquetes: dd tiene una opción obs (output block size, o tamaño del bloque de salida) que puede usarse para que produzca el paquete en una sola lectura.
Compruebe primero el funcionamiento correcto: p.ej. al probar que los paquetes se bloquean con éxito. Primero pruebe que los paquetes pasan normalmente, y luego pruebe que algunos paquetes quedan bloqueados. De otra manera, cualquier otro fallo podría estar parando los paquetes...
Trate de escribir pruebas precisas, no pruebas de `enviar cosas al azar y ver lo que pasa'. Si una prueba precisa falla, es útil saberlo. Si una prueba aleatoria falla una vez, no ayuda demasiado.
Si una prueba falla sin dejar un mensaje, puede añadir `-x' en la primera línea del script (es decir, `#! /bin/sh -x') para ver qué comandos está ejecutando.
Si una prueba falla aleatoriamente, compruebe si hay tráfico de red aleatorio interfiriendo (pruebe desactivando todas sus interfaces externas). Un ejemplo: como comparto la misma red con Andrew Tridgell, suelo recibir plagas de broadcasts de Windows.