Marcar y clasificar tráfico con iptables y tc

networkingArco

Siguiendo el hilo de la receta anterior, vamos a ver cómo podemos clasificar el tráfico que generamos para meterlos en las colas que vamos a crear y así clasificar el tráfico. Para ello, aunque existen multitud de formas de clasificar el tráfico vamos a utilizar el campo TOS (type of service) del protocolo IP.

Clasificando paquetes

Bueno, esta claro que si queremos establecer clases de tráfico podemos hacer dos cosas, una marcar el tráfico de paquetes en el origen y sólo clasificar en el nodo que hace de enlace con, por ejemplo, Internet y otra, no marcar en el origen y filtrarlo (ademas de clasificar) todo en el nodo que hace de enlace.

Si nos imaginamos un nodo con dos interfaces, una conectada a Internet y otra a una red ethernet través de la cual se conectan otros nodos podemos establecer reglas de marcado en esos nodos mientras que en el enlace simplemente clasificamos el tráfico que le llega en el sistema de colas.

El problema de tener que marcar en el origen, es que pueden existir nodos que no marcan sus paquetes o que los marcan mal para obtener el ancho de banda asociado a un tráfico de prioridad mas alta. Vamos a considerar que todos los nodos son buenos y marcan sus paquetes.

Para marcar un paquete debemos usar iptables. Si observamos una regla de iptables para marcar paquetes:
#iptables -t mangle -I POSTROUTING 1 -p tcp -s 111.11.11.105 -j TOS --set-tos 16

Vemos que lo primero que nos encontramos es el "-t mangle" , que le indica la tabla dónde vamos a operar, por la tabla mangle pasan todos los paquetes por lo que no se nos escapa ninguno, si quieres ver una descripción de las tablas, y su uso mira aquí.

Lo siguiente que viene es "-I POSTROUTING" que nos indica dónde vamos a aplicar la clasificación, como hemos dicho antes, estamos marcando el tráfico que el nodo genera por lo que lo marcamos despues del enrutado de los paquetes. En este punto hay que hacer una pequeña parada, el sitio ideal para marcar el paquete que ha sido originado en un sistema es en OUTPUT, ya que por ahí pasa todo el tráfico generado en un nodo, no obstante a mi me interesa hacerlo en POSTROUTING por que me interesa marcar tráfico que pasa por mi sistema y que no esta marcado (cosas del curro:-)).

El 1 que viene a continuación es el número de la regla que vas a crear, acuerdate de esto si quieres borrarla luego.

A continación vienen las reglas que debe cumplir el paquete para marcarlo, en nuestro caso buscamos todo el tráfico tcp que viene de la dirección 111.11.11.105, "-p tcp -s 111.11.11.105". Y por último especificamos qué queremos hacer con esos paquetes, en nuestro caso vamos a poner el valor 16 en el campo TOS.

Si queremos ver como queda la regla despues de que la ejecutemos en nuestro sistema:
# iptables -L -t mangle
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
TOS tcp -- 111.11.11.105 anywhere TOS set Minimize-Delay

Para borrar todas las reglas de marcado, en el caso de la tabla mangle:

#iptables -F -t mangle

Obviamente podemos especificar el marcado de los paquetes como queramos y atendiendo a multitud de parámetros. Veamos algunos ejemplos:

Especificar que todo el tráfico de salida de un host que sale del puerto 12345 se marque con el valor 4 en el campo TOS:

#iptables -t mangle -I OUTPUT -p tcp --sport 12345 -s localhost -j TOS --set-tos 4

En general, despues de la opción -p puedes poner cualquier tipo de protocolo (si esta incluido en /etc/protocols), tambien existe la posibilidad de marcar los paquetes que van a un destino específico (con -d), que entraron por un interfaz específico o van a salir etc. existen módulos asociados a protocolos que enriquecen las posibilidades, pero vamos estudiando un poco seguro que puedes marcar y filtrar lo que quieras.

Por ejemplo un paquete muy majo es este que te permite filtrar de forma cómoda por protocolos de la capa de aplicación y habilitar reglas como esta:
#iptables -t mangle -A FORWARD -p tcp -m ipp2p --kazaa ... acción

Vamos, te marca los paquetes de kazza.

Creando colas

Como vimos en la receta anterior, para crear colas, usamos la herramienta tc.
Por ejemplo si queremos establecer cuatro colas, cada una para un tipo de tráfico distinto, y que tengan el mismo ancho de banda, una estructura como esta sería apropiada:

#tc qdisc add dev eth0 root handle 1: htb default 1
#tc class add dev eth0 parent 1: classid 1:1 htb rate 3125kbps
#tc class add dev eth0 parent 1: classid 1:2 htb rate 3125kbps
#tc class add dev eth0 parent 1: classid 1:3 htb rate 3125kbps
#tc class add dev eth0 parent 1: classid 1:4 htb rate 3125kbps

Tal y como hemos creado las estructuras, el ancho de banda es dividido, es necesario resaltar que para que compartieran el ancho de banda deberíamos crear una cola hija de root de la cual "colgar" la clasificación. De esta forma si una clase de tráfico no ocupa su ancho de banda, el que sobra, es repartido en las otras clases de tráfico.

Nuestras colas, quedan, por lo tanto:

#tc qdisc show dev eth0
class htb 1:1 root prio 0 rate 25000Kbit ceil 25000Kbit burst 14096b cburst 14096b
class htb 1:2 root prio 0 rate 25000Kbit ceil 25000Kbit burst 14096b cburst 14096b
class htb 1:3 root prio 0 rate 25000Kbit ceil 25000Kbit burst 14096b cburst 14096b
class htb 1:4 root prio 0 rate 25000Kbit ceil 25000Kbit burst 14096b cburst 14096b
qdisc htb 1: r2q 10 default 1 direct_packets_stat 0

Clasificando paquetes

Una vez que tenemos el tráfico marcado y las clases de tráfico creado, debemos establecer las reglas para encolar el tráfico en su clase correspondiente, dentro de la clasificación de colas preestablecida.

Para ello, de nuevo utilizamos la herramienta tc:

#tc filter add dev eth0 parent 1:0 protocol ip prio 10 u32 match ip tos 0x10 0xff flowid 1:4
#tc filter add dev eth0 parent 1:0 protocol ip prio 9 u32 match ip tos 0x08 0xff flowid 1:3
#tc filter add dev eth0 parent 1:0 protocol ip prio 8 u32 match ip tos 0x04 0xff flowid 1:2
#tc filter add dev eth0 parent 1:0 protocol ip prio 7 u32 match ip tos 0x02 0xff flowid 1:1

Con estas instruciones le indicamos que vamos a crear un filtro "tc filter" y asociarlo a la interfaz eth0 "add dev eth0" y a la clase root "parent 1:0" (la qdisc que hemos creado antes). Este filtro es sobre el protocolo ip "protocol ip" y le fijamos una prioridad para indicar en que orden se aplican los filtros "prio 10" (mayor número, mayor prioridad). A continuación viene qué condiciones debe cumplir nuestro paquete (con el filtro u32), en nuestro caso, como hemos utilizado el campo TOS, lo especificamos con "match ip tos 0x10 0xff" y por último el flujo al que pertenece si cumple los criterios "flowid 1:4".

Si queremos ver que todo se ha configurado bien:
# tc filter show dev eth0
filter parent 1: protocol ip pref 7 u32
filter parent 1: protocol ip pref 7 u32 fh 803: ht divisor 1
filter parent 1: protocol ip pref 7 u32 fh 803::800 order 2048 key ht 803 bkt 0 flowid 1:1
match 00020000/00ff0000 at 0
filter parent 1: protocol ip pref 8 u32
filter parent 1: protocol ip pref 8 u32 fh 802: ht divisor 1
filter parent 1: protocol ip pref 8 u32 fh 802::800 order 2048 key ht 802 bkt 0 flowid 1:2
match 00040000/00ff0000 at 0
filter parent 1: protocol ip pref 9 u32
filter parent 1: protocol ip pref 9 u32 fh 801: ht divisor 1
filter parent 1: protocol ip pref 9 u32 fh 801::800 order 2048 key ht 801 bkt 0 flowid 1:3
match 00080000/00ff0000 at 0
filter parent 1: protocol ip pref 10 u32
filter parent 1: protocol ip pref 10 u32 fh 800: ht divisor 1
filter parent 1: protocol ip pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:4
match 00100000/00ff0000 at 0
#

Comprobando que todo funciona

Vale, y todo esto, ¿cómo comprobamos que funciona?, bueno, hay un script en perl que te permite visualizar las clases de tráfico que hay en tu sistema, el dispositvo y el tráfico que entra por cada clase en tiempo real:

#./monitor_tc_top.pl
18:49:55 up 1 day, 2:09, 5 users, load average: 0.20, 0.17, 0.17
Interval Cumulated Total
Dev Classid Tokens Ctokens Rate Speed Send Send
-------------------------------------------------------------------------
eth0 1:1 4558 4558 24.47KB 147B/s 103.17KB 333.33KB
eth0 1:2 4620 4620 0B 0B/s 0B 0B
eth0 1:3 4620 4620 0B 0B/s 0B 0B
eth0 1:4 4620 4620 0B 0B/s 0B 0B

Puedes bajártelo de aquí. El script no está mantenido pero de momento funciona bastante bien. Si observais, en la ejecución del comando sólo va tráfico a la clase 1 que es por defecto, se pueden generar tráfico con una herramienta (tipo scapy) para comprobar qué tráfico va a cada una de las colas.

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de david.villa

trickle

trickle es un bandwidth shaper en espacio de usuario. Evidentemente no es tan profesional como lo que tu cuentas pero es una herramienta bastante útil. Y también puede venir bien para hacer pruebecillas de shaping, calidad de servicio y estas cosillas.

No soy portavoz de ningún colectivo, grupo o facción. Mi opinión es personal e intransferible.

Imagen de magmax

Trickle...

A lo mejor no lo usé bien, pero haciendo pruebas con trickle lo único que conseguí fue que la CPU se me pusiera al 100% y que la red me fuera fatal (vaaaaaale: esto último era lo que yo pretendía; total, sólo era una prueba).

Supongo que las iptables serán un poco más amigables con mi pobre CPU...

Miguel Ángel García
http://magmax.org

Imagen de arturo

Tan sólo decir que htb

Tan sólo decir que htb funciona bastante bien, pero que en la práctica el que mejor funciona es cbq.

Un saludo, Arturo.

**********************************************************************************
Hay tontos que tontos parecen, hay tontos que tontos son, pero
hay una clase peor de tontos que hacen parecer tontos a los que
listos son.
**********************************************************************************

**********************************************************************************
Hay tontos que tontos parecen, hay tontos que tontos son, pero
hay una clase peor de tontos que hacen parecer tontos a los que
listos son.
*****************************