Sistemas Distribuidos I (75.74)
===============================
-----------------------------
-Trabajo práctico de stack IP
-----------------------------
+------------------------------------------------------------------
+TP 2: Sistema de resolución de nombres sobre IP adaptado a sockets
+------------------------------------------------------------------
:Author: Leandro Lucarella (77891)
En el directorio `src` se encuentra el código fuente del trabajo, con su
correspondiente `Makefile` para compilarlo tan solo ejecutando `make`.
-Dentro de este directorio hay también dos scripts de pruebas completas:
-`test.sh` (con 1 router) y `test2.sh` (con 2 routers).
En el directorio `rutas_ejemplo` contiene algunos archivos con descripciones de
-rutas de ejemplo para correr los programas.
+rutas de ejemplo para correr los programas. En el directorio `zonas_ejemplo` se
+encuentran archivos de configuración de zonas de dominios de nombre para
+realizar pruebas.
Uso
===
-El trabajo consta de un programa llamado `ip` (más algunas otras pruebas que no
-tiene relevancia). Este programa corre 3 procesos, uno que recibe paquetes IP
+El trabajo consta de dos programas, uno llamado `ip` y otro `dns` (más algunas
+otras pruebas que no tienen relevancia).
+
+ip
+--
+
+El programa `ip` corre 3 procesos (fork(2)eados), uno que recibe paquetes IP
otro que recibe entrada del usuario y envía paquetes IP y otro que redirecciona
(forward) paquetes IP en caso de ser pertinente.
Protocolo que transporta (default 0)
-El programa se queda esperando la entrada del usuario, y sale cuando está se
+El programa se queda esperando la entrada del usuario, y sale cuando esta se
termina (Ctrl-D). El formato de entrada es::
IP DESTINO
mensaje. Para enviar otro mensaje, nuevamente se pone IP de destino en una línea
y el mensaje en la siguiente.
+dns
+---
+
+El programa `dns` corre también 3 procesos (fork(2)eados), uno que recibe
+peticiones de nombres, otro que recibe entrada del usuario y envía peticiones
+(o mejor dicho encola peticiones para ser enviadas) y otro que realiza el envío
+de las peticiones realmente.
+
+Uso::
+
+ ./dns ip [route_file [zone_file [port]]]
+
+ip
+ IP que utiliza este proceso (ídem programa `ip`)
+
+route_file
+ Archivo con las rutas (ídem programa `ip`)
+
+zone_file
+ Archivo con la descripción de las zonas. El formato es muy simple. Cada zona
+ está separada por un renglón en blanco y empieza con una línea con 3 campos
+ separados por espacios o tab: nombre de la zona, TTL y nodo padre. Luego le
+ sigue la lista de registros de esa zona, también con 3 campos por renglón:
+ nombre, tipo de registro (A para indicar una IP, NS para indicar donde buscar
+ registros de una zona con ese nombre) e IP (ya sea la IP definitiva si es A o
+ la IP del nameserver al cual recurrir si es NS). Se pueden ver ejemplos de
+ estos archivos en el disco entregado.
+
+port
+ Puerto en el cual escuchará la abstracción de capa física sobre TCP.
+
+
+El programa es muy similar a `ip`, se queda esperando la entrada del usuario,
+y sale cuando esta se termina (Ctrl-D). El formato de entrada es::
+
+ HOSTNAME_A_BUSCAR
+
+Es decir, se escribe en una línea el nombre del host del cual se quiera obtener
+la IP y se presiona ENTER.
+
Diseño del trabajo
==================
siguientes clases:
Dev
- Encapsula la capa física y el dispositivo de red. Utiliza una cola como medio
- físico y el id representaría el cable (si 2 dispositivos tienen cola con id
- distinto serían como si no compartieran el mismo cable). Por simplicidad a la
- cola siempre se envía el tamaño del MTU completo pero se agrega una cabecera
- con el tamaño real del frame.
+ Encapsula la capa física y el dispositivo de red. Es una interfaz abstracta.
+
+DevQue
+ Implementación de Dev utilizando una cola como medio físico y el id
+ representaría el cable (si 2 dispositivos tienen cola con id distinto serían
+ como si no compartieran el mismo cable). Por simplicidad a la cola siempre
+ se envía el tamaño del MTU completo pero se agrega una cabecera con el
+ tamaño real del frame.
+
+DevTCP
+ Implementación de Dev utilizando conexiones TCP. Por cada frame saliente a un
+ destino en particular se crea una conexión TCP (a menos que ya esté creada, en
+ cuyo caso se reutiliza) y se escucha por conexiones entrantes para recibir
+ frames (también guardándolas para reutilizarlas). A diferencia del DevQue se
+ envía el tamaño del frame exacto (en realidad se agrega una pequeña cabecera).
IPAddr
Clase auxiliar que encapsula una dirección IP.
* No existe una ruta para el destino
* Tamaño de paquete más grande que MTU y DF=1
+libtcp
+ Es el único componente del TP que no es orientado a objetos ya que se
+ reutilizó de trabajos anteriores. Es una pequeña abstracción sobre la API de
+ sockets de BSD para mayor simplicidad.
-Ejemplo de corrida
-==================
-
-Host 10.10.10.1
----------------
-
-Rutas:
-
-* 10.10.10.1 0.0.0.0 35 0
-* 10.10.10.3 10.10.10.5 35 1
-* 10.10.10.5 0.0.0.0 35 0
-
-Envía "adios mundo cruel!!!" al host 10.10.10.3::
-
- $ (echo -e '10.10.10.3\nAdios mundo cruel!!!'; sleep 1) | ./ip 10.10.10.1 0 0 ../rutas_ejemplo/route_10.10.10.1.txt
- IPOut::send (10.10.10.1): Fragmento 0 => IPHeader: version=4 total_len=40 id=44919 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=214 src=10.10.10.1 dst=10.10.10.3
- data (15) = Adios mundo cru
- IPOut::send (10.10.10.1): Fragmento 1 => IPHeader: version=4 total_len=25 id=44919 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=315 src=10.10.10.1 dst=10.10.10.3
- data (5) = el!!!
- Enviado 'Adios mundo cruel!!!' a 10.10.10.3
-
-
-Router 10.10.10.5
------------------
+ResolvProtoRequest
+ Clase que encapsula una petición de resolución de nombre a enviar via IP.
-Rutas:
+ResolvProtoResponse
+ Clase que encapsula una respuesta de resolución de nombre a enviar via IP.
-* 10.10.10.1 0.0.0.0 35 0
-* 10.10.10.3 0.0.0.0 32 0
-* 10.10.10.5 0.0.0.0 35 0
+NameServer
+ Clase encargada de resolver los nombres. Escucha por peticiones y puede
+ resolverlas recursiva o directamente (según venga de otro NameServer o de un
+ Resolver la petición). Esta clase se compone de varias otras clases auxiliares
+ para almacenar las zonas y el cache.
-Recibe el mensaje::
- $ ./ip 10.10.10.5 1 1 ../rutas_ejemplo/route_10.10.10.5.txt
- IPIn::recv (10.10.10.5): IPHeader: version=4 total_len=40 id=44919 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=214 src=10.10.10.1 dst=10.10.10.3
- data (15) = Adios mundo cru
- IPIn::recv (10.10.10.5): IPHeader: version=4 total_len=25 id=44919 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=315 src=10.10.10.1 dst=10.10.10.3
- data (5) = el!!!
- IPOut::forward_loop (10.10.10.5): A forwardear (id 44919)
- IPOut::send (10.10.10.5): Fragmento 0 => IPHeader: version=4 total_len=40 id=44919 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=214 src=10.10.10.1 dst=10.10.10.3
- data (12) = Adios mundo
- IPOut::send (10.10.10.5): Fragmento 1 => IPHeader: version=4 total_len=28 id=44919 DF=0 MF=1 offset=12 TTL=64 proto=0 checksum=298 src=10.10.10.1 dst=10.10.10.3
- data (3) = cru
- IPOut::forward_loop (10.10.10.5): A forwardear (id 44919)
- IPOut::send (10.10.10.5): Fragmento 0 => IPHeader: version=4 total_len=25 id=44919 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=315 src=10.10.10.1 dst=10.10.10.3
- data (5) = el!!!
-
-
-Host 10.10.10.3
----------------
-
-Rutas:
-
-* 10.10.10.1 10.10.10.5 32 1
-* 10.10.10.3 0.0.0.0 32 0
-* 10.10.10.5 0.0.0.0 32 0
-
-Finalmente este host recibe todos los fragmentos, reensabla y pasa el
- paquete completo a la capa superior::
-
- $ ./ip 10.10.10.3 0 0 ../rutas_ejemplo/route_10.10.10.3.txt
- IPIn::recv (10.10.10.3): IPHeader: version=4 total_len=40 id=44919 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=214 src=10.10.10.1 dst=10.10.10.3
- data (12) = Adios mundo
- IPIn::recv (10.10.10.3): IPHeader: version=4 total_len=28 id=44919 DF=0 MF=1 offset=12 TTL=64 proto=0 checksum=298 src=10.10.10.1 dst=10.10.10.3
- data (3) = cru
- IPIn::recv (10.10.10.3): IPHeader: version=4 total_len=25 id=44919 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=315 src=10.10.10.1 dst=10.10.10.3
- data (5) = el!!!
- IPIn::recv (10.10.10.3): Paquete completo: data = 'Adios mundo cruel!!!'
- Recibido 'Adios mundo cruel!!!' (len 20) de 10.10.10.1 para 10.10.10.3 (proto = 0)
+Ejemplo de corrida
+==================
-.. vim: filetype=rst :
+Archivo de configuración de zonas de 10.10.10.2::
+
+ homero.casa 600 10.10.10.1
+ tito A 10.10.100.1
+ juan A 10.10.100.2
+ juan A 10.10.100.3
+ pepe A 10.10.100.4
+ juan A 10.10.100.5
+ pepe A 10.10.100.6
+ marge NS 10.10.10.3
+ todos NS 10.10.10.1
+ todos NS 10.10.10.3
+ todos NS 10.10.10.141
+
+Línea de comandos::
+
+ ./dns 10.10.10.2 ../rutas_ejemplo/mi_lan.txt ../zonas_ejemplo/10.10.10.2.txt
+
+Resolución de un nombre local con una sola IP
+---------------------------------------------
+
+Línea de comandos::
+
+ ./dns 10.10.10.2 ../rutas_ejemplo/mi_lan.txt ../zonas_ejemplo/10.10.10.2.txt
+
+Salida::
+
+ tito.homero.casa
+ Resolviendo tito.homero.casa...
+ resolv_direct -> tratando de resolver: tito.homero.casa
+ resolv_direct found (local/hijo): ResolvProtoResponse(ret=2, ttl=600, 10.10.100.1)
+ resolv_recursive -> gotcha! ResolvProtoResponse(ret=2, ttl=600, 10.10.100.1)
+ Resultado: ResolvProtoResponse(ret=2, ttl=600, 10.10.100.1)
+
+Resolución de un nombre local con múltiples IP
+----------------------------------------------
+
+Salida::
+
+ juan.homero.casa
+ Resolviendo juan.homero.casa...
+ resolv_direct -> tratando de resolver: juan.homero.casa
+ resolv_direct found (local/hijo): ResolvProtoResponse(ret=2, ttl=600, 10.10.100.2, 10.10.100.3, 10.10.100.5)
+ resolv_recursive -> gotcha! ResolvProtoResponse(ret=2, ttl=600, 10.10.100.2, 10.10.100.3, 10.10.100.5)
+ Resultado: ResolvProtoResponse(ret=2, ttl=600, 10.10.100.2, 10.10.100.3, 10.10.100.5)
+
+Resolución de un nombre local no existente
+------------------------------------------
+
+Salida::
+
+ none.homero.casa
+ Resolviendo none.homero.casa...
+ resolv_direct -> tratando de resolver: none.homero.casa
+ resolv_direct NOT FOUND (es local pero no existe)
+ Resultado: ResolvProtoResponse(ret=4, ttl=0)
+
+Resolución de un nombre remoto con múltiples IP y 2 niveles de indirección
+--------------------------------------------------------------------------
+
+Archivo de configuración de zonas de 10.10.10.1::
+
+ casa 600 0.0.0.0
+ burns A 10.10.10.1
+ homero A 10.10.10.2
+ marge A 10.10.10.3
+ manuk A 10.10.10.141
+ juan A 100.10.100.5
+ pepe A 100.10.100.6
+ homero NS 10.10.10.2
+ marge NS 10.10.10.3
+ manuk NS 10.10.10.141
+
+ burns.casa 600 0.0.0.0
+ tito A 100.10.100.1
+ juan A 100.10.100.2
+ juan A 100.10.100.3
+ pepe A 100.10.100.4
+ juan A 100.10.100.5
+ pepe A 100.10.100.6
+
+ todos.homero.casa 9500 0.0.0.0
+ tito A 10.1.100.1
+ juan A 10.1.100.2
+ juan A 10.1.100.3
+ pepe A 10.1.100.4
+ juan A 10.1.100.5
+ pepe A 10.1.100.6
+
+Archivo de configuración de zonas de 10.10.10.3::
+
+ marge.casa 600 10.10.10.1
+ tito A 30.10.100.1
+ juan A 30.10.100.2
+ juan A 30.10.100.3
+ pepe A 30.10.100.4
+ juan A 30.10.100.5
+ pepe A 30.10.100.6
+ manuk NS 10.10.10.141
+ todos NS 10.10.10.1
+ todos NS 10.10.10.3
+ todos NS 10.10.10.141
+
+ todos.homero.casa 9500 10.10.10.2
+ tito A 10.1.100.1
+ juan A 10.1.100.2
+ juan A 10.1.100.3
+ pepe A 10.1.100.4
+ juan A 10.1.100.5
+ pepe A 10.1.100.6
+
+ marge.homero.casa 9500 10.10.10.2
+ tito A 10.3.100.1
+ juan A 10.3.100.2
+ juan A 10.3.100.3
+ pepe A 10.3.100.4
+ juan A 10.3.100.5
+ pepe A 10.3.100.6
+
+
+La petición se realiza desde 10.10.10.2, quien debe recurir a su nodo padre
+(10.10.10.1) que indica que el encargado de resolver esa zona es 10.10.10.3.
+
+Salida de 10.10.10.2::
+
+ pepe.marge.casa
+ Resolviendo pepe.marge.casa...
+ resolv_direct -> tratando de resolver: pepe.marge.casa
+ resolv_direct -> evaluando padre 10.10.10.1
+ resolv_direct found (al padre): 10.10.10.1
+ resolv_recursive -> redirect a ResolvProtoResponse(ret=3, ttl=600, 10.10.10.1)
+ query -> pidiendo ResolvProtoRequest(query_type=0, name=pepe.marge.casa) a 10.10.10.1
+ query -> recibido ResolvProtoResponse(ret=3, ttl=600, 10.10.10.3) de 10.10.10.1
+ resolv_recursive_r -> redirect a ResolvProtoResponse(ret=3, ttl=600, 10.10.10.3)
+ query -> pidiendo ResolvProtoRequest(query_type=0, name=pepe.marge.casa) a 10.10.10.3
+ query -> recibido ResolvProtoResponse(ret=2, ttl=600, 30.10.100.4, 30.10.100.6) de 10.10.10.3
+ resolv_recursive_r -> gotcha! ResolvProtoResponse(ret=2, ttl=600, 30.10.100.4, 30.10.100.6)
+ Resultado: ResolvProtoResponse(ret=2, ttl=600, 30.10.100.4, 30.10.100.6)
+
+Salida de 10.10.10.1::
+
+ NameServer::send_loop() -> recibido ResolvProtoRequest(query_type=0, name=pepe.marge.casa)
+ resolv_direct -> tratando de resolver: pepe.marge.casa
+ resolv_direct found (local/hijo): ResolvProtoResponse(ret=3, ttl=600, 10.10.10.3)
+ NameServer::send_loop() -> respondo ResolvProtoResponse(ret=3, ttl=600, 10.10.10.3)
+
+Salida de 10.10.10.3::
+
+ NameServer::send_loop() -> recibido ResolvProtoRequest(query_type=0, name=pepe.marge.casa)
+ resolv_direct -> tratando de resolver: pepe.marge.casa
+ resolv_direct found (local/hijo): ResolvProtoResponse(ret=2, ttl=600, 30.10.100.4, 30.10.100.6)
+ NameServer::send_loop() -> respondo ResolvProtoResponse(ret=2, ttl=600, 30.10.100.4, 30.10.100.6)
+
+.. vim: filetype=rst sw=2 sts=2 et :