Mostrando entradas con la etiqueta udp. Mostrar todas las entradas
Mostrando entradas con la etiqueta udp. Mostrar todas las entradas

sábado, 26 de diciembre de 2015

Servidores DNS Raíz bajo ataque - Root DNS servers under attack

Leyendo algunos mails pendientes me encontré con una de los boletines de SANS que reportaba un ataque de DDOS a los servidores de nombre raíz. Efectivamente, entre el 30 de Noviembre y el 1 de Diciembre último, los servidores raíz fueron víctimas de un número inusual de consultas DNS.

Estos servidores mantienen la zona raíz, donde comienzan todas las consultas DNS recursivas y por lo tanto el correcto funcionamiento de estos servidores es crucial para la salud de Internet.

Podemos obtener la lista de servidores DNS raíz con una simple consulta desde la consola:

juan@juan-VirtualBox:~$ dig +short -t NS .
i.root-servers.net.
j.root-servers.net.
k.root-servers.net.
d.root-servers.net.
e.root-servers.net.
l.root-servers.net.
a.root-servers.net.
h.root-servers.net.
m.root-servers.net.
f.root-servers.net.
c.root-servers.net.
b.root-servers.net.
g.root-servers.net.
juan@juan-VirtualBox:~$


a partir de los nombres queda claro que cada uno de los servidores raíz se identifica por una letra en el abecedario. De momento hay servidores de la A a la M (13 servidores). Vale aclarar que en realidad detrás de cada uno de estos nombres hay en realidad muchas instancias del servidor respondiendo. Según Wikipedia a Octubre de 2014 había unos 504 servidores reales respondiendo consultas.

Horarios del ataque

 
  • El primer ataque comenzó a las 06:50 UTC del 30 de Noviembre y se extendió  hasta aproximadamente las 09:30 UTC.
  • El segundo ataque inició a las 05:10 UTC del 1 de Diciembre y se extendió hasta casi las 06:10 UTC.
Algunos sitios indican, erróneamente, que se trató de un ataque de amplificación y reflexión, sin embargo no parece haberlo sido. Según detalla la propia gente de www.root-servers.org en su informe, el ataque tuvo las siguientes características:
  • Durante el primer ataque, las consultas eran sobre un único dominio.
  • Durante el segundo ataque, las consultas involucraban diferentes dominios.
  • Buena parte de la flota de servidores recibieron este número excesivo de consultas, aunque no todos. Posiblemente por la naturaleza anycast de las direcciones IP de los servidores raíz. 
  • Extrañamente las direcciones origen de las consultas DNS parecían estar distribuidas aleatoriamente dentro del espacio de direcciones IPv4.
  • El pico máximo de consultas fue de alrededor de 5 millones de consultas por servidor raíz. 

Impacto


Afortunadamente el impacto del ataque fue casi nulo. Si confirmaron que algunos de los enlaces que conectan a los servidores raíz se vieron saturados, lo cual generó algunos retardos en las resoluciones destinadas a estos servidores. Una vez mas la robustez del mecanismo de anycast y la simplicidad de UDP mostraron ser un muy buena arquitectura para uno de los servicios mas críticos de Internet.

lunes, 8 de junio de 2015

UDP en GNU/Linux Parte II

Esta entrada es la continuación de UDP en GNU/Linux Parte I y la idea es continuar con las pruebas para entender un poco mas cómo funciona el stack UDP en GNU/Linux.

En la publicación anterior quedó pendiente probar packet receive errors  en una condición de buffer insuficiente. Dijimos que esta condición se puede dar en un escenario donde los paquetes arriban al host a una tasa mayor que con la que son retirados del buffer del socket. Para comprobar esto vamos a precisar algunos números y un receptor UDP lento.

Receptor UDP lento

La verdad es que no se me ocurrió ninguna idea maravillosa para hacer un receptor lento de paquetes UDP, así que hurgando un poco en internet armé un pequeño cliente.c (si ¬¬ .c, ¿qué tiene de malo?). El cliente básicamente realiza las siguientes tareas:
  • Abre un socket UDP y escucha en el puerto 5555.
  • Imprime en pantalla el tamaño del buffer del socket.
  • Luego en un loop toma del buffer del socket 1 paquete por segundo e imprime en pantalla un contador de paquetes leidos.
Acá pueden ver una ejecución abortada de ejemplo:
juan@ubuntu:~$ ./cliente
--Socket creado!
-Configuracion del socket tamanio del buffer de recepcion: 163840
^C
juan@ubuntu:~$ 


Como ven el tamaño del buffer por defecto es de 163840 bytes (160Kbytes). Este valor no es aleatorio ni nada que se le parezca, el tamaño está definido por la variable de kernel net.core.rmem_default

root@ubuntu:/home/juan# sysctl -a|grep rmem_default
net.core.rmem_default = 163840
root@ubuntu:/home/juan#


por ejemplo, se podría ampliar de la siguiente manera

root@ubuntu:/home/juan# sysctl -w net.core.rmem_default=1638400
net.core.rmem_default = 1638400
root@ubuntu:/home/juan# sysctl -a|grep rmem_default
net.core.rmem_default = 1638400
root@ubuntu:/home/juan# 


y se vería reflejado en la próxima ejecución de nuestro cliente

root@ubuntu:/home/juan# ./cliente
--Socket creado!
-Configuracion del socket tamanio del buffer de recepcion: 1638400
^C
root@ubuntu:/home/juan#  


Entonces, resumiendo los números:
  • Tamaño del buffer de recepción 163840 bytes.
  • Enviaremos paquetes de 1024 bytes forjados con Hping3. Por lo tanto, 160 paquetes son suficientes para llenar el buffer.
  • Se enviarán 2000 paquetes a una tasa de 10 paquetes por segundo.
  • La aplicación consume 1 paquete cada 1 segundo.
Está claro que si esta situación se prolonga lo suficiente en el tiempo, en algún momento el buffer se llenará y el sistema deberá descartar paquetes. Si bien es una condición un poco exagerada a fines prácticos resulta útil.

Antes de lanzar nuestro cliente lento tomamos los valores de las estadísticas del sistema:

root@ubuntu:/home/juan# netstat -su
Udp:
    20 packets received
    0 packets to unknown port received.
    0 packet receive errors
    22 packets sent
...
root@ubuntu:/home/juan#


lanzamos el cliente

root@ubuntu:/home/juan# ./cliente
--Socket creado!
-Configuracion del socket tamanio del buffer de recepcion: 163840


y apuntamos el cañón hping3 al host:

root@moon:/home/juan/pruebas# hping3 192.168.0.10 -2 -c 2000 --fast -E 1024 -d 1024 -p 5555 -V
using wlan0, addr: 192.168.0.2, MTU: 1500
HPING 192.168.0.10 (wlan0 192.168.0.10): udp mode set, 28 headers + 1024 data bytes
[main] memlockall(): Success
Warning: can't disable memory paging!

--- 192.168.0.10 hping statistic ---
2000 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms
root@moon:/home/juan/pruebas#


esta vez hay nuevos parámetros en hping3:
  • --fast: le indica que debe mandar 10 paquetes por segundo.
  • --E 1024: indica que debe meter como payload de los paquetes el contenido del archivo llamado 1024 (un archivo con 1024 bytes en 0).
  • -d 1024: este parámetro es el que realmente indica cuántos bytes del archivo indicado por -E se van a mandar como payload. En esta caso se arman datagramas de 1024 bytes.
  • -c 2000: indica que se enviarán 2000 paquetes.
en definitiva se enviaron 2000 paquetes con 1024 bytes como payload cada uno de ellos (en total se enviaron unos 2048000 bytes, claramente superamos el tamaño del buffer).

Vemos la salida de la aplicación (dado que la función de lectura es bloqueante, la aplicación no termina por sus propios medios después de leer el último paquete, luego de unos segundos sin nuevos paquetes la aborté con Ctrl+C)

root@ubuntu:/home/juan# ./cliente
--Socket creado!
-Configuracion del socket tamanio del buffer de recepcion: 163840
Paquete numero 0
Paquete numero 1
Paquete numero 2
Paquete numero 3
Paquete numero 4
Paquete numero 5
Paquete numero 6
Paquete numero 7
...

Paquete numero 279
Paquete numero 280
Paquete numero 281
Paquete numero 282

^C
root@ubuntu:/home/juan#


Entonces se enviaron 2000 paquetes pero nuestra aplicación lenta solo pudo leer 283 de ellos!!! A donde fueron los restantes mmmm 1717 paquetes?

root@ubuntu:/home/juan# netstat -su
Udp:
    303 packets received
    0 packets to unknown port received.
    1717 packet receive errors
    22 packets sent
...
root@ubuntu:/home/juan#


Claramente fueron al cielo de los paquetes. Fueron completamente descartados por el kernel debido a que no había espacio donde almacenarlos.

Dado que leemos 1 paquete por segundo y agregamos 10 por segundo, podríamos decir que llegan un neto de 9 paquetes por segundo al buffer. A 9 paquetes por segundo el buffer se llena en unos 17 segundos aproximadamente. Es decir que, si la matemática no me falla, a partir de los 17 segundos estaríamos perdiendo al menos 9 paquetes por segundo.

Hay dos maneras de enfrentar esta situación, dado que UDP no tiene control de flujo e implementarlo en la capa de aplicación sería un delirio, podemos:
  • Incrementar la eficiencia del consumidor, leyendo mas paquetes por segundo.
  • Aumentando el tamaño del buffer de recepción para poder soportar el asedio de paquetes sin perderlos.
Entonces supongamos que mejoramos el código y multiplicamos por 7 la eficiencia de la aplicación y ahora es capaz de leer 7 paquetes por segundo. Matemáticamente estamos en la misma (en el horno), estarían ingresando un neto de 3 paquetes por segundo, ahora el buffer se llenaría en 53 segundos y volvemos a tener pérdida de paquetes. El paso siguiente es aumentar el tamaño del buffer. Sabemos que vamos a recibir una ráfaga de 2000 paquetes de 1024 bytes, osea 2Mbytes es decir que podríamos configurar un buffer de 2MBytes y quedarnos re tranquilos, pero sería algo extremo.

Con el nuevo código llenamos el buffer en 53 segundos, osea que aún nos quedan 147 segundos con pérdida de paquetes. Pero ahora vamos a ampliar el buffer multiplicándolo por 4 (NOTA: vale aclarar que este nuevo cambio se aplicará a todos los nuevos sockets creados).

root@ubuntu:/home/juan# echo "163840*4"|bc
655360
root@ubuntu:/home/juan# sysctl -w net.core.rmem_default=655360
net.core.rmem_default = 655360

root@ubuntu:/home/juan# sysctl -w net.core.rmem_max=655360
net.core.rmem_max = 655360

root@ubuntu:/home/juan# sysctl -a | grep net.core.rmem_default
net.core.rmem_default = 655360
root@ubuntu:/home/juan# 


En teoría, con este nuevo buffer de solo 4 veces mayor tamaño no deberíamos ver pérdida de paquetes.

root@ubuntu:/home/juan# netstat -su 
Udp:
    2072 packets received
    0 packets to unknown port received.
    0 packet receive errors
    21 packets sent
root@ubuntu:/home/juan#


Ejecución cliente

root@ubuntu:/home/juan# ./cliente
--Socket creado!
-Configuracion del socket tamanio del buffer de recepcion: 655360
Paquete numero 7
Paquete numero 14
Paquete numero 21
Paquete numero 28
Paquete numero 35
Paquete numero 42
Paquete numero 49
Paquete numero 56

...
Paquete numero 1960
Paquete numero 1967
Paquete numero 1974
Paquete numero 1981
Paquete numero 1988
Paquete numero 1995
2000 paquetes leidos!!!

root@ubuntu:/home/juan#

Y corroboramos con las estadísticas:

root@ubuntu:/home/juan# netstat -su
Udp:
    4072 packets received
    0 packets to unknown port received.
    0 packet receive errors
    21 packets sent

root@ubuntu:/home/juan#

El aumento del tamaño del buffer y la mejora en la aplicación permitieron que esta vez no haya pérdida de paquetes.

domingo, 17 de mayo de 2015

UDP en GNU/Linux Parte I

Hace unos días me encontré con un caso interesante de pérdida de paquetes en transferencias utilizando UDP. Como se imaginaran poco me asombro que se perdieran paquetes UDP, ya que por definición se trata de un protocolo de transporte que no es fiable a la hora de entregar la información, una especie de cartero ebrio digamos. El control de flujo, el orden y la re transmisión no forman parte de las especificaciones de UDP [1], ya que fue ideado para ser simple. Meter los paquetes al cable y que la fuerza los acompañe.

Usar UDP como protocolo de transporte suele dar lugar a las siguientes situaciones:
  • Paquetes que nunca alcanzan el destino. Sin control de conexión y re transmisión, básicamente el emisor pone el paquete en el cable y se olvida por completo del mismo, no hay notificación de recepción ni nada que se le parezca.
  • Paquetes que llegan desordenados. Por esas cosas de las redes, los paquetes A y B que fueron enviados en ese orden podrían ser recibidos por el receptor en el orden inverso.
por lo tanto muchas aplicaciones que utilizan UDP deciden lidiar con estos problemas en la capa de aplicación.

En GNU/Linux, haciendo uso del programa netstat podemos ver las estadísticas UDP del sistema, por ejemplo:

root@ubuntu:/home/juan# netstat -su
Udp:
    23 packets received
    0 packets to unknown port received.
    0 packet receive errors
    23 packets sent
...
root@ubuntu:/home/juan#


En esta caso particular vemos que se enviaron 23 paquetes y se recibieron 23, muy probablemente se trate de consultas y respuestas DNS, ya que acabo de iniciar la máquina virtual. En total son 4 los campos disponibles de estadísticas UDP:
  • Packets received: número paquetes recibidos de manera satisfactoria por el sistema. Esto significa paquetes recibidos y pasados a la aplicación correspondiente.
  • Packets to unknown port received: número de paquetes que fueron recibidos pero no eran esperados por el sistema, es decir no había ninguna aplicación escuchando en ese puerto.
  • Packet receive errors: número de paquetes que no pasaron el checksum o que llegaron cuando el buffer de recepción se encontraba lleno y por lo tanto fueron descartados.
  • Packets sent: número de paquetes enviados por el sistema.

Probando Packets received:

Para probar este campo primero debemos identificar algún servicio escuchando en un puerto UDP, y para eso usamos netstat:

root@ubuntu:/home/juan# netstat -plun
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
udp        0      0 0.0.0.0:68              0.0.0.0:*                           558/dhclient   
udp        0      0 0.0.0.0:5113            0.0.0.0:*                           558/dhclient   
udp6       0      0 :::43512                :::*                                558/dhclient   
root@ubuntu:/home/juan#


Podemos ver que el puerto 68, 5113 y 43512 están en uso así que apuntaremos al puerto 68 y enviaremos 5 paquetes. Para generar tráfico UDP sin demasiadas complicaciones vamos a utilizar Hping3 [2] (aquí hay un post en donde lo utilicé para probar DNS Amplification attacks), para entender los parámetros man hping3.

root@moon:/home/juan# hping3 192.168.0.10 -2 -c 5 -p 68 -V
using wlan0, addr: 192.168.0.2, MTU: 1500
HPING 192.168.0.10 (wlan0 192.168.0.10): udp mode set, 28 headers + 0 data bytes

--- 192.168.0.10 hping statistic ---
5 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms
root@moon:/home/juan# 


Ahora veamos cómo se manifiesta esto en las estadísticas UDP:

root@ubuntu:/home/juan# netstat -su
Udp:
    28 packets received
    0 packets to unknown port received.
    0 packet receive errors
    23 packets sent

...
root@ubuntu:/home/juan#


Vemos que los paquetes recibidos se incrementaron en 5, como era de esperarse, ya que los paquetes tenían como destino un puerto donde había una aplicación escuchando (mas allá de que la aplicación haya sido capaz de interpretar el contenido de los paquetes o no).

Probando Packets to unknown port received:

Los campos Packets received y Packets sent son bastante simples de comprobar así que vamos a apuntar a este otro que es un poco mas interesante.El tráfico será:
  • Destinado al puerto 5555.
  • Enviaremos 10 paquetes.
 Shoot!

root@moon:/home/juan# hping3 8.8.8.8 -2 -c 10 -p 5555 -V
using wlan0, addr: 192.168.0.2, MTU: 1500
HPING 8.8.8.8 (wlan0 8.8.8.8): udp mode set, 28 headers + 0 data bytes

--- 8.8.8.8 hping statistic ---
10 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms
root@moon:/home/juan# hping3 192.168.0.10 -2 -c 10 -p 5555 -V
using wlan0, addr: 192.168.0.2, MTU: 1500
HPING 192.168.0.10 (wlan0 192.168.0.10): udp mode set, 28 headers + 0 data bytes
ICMP Port Unreachable from ip=192.168.0.10 name=UNKNOWN  
status=0 port=1179 seq=0
ICMP Port Unreachable from ip=192.168.0.10 name=UNKNOWN  
status=0 port=1180 seq=1
ICMP Port Unreachable from ip=192.168.0.10 name=UNKNOWN  
status=0 port=1181 seq=2
ICMP Port Unreachable from ip=192.168.0.10 name=UNKNOWN  
status=0 port=1182 seq=3
ICMP Port Unreachable from ip=192.168.0.10 name=UNKNOWN  
status=0 port=1183 seq=4
ICMP Port Unreachable from ip=192.168.0.10 name=UNKNOWN  
status=0 port=1184 seq=5
ICMP Port Unreachable from ip=192.168.0.10 name=UNKNOWN  
status=0 port=1185 seq=6
ICMP Port Unreachable from ip=192.168.0.10 name=UNKNOWN  
status=0 port=1186 seq=7
ICMP Port Unreachable from ip=192.168.0.10 name=UNKNOWN  
status=0 port=1187 seq=8
ICMP Port Unreachable from ip=192.168.0.10 name=UNKNOWN  
status=0 port=1188 seq=9

--- 192.168.0.10 hping statistic ---
10 packets transmitted, 10 packets received, 0% packet loss
round-trip min/avg/max = 3.4/19.6/161.2 ms
root@moon:/home/juan#


Vemos que el destino nos respondió con un mensaje ICMP Port Unreachable por cada paquete que enviamos, lo cuál nos da dos pautas:
  • Los paquetes llegaron al sistema y el kernel reconoció que no tenía a quién entregarlos.
  • El host no tiene un firewall que descarte los paquetes a puertos que no sean necesarios.
Pero bien, ahora veamos qué pasó en los contadores del host destino!!

root@ubuntu:/home/juan# netstat -su
IcmpMsg:
    OutType3: 10
Udp:
    28 packets received
    10 packets to unknown port received.
    0 packet receive errors
    23 packets sent
...

root@ubuntu:/home/juan#

Exacto! Ahora tenemos 10 paquetes reconocidos como "packets to unknown port received" y también vemos los 10 mensajes ICMP enviados como respuesta.

Probando packet receive errors:

Ahora pongamos a prueba el reconocimiento de paquetes con problemas. Por suerte Hping3 nos permite, con el flag -b, enviar paquetes con el checksum corrupto así que usaremos eso para probar. En este punto haremos dos pruebas:

  • Prueba1
    • 5 paquetes con checksum inválido
    • puerto 68
  • Prueba 2
    • 5 paquetes con checksum inválido
    • puerto 5555
Prueba 1:

/root@moon:/home/juan# hping3 192.168.0.10 -2 -c 5 -p 68 -b -V
using wlan0, addr: 192.168.0.2, MTU: 1500
HPING 192.168.0.10 (wlan0 192.168.0.10): udp mode set, 28 headers + 0 data bytes

--- 192.168.0.10 hping statistic ---
5 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms
root@moon:/home/juan#



root@ubuntu:/home/juan# netstat -su
IcmpMsg:
    OutType3: 10
Udp:
    28 packets received
    10 packets to unknown port received.
    5 packet receive errors
    23 packets sent
    InCsumErrors: 5
...
root@ubuntu:/home/juan#

Ahora podemos ver que el valor de "packet receive errors" pasó de 0 a 5, también tenemos un nuevo campo llamado InCsumErrors con valor 5.

Prueba 2:

root@moon:/home/juan# hping3 192.168.0.10 -2 -c 5 -p 5555 -b -V
using wlan0, addr: 192.168.0.2, MTU: 1500
HPING 192.168.0.10 (wlan0 192.168.0.10): udp mode set, 28 headers + 0 data bytes

--- 192.168.0.10 hping statistic ---
5 packets transmitted, 0 packets received, 100% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms
root@moon:/home/juan#



root@ubuntu:/home/juan# netstat -su
IcmpMsg:
    OutType3: 10
Udp:
    28 packets received
    10 packets to unknown port received.
    10 packet receive errors
    23 packets sent
    InCsumErrors: 10
...
root@ubuntu:/home/juan#


El número de packet receive errors (y InCsumErrors) volvió a incrementarse en 5. Vale notar que esta vez no recibimos los mensajes ICMP, básicamente porque los paquetes fueron descartados rápidamente por no tener el checksum inválido.

Un detalle llamativo de estas dos últimas pruebas es el siguiente. Viendo los logs escritos en /var/log/syslog, encontré:

May 17 15:08:25 ubuntu dhclient: 5 bad udp checksums in 5 packets
May 17 15:08:34 ubuntu kernel: [ 9005.777840] UDP: bad checksum. From 192.168.0.2:2868 to 192.168.0.10:5555 ulen 8
May 17 15:08:35 ubuntu kernel: [ 9006.776665] UDP: bad checksum. From 192.168.0.2:2869 to 192.168.0.10:5555 ulen 8
May 17 15:08:36 ubuntu kernel: [ 9007.781846] UDP: bad checksum. From 192.168.0.2:2870 to 192.168.0.10:5555 ulen 8
May 17 15:08:37 ubuntu kernel: [ 9008.776246] UDP: bad checksum. From 192.168.0.2:2871 to 192.168.0.10:5555 ulen 8
May 17 15:08:38 ubuntu kernel: [ 9009.779863] UDP: bad checksum. From 192.168.0.2:2872 to 192.168.0.10:5555 ulen 8


La primera línea indica que dhclient (el servicio escuchando en 68/UDP) recibió, o al menos se enteró de, los 5 paquetes con checksum erróneo, lo cual me deja un poco desconcertado. Aparentemente el kernel pasa estos paquetes de todas maneras a la aplicación, probablemente para que la aplicación decida qué medidas tomar. Las siguientes 5 líneas son del kernel indicando que se recibieron 5 paquetes UDP con bad checksum (dirigidos al 5555/UDP).

Otra forma un poco mas complicada de analizar packet receive erors es desde /proc/net/udp. La ventaja de este método es que la información está mas detallada, por ejemplo por puerto. netstat resume esta información.

root@ubuntu:/home/juan# cat /proc/net/udp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode ref pointer drops            
   67: 00000000:0044 00000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 8110 2 caaa82c0 5                
  248: 00000000:13F9 00000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 8044 2 caaa8000 0                 
root@ubuntu:/home/juan#


En este caso marcado en "negrita" vemos 0044 valor hexadecimal del puerto 68, y por último el número de paquetes descartados para ese puerto 5 (los paquetes enviados con bad checksum). Otros valores importantes que vemos son tx_queue y rx_queue que básicamente indican que las colas están vacías dado que no hay paquetes llegando o saliendo del host.

Cuando describí el campo packet receive errors al comienzo del post, dije que este contador no solo se incrementa por paquetes defectuosos sino también por paquetes que al llegar encuentran el buffer de recepción lleno y son descartados. Esta última condición se genera cuando la tasa de llegada de paquetes es mayor a la tasa de procesamiento de los mismos. Un clásico problema productor-consumidor, si se produce a mayor tasa de la que se consume, el productor debe ser capaz de reconocer la situación y frenar la producción (control de flujo que UDP no posee) o el consumidor debe ser capaz de aumentar su velocidad de consumo o ampliar su capacidad de almacenar productos (incrementar el tamaño de los buffers).

Probar esta última situación resulta un poco mas complicado así que queda pendiente para la próxima publicación :P

Links:

[1] UDP - https://www.ietf.org/rfc/rfc768.txt
[2] Hping3 - http://wiki.hping.org/

sábado, 3 de abril de 2010

Pequeeeeña intro MDNS (Multicast DNS):

Hoy (01/04/2010), mientras preparaba la próxima entrada del blog "casualmente" tenía wireshark corriendo y me encontré con un paquete que me llamó poderosamente la atención. El protocolo es MDNS, lo había visto antes pero siempre creí que se trataba de alguna de las aplicaciones que estaba corriendo.

Intro:

Googleando un poco encontré de que se trata: "Multicast DNS is a way of using familiar DNS programming interfaces, packet formats and operating semantics, in a small network where no conventional DNS server has been installed." (http://www.multicastdns.org/). Es decir, se trata de una implementación del protocolo de resolución de nombres (DNS) para redes de área local, donde no existe un servidor DNS real. Producto de los grupos Zero Configuration Networking y DNS Extensions, creado con el objetivo de facilitar la configuración de redes locales que no cuentan con un servidor de nombres propio.

Según el draft (http://files.multicastdns.org/draft-cheshire-dnsext-multicastdns.txt) "Clients performing DNS-like queries for DNS-like resource records by sending DNS-like UDP query and response packets over IP Multicast to UDP port 5353." se trata de clientes realizando consultas tipo DNS por registros tipo DNS enviando paquetes (tipo DNS) al puerto 5353 UDP  sobre direcciones IP Multicast (JA!, para los que creen que las clase D no se usan jajaaj).

Las direcciones Multicast o clase D van de 224.0.0.0 a 239.255.255.255, y se caracterizan por: una dirección Multicast está asociada con un grupo de receptores interesados, cuando uno de los interesados envía un paquete a una dirección Multicast todos los demás lo reciben, los routers que se encuentren entre estos interesados deben ser capaces de reenviar estos paquetes a cada uno de ellos.

Al tratarse de una dirección Multicast, todos los asociados reciben todos los paquetes, y de esta manera las caches de nombres se mantienen actualizadas. Cada respuesta a una consulta Multicast DNS trae un campo donde se especifica el tiempo de validez que tiene la respuesta, luego de que expire ese tiempo es necesario volver a efectuar la consulta.

Este servicio de DNS cuenta también con un TLD (Top-Level Domain) propio y es ".local.". Todo FQDN (Fully Qualified Domain Name, nombre completo xD) que finalice con ".local." se lo considera de enlace local, es decir... es un análogo a las direcciones IP privadas, que sólo valen en el ámbito local de la red y de nada sirven fuera de ella. Toda consulta DNS que finalice con ".local." debe ser enviada a la dirección 224.0.0.251 (si se trata de IPv4, o FF02::FB si se trata de IPv6).

Existen 3 tipo de consultas: las consultas convencionales 1-consulta->1-respuesta, 1-consulta->N-respuestas y el ultimo tipo que consiste en consultas continuas.

En fin... eso es mas o menos a modo de introducción :D. Si realmente querés saber mas, está el link del borrador mas arriba, de ahora en mas voy a intentar controlar/activar/desactivar este servicio de mi laptop. Resulta ser que en la mayoría de las distribuciones de GNU/Linux viene instalado por defecto un servicio que implementa este protocolo, y se llama Avahi (http://avahi.org/). Avahi es capaz de publicar y descubrir dispositivos, y servicios disponibles en la red local, sin necesidad de realizar configuración alguna.

Veamos si el servicio está corriendo :D  (hagamos de cuenta que nunca vi el paquete con wireshark xD):
"Lo sospeché desde un principio..." asi es, tengo corriendo como demonio a avahi-daemon



Buscando un poco mas se puede ver que escucha en el puerto UDP 5353 de todas las interfaces disponibles, a la espera de consultas/respuestas que pueden provenir de cualquier dirección de red.



Ahora probemos la facilidad de uso de este protocolo. La lan de prueba está compuesta por 2 hosts, la laptop con direccion 192.168.206.1 (nombre moon) y una vm con dirección 192.168.206.134 (nombre ubuntu). Ambos hosts tienen instalado Ubuntu 9.10, que trae por defecto instalado avahi-daemon versión 0.6.25. Ninguno de los host recibió algún tipo de configuración de este servicio, ambos corren como fueron instalados. En el host moon estará nuestro amigo wireshark capturando los paquetes para ver lo que sucede :D.

Buscando a "ubuntu" desde "moon":

Sabemos que está conectadp a la red un host de nombre "ubuntu", pero no sabemos la dirección IP que le fue asignada, y no contamos con un servidor DNS local :D, maldita sea!, pero para eso está corriendo avahi-daemon. Para conocer la dirección de ese host nos basta con hacer un "ping ubuntu.local.", como muestra la imagen



ahora veamos lo que capturó nuestro amigo :D.
Wireshark nos muestra 4 paquetes MDNS, los dos primeros son la resolución directa del nombre de host "ubuntu.local.".
-192.168.206.1 (moon) envía una consulta MDNS a 224.0.0.251 (Multicast IP Address) preguntando por la dirección de "ubuntu.local.".
-192.168.206.134 (ubuntu) envía una respuesta MDNS a 224.0.0.251 (Multicast IP Address) diciendo que 192.168.206.134 corresponde al "host ubuntu.local.".
Los últimos dos paquetes son la resolución inversa, es decir, intenta averiguar el nombre que le corresponde a la dirección 192.168.206.134, esto debe ser una suerte de mecanismo de seguridad, para ver que sean consistentes:
-192.168.206.1 (moon) envía una consulta inversa a la dirección 224.0.0.251, consultando por el nombre que le corresponde a "134.206.168.192.in-addr.arpa.".
-192.168.206.134 (ubuntu) rsponde a la dirección 224.0.0.251, diciendo que esa dirección le corresponde al nombre "ubuntu.local.".



Exáctamente lo mismo podemos observar si ahora realizamos el ping desde ubuntu hacia moon.local.



Publicando y Descubriendo servicios:

Junto con MDNS se puede utilizar algo llamado DNS-SD (DNS-Service Discovery), que consiste en dar a conocer y encontrar servicios locales utilizando MDNS. De nuevo se trata de algo de simple puesta en marcha. Como ejemplo publicaremos dos servicios en el host de nombre moon (FQDN moon.local.), un servidor web en el puerto 80 y un ftp en el puerto 21. El proceso de publicación de los servicios consiste en crear un archivo con sintaxis XML en el directorio /etc/avahi/services/, con la condición que el nombre del archivo debe finalizar en ".service" (sin las comillas :D), como el siguiente:



Para entender bien la sintaxis basta con dar una breve leída a "man avahi.service" :D. Luego de configurar adecuadamente los servicios que querramos reiniciamos el demonio avahi con "avahi-daemon -r" y listo, toda la magia de la publicación de servicios es esa jajaja. Ahora hay que comprobar que los servicios están siendo publicados, para eso instalé dos porgramas mdns-scan y mzclient, NO instalen mdns-scan es DEMASIADO BASICO (ni siquiera recibe parámetros y solo busca types "_workstation"). Primero veamos los hosts que se encuentran utilizando MDNS ejecutamos mzclient como en la próxima imagen (-r se encarga de resolver los nombres de los hosts):



moon tiene 3 direcciones MAC diferentes porque se trata de las 3 interfaces de red, dos virtuales y la eth0 real. Entonces los hosts siguen bien configurados, ahora busquemos los servicios publicados :D. Para eso usamos la opcion -t, que indica la etiqueta type del archivo de servicios, buscamos primero si hay servicios tipo "_http._tcp", incluimos -r para que resuelva nombres:



Ahora busquemos el ftp :D:



Ambos servicios fueron asociados al nombre "moon.local" con dirección 192.168.206.1, como lo configuramos y como debe ser. Eso es gran parte de la publicación de servicios, para mas información http://avahi.org :P.

Deteniendo el demonioooooooo:

Si nos iteresa detener el demonio solo por un momento o reiniciarlo, lo podemos hacer directamente mediante el script ubicado en /etc/init.d. Ejecutamos sudo /etc/init.d/avahi-daemon stop, o mas elegantemente sudo service avahi-daemon stop, para detenerlo, cambiamos stop por restart, para reiniciarlo y start para iniciarlo cuando está detenido.



Deshabilitando temporalmente al demonio:
Si queremos deshabilitarlo temporalmente pero no borrarlo del sistema podemos recurrir a un pequeño truquillo :D. La idea básicamente consiste en que sencillamente el demonio nunca se inicie xD, y esto lo podemos lograr alterando el script de inicio del demonio, ubicado en "/etc/init/avahi-daemon.conf". Como se ve en la imagen hay que comentar la linea de "start".



En definitiva, se trata de un servicio bastante útil, pero que sinceramente no necesito tener activo en este momento. Posiblemente en una LAN donde todo el tiempo entran y salen dispositivos diferentes sea de suma utilidad, pero no lo veo tan así en una LAN chica con poco cambio de los dispositivos.