Member of The Internet Defense League Últimos cambios
Últimos Cambios
Blog personal: El hilo del laberinto Geocaching

Desactivación de "Gratuitous ARP" en Oracle Solaris 10

Última Actualización: 06 de Julio de 2010 - Martes

Hace unos días nuestro proveedor, OVH, nos envió el siguiente correo electrónico:

Subject: Mala configuración concerniente su servidor XXXX.ovh.net
From: soporte@ovh.es
Message-Id: <20100620175453.D0F5627466@mozg.ha.ovh.net>
Date: Sun, 20 Jun 2010 19:54:53 +0200 (CEST)

Estimado(a) Cliente,

Hemos constatado que su servidor XXX.ovh.net envía inutilmente
un número importante de solicitudes en la red vía su IP failover 94.xx.xx.xx,
esto es debido a una mala configuración de esta.

Le hemos solicitado en un mail precedente que reconfigure esta IP 
failover, constatando que el problema persiste, le reiteramos de
nuevo esta solicitud. 

Si el problema no esta resuelto lo más rápido posible, 
nos veremos en la obligación de bloquear su IP.

¡¡¡ESTE ES EL ÚLTIMO AVISO ANTES DEL BLOQUEO DE SU IP!!!

Puede servirle la siguiente guía con el fín de ayudarle en la 
la tarea de reconfiguración :
http://guias.ovh.es/NuevoAliasIp


Encontrará a continuación un extracto de la solicitudes enviadas por su servidor :

-------  EXTRACTO DES SOLICITUDES  -------

19:11:11.898261 arp who-has 94.xx.xx.xx (ff:ff:ff:ff:ff:ff) tell 94.xx.xx.xx
19:16:21.951549 arp who-has 94.xx.xx.xx (ff:ff:ff:ff:ff:ff) tell 94.xx.xx.xx
19:21:50.014500 arp who-has 94.xx.xx.xx (ff:ff:ff:ff:ff:ff) tell 94.xx.xx.xx
19:25:52.269255 arp who-has 94.xx.xx.xx (ff:ff:ff:ff:ff:ff) tell 94.xx.xx.xx
19:30:55.712737 arp who-has 94.xx.xx.xx (ff:ff:ff:ff:ff:ff) tell 94.xx.xx.xx
19:35:37.726666 arp who-has 94.xx.xx.xx (ff:ff:ff:ff:ff:ff) tell 94.xx.xx.xx
19:40:32.870364 arp who-has 94.xx.xx.xx (ff:ff:ff:ff:ff:ff) tell 94.xx.xx.xx
19:45:20.324207 arp who-has 94.xx.xx.xx (ff:ff:ff:ff:ff:ff) tell 94.xx.xx.xx
19:50:25.457682 arp who-has 94.xx.xx.xx (ff:ff:ff:ff:ff:ff) tell 94.xx.xx.xx
19:54:50.262039 arp who-has 94.xx.xx.xx (ff:ff:ff:ff:ff:ff) tell 94.xx.xx.xx

-------   FIN DEL EXTRACTO   -------



OVH, Servicio de Atención al Cliente.

Para contactar con nosotros:
Teléfono : 902 106 113 
(Lunes a Viernes de 8:30 - 20:30)
email: soporte@ovh.es
No olvide visitar nuestro foro:
http://foros.ovh.es/

Obsérvese que este mensaje amenazante se envió el domingo por la tarde. El aviso anterior al que hace referencia se envió el viernes anterior por la noche. En fin. Pero bueno, no será la primera vez que me apagan máquinas por "considerarlas hackeadas" una madrugada de sábado a domingo, sin aviso previo. En este caso, "máquina hackeada" era "excesivas conexiones SSL de salida". Bueno, corramos un tupido velo.

Obsérvese también que "envía inutilmente un número importante de solicitudes" significa un datagrama cada CINCO minutos.

Constatando en ocasiones anteriores que intentar razonar con OVH es una misión imposible, todo razonamiento es inútil. OVH tiene unos precios inmejorables, y un servicio bastante decente, y eso solo puede ser rentable si el personal es mínimo y todo está automatizado. Por tanto, es difícil poder hablar con un ser humano con capacidad de decisión. Solo cabe amoldarse a su "petición".

Tras poner un sniffer en la máquina (previo filtro, porque la cantidad de basura, dirigida a otras máquinas pero visible por nosotros, es muy importante), constato mis sospechas: Ese tráfico se corresponde a datagramas "Gratuitous ARP", enviados por nuestra máquina Solaris.

Las peticiones ARP permiten traducir direcciones IP a direcciones MAC Ethernet. Normalmente las respuestas ARP se producen cuando algún otro nodo de la LAN realiza una petición ARP. Los datagramas "Gratuitous ARP" son paquetes de respuesta que no se envían como resultado de una petición ARP, sino de forma "espontanea", gratuita.

La causa habitual para generar "Gratuitous ARP" es la migración de una IP a otra máquina, por ejemplo en sistemas cluster (se cae un nodo, se levanta otro y se "lleva" la IP con él) durante un "failover", para que los nodos de la red encamine los datagramas a la tarjeta de red correcta.

En este caso, en cambio, el envío de "Gratuitous ARP" se realiza para detectar direcciones IP duplicadas: Si un nodo recibe una respuesta ARP (este tipo de respuestas ARPs son "broadcast") con su dirección IP pero una dirección MAC diferente, sabemos que existe otra máquina en la red con una IP duplicada. Esta técnica se llama DAD: "Detection of Address Duplication" (Detección de Direcciones Duplicadas).

Una búsqueda rápida en Google explica el proceso, y da las pistas para solucionarlo. Básicamente hay que hacer:

[root@XXX /]# ndd -set /dev/arp arp_probe_count 0
[root@XXX /]# ndd -set /dev/arp arp_defend_interval 0

Una vez que se ejecutan esos comandos, pongo un sniffer, lo dejo un buen rato, y constato que ya no estamos enviando esos datagramas. Hay que esperar unos minutos para confirmarlo, porque los datagramas solo se mandan cada cinco minutos, y una vez que se activa el "timer", el siguiente datagrama va a salir de todas formas, aunque hayamos desactivado la funcionalidad mientras tanto. Digamos que ya está "planificado". Eso sí, ya no saldrán más, tras la expiración del "timer" y el envío de la siguiente respuesta ARP.

Una vez que comprobamos que todo funciona como debe, hay que instalar estos cambios de forma que se activen automáticamente al arrancar el ordenador. Como hablamos de Solaris 10, la forma nativa de hacerlo es emplear SMF.

Primero creamos el siguiente fichero como "/datos/svc/no_gratuitous_arp.start", y le damos permiso de ejecución: (ATENCIÓN: Este script ocasiona problemas con zonas Solaris. Ver más abajo)

#!/bin/sh

. /lib/svc/share/smf_include.sh
. /lib/svc/share/net_include.sh

# Make sure that the libraries essential to this stage of booting  can be found.
LD_LIBRARY_PATH=/lib; export LD_LIBRARY_PATH

/usr/sbin/ndd -set /dev/arp arp_probe_count 0
/usr/sbin/ndd -set /dev/arp arp_defend_interval 0

# Reset the library path now that we are past the critical stage
unset LD_LIBRARY_PATH

Mi manifiesto SMF, en "/datos/svc/no_gratuitous_arp.xml", es:

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type='manifest' name='jcea:no_gratuitous_arp'>
<service
    name='jcea/no_gratuitous_arp'
    type='service'
    version='1'>
                        <create_default_instance enabled='true' />
                        <single_instance />
                <dependency
        name='fs-local'
        type='service'
        grouping='require_all'
        restart_on='none'>
                        <service_fmri value='svc:/system/filesystem/local' />
                </dependency>
                <dependency
        name='loopback-network'
        grouping='require_any'
        restart_on='none'
        type='service'>
                        <service_fmri value='svc:/network/loopback' />
                </dependency>
                <dependency
        name='physical-network'
        grouping='optional_all'
        restart_on='none'
        type='service'>
                        <service_fmri value='svc:/network/physical' />
                </dependency>
                <exec_method
        type='method'
        name='start'
        exec='/datos/svc/no_gratuitous_arp.start'
        timeout_seconds='30'>
                </exec_method>

                <exec_method
               type='method'
               name='stop'
               exec=':true'
               timeout_seconds='30' >
                </exec_method>

                <property_group name='startd' type='framework'>
                        <propval name='duration' type='astring'  value='transient' />
                </property_group>

                <stability value='Unstable' />
                <template>
                        <common_name>
                                <loctext xml:lang='C'>
                                        No Gratuitous ARP - http://www.jcea.es/artic/solaris-arp.htm
                                </loctext>
                        </common_name>
                        <documentation>
                                <manpage title='ndd' section='1M'
                manpath='/usr/share/man' />
                        </documentation>
                </template>
</service>
</service_bundle>

Comparado con el ejemplo que tomamos de plantilla, yo añado una dependencia del "filesystem/local", porque mi script está en un "dataset" ZFS que no se monta inmediatamente tras el arranque. También ponemos timeouts de 30 segundos, en vez de 3 segundos.

Ahora ejecutamos los siguientes comandos:

[root@XXX svc]# svccfg validate no_gratuitous_arp.xml
[root@XXX svc]# svccfg import no_gratuitous_arp.xml
[root@XXX svc]# svcadm enable no_gratuitous_arp
[root@XXX svc]# svcs -l no_gratuitous_arp
fmri         svc:/jcea/no_gratuitous_arp:default
name         No Gratuitous ARP - http://www.jcea.es/artic/solaris-arp.htm
enabled      true
state        online
next_state   none
state_time   Mon Jun 28 17:09:01 2010
logfile      /var/svc/log/jcea-no_gratuitous_arp:default.log
restarter    svc:/system/svc/restarter:default
dependency   require_all/none svc:/system/filesystem/minimal (online)
dependency   require_any/none svc:/network/loopback (online)
dependency   optional_all/none svc:/network/physical (online)

Ahora reiniciamos el equipo, para asegurarnos de que todo va bien, y comprobamos, con un "sniffer", que no mandamos "Gratuitous ARP". Recordemos que hay que dejarlo un buen rato, al menos 15 minutos, para estar seguros.

Problemas con Zonas Solaris y cómo solucionarlo

El trabajo expuesto funciona, ya no mandamos más "Gratuitous ARP". Pero las Zonas Solaris no tendrán red si lanzamos ese cambio de configuración al arrancar el equipo.

Los síntomas son los siguientes: La máquina recibe los datagramas destinados a las zonas, pero ese tráfico no parece llegar a la zona correspondiente. Usando un "sniffer" comprobamos que el tráfico llega a la máquina, pero se ignora. Como si estuviese siendo filtrado por el cortafuegos.

Experimentando un poco se puede ver que el problema se produce cuando hacemos el cambio de configuración ARP y, LUEGO, levantamos las Zona Solaris. Por tanto, mi primer cambio fue añadir una dependencia SMF a nuestro script, para que se lance tras lanzar las Zonas. Pero eso no funciona porque una vez que arranca una zona, nuestro script se ejecuta, pero la Zona aún no ha levantado su interfaz de red cuando hacemos el cambio. Podría haber añadido un "sleep" en el script, para esperar un minuto o dos a que las Zonas estén "online" y funcionales. Eso funcionaría, pero si paramos la Zona y la levantamos de nuevo, con posterioridad, volvemos a tener el mismo problema.

He preguntado en varias listas de correo sobre el particular, sin recibir ninguna ayuda útil. También planteé la posibilidad de usar el cortafuegos del equipo para filtrar el tráfico saliente ARP, cuando se trata de una respuesta ARP dirigida al "broadcast" (osea, es un "Gratuitous ARP"). Pero, aparentemente, el cortafuegos de Solaris (ipfilter) no dispone de esa capacidad.

La máquina corre Solaris 10, pero tengo el código fuente de OpenSolaris y me puse a curiosear. Lo primero que pensé fue que en vez de desactivar el "timeout" que manda los "Gratuitous ARP", podría ponerle un valor muy alto. Pasar de los cinco minutos por defecto a siete días, por ejemplo. Incluso 24 horas sería algo aceptable. Pero la configuración para ese contador tiene un límite máximo de una hora, y no estoy seguro de que nuestros amigos de OVH estuviesen contentos con esa reducción. Teniendo el código fuente me planteé recompilarlo, pero no estoy seguro de que ese módulo, proveniente de OpenSolaris, pueda funcionar correctamente en Solaris 10, amén de los posibles problemas futuros al parchear o actualizar el sistema. Otra posibilidad sería buscar en la imagen del kernel, localizar ese límite y modificarlo "a saco" para subirlo. Pero es una tarea delicada y sigo teniendo problemas a la hora de parchear y actualizar el sistema.

Lo bueno de tener el código fuente es que puedes ver cómo funciona, estudiarlo. Existen multitud de contadores y "timeouts" relativos al ARP, y no están documentados claramente por ninguna parte, y mucho menos sus interacciones. Pero analizando el código y haciendo pruebas, llego al siguiente script:

#!/bin/sh

. /lib/svc/share/smf_include.sh
. /lib/svc/share/net_include.sh

# Make sure that the libraries essential to this stage of booting  can be found.
LD_LIBRARY_PATH=/lib; export LD_LIBRARY_PATH

/usr/sbin/ndd -set /dev/arp arp_probe_count 1
/usr/sbin/ndd -set /dev/arp arp_publish_count 1
/usr/sbin/ndd -set /dev/arp arp_fastprobe_count 1
/usr/sbin/ndd -set /dev/arp arp_defend_interval 0

# Reset the library path now that we are past the critical stage
unset LD_LIBRARY_PATH

Este script desactiva el "Gratuitous ARP" periódico, pero permite un "Gratuitous ARP" espontaneo cuando se "levanta" una interfaz de red. Ese datagrama es suficiente para registrar la interfaz de la Zona Solaris correctamente, de forma que el sistema operativo le proporcione red de forma apropiada. En la LAN veremos unos datagramas ARP extra, odiados por OVH, pero solo un puñado (3-5) cuando se levanta una interfaz de red, no de forma periódica, 24 horas al día.

Con este cambio, la red de las Zonas Solaris funciona correctamente, y hemos reducido el tráfico "Gratuitous ARP" a eventos puntuales, básicamente cuando se reinicia el servidor (o alguna Zona). Espero que esto sea suficiente para contentar a OVH.


Historia

  • 06/jul/10: Documento los problemas con Zonas Solaris y cómo arreglarlo.

  • 28/jun/10: Primera versión de esta página.



Python Zope ©2010 jcea@jcea.es

Más información sobre los OpenBadges

Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS