Como se explicó en la sección de disciplinas de cola con clases, se necesitan filtros para clasificar los paquetes en cualquiera de las subcolas. Estos filtros se llaman desde dentro de las qdisc con clases.
Aquí tiene una lista incompleta de los clasificadores disponibles:
Basa la decisión en la forma en que el cortafuegos ha marcado el paquete. Es una manera sencilla si no quiere aprender la sintaxis de filtros de tc. Vea el capítulo de Colas para más detalles.
Basa la decisión en campos del interior del paquete (dirección IP de origen, etc)
Basa la decisión en la ruta a la que será enviado el paquete. Bases the decision on which route the packet will be routed by
Encamina los paquetes basándose en RSVP . Sólo es útil en las redes que usted controle (Internet no respeta RSVP).
Se usa con la qdisc DSMARK. Vea la sección relevante.
Fíjese que en general hay muchas maneras de clasificar los paquetes y que generalmente el sistema de que desea usar se reduce a sus preferencias.
En general los clasificadores aceptan unos pocos argumentos comunes. Aparecen aquí por conveniencia:
El protocolo que aceptará este clasificador. Generalmente sólo querrá aceptar tráfico IP. Se requiere.
El controlador al que estará asociado este clasificador. Este controlador debe ser una clase ya existente. Requerido.
La prioridad de este clasificador. Los números más bajos se comprueban antes.
Este controlador significa cosas diferentes para filtros diferentes.
Todas las secciones que siguen asumen que está intentando dar forma al tráfico que va hacia MáquinaA. Asumen que se ha configurado la clase raíz en 1: y que la clase a la que desea enviar el tráfico elegido es 1:1.
El filtro U32 es el más avanzado disponible en la implementación actual. Se basa completamente en tablas hash, lo que lo hace robusto cuando hay muchas reglas de filtrado.
En su forma más simple el filtro U32 es una lista de registros, consistente cada una en dos campos: un selector y una acción. Los selectores, descritos más adelante, se comparan con el paquete IP que se está procesando hasta encontrar la primera coincidencia, y entonces se ejecuta la acción asociada. El tipo más sencillo de acción sería dirijir el paquete en una clase CBQ definida.
La línea de órdenes del programa tc filter, que se usa para configura el filtro, consiste en tres partes: especificación del filtro, selector y acción. La especificación del filtro puede definirse así:
tc filter add dev IF [ protocol PROTO ]
[ (preference|priority) PRIO ]
[ parent CBQ ]
El campo protocol describe el protocolo al que se aplicará el filtro. Sólo comentaremos el caso del protocolo ip. El campo preference (alternativamente se puede usar priority) establece la prioridad del filtro escogido. Esto es importante, porque puede tener varios filtros (listas de reglas) con diferentes prioridades. Se pasará por cada lista en el orden en que se agreguen las reglas, y entonces se procesarán las listas de menor prioridad (numero "preference" más alto). El campo parent define la cima del árbol CBQ (por ejemplo, 1:0), a la que se asociará el filtro.
Las opciones descritas anterioremente se aplican a todos los filtros, no sólo a los U32.
El selector U32 contiene definiciones de los patrones, que serán comparados con el paquete procesado en cada momento. Para ser más precisos, define qué bits hay que comparar en la cabecera del paquete y nada más, pero este método sencillo es muy poderoso. Veamos los ejemplos siguientes, tomados directamente de un filtro muy complejo, del mundo real:
# tc filter add dev eth0 protocol ip parent 1:0 pref 10 u32 \ match u32 00100000 00ff0000 at 0 flowid 1:10
Por ahora, olvidémonos de la primera línea (todos estos parámetros describen las tablas hash del filtro). Centrémonos en la línea del selector, que contiene la palabra clave match. Este selector coincidirá con cabeceras IP cuyo segundo byte sea 0x10 (0010). Como puede adivinar, el número 00ff es la máscara de comparación, que le dice al filtro qué bits exactamente tiene que comparar. Aquí es 0xff, de manera que el byte coincidirá si es exactamente 0x10. La clave at indica que la coincidencia debe comenzar en un desplazamiento específico (en bytes) (en este caso, al principio del paquete). Traduciendo todo esto a lenguaje humano, el paquete coincidirá si su campo Tipo de Servicio tiene los bits de «poco retraso» activos. Analicemos otra regla:
# tc filter add dev eth0 protocol ip parent 1:0 pref 10 u32 \ match u32 00000016 0000ffff at nexthdr+0 flowid 1:10
La opción nexthdr indica la siguiente cabecera encapsulada en el paquete IP, esto es, la cabecera del protocolo de la capa superior. La coincidencia también debe empezar al principio de la siguiente cabecera. La coincidencia debería ocurrir en la segunda palabra de 32 bits te la cabecera. En los protocolos TCP y UDP este campo contiene el puerto de destino del paquete. El puerto se da en formato big-endian, es decir, los bits más significativos primero, de manera que simplemente leemos 0x0016 como 22 decimal, lo que indicaría el servicio SSH si fuera TCP. Como puede adivinar, esta coincidencia es ambigua sin un contexto, y de eso hablaremos más tarde.
Habiendo entendido todo lo anterior, encontraremos fácil de leer el siguiente selector: match c0a80100 ffffff00 at 16. Lo que tenemos aquí es una coincidencia de tres bytes partiendo del decimoséptimo byte, contando desde el principio de la cabecera IP. Coincidirá con los paquetes cuya dirección de destino sea cualquiera dentro de la red 192.168.1/24. Tras analizar los ejemplo, podemos resumir lo que hemos aprendido.
Los selectores generales definen el patrón, máscara y desplazamiento del patrón que será comparado con el contenido del paquete. Usando los selectores generales se puede coincidir con virtualmente cualquier bit de la cabecera IP (o capas superiores). Sin embargo, son más difíciles de leer y escribir que los selectores específicos descritos más adelante. La sintaxis general del selector es:
match [ u32 | u16 | u8 ] PATRON MASCARA [ at DESPL | nexthdr+DESPL]
Una de las palabras clave u32, u16 o u8 especifica la longitud en bits de los patrones. Deberían seguirle PATRON y MASCARA, de la longitud definida por la palabra clave anterior. El parámetro DESPL es el desplazamiento, en bytes, desde donde empezar a comparar. Si se da la palabra clave nexthdr+, el desplazamiento es relativo al inicio de una cabecera de capa superior.
Algunos ejemplos:
# tc filter add dev ppp14 parent 1:0 prio 10 u32 \
match u8 64 0xff at 8 \
flowid 1:4
Un paquete coincidirá con esta regla si su tiempo de vida (TTL) es 64. TTL es el campo que empieza justo después del octavo byte de la cabecera IP.
# tc filter add dev ppp14 parent 1:0 prio 10 u32 \
match u8 0x10 0xff at nexthdr+13 \
protocol tcp \
flowid 1:3
FIXME: se nos ha indicado que esta sintaxis ya no funciona.
Use esto para capturar los ACK en paquetes menores de 64 bytes:
## captura de acks a la manera difícil:
## IP protocol 6,
## IP header length 0x5(32 bit words),
## IP Total length 0x34 (ACK + 12 bytes of TCP options)
## TCP ack set (bit 5, offset 33)
# tc filter add dev ppp14 parent 1:0 protocol ip prio 10 u32 \
match ip protocol 6 0xff \
match u8 0x05 0x0f at 0 \
match u16 0x0000 0xffc0 at 2 \
match u8 0x10 0xff at 33 \
flowid 1:3
Esta regla sólo coincidirá con paquetes TCP cuando esté activo el bit ACK, y no haya contenido. Aquí podemos ver un ejemplo de uso de dos selectores, siendo el resultado final el AND lógico de sus resultados. Si echamos un vistazo al diagrama de la cabecera TCP, podemos ver que el bit ACK es el tercer bit de más peso (0x10) en el catorceavo byte de la cabecera TCP (at nexthdr+13). En lo que respecta al segundo selector, si quisiéramos hacernos la vida más complicada, podríamos escribir match u8 0x06 0xff at 9 en lugar de usar el selector específico protocol tcp, porque 6 es el número del protocolo TCP, presente en el décimo byte de la cabecera IP. Por otro lado, en este ejemplo no podríamos usar selectores específicos para la primera coincidencia (simplemente porque no hay selectores específicos para el bit ACK de TCP).
La siguiente tabla contiene una lista de todos los selectores específicos que ha encontrado el autor de esta sección en el código fuente del programa tc. Simplemente te hacen la vida más sencilla e incrementan la legibilidad de la configuración de los filtros.
FIXME: aquí iría la tabla (la tabla está en un fichero aparte, "selector.html"
FIXME: y todavía está en polaco :-(
FIXME: debe ser sgmlizada
Algunos ejemplos:
# tc filter add dev ppp0 parent 1:0 prio 10 u32 \
match ip tos 0x10 0xff \
flowid 1:4
FIXME: el filtro tcp dst no funciona como se describe:
La regla anterior coincidirá con paquetes que tengan el campo TOS a 0x10. El campo TOS empieza en el segundo byte del paquete y es de un byte de largo, de manera que podríamos escribir un selector general equivalente: match u8 0x10 0xff at 1. Esto nos da una pista de las interioridades del filtro U32 (las reglas específicas siempre se traducen a generales, y es de esta manera que se almacenan en la memoria del núcleo). Lo que nos lleva a otra conclusión: los selectores tcp y udp son exactamente el mismo, y ésta es la razón de que no podamos usar un único selector match tcp dst 53 0xffff para capturar paquetes TCP enviados a dicho puerto (también coincidiría con los paquetes UDP). También debe recordar especificar el protocolo y terminará con la siguiente regla:
# tc filter add dev ppp0 parent 1:0 prio 10 u32 \
match tcp dst 53 0xffff \
match ip protocol 0x6 0xff \
flowid 1:2