Si tenéis un router “La Fonera”, con versión del firmware 0.7.1 r2, esto te interesa. Hasta esta versión era muy sencillo acceder al shell por diferentes maneras, pero los de Fon se lo han currado y en la revisión 2 han cerrado muchos agujeros.
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:
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:
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:
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:
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:
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:
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.
Si conocéis a alguien que use Gentoo puede que tengáis que aguantar frases del tipo "todos mis programas están compilados y optimizados a mi sistema", etc. Bueno, pues en Debian podemos tener eso también, o incluso mejor: tener paquetes deb optimizados a nuestra arquitectura. Y lo mejor: sólo para los paquetes que nosotros queramos.
Cómo mantener sincronizados directorios en varios PCs de forma rápida y sencilla utilizando la herramienta libre unison-gtk.
Introducción
Si tienes varios PCs que usas frecuentemente (por ejemplo un portátil y el ordenador de casa o el del trabajo) tal vez te haya surgido la necesidad de tener ciertos directorios con información “sensible” sincronizados entre dichos PCs. Una forma muy sencilla de conseguir eso en GNU/Linux es utilizar la herramienta libre unison.
Ingredientes
unison
unison-gtk
En mi caso concreto, he utilizado la versión 2.9.1, es decir, los paquetes
Tienes que instalar los dos paquetes, ya que aunque unison-gtk necesita de unison, no lo instalará como dependencia. También necesitas ssh.
Una nota importante es que debes instalar la misma versión de unison en todas las máquinas que vayas a sincronizar. Si intentas sincronizar dos máquinas con distintas versiones de unison, se producirá un error y se abortará la sincronización.
Configurando unison
Este paso sólo hay que realizarlo en una de las máquinas. Suponiendo que has instalado unison2.9.1-gtk lo invocas:
javieralso@richie:~$unison-2.9.1-gtk
Esto abrirá la ventana principal de unison-gtk. Ahora debes crear un perfil. Para ello pulsa el botón Create new profile y escribe un nombre para dicho perfil, por ejemplo “Documentos casa”.
Verás que se ha añadido dicho perfil a la lista de perfiles existentes. Si haces doble click te aparecerá una ventana en la que te pedirá que introduzcas el nombre del directorio que deseas sincronizar dentro de tu máquina local. Pon por ejemplo el directorio ~/Documentos. Pulsa en “aceptar” y pasarás a la ventana de selección del directorio con el que deseas sincronizar el directorio anterior.
Utiliza SSH para conectar, selecciona esa opción y elige el directorio en la máquina remota con el que deseas sincronizar tus archivos, por ejemplo ~/Documentos.
En el campo Host escribe IP del host con el que deseas sincronizar o el nombre de la máquina si están en el DNS de tu red. Si el usuario de la máquina remota es distinto del usuario de la máquina local en la que deseas sincronizar, escribe el nombre.
Sincronizando
Con lo anterior unison está configurado y listo para la sincronización. Ahora, en la ventana principal, selecciona el nombre del perfil que quieras. Dependiendo de la versión que tengas instalada, te pedirá la clave del usuario del equipo remoto, bien por consola (desde la que has invocado a unison-gtk) o bien en una ventana emergente. Una vez que introduces dicha contraseña, unison comenzará a escanear todos los archivos y subdirectorios contenidos en el directorio principal. La primera vez puede tardar tiempo. Cuando termine, verás aparecer una lista con todos los archivos y subdirectorios tanto en la máquina local como en la remota. unison hará una propuesta de actualización basada en la antiguedad de los archivos. Intentará que prevalezcan los archivos más modernos frente a los mas antiguos.
Todo ésto se verá con una flecha que indica la dirección en la que se llevará a cabo la actualización. Si hubiese dos archivos o subdirectorios con el mismo nombre y unison no supiese cual de los dos elegir, pondría una interrogación roja entre medias. Puedes cambiar la dirección de sincronización con las teclas de cursor. Cuando estés seguro, pulsa el botón GO y unison comenzará la sincronización.
La primera vez que se lleve a cabo la sincronización, es muy recomendable que uno de los directorios se encuentre completamente vacío; de ese modo se evitan mucho problemas.
Si vives en Ciudad Real (y alrededores) y has sintonizado tu televisión recientemente, te habrás dado cuenta de que existe un nuevo canal en antena: Quijote Información. Yo lo sintonicé hace tiempo (desde su nacimiento, por pura casualidad) y quiero comentar un par de cosas interesantes.
Esto va sobre Ice-E, que es simplemente Ice para dispositivos empotrados. Veamos como configurar el entorno de desarrollo necesario para compilar aplicaciones con Ice-E que funcionen en OpenWRT, concretamente en un MIPS: el de la fonera.
Si usas con frecuencia ssh, habrás notado que muchas veces tarda muchísimo en conectar incluso aunque utilices autenticación por clave pública. Estos son algunos ajustes de configuración que pueden hacer que la conexión sea mucho más rápida.
Acelerando el login
DNS
Si la máquina a la que quieres conectar tiene IP fija, puedes utilizar tu fichero de configuración de ssh para indicar la IP y así te ahorras resolver la dirección de la máquina cada vez que conectes. Para eso, escribes en ~/.ssh/config:
Host example.com
Hostname 208.77.188.166
User Gil.Puertas
Otra cosa que hace SSH y que puede influir mucho en la duración del «login» es la opción «UseDNS». Según dice el manual:
UseDNS specifies whether sshd should look up the remote host name and check that the resolved host name for the remote IP address maps back to the very same IP address. The default is “yes”.
Y claro, si trata de hacer la resolución inversa de una IP de una conexión ADSL puede tardar bastante (suponiendo que pueda). De modo que una buena forma de ahorrar unos valiosos segundos es poner lo siguiente en el /etc/ssh/ssd_config:
UseDNS no
Recuerda que ésta es una cuestión de seguridad que estás decidiendo no usar. La seguridad tiene un coste, pero no tenerla también, tú decides.
GSSAPI
GSSAPI es un API genérico normalizado para usar mecanismos de seguridad como Kerberos o SASL. Por defecto, al menos en Debian, ssh viene configurado para utilizar autenticación GSSAPI. Si no sabías lo que era, lo más probable es que no lo necesites. Así que lo puedes desactivar comentando la línea correspondiente en /etc/ssh/ssh_config:
# GSSAPIAuthentication yes
Esto supone una diferencia considerable en el tiempo de acceso. En una prueba ejecutando un simple “ssh example ls” en una máquina de la misma LAN, el tiempo necesario pasa de 15.2 a 0.1 segundos.
ControlMaster
Si sueles abrir varias sesiones (login, repos, sftp, etc) hacia el mismo servidor, SSH permite reutilizar una conexión establecida para sesiones adicionales. Eso supone un ahorro de tiempo considerable ya que no necesita establecer una nueva conexión. Para ello, simplemente escribe esto en un ~/.ssh/config
Host *
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p
Acelerando la transferencia
Si utilizas SCP o SFTP para copiar ficheros también hay algunas cosas que puedes hacer para mejorar la velocidad.
Compresión
SSH permite comprimir el flujo de datos, que muchas veces viene desactivado por defecto. Tienes que activarlo tanto en el servidor como en el cliente. Para el servidor edita /etc/ssh/sshd_config y añade una línea tal que:
Compression delayed
Es la opción por defecto si no se especifica. Para el cliente puedes activarlo para todo el mundo editando el /etc/ssh/ssh_config:
Compression yes
O que sólo los usuarios que lo deseen escriban esa línea en su ~/.ssh/config.
Comentarios
Si conoces otras formas de mejorar el rendimiento de SSH, por favor, deja un comentario.
Vamos a describir en esta receta algunos de los comandos útiles para lo que se ha venido a denominar traffic shaping, en cristiano, control de nuestro ancho de banda. Aviso a navegantes, este tema es un poco lioso y yo no soy ni mucho menos un experto por lo que, primero, espero comentarios, correcciones, mejoras, etc. y segundo, ojo con lo que haces!!
Enviando paquetes a la red
Bueno vamos con algunos comandos y de paso vamos introduciendo algunos conceptos:
# ip link show
1: lo: <LOOPBACK,UP,10000> mtu 16436 qdisc noqueue
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,10000> mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 00:e0:4c:00:84:bb brd ff:ff:ff:ff:ff:ff
Este comando muestra los “enlaces” presentes en un computador, en esta información va incluida alguna información muy útil, dejando aparte la interfaz loopback, nos centramos en el enlace número dos, es decir la eth0 que es una interfaz ethernet. Despues de la información relativa a la mtu (Maximum transmission unit) que en una ethernet es 1500 tenemos la disciplina de colas (qdisc). Para que nos entendamos, todos los paquetes que se envían son almacenados en un sistema de colas hasta la entrega a la red.
Ahora bien, cómo se gestionan las colas y qué algoritmo se utiliza para decidir qué paquete desencolamos es un mundo un poco complejo que trataremos de introducir en esta receta.
Antes de continuar hay que indicar que, aparte de las colas, están las clases de tráfico y los filtros. Generalmente (esto depende mucho del tipo de colas que estamos usando) se definen clases de tráfico y los filtros clasifican el tráfico en esas clases atendiendo al protocolo, ip, etc..
Tipos de Colas
El algoritmo por defecto es “pfifo_fast”, que es el más sencillo, el primer paquete que llega es el primero que sale y lo más rápido posible, esto no tiene ningún misterio. Con esta política todo el mundo es feliz y todos los paquetes son tratados exactamente igual buscando las máximas prestaciones. No obstante estaremos de acuerdo en que no todas las aplicaciones y ordenadores son de igual importancia por lo que asignar un recurso tan escaso como el ancho de banda, puede ser una buena idea y muy útil.
Hay mas disciplinas de colas, entre las cuales podemos enumerar:
FIFO – simple FIFO (packet (p-FIFO) or byte (b-FIFO) ): la que hemos visto, tambien hay ha nivel de byte.
PRIO – n-band strict priority scheduler: En esta disciplina tenemos un sistemas de encolado basado en clases de tráfico a las cuales se les asigna una prioridad, Las clases de tráfico son desencoladas en funcíon de la prioridad (el 0 es la mayor prioridad y cuanto mayor es el número menor prioridad).
TBF – token bucket filter: Esta es una disciplina para establecer límites en el ratio de entrega de paquetes para las distintas colas. Si quieres limitar el ancho de banda de una interfaz, esto es lo que necesitas.
CBQ – class based queue: Otro sistema basado en colas un poco mas complejo que el PRIO, aquí puedes establecer jerarquías de clases y prioridades. Hay que resaltar que dentro de cada una de las clases hay una qdisc que, por defecto es una pfifo pero que puede ser configurada por lo que la cantidad de combinaciones es enorme.
CSZ – Clark-Scott-Zhang: Para que nos entendamos garantiza el ancho de banda de los servicios garantizados y el resto lo deja para los paquetes que no se clasifican (best-effort traffic), la teoría de esto es compleja.
SFQ – stochastic fair queue: Tienes diferentes colas asociadas a flujos y vas sacando de cada cola un paquete a la vez (round robin) para que todas los flujos tengan el mismo ancho de banda, el tema es que si una aplicación establece muchos flujos obtiene mas ancho de banda.
RED – random early detection: Esto esta diseñado para backbones, el tema es que trata de aprovechar las características de control de flujo del protocolo TCP para ajustar los parámetros de entrega de los paquetes y evitar la congestión antes de que se produzca. Lo que hace es eliminar aleatoriamente paquetes cuando las colas empiezan a llenarse, cuanto mas llena esta la cola, va aumentando la probabilidad de eliminar un paquete de forma aleatoria. TCP cuando pierde paquetes reduce su tasa de envío por lo que reduce la posibilidad de congestiones, hay que ajustar muy bien los valores para que no perdamos mas paquetes de los que perderíamos en congestión (vamos eliminando paquetes por que la red no da mas de si). Esto plantea un problema ya que UDP no implementa un mecanismo similar con lo que los flujos UDP no se ajustan.
GRED – generalized random early detection: El tema es que RED descarta aleatoriamente paquetes cuando hay una posible congestión y de forma aleatoria tratando todos los flujos igual, como en el campo del señor no todos somos iguales, GRED crea una serie de colas virtuales y establece políticas RED distintas (como por ejemplo la probabilidad de eliminar un paquete cuando se empieza a llenar la cola) a cada una de ellas.
ATM – asynchronous transfer mode: Esto es para que emules el comportamiento de una red ATM transmitiendo unidades de información en celdas.
DSMARK – DSCP (Diff-Serv Code Point)marker/remarker: Esto mas que una disciplina es una política de marcado de paquetes en función de reglas específicas.
Hierarchical Token Bucket (HTB): Podemos dividir el ancho de banda especificando el mínimo y el máximo, si alguien no esta usando su ancho de banda, se asigna al resto de clases. Este se considera mas sencillo que el CBQ y bastante flexible por lo que lo usaremos para los ejemplitos.
La herramienta tc: comándos básicos
Vamos con algunos comandos, de aqui en adelante si queremos ver como van nuestras colas:
Este primer comando define una cola que se añade a la raiz (root) con un manejador handle 1: y que
por defecto manda el tráfico a la clase de tráfico 1.
Ahora creamos la clase de tráfico:
$tc class add dev eth0 parent 1: classid 1:1 htb rate 1kbps ceil 5kbps
Para esta clase de tráfico, el padre es la qdisc que acabamos de crear (parent 1:) y cuyo identificador es 1 (classid 1:1). Por último, la parte de comando que delimita el ancho de banda que pueden consumir viene determinado por la parte del comando “rate 1kbps ceil 5 kbps” que le dice al kernel, que, asegure una tasa de 1kbps en caso de congestión y que como mucho esa clase puede llegar a 5 kbps. Si no ponemos la parte ceil, la clase consumirá todo el ancho de banda sobrante que quede (esto es así por que estamos usando HTB).
En teoría ya esta todo, al indicarle al crear la cola que la clase por defecto es la 1, todo el tráfico es dirigido a esa clase que ya esta limitada. Ahora bien, si queremos indicarle explícitamente que mande todo el tráfico ip a esa clase debemos crear un filtro:
$tc filter add dev eth0 protocol ip parent 1: handle 1 fw classid 1:1
De nuevo le indicamos que el parent es la qdisc htb root (parent 1:), el manejador de este filtro es el 1 y la acción es forwardear todo el protocolo ip (protocol ip) a la clase 1:1 (fw classid 1:1).
Varios temas, primero sólo podemos controlar el tráfico que sale por eth0, para controlar el tráfico de entrada hay que trabajar con la cola de entrada (ingress). A menos que estes probando cosas, es recomendable meter tu configuración (lista de comandos) en un script ya que es frecuente cometer errores, y aunque se pueden cambiar las especificaciones, muchas veces puede ser lioso.
Viendo como va nuestra configuración
Si queremos ver como va nuestra configuración de filtros:
#tc filter show dev eth0
filter parent 1: protocol ip pref 49152 fw
filter parent 1: protocol ip pref 49152 fw handle 0x1 classid 1:1
Nuestras clases:
#tc class show dev eth0
class htb 1:1 root prio 0 rate 8000bit ceil 40000bit burst 1603b cburst 1619b
El rate es en bit, le pusimos 1kb es decir 1000*8 bits (lo coge en bytes).
Y las colas:
#tc qdisc show dev eth0
qdisc htb 1: r2q 10 default 1 direct_packets_stat 294
Cada sistema de colas diferentes tiene comandos y parámetros específicos , en algunos casos puedes añadirle a las clases de tráfico qdisc propias que tienen nuevas clases (en forma de árbol) por lo que las combinaciones son múltiples.