parando un DoS con nada

10 de julio de 2009

Hay situaciones en las que se produce un ataque de DoS y no tenemos nada para pararlo, o al menos, no tenemos el suficiente control sobre los servidores para detener el ataque. La manera más fácil de denegar las IPs de maquinas que nos atacan es utilizar una cosas que se llama null-route. Es decir, enviar los paquetes a una ruta sin salida.
He de suponer que no tenemos iptables, que no tenemos control sobre los firewall externos, que no tenemos control sobre apache o postfix... solo somos unos pobres admins que nos dedicamos a controlar el estado de la máquina.

Es fácil ver que algo está pasando con un "netstat". Sobre todo cuando tenemos decenas de IPs iguales (DoS) o diferentes (DDoS) conectadas, en un estado de estar pero sin estar: SYN o un SYN_RECV.

Para bannear una IP de estas con un null-route basta con enviar los paquetes de vuelta hacia esa IP por la interfaz de loopback. Supongamos que el ataque viene de 89.140.142.56:

# route add 89.140.142.56 lo

Y ya está. Sin reiniciar, sin iptables, sin tcpwrappers, sin tocar el pix, sin tocar el router... Más información:
- parando un DoS con iptables

mi receta para dom4j

9 de julio de 2009

Hace ya una semana que se publicó un parche para todas las versiones de Zimbra como solución a un bug grave. Lo normal para arreglar bugs era esperar a una nueva versión. Desde la versión 3 solo recuerdo haber añadido un parche de urgencia.

Llevo varios días con el parche instalado y la verdad es que todo funciona igual (es decir, de puta madre). Por lo que he podido ver en el desempaquetado del Jar, el problema debe ir por algún tipo de injección XPath, que tal como dice el descubridor, permite el acceso no autorizado a los archivos situados en el store del Zimbra.

Esta es mi receta de pasos para un Zimbra 5.0.16 bajo CentOS 5. Notar que hay dos archivos Jar para cambiar:

(creamos una carpeta de backup y paramos Zimbra)
# mkdir /backup
# su - zimbra
# zmcontrol stop
# exit
# cd /tmp

(descargamos el patch)
# wget http://files.zimbra.com/downloads/security/dom4j-1.5.jar

(dentro de Zimbra hay dos archivos dom4j-1.5.jar y comprobamos que sean el mismo)
# md5sum /opt/zimbra/lib/jars/dom4j-1.5.jar
# md5sum /opt/zimbra/jetty-6.1.5/common/lib/dom4j-1.5.jar

(hacemos un backup y los sustituimos)
# cp /opt/zimbra/lib/jars/dom4j-1.5.jar /backup
# cp /tmp/dom4j-1.5.jar /opt/zimbra/lib/jars/
# cp /tmp/dom4j-1.5.jar /opt/zimbra/jetty-6.1.5/common/lib/

(les ponemos permisos y arrancamos Zimbra)
# chown zimbra:zimbra /opt/zimbra/lib/jars/dom4j-1.5.jar
# chown zimbra:zimbra /opt/zimbra/jetty-6.1.5/common/lib/dom4j-1.5.jar
# su - zimbra
# zmcontrol start

Más información:
- Una nueva herramienta desde los mandriles

dónde está cada cosa

8 de julio de 2009

Tanto si elegimos una distribución de Zimbra en Ubuntu/Debian como en RedHat/Fedora, encontraremos dentro de la instalación una carpeta llamada /packages. En esta carpeta están todos los archivos necesarios para la instalación de Zimbra en formato binario .deb si bajamos un Ubuntu o .rpm si bajamos una RedHat. Es curioso como como por cada versión va y va creciendo el tamaño de estos paquetes.
¿Alguien ha mirado que hay dentro de cada paquete? ¿qué archivos instala cada paquete?

Esto es un resumen de lo que hay dentro de cada uno de los paquetes .rpm para una versión 5.0.16.

+ zimbra-apache...rpm: Solo encontramos los archivos de Apache HTTP 2.2.8 y sus archivos de configuración.

+ zimbra-core...rpm: Este es el paquete que más cosas instala. Instala los script bashrc y profile del usuario Zimbra, la carpeta bin, conf, CURL 7.18.1, Cyrus-SASL 2.1.22, docs, Heimdal 1.2, el JDK 1.5, la carpeta libexec, OpenLdap Libs 2.3.43, Openssl 0.9.8, Sleepycat 4.2.52, Tcmalloc 0.97 y Zimbramon.

+ zimbra-ldap...rpm: OpenLDAP 2.3.43

+ zimbra-logger...rpm: Instala el logger con un MySQL 5.0.67

+ zimbra-mta...rpm: Amavis-new 2.5.4, ClamAv 0.94.1 y Postfix 2.4.7

+ zimbra-proxy...rpm: memcache 1.2.5 y nginx 0.5.30

+ zimbra-snmp...rpm: net-snmp 5.4.1

+ zimbra-spell...rpm: aspell 0.60.6

+ zimbra-store...rpm: Jetty 6.1.5, MySQL 5.0.67, la wiki y los zimlets.

Como cosa curiosa ver que MySQL se instala dos veces: una para el store y otra para el logger. Una cosa es que tengamos dos instancias del mismo software corriendo, pero ¿instalar dos veces todos los binarios de MySQL?.

este finde estoy disponible (ii de ii)

6 de julio de 2009

Para maximizar la disponibilidad (hacerla tender a 100%) hay que minimizar el riesgo. Hay que tener bien claro cuales pueden ser los posibles fallos de mi sistema, cual es la probabilidad que esos fallos se produzcan y cuales son los impactos en mi sistema de cada uno de esos fallo.
El problema es la aparición de la palabra "probabilidad". ¿Como puedo formular una probabilidad de algo que aun no ha pasado?.

Esto es un pequeño ejemplo de un "calculo de riesgo (relativo)" en un servicio de correo electrónico. Naturalmente es solo una base, ya que dentro de un calculo de riesgo existen varios métodos predictivos e infinidad de variables de riesgo.

Supongamos que tenemos un sistema de correo en el cual, después de un estudio hemos llegado a la conclusión de que solo existen dos posibles fallos de riesgo (naturalmente son muchos más).
Una rotura de disco SCSI que hemos llegado a la conclusión de que es poco probable y por tanto tiene una probabilidad de 0,2. Otro posible fallo es la caída de la linea de Internet que esto es más frecuente con una probabilidad de 0,8.
Por otro lado hemos llegado a la conclusión que la rotura de disco tiene un impacto catastrófico ya que no tenemos RAID. Por tanto el impacto en una escala de 10 sería un 9. Para el caso de la caída de Internet, tenemos un impacto de 2 ya que tenemos una linea de Internet redundante y con un simple cambio volvemos a tener conexión.

                   Prob.    Impac.
rotura disco       0,2      9
caida de internet  0,8      2
Si realizamos este cálculo:
0,2 * 9 = 1,9 riesgo
0,8 * 2 = 1,6 riesgo
Viendo los resultados vemos que la rotura de disco me supone un mayor riesgo y por tanto debería reducir al máximo mi riesgo.
La probabilidad de que se produzca un fallo es de 0,2. Esta probabilidad es imposible cambiarla ya que es inherente al propio hardware, en este caso un disco SCSI. Lo que si puedo minimizar es el impacto si en vez de utilizar un disco SCSI, utilizo dos discos SCSI en RAID y por otro lado realizo copias de seguridad diarias. Si implantamos todo esto vemos que el impacto de la rotura de un disco pasa de 9 a 4. Si volvemos hacer nuestro análisis de riesgo tenemos que ahora (0,2*4=0,8) la caída de la linea de Internet tiene un riesgo mayor.

este finde estoy disponible (i de ii)

4 de julio de 2009

Uno de los parámetros que se pueden medir matemáticamente a la hora de montar nuestro servicio IT es la disponibilidad, la fiabilidad y la mantenibilidad. Todos ellos están relacionados con el tiempo de funcionamiento de nuestro servicio. Es decir, contra menos tiempo parado pase nuestro servicio, más disponible, más fiable y menos mantenible es.
Debemos distinguir entre el tiempo de parada debido a una incidencia (por ejemplo, una caída de Internet, un disco roto, una excepción de programación no controlada, etc) y el tiempo de parada debido a un mantenimiento (actualización mensual del software, un reboot programado, etc). Todo el tiempo de mantenimiento programado no debe contabilizarse desde de la disponibilidad, fiabilidad o mantenibilidad, ya que lo que queremos calcular es el tiempo de paradas no previstas y que por tanto, pueden afectar a la calidad del servicio por lo cual el cliente está pagando.

Una parada programada no afecta a la calidad del servicio ya que el cliente en su contrato ya sabe de la existencia de tantas paradas programadas al mes (por ejemplo el servicio de correo puede sufrir 1 una parada programada al mes de no más de 5 minutos).

Como hemos dicho tenemos tres valores para calcular:

+ Disponibilidad o availability: porcentaje de tiempo activo frente a tiempo inactivo.

+ Fialibilidad o reliability: lapso de tiempo entre fallos de servicio o componentes. Este valor nos lo da el MTBS (Mean Time Between Failures o Tiempo medio entre fallos).

+ Mantenibilidad o maintainability: lapso de tiempo para reparar el servicio o componente. Este valor nos lo da el MTRS (Mean Time to Restore Service o Tiempo medio de restauración del servicio).

Supongamos que tenemos un servicio de correo electrónico con un servidor Zimbra y que durante un año estos han sido los downtimes del servicio:

05/03/2008 -> 1h de caída del servicio
16/06/2008 -> 2h de caída del servicio
01/08/2008 -> 0,5h de caída del servicio
23/11/2008 -> 8h de caída del servicio
24/11/2008 -> 2h de caída del servicio

5 paradas de 13,5 horas de caída del servicio
Horas de un año: 365 dias * 24h = 8760h

Calculamos pues la disponibilidad, la fiabilidad y la mantenibilidad:

D = ( (8760-13,5)/8760 ) * 100% =  99,8% (disponibilidad)
MTBF = (8760-13,5)/5 =  1749h entre cada fallo (tiempo medio entre fallo)
MTRS = 13,5/5 = 2,7h de reparación (tiempo medio reparación)
Ahora la pregunta es: ¿esto es malo?, ¿el cliente podría quejarse?, ¿podría cancelar el servicio de correo electrónico?. La respuesta es depende. Depende lo que hayamos firmado. Es decir, dentro del contrato existen lo que se llaman las SLA (Service Level Agreement o Acuerdos del nivel del servicio). Si en la SLA firmada por el cliente dice que la disponibilidad del servicio no será menor de 99,0% pues el cliente no tiene base para poder realizar una queja ya que estamos en el nivel establecido.

file descriptors (ii de ii)

3 de julio de 2009

Hasta ahora no hemos hablado para nada de la salida estandard STDERR. Este tipo de salida es utilizada por los procesos para mostrar los errores o para trabajos de diagnóstico. Como mencioné en el primer post la STDIN y la STDERR se muestran por el terminal. La información "buena" del proceso y la información de error se entremezclan.

Supongamos que tenemos un proceso el cual es susceptible de producir errores. Supongamos también que se lanza cada día en un cron de la siguiente forma:

# miproceso > /var/log/miproceso.log

Aparentemente, el proceso cada día se ejecutará y almacena su resultado dentro de /var/log/miproceso.log. No es correcto del todo. Dentro del miproceso.log solo encontraremos el resultado de la STDOUT de miproceso, pero no los errores que se hayan producido. Es decir, el resultado legitimo del programa lo hemos redireccionado a un fichero, pero los errores se siguen mostrando por el terminal. Para solucionar esto, tenemos que redidireccionar la STDOUT y la STDERR con la siguiente sintaxis:
# miproceso > /var/log/miproceso.log 2>&1

Le estamos diciendo que la STDERR (o file descriptor 2) se redireccione al mismo sitio donde esta redireccionado la STDOUT (o file descriptor 1).

También es posible redireccionar cada salida a un archivo diferente. Es decir que los resultados vayan a un log y los errores a otro log:
# miproceso 1> /var/log/resultado.log
# miproceso 2> /var/log/errores.log

Veamos un ejemplo real de la existencia y del funcionamiento de STDERR. Supongamos que tenemos un archivo llamado "pepe.txt" que no existe. Si intentamos ver su contenido se producirá un mensaje de error. Este mensaje de error, aunque haya gente que cree lo contrario, lo vemos por pantalla pero no viene de la STDOUT. Viene de la STDERR. Redireccionemos los errores del comando cat a un fichero de log.
# cat pepe.txt
cat: pepe.txt: No existe el fichero ó directorio
# cat pepe.txt 2>error.log
# cat error.log
cat: pepe.txt: No existe el fichero ó directorio

Otro ejemplo muy utilizado de los redirectores es utilizarlo junto con el dispositivo null. El dispositivo /dev/null es un dispositivo que todo lo que enviemos se perderá en el infinito. Pensémoslo como un dispositivo papelera. Se utiliza mucho cuando queremos ejecutar un proceso y no queremos almacenar nada de su resultado. Es decir, no queremos que muestre nada por el terminal:
# miproceso > /dev/null 2>&1

Tanto la STDOUT como la STDERR las envio a la papelera.

Un comando muy utilizado junto con las pipe es el comando de Linux tee. Si utilizamos un redirector hacia un archivo, el problema que tenemos es que ya no veremos nada por el terminal. Si lo que queremos es redireccionar y al mismo tiempo ver por el terminal debemos utilizar un tee:
# cat /etc/passwd | grep root | tee resultado.txt | less
root:x:0:0:root:/root:/bin/bash
# cat resultado.txt 
root:x:0:0:root:/root:/bin/bash

El comando tee recibe por su STDIN unos datos que los almacena en resultado.txt y al mismo tiempo los manda por su STDOUT lo que posibilita que los veamos por el terminal.

No solo Linux/UNIX dispone de esta potencia en sus shells. Windows con la aparición de la Windows Power Shell también dispone de todas estas funciones.

file descriptors (i de ii)

30 de junio de 2009

La potencia de los shells de Linux (como puede ser Bash) radica en la posibilidad de unir comandos pasando la información de uno hacia el otro. Tareas que a primera vista pueden resultar complicadas con un simple comando se hacen bastante sencillas con la unión de comandos usando conductores y redirectores.

En Linux/UNIX tenemos tres archivos llamados STDIN, STDOUT y STDERR. Estos archivos y las capacidades de la "standard I/O" nos ofrecen la posibilidad de controlar el flujo de datos que entran, salen o muestran información de error.
Como comportamiento estandard, un flujo de STDIN o entrada está provocado por las pulsaciones de un teclado. Por ejemplo, cuando arrancamos el programa "mail" este estará leyendo de STDIN todas las pulsaciones de teclado para ir construyendo el mail.
Para el caso de STDOUT, este como comportamiento estandard está enlazado con el monitor. Por tanto todo lo que enviemos aquí se verá reflejado por el monitor.
El caso de STDERR es similar al de STDOUT. Por defecto su contenido se enviará al monitor.

Estos archivos también reciben el nombre de "standard input", "standard output" y "standard error". También se les puede indentificar con un numero, "file descriptor 0", "file descriptor 1" y "file descriptor 2" respectivamente.

Cada vez que lanzamos un proceso asociamos estos tres file descriptors correspondientes.

Veamos ahora las dos herramientas que me permiten cambiar el flujo de datos de un sitio a otro. Estas herramientas son las pipes y los redirectors.
Las pipes se representan por el carácter "|" y su función es redirigir la STDOUT de un proceso a la STDIN de otro proceso igual o diferente. Es decir, el resultado que produzca un procesos (que normalmente lo veremos por el monitor) lo redireccionamos como si fueran pulsaciones de teclado a otro proceso.

Por ejemplo:

# cat /var/log/messages | grep kernel

El resultado de cat que sale por STDOUT se redirecciona al STDIN del comando grep. Por tanto lo que estamos haciendo es listar el contenido de /var/log/messages y sobre este resultado filtrar y buscar las lineas que contengan la palabra kernel.

Las pipes se pueden anidar formando comandos más complicados.

Por ejemplo:
# cat /etc/passwd | cut -d: -f6 | uniq | sort | nl
     1 /bin
     2 /bin
     3 /bin
     4 /dev
     5 /home/amperis
     6 /home/clamav
     7 /home/klog
     8 /home/saned
     9 /home/syslog
    10 /nonexistent
    11 /root
    12 /usr/games
    13 /usr/sbin
    14 /var/backups
    15 /var/cache/man
    16 /var/lib/avahi-autoipd
    17 /var/lib/gdm
    18 /var/lib/gnats
    19 /var/lib/libuuid
    20 /var/list
    21 /var/mail
    22 /var/run/avahi-daemon
    23 /var/run/dbus
    24 /var/run/hald
    25 /var/run/hplip
    26 /var/run/ircd
    27 /var/run/PolicyKit
    28 /var/run/pulse
    29 /var/spool/lpd
    30 /var/spool/news
    31 /var/spool/uucp
    32 /var/www

Con la siguiente anidación de pipes, listamos el contenido de /etc/passwd, luego recortamos para obtener la columna donde están los homes, ordenados el resultado y enumeramos las lineas. Lo que estamos haciendo es pasar el resultado que proporciona un proceso a la entrada del siguiente proceso. El ultimo proceso como no tiene ningún tipo de redirección mostrará su resultado por su STDOUT, es decir por el monitor.
No confundir "cat /etc/passwd | cut -d: -f6 | uniq | sort | nl" con "cat /etc/passwd; cut -d: -f6 ; uniq; sort; nl". En este último caso los procesos se ejecutan uno por uno, pero no existe ninguna relación entre ellos.

Con la herramienta de los redirectors lo que podemos hacer es redireccionar el contenido de un archivo a la entrada de un proceso o la salida de un proceso enviarla a un archivo.
Veamos un ejemplo de como enviar el contenido de un archivo a un proceso. Supongamos que tenemos un archivo llamado "email.txt" con el cuerpo del mensaje de un correo electrónico. Se lo queremos enviar a un usuario llamado "paco":
# mail paco < email.txt

Lo que estamos haciendo es redireccionar el contenido de fichero a la STDIN del proceso mail.

Veamos el caso contrario, es decir, cómo guardar el contenido de un proceso en un fichero. Supongamos que queremos guardar en un fichero de log las 10 ultimas lineas de otro log:
# tail /var/log/messages > mini.log

El comando tail muestras las 10 últimas lineas de /var/log/menssages. Esta salida la redireccionamos al fichero mini.log.
La redirección utilizando ">", siempre crear el archivo en caso de no existir. Si existe el archivo lo sobreescribe. También tenemos la posibilidad de hacer un append, es decir, si existe continuar por su ultima linea y si no existe crearlo. Para ello utilizamos los caracteres ">>":
# tail /var/log/messages >> minilog.log; sleep 60; tail /var/log/messages >> minilog.log

Ahora que ya conocemos estas dos herramientas podemos utilizarlas en conjunción. Veamos como almacenar el resultado del segundo ejemplo en un fichero:
# cat /etc/passwd | cut -d: -f6 | uniq | sort | nl > /tmp/homes.txt

Otro ejemplo utilizando todas las herramientas:
# tr '[a-z]' '[A-Z]' < /etc/passwd | cut -d: -f6 > homes.txt
# head homes.txt
/ROOT
/USR/SBIN
/BIN
/DEV
/BIN
/USR/GAMES
/VAR/CACHE/MAN
/VAR/SPOOL/LPD
/VAR/MAIL
/VAR/SPOOL/NEWS

En el ejemplo anterior enviamos el contenido de /etc/passwd al proceso tr que nos lo convierte todo en mayúsculas. El resultado de esto los cortamos para quedarnos con los homes de los usuarios y lo guardamos en el fichero homes.txt.

prioridades en linux (ii de ii)

24 de junio de 2009

Los comandos nice y renice nos permiten cambiar las prioridades de los procesos. Las prioridades van en un rango entre el -20..0 y el 0..19. El -20 es máxima prioridad y por tanto máxima apropiación de la CPU y el 19 es la mínima apropiación de la CPU. El 0 es la prioridad que se da por defecto a todos los usuarios del sistema. Otra cosa muy importante es que solo root puede dar prioridades negativas.

Para ser más correcto lo que estamos cambiando no es exactamente la prioridad sino "el valor de nice". Como hemos explicado anteriormente la apropiación y tiempo de uso de una CPU se calcula en base a uno o varios algoritmos de planificación y en base a muchos parámetros entre ellos, el valor de nice.

Para lanzar un nuevo proceso con un valor de nice haremos lo siguiente:

# nice -n -15 xeyes (lanzamos xeyes con una prioridad alta)

Si por el contrario queremos cambiar la prioridad a un proceso ya en ejecución, utilizaremos el comando renice:

# renice 10 -p 1967 (lanzamos el proceso con PID 1967 con una prioridad baja)

Para ver que nice tiene asignado cada proceso hay que consultar la columna NI que muestra el comando top:

top - 23:18:30 up 10:52,  5 users,  load average: 0.00, 0.31, 0.40
top - 23:25:57 up 10:59,  5 users,  load average: 0.28, 0.19, 0.28
Tasks: 139 total,   3 running, 136 sleeping,   0 stopped,   0 zombie
Cpu(s): 11.3%us,  3.7%sy,  1.0%ni, 84.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   3989648k total,  3425068k used,   564580k free,    97340k buffers
Swap:  4000176k total,        0k used,  4000176k free,  2796996k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                           
 3035 root      20   0  495m  60m  15m R  7.0  1.6   9:37.19 Xorg                                                                                                                                              
 3638 amperis   20 -20  317m  49m  17m S  4.3  1.3   2:42.72 bucle.sh                                                                                                                                       
17023 amperis   39  19  578m 122m  27m S  2.0  3.1   1:05.72 bucle.sh                                                                                                                                           
17067 amperis   20 -15  199m  20m  10m R  1.7  0.5   0:58.31 xeyes                                                                                                                                    
17959 root      20   0 19116 1344  988 R  0.3  0.0   0:02.62 top 
...

Como regla general Linux por si mismo ya es lo suficiente eficiente para mantener el buen uso de la CPU, por tanto, no es necesario ir cambiando los nice. Si este no fuera tú caso, lo normal es cambiarlo o jugar con ellos en aplicaciones como audio, video, diseño, donde los retardos en los resultados es muy apreciable.

Para los que le gusta tunear su Kernel existen parches para compilarlo utilizando opciones de tuning y real-time. Existen proyectos dedicados al real-time del Kernel.

Para hacer notar el poder del nice podéis crear un script con un bucle infinito que vaya mostrando números por pantalla. Lo lanzáis dos veces en dos terminales diferentes. Por defecto, los dos procesos entraran en ejecución con un nice 0. Ahora a uno le ponéis un -20 y al otro un 19. Veréis como uno incrementará su velocidad y el otro irá más lento. En verdad no va más lento, sino que recibe la CPU menos veces por unidad de tiempo.

#!/bin/bash

while [ 1 ] 
do
  echo $RANDOM
done


prioridades en linux (i de ii)

23 de junio de 2009

Todos los sistemas operativos tienen algún tipo de algoritmo de planificación más o menos eficiente que permite a todos los procesos del sistema y del usuario poder hacer uso de la CPU. Un buen algoritmo de planificación debe ser capaz de controlar todos estos parámetros:

+ equitatividad: cada proceso debe recibir su parte justa de CPU y recursos.
+ eficiencia: la CPU debe ser usada todo el tiempo. No desaprovecharla.
+ throughput: producir el mayor numero de trabajos terminados por hora.
+ respuesta: minimizar el tiempo de respuesta en las aplicaciones interactivas.

Manejar todos estos parámetros es muy difícil ya que dentro de un sistema podemos encontrar diferentes tipos de procesos y tareas cada una con sus propias características y necesidades. Por ejemplo, tenemos procesos que utilizan intensamente la CPU y otros que estarían todo el día parados esperando E/S. Por tanto, cuando Linux empieza a ejecutar un proceso, no sabe 100% cuanto tiempo necesitará ese proceso la CPU.

Durante el diseño de sistemas de compartición y scheluding han ido surgiendo diferentes tipos de algoritmos de palanificación:

+ planificación por round-robin: quizás el más conocido y que se estudia más durante la carrera informática. Es uno de los más antiguos y tal vez el más sencillo de implementar y justo. Se basa en mantener una cola o lista de procesos, asignándoles un tiempo de ejecución a cada proceso. Pasado ese tiempo le quitamos al proceso la CPU y se la damoss a otro. Lo más difícil de calcular es el ¿cuanto tiempo?. Si ponemos poco tiempo haremos mucho swaping entre procesos y eso puede ser malo porque podemos perder mucho tiempo en cambiar de contexto. Si decidimos poner mucho tiempo, podemos perjudicar a otros procesos que son muy interactivos con el usuario.

+ planificación por prioridades: consiste en dar una prioridad al proceso. Contra más prioridad tenga un proceso antes utilizará la CPU. Dentro de este tipo de planificación podemos encontrar que las prioridades se pueden asignar estática o dinámicamente.

+ planificación por colas: consiste en tener varias colas donde los procesos alojados en una cola utilizan la CPU X ms., los alojadas en la segunda cola la utilizan 2X ms., y así sucesivamente. Una vez los procesos utilizan todo su tiempo van rotando por las diferentes colas.

+ planificación en tiempo real: quizás estos algoritmos son los más complicados ya que deben asegurar respuestas a posibles eventos. Por ejemplo, un sistema que controle la altura de un vuelo. Si salta la alarma de altura, el proceso que controla este evento tiene que estar dentro de la CPU para poder tomar el control. Una respuesta correcta pero tarde, puede ser peor que no obtener respuesta.

+ otros planificadores: planificación por lotería, planificación garantizada, planificación en varios niveles, etc.

En Linux tenemos una mezcla de varios de los planificadores que he explicado, pero básicamente sería algo como un round-robin con prioridades. En realidad podemos planificar cada proceso con una política diferente. Estas son las políticas de Linux:

+ SCHED_OTHER: en Unix es la planificación clásica. No es aplicable en tiempo real. Examina las prioridades dinámicas (calculadas como combinación de las especificadas por el usuario y las calculadas por el sistema). Los procesos que llevan más tiempo en el sistema van perdiendo prioridad.

+ SCHED_FIFO: El primero en entrar en la cola es el primero en ser servido. Los procesos esperan en cola y se ejecutan secuencialmente. Se sigue calculando un cuanto de tiempo para el proceso, aunque normalmente no se use porque con esta planificación no se fuerza al proceso a abandonar la CPU. Se usa en procesos de tiempo real.

+ SCHED_RR: round-robin. Funciona como el FIFO pero ahora cuando un proceso acaba su cuanto de tiempo (time slice) se le desaloja. El siguiente proceso se escoge de la lista de procesos con SCHED_RR o de la lista SCHED_FIFO. Son procesos en tiempo real.

+ SCHED_YIELD: No es una política de planificación, sino un modificador que afecta a las tres políticas anteriores. El proceso cede la CPU a cualquier otro que esté listo.

Más información:
- Understanding the Linux 2.6.8.1 CPU Scheduler

envio de sms en linux

11 de junio de 2009

Una de las cosas chulas de Nagios es que puedes ir creando servicios de notificación para enviar mensajes por diferentes medios cuando un servicio cae. Lo normal es hacer que Nagios te envíe un mail cuando un disco se llene, cuando una impresora deje de funcionar o cuando el ancho de banda de un router esté al 80%.
Otra forma curiosa de enviar notificaciones es enviar todas estas a Twitter. Simplemente echando un vistazo a tú Twitter puedes ver que está pasando con tus servidores... ¿arriesgado?.

Lo más efectivo es el envio de SMS a tú móvil en caso de que un servicio importante deje de funcionar. El uso de la notificación por correo (o el Twitter) solo funciona si tú conexión a Internet está funcionando. ¿Que pasa si monitorizas tú conexión a Internet y esta ha caído?.
Para ello he rebuscado y rebuscado entre todos lo móviles de la empresa hasta encontrar uno con conexión USB y sobre todo que sea capaz de cargarse la batería también por el mismo cable USB... al final encontré uno muy chulo: un Motorola V3.

Lo primero que tenemos que hacer es verificar si es capaz de detectar el móvil. Para ello lanzamos un lsusb (todos los resultados están bajo un Fedora 7):

[root@server ~]# lsusb
Bus 001 Device 001: ID 0000:0000
Bus 004 Device 001: ID 0000:0000
Bus 002 Device 001: ID 0000:0000
Bus 003 Device 007: ID 22b8:4902 Motorola PCS E398 GSM Phone
Bus 003 Device 001: ID 0000:0000

Como resultado también obtendremos un nuevo dispositivo mapeado en /dev/ttyACM0. Un dispositivo ttyACM identifica a un módem USB, y como tal módem es capaz de ser atacado vía comandos AT. Los comandos AT son cadenas de texto que nos permiten interactuar con cualquier módem para inicializarlo, marcar un número, transferir un fichero o colgar una llamada. Los móviles son modems GSM y, por tanto, también acepta comandos AT.

Los comandos AT que debemos enviar para que el móvil envie un SMS son los siguientes:
AT+CMGF=1 (le dice al módem que enviamos los SMS en formato texto).
AT+CSCA="+34607003110" (le decimos que el número del centro de mensajes es el 
                        +34607003110)
AT+CMGS="696342572" (le decimos el número donde debe enviar el SMS)
> Hola caracola <Ctrl+Z> (escribimos el mensaje y lanzamos un Ctrl+Z).

Lo único que necesitamos saber es el número del centro de mensajes SMS de nuestra operadora. En mi caso el SIM de la tarjeta es Vodafone y el centro de mensajes es el +34607003110. Esta información la puedes encontrar dentro de la configuración del móvil o te la puede dar la operadora.

Una vez sabemos como funciona todo, podemos crear un script en Perl que nos permita hacer todo esto en una simple línea de comandos.

#!/usr/bin/perl

$_SMS_CM="+34607003110";
$_SMS_MODEM="/dev/ttyACM0";

if ($#ARGV != 1 ) {
   print "sendsms.pl v0.1b, por amperis[@]gmail.com\n\n";
   print "Uso:\n";
   print "   ./sendsms.php <numero destino> \"<mensaje>\"\n\n";
   exit;
}

use Device::Modem;

my $modem = new Device::Modem( port => $_SMS_MODEM );

if ( $modem->connect( baudrate => 115200 ) ) {
   $modem->echo(1);
   $modem->verbose(1);

   $modem->atsend( 'AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0'.Device::Modem::CR);
   print $modem->answer()."\n";

   $modem->atsend( 'AT+CMGF=1'.Device::Modem::CR);
   print $modem->answer()."\n";

   $modem->atsend( 'AT+CSCA="' . $_SMS_CM. '"'.Device::Modem::CR);
   print $modem->answer()."\n";

   $modem->atsend( 'AT+CMGS="' .$ARGV[0]. '"'.Device::Modem::CR);
   print $modem->answer()."\n";

   $modem->atsend( $ARGV[1].chr(26));
   print $ARGV[1]."\n\n";

   print "\nFin de la conexion.\n\n";


} else {
   print "ERROR: No encuentro el modem.\n";
}

Nota: Tenemos que tener instalado en Perl el paquete Device::Modem. Para instalar paquetes en Perl hacemos un "perl -e shell -MCPAN" y luego haremos un ">install Device:Modem".

Ahora solo queda dar permisos de ejecución al script (chmod +x sendsms.pl) y ejecutarlo:
# ./sendsms.pl 696342572 "Error a las 19:35h. Router Cisco 877 sin conexión"

Más información:
+ Using AT commands to Send and Receive SMS