un dia en la oficina con el axis 207mw

29 de diciembre de 2009

keepass

27 de diciembre de 2009

Cuando tienes más de 100 passwords para administrar se hace necesaria una herramienta de administración de password muy portable. Portable para Windows, portable para Linux, portable para la Blackberry o portable el iPhone. Cada uno de los técnicos accede a los passwords de una manera diferente.

Necesitamos por tanto que sea multiplataforma y multi-dispositivo. Que encripte lógicamente la información, que permita hacer grupos de password (servidores, access points, switches, etc), que permita adjuntar ficheros como puede ser una config de un Cisco, que permita búsquedas, que permita exportar a un Excel, que permita crear campos como la IP de un servidor o la fecha de la ultima actualización del servidor y sobre todo que sea opensource.

Pues bien, después de mucho probar la solución es: KeePass Password Safe.

Ahora cada vez que conectamos una Blackberry o un iPhone al portátil, sincronizamos el fichero de password automáticamente. Una maravilla…

run kiosco

20 de diciembre de 2009

Un kiosco en Linux es una máquina dispuesta en un stand para que los usuarios la puedan utilizar a modo de terminal de consulta. Por ejemplo si habéis ido alguna tienda de Pixmania, a la entrada hay un terminal (pantalla+teclado+ratón) donde solo tenéis acceso a su pagina Web para consultar sus productos.

En mi empresa hemos montado tres kioscos para que los empleados tengan acceso al "portal del empleado" y estén siempre al día de la noticias de la empresa. Una está en la cafetería, la otra en el restaurante y la otra aun no se donde irá.

Explico pues como montar una maquina de estas. La idea es que el Linux arranque automáticamente, cargue el firefox con la página de inicio y el usuario solo pueda consultar esta página. Naturalmente no podrá navegar por ningún otro sitio, no podrá reiniciarla, no podrá ejecutar ninguna aplicación, etc.

+ Instalaremos una versión ligera de Linux como Ubuntu Server. La idea es que cualquier maquina con poco disco (unos 2Gb) y memoria (unos 256Mb) nos pueda funcionar. Haremos una instalación estándar y consideraremos los siguientes puntos:

1) Crear el usuario con nombre "operador". Este será el usuario con el que funcionará el Kiosco.
2) No utilizar LVM ya que no es necesario.
3) Instalar OpenSSH Server. Es necesario para realizar un mantenimiento remoto del kiosco.

+ Actualizar la máquina e instalar un entorno X ligero como Blackbox (con 5Mb de RAM ya funciona):

operador@kiosko$ sudo passwd root
operador@kiosko$ su root
root@kiosko# apt-get update
root@kiosko# apt-get upgrade
root@kiosko# apt-get install x-window-system-core blackbox squid firefox mingetty 
flashplugin-nonfree
+ Lo primero que haremos es configurar el Squid para decirle el conjunto de paginas Web por donde podrá navegar el kiosco. Si solo tenemos un kiosco el proxy lo instalaremos en la maquina local, si tenemos varios podemos instalar el proxy en uno de ellos y hacer que el resto de kioscos lo utilicen.

El usuario no puede escribir una URL ya que la pagina inicial le viene impuesta, el problema es que si la pagina contiene un link a otro site no controlado o no previsto, el usuario podrá navegar. Imagina que dentro de la pagina inicial encuentra un link a Google. Si accede a Google podrá navegar por donde quiera.

Para ello creamos el archivo "/etc/squid/kiosko_allow_sites.conf" y dentro colocaremos todos los dominios (incluidos nuestra pagina inicial) por donde queramos que navegue nuestro kiosco:

root@kiosko# cat kiosko_allow_sites.conf 
intranet.miempresa.com
miempresa.com
submiempresa.com
Ahora le decimos a Squid que acepte estos sites y que todo lo demás lo deniegue. Para ello editamos el /etc/squid/squid.conf. Dentro del "Defining an Access List", añadimos la ACL:

acl kiosko_allow_sites url_regex "/etc/squid/kiosko_allow_sites.conf"
Ahora creamos la rule para aceptar estas sites y denegar el resto. Dentro de "Allowing or Denying access based on defined access lists" añadimos:
http_access allow kiosko_allow_sites
http_access deny all
Ahora solo queda reiniciar Squid:
root@kiosko# /etc/init.d/squid restart
+ Ya podemos arrancar el entorno X. Mientras tanto podemos ir conectándonos por SSH y terminar de configurar la maquina:
root@kiosko# startx
Para arrancar Firefox manualmente, hacemos botón derecho en el ratón y ejecutamos xterm. En la ventana de consola podemos escribir "firefox" para ejecutarlo.

Una vez arrancado el Firefox lo configuramos para que siempre arranque nuestra pagina de inicio. Para ellos hacemos "Editar->Preferencias" y modificamos la "Pagina de Inicio".

Es aconsejable revisar todas las opciones de Firefox para no dejarnos nada. Por ejemplo:

1) cambiar la ruta de descargas de archivos a /tmp.
2) deshabilitar la barra de progreso de descargas
3) no recordar nunca los passwords
4) limpiar historial todos los dias
5) deshabilitar las actualizaciones

También debemos decirle a Firefox que utilice el proxy (Squid) que hemos configurado en el punto anterior. Para ello dentro de Preferencias vamos a Advanced->Network->Settings y añadimos:

HTTP Proxy: 127.0.0.1
Puerto: 3127

Otra cosa para configurar es deshabilitar la restauración de la sesión de Firefox al cerrar incorrectamente el navegador. Esto evita que cada vez que arranque el Firefox (al reiniciar el kiosco) pregunte si deseamos restaurar la ultima sesión:

1) En la URL escribimos "about:config" y pulsamos Enter
2) Buscamos "browser.sessionstore.resume_from_crash"
3) Hacemos doble click en el parámetro para ponerlo a false

También pondremos a false el parámetro "network.protocol-handler.external.mailto". Esto lo que hará es que cuando la pagina encuentre un link del tipo "mailto" este no funcione y no cargue ningún Webmail tipo GMail o Yahoo.

Tras finalizar la configuración de Firefox viene la parte más importante que es la instalación de un complemento de Firefox que nos permite eliminar las barras de navegación, la minimización de las ventanas, el botón derecho del ratón, etc: el R-Kiosk.

Lo debemos instalar accediendo a su descarga: https://addons.mozilla.org/en-US/firefox/addon/1659

Una vez arrancado Firefox con este complemento perderemos toda posibilidad de acceder a los menus y al escritorio la maquina. Si queremos arrancar con los menús de Firefox, tendremos que arrancarlo en safe-mode como se indica más abajo.

+ Hacer auto-login y arrancar el entorno grafico automáticamente.

Primero editamos "/etc/event.d/tty1" y cambiamos "exec /sbin/getty 38400 tty1" por "exec /sbin/mingetty –-autologin operador tty1". Esto lo que hace es el auto-login con el usuario "operador" creado durante la instalación.

Para arrancar las X editamos "/home/operador/.profile" y añadimos en la última linea un "startx".

+ Arrancar automáticamente Firefox. Creamos el archivo "/home/operador/.xinitrc". Este archivo se ejecuta cada vez que arranque el entorno gráfico:
root@kiosko# cat .xinitrc 
#!/bin/bash

## Arranque normal de Firefox
firefox &

## Utilizar esta linea para arrancar Firefox en safe-mode
##firefox -safe-mode &

. /etc/X11/Xsession

root@kiosko# chown operador:operador .xinitrc
NOTA: Si no queremos arrancar el R-Kiosk arrancaremos el Firefox con "firefox -safe-mode &".

+ También es necesario que el usuario no pueda hacer un "ctrl+alt+del" y reiniciar el kiosco. Para ello renombramos este archivo:
root@kiosko# cd /etc/envet.d
root@kiosko# mv control-alt-delete control-alt-delete.disable
Otras consideraciones: la máquina al arrancar es vulnerable a que un usuario pueda acceder. Por ejemplo, al arrancar el grub podría modificar los parametros de arranque, podría cambiar de tty mientras está cargado, o podría llegar a ejecutar un xterm antes de arrancar el Firefox.

Por esto unas modificaciones que podrías hacer tú es:

+ Modificar el grub para que el timeout sea 0 segundos.
+ Quitar todos los ttys no necesarios
+ No ejecutar ningún programa una vez dentro de Blackbox.

lvm: ponme un nuevo disco

14 de diciembre de 2009

Actualmente tengo una maquina con un Oracle al que se le termina el espacio de disco. Tiene un disco de 68Gb en RAID1 montado por LVM (el /dev/sda). Hemos montado otro disco de 68Gb en RAID1 (el /dev/sdb) con la idea de ampliar el espacio del volum-group formado en la maquina.

Miramos primero que se ha reconocido el segundo disco:

root@virtuozo:~# ls -l /dev/sd*   
brw-rw---- 1 root disk 8,  0 2009-12-11 11:50 /dev/sda
brw-rw---- 1 root disk 8,  1 2009-12-11 11:50 /dev/sda1
brw-rw---- 1 root disk 8,  2 2009-12-11 11:50 /dev/sda2
brw-rw---- 1 root disk 8,  5 2009-12-11 11:50 /dev/sda5
brw-rw---- 1 root disk 8, 16 2009-12-12 16:39 /dev/sdb

Miramos cómo está montado el LVM en esta máquina. Miramos los Physical Volumen o los discos físicos que forman mi LVM:
root@virtuozo:~# pvscan
  PV /dev/sda5   VG virtuozo.barcelona   lvm2 [68.00 GB / 0    free]
  Total: 1 [68.00 GB] / in use: 1 [68.00 GB] / in no VG: 0 [0   ]

Vemos que existe un volum-group llamado “virtuozo.barcelona” que está compuesto de la partición física /dev/sda5 de 68Gb.

Vemos ahora como está particionado este volum-group en diferentes logical-volum:
root@virtuozo:~# lvscan
  ACTIVE            '/dev/virtuozo.barcelona/root' [65.18 GB] inherit
  ACTIVE            '/dev/virtuozo.barcelona/swap_1' [2.82 GB] inherit

Está particionado en dos. La primera en “root” de 65Gb y la segunda es “swap_1” de 2Gb.

Ahora que tenemos esto presente, la idea de añadir un nuevo disco (el /dev/sdb) es aumentar el tamaño del logical-volum “root”, pasando de 65Gb a 133Gb aproximadamente.

Vamos pues. Lo primero que haremos es crear una única partición en /dev/sdb de system id “8e” (tipo LVM).
root@virtuozo:~# fdisk /dev/sdb

The number of cylinders for this disk is set to 8908.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
   (e.g., DOS FDISK, OS/2 FDISK)

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-8908, default 1): 
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-8908, default 8908): 
Using default value 8908

Command (m for help): t
Selected partition 1
Hex code (type L to list codes): 8e
Changed system type of partition 1 to 8e (Linux LVM)

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

Una vez creada la partición (ver ls –l /dev/sd*), la formateamos. En mi caso es formato ext3:
root@virtuozo:~# mkfs -t ext3 -c /dev/sdb1

Ahora ya podemos añadir nuestro nuevo disco al volum-group:
root@virtuozo:~# pvcreate /dev/sdb1
root@virtuozo:~# vgextend virtuozo.barcelona /dev/sdb1
root@virtuozo:~# pvdisplay
  --- Physical volume ---
  PV Name               /dev/sda5
  VG Name               virtuozo.barcelona
  PV Size               68.00 GB / not usable 1.27 MB
  Allocatable           yes (but full)
  PE Size (KByte)       4096
  Total PE              17408
  Free PE               0
  Allocated PE          17408
  PV UUID               gextNx-qoAF-aNn9-1ARg-72bY-oQeY-sHaOQ7   
  --- Physical volume ---
  PV Name               /dev/sdb1
  VG Name               virtuozo.barcelona
  PV Size               68.24 GB / not usable 454.00 KB
  Allocatable           yes 
  PE Size (KByte)       4096
  Total PE              17469
  Free PE               17469
  Allocated PE          0
  PV UUID               dCibq8-B4TY-adnR-HR6j-iLv6-f15H-pBknpX

Para finalizar aumentamos el tamaño del logical-volum llamado “root”:
root@virtuozo:~# lvextend -l+17469 /dev/virtuozo.barcelona/root 
  Extending logical volume root to 133.42 GB
  Logical volume root successfully resized
root@virtuozo:~# lvscan
  ACTIVE            '/dev/virtuozo.barcelona/root' [133.42 GB] inherit
  ACTIVE            '/dev/virtuozo.barcelona/swap_1' [2.82 GB] inherit
# resize2fs /dev/virtuozo.barcelona/root
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/virtuozo.barcelona-root
                      133G  2.8G  123G   3% /
varrun               1008M   84K 1008M   1% /var/run
varlock              1008M     0 1008M   0% /var/lock
udev                 1008M   52K 1008M   1% /dev
devshm               1008M     0 1008M   0% /dev/shm
/dev/sda1             236M   26M  199M  12% /boot

Observar como utilizamos el parámetro +17469 para aumentar el espacio con los “Free PE” (Physical Extended) del nuevo disco que hemos añadido. También podríamos utilizar algo como “lvextend -L+68G /dev/virtuozo.barcelona/root”.

Esta es una tabla de todos los comandos que se pueden utilizar para LVM:
--------------------
Comandos de volúmenes físicos
--------------------
pvchange |  Cambia los atributos de un volumen físico
pvcreate |  Crea un volumen físico
pvdata  |  Muestra información de depuración sobre un volumen físico
pvdisplay  | Muestra información sobre un volumen físico
pvmove   | Mueve extensiones físicas de un volumen físico a otro.
pvscan  | Localiza y enumera todos los volúmenes físicos
--------------------
Comandos de grupos volumen
--------------------
vgcfgbackup  | Hace una copia del área del descriptor de grupo volumen
vgcfgrestore  | Recupera el área del descriptor de grupo volumen al disco
vgchange  | Cambia los atributos de un grupo volumen
vgck   | Comprueba la consistencia del área del descriptor de grupo volumen
vgcreate  | Crea un grupo volumen a partir de volúmenes físicos
vgdisplay  | Muestra los atributos de un grupo volumen
vgexport  | Exporta un grupo volumen del sistema
vgextend  | Añade volúmenes físicos a un grupo volumen
vgimport  | Importa un grupo volumen al sistema
vgmerge  | Combina dos grupos volumen
vgmknodes  | Combina un directorio y los archivos especiales de un grupo volumen
vgreduce  | Elimina volúmenes físicos de un grupo volumen
vgremove  | Elimina un grupo volumen
vgrename  | Renombra un grupo volumen
vgscan   | Localiza y enumera todos los grupos volumen del sistema
vgsplit  | Divide un grupo volumen
--------------------
Comandos de volúmenes lógicos
--------------------
lvchange  | Cambia los atributos de un volumen lógico 
lvcreate  | Crea un volumen lógico
lvdisplay  | Muestra los atributos de un volumen lógico
lvextend  | Incrementa el tamaño de un volumen lógico
lvreduce  | Reduce el tamaño de un volumen lógico
lvremove  | Elimina un volumen lógico
lvrename  | Renombra un volumen lógico
lvscan   | Localiza y enumera todos los volúmenes lógicos, creando /etc/lvmtab 
y /etc/lvmtab.d/*
--------------------
Comandos del Administrador de Volúmenes Lógicos (LVM)
--------------------
lvmchange  | Cambia los atributos del sistema LVM
lvmdiskscan  | Localiza y enumera todos los discos disponibles, los dispositivos 
múltiples y las particiones
lvmsadc  | Recoge información sobre la actividad de LVM
lvmsar   | Muestra información sobre la actividad de LVM


instalar oracle en linux y no morir en el intento (parte ii)

12 de diciembre de 2009

Es posible que al finalizar ya podamos acceder directamente a la consola de administración desde: http://ip_server:1158/em

Pero si reiniciamos veremos como Oracle no arranca por defecto. Hay muchos scripts por Internet para arrancar automáticamente la BBDD.
Lo que primero haremos es indicarle a Oracle que BBDD queremos arrancar al arrancar Oracle.

Editamos el /etc/oratab e indicamos que queremos que la única base de datos creada arranque:

dbora01:/u01/app/oracle/oracle/product/10.2.0:Y

Iniciar Oracle:
# su oracle
# . oraenv (cargamos las variables de entorno)
$ . oraenv
ORACLE_SID = [oracle] ? dbora01

$ lsnrctl start (arrancamos el listener)
$ dbstart (arrancamos la bbdd)
$ emctl start dbconsole (arrancamos la consola de administración)

Podemos ver todos lo procesos que se arrancan:
$ ps -x
Warning: bad syntax, perhaps a bogus '-'? See /usr/share/doc/procps-3.2.3/FAQ
  PID TTY      STAT   TIME COMMAND
 6439 pts/0    S      0:00 bash
 6469 ?        Ssl    0:00 /u01/app/oracle/oracle/product/10.2.0/bin/tnslsnr LISTENER 
-inherit
 6514 ?        Ss     0:00 ora_pmon_dbora01
 6516 ?        Ss     0:00 ora_psp0_dbora01
 6518 ?        Ss     0:01 ora_mman_dbora01
 6520 ?        Ss     0:00 ora_dbw0_dbora01
 6522 ?        Rs     0:03 ora_lgwr_dbora01
 6524 ?        Ss     0:00 ora_ckpt_dbora01
 6526 ?        Ss     0:04 ora_smon_dbora01
 6528 ?        Ss     0:00 ora_reco_dbora01
 6530 ?        Ss     0:02 ora_cjq0_dbora01
 6532 ?        Ss     0:04 ora_mmon_dbora01
 6534 ?        Ss     0:00 ora_mmnl_dbora01
 6536 ?        Ss     0:00 ora_d000_dbora01
 6538 ?        Ss     0:00 ora_s000_dbora01
 6542 ?        Ss     0:00 ora_qmnc_dbora01
 6544 ?        Ss     0:00 ora_q000_dbora01
 6546 ?        Ss     0:00 ora_q001_dbora01
 7029 pts/0    S      0:00 /u01/app/oracle/oracle/product/10.2.0/perl/bin/perl 
/u01/app/oracle /oracle/product/10.2.0/bin/emwd.pl dbc
 7054 pts/0    Sl     0:28 /u01/app/oracle/oracle/product/10.2.0/jdk/bin/java 
-server -Xmx256M -XX:MaxPermSize=96m -XX:MinHeapFreeRa
 7219 ?        Ss     0:00 oracledbora01 (LOCAL=NO)
 7226 ?        Ss     0:01 oracledbora01 (LOCAL=NO)
 7230 ?        Ss     0:04 oracledbora01 (LOCAL=NO)
 7235 ?        Ss     0:02 oracledbora01 (LOCAL=NO)
 7260 ?        Ss     0:00 oracledbora01 (LOCAL=NO)
 7274 ?        Ss     0:00 oracledbora01 (LOCAL=NO)
 7866 pts/0    Sl     0:01 /u01/app/oracle/oracle/product/10.2.0/bin/emagent
 7897 ?        Ss     0:01 oracledbora01 (LOCAL=NO)
 7941 ?        Ss     0:02 oracledbora01 (LOCAL=NO)
 7973 ?        Ss     0:04 oracledbora01 (LOCAL=NO)
 8253 ?        Ss     0:00 ora_j000_dbora01
 8268 pts/0    R+     0:00 ps -x
El primero que arrancamos es el listener. El listener es un servicio TCP que por defecto escucha en el 1521 y provee la conexión de clientes que necesitan realizar operaciones con la base de datos. Por ejemplo si tenemos una aplicación Java o PHP que desea realizar consultas contra la BBDD deberá contactar con el listener de Oracle pasándole su usuario/password y el SID de la base de datos.

La configuración del listener está en: $ORACLE_HOME/network/admin.

Luego levantamos la BBDD y con ello aparecen toda una serie de procesos llamados ora_*. Explicaré rápidamente algunos de estos procesos:

+ Ora_pmon: Es el Process Monitor. Es el encargado de limpiar los bufer y las caches que un usuario haya podido dejar sin liberar. Por ejemplo la conexión de red de un usuario cae y este tiene bloqueos de tablas, pmon libera las tablas, realiza rollbacks, etc de los recursos consumidos.

+ Ora_smon: Es el System Monitor. Es el encargado de recuperar la base de datos en caso de fallo de Oracle. Para ello utiliza los archivos de rehacer.

+ Ora_dbw: Es el Dabase Writer. Es proceso encargado de escribir en los ficheros fisicos los bloques de datos nuevos o modificados. Dependiendo del redimiento y necesidades de nuestro Oracle, podemos arrancar hasta 20 dbw.

+ Ora_lgwr: Es el Log Writer. Es el encargado de escribir los bloques del rehacer. Cuando tenemos una transacción primero se escriben los datos en los registros de rehacer antes que el ora_dbw los escriba finalmente en los ficheros de datos. Una transacción es correcta si ora_lgwr ha podido escribir los datos en sus archivos de rehacer.

Finalmente arrancamos la consola de administración que no es más que una aplicación Java (http://ip_server: 1158/em).
Ahora que parece que todo está arrancado vamos a conectarnos a la base de datos y hacer unas cuantas consultas de administración. No conectamos a la BBDD.
$ sqlplus /nolog
> connect / as sysba
Connected.

Veamos cuantas base de datos tenemos creadas:
SQL> select name, created, log_mode, open_mode, platform_name from v$database;

NAME      CREATED  LOG_MODE     OPEN_MODE
--------- -------- ------------ ----------
PLATFORM_NAME
--------------------------------------------------------------------------------
DBORA01   08/12/09 NOARCHIVELOG READ WRITE
Linux IA (32-bit)

Vemos que tenemos una BBDD llamada DBORA01 y que está abierta para lectura/escritura.

Veamos cuantos tablespaces tiene esta base de datos:
SQL> select tablespace_name, contents from dba_tablespaces;

TABLESPACE_NAME                CONTENTS
------------------------------ ---------
SYSTEM                         PERMANENT
UNDOTBS1                       UNDO
SYSAUX                         PERMANENT
TEMP                           TEMPORARY
USERS                          PERMANENT
EXAMPLE                        PERMANENT

6 rows selected.

Todos a excepción del EXAMPLE son los que nos encontraremos en una instalación estándar de Oracle. En el tablespace EXAMPLE encontraremos tablas de ejemplo para hacer pruebas.

Juguemos ahora con el schema SCOTT que se encuentra dentro del tablespace EXAMPLE. Para ello primero habilitamos el usuario que por defecto está cerrado:
SQL> ALTER USER scott ACCOUNT UNLOCK;

Entramos ahora con este nuevo usuario que por defecto tiene el password “tiger”.
$ sqlplus /nolog
> connect scott/tiger

Veamos ahora su schema:
Sql> select * from cat;
TABLE_NAME                     TABLE_TYPE
------------------------------ -----------
DEPT                           TABLE
EMP                            TABLE
BONUS                          TABLE
SALGRADE                       TABLE

SQL> select ename,job,sal from emp;

ENAME      JOB              SAL
---------- --------- ----------
SMITH      CLERK            800
ALLEN      SALESMAN        1600
WARD       SALESMAN        1250
JONES      MANAGER         2975
MARTIN     SALESMAN        1250
BLAKE      MANAGER         2850
CLARK      MANAGER         2450
SCOTT      ANALYST         3000
KING       PRESIDENT       5000
TURNER     SALESMAN        1500
ADAMS      CLERK           1100

ENAME      JOB              SAL
---------- --------- ----------
JAMES      CLERK            950
FORD       ANALYST         3000
MILLER     CLERK           1300

14 rows selected.

¿Parece que Oracle funciona no?

instalar oracle en linux y no morir en el intento (parte i)

8 de diciembre de 2009

El éxito o fracaso de una instalación de Oracle en Linux consiste básicamente en leerse un único documento: la Quick Installation Guide. Para la correcta instalación debemos de cumplir una serie de requisitos de hardware, software, parámetros de kernel y directorio requeridos. Si fallamos en uno de ellos el proceso de instalación fallará.

Para el siguiente post instalaremos un Oracle 10g R2 para Linux x86. Para ello lo descargamos directamente de la Web de Oracle. También necesitaremos a mano su guía de instalación.

Primero de todo hemos de revisar los requisitos de hardware de nuestra versión de Oracle dentro de la guía. Para ello necesitaremos una maquina x86, con 1Gb de RAM mínimo y unos 4Gb de disco para el software base de Oracle. Todo lo que sea superior a esto lógicamente será mejor. Por otro lado debemos seleccionar un sistema operativo que esté dentro de los sistemas operativos soportados por Oracle: Red Hat Enterprise 3, 4, SUSE Enterprise 9 y Asianux 1 y 2.

Yo voy a seleccionar un clon de Red Hat 4 como es CentOS 4. Si tuviéramos esta máquina en producción y quisiéramos que Oracle nos diera soporte en caso de problemas tendríamos que optar necesariamente por un sistema Red Hat si no queremos que Oracle se desentienda.

Empezamos pues la instalación:

+ Realizamos una instalación tipo servidor de un CentOS 4.8. Seleccionamos un particionado automático que utilizará LVM, configuramos el TCP/IP, desactivamos el firewall y también el SELinux.

+ Al finalizar la instalación comprobamos que tenemos acceso a Internet y que tenemos espacio suficiente en el sistema:

# ping www.google.com
# free (ver estado de la memoria y de la swap)
# df –h (ver espacio libre en /)

+ Actualizamos el sistema e instalamos los paquetes requeridos para la instalación:
# yum update
# yum groupinstall "X Window System" "GNOME Desktop Environment"
# yum install \
    setarch* \
    compat-libstdc++* \
    control-center* \
    gnome-libs* \
    gdb-6.1post* \
    make* \
    compat-gcc* \
    compat-gcc-c++* \
    glibc* \
    glibc-common* \
    glibc-devel* \
    gcc* \
    gcc-c++* \
    compat-db* \
    openmotif* \
    libstdc++* \
    libstdc++* \
    sysstat* \
    libaio* \
    libaio-devel*
# reboot

La instalación de Oracle utiliza un entorno de ventanas. Por este motivo he instalado el entorno gráfico en el servidor. Lógicamente en entorno solo lo arrancaremos para hacer la instalación, luego lo dejaremos apapagado.

+ Ahora creamos el usuario y los directorios necesarios para la instalación. Por defecto crearemos tres directorios: u01 (software base de oracle), u02 (archivos de la base de datos) y u03 (área de recuperación de datos).
# groupadd oinstall
# groupadd dba
# useradd -g oinstall -G dba oracle
# passwd oracle

# mkdir -p /u01/app/oracle
# chown -R oracle:oinstall /u01/app/oracle   
# chmod -R 755 /u01/app/oracle

# mkdir -p /u02/oradata
# chown -R oracle:oinstall /u02/oradata   
# chmod -R 755 /u02/oradata

# mkdir -p /u03/flash_recovery_area
# chown -R oracle:oinstall /u03/flash_recovery_area   
# chmod -R 755 /u03/flash_recovery_area

+ Configuramos los parámetros del Kernel. Para ello editamos el /etc/sysctl.conf y añadimos las siguientes líneas:
kernel.shmall = 2097152
kernel.shmmax = 2147483648
kernel.shmmni = 4096
kernel.sem = 250 32000 100 128
fs.file-max = 65536
net.ipv4.ip_local_port_range = 1024 65000
net.core.rmem_default = 262144
net.core.rmem_max = 262144
net.core.wmem_default = 262144
net.core.wmem_max = 262144

+ Ahora añadimos las siguientes restricciones en los siguientes archivos:

En el /etc/security/limits.conf:
oracle soft nproc 2047
oracle hard nproc 16384
oracle soft nofile 1024
oracle hard nofile 65536

En el /etc/pam.d/login:
session required pam_limits.so

Y finalmente en el /etc/profile:
if [ $USER = "oracle" ]; then
   if [ $SHELL = "/bin/ksh" ]; then
      ulimit -p 16384
      ulimit -n 65536
   else
      ulimit -u 16384 -n 65536
   fi
fi

Tras finalizar hacemos un reboot para cargar los nuevos parámetros del Kernel.

+ Ahora ya estamos en disposición de comenzar la instalación de Oracle. Para ello copiamos el “10201_database_linux32.zip” en una carpeta temporal. Por ejemplo en /usr/src/oracle10g.

Descomprimimos el software de Oracle:
# unzip /usr/src/oracle10g/10201_database_linux32.zip

+ Abrimos el entorno gráfico ya que el proceso de instalación de Oracle es en un entorno de ventanas.
# startx
# hostname
oracle.miserver.com
# xhost oracle.miserver.com
# su oracle
$ cd /usr/src/oracle10g/database
$ ./runInstaller

+ Una vez arranca el entorno gráfico de instalación hay que seguir las siguientes pantallas.
SimulacionInstalacion10gR2

+ Al finalizar la instalación no olvidarse de ejecutar (como root) los scripts de postinstalación tal como se recuerda.
# /u01/app/oracle/oraInventory/orainstRoot.sh
# /u01/app/oracle/oracle/product/10.2.0/root.sh


routing por diferentes proveedores

29 de noviembre de 2009

Supongamos que tenemos un servidor (en este caso un servidor de VPN) que por cualquier razón su conexión a Internet (por el RouterA) se ha quedado pequeña. Hemos decidido comprar un nuevo router simétrico (el RouterB) para garantizar la calidad de la conexiones VPN para ciertas personas. Una grupo de personas se conectarán a la VPN por el RouterA y otros por el RouterB.



Este ejemplo es extensible a cualquier otro tipo de servicio que queramos ofrecer de forma que una parte del trafico va por un sitio y el otro por otro. La dificultad radica en que el tráfico debe volver por el mismo router por el que ha llegado.

Para realizar esto utilizaremos el comando "ip" que nos permite manipular las tablas de rutas, crear políticas de rutas y crear tuneles.

Veamos como está la tabla de rutas del servidor:

root# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.2.0     *               255.255.255.0   U     1      0        0 eth1
192.168.1.0     *               255.255.255.0   U     1      0        0 eth0
link-local      *               255.255.0.0     U     1000   0        0 eth1
default         192.168.1.1     0.0.0.0         UG    0      0        0 eth0

root# ip route show
192.168.2.0/24 dev eth1  proto kernel  scope link  src 192.168.2.2  metric 1
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.6  metric 1
169.254.0.0/16 dev eth1  scope link  metric 1000
default via 192.168.1.1 dev eth0  proto static
Tanto el comando "route" e "ip route show" muestran la misma información. El comando "route" es la versión ligera del comando "ip route show".

Cuando Linux necesita enrutar un paquete busca dentro de las tablas su camino. Por defecto hay tres tablas de enrutamiento: local, main y default.
root# ip rule list
0: from all lookup local
32766: from all lookup main
32767: from all lookup default

Veamos que hay dentro de cada una de ellas:
root# ip route list table local
broadcast 192.168.1.0 dev eth0  proto kernel  scope link  src 192.168.1.6
broadcast 192.168.2.255 dev eth1  proto kernel  scope link  src 192.168.2.2
broadcast 127.255.255.255 dev lo  proto kernel  scope link  src 127.0.0.1
local 192.168.1.6 dev eth0  proto kernel  scope host  src 192.168.1.6
broadcast 192.168.1.255 dev eth0  proto kernel  scope link  src 192.168.1.6
broadcast 192.168.2.0 dev eth1  proto kernel  scope link  src 192.168.2.2
local 192.168.2.2 dev eth1  proto kernel  scope host  src 192.168.2.2
broadcast 127.0.0.0 dev lo  proto kernel  scope link  src 127.0.0.1
local 127.0.0.1 dev lo  proto kernel  scope host  src 127.0.0.1
local 127.0.0.0/8 dev lo  proto kernel  scope host  src 127.0.0.1

root# ip route list table main
192.168.2.0/24 dev eth1  proto kernel  scope link  src 192.168.2.2  metric 1
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.6  metric 1
169.254.0.0/16 dev eth1  scope link  metric 1000
default via 192.168.1.1 dev eth0  proto static

root# ip route list table default
(vacia)

Ver como la tabla por defecto del sistema (la que vemos al hacer "route") se llama main.

Lo que vamos hacer es crear dos tablas más (lan1 y lan2) para que contengan las rutas para cada una de las diferentes salidas a Internet. Para ello editaremos el archivo /etc/iproute2/rt_table con el siguiente contenido:
root# cat /etc/iproute2/rt_tables
#
# reserved values
#
255     local
254     main
253     default
0       unspec
#
# local
#
#1      inr.ruhep
10 lan1
20 lan2

Ahora crearemos las rutas que irán en cada una de estas tablas. Para que estas rutas se carguen en el sistema cada vez que arranquemos, la meteremos en /etc/rc.local:
root# cat /etc/rc.local
#!/bin/sh -e

ip rule add from 192.168.1.6 table lan1
ip route add 192.168.1.0/24 dev eth0 src 192.168.1.6 table lan1
ip route add default via 192.168.1.1 table lan1

ip rule add from 192.168.2.2 table lan2
ip route add 192.168.2.0/24 dev eth0 src 192.168.2.2 table lan2
ip route add default via 192.168.2.1 table lan2

exit 0
root# reboot

Estas órdenes aseguran que el tráfico que proviene de una interfaz, es contestado por la misma interfaz.

Una vez reiniciado el sistema vemos si las rutas se han cargado correctamente en el sistema:
root# ip rule list
0:      from all lookup local
32764:  from 192.168.2.2 lookup lan2
32765:  from 192.168.1.6 lookup lan1
32766:  from all lookup main
32767:  from all lookup default

root# ip route list table lan1
192.168.1.0/24 dev eth0  scope link  src 192.168.1.6
default via 192.168.1.1 dev eth0

root# ip route list table lan2
192.168.2.0/24 dev eth0  scope link  src 192.168.2.2
default via 192.168.2.1 dev eth1

Cuando un paquete llega al servidor este comprueba por orden si se cumple alguna de las reglas de tabla. Primero mira si se cumple "from 192.168.2.2". Si se cumple utiliza la tabla "lan2", de lo contrario pasará a ver si se cumple "from 192.168.1.6". Si se cumple utilizará la tabla "lan2". Por ultimo utilizará la tabla por defecto "main".

Para depurar y ver que todo funciona se puede utilizar el comando tcpdump y ver si el trafico pasa por una interfaz o u otra.

El siguiente escenario también lo podríamos utilizar por ejemplo para un servidor de correo donde queremos que el trafico del webmail (puerto 80 y 443) vaya por una ISP y el trafico al 25 vaya por otro ISP.

Más información:
+ Linux Advanced Routing & Traffic Control HOWTO

mi script de backups

8 de noviembre de 2009

Cuando empiezas hacer copias de backups, se suele empezar por un pequeño tar, luego lo programas diariamente, te envías un report por correo, luego lo envías a otra maquina y finalmente terminas haciendo copias completas e incrementales.

El siguiente script en Bash es el que utilizo para realizar copias diarias. Se ejecuta cada día en un cron. Los sábados realiza un backup completo y el resto de dias un incremental. Realiza un backup en local y también lo envía por SSH a una máquina remota.

Descargar kbackup.sh.

#!/bin/bash

### modificar las variables segun las necesidades

DATA_BACKUP="/etc/network /etc/ssh /etc/rc.local /var/log/syslog /var/log/auth.log
 /var/log/messages /var/log/dmesg /var/log/daemon.log"
LOCAL_DST_BACKUP="/var/backuplocal"
NAME_BACKUP="mi_srv"

SEND_REMOTE_BACKUP="yes"
REMOTE_DST_BACKUP="/var/backup/mi_srv"
HOST_REMOTE_BACKUP="srvbackup.miempresa"

DAY_FULL_BACKUP="Sun"

### variables especificas del script. No modificar

_LIST="/tmp/backup$$.list"

echo "kbackup.sh v0.1b, por amperis[@]gmail.com"
echo

case $1 in
   --help)
      echo "Sintaxis:"
      echo "  # ./kbackup.sh "
      echo
      echo "  --help: muestra la ayuda"
      echo "  --exec: ejecuta el script"
      echo
      echo "Notas:"
      echo
      echo "1) Editar este script y modificar las variables necesarias."
      echo "   DATA_BACKUP: Lista de directorio o fichero que de desean incluir en 
               el backup."
      echo "   LOCAL_DST_BACKUP: Directorio local donde se guardará la copia local 
               del backup."
      echo "   NAME_BACKUP: Nombre o prefijo del backup."
      echo "   SEND_REMOTE_BACKUP: yes/no, indicar si queremos que el backup tambien
               se copie"
      echo "      en un servidor remoto."
      echo "   REMOTE_DST_BACKUP: Directorio remoto donde debe copiarse el backup."
      echo "   HOST_REMOTE_BACKUP: Nombre de host o IP de la maquina remota que 
               almacena el"
      echo "      backup."
      echo "   DAY_FULL_BACKUP: Día de la semana que queremos hacer el full backup"
      echo
      echo
      echo "2) Crear una tarea programada diaria para este script."
      echo
      echo "   # crontab -e"
      echo "   @daily /root/script/kbackup.sh | mail -s 'Report de Backup' 
               admin@miempresa.com"
      echo
      echo "3) Para realizar el backup remoto es necesario que el servidor destino
               confie"
      echo "   en cliente. Copia su llave al servidor (http://amperis.blogspot.com
               /2009/02/scp-entre-maquinas.html)"
      echo     
      exit 0
      ;;

   --exec)
      echo "-> Inciado a las `date +%H:%M:%S`h"

      if [ -d "$LOCAL_DST_BACKUP" ]; then
        set $(date)
        ## Backup completo. Se realiza solo los sabados
        if test "$1" = "$DAY_FULL_BACKUP" ; then

           echo "-> Ejecutando copia completa del $3 de $2 del $6"
           _NAME_BACKUP="$NAME_BACKUP-full-$6-$2-$3.tgz"
           tar cfzv "$LOCAL_DST_BACKUP/$_NAME_BACKUP" $DATA_BACKUP
           rm -f $LOCAL_DST_BACKUP/$NAME_BACKUP-incr*

        else

           ## Backup incremental, se realiza el resto de dias
           echo "-> Ejecutando copia incremental del $3 de $2 del $6 ..."
           find $DATA_BACKUP -depth -type f \( -ctime -1 -o -mtime -1 \) -print > $_LIST
           _NAME_BACKUP="$NAME_BACKUP-incr-$6-$2-$3.tgz"
           tar cfzTv "$LOCAL_DST_BACKUP/$_NAME_BACKUP" "$_LIST"
           rm -f "$_LIST"

         fi

         echo "-> Backup creado: $_NAME_BACKUP"
         ## Enviado el backup a un servidor externo
         if [ $SEND_REMOTE_BACKUP = "yes" ]; then
            echo "-> Enviando backup a $HOST_REMOTE_BACKUP"
            rsync -avz $LOCAL_DST_BACKUP/ -e ssh root@$HOST_REMOTE_BACKUP:$REMOTE_DST_BACKUP
         fi

      else
         echo "ERROR: El directorio $LOCAL_DST_BACKUP no existe"
      fi
    
      echo "-> Finalizado a las `date +%H:%M:%S`h"
      ;;
   *)
      echo "Utilice la opción --help para más información."
      ;;
  
esac


actualizar versiones antiguas de ubuntu

25 de octubre de 2009

Dentro de las actualizaciones de Ubuntu podemos ir a buscar estas en dos repositorios muy diferentes. Uno en http://archive.ubuntu.com/ y el otro en http://old-releases.ubuntu.com/. El primero de ellos es el repositorio oficial donde se encuentran las tres últimas versiones de Ubuntu que aun están en mantenimiento y actualización. En el otro repositorio se encuentran todas las distribuciones de Ubuntu de las que se ha dejando de dar mantenimiento.

Como regla general, Ubuntu presenta nueva versión cada medio año (6 meses) y da mantenimiento de ella un año y medio (18 meses). Existen excepciones en el manteamiento ya que hay versiones de Ubuntu etiquetadas como LTS (Long Term Support) donde se presta un manteniendo de cinco años. Estas han sido la 6.06 LTS y la 8.04 LTS. Las versiones LTS permiten a los sysadmins montar servidores con altos periodos de vida sin necesidad de migrar de versión.



Si te ha dejado de funcionar el apt-get o el synaptic deberías comprobar si tú versión de Ubuntu se encuentra aún mantenida. Si no es así, deberías modificar tú source.list para que apt-get busque las actualizaciones dentro del old-releases.ubuntu.com.

En el siguiente ejemplo buscamos actualizaciones para la versión gutsy (7.10):

deb http://old-releases.ubuntu.com/ubuntu/ gutsy main restricted universe 
   multiverse
deb http://old-releases.ubuntu.com/ubuntu/ gutsy-updates main restricted 
   universe multiverse
deb http://old-releases.ubuntu.com/ubuntu gutsy-security main restricted 
   universe multiverse
deb http://old-releases.ubuntu.com/ubuntu/ gutsy-backports main restricted 
   universe multiverse


test de velocidad entre dos puntos de red

1 de octubre de 2009

La idea es saber cómo se encuentran dos puntos de red distantes (por ejemplo entre un centro en Barcelona, otro en Madrid y separados por una FrameRelay, una MPLS o por Internet). Lógicamente también sirve para medir la velocidad entre dos puntos de una misma LAN.

Normalmente haríamos un ping con tamaños variables de los paquetes y observariamos los retardos o simplemente descargariamos de un punto a otro un archivo por ftp, por web o por carpetas compartidas.

Con la utilidad Netcps.exe podemos montar un control de velocidad de un extremo a otro. Simplemente basta con copiar el ejecutable en cada una de las maquinas y poner a funcionar uno como servidor y el otro como cliente. El cliente Netcps.exe se conectará al servidor Netcps.exe del otro extremo y realizará una descarga de 100Mb. Finalmente te dará una media de la velocidad de la linea.

Supongamos que hacemos las pruebas en una red Ethernet a 100Mbps (que son aproximadamente 12.5MB/s). Lanzamos el servidor en una maquina:

C:\>netcps -server
NetCPS 1.0 - Entering server mode. Press ^C to quit
Waiting for new connection...

Ahora lo lanzamos desde la maquina cliente para obtener la velocidad (la dirección 192.168.1.106 es el otro punto extremo):
C:\>netcps 192.168.1.106
NetCPS 1.0 - Entering client mode. Press ^C to quit
Connecting to 192.168.1.106 port 4455... Connected!
---> CPS  11483136.00  KPS: 11214.00  MPS: 10.95
Avrg CPS  11432359.00  KPS: 11164.41  MPS: 10.90
Peek CPS  11509760.00  KPS: 11240.00  MPS: 10.98
Done. 104857600 Kb transferred in 9.17 seconds.

Como resultado vemos que la velocidad obtenida es de 10.9MB/s que lógicamente tiene que estar muy cercano a los 12.5MB/s reales que es la LAN Ethernet.

Más información:
- Conversor de velocidades

activar spf en zimbra

22 de septiembre de 2009

Hay una persona que me matará cuando lea esta entrada. Seguro que me dirá algo como "¿cabroncete, después de 5 años me dices que no filtra por SPF?".

Se esperaba que con la versión 6 de Zimbra ya se trajera esto activado de serie... pero va ser que no. Y mucho peor, yo creía que ya lo traía de serie. Está muy bien que tú dominio ya esté preparado con los registros de SPF y esas cosas, ¿pero tú Zimbra los está utilizando?.

[root@zimbra ~]# dig txt google.com
...
google.com.   3600   IN   TXT   "v=spf1 include:_netblocks.google.com 
                                 ip4:216.73.93.70/31 ip4:216.73.93.72/31 ~all"
...

La respuesta es no. No tengo ni puta idea de por qué no lo está utilizando sabiendo desde hace años todo el problema del spam y concretamente del phishing.

Quien hace uso de esta funcionalidad dentro de todos los módulos Zimbra es el SpamAssessin. Es más, lo intenta cargar al arrancar:
# cat /opt/zimbra/conf/spamassassin/init.pre | grep SPF
loadplugin Mail::SpamAssassin::Plugin::SPF

Lo que se intenta cargar es el módulo de Perl llamado "Mail::SPF::Query" que normalmente no está instalado en una distribución Linux, tampoco lo instala Zimbra y tampoco está como recomendación. ¿Raro no?.

Simplemente debemos instalar el módulo de Perl Mail::SPF::Query y todos los requisitos que previamente nos hace saber:
# perl -MCPAN -e shell
cpan> install Mail::SPF::Query
cpan> force install Mail::SPF::Query (utilizar este comando si hay algún 
problema durante la instalación)

Ahora solo queda reiniciar Zimbra y ver en el log como se hace uso del nuevo módulo de SPF:
# zcontrol stop && zmcontrol start
# cat /var/log/zimbra.log | grep SPF
Sep 22 21:57:52 zimbra amavis[31739]: extra modules loaded after 
daemonizing/chrooting: Mail/SPF/Query.pm

Enviamos una par de emails de pruebas y miramos el cuerpo del mensaje. Uno utilizado el módulo SPF:
X-Spam-Status: No, score=1.763 tagged_above=-10 required=6.6
 tests=[BAYES_50=0.001, HTML_MESSAGE=0.001, MISSING_SUBJECT=1.762,
 SPF_PASS=-0.001] autolearn=no

Y el otro sin utilizar el módulo de Perl:
X-Spam-Status: No, score=0.463 tagged_above=-10 required=6.6 tests=[AWL=1.299,
 BAYES_00=-2.599, HTML_MESSAGE=0.001, MISSING_SUBJECT=1.762]
 autolearn=no

Ver como ahora hay un nuevo filtro llamado SPF_PASS.

Más información:
- http://www.zimbra.com/forums/administrators/33120-zcs-6-0-open-source-enable-spf.html
- http://wiki.zimbra.com/index.php?title=Improving_Anti-spam_system#SPF
- http://www.abuses.es/eswl/doc/spamassassin-eswl.pdf

lluvia en estambul

15 de septiembre de 2009

La fecha, 9 de septiembre en Estambul, situación, datacenter de Vodafone... llegada de tormentas torrenciales. Momento desesperado el minuto 3:20.



configuración y uso de fetchmail

14 de septiembre de 2009

fetchmail es una utilidad para UNIX/Linux que nos permite hacer de cliente POP/IMAP y descargar el correo de un buzón (o varios buzones) en local. Originalmente se basaba en otro proyecto llamado popclient hasta que al introducir el protocolo IMAP en 1996 cambio de nombre.

Puede ser utilizado para varias cosas. Una de ellas es para los usuario que no tienen acceso directo a Internet y es un admin (o ellos mismo) el que acceden a la cuenta de correo bajo fetchmail y le entregan el correo es su buzón local de su maquina. Yo, por ejemplo, lo utilizo para acceder a un buzón de correo donde hay multitud de correos para varios destinatarios y lo injecto al MTA de Postfix para que los reparta entre los buzones de los usuario finales.

Permite hacer pool de cuentas, acceder via SSL, liminar el numero de mensajes a descargar para reducir el ancho de banda, programar los pools cada cierto tiempo, descargar correos de un dominio concreto, reescribir direcciones de correo, etc.

A petición popular de zimbra-grupo se ha escrito un manual de fetchmail con casos reales de configuraciones.

configuración y uso de fetchmail.pdf

Más información:
+ Manual de fetchmail

google apps como servidor de correo de backup

7 de septiembre de 2009

Google Apps tiene una versión gratuita que puede servirnos para usarla como servidor de correo secundario (backup) en nuestra infraestructura de empresa. La idea es que cuando nuestro servidor de correo principal este offline (servidor caído, mantenimiento, caída de la linea de Internet, etc) no perdamos ningún correo de los que nos envían.

Para ello simplemente nos damos de alta en el servicio con nuestro propio dominio y le decimos a Google Apps que comience a aceptar correo de nuestro dominio enviándoselo a una única cuenta de relay o backup.

Posteriormente nosotros, cuando el servidor primario vuelva a funcionar, comenzaremos haciendo un fecth de los correo.

Aquí tenéis toda la información necesaria: servidor_backup_googleapps.pdf

ocultando php

6 de septiembre de 2009

Hace algún tiempo escribí un post explicando los tres parámetros básico para ocultar el rastro de versión que dejaba Apache y PHP. Aun así, cualquier usuario podía saber si nuestra Web estaba escrita en PHP simplemente viendo que los archivos cargados de la Web terminaban en ".php".
Con ayuda del módulo mod_rewrite de Apache vamos a reescribir todas las URL de forma que el usuario no sepa en ningún momento que tipo de archivo está cargando. Nuestro objetivo es reescribir URLs como "http://miweb/index.php?id=123" por una URL como "http://miweb/index?id=123". Si el usuario quisiera cargar la página "index.php" debería producir un error de que la página no existe ya que realmente la que debe cargar es "index".

Los archivos que creemos no debemos quitarles el .php ya que esto será transparente para el programador Web.

Para crear estas reglas hay que crear un .htaccess en la raiz de nuestra Web o modificar la configuración general (el httpd.conf) de Apache.

RewriteEngine on

# Rescribe /carpeta/archivo.php por /carpeta/archivo
RewriteRule ^([^.?]+)$ %{REQUEST_URI}.php [L]

# Devuelve 404 si hacemos la petición /carpeta/archivo.php
# Para Apache en Windows utilizar esta condición. Para Linux no utilizar [NC]
# RewriteCond %{THE_REQUEST} "^[^ ]* .*?\.php[? ].*$" [NC]
RewriteCond %{THE_REQUEST} "^[^ ]* .*?\.php[? ].*$"
RewriteRule .* - [L,R=404]

Más información:
- Apache mod_rewrite

los peligros del informador

27 de agosto de 2009

Una de las cosas que más gusta a un programador es saber en que servidor y que configuración por defecto tiene antes de empezar a programar su Web. Para los programadores de PHP tenemos una función muy bonita llamada phpinfo() que nos muestra una tabla colorida con toda la información de estado actual del motor de PHP, la versión del sistema Linux (o Windows), la ruta por defecto del php.ini, los módulos cargados del Apache, etc.

Muchas veces estas paginas quedan olvidadas dentro de nuestra aplicación Web a la espera que gente "despistada" las llame... nombres como hello.php, info.php e incluso phpinfo.php es lo normal.
Una búsqueda rápida en Yahoo o Google nos da una idea de los despistados programadores que han ido dejando sus pruebas.


La información que puedes encontrar en estas paginas es muy valiosa para la gente "con mucho tiempo libre", ya que puede encontrar números de versiones, módulos de Apache a los cuales poder atacar si existiera un bug, estado de los permisos de archivo o safe_mode o incluso en la variable path puedes encontrar otro tipo de software que corre en la maquina, como por ejemplo: NetBackups, tools de servidores Dell, antivirus, etc.

formularios php con muuu (parte ii de ii)

24 de agosto de 2009

muu posee diferentes tipos de datos que podrán utilizarse dentro de la función addField(). Estos pueden ser: text, textarea, password, select, radio o checkbox. Como vemos representan las estrucutas típicas de un formulario HTML.

Estos son algunos ejemplos:

$form->addField("text", "fecha", "Fecha de compra", array("instructions"=>"En 
       formato dd/mm/aaaa"));
$form->addField("checkbox", "vehiculo", "¿Qué vehiculo tienes?", 
       array("checkbixValues"=>array("moto"=>"Motocicleta","coche"=>"coche")));
$form->addField("select", "colores", "Seleccione un color", 
       array("selectValues"=>array("rojo"=>"Rojo","Azul"=>"Azul")));
$form->addField("radio", "sexo", "Sexo", 
       array("radioValues"=>array("hombre"=>"Hombre","mujer"=>"mujer")));
$form->addField("textarea", "opinion", "Su opinion");

Por otro lado, tambien tenemos un montón de tipos de reglas de validación. Veamos las más importantes:

- required: el campo no puede estar vacio.
- email: el campo debe ser una dirección de correo.
- emailorblank: el campo debe ser una dirección de correo o estar en blanco.
- rangelength: la longitud del campo debe estar dentro de un minlength y un maxlength
- equal: el valor del campo debe ser igual a otro valor
- lettersonly: el valor del campo debe tener solo letras
- aphanumeric: el valor del campo contiene letras y numeros
- numeric: el valor del campo contiene solo numeros
- maxvalue: el valor del campo no puede ser mayor del maxvalue
- minvalue: el valor del campo debe ser mayor que el minvalue
- float: el valor del campo debe ser un numero real
- integer: el valor del campo debe ser un numero entero
- ip: el valor del campo debe ser una dirección IP
- url: el valor del campo debe ser una dirección URL
- date: el valor del campo debe contener una fecha en formato dd/mm/aaaa.

Existen otras más y por si aun no se nos satisface nuestras necesidades siempre podemos utilizar la opción de regla "regex" que nos permite crear nuestra propia expresión regular para satisfacer nuestra propia regla de filtrado.

Veamos algunos ejemplos de estas reglas:
$form->addRule("required", "apellido", "El apellido no puede estar en blanco");
$form->addRule("date", "fecha_compra", "La fecha de compra no es correcta");
$form->addRule("rangelength", "password" , "La contraseña debe tener más de 3 
               caracteres", array("minlength"=>4,"maxlength"=>256) );
$form->addRule("equals", "clave", "Contraseñas diferentes", array("equalfield"=>"clave2"));

Para finalizar y una vez comprendido cómo funciona muuu, este es el código completo de una pagina de login desarrollada utilizando las librerías de muuu:
<?php
   include_once("muuu-v0.5.class.php");
   
   //--- campos de mi formulario
   $form= new muuu("form", "post", "login.php");
   $form->addField("text", "login", "Usuario: ", array("instructions"=>"(utiliza tú 
                   dirección de correo)") );
   $form->addField("password", "password", "Contraseña: ");
   $form->addField("submit", "boton", "", array("fieldAdd"=>"value='Enviar'"));

   //--- reglas de mi formulario
   $form->addRule("email", "login", "El nombre de usuario tiene que ser una 
                  direccion de correo válida.");
   $form->addRule("rangelength", "password" , "La contraseña debe tener más de 3 
                  caracteres", array("minlength"=>4,"maxlength"=>256) );
   
   if ( $form->formSuccess() == true ) {
      //--- procesamos los datos del formulario. En este caso se trata de una validación de usuario
      if ( $form->formValue("login")=="usuario@miempresa.com" &&
           $form->formValue("password")=="12345" )
         echo "Ok, estas dentro";
      else
         echo "Este usuario no es correcto";      
   } else {
      //--- arrancamos el formulario
      $form->startForm();
      echo "<fieldset>";
      echo "<legend>Inicio</legend>";
      //--- imprimimos el formulario
      foreach ( $form->fieldsarray as $key=>$value ) {
         echo "<p><label for='$key'>" . $form->labelsarray[$key] . "</label>$value</p>";
         echo "<p id='instructions'>" . $form->instructionsarray[$key] . "</p>";
         echo "<p id='error'>" . $form->errorarray[$key] . "</p>";   
      }
      echo "</fieldset>";
      $form->endForm();
   }
?>


formularios php con muuu (parte i de ii)

23 de agosto de 2009

Aunque suene a mugido de vaca española, "muuu" es una clase en PHP para facilitar a los programadores el desarrollo de formularios en PHP. Resulta muy pesado el escribir todo el código HTML del form, los campos, luego validarlos, repetir el campo si este no es correcto...

Para solucionar esto existe una librería libre llamada muuu que con dos funciones addField() y addRule() nos permite crear campos en nuestro formulario y lo más importante crear reglas que validen nuestro formulario. Para ver como funciona imaginemos que queremos una pagina PHP para validar a un usuario (una login.php). Con dos campos: nombre de usuario y contraseña. Como dos reglas, el nombre de usuario será una dirección de correo y la contraseña deberá tener más de 3 caracteres. Si no se cumple ninguna de estas reglas, el formulario no se procesa.

Lo primero que tenemos que hacer es cargar la librería, crear el formulario y añadir los campos que necesitamos (dos campos de texto y el botón de enviar):

   include_once("muuu-v0.5.class.php");
   $form= new muuu("form", "post", "login.php");
   $form->addField("text", "login", "Usuario: ", array("instructions"=>
                   "(utiliza tú dirección de correo)") );
   $form->addField("password", "password", "Contraseña: ");
   $form->addField("submit", "boton", "", array("fieldAdd"=>"value='Enviar'"));

Posteriormente debemos crear las reglas que deben cumplir nuestros campos. El usuario debe ser una dirección de correo electrónico y la contraseña debe tener más de 3 caracteres:
   $form->addRule("email", "login", "El nombre de usuario tiene que ser una 
                  direccion de correo válida.");
   $form->addRule("rangelength", "password" , "La contraseña debe tener más de 3 
                  caracteres", array("minlength"=>4,"maxlength"=>256) );

Una vez configurado nuestro formulario solo falta arrancarlo, imprimirlo en la Web y procesar el formulario si todos los campos han pasado las reglas:
   if ( $form->formSuccess() == true ) {
      //--- procesamos el formulario
   } else {
      //--- arrancamos el formulario
      $form->startForm();
      foreach ( $form->fieldsarray as $key=>$value ) {
         echo "<p><label for='$key'>" . $form->labelsarray[$key] . "</label>
              $value</p>";
         echo "<p id='instructions'>" . $form->instructionsarray[$key] . "</p>";
         echo "<p id='error'>" . $form->errorarray[$key] ."</p>";   
      }
      echo "</fieldset>";
      $form->endForm();
   }

El próximo post veremos el código completo de login.php

obtener todas las direcciones de correo

18 de agosto de 2009

La siguiente linea de comandos obtiene todas las direcciones de correo que aparecen dentro del log de Zimbra o cualquier otro archivo de log.

# sed -n -e '/postfix\/smtp\[.*status=sent/s/^.*to=<\([^>]*\).*$/\1/p' /var/log/zimbra.log | sort -u


hackeando el cristal glaseado con celo

7 de agosto de 2009



orden de preferencias en mysql

3 de agosto de 2009

En infomática por regla general la multiplicación y la división tienen preferencia sobre operaciones como la suma y la resta. Algo similar tambien sucede con operaciones lógicas como AND y OR. Las ANDs tienen preferencia sobre las OR. Una mala construcción de una consulta SQL nos puede jugar malas pasadas:

select true and false --> FALSE
select true or true and false --> TRUE

Esta característica se puede utilizar para saltarse mediante injección SQL paginas de login (en este caso PHP) que tengan una consulta así:
$sql = "
   SELECT * 
   FROM users 
   WHERE username='".$_POST["username"]."' AND password='".md5($_POST["psw"])."'";

Como vemos el campo password no es injectable ya que cualquier valor introducido es filtrado por una función. En este caso un hash md5.
El único parámetro injectable es username. Pongamos lo que pongamos en username siempre arrastraremos un "AND password=md5()" que por tanto deberá evaluarse.

Si tenemos en cuenta la prioridad en las operaciones AND/OR de MySQL podemos injectar con:
Username: ' or username<>'' or password<>'
Password: foo

La consulta SQL queda así:
SELECT * 
FROM users 
WHERE username='' or username<>'' or password<>'' 
      AND password='acbd18db4cc2f85cedef654fccc4a4d8'

La consulta siempre será evaluada a TRUE.

proteger ficheros en apache para su descarga

29 de julio de 2009

Muchas veces cuando programamos directamente sobre una carpeta del DocumentRoot dejamos sin querer todo tipo de archivos como backups de una carpeta, volcado sql de una tabla, backup de un archivo php generado por nuestro editor de texto, archivos de include, etc. Todos estos archivos quedan disponibles para la descarga.

La directiva <FilesMatch> de Apache evita que cualquier archivo no deseado con información sensible pueda ser descargada. Para ello simplemente tenemos que pasarle una expresión regular con los archivo que queremos denegar el acceso y el Apache devolverá un error 403 cada vez que se intente acceder a ellos:

<FilesMatch "\.(old|bak|tgz|sql|inc|tar\.gz|zip|rar)$">
   Order Deny,Allow
   Deny from All
</FilesMatch>

La ultima vez que utilicé esto era para proteger dumps de SQL que se generaban automáticamente (ddmmaaa-backup.sql.tgz) y que por narices debían de permanecer dentro del DocumentRoot de la aplicación.

Solo hace falta darse un a vuelta por la Google Hacking Database para encontrar todo tipo de ficheros como estos por Internet.

¿qué es ITIL? (ii de ii)

24 de julio de 2009

3. Transmisión del servicio

Consiste en preparar y dejar listo el servicio garantizando el menor impacto posible sobre los servicios en producción, las operaciones y la propia organización. Esta fase consta de tres procesos: gestión de cambios, gestión de la configuración y gestión de versiones.

La gestión de cambios tiene como objetivo emplear medios y procedimientos estandarizados para una tramitación eficaz y rápida de todos los cambios, a fin de reducir al mínimo el impacto sobre los servicios relacionados. Se define la figura del comité de cambios como un asesor que se reúne periódicamente para evaluar cambios y ayudar a priorizarlos.

La gestión de la configuración define y controla todos los componentes de una infraestructura IT y mantiene una base de datos con toda la información de las configuraciones (CMDB, Configuration Management Database).

Por último la gestión de versiones garantiza que existen planes de cambios y despliegues necesarios para mantener la alineación con los clientes y el negocio en los proyectos de cambios. Asegura que las versiones podrán crearse, instalarse, testearse y desplegarse exitosamente dentro de los plazos establecidos.

4. Operación del servicio

Consiste en coordinar y ejecutar las actividades, procedimientos y procesos necesarios para entregar y gestionar servicios con los niveles acordados. En esta fase se administra el servicio contratado por el cliente y se le da soporte.

Aparecen cinco procesos: gestión de incidencias, gestión de problemas, gestión de peticiones de servicio, gestión de accesos y gestión de eventos.

La gestión de incidencias tiene como objetivo restaurar la operación normal del servicio tan rápido como sea posible y minimizar el impacto negativo.

La gestión de problemas estudia más tarde y más detalladamente todas las incidencias producidas para evitar que se vuelvan a producir.

La gestión de peticiones define un único canal para que el cliente pueda recibir o solicitar servicios estándares (de nuestro catálogo) y aprobados.

El objetivo de la gestión de accesos es proporcionar a los usuarios autorizados el derecho a utilizar los servicios mientras se impide el acceso a otros. Se basa siempre sobre la gestión de disponibilidad y la gestión de seguridad de los puntos anteriores.

Por último la gestión de eventos proporciona la detección de fallos, proporcionando la capacidad en tiempo de real de comparar el rendimiento de nuestro servicio IT con lo contratado por el cliente en la SLA.

5. Mejora continua del servicio

Su objetivo es hacer recomendaciones sobre cualquier oportunidad de mejora durante toda la fase de vida del servicio. También intenta mejorar la rentabilidad de la prestación del servicio sin sacrificar la satisfacción del cliente.

¿qué es ITIL? (i de ii)

Últimamente están apareciendo en muchos centros una nueva certificación llamada ITIL Foundation. Yo en su día me tuve que preguntar que era esto de la ITIL...
ITIL son las siglas de Information Technology Infraestructure Library, y como en muchas certificación IT consta de muchos cursos, cada uno con su examen y su pasta para desembolsar.

El primer curso de ITIL es el que se conoce como la ITIL Foundation v3, que básicamente es la base que se debe conocer. El concepto de ITIL recoge un conjunto de las mejores prácticas para la gestión eficiente de una infraestructura de servicios IT. Fue escrita por la agencia de telecomunicaciones británica en los 80 y se ha demostrado con el tiempo su utilidad en cualquier empresa de cualquier tamaño.

La ITIL Foundation se estructura y se estudia según cinco libros (no necesariamente en este orden):

- 1. Estrategia del servicio
- 2. Diseño del servicio
- 3. Transmisión del servicio
- 4. Operación del servicio
- 5. Mejora continua de la calidad del servicio

Como veis se trata de un orden lógico en el diseño, implementación y puesta en marcha de un servicio.

En la ITIL Foundation se da una explicación muy detallada de cada una de estas fases y como se relacionan entre sí. Además proporciona todo un vocabulario muy extenso que debe aprenderse ya que se utiliza constantemente en todos las fases.

Explico que es cada una de estas fases:

1. Estrategia del servicio

El objetivo de esta fase es identificar a la competencia y hacer diferenciar nuestro producto o servicio. Debemos encontrar respuestas a ¿qué servicios ofreceremos y a quién?, ¿cómo nos diferenciaremos?, ¿cómo alcanzamos una calidad de servicio?... En esta fase ITIL distingue tres procesos llamados: gestión financiera, gestión de la demanda y gestión del portfolio.

En la gestión financiera debemos de cuantificar, a través de una análisis de inversión, el coste de cada uno de nuestros servicios IT a lo largo de todo su proceso de vida.

En el proceso de gestión de la demanda debemos calcular con precisión la demanda que puede suponer un servicio y de esta forma ajustar al máximo los recursos IT que poseemos.

Por último en la gestión del porfolio encontraremos todo lo que sabemos hacer. No todo está disponible, pero un buen porfolio nos permite anticipar nuestros servicios IT a la competencia.

2. Diseño del servicio

El objetivo de esta fase es diseñar el servicio IT siempre minimizando los riesgos, cumpliendo los objetivos marcados en la estrategia y ahorrando en tiempo y dinero. En el diseño del servicio se definen 5 procesos: gestión del catálogo, gestión del nivel del servicio, gestión de la disponibilidad, gestión de la continuidad, gestión de los proveedores, gestión de la seguridad y gestión de la capacidad.

La gestión del catálogo es proporcionar una única fuente de información de todos los productos que proporciona nuestra empresa. Se trata de un subconjunto de servicios disponibles en nuestro porfolio (definido en la estrategia del servicio). Nosotros ofrecemos nuestro catálogo de servicio al cliente y cualquier otra cosa que no se encuentre en nuestro catálogo, para ITIL no se puede ofrecer.

La gestión del nivel del servicio controla y mejora los niveles acordados al comprar un servicio. Se define el concepto de SLA (Service Level Agreemet) que se estipula en el contrato del cliente (tiempos de respuesta, tiempos de parada, horarios de atención al cliente, etc).

La gestión de la disponibilidad optimiza los recursos de nuestra IT para que todo funcione correctamente para cumplir la SLA firmada por el cliente.

La gestión de la continuidad del servicio se preocupa de que todo siga funcionando en caso de una fuerza mayor. Por ejemplo redundando lo servicios en otro lugar y siempre teniendo en cuenta que la continuidad de nuestro servicio debe cumplir la SLA.

La gestión de los proveedores negocia y acuerda todos los contratos con terceros. El mantenimiento de una política con nuestros proveedores debe asegurar como siempre los niveles de SLA. No podemos dejar de prestar un servicio porque nuestro proveedor nos ha fallado.

La gestión de la seguridad como este todas políticas de seguridad debe asegurar la confidencialidad, la integridad y la disponibilidad de toda la información que manipulamos. Además incluye políticas sobre control de contraseñas, acceso remoto y el uso correcto de todos los activos por parte de los trabajadores.

Por último la gestión de la capacidad es la encargada de que todos los servicios se vean respaldados por una capacidad de proceso y almacenamiento suficiente. Debemos estudiar que los recursos se aprovechen adecuadamente (ni más ni menos) para evitar inversiones innecesarias. O peor aun, que los recursos que tengamos se queden cortos y no nos permitan cumplir la SLA.

hackeando las pilas

un ordenador en la luna

21 de julio de 2009

No se que pasa que cada día en la tele estamos llegando a la luna. Cada día estamos celebrando que el hombre llegó a la luna. Yo soy de los que no se cree que llegara, al menos, en la fecha oficial.

Lo que si me ha hecho gracia y he perdido un poco el tiempo es en leer la publicación del diseñó interno del AGC (Apollo Guidance Computer) o para los mortales que veían Start Treck el ordenador de a bordo o TomTom. Viendo los diagramas del diseño y la reducción de puertas lógicas me parecía haber vuelto a la universidad cuando estudiaba la asignatura de estructura de computadores.

Resulta que el AGC puede considerarse el primer computador de circuito integrado empotrado y en tiempo real. Tenía un procesador de 1Mhz y 4Kb de memoria RAM. Además tenia un juego de 11 instrucciones. Este cacharro se utilizaba para realizar los cálculos para los aterrizajes y los acoplamientos. A lo largo de las diferentes misiones del Apollo se fue perfeccionando su funcionamiento ya que en su primera misión este cacharro fallo y los astronautas del Apollo 11 tuvieron que aterrizar de forma manual.

Aquí tenéis los planos del AGC por si queréis montaros uno en casa y subiros en un petardo para llegar a la luna. Son más de 1000 paginas de diseño con un coste de $3000 en componentes.

Ya me veo algún becario de arquitectura de computadores que le manden de proyecto final de carrera la implementación del AGC. A pelearse con los mapas de Karnaugh.



mira dentro de mí

15 de julio de 2009

Cuando enviamos un correo electrónico de una dirección a otra, toda esta información se envía en formato texto ASCII. Incluso cuando adjuntamos una imagen o un archivo PDF el correo resultante que viaja de un servidor a otro lo hace en formato texto.
Para ello se utilizan conceptos como los tipo MIME y la codificación en Base64. Hoy día es difícil ver correos que no este hechos en formato HTML con imágenes y a todo color.

Cuando enviamos un correo no solo estamos enviado el cuerpo del mensaje con su From/To, sino mucha más información como editor de correo donde se escribió el mensaje, cuales han sido los antivirus que han analizado el correo, por donde ha ido pasando el correo etc.
El analizar las cabeceras de un correo electrónico puede ser una manera de depurar errores y de comprender un poco más el funcionamiento del SMTP.

Aquí tenéis un ejemplo de un correo que utilizaré para explicar cada una de las partes que lo componen: example_mail.txt.
Se trata de un correo de publicidad de masters de la Universidad de La Salle (Barcelona) enviado a mí a través de una lista de distribución tal como veremos. Desde cualquier cliente de correo podéis acceder a las cabeceras de un correo electrónico.

Si abrimos este correo de ejemplo lo primero que miraremos es quien lo escribe y quien lo recibe:

From: "BES La Salle" <infosolicitud@lasalleonline.net>
To: <infosolicitud@lasalleonline.net>

Es curioso ver que el emisor y el receptor son la misma persona. ¿Cómo puede ser?. En este caso se trata de una lista de distribución. Para ello debemos fijarnos en:
Delivered-To: amperisblog@gmail.com
List-Unsubscribe: <http://columba.salleURL.edu/cgi-bin/mailman/options/infoalumnes>,
                <mailto:infoalumnes-request@columba.salleURL.edu?subject=unsubscribe>
X-Mailman-Approved-At: Fri, 10 Jul 2009 10:09:03 +0200

Nos da la posibilidad de borrarnos de la lista de distribución. Este tipo de casos también pude darse cuando se envia un mail con copia oculta. En el campo To: no aparece nuestro nombre. Esto es debido a que nos han puesto como copia oculta.

También tenemos el campo Date que indica la hora a la que se escribió el mensaje. No es la hora en la que se descargó el mensaje. Por este motivo si tenemos algún problema con nuestro servidor de correo y los correos llegan tarde, es normal que nos aparezcan en nuestra bandeja de entrada correos de fechas pasadas. Normalmente la bandeja de entrada está ordena por fecha.

Date: Fri, 10 Jul 2009 10:08:34 +0200

También podemos ver los diferentes servidores MX por los que ha ido pasando el correo y extraer mucha información de como una empresa tiene implementado sus servidores de correo. Para ello nos tenemos que fijar en los campos "Received":
Received: by 10.103.218.8 with SMTP id v8cs318399muq;
        Fri, 10 Jul 2009 01:10:31 -0700 (PDT)
Received: by 10.204.50.195 with SMTP id a3mr1643982bkg.123.1247213430935;
        Fri, 10 Jul 2009 01:10:30 -0700 (PDT)
Received: from relay1.salle.url.edu (relay1.salle.url.edu [84.88.232.246])
        by mx.google.com with ESMTP id 27si1340370fxm.114.2009.07.10.01.10.29;
        Fri, 10 Jul 2009 01:10:30 -0700 (PDT)
Received: from columba.salle.url.edu (columba.salleURL.edu [84.88.232.238])
 by relay1.salle.url.edu (8.14.3/8.14.3/Debian-5) with ESMTP id n6A8A2sH019065
 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT);
 Fri, 10 Jul 2009 10:10:03 +0200
Received: from columba.salle.url.edu (localhost [127.0.0.1])
 by columba.salle.url.edu (8.14.3/8.14.3/Debian-5) with ESMTP id n6A894eQ014556;
 Fri, 10 Jul 2009 10:09:59 +0200
Received: from jordiribesi00cc (pcjribes.salle.url.edu [172.16.17.189])
 (authenticated bits=0)
 by columba.salle.url.edu (8.14.3/8.14.3/Debian-5) with ESMTP id
 n6A88ZMC014449; Fri, 10 Jul 2009 10:08:35 +0200

El primer Received que encontramos es directamente nuestro servidor donde está alojado el correo a la espera que nosotros lo leamos por POP/IMAP/Webmail. El último "Received" es el primer servidor SMTP que recibió el correo.
Podemos ver como el correo lo escribió una persona llamada jordiribesi00cc, que su ordenador tenia la IP 172.16.17.189 y que se lo envió a su servidor de correo llamado columba.salle.url.edu" que resulta ser un Sendmail versión 8.14.3 con un Debian v5.
Luego lo volvió a recibir la maquina columba.salle.url.edu en la IP 127.0.0.1. Esto es posible porque se lo pasó al antivirus alojado en su misma maquina. Posteriormente se lo envía a una maquina de relay de correo bajo el nombre de relay1.salle.url.edu a través de una sesión cifrada (cipher=DHE-RSA-AES256-SHA). Finalmente esta maquina sale de la empresa salle.url.edu y contacta con Google para entregarle el correo. La maquina relay1.salle.url.edu con IP pública 84.88.232.246 contacta con el servidor mx.google.com y le entrega el correo a las 01:10:30 hora verano del Pacifico Norte (PDT=UTC-7).
Para finalizar, el correo va pasando por dos máquina más de Google hasta que a las 01:10:31 hora verano del Pacifico Norte se almacena en el servidor con IP 10.103.218.8.

Notar que hay 7 saltos para hacer llegar el correo de un servidor a otro. ¿Son 7 o son más?. Realmente no lo podemos saber. Podría ser el caso que algún servidor interno, por ejemplo Google, no notificara en sus cabeceras por donde va pasando dicho correo.
Otra cosa interesante es saber la versión de Sendmail que está utilizando salle.url.edu. Deberíamos evitar que nuestros servidores dejaran información sobre versiones y sistemas operativos de los servidores de correo. Normalmente por cuestiones de seguridad y bugs que puedan ser explotados.

Se está trabajando en técnicas conocidas como "Reciprocation of SMTP Trace Record" para depurar por donde a ido pasando un correo electrónico. Incluso existe alguna Web que haces un copy-paste del tus Received y te dibuja en un mapa la ruta seguida por el correo al más puro estilo Neotrace.

Los antivirus y otros filtros también dejan su marca cada vez que escanean un correo:
X-Virus-Scanned: ClamAV version 0.94.2, clamav-milter version 0.94.2 on relay1.salle.url.edu
X-Virus-Scanned: ClamAV version 0.94.2, clamav-milter version 0.94.2 on columba.salle.url.edu
X-Virus-Scanned: ClamAV version 0.94.2, clamav-milter version 0.94.2 on columba.salle.url.edu
X-Virus-Status: Clean
X-Scanned-By: MIMEDefang 2.64 on 84.88.232.246
X-Scanned-By: MIMEDefang 2.64 on 84.88.232.238
X-Scanned-By: MIMEDefang 2.64 on 84.88.232.238

Estamos en lo de simpre... evitar que aparezcan versiones y cualquier tipo de información.

Nota: Para evitar que nuestro Postfix/Sendmail anote sus direcciones IP internas o externas en la cabeceras hay que retocar el código fuente y recompilar.

Para debugear este correo cuando llega al primer servidor de correo se añade una marca de idetificación llamada Message-ID. Esta marca la podemos utilizar para tracear el mensaje dentro de nuestros logs de correo.
Message-ID: <000601ca0135$9f2ab0b0$dd801210$@net>

Finalmente llegamos a la parte del cuerpo del mensaje. Dado de que se trata de un correo con imágenes, en HTML y con archivos adjuntos este correo debe ser compuesto en formato MIME (Multipurpose Internet Mail Extension). El MIME son unas extensiones del protocolo SMTP que me permite intercambiar todo tipo de contenido (video, PDF, imágenes, Words, etc) de forma transparente para el usuario.

Lo primero que debemos encontrar son estas dos cabeceras:
MIME-Version: 1.0
Content-Type: multipart/mixed;
 boundary="----=_NextPart_000_0007_01CA0146.62B380B0"
X-Mailer: Microsoft Office Outlook 12.0

Lo primero indica que estamos utilizando MIME v1 y el segundo nos indica que el mail está estructurado en varias partes (cuerpo, adjuntos, cuerpo en HTML, etc). En este caso cada parte podrá contener más objetos de tipo MIME. Para separar cada parte de los objetos MIME se utilizará la marca "----=_NextPart_000_0007_01CA0146.62B380B0". Vemos también que el cliente de correo que ha construido el mail en formato MIME a sido un Outlook 2007.

Dentro del objeto MIME con marca "----=_NextPart_000_0007_01CA0146.62B380B0" veremos que encontramos otros objetos MIME que lógicamente también contienen su marca. Por ejemplo "----=_NextPart_001_0008_01CA0146.62B380B0" o "----=_NextPart_002_0009_01CA0146.62B380B0".

Bajo la marca "----=_NextPart_002_0009_01CA0146.62B380B0" encontramos el cuerpo del mensaje en formato texto o "text/plain". Este tipo de objeto se añade por si el receptor no tiene un cliente de correo que acepte HTML.
Luego encontraremos bajo esta misma marca el mismo correo pero en formato HTML o "text/html". Este tipo de objeto se añade para los clientes que tienen un cliente de correo compatible con HTML.

Finalmente, los ficheros adjuntos también van dentro de su tipo MIME:
------=_NextPart_001_0008_01CA0146.62B380B0
Content-Type: image/jpeg;
 name="image001.jpg"
Content-Transfer-Encoding: base64
Content-ID: 

/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIf
IiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7
Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wAARCAB8AoQDASI
...

En este caso, una de las imágenes a sido añadida como un tipo de fichero adjunto. Para ello le decimos que es de tipo MIME "image/jpeg", que la imagen se llama image001.jpg y que está codificada en Base64. La codificación siempre es necesaria ya que al tratarse de un formato binario este debe convertirse en un formato de texto ASCII para poder ser enviado por SMTP.

Hay otras muchas cabeceras que incluso no salen es este mail de ejemplo. Todas ellas esta explicadas en sus RFCs correspondientes: RFC2045 y RFC2821.

Más información:
- http://es.wikipedia.org/wiki/Multipurpose_Internet_Mail_Extensions
- http://es.wikipedia.org/wiki/Base64

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