La red de la empresa es un quilombo. Tenemos la red de la oficina por un lado, con los desktops en una red privada y los servers en una red pública (parte de la red pública del edificio donde está la oficina). Tenemos dos CoLos, uno en Rotterdam (Verizon; no me pidan comentarios) y otro en Amsterdam (xs4all; parece que le da housing a la mitad de .nl). En el primero tenemos tres rangos públicos y al menos dos privados, y en el otro tenemos sólo un rango público y unos dos o tres privados, incluyendo un cross-over entre los dos firewalls para hacer fail-over. En resumen, 5 redes públicas y vayasabersecuántas privadas desperdigadas.

Para complicar un poco más las cosas, montamos (bueno, yo no tuve nada que ver, pero ya trabajaba acá) una VPN entre los dos CoLos, teniendo ambas puntas en los firewalls (sin contar de que una punta tenemos dos; uno duerme hasta que el otro se cae).

El último ingrediente de esta sopa: graficamos el tráfico con MRTG (si, ya sé de Munin, ya lo sugerí, pero son como 80 servers en total) sacando los datos por SNMP (que, como dicen en todos lados, de simple tiene sólo el nombre). Pero para el caso es simple: un cliente corre en el server graficador, en este caso en Rotterdam, y en el nodo a graficar un servidorcito SNMP; el tráfico es por UDP.

'Bueno, ¿y dónde está la complicación?', se preguntarán. Les cuento.

Esta gente (notar cómo cuando se mandan una 'cagada' me despego :-P) tiene unos firewalls implementados a mano en bash. No es la típica ristra de reglas iptables, sino algo un poco más elaborado, con funcioncitas, pero aún así son 1400 líneas de bash y otras 630 de configuración (en bash también, obvio; no hay manera más fácil de hacer configuración de scripts bash que en bash mismo). Ya les comenté de shorewall también, pero todo a su tiempo.

Entonces me tocó la tarea de poner a andar el SMNP contra los firewalls de Amsterdam. Parece una boludez, sobre todo porque el MRTG tiene scripts con los que crear la configuración automáticamente leyendo lo que hay disponible por el mismo protocolo (lo diseñadores tuvieron la decencia de ponerle 'descubribilidad'). Por simple que parezca, no andaba nipatrásnipadelante. Le dimos quichicientas vueltas y náa.

Lo más raro fue cuando empezamos a usar tcpdump en las interfaces externas de los firewalls. Filtrando por el puerto 161 (snmp), en el firewall de Amsterdam veíamos el tráfico entrante pero no el saliente. Eso nos llevó a pensar que el firewall estaba jodiendo, pero entonces vimos que el tráfico que generaba el gráfico para el otro firewall, el durmiente, hacía lo mismo: veíamos el request pero no la respuesta. Pero el gráfico andaba. Y para complicar las cosas, con IPSec andando no deberíamos ver el tráfico, pues tcpdump no sabe desencriptar esos paquetes, sino apenas reconocerlos.

Entonces sospechamos.

Probando el tcpdump en el firewall de la red de Rotterdam vimos un comportamiento simétrico: no veíamos el request pero si la respuesta. Y sospechamos mas fuerte.

Mirando con mas fuerza me dí con que los scripts de firewall tenían un par de bugs: la función que seteaba las excepciones para el firewall mismo no era llamada nunca y además llamaba a iptables con parámetros erróneos.

La conclusión a la que llegamos, basada únicamente en lo que pudimos ver, es que el túnel anda, y que IPSec hace cosas raras con los paquetes; creemos que cuando los termina de procesar un paquete lo inyecta en la interfaz por la que entró, y eso es lo que hace que veamos el tráfico para un lado. Algún día que esté muy aburrido me voy a poner a ver si esta teoría es cierta.

sysadmin security

Posted Mon 29 Jun 2009 11:39:52 PM CEST Tags: sysadmin

Since a couple of hal versions (0.5.12~git20090406.46dc48-1) in Debian Sid, it stopped using system groups as the method to grant privileges to users, and started using something called PolicyKit instead. Just to remember what are we talking about here, a user in the powerdevil group used to suspend or hibernate his machine sucessfully. But now Mr. PL is a not-understood monster and the package does not give a smooth transition. That's what I'll try to do here.

To make sure this is the problem, let's try to suspend the machine simply by calling hal through d-bus. I use qdbus here, found in the libqt4-dbus package, because it lets me introspect the dbus interface, but you could use dbus-send instead:

qdbus --system org.freedesktop.Hal /org/freedesktop/Hal/devices/computer org.freedesktop.Hal.Device.SystemPowerManagement.Suspend 0
Error: org.freedesktop.Hal.Device.PermissionDeniedByPolicy
org.freedesktop.hal.power-management.suspend no <-- (action, result)

If we edit the file /etc/PolicyKit/PolicyKit.conf we'll see the empty default config that comes with the package. According to its documentation, we just need to add a couple of nested <match> tags with a <return> inside. The outher match will filter the hal action, the inner one the group, and the return will grant access.

... we wish! There's no way to match to a group, only to a user. Ok, the first shot will use the user, then we'll see if we really can do it.

How do we discover which action we must use? We can use polkit-action to see what are the available actions. In the first case, org.freedesktop.hal.power-management.* will do.

<match action="org.freedesktop.hal.power-management.*">
    <!--match group="powerdev"-->
    <match user="mdione">
        <return result="yes"/>
    </match>
</match>

Now the previous command suspends the machine allright! Next, removable devices:

<match action="org.freedesktop.hal.storage.mount-removable">
    <!--match group="plugdev"-->
    <match user="mdione">
        <return result="yes"/>
    </match>
</match>
<match action="org.freedesktop.hal.storage.eject">
    <!--match group="plugdev"-->
    <match user="mdione">
        <return result="yes"/>
    </match>
</match>

I added the eject action just in case. All this works fine for my user, but I really liked the group interface. The complaining about it was that it was too coarse, and now this way one can grant specific actions in amore fine grained way, but I think is too fine grained. Unluckly we cannot (ab)use the define_admin_auth tag to give a similar functionality, it doesn't work that way (I don't know what way it works either).

As a final note, see that I used a per-action approach, where the outer match points to an action. we could use a per-user approach, where the outer match points to a user:

<match user="mdione">
    <match action="...">
    <match action="...">
    <match action="...">
</match>

debian sysadmin

Posted Wed 27 May 2009 05:25:03 PM CEST Tags: sysadmin

El sábado pasado recibo un mail de un chango del laburo con subject «ayuuuudaaa urgenteeeeee»[sic]. Me dice que estaba boludeando el viernes a la noche cuando la máquina se quedó primero sin sonido y luego se tildaba. Cuando la quizo reiniciar no arrancó más. «dice algo de disco no booteable...».

El lunes caigo como siempre y me voy a verla. Efectivamente, decía algo de disco no booteable. Booteo con un GRML que tengo en un pendrive y descubro que el disco no tiene particiones.

Pánico.

El tipo está acá haciendo un posdoc en algo astronómico (literalmente) y todo su laburo está ahí dentro. No hay backups, como corresponde, así que me preparo a hacer un rescate de particiones.

En el mismo pendrive tengo un sistema con parted. Booteo con eso y trato de usar el rescue del parted. Naranja. Le pregunto cómo eran las particiones, etc. Me responde que él sólo instaló un Kubuntu por defecto. Por defecto Kubuntu crea una partición swap y una ext3 para / y eso es todo, lo cual hacía mas fácil lo que estaba por venir.

Reninicio en el GRML y con hexdump -C /dev/sda | more me pongo a ver el contenido del diso a pelo. No es la primera vez que hago malabares con particiones y MBRs, pero antes lo hacía con una herramienta que creo que a esta ahora está discontinuada (El programa se llamaba adecuadamente DiskEdit, de una empresa que lleva el mismo nobre que un vino y que el apellido del dueño, cuyo nombre es el mismo que el padre en Family Guy, y que vienen haciendo Utilities para Windows desde que las hacían para DOS) y que tenía visores especiales para estos sectores y también editar FATs y un montón cosas útiles... en el universo M$.

Primero confirmo que, efectivamente, el primer sector es un MBR (al menos tiene el signature 0x55aa en los últimos dos bytes), y toda la tabla de particiones está vacía, pero que en el segundo sector parece haber una copia. Agarro papel y lápiz, transcribo lo que parece haber, pero al final resulta que no sólo tengo la mitad de los datos, sino que es una partición muy chica.

Entonces me propongo buscar la partición ext3 a mano. Para ello tuve que averiguar cómo es que hace un ext3 para saber que la partición realmente es una ext3 y no cualquier verdura. Sabía que que sería con un magic, pero no tenía ni idea. Instalé las fuentes del 2.6.29 en mi laptop y me puse a mirar el código de ext3. Después de dar bastante vueltas, incluyendo seguir el código que se ejecuta cuando montás un filesystem ext3, donde podemos ver que usa un magic[3] y también la estructura del superblock del ext3, donde vemos que el offset del magic es 0x38.

Entonces el problema de encontrar un ext3 en un disco se reduce a buscar un 0x53ef (fucking little endian) en la posición 0x38 de un sector en el disco. Por suerte more tiene para buscar, así que me siento a buscar toooodas las ocurrencias de 53 ef esperando que la dirección a la derecha termine con 30 y que sean el 9no y el 10mo byte de la línea (maldito 0 based).

Unos cuantos next después, tengo mi primer candidato. Pinta muy bien, porque además lo estaba comparando con el mismo dump pero del pendrive (que tengo formateado en ext2, y por suerte ext2 y ext3 comparten todas estas estructuras), y además pude ver algo que tenía toda la pinta de ser un uuid.

Saco que la dirección del magic es 0x80731038. A eso le resto los 0x38 y me da que el superblock empieza en 0x80731000, un lindo número redondito. Pasado a decimal me dá el byte 2.155.024.384, unos 2GiB desde del comienzo del disco. ¡Pinta muy bien! El swap podría estar primero, y ser de unos 2GiB.

Arranco un fdisk /dev/sda y al mostrar la tabla (aún vacía) de particiones me dice que hay 16.065 sectores por cilindro*512 bytes por sector= 8.225.280 bytes por cilindro. Casi todas las distros (en realidad creo que todas) particionan los discos por cilindros[1], por lo que si el sector éste está justo al principio de un cilindro...

Divido 2.155.024.384/8.225.280=...

(suspenso)[2]

262.000124494...

¡Damn! Casi lo tenía... Hmm, ¿y cuánto es lo que sobra? (262.000124494-262)*8.225.280=... ¡1024! ¿Será que...?

Arranco un strace debugfs -R show_super_stats /dev/sdb1 (la partición en mi pendrive) y veo que ¡efectivamente hace un seek de 1024 bytes dentro de la partición para leer el superblock!

This is it. Con el 262 en la cabeza arranco fdisk /dev/sda y creo dos particiones: un swap en los cilindros 1-261 y una linux del cilindro 262 en adelante. Guardo, salgo, cruzo los dedos y corro un debugfs -R show_super_stats /dev/sda1. ¡Fail! ¿Qué pasa? Reinicio y pruebo de nuevo, no vaya a ser que el kernel no haya leído bien la nueva tabla de particiones. Tampoco. ¿WTF?

Ah, duh, es sda2. Ok, debugfs -R show_super_stats /dev/sda2... ¡Anda, el muy HDP anda! No lo puedo creer. Me la juego: fsck -n /dev/sda2. «Filesystem is clean» Damn, vamos de nuevo: fsck -n -f /dev/sda2...

Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/sda2 sarasa sarasa...

¡Intacto! Pero el MBR no tiene un grub, así que hago el habitual proceso de reinstalar Grub, reinicio...

Bootea perfecto, y termina en un hermoso login. Satisfecho, me doy unas palmaditas en la espalda, cargo mis cosas y comienzo el fin de semana.

sysadmin rescue


[1] ... desperdiciando unos 8MiB entre el MBR y la primera partición

[2] Los perspicaces se darán cuenta al toque que eso no puede ni a ganchos dar entero.

[3] Son muy graciosos los magics de Reiser. Parece haber iniciado una moda que ahora usan los AdOlEsCeNtEs.

Posted Fri 17 Apr 2009 07:11:48 PM CEST Tags: rescue sysadmin

Esto capaz es una boludez, pero buéh...

En uno de mis laburos (ahora tengo 3) tenemos un server que da DHCP y DNS a una red interna, un Debian Etch con dnsmasq. El punto es que dnsmasq concentra muy bien estos dos servicios, haciendo muy simple el poder resolver nombres de máquinas que tomaron su IP dinámicamente por DHCP. Esto se logra haciendo que el cliente mande un nombre de máquina, y según el ip que le asigna agrega una entrada de DNS. Para el entorno donde estoy trabajando esto viene de pelos.

También toma DNS del /etc/hosts. El problema es que si en la entrada del 127.0.0.1, además del típico localhost y/o localhost.localdomain (puaj) hay otro nombre de máquina, y está primero, antes que ninguna otra máquina, esa entrada queda en el DNS. Así, si desde dentro de la red preguntás por el nombre del servidor, el DNS responde que 127.0.0.1. Parrafraseando a un famoso personaje de una serie televisiva: “D-oh!”.

sysadmin dnsmasq

Posted Mon 29 Sep 2008 09:25:40 PM CEST Tags: sysadmin

¿Se acuerdan de la primera parte? Bueno, venía aplicando esto varias veces últimamente (nuevamente tracs y nuevamente plugins). Sé que mi jefe me va a retar, pero la verdad es que lo prefiero así. Generalizé esa idea y lo hice un script, y para marcar su diferencia con el easy_install, lo llamé useful_install:

#! /usr/bin/python

__requires__ = 'setuptools==0.6c3'
import sys

path= sys.argv.pop (1)
sys.path.append (path)

sys.argv= [sys.argv[0], '--install-dir', path, '--site-dirs', path ]+sys.argv[1:]

from pkg_resources import load_entry_point

sys.exit(
    load_entry_point('setuptools==0.6c3', 'console_scripts', 'easy_install')()
)

Como verán es idéntico al easy_install, salvo que el primer parámetro es el directorio donde vamos a instalar las cosas y que hace la magia necesaria de agregarlo al sys.path y armar los argumentos para e_i. Además, le podemos pasar más parámetros a voluntad y pasan derecho al load_entry_point del e_i. Que lo disfruten.

trac python sysadmin

Posted Tue 09 Sep 2008 02:17:05 AM CEST Tags: sysadmin

Desde hace como dos semanas que vengo esporádicamente peleando con un problema: Tenía que poner a andar el plugin de Mercurial para Trac. Según las instrucciones de la página, sólo es cuestión de generar un .egg (¿se acuerdan?), ponerlo en el directorio plugins del environment y ya. Pero corriendo tracd y entrando con un browser me daba:

TracError: Unsupported version control system "hg"

Mi primer sospechoso era el .egg; creía que no lo estaba encontrando. Prendiendo el logging en el trac.ini descubrí que en realidad si lo levantaba. Siguiendo un par de links encontré una sugerencia de correr todos los imports que corre el backend.py del plugin. Finalmente descubrí que la línea:

from mercurial.revlog import LookupError

fallaba. Se vé que el Mercurial que viene en Etch (0.9.1-1+etch1) no es del todo compatible, a pesar que la página del plugin dice que lo es, inclusive hasta con 0.8. Para "repararlo" simplemente saué las (1) referencias a LookupError.

trac mercurial sysadmin

Posted Fri 18 Jul 2008 03:09:46 AM CEST Tags: sysadmin

En la oficina tenemos un server que entrega nfs; también tenemos mucha gente que compila cosas. Estos dos parámetros hacen que tener sincronizadas las horas de las máquinas sea una necesidad. Pra esto se pueden usar los paquetes ntpdate (para on-time-sync) y ntp (para keep-in-sync). Hoy estuve revisando bien como interactúan ambos, sobre todo al momento del booteo. antes una descripción de qué hace cada uno.

ntp se encarga de mantener la hora de la máquina mas-o-menos sincronizada con la de una fuente externa. Si llega a haber cierta diferencia, se encarga de ir acomodando la hora de a poco, para que el sistema no sufra por cambios bruscos. Un problema que tiene es que si la diferencia con la referencia externa es muy grande, ntp no es capaz de salvar las diferencias y entonces ''no hace nada''. ntpdate se encarga simplemente de setear incondicionalmente la hora local según la hora que consiga de esta referencia externa. El escenario ideal sólo haría uso de ntp, pero en general se podría usar también ntpdate para máquinas con el reloj para-el-carajo, como parece ser el caso de al menos una de nuestra máquinas.

El tema es que, por defecto, ntpdate utiliza un archivo de configuración de ntp, pero a su vez corre despúes de éste, en cuya condición falla pues el puerto UDP que usa ya está en uso por ntp. Desinstalando ntp nos deja sin el archivo de configuración, y en realidad tiene sentido quedarnos con él.

La solución que encontré es simplemente hacer un symlink al script de ntpdate en /etc/network/if-up.d a un nombre anterior al de ntp (por ejemplo, mntpdate). Voy a ver si en debian/ubuntu me dan pelota con lo de ponerles mejor orden que simplemente el nombre.

sysadmin ubuntu debian

Posted Thu 10 Jul 2008 10:34:23 PM CEST Tags: sysadmin

Hoy llegué a la oficina con la idea de que algunos tracs aún no andaban. Resultó que la auth contra LDAP no estaba lista. Encontré que esta configuración si andaba:

    AuthLDAPURL ldap://ldap.except.com.ar/ou=People,dc=except,dc=com,dc=ar
    Require valid-user

Mientras que esta otra no:

    AuthLDAPURL ldap://ldap.except.com.ar/ou=People,dc=except,dc=com,dc=ar
    AuthLDAPGroupAttribute memberUid
    AuthLDAPGroupAttributeIsDN off
    Require group cn=except,ou=Group,dc=except,dc=com,dc=ar

Resulta que ahora tenés que avisarle que el grupo lo tiene que buscar en el LDAP:

    Require ldap-group cn=except,ou=Group,dc=except,dc=com,dc=ar

sysadmin apache ldap

Posted Sat 05 Jul 2008 01:29:16 AM CEST Tags: sysadmin

Hoy me tocó hacer una negrada marca cañón. Resulta que tenemos un Xarope andando. En la arquitectura de Xarope tenemos un Apache que nos hace de frontend a todos los sitios Zope que corren en los DomU's.

El tema es que estaba poniendo a andar en uno de los DomU's un repo Mercurial, el cual corre detrás de un lighty. Ponerlo a andar no fue muy duro, salvo que no sabía mucho ni de uno ni del otro. Cuestión que llegué al punto en que podía hacer un hg clone para bajarme una copia del repo, mas no hacer un push. Acá es donde se ponía peluda la cosa.

El problema es el siguiente: para que las passwds no anden volando en cueros tenía que poder acceder al repo por https. Ahora, repiensen el esquema: tengo un Apache al que le llegan los pedidos https, el que a través de un Rewrite forwardea el pedido al Lighttpd corriendo en otra máquina (virtual, pero no viene al caso). Por razones casi obvias forwardear de un 443 a un 443 no anda. ¡Pero resulta que si el forward es al 80 si!

Es decir, el Apache recibe https, y cuando forwardea el pedido, lo hace en http plano. Esto responde a mi pregunta "¿Comocatzo vamos a hacer cuando los usuarios de Zope pidan acceso por https?". La única contra que le veo a este setup es que el sitio final (sea un Zope o un repo Mercurial) no sabe si el acceso viene con SSL o no.

sysadmin lighttpd apache ssl mercurial xarope

Posted Sat 05 Jul 2008 01:29:16 AM CEST Tags: sysadmin

hoy finalmente hicimos el doble salto mortal en nuestras 11 máquinas. he aquí un reporte.

una de las máquinas volvió a tener el hipo de hwdb-client* que no podían instalarse por lo que comenté en el post anterior. el tema es que el truco de hacer dpkg -i hwdb-client* no funcionó poruqe hwdb-client a secas iba a ser removido luego de ser instalados los otros. para salir del paso, hubo que recurrir a la fuerza bruta:

dpkg --force-depends -P hwdb-client

en otra no anduvo porque no se pudo instalar python-central. sólo hubo que darle otra vielta por dselect antes de hacer la manganeta con dpkg. cabe aclarar que si bien todas son *buntus, la mayoría son ubuntus, hay una que otra kubuntu, y en general cada una tiene un montón de paquetes instalados para satisfacer las necesidades de aquellos que alguna vez la usaron.

ya a la cuarta máquina a la que le hacía el upgrade me sabía de memoria qué hacer cuándo y dónde. se volvió tan aburrido que en un momento dado estaba upgradeando 5 máquinas a la vez. el vinito del mediodía le puso un poco de pimienta al asunto.

salvo algunos detalles con una placa de video via k8m890 todo salió a la perfección. creo que esta pirueta no habría salido si no fuera por debian y ubuntu. estoy seguro que en alguna otra distro no debian-based aún estaría renegando.

sysadmin ubuntu

Posted Sat 05 Jul 2008 01:29:16 AM CEST Tags: sysadmin