--- /dev/null
+Enunciado extraoficial
+
+Hay que hacer 2 procesos, uno que manda y otro que recibe IP, por cada
+host/router. Todos los procesos que envian, ponen las cosas en una cola, todos
+los que reciben, sacan de esa cola. Se usa como MAC la IP, y como ID del mensaje
+de la cola (de esta manera cada proceso saca solo los "paquetes" con el ID/MAC
+que le corresponda).
+
+1) Campos en IP
+ id de paquete
+ ip origen
+ ip destino
+ checksum (0/1, de juguete)
+ tamaño del paquete completo
+ ToS
+ Don't Fragment (0/1)
+ End (0/1)
+ offset
+ TTL
+ tamaño de este fragmento
+ tipo de payload (IP / ICMP)
+ (se que faltan algunos, si tienen algo mas,
+ completen)
+
+2) Casos de descarte de paquetes
+ Error de checksum (silencioso)
+ No hay buffer para fragmento (silencioso)
+ Un host que no rutea recibe un paquete para otro host
+ (silencioso)
+ No hay ruta (icmp)
+ DF == 1 y MTU < size (icmp)
+ TTL == 0 (icmp)
+
+3) Comportamiento del protocolo
+ Debe rutear (si es un router)
+ Debe fragmentar y reensamblar
+ Debe contemplar todos los casos de descarte de
+ paquetes anteriores escribiendo en un archivo
+ los paquetes descartados según corresponda
+ (silecioso, icmp).
+
--- /dev/null
+===============================
+Sistemas Distribuidos I (75.74)
+===============================
+
+------------------------------------------------------------------
+TP 2: Sistema de resolución de nombres sobre IP adaptado a sockets
+------------------------------------------------------------------
+
+:Author: Leandro Lucarella (77891)
+
+
+Organización
+============
+
+En el directorio `src` se encuentra el código fuente del trabajo, con su
+correspondiente `Makefile` para compilarlo tan solo ejecutando `make`.
+
+En el directorio `rutas_ejemplo` contiene algunos archivos con descripciones de
+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 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.
+
+Uso::
+
+ ./ip ip [router [forward [route_file [queue_id [proto]]]]]
+
+ip
+ IP que utiliza este proceso
+
+router
+ 0 si es router, 1 si no lo es (default 0)
+
+forward
+ 0 si puede hacer forwarding, 1 si no (default 0)
+
+route_file
+ Archivo con las rutas. El formato del archivo es una ruta por línea, cada
+ línea se compone de red (por ahora sólo soporta IPs puntuales), gateway (si es
+ cero es que están en la misma red), MTU y métrica (todavía no se usa),
+ separados por uno o más espacios o tabs (default `route.txt`)
+
+queue_id
+ Identificador de la cola a usar como medio físico, también establece el
+ identificador de la cola a usar para comunicarse con el otro proceso
+ (`test_ipout`) para hacer forwarding, que será queue_id + 1 (default
+ `DEV_DEFAULT_KEY` obtenido de `dev.h`)
+
+proto
+ Protocolo que transporta (default 0)
+
+
+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
+
+Es decir, en una línea se pone la IP de destino y en la línea siguiente el
+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
+==================
+
+El trabajo fue desarrollado en C++, orientado a objetos. Se compone de las
+siguientes clases:
+
+Dev
+ 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.
+
+IPHeader
+ Encapsula una cabecera IP. El cálculo de checksum se simplificó (haciendo una
+ suma byte a byte de toda la cabecera) porque cumple con el objetivo didactico
+ de todas maneras.
+
+RouteTable
+ Encapsula una tabla de ruteo. Por falta de tiempo y simplicidad por ahora sólo
+ soporta rutas a un sólo host (no a una red) pero es muy fácilmente extensible
+ y transparente para el resto de las clases que la usan. Las rutas se componen
+ de red (en realidad por ahora host), geteway, MTU, metrica y dispositivo de
+ red por el cual salir (Dev).
+
+IPIn
+ Es la clase encargada de recibir paquetes IP. Hace chequeos varios y descarta
+ paquetes según los siguientes criterios:
+
+ * Cabecera incompleta o no es IP
+ * Versión IP incorrecta
+ * Mal checksum
+ * TTL=0
+ * No es para nosotros y no hacemos forward
+ * Es para nosotros pero somos un router
+
+ Si hace forwarding le pasa a IPOut el paquete por una cola y reensabla de ser
+ necesario.
+
+IPOut
+ Es la clase encargada de enviar paquetes IP. Tiene una RouteTable para hacer
+ el ruteo y verifica si hay paquetes a forwardear antes de enviar lo que le
+ piden. También fragmenta y puede "descartar" paquetes según estos criterios:
+
+ * 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.
+
+ResolvProtoRequest
+ Clase que encapsula una petición de resolución de nombre a enviar via IP.
+
+ResolvProtoResponse
+ Clase que encapsula una respuesta de resolución de nombre a enviar via IP.
+
+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.
+
+
+Ejemplo de corrida
+==================
+
+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 :
--- /dev/null
+IP:
+===
+- Implementar metricas
+- Implementar rutas de redes completas (no sólo ruta a un host)
+- Arreglar cola de forwarding para que no dependa del medio fisico/dispositivo
+- Tener en cuenta el TTL para limpiar buffers
+- Ver que hayan llegado todos los fragmentos antes de subir a capa superior
+- Separar descartes de ICMP de silenciosos (parcialmente hecho)
+- Manejar envíos a través de una cola para que no se rompa (como creo que
+ debería romperse, por ser 2 procesos distintos los que mandan y no comparten
+ el pool de conexiones TCP) el forwarding.
+
+DevTCP:
+=======
+- Controlar pérdidas de conexiones.
+
+DNS:
+====
+- Agregar entradas al cache y revisar la edad del cache antes de usarlo (y
+ limpiarlo si es viejo).
+- Resolver el problema de requests/responses simultáneos de distintos lugares
+ (probablemente haya que agregar un ID al protocolo para identificar distintas
+ respuestas).
+- Resolver (!)
--- /dev/null
+{\rtf1\ansi\ansicpg1252\deff0
+{\fonttbl
+{\f0\fnil\fcharset0\fprq0\fttruetype Arial;}
+{\f1\fnil\fcharset0\fprq0\fttruetype Times New Roman;}
+{\f2\fnil\fcharset0\fprq0\fttruetype Courier New;}
+{\f3\fnil\fcharset0\fprq0\fttruetype Dingbats;}
+{\f4\fnil\fcharset0\fprq0\fttruetype Symbol;}}
+{\colortbl
+\red0\green0\blue0;
+\red255\green255\blue255;}
+{\stylesheet
+{\s1\fi-431\li720\sbasedon28\snext28Contents 1;}
+{\s2\fi-431\li1440\sbasedon28\snext28Contents 2;}
+{\s3\fi-431\li2160\sbasedon28\snext28Contents 3;}
+{\s8\fi-431\li720\sbasedon28Lower Roman List;}
+{\s5\tx431\sbasedon24\snext28Numbered Heading 1;}
+{\s6\tx431\sbasedon25\snext28Numbered Heading 2;}
+{\s7\fi-431\li720Square List;}
+{\*\cs11\sbasedon28Endnote Text;}
+{\s4\fi-431\li2880\sbasedon28\snext28Contents 4;}
+{\s9\fi-431\li720Diamond List;}
+{\s10\fi-431\li720Numbered List;}
+{\*\cs12\fs20\superEndnote Reference;}
+{\s13\fi-431\li720Triangle List;}
+{\s14\tx431\sbasedon26\snext28Numbered Heading 3;}
+{\s15\fi-431\li720Dashed List;}
+{\s16\fi-431\li720\sbasedon10Upper Roman List;}
+{\s17\sb440\sa60\f0\fs24\b\sbasedon28\snext28Heading 4;}
+{\s18\fi-431\li720Heart List;}
+{\s34\fi-431\li720Box List;}
+{\s20\fi-431\li720\sbasedon10Upper Case List;}
+{\s21\fi-431\li720Bullet List;}
+{\s22\fi-431\li720Hand List;}
+{\*\cs23\fs20\sbasedon28Footnote Text;}
+{\s24\sb440\sa60\f0\fs34\b\sbasedon28\snext28Heading 1;}
+{\s25\sb440\sa60\f0\fs28\b\sbasedon28\snext28Heading 2;}
+{\s19\qc\sb240\sa120\f0\fs32\b\sbasedon28\snext28Contents Header;}
+{\s27\fi-431\li720Tick List;}
+{\s26\sb440\sa60\f0\fs24\b\sbasedon28\snext28Heading 3;}
+{\s29\fi-431\li720\sbasedon10Lower Case List;}
+{\s30\li1440\ri1440\sa120\sbasedon28Block Text;}
+{\s36\f2\sbasedon28Plain Text;}
+{\s32\tx1584\sbasedon5\snext28Section Heading;}
+{\s33\fi-431\li720Implies List;}
+{\s28\f1\fs24\lang1034Normal;}
+{\s35\fi-431\li720Star List;}
+{\*\cs31\fs20\superFootnote Reference;}
+{\s37\tx1584\sbasedon5\snext28Chapter Heading;}}
+\kerning0\cf0\ftnbj\fet2\ftnstart1\ftnnar\aftnnar\ftnstart1\aftnstart1\aenddoc\revprop3{\info\uc1}\deftab720\viewkind1\paperw11905\paperh16837\margl1440\margr1440\widowctl
+\sectd\sbknone\colsx360\pgncont\ltrsect
+\pard\plain\ltrpar\qc\s28\itap0{\s28\f0\fs52\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Sistemas Distribuidos I (75.74)}{\s28\f1\fs24\lang1034{\*\listtag1003}\par}
+\pard\plain\ltrpar\qc\s28\itap0{\s28\f0\fs28\lang1034{\*\listtag0}\abinodiroverride\ltrch TP 2: Sistema de resoluci\'f3n de nombres sobre IP adaptado a sockets}{\s28\f0\fs28\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\qc\s28\itap0{\field\fdledit{\*\fldinst {\ TOC }}}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s24\itap0{\s24\f0\fs34\b\lang1034{\*\listtag0}\abinodiroverride\ltrch DNS}{\s24\f0\fs34\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s25\itap0{\s25\f0\fs28\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Diagrama de secuencia}{\s25\f0\fs28\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch \page }{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s25\itap0{\s25\f0\fs28\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Dise\'f1o de mensajes de intercambio de DNS.}{\s25\f0\fs28\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch Petici\'f3n de un nameserver}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch +------------+------------+------------+}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch | QUERY_TYPE | SIZE | NAME |}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch +------------+------------+------------+}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch /-- 1 byte --/- 2 bytes --/- variable -/}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch QUERY_TYPE en realidad es una cabecera com\'fan a las peticiones y respuestas, cuyos c\'f3digos pueden ser los siguientes:}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Requests}{\s28\f2\fs22\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch RP_REQ_DIRECT -> B\'fasqueda directa (inter nameservers)}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch RP_REQ_RECURSIVE-> B\'fasqueda recursiva (para resolvers)}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Responses}{\s28\f2\fs22\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch RP_RES_A -> OK, se devolvi\'f3 un registro A}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch RP_RES_NS -> OK, se devolvi\'f3 un registro NS (s\'f3lo en directo)}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch RP_RES_NOTFOUND -> No se encontr\'f3}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs22\lang1034{\*\listtag0}\abinodiroverride\ltrch RP_RES_TIMEOUT -> Tard\'f3 demasiado la consulta}{\s28\f2\fs22\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch SIZE es el tama\'f1o del string con el nombre a buscar, NAME es el string (de longitud variable). Faltar\'eda agregar un campo con un ID para evitar que se confundan unas respuestas o peticiones con otras.}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch Respuesta de un nameserver}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\abinodiroverride\ltrch +-----------+-----------+-----------+-----------+-----------+-----------+}{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\abinodiroverride\ltrch | RET | TTL | COUNT | IP 1 | ... | IP N |}{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\abinodiroverride\ltrch +-----------+-----------+-----------+-----------+-----------+-----------+}{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\abinodiroverride\ltrch /-- 1 byte -/- 4 bytes -/-- 1 byte -/- 4 bytes -/- 4 bytes -/- 4 bytes -/}{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch RET es del mismo tipo que QUERY_TYPE y se hizo as\'ed para poder reconocer si un paquete es un request o un response con s\'f3lo leer el 1er byte. TTL es el tiempo que puede vivir en el cache (en segundos), COUNT es la cantidad de IPs encontradas para ese registro e IP1 a IPN son las IP en s\'ed (cantidad variable).}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s25\itap0{\s25\f0\fs28\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Par\'e1metros y resultados de la funci\'f3n gethostbyname()}{\s25\f0\fs28\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\abinodiroverride\ltrch std::vector< IPAddr > gethostbyname(std::string name, int& result);}{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs20\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch Esta funci\'f3n toma como par\'e1metro un string con el nombre de dominio a buscar (por ejemplo "mi.dominio.casa") y retorna un vector de IPs. Si hay un error o no encuentra ninguna el vector se devuelve vac\'edo y se pone el c\'f3digo de error en la variable result. El trabajo de la funci\'f3n es conectarse a todos los nameservers que conozca y env\'ede un pedido de resoluci\'f3n de nombre RECURSIVO, hasta que tenga \'e9xito o se acabe la lista de nameservers disponibles. Por falta de tiempo esta funci\'f3n no est\'e1 implementada del lado del resolver pero s\'ed del nameserver, y es muy muy similar (hace exactamente lo mismo).}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s24\itap0{\s24\f0\fs34\b\lang1034{\*\listtag0}\abinodiroverride\ltrch IP}{\s24\f0\fs34\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s25\itap0{\s25\f0\fs28\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Dise\'f1o del paquete IP}{\s25\f0\fs28\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch \page }{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch // Campos}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch uint8_t version;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch uint16_t total_len;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch uint16_t id;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch uint16_t reserved_flag: 1;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch uint16_t df: 1;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch uint16_t mf: 1;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch uint16_t offset: 13;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch uint8_t ttl;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch uint8_t proto;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch uint16_t checksum;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch uint32_t src;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f2\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch uint32_t dst;}{\s28\f2\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch \page }{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s25\itap0{\s25\f0\fs28\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Diagrama de secuencia}{\s25\f0\fs28\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch \page }{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s25\itap0{\s25\f0\fs28\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Cambios}{\s25\f0\fs28\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch Se agreg\'f3 principalmente la clase DevTCP que implementa la capa f\'edsica a trav\'e9s de TCP. Por cada frame saliente a un destino en particular se crea una conexi\'f3n TCP (a menos que ya est\'e9 creada, en cuyo caso se reutiliza) y se escucha por conexiones entrantes para recibir frames (tambi\'e9n guard\'e1ndolas para reutilizarlas). A diferencia del DevQue se env\'eda el tama\'f1o del frame exacto (en realidad se agrega una peque\'f1a cabecera).}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\sb440\sa60\s24\itap0{\s24\f0\fs34\b\lang1034{\*\listtag0}\abinodiroverride\ltrch Lista de fuentes de informaci\'f3n}{\s24\f0\fs34\b\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch RFC 1034 - Domain names - concepts and facilities:}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch \tab http://www.faqs.org/rfcs/rfc1034.html}{\s28\f1\fs24\lang1034{\*\listtag0}\par}
+\pard\plain\ltrpar\ql\s28\itap0{\s28\f1\fs24\lang1034{\*\listtag0}\abinodiroverride\ltrch \tab Conceptos y desiciones de dise\'f1o del DNS.}{\s28\f1\fs24\lang1034{\*\listtag0}\par}}
\ No newline at end of file
--- /dev/null
+10.10.10.1 0.0.0.0 30 0
+10.10.10.2 0.0.0.0 30 0
+10.10.10.3 0.0.0.0 30 0
+10.10.10.141 0.0.0.0 30 0
--- /dev/null
+10.10.10.1 0.0.0.0 25 0
+10.10.10.2 0.0.0.0 25 0
+10.10.10.3 10.10.10.5 25 0
--- /dev/null
+10.10.10.1 0.0.0.0 35 0
+10.10.10.2 10.10.10.5 35 2
+10.10.10.3 10.10.10.5 35 1
+10.10.10.4 10.10.10.5 35 1
+10.10.10.5 0.0.0.0 35 0
--- /dev/null
+10.10.10.2 0.0.0.0 25 0
+10.10.10.141 0.0.0.0 25 0
--- /dev/null
+10.10.10.1 10.10.10.4 25 2
+10.10.10.2 0.0.0.0 25 0
+10.10.10.3 10.10.10.4 25 2
+10.10.10.4 0.0.0.0 25 0
+10.10.10.5 10.10.10.4 25 1
--- /dev/null
+10.10.10.2 0.0.0.0 25 0
+10.10.10.141 0.0.0.0 25 0
--- /dev/null
+10.10.10.1 10.10.10.5 32 1
+10.10.10.2 10.10.10.5 32 2
+10.10.10.3 0.0.0.0 32 0
+10.10.10.4 10.10.10.5 32 1
+10.10.10.5 0.0.0.0 32 0
--- /dev/null
+10.10.10.1 10.10.10.5 28 1
+10.10.10.2 0.0.0.0 25 0
+10.10.10.3 10.10.10.5 28 1
+10.10.10.4 0.0.0.0 28 0
+10.10.10.5 0.0.0.0 28 0
--- /dev/null
+10.10.10.1 0.0.0.0 35 0
+10.10.10.2 10.10.10.4 28 1
+10.10.10.3 0.0.0.0 32 0
+10.10.10.4 0.0.0.0 28 0
+10.10.10.5 0.0.0.0 35 0
--- /dev/null
+# Makefile de ejemplo para C++
+#
+# Creado: jue abr 15 15:34:19 ART 2004
+#
+# Copyleft 2004 - Leandro Lucarella, Bajo licencia GPL [http://www.gnu.org/]
+#
+
+# CONFIGURACION
+################
+
+# Opciones para el compilador C/C++ en modo ansi.
+CFLAGS = -Wall -ansi -pedantic-errors
+
+# Para que explote lo mas posible
+#CFLAGS += -O3 -DNDEBUG
+
+# Para valgrind o debug
+CFLAGS += -ggdb -DDEBUG
+
+# Para más verbose
+CFLAGS += -DDEBUG2
+
+# Opciones para el compilador C++.
+CXXFLAGS = $(CFLAGS) -fno-inline
+
+# Opciones del enlazador.
+#LDFLAGS=
+
+# Compilador.
+CC=g++
+
+# Programas
+targets=ip dns
+tests=test_send test_recv test_ipaddr test_ipin test_ipout test_devtcp \
+ test_poll test_resolvproto test_nameserver_file \
+ test_nameserver_resolvnext
+
+# Fuentes
+fuentes ?= $(wildcard *.cpp) $(wildcard *.c)
+
+ip_objs=ipout.o ipin.o ipaddr.o ipheader.o devque.o devtcp.o routetable.o \
+ libtcp.o
+dns_objs=nameserver.o resolvproto.o
+
+# REGLAS
+#########
+
+.PHONY: all clean
+
+all: depend $(targets)
+
+tests: depend $(tests)
+
+test_send: test_send.o devque.o
+
+test_recv: test_recv.o devque.o
+
+test_ipaddr: test_ipaddr.o ipaddr.o ipheader.o
+
+test_ipin: test_ipin.o ipin.o ipaddr.o ipheader.o devque.o
+
+test_ipout: test_ipout.o ipout.o ipaddr.o ipheader.o devque.o routetable.o
+
+test_devtcp: test_devtcp.o devtcp.o libtcp.o ipaddr.o
+
+test_poll: test_poll.o libtcp.o
+
+test_resolvproto: test_resolvproto.o resolvproto.o ipaddr.o
+
+test_nameserver_file: test_nameserver_file.o $(dns_objs) $(ip_objs)
+
+#FIXME no va libtcp.o, debe ir sobre mi implementación de ip.
+test_nameserver_resolvnext: test_nameserver_resolvnext.o $(dns_objs) $(ip_objs)
+
+ip: ip.o $(ip_objs)
+
+dns: dns.o $(ip_objs) $(dns_objs)
+
+depend:
+ @makedepend $(fuentes) > /dev/null 2>&1
+
+clean:
+ @$(RM) -fv *.o Makefile.bak $(targets) $(tests)
+
+# DO NOT DELETE
+
+devque.o: devque.h dev.h /usr/include/unistd.h /usr/include/features.h
+devque.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+devque.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+devque.o: /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h
+devque.o: /usr/include/bits/confname.h /usr/include/getopt.h
+devque.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+devque.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
+devque.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+devque.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+devque.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+devque.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+devque.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+devque.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
+devque.o: /usr/include/bits/msq.h
+devtcp.o: devtcp.h dev.h /usr/include/stdint.h /usr/include/features.h
+devtcp.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+devtcp.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+devtcp.o: /usr/include/sys/poll.h /usr/include/bits/poll.h ipaddr.h libtcp.h
+devtcp.o: /usr/include/stdio.h /usr/include/bits/types.h
+devtcp.o: /usr/include/bits/typesizes.h /usr/include/libio.h
+devtcp.o: /usr/include/_G_config.h /usr/include/wchar.h /usr/include/gconv.h
+devtcp.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
+devtcp.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h
+devtcp.o: /usr/include/endian.h /usr/include/bits/endian.h
+devtcp.o: /usr/include/sys/select.h /usr/include/bits/select.h
+devtcp.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+devtcp.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+devtcp.o: /usr/include/bits/sched.h /usr/include/alloca.h
+devtcp.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+devtcp.o: /usr/include/bits/confname.h /usr/include/getopt.h
+devtcp.o: /usr/include/signal.h /usr/include/bits/signum.h
+devtcp.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
+devtcp.o: /usr/include/bits/sigcontext.h /usr/include/asm/sigcontext.h
+devtcp.o: /usr/include/asm-i486/sigcontext.h /usr/include/linux/compiler.h
+devtcp.o: /usr/include/bits/sigstack.h /usr/include/bits/sigthread.h
+devtcp.o: /usr/include/sys/wait.h /usr/include/sys/resource.h
+devtcp.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+devtcp.o: /usr/include/bits/waitstatus.h /usr/include/string.h
+devtcp.o: /usr/include/sys/socket.h /usr/include/sys/uio.h
+devtcp.o: /usr/include/bits/uio.h /usr/include/bits/socket.h
+devtcp.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
+devtcp.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
+devtcp.o: /usr/include/bits/posix2_lim.h /usr/include/bits/sockaddr.h
+devtcp.o: /usr/include/asm/socket.h /usr/include/asm-i486/socket.h
+devtcp.o: /usr/include/asm/sockios.h /usr/include/asm-i486/sockios.h
+devtcp.o: /usr/include/netinet/in.h /usr/include/bits/in.h
+devtcp.o: /usr/include/bits/byteswap.h /usr/include/arpa/inet.h
+devtcp.o: /usr/include/netdb.h /usr/include/rpc/netdb.h
+devtcp.o: /usr/include/bits/netdb.h /usr/include/fcntl.h
+devtcp.o: /usr/include/bits/fcntl.h /usr/include/sys/ipc.h
+devtcp.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+devtcp.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+dns.o: ipout.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+dns.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+dns.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h ipheader.h
+dns.o: routetable.h dev.h ipin.h devtcp.h /usr/include/sys/poll.h
+dns.o: /usr/include/bits/poll.h devque.h nameserver.h resolvproto.h
+dns.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+dns.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
+dns.o: /usr/include/bits/confname.h /usr/include/getopt.h
+dns.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+dns.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
+dns.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+dns.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+dns.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+dns.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+dns.o: /usr/include/sys/wait.h /usr/include/signal.h
+dns.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h
+dns.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
+dns.o: /usr/include/asm/sigcontext.h /usr/include/asm-i486/sigcontext.h
+dns.o: /usr/include/linux/compiler.h /usr/include/bits/sigstack.h
+dns.o: /usr/include/bits/sigthread.h /usr/include/sys/resource.h
+dns.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+dns.o: /usr/include/bits/waitstatus.h /usr/include/sys/ipc.h
+dns.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+dns.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+ip.o: ipout.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+ip.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+ip.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h ipheader.h
+ip.o: routetable.h dev.h ipin.h devtcp.h /usr/include/sys/poll.h
+ip.o: /usr/include/bits/poll.h devque.h /usr/include/unistd.h
+ip.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+ip.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+ip.o: /usr/include/getopt.h /usr/include/fcntl.h /usr/include/bits/fcntl.h
+ip.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
+ip.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+ip.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+ip.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+ip.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+ip.o: /usr/include/sys/wait.h /usr/include/signal.h
+ip.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h
+ip.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
+ip.o: /usr/include/asm/sigcontext.h /usr/include/asm-i486/sigcontext.h
+ip.o: /usr/include/linux/compiler.h /usr/include/bits/sigstack.h
+ip.o: /usr/include/bits/sigthread.h /usr/include/sys/resource.h
+ip.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+ip.o: /usr/include/bits/waitstatus.h /usr/include/sys/ipc.h
+ip.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+ip.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+ipaddr.o: ipaddr.h /usr/include/stdint.h /usr/include/features.h
+ipaddr.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+ipaddr.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+ipheader.o: ipheader.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+ipheader.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+ipheader.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+ipin.o: ipin.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+ipin.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+ipin.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h ipheader.h
+ipin.o: dev.h
+ipout.o: ipout.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+ipout.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+ipout.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h ipheader.h
+ipout.o: routetable.h dev.h /usr/include/unistd.h
+ipout.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+ipout.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+ipout.o: /usr/include/getopt.h /usr/include/fcntl.h /usr/include/bits/fcntl.h
+ipout.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
+ipout.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+ipout.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+ipout.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+ipout.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+ipout.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+ipout.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
+ipout.o: /usr/include/bits/msq.h
+nameserver.o: nameserver.h devque.h dev.h ipaddr.h /usr/include/stdint.h
+nameserver.o: /usr/include/features.h /usr/include/sys/cdefs.h
+nameserver.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+nameserver.o: /usr/include/bits/wordsize.h resolvproto.h ipin.h ipheader.h
+nameserver.o: ipout.h routetable.h
+resolvproto.o: resolvproto.h ipaddr.h /usr/include/stdint.h
+resolvproto.o: /usr/include/features.h /usr/include/sys/cdefs.h
+resolvproto.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+resolvproto.o: /usr/include/bits/wordsize.h ipin.h ipheader.h dev.h ipout.h
+resolvproto.o: routetable.h
+routetable.o: routetable.h dev.h ipaddr.h /usr/include/stdint.h
+routetable.o: /usr/include/features.h /usr/include/sys/cdefs.h
+routetable.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+routetable.o: /usr/include/bits/wordsize.h
+test_devtcp.o: ipaddr.h /usr/include/stdint.h /usr/include/features.h
+test_devtcp.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_devtcp.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+test_devtcp.o: devtcp.h dev.h /usr/include/sys/poll.h
+test_devtcp.o: /usr/include/bits/poll.h /usr/include/unistd.h
+test_devtcp.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+test_devtcp.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+test_devtcp.o: /usr/include/getopt.h /usr/include/fcntl.h
+test_devtcp.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
+test_devtcp.o: /usr/include/time.h /usr/include/endian.h
+test_devtcp.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+test_devtcp.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+test_devtcp.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+test_devtcp.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+test_devtcp.o: /usr/include/sys/wait.h /usr/include/signal.h
+test_devtcp.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h
+test_devtcp.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
+test_devtcp.o: /usr/include/asm/sigcontext.h
+test_devtcp.o: /usr/include/asm-i486/sigcontext.h
+test_devtcp.o: /usr/include/linux/compiler.h /usr/include/bits/sigstack.h
+test_devtcp.o: /usr/include/bits/sigthread.h /usr/include/sys/resource.h
+test_devtcp.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+test_devtcp.o: /usr/include/bits/waitstatus.h /usr/include/sys/ipc.h
+test_devtcp.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+test_devtcp.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+test_ipaddr.o: ipaddr.h /usr/include/stdint.h /usr/include/features.h
+test_ipaddr.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_ipaddr.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+test_ipaddr.o: ipheader.h
+test_ipin.o: ipin.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+test_ipin.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_ipin.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+test_ipin.o: ipheader.h dev.h devque.h /usr/include/unistd.h
+test_ipin.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+test_ipin.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+test_ipin.o: /usr/include/getopt.h /usr/include/fcntl.h
+test_ipin.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
+test_ipin.o: /usr/include/time.h /usr/include/endian.h
+test_ipin.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+test_ipin.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+test_ipin.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+test_ipin.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+test_ipin.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+test_ipin.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
+test_ipin.o: /usr/include/bits/msq.h
+test_ipout.o: ipout.h ipaddr.h /usr/include/stdint.h /usr/include/features.h
+test_ipout.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_ipout.o: /usr/include/bits/wchar.h /usr/include/bits/wordsize.h
+test_ipout.o: ipheader.h routetable.h dev.h devque.h /usr/include/unistd.h
+test_ipout.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+test_ipout.o: /usr/include/bits/typesizes.h /usr/include/bits/confname.h
+test_ipout.o: /usr/include/getopt.h /usr/include/fcntl.h
+test_ipout.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
+test_ipout.o: /usr/include/time.h /usr/include/endian.h
+test_ipout.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+test_ipout.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+test_ipout.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+test_ipout.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+test_ipout.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h
+test_ipout.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h
+test_ipout.o: /usr/include/bits/msq.h
+test_nameserver_file.o: nameserver.h devque.h dev.h ipaddr.h
+test_nameserver_file.o: /usr/include/stdint.h /usr/include/features.h
+test_nameserver_file.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_nameserver_file.o: /usr/include/bits/wchar.h
+test_nameserver_file.o: /usr/include/bits/wordsize.h resolvproto.h ipin.h
+test_nameserver_file.o: ipheader.h ipout.h routetable.h
+test_nameserver_resolvnext.o: nameserver.h devque.h dev.h ipaddr.h
+test_nameserver_resolvnext.o: /usr/include/stdint.h /usr/include/features.h
+test_nameserver_resolvnext.o: /usr/include/sys/cdefs.h
+test_nameserver_resolvnext.o: /usr/include/gnu/stubs.h
+test_nameserver_resolvnext.o: /usr/include/bits/wchar.h
+test_nameserver_resolvnext.o: /usr/include/bits/wordsize.h resolvproto.h
+test_nameserver_resolvnext.o: ipin.h ipheader.h ipout.h routetable.h
+test_recv.o: devque.h dev.h /usr/include/unistd.h /usr/include/features.h
+test_recv.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_recv.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+test_recv.o: /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h
+test_recv.o: /usr/include/bits/confname.h /usr/include/getopt.h
+test_recv.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+test_recv.o: /usr/include/sys/types.h /usr/include/time.h
+test_recv.o: /usr/include/endian.h /usr/include/bits/endian.h
+test_recv.o: /usr/include/sys/select.h /usr/include/bits/select.h
+test_recv.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+test_recv.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+test_recv.o: /usr/include/bits/sched.h /usr/include/sys/ipc.h
+test_recv.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+test_recv.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+test_resolvproto.o: resolvproto.h ipaddr.h /usr/include/stdint.h
+test_resolvproto.o: /usr/include/features.h /usr/include/sys/cdefs.h
+test_resolvproto.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h
+test_resolvproto.o: /usr/include/bits/wordsize.h ipin.h ipheader.h dev.h
+test_resolvproto.o: ipout.h routetable.h libtcp.h /usr/include/stdio.h
+test_resolvproto.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
+test_resolvproto.o: /usr/include/libio.h /usr/include/_G_config.h
+test_resolvproto.o: /usr/include/wchar.h /usr/include/gconv.h
+test_resolvproto.o: /usr/include/bits/stdio_lim.h
+test_resolvproto.o: /usr/include/bits/sys_errlist.h /usr/include/stdlib.h
+test_resolvproto.o: /usr/include/sys/types.h /usr/include/time.h
+test_resolvproto.o: /usr/include/endian.h /usr/include/bits/endian.h
+test_resolvproto.o: /usr/include/sys/select.h /usr/include/bits/select.h
+test_resolvproto.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+test_resolvproto.o: /usr/include/sys/sysmacros.h
+test_resolvproto.o: /usr/include/bits/pthreadtypes.h
+test_resolvproto.o: /usr/include/bits/sched.h /usr/include/alloca.h
+test_resolvproto.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+test_resolvproto.o: /usr/include/bits/confname.h /usr/include/getopt.h
+test_resolvproto.o: /usr/include/signal.h /usr/include/bits/signum.h
+test_resolvproto.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
+test_resolvproto.o: /usr/include/bits/sigcontext.h
+test_resolvproto.o: /usr/include/asm/sigcontext.h
+test_resolvproto.o: /usr/include/asm-i486/sigcontext.h
+test_resolvproto.o: /usr/include/linux/compiler.h
+test_resolvproto.o: /usr/include/bits/sigstack.h
+test_resolvproto.o: /usr/include/bits/sigthread.h /usr/include/sys/wait.h
+test_resolvproto.o: /usr/include/sys/resource.h /usr/include/bits/resource.h
+test_resolvproto.o: /usr/include/bits/waitflags.h
+test_resolvproto.o: /usr/include/bits/waitstatus.h /usr/include/string.h
+test_resolvproto.o: /usr/include/sys/socket.h /usr/include/sys/uio.h
+test_resolvproto.o: /usr/include/bits/uio.h /usr/include/bits/socket.h
+test_resolvproto.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
+test_resolvproto.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
+test_resolvproto.o: /usr/include/bits/posix2_lim.h
+test_resolvproto.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h
+test_resolvproto.o: /usr/include/asm-i486/socket.h /usr/include/asm/sockios.h
+test_resolvproto.o: /usr/include/asm-i486/sockios.h /usr/include/netinet/in.h
+test_resolvproto.o: /usr/include/bits/in.h /usr/include/bits/byteswap.h
+test_resolvproto.o: /usr/include/arpa/inet.h /usr/include/netdb.h
+test_resolvproto.o: /usr/include/rpc/netdb.h /usr/include/bits/netdb.h
+test_send.o: devque.h dev.h /usr/include/unistd.h /usr/include/features.h
+test_send.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_send.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h
+test_send.o: /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h
+test_send.o: /usr/include/bits/confname.h /usr/include/getopt.h
+test_send.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h
+test_send.o: /usr/include/sys/types.h /usr/include/time.h
+test_send.o: /usr/include/endian.h /usr/include/bits/endian.h
+test_send.o: /usr/include/sys/select.h /usr/include/bits/select.h
+test_send.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+test_send.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+test_send.o: /usr/include/bits/sched.h /usr/include/sys/ipc.h
+test_send.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h
+test_send.o: /usr/include/sys/msg.h /usr/include/bits/msq.h
+libtcp.o: libtcp.h /usr/include/stdio.h /usr/include/features.h
+libtcp.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+libtcp.o: /usr/include/bits/types.h /usr/include/bits/wordsize.h
+libtcp.o: /usr/include/bits/typesizes.h /usr/include/libio.h
+libtcp.o: /usr/include/_G_config.h /usr/include/wchar.h
+libtcp.o: /usr/include/bits/wchar.h /usr/include/gconv.h
+libtcp.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
+libtcp.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h
+libtcp.o: /usr/include/endian.h /usr/include/bits/endian.h
+libtcp.o: /usr/include/sys/select.h /usr/include/bits/select.h
+libtcp.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
+libtcp.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
+libtcp.o: /usr/include/bits/sched.h /usr/include/alloca.h
+libtcp.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+libtcp.o: /usr/include/bits/confname.h /usr/include/getopt.h
+libtcp.o: /usr/include/signal.h /usr/include/bits/signum.h
+libtcp.o: /usr/include/bits/siginfo.h /usr/include/bits/sigaction.h
+libtcp.o: /usr/include/bits/sigcontext.h /usr/include/asm/sigcontext.h
+libtcp.o: /usr/include/asm-i486/sigcontext.h /usr/include/linux/compiler.h
+libtcp.o: /usr/include/bits/sigstack.h /usr/include/bits/sigthread.h
+libtcp.o: /usr/include/sys/wait.h /usr/include/sys/resource.h
+libtcp.o: /usr/include/bits/resource.h /usr/include/bits/waitflags.h
+libtcp.o: /usr/include/bits/waitstatus.h /usr/include/string.h
+libtcp.o: /usr/include/sys/socket.h /usr/include/sys/uio.h
+libtcp.o: /usr/include/bits/uio.h /usr/include/bits/socket.h
+libtcp.o: /usr/include/limits.h /usr/include/bits/posix1_lim.h
+libtcp.o: /usr/include/bits/local_lim.h /usr/include/linux/limits.h
+libtcp.o: /usr/include/bits/posix2_lim.h /usr/include/bits/sockaddr.h
+libtcp.o: /usr/include/asm/socket.h /usr/include/asm-i486/socket.h
+libtcp.o: /usr/include/asm/sockios.h /usr/include/asm-i486/sockios.h
+libtcp.o: /usr/include/netinet/in.h /usr/include/stdint.h
+libtcp.o: /usr/include/bits/in.h /usr/include/bits/byteswap.h
+libtcp.o: /usr/include/arpa/inet.h /usr/include/netdb.h
+libtcp.o: /usr/include/rpc/netdb.h /usr/include/bits/netdb.h
+test_poll.o: libtcp.h /usr/include/stdio.h /usr/include/features.h
+test_poll.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+test_poll.o: /usr/include/bits/types.h /usr/include/bits/wordsize.h
+test_poll.o: /usr/include/bits/typesizes.h /usr/include/libio.h
+test_poll.o: /usr/include/_G_config.h /usr/include/wchar.h
+test_poll.o: /usr/include/bits/wchar.h /usr/include/gconv.h
+test_poll.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
+test_poll.o: /usr/include/stdlib.h /usr/include/sys/types.h
+test_poll.o: /usr/include/time.h /usr/include/endian.h
+test_poll.o: /usr/include/bits/endian.h /usr/include/sys/select.h
+test_poll.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
+test_poll.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
+test_poll.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h
+test_poll.o: /usr/include/alloca.h /usr/include/unistd.h
+test_poll.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h
+test_poll.o: /usr/include/getopt.h /usr/include/signal.h
+test_poll.o: /usr/include/bits/signum.h /usr/include/bits/siginfo.h
+test_poll.o: /usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h
+test_poll.o: /usr/include/asm/sigcontext.h /usr/include/asm-i486/sigcontext.h
+test_poll.o: /usr/include/linux/compiler.h /usr/include/bits/sigstack.h
+test_poll.o: /usr/include/bits/sigthread.h /usr/include/sys/wait.h
+test_poll.o: /usr/include/sys/resource.h /usr/include/bits/resource.h
+test_poll.o: /usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h
+test_poll.o: /usr/include/string.h /usr/include/sys/socket.h
+test_poll.o: /usr/include/sys/uio.h /usr/include/bits/uio.h
+test_poll.o: /usr/include/bits/socket.h /usr/include/limits.h
+test_poll.o: /usr/include/bits/posix1_lim.h /usr/include/bits/local_lim.h
+test_poll.o: /usr/include/linux/limits.h /usr/include/bits/posix2_lim.h
+test_poll.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h
+test_poll.o: /usr/include/asm-i486/socket.h /usr/include/asm/sockios.h
+test_poll.o: /usr/include/asm-i486/sockios.h /usr/include/netinet/in.h
+test_poll.o: /usr/include/stdint.h /usr/include/bits/in.h
+test_poll.o: /usr/include/bits/byteswap.h /usr/include/arpa/inet.h
+test_poll.o: /usr/include/netdb.h /usr/include/rpc/netdb.h
+test_poll.o: /usr/include/bits/netdb.h /usr/include/assert.h
+test_poll.o: /usr/include/sys/poll.h /usr/include/bits/poll.h
--- /dev/null
+#include "dev.h"
+#include <cstring>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+struct Frame
+{
+ Dev::mac_type mac;
+ size_t size;
+ char frame[1];
+};
+
+Dev::Dev(mac_type mac, size_t mtu, key_t key)
+ throw (std::runtime_error, std::logic_error):
+ mac(mac), mtu(mtu)
+{
+ if (mtu > DEV_MAX_MTU)
+ throw std::logic_error("MTU más grande que DEV_MAX_MTU");
+ que_id = msgget(key, 0666); // Debe estar previamente creada
+ if (que_id == -1)
+ throw std::runtime_error("No se pudo crear la cola");
+}
+
+void Dev::transmit(const std::string& data, const mac_type& mac)
+ throw (std::runtime_error, std::logic_error)
+{
+ if (data.size() > mtu)
+ throw std::logic_error("Tamaño de datos mayor al MTU");
+ Frame* f = (Frame*) malloc(sizeof(Frame) + mtu);
+ if (!f)
+ throw std::runtime_error("No se puede reservar memoria");
+ f->mac = mac;
+ f->size = data.size();
+ memcpy(f->frame, data.c_str(), data.size());
+ int res = msgsnd(que_id, f, mtu + sizeof(size_t), 0);
+#ifdef DEBUG
+ //std::cout << "Dev::transmit(msgtype/mac = " << f->mac << ", size = "
+ // << f->size << ")\n";
+#endif
+ free(f);
+ if (res == -1)
+ throw std::runtime_error("Error al poner en la cola");
+}
+
+std::string Dev::receive() throw (std::runtime_error)
+{
+ Frame* f = (Frame*) malloc(sizeof(Frame) + mtu);
+ if (!f)
+ throw std::runtime_error("No se puede reservar memoria");
+ int res = msgrcv(que_id, f, mtu + sizeof(size_t), mac, 0);
+ if (res == -1)
+ {
+ free(f);
+ throw std::runtime_error("Error al sacar de la cola");
+ }
+ std::string s((char*) f->frame, f->size);
+ free(f);
+#ifdef DEBUG
+ //std::cout << "Dev::receive(msgtype/mac = " << mac << ", size = "
+ // << s.size() << ")\n";
+#endif
+ return s;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _DEV_H_
+#define _DEV_H_
+
+#include <stdexcept>
+
+#define DEV_MAX_MTU 1500
+
+/// Dispositivo de red (capa de enlace)
+struct Dev
+{
+
+ /// Tipo de la mac
+ typedef long mac_type;
+
+ /// Dirección MAC
+ mac_type mac;
+
+ /// MTU
+ size_t mtu;
+
+ /// Constructor
+ Dev(mac_type mac, size_t mtu = DEV_MAX_MTU)
+ throw (std::runtime_error, std::logic_error):
+ mac(mac), mtu(mtu)
+ {
+ if (mtu > DEV_MAX_MTU)
+ throw std::logic_error("MTU más grande que DEV_MAX_MTU");
+ }
+
+ /// Envía un frame
+ virtual void transmit(const std::string& data, const mac_type& mac)
+ throw (std::runtime_error, std::logic_error) = 0;
+
+ /// Recibe un frame
+ virtual std::string receive()
+ throw (std::runtime_error) = 0;
+
+ /// Destructor virtual por si las moscas
+ virtual ~Dev() {}
+
+ // Nada de andar copiando placas...
+ private:
+ Dev(const Dev&);
+ Dev& operator=(const Dev&);
+
+};
+
+#endif // _DEV_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#include "devque.h"
+#include <cstring>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+struct Frame
+{
+ Dev::mac_type mac;
+ size_t size;
+ char frame[1];
+};
+
+DevQue::DevQue(mac_type mac, key_t key, size_t mtu)
+ throw (std::runtime_error, std::logic_error):
+ Dev(mac, mtu)
+{
+ que_id = msgget(key, IPC_CREAT | 0666);
+ if (que_id == -1)
+ throw std::runtime_error("No se pudo crear la cola");
+}
+
+void DevQue::transmit(const std::string& data, const mac_type& mac)
+ throw (std::runtime_error, std::logic_error)
+{
+ if (data.size() > mtu)
+ throw std::logic_error("Tamaño de datos mayor al MTU");
+ Frame* f = (Frame*) malloc(sizeof(Frame) + mtu);
+ if (!f)
+ throw std::runtime_error("No se puede reservar memoria");
+ f->mac = mac;
+ f->size = data.size();
+ memcpy(f->frame, data.c_str(), data.size());
+ int res = msgsnd(que_id, f, mtu + sizeof(size_t), 0);
+#ifdef DEBUG2
+ std::cout << "DevQue::transmit(msgtype/mac = " << f->mac << ", size = "
+ << f->size << ")\n";
+#endif
+ free(f);
+ if (res == -1)
+ throw std::runtime_error("Error al poner en la cola");
+}
+
+std::string DevQue::receive() throw (std::runtime_error)
+{
+ return receive(mac);
+}
+
+std::string DevQue::receive(mac_type& mac) throw (std::runtime_error)
+{
+ Frame* f = (Frame*) malloc(sizeof(Frame) + mtu);
+ if (!f)
+ throw std::runtime_error("No se puede reservar memoria");
+ int res = msgrcv(que_id, f, mtu + sizeof(size_t), mac, 0);
+ if (res == -1)
+ {
+ free(f);
+ throw std::runtime_error("Error al sacar de la cola");
+ }
+ std::string s((char*) f->frame, f->size);
+ if (mac == 0)
+ mac = f->mac;
+ free(f);
+#ifdef DEBUG2
+ std::cout << "DevQue::receive(msgtype/mac = " << mac << ", size = "
+ << s.size() << ")\n";
+#endif
+ return s;
+}
+
+/// Indica cuantos elementos hay en la cola
+size_t DevQue::size() const
+{
+ struct msqid_ds minfo;
+ msgctl(que_id, IPC_STAT, &minfo);
+ return minfo.msg_qnum;
+}
+
+/// Indica si está vacía la cola
+bool DevQue::empty() const
+{
+ return size() == 0;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _DEVQUE_H_
+#define _DEVQUE_H_
+
+#include "dev.h"
+
+#define DEVQUE_DEFAULT_KEY 0x1abcdef1
+
+/// Dispositivo de red (capa de enlace) implementado con una cola
+struct DevQue: Dev
+{
+
+ /// Identificador de la cola a usar
+ int que_id;
+
+ /// Constructor
+ DevQue(mac_type mac, key_t key = DEVQUE_DEFAULT_KEY,
+ size_t mtu = DEV_MAX_MTU)
+ throw (std::runtime_error, std::logic_error);
+
+ /// Envía un frame
+ void transmit(const std::string& data, const mac_type& mac)
+ throw (std::runtime_error, std::logic_error);
+
+ /// Recibe un frame
+ std::string receive()
+ throw (std::runtime_error);
+
+ /// Recibe un frame para el tipo de mac especificado, si es 0 recibe
+ /// cualquier y guarda en esa mac la dirección.
+ std::string receive(mac_type& mac)
+ throw (std::runtime_error);
+
+ /// Indica cuantos elementos hay en la cola
+ size_t size() const;
+
+ /// Indica si está vacía la cola
+ bool empty() const;
+
+};
+
+#endif // _DEVQUE_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#include "devtcp.h"
+#include "ipaddr.h"
+#include "libtcp.h"
+#include <cstring>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/poll.h>
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+#define ISSET(var, flag) ((var & flag) == flag)
+
+DevTCP::DevTCP(mac_type mac, uint16_t port, size_t mtu)
+ throw (std::runtime_error, std::logic_error):
+ Dev(mac, mtu), port(port), pfds_size(1)
+{
+ if ((pfds[0].fd = libtcp_open_pasivo(port)) == -1)
+ throw std::runtime_error("No se pudo crear el socket que escucha");
+ pfds[0].events = POLLIN | POLLPRI;
+}
+
+void DevTCP::transmit(const std::string& data, const mac_type& mac)
+ throw (std::runtime_error, std::logic_error)
+{
+ if (data.size() > mtu)
+ throw std::logic_error("Tamaño de datos mayor al MTU");
+ if (tx_pool.find(mac) == tx_pool.end()) // No existe la conexión
+ {
+ std::string addr = IPAddr(mac);
+#ifdef DEBUG2
+ std::cout << "DevTCP::transmit: conectando a " << addr << ":" << port << "\n";
+#endif
+ tx_pool[mac] = libtcp_open_activo(addr.c_str(), port);
+ if (tx_pool[mac] == -1)
+ throw std::runtime_error("Error al conectar el socket");
+ }
+ size_t size = data.size();
+ if (libtcp_send(tx_pool[mac], &size, sizeof(size_t)) != sizeof(size_t))
+ throw std::runtime_error("Error al enviar por el socket");
+ if ((unsigned)libtcp_send(tx_pool[mac], data.c_str(), data.size()) != data.size())
+ throw std::runtime_error("Error al enviar por el socket");
+#ifdef DEBUG2
+ std::cout << "DevTCP::transmit(mac = " << mac << ", size = "
+ << data.size() << ")\n";
+#endif
+}
+
+std::string DevTCP::receive() throw (std::runtime_error)
+{
+ // Nos fijamos en todos los file descriptors si hay algo para nosotros.
+ while (true)
+ {
+ int res = poll(pfds, pfds_size, 5000);
+ if (res == -1)
+ throw std::runtime_error("Error al hacer poll");
+ if (!res)
+ continue;
+ // Si tengo conexiones esperando, las atiendo...
+ if (ISSET(pfds[0].revents, POLLIN)
+ || ISSET(pfds[0].revents, POLLPRI))
+ {
+ if (pfds_size == DEVTCP_MAX_CONN)
+ throw std::runtime_error("Demasiadas conexiones activas");
+ pfds[pfds_size].fd = accept(pfds[0].fd, NULL, NULL);
+ if (pfds[pfds_size].fd == -1)
+ throw std::runtime_error("Error al hacer accept");
+ pfds[pfds_size].events = POLLIN | POLLPRI;
+ ++pfds_size;
+ }
+ // Luego me fijo si tengo algún otro socket con cosas para recibir
+ for (size_t i = 1; i < pfds_size; ++i)
+ {
+ if (ISSET(pfds[i].revents, POLLIN)
+ || ISSET(pfds[i].revents, POLLPRI))
+ {
+ size_t size;
+ int r = libtcp_receive_bin(pfds[i].fd, &size, sizeof(size_t));
+ if (r != sizeof(size_t))
+ // TODO cerrar socket?
+ continue;
+ char* buf = (char*)malloc(size);
+ r = libtcp_receive_bin(pfds[i].fd, buf, size);
+ if ((unsigned)r != size)
+ // TODO cerrar socket?
+ continue;
+ std::string ret(buf, size);
+ free(buf);
+#ifdef DEBUG2
+ std::cout << "DevTCP::receive(msgtype/mac = " << mac << ", size = "
+ << ret.size() << ")\n";
+#endif
+ return ret;
+ }
+ }
+ }
+ return ""; // No deberíamos caer nunca acá.
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _DEVTCP_H_
+#define _DEVTCP_H_
+
+#include "dev.h"
+#include <map>
+#include <stdint.h>
+#include <sys/poll.h>
+
+#define DEVTCP_DEFAULT_PORT 65000
+#define DEVTCP_MAX_CONN 16
+
+/// Dispositivo de red (capa de enlace) implementado con TCP
+struct DevTCP: Dev
+{
+
+ /// Puerto en el cual escucha por conexiones
+ uint16_t port;
+
+ /// Información para poll sobre los fds
+ pollfd pfds[DEVTCP_MAX_CONN];
+ size_t pfds_size;
+
+ /// Mapa con el fd que corresponde a la conexión saliente con cada host
+ std::map< mac_type, int > tx_pool;
+
+ /// Constructor
+ DevTCP(mac_type mac, uint16_t port = DEVTCP_DEFAULT_PORT,
+ size_t mtu = DEV_MAX_MTU)
+ throw (std::runtime_error, std::logic_error);
+
+ /// Envía un frame
+ void transmit(const std::string& data, const mac_type& mac)
+ throw (std::runtime_error, std::logic_error);
+
+ /// Recibe un frame
+ std::string receive()
+ throw (std::runtime_error);
+
+};
+
+#endif // _DEVTCP_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "ipout.h"
+#include "ipin.h"
+#include "ipaddr.h"
+#include "routetable.h"
+#include "devtcp.h"
+#include "devque.h"
+#include "nameserver.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <signal.h>
+
+// Uso: ./dns ip [routes_file zones_file forward port]
+
+void send_loop(NameServer& ns);
+
+void add_routes(RouteTable& rt, std::istream& is, Dev& dev);
+
+int main(int argc, char* argv[])
+{
+ uint16_t port = DEVTCP_DEFAULT_PORT;
+ std::string rfile = "route.txt";
+ std::string zfile = "zones.txt";
+ if (argc < 2)
+ {
+ std::cerr << "Uso: " << argv[0] << " ip [route_file zone_file port]\n";
+ return 1;
+ }
+ IPAddr addr(argv[1]);
+ if (argc > 2)
+ rfile = argv[2];
+ if (argc > 3)
+ zfile = argv[3];
+ if (argc > 4)
+ port = atoi(argv[4]);
+ // Abro archivo con rutas
+ std::ifstream rifs(rfile.c_str()); assert(rifs);
+ // Abro archivo con zonas
+ std::ifstream zifs(zfile.c_str()); assert(zifs);
+ // Creo medio físico y colas para forwarding y NameServer
+ DevTCP dev(addr, port);
+ DevQue fwque(addr, DEVQUE_DEFAULT_KEY-1);
+ DevQue nsreqque(addr, DEVQUE_DEFAULT_KEY-2);
+ DevQue nsresque(addr, DEVQUE_DEFAULT_KEY-3);
+ DevQue nssndque(addr, DEVQUE_DEFAULT_KEY-4);
+ // Creo Rutas, IPOut, IPIn
+ RouteTable table(dev);
+ add_routes(table, rifs, dev);
+ IPOut ipout(addr, table, fwque, std::cerr);
+ IPIn ipin(addr, dev, fwque, false, false, std::cerr);
+ NameServer ns(zifs, ipin, ipout, nsreqque, nsresque, nssndque);
+ // Creo procesos
+ pid_t pid_send = fork();
+ if (pid_send == -1)
+ {
+ perror("fork() send");
+ return 2;
+ }
+ if (pid_send) // IPOut
+ {
+ pid_t pid_fw = fork();
+ if (pid_fw == -1)
+ {
+ perror("fork() forward");
+ return 3;
+ }
+ if (pid_fw) // Padre (Entrada por teclado)
+ {
+ int ret;
+ send_loop(ns);
+ kill(pid_send, SIGTERM);
+ waitpid(pid_send, &ret, 0);
+ kill(pid_fw, SIGTERM);
+ waitpid(pid_fw, &ret, 0);
+ return 0;
+ }
+ else // Hijo 1 (envío del DNS)
+ {
+ ns.send_loop();
+ return 0;
+ }
+ }
+ else // Hijo 2 (recepción del DNS)
+ {
+ ns.recv_loop();
+ return 0;
+ }
+ return 0;
+}
+
+void send_loop(NameServer& ns)
+{
+ std::string name;
+ while (std::getline(std::cin, name))
+ {
+ std::cout << "Resolviendo " << name << "...\n";
+ ResolvProtoResponse res = ns.resolv_recursive(name);
+ std::cout << "Resultado: " << res << "\n";
+ }
+}
+
+void add_routes(RouteTable& rt, std::istream& is, Dev& dev)
+{
+ std::string line;
+ while (std::getline(is, line))
+ {
+ std::istringstream iss(line);
+ std::string net;
+ std::string gw;
+ unsigned mtu;
+ unsigned metric;
+ iss >> net >> gw >> mtu >> metric;
+ if (net == "0") net = "0.0.0.0";
+ if (gw == "0") gw = "0.0.0.0";
+ rt.add(net, gw, metric, mtu, dev);
+ }
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "ipout.h"
+#include "ipin.h"
+#include "ipaddr.h"
+#include "routetable.h"
+#include "devtcp.h"
+#include "devque.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <signal.h>
+
+// Uso: ./ip ip [router forward routes_file port proto]
+
+void send_loop(IPOut& ipout, unsigned proto);
+
+void add_routes(RouteTable& rt, std::istream& is, Dev& dev);
+
+int main(int argc, char* argv[])
+{
+ bool router = false;
+ bool forward = false;
+ uint8_t proto = 0;
+ uint16_t port = DEVTCP_DEFAULT_PORT;
+ std::string fname = "route.txt";
+ if (argc < 2)
+ {
+ std::cerr << "Uso: " << argv[0] << " ip [router forward routes_file "
+ "port proto]\n";
+ return 1;
+ }
+ IPAddr addr(argv[1]);
+ if (argc > 2)
+ router = atoi(argv[2]);
+ if (argc > 3)
+ forward = atoi(argv[3]);
+ if (argc > 4)
+ fname = argv[4];
+ if (argc > 5)
+ port = atoi(argv[5]);
+ if (argc > 6)
+ proto = atoi(argv[6]);
+ // Creo cola para comunicar el IPIn con IPOut
+ int que_id = msgget(DEVQUE_DEFAULT_KEY-1, IPC_CREAT | 0666); assert(que_id != -1);
+ // Abro archivo con rutas
+ std::ifstream ifs(fname.c_str()); assert(ifs);
+ // Creo medio físico y cola para forwarding
+ DevTCP dev(addr, port);
+ DevQue fwque(addr, DEVQUE_DEFAULT_KEY-1);
+ // Creo procesos
+ pid_t pid_send = fork();
+ if (pid_send == -1)
+ {
+ perror("fork() send");
+ return 2;
+ }
+ if (pid_send) // IPOut
+ {
+ RouteTable table(dev);
+ add_routes(table, ifs, dev);
+ IPOut ipout(addr, table, fwque, std::cerr);
+ pid_t pid_fw = fork();
+ if (pid_fw == -1)
+ {
+ perror("fork() forward");
+ return 3;
+ }
+ if (pid_fw) // Padre (IPOut send)
+ {
+ int ret;
+ send_loop(ipout, proto);
+ kill(pid_send, SIGTERM);
+ waitpid(pid_send, &ret, 0);
+ kill(pid_fw, SIGTERM);
+ waitpid(pid_fw, &ret, 0);
+ return 0;
+ }
+ else // Hijo 1 (IPOut forward)
+ {
+ ipout.forward_loop();
+ return 0;
+ }
+ }
+ else // Hijo 2 (IPIn)
+ {
+ IPIn ipin(addr, dev, fwque, router, forward, std::cerr);
+ while (true)
+ {
+ IPAddr src, dst;
+ std::string s = ipin.recv(proto, src, dst);
+ std::cout << "Recibido '" << s << "' (len " << s.size() << ") de "
+ << src << " para " << dst << " (proto = " << unsigned(proto)
+ << ")\n";
+ }
+ return 0;
+ }
+ return 0;
+}
+
+void send_loop(IPOut& ipout, unsigned proto)
+{
+ std::string dst;
+ std::string msg;
+ while (std::getline(std::cin, dst))
+ {
+ if (!std::getline(std::cin, msg))
+ break;
+ if (ipout.send(msg, proto, IPAddr(dst.c_str())))
+ std::cout << "Enviado '" << msg << "' a " << dst << "\n";
+ else
+ std::cout << "NO SE PUDO ENVIAR '" << msg << "' a " << dst << "\n";
+ }
+}
+
+void add_routes(RouteTable& rt, std::istream& is, Dev& dev)
+{
+ std::string line;
+ while (std::getline(is, line))
+ {
+ std::istringstream iss(line);
+ std::string net;
+ std::string gw;
+ unsigned mtu;
+ unsigned metric;
+ iss >> net >> gw >> mtu >> metric;
+ if (net == "0") net = "0.0.0.0";
+ if (gw == "0") gw = "0.0.0.0";
+ rt.add(net, gw, metric, mtu, dev);
+ }
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "ipaddr.h"
+#include <sstream>
+
+/// Constructor
+IPAddr::IPAddr()
+{
+ atoms[0] = 0;
+ atoms[1] = 0;
+ atoms[2] = 0;
+ atoms[3] = 0;
+}
+
+/// Constructor
+IPAddr::IPAddr(atom a1, atom a2, atom a3, atom a4)
+{
+ atoms[0] = a1;
+ atoms[1] = a2;
+ atoms[2] = a3;
+ atoms[3] = a4;
+}
+
+/// Constructor
+IPAddr::IPAddr(uint32_t ip)
+{
+ atoms[0] = ip >> 24;
+ atoms[1] = ip >> 16;
+ atoms[2] = ip >> 8;
+ atoms[3] = ip;
+}
+
+#if 0
+/// Constructor
+IPAddr::IPAddr(const char* ip) throw (std::logic_error)
+{
+ std::istringstream iss(ip);
+ std::string ips;
+ for (int i = 0; i < 4; ++i)
+ {
+ if (!std::getline(iss, ips, '.'))
+ throw std::logic_error("Dirección IP inválida");
+ atoms[i] = std::atoi(ips.c_str());
+ }
+}
+#endif
+
+/// Constructor
+IPAddr::IPAddr(const std::string& ip) throw (std::logic_error)
+{
+ std::istringstream iss(ip);
+ std::string ips;
+ for (int i = 0; i < 4; ++i)
+ {
+ if (!std::getline(iss, ips, '.'))
+ throw std::logic_error("Dirección IP inválida");
+ atoms[i] = std::atoi(ips.c_str());
+ }
+}
+
+/// Operador de casteo a unsigned
+IPAddr::operator uint32_t () const
+{
+ return (atoms[0] << 24) + (atoms[1] << 16) + (atoms[2] << 8) + atoms[3];
+}
+
+/// Operador de casteo a std::string
+IPAddr::operator std::string () const
+{
+ std::ostringstream oss;
+ oss << unsigned(atoms[0]) << "." << unsigned(atoms[1]) << "."
+ << unsigned(atoms[2]) << "." << unsigned(atoms[3]);
+ return oss.str();
+}
+
+std::ostream& operator<< (std::ostream& os, const IPAddr& ip)
+{
+ return os << std::string(ip);
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _IPADDR_H_
+#define _IPADDR_H_
+
+#include <string>
+#include <cstdlib>
+#include <stdexcept>
+#include <stdint.h>
+
+/// Dirección IP
+struct IPAddr
+{
+
+ /// Átomo de dirección IP
+ typedef uint8_t atom;
+
+ /// Representación interna
+ atom atoms[4];
+
+ /// Constructor
+ IPAddr();
+
+ /// Constructor
+ IPAddr(atom a1, atom a2, atom a3, atom a4);
+
+ /// Constructor
+ IPAddr(uint32_t ip);
+
+ /// Constructor
+ //IPAddr(const char* ip) throw (std::logic_error);
+
+ /// Constructor
+ IPAddr(const std::string& ip) throw (std::logic_error);
+
+ /// Operador de casteo a unsigned
+ operator uint32_t () const;
+
+ /// Operador de casteo a std::string
+ operator std::string () const;
+
+};
+
+std::ostream& operator<< (std::ostream& os, const IPAddr& ip);
+
+#endif // _IPADDR_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#include "ipheader.h"
+
+IPHeader::IPHeader(uint8_t version, uint16_t total_len, uint16_t id, bool df,
+ bool mf, uint16_t offset, uint8_t ttl, uint8_t proto,
+ const IPAddr& src, const IPAddr& dst):
+ version(version), total_len(total_len), id(id), reserved_flag(0),
+ df(df), mf(mf), offset(offset), ttl(ttl), proto(proto), checksum(0),
+ src(src), dst(dst)
+{
+ do_checksum();
+}
+
+IPHeader::IPHeader(const std::string& s)
+{
+ *this = *((IPHeader*)s.c_str());
+}
+
+size_t IPHeader::header_len()
+{
+ return sizeof(IPHeader);
+}
+
+bool IPHeader::check_checksum() const
+{
+ IPHeader iph = *this;
+ iph.checksum = 0;
+ char* raw = (char*) &iph;
+ uint16_t sum = 0;
+ for (unsigned i = 0; i < sizeof(IPHeader); ++i)
+ sum += raw[i];
+ return sum == checksum;
+}
+
+void IPHeader::do_checksum()
+{
+ checksum = 0;
+ char* raw = (char*) this;
+ uint16_t sum = 0;
+ for (unsigned i = 0; i < sizeof(IPHeader); ++i)
+ sum += raw[i];
+ checksum = sum;
+}
+
+std::ostream& operator<<(std::ostream& os, const IPHeader& iph)
+{
+ return os
+ << "version=" << unsigned(iph.version)
+ << " total_len=" << iph.total_len
+ << " id=" << iph.id
+ << " DF=" << bool(iph.df)
+ << " MF=" << bool(iph.mf)
+ << " offset=" << unsigned(iph.offset)
+ << " TTL=" << unsigned(iph.ttl)
+ << " proto=" << unsigned(iph.proto)
+ << " checksum=" << iph.checksum
+ << " src=" << IPAddr(iph.src)
+ << " dst=" << IPAddr(iph.dst);
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _IPHEADER_H_
+#define _IPHEADER_H_
+
+#include "ipaddr.h"
+#include <string>
+#include <ostream>
+#include <stdint.h>
+
+/// Dispositivo de red (capa de enlace)
+struct IPHeader
+{
+
+ // Campos
+ uint8_t version;
+ //TODO IHL
+ //TODO TOS
+ uint16_t total_len;
+ uint16_t id;
+ uint16_t reserved_flag: 1;
+ uint16_t df: 1;
+ uint16_t mf: 1;
+ uint16_t offset: 13;
+ uint8_t ttl;
+ uint8_t proto;
+ uint16_t checksum;
+ uint32_t src;
+ uint32_t dst;
+
+ IPHeader(uint8_t version, uint16_t total_len, uint16_t id, bool df,
+ bool mf, uint16_t offset, uint8_t ttl, uint8_t proto,
+ const IPAddr& src, const IPAddr& dst);
+
+ IPHeader(const std::string& s);
+
+ static size_t header_len();
+
+ bool check_checksum() const;
+
+ void do_checksum();
+
+};
+
+std::ostream& operator<<(std::ostream& os, const IPHeader& iph);
+
+#endif // _IPHEADER_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "ipin.h"
+#include "ipheader.h"
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+/// Constructor
+IPIn::IPIn(const IPAddr& ip, Dev& dev, Dev& forward_que, bool router,
+ bool forward, std::ostream& log):
+ ip(ip), dev(dev), forward_que(forward_que), router(router),
+ forward(forward), log(log)
+{
+ if (router) forward = true;
+}
+
+void IPIn::drop(const std::string& msg, const std::string& buf)
+{
+ log << "IPIn::drop (" << ip << "): " << msg << "\n\tBuffer: " << buf
+ << "\n";
+}
+
+void IPIn::drop(const std::string& msg, const IPHeader& iph)
+{
+ log << "IPIn::drop (" << ip << "): " << msg << "\n\tIPHeader: " << iph
+ << "\n";
+}
+
+/// Recibe un paquete IP
+std::string IPIn::recv(uint8_t& proto, IPAddr& src, IPAddr& dst)
+ throw (std::runtime_error)
+{
+ while (true)
+ {
+ std::string buf = dev.receive();
+ // No es siquiera IP
+ if (buf.size() < IPHeader::header_len())
+ {
+ // Silencioso
+ drop("Cabecera incompleta o no es IP", buf);
+ continue;
+ }
+ IPHeader iph(buf);
+#ifdef DEBUG
+ std::cout << "IPIn::recv (" << ip << "): IPHeader: " << iph << "\n";
+ std::string tmp = buf.substr(iph.header_len());
+ std::cout << "\tdata (" << tmp.size() << ") = " << tmp << "\n";
+#endif
+ if (iph.version != 4)
+ {
+ // Silencioso
+ drop("Versión IP incorrecta", iph);
+ continue;
+ }
+ if (!iph.check_checksum())
+ {
+ // Silencioso
+ drop("Mal checksum", iph);
+ continue;
+ }
+ // Si el TTL se va a 0
+ if (!--iph.ttl)
+ {
+ // ICMP
+ drop("TTL == 0 -> ICMP", iph);
+ continue;
+ }
+ // No es para nosotros y no forwardeamos
+ if (iph.dst != ip && !forward)
+ {
+ // Silencioso
+ drop("No es para nosotros y no hacemos forward", iph);
+ continue;
+ }
+ // No es para nosotros pero forwardeamos
+ else if (iph.dst != ip)
+ {
+ forward_que.transmit(buf, ip);
+ continue;
+ }
+ // Es para nosotros pero somos router
+ else if (router)
+ {
+ // Silencioso
+ drop("Es para nosotros pero somos un router", iph);
+ continue;
+ }
+ // Es para nosotros y somos un host
+ // Guarda en buffer
+ buffer[iph][iph.offset] = buf.substr(iph.header_len());
+ // Si tiene más fragmentos, sigo
+ if (iph.mf)
+ continue;
+ // No hay más fragmentos, reensamblamos (de ser necesario)
+ std::string data;
+ for (offsetmap_type::iterator i = buffer[iph].begin();
+ i != buffer[iph].end(); ++i)
+ {
+ //TODO chequear que los fragmentos estén todos
+ data += i->second;
+ }
+#ifdef DEBUG
+ std::cout << "IPIn::recv (" << ip << "): Paquete completo: data = '"
+ << data << "'\n";
+#endif
+ buffer.erase(iph);
+ //TODO faltaría limpiar fragmentos viejos cada tanto (timer?)
+ src = iph.src;
+ dst = iph.dst;
+ proto = iph.proto;
+ return data;
+ }
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _IPIN_H_
+#define _IPIN_H_
+
+#include "ipaddr.h"
+#include "ipheader.h"
+#include "dev.h"
+#include <map>
+#include <string>
+#include <iostream>
+#include <stdexcept>
+
+/// IP de recepción
+struct IPIn
+{
+
+ /// Dirección IP
+ IPAddr ip;
+
+ /// Dispositivo de red
+ Dev& dev;
+
+ /// Cola para forwardear paquetes
+ Dev& forward_que;
+
+ /// Indica si es un router
+ bool router;
+
+ /// Indica si hace forwarding
+ bool forward;
+
+ /// Dispositivo de logging
+ std::ostream& log;
+
+ /// Buffers de recepción
+ struct BufferKey
+ {
+ uint16_t id;
+ uint32_t src, dst;
+ uint8_t proto;
+ BufferKey(const IPHeader& h):
+ id(h.id), src(h.src), dst(h.dst), proto(h.proto)
+ {}
+ bool operator< (const BufferKey& b) const
+ { return id < b.id && src < b.src && dst < b.dst && proto < b.proto; }
+ };
+ typedef std::map< uint16_t, std::string > offsetmap_type;
+ typedef std::map< BufferKey, offsetmap_type > buffer_type;
+ buffer_type buffer;
+
+ /// Constructor
+ IPIn(const IPAddr& ip, Dev& dev, Dev& forward_que, bool router = false,
+ bool forward = false, std::ostream& log = std::cout);
+
+ /// Descarta un paquete
+ void drop(const std::string& msg, const std::string& buf);
+ void drop(const std::string& msg, const IPHeader& iph);
+
+ /// Recibe un paquete IP
+ std::string recv(uint8_t& proto, IPAddr& src, IPAddr& dst)
+ throw (std::runtime_error);
+
+ // Nada de andar copiando placas...
+ private:
+ IPIn(const IPIn&);
+ IPIn& operator=(const IPIn&);
+
+};
+
+#endif // _IPIN_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "ipout.h"
+#include "ipheader.h"
+#include <ctime>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+/// Constructor
+IPOut::IPOut(const IPAddr& ip, RouteTable& rtable, Dev& forward_que, std::ostream& log):
+ ip(ip), rtable(rtable), forward_que(forward_que), log(log)
+{
+}
+
+void IPOut::drop(const std::string& msg, const std::string& buf)
+{
+ log << "IPOut::drop (" << ip << "): " << msg << "\n\tBuffer: " << buf
+ << "\n";
+}
+
+void IPOut::drop(const std::string& msg, const IPHeader& iph)
+{
+ log << "IPOut::drop (" << ip << "): " << msg << "\n\tIPHeader: " << iph
+ << "\n";
+}
+
+/// Envía un paquete IP
+bool IPOut::send(const std::string& data, uint8_t proto, IPAddr dst, IPAddr src,
+ bool df, uint8_t ttl, uint16_t id)
+ throw (std::runtime_error)
+{
+ // Armamos cabecera
+ if (!src)
+ src = ip;
+ if (!id)
+ id = get_id();
+ IPHeader iph(4, IPHeader::header_len() + data.size(), id, df, 0, 0,
+ ttl, proto, src, dst);
+ // Enviamos
+ return send(iph, data);
+}
+
+/// Envía un paquete IP
+bool IPOut::send(IPHeader iph, std::string data) throw (std::runtime_error)
+{
+ // Buscamos ruta
+ RouteTable::Route* r = rtable.get(iph.dst);
+ if (!r)
+ {
+ // ICMP
+ drop("No existe una ruta para el destino -> ICMP", iph);
+ return false;
+ }
+ // No quieren fragmentar
+ if (iph.df && (IPHeader::header_len() + data.size() > r->mtu))
+ {
+ // Silencioso
+ drop("Tamaño de paquete más grande que MTU y DF=1", iph);
+ return false;
+ }
+ // Fragmenta (de ser necesario)
+ int max_payload = r->mtu - IPHeader::header_len();
+ int cant_frag = data.size() / max_payload;
+ if (data.size() % max_payload)
+ ++cant_frag;
+ for (int i = 0; i < cant_frag; ++i)
+ {
+ IPHeader iph2 = iph;
+ if (i != (cant_frag - 1))
+ iph2.mf = 1;
+ iph2.offset += i * max_payload;
+ iph2.total_len -= i * max_payload;
+ iph2.do_checksum();
+ std::string buf((char*) &iph2, sizeof(IPHeader));
+ buf += data.substr(i * max_payload, max_payload);
+#ifdef DEBUG
+ std::cout << "IPOut::send (" << ip << "): Fragmento " << i
+ << " => IPHeader: " << iph2 << "\n";
+ std::string tmp = data.substr(i * max_payload, max_payload);
+ std::cout << "\tdata (" << tmp.size() << ") = " << tmp << "\n";
+#endif
+ r->iface->transmit(buf, r->gateway ? r->gateway : IPAddr(iph.dst));
+ }
+ return true;
+}
+
+/// Realiza el forwarding de paquetes (en un loop infinito)
+void IPOut::forward_loop()
+ throw (std::runtime_error)
+{
+ while (true)
+ {
+ std::string buf = forward_que.receive();
+ IPHeader iph(buf);
+#ifdef DEBUG
+ std::cout << "IPOut::forward_loop (" << ip << "): A forwardear (id "
+ << iph.id << ", offset " << iph.offset << ")\n";
+#endif
+ send(iph, buf.substr(iph.header_len()));
+ }
+}
+
+/// Obtiene un identificador para el paquete
+uint16_t IPOut::get_id() const
+{
+ static uint16_t st = time(NULL);
+ uint16_t tt = time(NULL);
+ return (tt == st) ? ++st : tt;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _IPOUT_H_
+#define _IPOUT_H_
+
+#include "ipaddr.h"
+#include "ipheader.h"
+#include "routetable.h"
+#include <iostream>
+#include <string>
+#include <stdexcept>
+
+/// IP de envío
+struct IPOut
+{
+
+ /// Dirección MAC
+ IPAddr ip;
+
+ /// Dispositivo de logging
+ RouteTable& rtable;
+
+ /// Cola para forwardear paquetes
+ Dev& forward_que;
+
+ /// Dispositivo de logging
+ std::ostream& log;
+
+ /// Constructor
+ IPOut(const IPAddr& ip, RouteTable& rtable, Dev& forward_que,
+ std::ostream& log = std::cout);
+
+ /// Descarta un paquete
+ void drop(const std::string& msg, const std::string& buf);
+ void drop(const std::string& msg, const IPHeader& iph);
+
+ /// Envía un paquete IP a armar (y forwardea los encolados, de haber)
+ bool send(const std::string& data, uint8_t proto, IPAddr dst,
+ IPAddr src = 0, bool df = 0, uint8_t ttl = 64, uint16_t id = 0)
+ throw (std::runtime_error);
+
+ /// Envía un paquete IP ya armado
+ bool send(IPHeader iph, std::string data) throw (std::runtime_error);
+
+ /// Realiza el forwarding de paquetes (en un loop infinito)
+ void forward_loop() throw (std::runtime_error);
+
+ /// Obtiene un identificador para el paquete
+ uint16_t get_id() const;
+
+ /// Se fija si hay paquetes a forwardear (y devuelve cuantos hay)
+ unsigned to_forward();
+
+ // Nada de andar copiando...
+ private:
+ IPOut(const IPOut&);
+ IPOut& operator=(const IPOut&);
+
+};
+
+#endif // _IPOUT_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+/* LibTcp - Released underOpen Software License v. 2.0
+ *
+ * This Open Software License (the "License") applies to any original work of authorship
+ * (the "Original Work") whose owner (the "Licensor") has placed the following notice
+ * immediately following the copyright notice for the Original Work:
+ *
+ * Licensed under the Open Software License version 2.0
+ *
+ * See http://www.opensource.org/licenses/osl-2.0.php or the LICENSE file for more
+ * details.
+ */
+
+#include "libtcp.h"
+
+/** Abre un socket en modo activo para establecer una conexión con un servidor.
+ *
+ * Esta función es utilizada por los clientes para establecer una conexión TCP
+ * con un servidor.
+ *
+ * \param servidor Nombre del host server
+ * \param port Número del puerto
+ * \return >0 El descriptor del socket, si se conecto al servidor.
+ * \return -2 Si no existe el nombre del servidor.
+ * \return -1 Si hubo error en la conexion y se debe consultar errno.
+ */
+int libtcp_open_activo (const char *server, int port)
+{
+ int sockfd; /* socket de la conexion */
+ struct sockaddr_in serv_addr;
+ struct hostent *ptr_server; /*puntero a dir del server(gethostbyname)*/
+
+ /* Borrar la estructura (poner en cero) */
+ bzero ((char *) &serv_addr, sizeof(serv_addr));
+
+ /* Inicializo familia de direcciones (protocolo IP) */
+ serv_addr.sin_family = AF_INET;
+
+ /* Cargar port en el socket: Convertir Host-TO-Network-Short integer */
+ serv_addr.sin_port = htons (port);
+
+ /* Cargo dirección del server en el socket. Convertir nombre del host en su direccion */
+ ptr_server = gethostbyname (server);
+ if (ptr_server == NULL) {
+ /* No existe nombre de host. Posible falla en resolución de nombre */
+ return -2;
+ }
+ memcpy (&serv_addr.sin_addr, ptr_server->h_addr, ptr_server->h_length);
+
+ /* Abro como un socket de TCP (Internet stream socket) */
+ if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+ /* Error en la creacion del socket */
+ return -1;
+ }
+
+ if (connect (sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
+ /* TODO : Deberia ser un codigo de error diferente, asi puedo diferenciarlos */
+ return -1;
+ }
+
+ return sockfd;
+}
+
+/** Abre un socket en modo pasivo usando protocolo TCP.
+ *
+ * La función se encarga de inicializar y crear el socket, y
+ * luego enlazarla con el SO.
+ *
+ * \param port Puerto sobre el cual atiende este servidor
+ * \return >0 El socket, si la operacion fue exitosa
+ * \return <0 Si hubo un error (ver errno)
+ */
+int libtcp_open_pasivo (int port)
+{
+ char mostrar[80]; /* mensajes en la pantalla */
+ int sockfd; /* socket que sirve como template */
+ struct sockaddr_in serv_addr;
+
+ bzero ((char *)&serv_addr, sizeof (serv_addr));
+ serv_addr.sin_family = AF_INET; /* Familia protocolos TCP/IP */
+ serv_addr.sin_addr.s_addr = htonl (INADDR_ANY); /* Cualquier cliente */
+ serv_addr.sin_port = htons ((unsigned short)port); /* Port en formato red */
+
+ /* Crea un socket para TCP (un Internet stream socket) */
+ if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
+ return -1;
+ }
+
+ // Reusamos address
+ int yes = 1;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &yes,
+ sizeof(yes)) < 0)
+ {
+ perror ("setsockopt");
+ close (sockfd);
+ return -1;
+ }
+
+#ifdef DEBUG2
+ sprintf (mostrar, "LibTcp::ServerPasivo: socket creado %d\n", sockfd);
+ write (fileno(stdout), mostrar, strlen (mostrar));
+#endif
+
+ /* Vincular el socket con la direccion local */
+ if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) {
+ return -1;
+ }
+
+#ifdef DEBUG2
+ sprintf (mostrar, "LibTcp::Server: se hizo el bind\n");
+ write(fileno(stdout), mostrar, strlen(mostrar));
+#endif
+
+ /* Definir la cola de espera = hasta 5 clientes */
+ listen(sockfd, 5);
+
+#ifdef DEBUG2
+ sprintf (mostrar, "LibTcp::Server: se hizo el listen con el socket %d\n", sockfd);
+ write(fileno(stdout), mostrar, strlen(mostrar));
+#endif
+
+ return sockfd;
+}
+
+/** Lee de a un byte por vez a un buffer hasta encontrar un "\n".
+ *
+ * La cadena leída es terminada en "\0".
+ *
+ * \return El tamaño, en caracteres, de la cadena leida.
+ * \param fd Descriptor del socket
+ * \param ptr Puntero al buffer
+ * \param maxlong Tamaño del buffer (en bytes)
+ * \TODO Soporte de caracteres multibyte
+ */
+int libtcp_receive (int fd, char *ptr, unsigned int maxlong)
+{
+ unsigned n;
+ int car;
+ char c;
+
+ for (n = 0; n < maxlong; n++) {
+ if ((car = read (fd, &c, sizeof (char))) == 1) {
+ *ptr++ = c;
+ if (c == '\n')
+ break;
+ } else if (car == 0) {
+ if (n == 1)
+ /* EOF, sin datos leidos */
+ return 0;
+ else
+ break; /* EOF, se leyo algo */
+ } else
+ return -1;
+ }
+
+ *ptr = '\0';
+ return n;
+}
+
+/** Lee una informacion binaria */
+int libtcp_receive_bin (int fd, void *ptr, unsigned int n)
+{
+ int nfaltan, nrecibidos;
+ char *p = (char*) ptr;
+
+ nfaltan = n;
+ while (nfaltan > 0) {
+ nrecibidos = read (fd, p, nfaltan);
+ if (nrecibidos <= 0)
+ return nrecibidos;
+
+ nfaltan -= nrecibidos;
+ p += nrecibidos;
+ }
+
+ return n - nfaltan;
+}
+
+
+/** Escribe n bytes sobre un descriptor.
+ *
+ * Si no se escribieron n bytes, trata de repetir hasta que se hayan escrito
+ * los n bytes.
+ *
+ * Se debe usar esta funcion cuando el descriptor en un stream socket.
+ *
+ * \param fd Descriptor del socket
+ * \param ptr Puntero al mensaje
+ * \param n cantidad de bytes
+ */
+int libtcp_send (int fd, const void *ptr, unsigned int n)
+{
+ int nfaltan, nenviados;
+ const char *p = (const char *) ptr;
+
+ nfaltan = n;
+ while (nfaltan > 0) {
+ nenviados = write (fd, p, nfaltan);
+ if (nenviados <= 0)
+ return nenviados;
+
+ nfaltan -= nenviados;
+ p += nenviados;
+ }
+
+ return n - nfaltan;
+}
+
--- /dev/null
+/* LibTcp - Released underOpen Software License v. 2.0
+ *
+ * This Open Software License (the "License") applies to any original work of authorship
+ * (the "Original Work") whose owner (the "Licensor") has placed the following notice
+ * immediately following the copyright notice for the Original Work:
+ *
+ * Licensed under the Open Software License version 2.0
+ *
+ * See http://www.opensource.org/licenses/osl-2.0.php or the LICENSE file for more
+ * details.
+ */
+
+#ifndef _LIBTCP_COMMON_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#define LIBTCP_DEFAULT_UDP_PORT 5000
+#define LIBTCP_DEFAULT_TCP_PORT 5000
+
+extern int errno;
+
+int libtcp_open_activo (const char *server, int port);
+int libtcp_open_pasivo (int port);
+int libtcp_receive (int fd, char *ptr, unsigned int maxlong);
+int libtcp_receive_bin (int fd, void *ptr, unsigned int maxlong);
+int libtcp_send (int fd, const void *ptr, unsigned int n);
+
+#endif // _LIBTCP_COMMON_H_
+
--- /dev/null
+#include "nameserver.h"
+#include <sstream>
+#include <algorithm>
+#include <iterator>
+#include <sstream>
+#include <functional>
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+#define DEBUG_RESOLV
+
+NameServer::Name::Name(const std::string& s)
+{
+ std::istringstream iss(s);
+ std::string tok;
+ while (std::getline(iss, tok, '.'))
+ push_back(tok);
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer::Name& name)
+{
+ if (name.empty())
+ return os;
+ std::copy(name.begin(), name.end() - 1,
+ std::ostream_iterator< std::string >(os, "."));
+ return os << name.back();
+}
+
+NameServer::Name::operator std::string () const
+{
+ std::stringstream ss;
+ ss << *this;
+ return ss.str();
+}
+
+/// Parsea una zona
+static std::istream& parsezone(std::istream& is, NameServer::Zone& z)
+ throw (std::runtime_error)
+{
+ std::string line, sname, ip;
+ // [dominio] [ttl] [parent ip]
+ while (std::getline(is, line) && (line == "")); // Salteo líneas en blanco
+ if (!is)
+ return is;
+ std::istringstream iss(line);
+ if (!(iss >> sname >> z.ttl >> ip))
+ throw std::runtime_error("Error al parsear");
+ z.name = sname;
+#ifdef DEBUG_PARSER
+ std::cerr << "parsezone: IP = " << ip << "\n\n";
+#endif
+ z.parent = IPAddr(ip);
+ // un record por linea, sin líneas vacías
+ // [name] [type] [ip]
+ while (std::getline(is, line) && (line != ""))
+ {
+ iss.clear();
+ iss.str(line);
+ std::string key, type;
+ if (!(iss >> key >> type >> ip))
+ throw std::runtime_error("Error al parsear");
+ typedef NameServer::Record Rec;
+#ifdef DEBUG_PARSER
+ std::cerr << "parsezone: IP = " << ip << "\n\n";
+#endif
+ Rec r((type == "NS") ? Rec::NS : Rec::A, IPAddr(ip));
+ z.records.insert(NameServer::Zone::records_t::value_type(key, r));
+ }
+#ifdef DEBUG_PARSER
+ std::cerr << "parsezone: " << z << "\n\n";
+#endif
+ return is;
+}
+
+/// Constructor
+NameServer::Zone::Zone(std::string sname, size_t ttl, const IPAddr& parent):
+ name(sname), ttl(ttl), parent(parent)
+{
+}
+
+/// Constructor
+NameServer::Zone::Zone(std::istream& is)
+ throw (std::runtime_error)
+{
+ // Parsea la zona
+ if (!parsezone(is, *this))
+ throw std::runtime_error("Error de parser, no hay zona");
+}
+
+/// Limpia una zona
+void NameServer::Zone::clear()
+{
+ name.clear();
+ records.clear();
+}
+
+/// Constructor
+NameServer::NameServer(std::istream& is, IPIn& ipin, IPOut& ipout,
+ DevQue& req_que, DevQue& res_que, DevQue& snd_que)
+ throw (std::runtime_error):
+ ipin(ipin), ipout(ipout), req_que(req_que), res_que(res_que),
+ snd_que(snd_que)
+{
+ Zone z;
+ while (parsezone(is, z))
+ {
+ zones.push_back(z);
+ z.clear();
+#ifdef DEBUG_PARSER
+ std::cerr << "NameServer: " << z << "\n\n";
+#endif
+ }
+}
+
+/// Devuelve la parte izquierda de n, si la parte derecha coincide exactamente
+/// con m, si no devuelve un vector vacío.
+/// Elemplo: name_split("mi.domi.nio", "domi.nio") == ["mi"]
+/// name_split("dos.mi.domi.nio", "domi.nio") == ["dos", "mi"]
+/// name_split("domi.nio", "domi.nio") == []
+/// name_split("papeli.nio", "domi.nio") == []
+static NameServer::Name
+name_split(NameServer::Name n, NameServer::Name m)
+{
+ NameServer::Name r;
+ std::reverse(n.begin(), n.end());
+ std::reverse(m.begin(), m.end());
+ // Si m es más grande o igual que n, no hay nada que hacer
+ if (n.size() <= m.size())
+ return r;
+ // Si no coincide la parte derecha, no hay nada que hacer
+ NameServer::Name::size_type i;
+ for (i = 0; i < m.size(); ++i)
+ if (n[i] != m[i])
+ return r;
+ // Si era todo igual y sobran cosas, devolvemos lo que "sobra"
+ while (i < n.size())
+ r.push_back(n[i++]);
+ std::reverse(r.begin(), r.end());
+#ifdef DEBUG_NAME
+ std::cerr << "name_split(" << n << ", " << m << ") -> " << r << "\n";
+#endif
+ return r;
+}
+
+/// Devuelve -1 si es un nombre "hijo" (la parte derecha de n está contenida
+/// completamente en m, pero m y n no son iguales), 0 si m == n y 1 si es
+/// "padre" (m no coincide con la parte derecha de n).
+/// Elemplo: namecmp("mi.domi.nio", "domi.nio") == -1
+/// namecmp("otra.cosa", "domi.nio") == 1
+/// namecmp("papeli.nio", "domi.nio") == 1
+/// namecmp("domi.nio", "domi.nio") == 0
+/*enum name_cmp_t
+{
+ NC_DIRECT_CHILD, ///> Hijo directo, es decir, está en la zona m
+ NC_CHILD, ///> Hijo indirecto, está en una zona que cuelga de m
+ NC_EQUAL, ///> Es el host de la zona m
+ NC_DIRECT_PARENT, ///> Padre directo, es decir, coincide en parte con m
+ NC_PARENT ///> Padre indirecto, es completamente distinto a m
+};*/
+#if 0
+static int name_cmp(const NameServer::Name& n, const NameServer::Name& m)
+{
+ // Si m es más grande que n, seguro es padre
+ if (n.size() < m.size())
+ return 1;
+ // Si no coincide la parte derecha, seguro es padre
+ NameServer::Name::size_type i;
+ for (i = m.size(); i > 0; --i)
+ if (n[i-1] != m[i-1])
+ return 1;
+ // Si era todo igual y sobran cosas, es hijo
+ if (i)
+ return -1;
+ // Si no, son iguales.
+ return 0;
+}
+#endif
+
+struct search_zone: std::unary_function< NameServer::Zone, bool >
+{
+ bool local;
+ ResolvProtoResponse resp;
+ const NameServer::Name& name;
+ search_zone(const NameServer::Name& n): local(false), name(n) {}
+ bool operator() (const NameServer::Zone& z)
+ {
+ bool found = false;
+ NameServer::Name local_part = name_split(name, z.name);
+ if (!local_part.empty()) // Está en esta zona
+ {
+ local = true;
+ std::string n = local_part.back(); // Obtengo última parte
+ // busco
+ typedef NameServer::Zone::records_t::const_iterator itt;
+ std::pair<itt, itt> p = z.records.equal_range(n);
+ for (; p.first != p.second; ++p.first)
+ {
+ const NameServer::Record& r = (*p.first).second;
+ // Tiene que buscar solo A porque era un nombre
+ if ((local_part.size() == 1) && (r.type != NameServer::Record::A))
+ continue;
+ // Tiene que seguir para abajo, solo busca NS
+ if ((local_part.size() > 1) && r.type != NameServer::Record::NS)
+ continue;
+ found = true;
+ resp.ret = (r.type == NameServer::Record::NS) ? RP_RES_NS
+ : RP_RES_A;
+ resp.ttl = z.ttl;
+ resp.ips.push_back(r.ip);
+ }
+ }
+ return found;
+ }
+};
+
+/// Resuelve un nombre de forma directa (no recursiva)
+ResolvProtoResponse NameServer::resolv_direct(const Name& n)
+{
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_direct -> tratando de resolver: " << n << "\n";
+#endif
+ search_zone zs(n);
+ bool found;
+ for (zones_t::const_iterator i = zones.begin(); i!= zones.end(); ++i)
+ if ((found = zs(*i)))
+ break;
+ if (found)
+ {
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_direct found (local/hijo): " << zs.resp << "\n";
+#endif
+ return zs.resp;
+ }
+ if (zs.local)
+ {
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_direct NOT FOUND (es local pero no existe)\n";
+#endif
+ return ResolvProtoResponse(RP_RES_NOTFOUND);
+ }
+ cache_t::const_iterator i = cache.find(n);
+ // TODO TTL!?!
+ if (i != cache.end())
+ {
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_direct found (en cache): " << i->second << "\n";
+#endif
+ const CacheRecord& cr = i->second;
+ return ResolvProtoResponse(RP_RES_A, cr.ttl, cr.ips);
+ }
+ if (zones.size())
+ {
+ // Busco una zona con padre para ver si puedo "trepar"
+ for (zones_t::const_iterator i = zones.begin(); i != zones.end(); ++i)
+ {
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_direct -> evaluando padre " << i->parent
+ << "\n";
+#endif
+ if (i->parent != IPAddr(0))
+ {
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_direct found (al padre): "
+ << i->parent << "\n";
+#endif
+ ResolvProtoResponse rpr(RP_RES_NS, i->ttl);
+ rpr.ips.push_back(i->parent);
+ return rpr;
+ }
+ }
+ }
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_direct NOT FOUND (no hay padre)\n";
+#endif
+ // No hay padre, no puedo hacer nada más
+ return ResolvProtoResponse(RP_RES_NOTFOUND);
+}
+
+/// Resuelve un nombre de forma recursiva
+ResolvProtoResponse NameServer::resolv_recursive(const Name& n)
+{
+ ResolvProtoResponse rpr = resolv_direct(n);
+ switch (rpr.ret)
+ {
+ case RP_RES_NS:
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_recursive -> redirect a " << rpr << "\n";
+#endif
+ return resolv_recursive_r(n, rpr); // Sigo "bajando"
+ case RP_RES_A:
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_recursive -> gotcha! " << rpr << "\n";
+#endif
+ // TODO agregar a cache
+ break;
+ }
+ return rpr; // Devuelvo el A o NOTFOUND
+}
+
+/// Resuelve un nombre de forma recursiva entrando a otros ns
+ResolvProtoResponse NameServer::resolv_recursive_r(const Name& n,
+ ResolvProtoResponse rpr)
+{
+ ResolvProtoResponse r;
+ for (ResolvProtoResponse::ipvec_t::const_iterator ip = rpr.ips.begin();
+ ip != rpr.ips.end(); ++ip)
+ {
+ r = query(n, *ip);
+ switch (r.ret)
+ {
+ case RP_RES_NS:
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_recursive_r -> redirect a " << r << "\n";
+#endif
+ return resolv_recursive_r(n, r); // Sigo "bajando"
+ case RP_RES_NOTFOUND:
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_recursive_r -> NOT FOUND en " << *ip
+ << ", sigo probando\n";
+#endif
+ break; // Sigo probando del mismo nivel
+ case RP_RES_A:
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_recursive_r -> gotcha! " << r << "\n";
+#endif
+ // TODO agregar a cache
+ return r; // Gotcha!
+ }
+ }
+#ifdef DEBUG_RESOLV
+ std::cerr << "resolv_recursive_r -> NOT FOUND, no hay más por hacer\n";
+#endif
+ return r; // NOTFOUND
+}
+
+/// Consulta a otro name server sobre un nombre
+ResolvProtoResponse NameServer::query(const Name& n, const IPAddr& ip)
+{
+ ResolvProtoRequest r(std::string(n), RP_REQ_DIRECT);
+#ifdef DEBUG_RESOLV
+ std::cerr << "query -> pidiendo " << r << " a " << ip << "\n";
+#endif
+ // Envía a través de la cola de envío
+ snd_que.transmit(std::string(r), ip);
+ Dev::mac_type mac = ip;
+ std::string buf = res_que.receive(mac);
+ ResolvProtoResponse resp(buf);
+#ifdef DEBUG_RESOLV
+ std::cerr << "query -> recibido " << resp << " de " << ip << "\n";
+#endif
+ return resp;
+}
+
+void NameServer::recv_loop()
+{
+ while (true)
+ {
+ IPAddr src, dst;
+ uint8_t proto;
+ std::string s = ipin.recv(proto, src, dst);
+#ifdef DEBUG_RESOLV
+ std::cout << "NameServer::recv_loop() -> recibido len=" << s.size()
+ << " de " << src << " para " << dst << " (proto = "
+ << unsigned(proto) << ")\n";
+#endif
+ if (proto == NAMESERVER_PROTO) // Si es para nosotros
+ {
+ rp_pkt_type_t type;
+ memcpy(&type, s.c_str(), sizeof(uint8_t));
+ switch (type)
+ {
+ // Request
+ case RP_REQ_DIRECT:
+ case RP_REQ_RECURSIVE:
+#ifdef DEBUG_RESOLV
+ std::cout << "---> " << ResolvProtoRequest(s) << "\n";
+#endif
+ req_que.transmit(s, src); // Encolo
+ break;
+ // Response
+ default:
+#ifdef DEBUG_RESOLV
+ std::cout << "---> " << ResolvProtoResponse(s) << "\n";
+#endif
+ res_que.transmit(s, src); // Encolo
+ }
+ }
+ }
+}
+
+void NameServer::send_loop()
+{
+ while (true)
+ {
+ if (!req_que.empty())
+ {
+ Dev::mac_type mac = 0;
+ ResolvProtoRequest req(req_que.receive(mac));
+#ifdef DEBUG_RESOLV
+ std::cout << "NameServer::send_loop() -> recibido " << req << "\n";
+#endif
+ ResolvProtoResponse res
+ = (req.query_type == RP_REQ_DIRECT)
+ ? resolv_direct(req.name)
+ : resolv_recursive(req.name);
+#ifdef DEBUG_RESOLV
+ std::cout << "NameServer::send_loop() -> respondo " << res << "\n";
+#endif
+ ipout.send(res, NAMESERVER_PROTO, IPAddr(mac));
+ }
+ else if (!snd_que.empty()) // Hay un request para enviar
+ {
+ Dev::mac_type mac = 0;
+ std::string buf = snd_que.receive(mac);
+#ifdef DEBUG_RESOLV
+ std::cout << "NameServer::send_loop() -> envío request "
+ << ResolvProtoRequest(buf) << "\n";
+#endif
+ ipout.send(buf, NAMESERVER_PROTO, IPAddr(mac));
+ }
+ else // No hay nada, esperamos un rato
+ {
+ usleep(10000);
+ }
+ }
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer::Record::type_t& t)
+{
+ if (t == NameServer::Record::NS)
+ return os << "NS";
+ else
+ return os << "A";
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer::Record& r)
+{
+ return os << r.type << " " << r.ip;
+}
+
+std::ostream& operator<< (std::ostream& os,
+ const NameServer::Zone::records_t::value_type& p)
+{
+ return os << p.first << ": " << p.second;
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer::Zone& z)
+{
+ os << "Zone " << z.name << " " << z.ttl << " " << z.parent << "\n";
+ std::copy(z.records.begin(), z.records.end(), std::ostream_iterator<
+ NameServer::Zone::records_t::value_type >(os, "\n"));
+ return os;
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer::CacheRecord& cr)
+{
+ os << "CacheRecord(ttl=" << cr.ttl << ", records=";
+ std::copy(cr.ips.begin(), cr.ips.end(),
+ std::ostream_iterator< IPAddr >(os, ","));
+ return os << ")";
+}
+
+std::ostream& operator<< (std::ostream& os, const NameServer& ns)
+{
+ os << "NameServer: zones[" << ns.zones.size() << "] (\n\n";
+ std::copy(ns.zones.begin(), ns.zones.end(),
+ std::ostream_iterator< NameServer::Zone >(os, "\n"));
+ return os << ")";
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _NAMESERVER_H_
+#define _NAMESERVER_H_
+
+#include "devque.h"
+#include "ipaddr.h"
+#include "resolvproto.h"
+#include <string>
+#include <vector>
+#include <map>
+#include <istream>
+#include <ostream>
+#include <stdexcept>
+
+#define NAMESERVER_PROTO 59
+
+/// Petición del resolver a un nameserver
+struct NameServer
+{
+
+ /// Nombre de un dominio dividido en tokens
+ struct Name: std::vector< std::string >
+ {
+ /// Constructor
+ Name() {}
+ Name(const std::string& name);
+ operator std::string () const;
+ };
+
+ /// Registro de una zona
+ struct Record
+ {
+ /// Tipo de registro
+ enum type_t { A, NS };
+ type_t type;
+ /// Dirección IP del registro
+ IPAddr ip;
+ /// Constructor
+ Record(type_t t, const IPAddr& i): type(t), ip(i) {}
+ };
+
+ /// Zona
+ struct Zone
+ {
+ /// Nombre
+ Name name;
+ /// Time to live
+ size_t ttl;
+ /// Nodo padre
+ IPAddr parent;
+ /// Registros
+ typedef std::multimap< std::string, Record > records_t;
+ records_t records;
+ /// Constructores
+ Zone() {}
+ Zone(std::string sname, size_t ttl, const IPAddr& parent);
+ Zone(std::istream& is) throw (std::runtime_error);
+ /// Limpia una zona
+ void clear();
+ };
+
+ /// Zonas para las que este servidor de nombres es autoridad
+ typedef std::vector< Zone > zones_t;
+ zones_t zones;
+
+ /// Cache de un registro
+ struct CacheRecord
+ {
+ /// Time to live
+ size_t ttl;
+ /// Dirección IP del registro
+ typedef ResolvProtoResponse::ipvec_t ipvec_t;
+ ipvec_t ips;
+ /// Constructor
+ CacheRecord(): ttl(0) {}
+ CacheRecord(size_t ttl, const ipvec_t& ips):
+ ttl(ttl), ips(ips) {}
+ };
+
+ /// Cache de records
+ typedef std::map< Name, CacheRecord > cache_t;
+ cache_t cache;
+
+ /// IP
+ IPIn& ipin;
+ IPOut& ipout;
+
+ /// Colas de recepción
+ DevQue& req_que; // De requests
+ DevQue& res_que; // De responses
+
+ /// Cola de envío
+ DevQue& snd_que;
+
+ /// Constructor
+ NameServer(std::istream& is, IPIn& ipin, IPOut& ipout, DevQue& req_que,
+ DevQue& res_que, DevQue& snd_que) throw (std::runtime_error);
+
+ /// Resuelve un nombre de forma directa (no recursiva)
+ ResolvProtoResponse resolv_direct(const Name& n);
+
+ /// Resuelve un nombre de forma recursiva
+ ResolvProtoResponse resolv_recursive(const Name& n);
+
+ /// Consulta a otro name server sobre un nombre
+ ResolvProtoResponse query(const Name&n, const IPAddr& ip);
+
+ /// Loop que recibe y carga los paquetes en las colas para ser procesados
+ void recv_loop();
+
+ /// Loop que envía los paquetes de la cola de envío
+ void send_loop();
+
+ private:
+ /// Resuelve un nombre de forma recursiva entrando a otros ns
+ ResolvProtoResponse resolv_recursive_r(const Name& n,
+ ResolvProtoResponse rpr);
+
+};
+
+/// Impresión (para debug)
+std::ostream& operator<< (std::ostream& os, const NameServer& ns);
+std::ostream& operator<< (std::ostream& os, const NameServer::Name& name);
+std::ostream& operator<< (std::ostream& os, const NameServer::Record& r);
+std::ostream& operator<< (std::ostream& os, const NameServer::Zone& z);
+std::ostream& operator<< (std::ostream& os, const NameServer::CacheRecord& cr);
+
+#endif // _NAMESERVER_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#include "resolvproto.h"
+#include <cstdlib>
+#include <algorithm>
+#include <iterator>
+
+/// Constructor
+ResolvProtoRequest::ResolvProtoRequest(std::string name, rp_pkt_type_t query_type):
+ query_type(query_type), name(name)
+{}
+
+/// Constructor a partir de un buffer
+ResolvProtoRequest::ResolvProtoRequest(std::string buf)
+{
+ memcpy(&query_type, buf.c_str(), sizeof(uint8_t));
+ uint16_t size;
+ memcpy(&size, buf.c_str() + sizeof(uint8_t), sizeof(uint16_t));
+ name.assign(buf.c_str() + sizeof(uint8_t) + sizeof(uint16_t), size);
+}
+
+/// Convierte a un buffer
+ResolvProtoRequest::operator std::string () const
+{
+ std::string buf((char*)&query_type, sizeof(uint8_t));
+ uint16_t size = name.size();
+ buf.append((char*)&size, sizeof(uint16_t));
+ buf.append(name);
+ return buf;
+}
+
+size_t ResolvProtoRequest::packet_size() const
+{
+ return sizeof(uint8_t) + sizeof(uint16_t) + name.size();
+}
+
+/// Impresión de request
+std::ostream& operator<< (std::ostream& os, const ResolvProtoRequest& rpr)
+{
+ return os << "ResolvProtoRequest(query_type=" << unsigned(rpr.query_type)
+ << ", name=" << rpr.name << ")";
+}
+
+/// Constructor
+ResolvProtoResponse::ResolvProtoResponse(): ret(RP_RES_NOTFOUND), ttl(0)
+{
+}
+
+/// Constructor
+ResolvProtoResponse::ResolvProtoResponse(std::string buf)
+{
+ memcpy(&ret, buf.c_str(), sizeof(uint8_t));
+ memcpy(&ttl, buf.c_str() + sizeof(uint8_t), sizeof(uint32_t));
+ uint8_t count;
+ memcpy(&count, buf.c_str() + sizeof(uint8_t) + sizeof(uint32_t),
+ sizeof(uint8_t));
+ ips.reserve(count);
+ for (uint8_t i = 0; i < count; ++i)
+ {
+ uint32_t ip;
+ memcpy(&ip, buf.c_str() + 2 * sizeof(uint8_t)
+ + sizeof(uint32_t) * (i + 1), sizeof(uint32_t));
+ ips.push_back(ip);
+ }
+}
+
+/// Constructor
+ResolvProtoResponse::ResolvProtoResponse(rp_pkt_type_t ret, uint32_t ttl,
+ const ipvec_t& ips):
+ ret(ret), ttl(ttl), ips(ips)
+{}
+
+/// Convierte a buffer
+ResolvProtoResponse::operator std::string () const
+{
+ std::string buf((char*)&ret, sizeof(uint8_t));
+ buf.append((char*)&ttl, sizeof(uint32_t));
+ uint8_t count = ips.size();
+ buf.append((char*)&count, sizeof(uint8_t));
+ for (ipvec_t::const_iterator i = ips.begin(); i != ips.end(); ++i)
+ {
+ uint32_t ip = *i;
+ buf.append((char*)&ip, sizeof(uint32_t));
+ }
+ return buf;
+}
+
+size_t ResolvProtoResponse::packet_size() const
+{
+ return 2 * sizeof(uint8_t) + (ips.size() + 1) * sizeof(uint32_t);
+}
+
+/// Impresión de response
+std::ostream& operator<< (std::ostream& os, const ResolvProtoResponse& rpr)
+{
+ os << "ResolvProtoResponse(ret=" << unsigned(rpr.ret)
+ << ", ttl=" << rpr.ttl;
+ if (rpr.ips.empty())
+ return os << ")";
+ os << ", ";
+ std::copy(rpr.ips.begin(), rpr.ips.end() - 1,
+ std::ostream_iterator< IPAddr >(os, ", "));
+ return os << rpr.ips.back() << ")";
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _RESOLVPROTO_H_
+#define _RESOLVPROTO_H_
+
+#include "ipaddr.h"
+#include "ipin.h"
+#include "ipout.h"
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <stdint.h>
+
+/// Tipo de petición
+enum rp_pkt_type_t
+{
+ // requests
+ RP_REQ_DIRECT, ///> Búsqueda directa (inter nameservers)
+ RP_REQ_RECURSIVE, ///> Búsqueda recursiva (para resolvers)
+ // responses
+ RP_RES_A, ///> OK, se devolvió un registro A
+ RP_RES_NS, ///> OK, se devolvió un registro NS (sólo en directo)
+ RP_RES_NOTFOUND, ///> No se encontró
+ RP_RES_TIMEOUT ///> Tardó demasiado la consulta
+};
+
+/// Petición de un nameserver
+/// +------------+------------+------------+
+/// | QUERY_TYPE | SIZE | NAME |
+/// +------------+------------+------------+
+/// /-- 1 byte --/- 2 bytes --/- variable -/
+struct ResolvProtoRequest
+{
+
+ /// Tipo de petición (de tipo rp_pkt_type_t)
+ uint8_t query_type;
+
+ /// Nombre a buscar
+ std::string name;
+
+ /// Constructores
+ ResolvProtoRequest(std::string name, rp_pkt_type_t query_type);
+ ResolvProtoRequest(std::string buf);
+
+ /// Envía por socket
+ void send(IPOut& ipo) const throw (std::runtime_error);
+
+ /// Recibe por socket
+ void recv(IPIn& ipi) throw (std::runtime_error);
+
+ /// Obtiene tamaño del paquete
+ size_t packet_size() const;
+
+ /// Convierte a un string
+ operator std::string () const;
+
+};
+
+/// Impresión de request
+std::ostream& operator<< (std::ostream& os, const ResolvProtoRequest& rpr);
+
+
+/// Respuesta de un nameserver
+/// +-----------+-----------+-----------+-----------+-----------+-----------+
+/// | RET | TTL | COUNT | IP 1 | ... | IP N |
+/// +-----------+-----------+-----------+-----------+-----------+-----------+
+/// /-- 1 byte -/- 4 bytes -/-- 1 byte -/- 4 bytes -/- 4 bytes -/- 4 bytes -/
+struct ResolvProtoResponse
+{
+
+ /// Resultado de la respuesta (de tipo rp_pkt_type_t)
+ uint8_t ret;
+
+ /// TTL (sólo útil para búsquedas (inter nameserver)
+ uint32_t ttl;
+
+ /// IPs devueltas
+ typedef std::vector< IPAddr > ipvec_t;
+ ipvec_t ips;
+
+ /// Constructores
+ ResolvProtoResponse();
+ ResolvProtoResponse(rp_pkt_type_t ret, uint32_t ttl = 0,
+ const ipvec_t& ips = ipvec_t());
+ ResolvProtoResponse(std::string buf);
+
+ /// Envía por socket
+ void send(IPOut& ipo) const throw (std::runtime_error);
+
+ /// Recibe por socket
+ void recv(IPIn& ipi) throw (std::runtime_error);
+
+ /// Obtiene tamaño del paquete
+ size_t packet_size() const;
+
+ /// Convierte a un string
+ operator std::string () const;
+
+};
+
+/// Impresión de response
+std::ostream& operator<< (std::ostream& os, const ResolvProtoResponse& rpr);
+
+#endif // _RESOLVPROTO_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#include "routetable.h"
+#ifdef DEBUG
+#include <iostream>
+#endif
+
+RouteTable::RouteTable(Dev& default_iface): default_iface(default_iface)
+{
+}
+
+void RouteTable::add(const IPAddr& net, const IPAddr& gw, unsigned mtu,
+ unsigned metric, Dev& iface)
+{
+ table[net] = Route(gw, metric, mtu, iface);
+#ifdef DEBUG
+ //std::cout << "Se agregó tabla para " << net << ": gw = " << gw
+ // << ", metric = " << metric << "\n";
+#endif
+}
+
+void RouteTable::del(const IPAddr& net)
+{
+ table.erase(net);
+}
+
+RouteTable::Route* RouteTable::get(const IPAddr& dst)
+{
+ // No existe
+ if (table.find(dst) == table.end())
+ return 0;
+ return &table[dst];
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#ifndef _ROUTETABLE_H_
+#define _ROUTETABLE_H_
+
+#include "dev.h"
+#include "ipaddr.h"
+#include <map>
+
+/// Tabla de ruteo
+struct RouteTable
+{
+
+ /// Ruta
+ struct Route
+ {
+ IPAddr gateway;
+ unsigned mtu;
+ unsigned metric;
+ Dev* iface;
+ Route(): gateway(0), mtu(0), metric(0), iface(0) {}
+ Route(const IPAddr& gateway, unsigned mtu, unsigned metric, Dev& iface):
+ gateway(gateway), mtu(mtu), metric(metric), iface(&iface) {}
+ };
+
+ /// Tabla
+ std::map< IPAddr, Route > table;
+
+ /// Interfaz por default
+ Dev& default_iface;
+
+ /// Constructor
+ RouteTable(Dev& default_iface);
+
+ /// Agrega ruta
+ void add(const IPAddr& net, const IPAddr& gw, unsigned mtu, unsigned metric, Dev& iface);
+
+ /// Borra ruta
+ void del(const IPAddr& net);
+
+ /// Obtiene dirección e interfaz por la cual salir para un destino
+ Route* get(const IPAddr& dst);
+
+};
+
+#endif // _ROUTETABLE_H_
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#!/bin/bash
+# 35 28 25
+# 10.10.10.1 ------ 10.10.10.5 ------ 10.10.10.4 ------ 10.10.10.2
+# |
+# | 32
+# |
+# 10.10.10.3
+#
+
+# Host 10.10.10.1
+(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 &
+
+# Host 10.10.10.5
+(echo ; sleep 2) \
+ | ./ip 10.10.10.5 1 1 ../rutas_ejemplo/route_10.10.10.5.txt &
+
+# Host 10.10.10.3
+(echo ; sleep 3) \
+ | ./ip 10.10.10.3 0 0 ../rutas_ejemplo/route_10.10.10.3.txt &
+
+# Limpio
+sleep 4
+ipcrm -Q 0x1abcdef1
+ipcrm -Q 0x1abcdef0
--- /dev/null
+#!/bin/bash
+# 35 28 25
+# 10.10.10.1 ------ 10.10.10.5 ------ 10.10.10.4 ------ 10.10.10.2
+# |
+# | 32
+# |
+# 10.10.10.3
+#
+
+# Host 10.10.10.1
+(echo -e '10.10.10.2\nAdios mundo cruel!!!'; sleep 1) \
+ | ./ip 10.10.10.1 0 0 ../rutas_ejemplo/route_10.10.10.1.txt &
+
+# Host 10.10.10.5
+(echo ; sleep 2) \
+ | ./ip 10.10.10.5 1 1 ../rutas_ejemplo/route_10.10.10.5.txt &
+
+# Host 10.10.10.4
+(echo ; sleep 3) \
+ | ./ip 10.10.10.4 1 1 ../rutas_ejemplo/route_10.10.10.4.txt &
+
+# Host 10.10.10.2
+(echo ; sleep 4) \
+ | ./ip 10.10.10.2 0 0 ../rutas_ejemplo/route_10.10.10.2.txt &
+
+# Limpio
+sleep 5
+ipcrm -Q 0x1abcdef1
+ipcrm -Q 0x1abcdef0
+
--- /dev/null
+
+#include "ipaddr.h"
+#include "devtcp.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <signal.h>
+
+// Uso: ./test_devtcp port
+
+void send_loop(Dev& dev);
+
+int main(int argc, char* argv[])
+{
+ if (argc < 3)
+ {
+ std::cerr << "Uso: " << argv[0] << " addr port\n";
+ return 1;
+ }
+ Dev::mac_type mac = atoi(argv[1]);
+ uint16_t port = atoi(argv[2]);
+ // Creo medio físico y cola para forwarding
+ DevTCP dev(mac, port);
+ // Creo procesos
+ pid_t pid_send = fork();
+ if (pid_send == -1)
+ {
+ perror("fork()");
+ return 2;
+ }
+ if (pid_send) // Padre, send
+ {
+ int ret;
+ send_loop(dev);
+ kill(pid_send, SIGTERM);
+ waitpid(pid_send, &ret, 0);
+ return 0;
+ }
+ else // Hijo receive
+ {
+ while (true)
+ {
+ std::string s = dev.receive();
+ std::cout << "Recibido '" << s << "' (len " << s.size() << ")\n";
+ }
+ return 0;
+ }
+ return 0;
+}
+
+void send_loop(Dev& dev)
+{
+ std::string dst;
+ std::string msg;
+ while (std::getline(std::cin, dst))
+ {
+ if (!std::getline(std::cin, msg))
+ break;
+ dev.transmit(msg, IPAddr(dst.c_str()));
+ std::cout << "Enviado '" << msg << "' a " << dst << "\n";
+ }
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+#include "ipaddr.h"
+#include "ipheader.h"
+#include <iostream>
+
+int main()
+{
+ // Addr
+ IPAddr ip1(0x0a0a0a05);
+ IPAddr ip2("10.10.10.1");
+ IPAddr ip3(10, 10, 10, 2);
+ std::cout << "IP1 = " << ip1 << "\n";
+ std::cout << "IP2 = " << ip2 << "\n";
+ std::cout << "IP3 = " << ip3 << "\n";
+ // Header
+ IPHeader h1(4, 20, 1, 1, 0, 0, 64, 0x11, ip1, ip2);
+ std::cout << "Header1 = " << h1 << "\n";
+ if (h1.check_checksum())
+ std::cout << "Checksum OK\n";
+ else
+ std::cout << "Checksum MAL!\n";
+ h1.checksum = 1;
+ if (h1.check_checksum())
+ std::cout << "Checksum OK\n";
+ else
+ std::cout << "Checksum MAL!\n";
+ return 0;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "ipin.h"
+#include "ipaddr.h"
+#include "devque.h"
+#include <iostream>
+#include <cstdlib>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+// Uso: ./test_ipin ip mtu router forward proto queue_id
+
+int main(int argc, char* argv[])
+{
+ IPAddr addr("10.10.10.1");
+ unsigned mtu = 25;
+ bool router = false;
+ bool forward = false;
+ uint8_t proto = 0;
+ key_t queue_id = DEVQUE_DEFAULT_KEY;
+ if (argc > 1)
+ addr = IPAddr(argv[1]);
+ if (argc > 2)
+ mtu = atoi(argv[2]);
+ if (argc > 3)
+ router = atoi(argv[3]);
+ if (argc > 4)
+ forward = atoi(argv[4]);
+ if (argc > 5)
+ proto = atoi(argv[5]);
+ if (argc > 6)
+ queue_id = atoi(argv[6]);
+ int que_id = msgget(queue_id, IPC_CREAT | 0666);
+ assert(que_id != -1);
+ DevQue dev(addr, mtu, queue_id);
+ que_id = msgget(queue_id+1, IPC_CREAT | 0666);
+ assert(que_id != -1);
+ DevQue fwque(addr, DEV_MAX_MTU, queue_id+1);
+ IPIn ipin(addr, dev, fwque, router, forward, std::cerr);
+ struct msqid_ds minfo;
+ for (msgctl(dev.que_id, IPC_STAT, &minfo); minfo.msg_qnum;
+ msgctl(dev.que_id, IPC_STAT, &minfo))
+ {
+ IPAddr src, dst;
+ std::cout << "Quedan " << minfo.msg_qnum << " mensajes en la cola\n";
+ std::string s = ipin.recv(proto, src, dst);
+ std::cout << "Recibido '" << s << "' (len " << s.size() << ") de "
+ << src << " para " << dst << " (proto = " << proto << ")\n";
+ }
+ return 0;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "ipout.h"
+#include "ipaddr.h"
+#include "routetable.h"
+#include "devque.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+// Uso: ./test_ipout ip dst mtu routes_file proto queue_id
+
+void add_routes(RouteTable& rt, std::istream& is, size_t mtu, Dev& dev);
+
+int main(int argc, char* argv[])
+{
+ IPAddr addr("10.10.10.2");
+ IPAddr dst("10.10.10.1");
+ unsigned mtu = 25;
+ unsigned proto = 0;
+ key_t queue_id = DEVQUE_DEFAULT_KEY;
+ std::string fname = "route.txt";
+ if (argc > 1)
+ addr = IPAddr(argv[1]);
+ if (argc > 2)
+ dst = IPAddr(argv[2]);
+ if (argc > 3)
+ mtu = atoi(argv[3]);
+ if (argc > 4)
+ fname = argv[4];
+ if (argc > 5)
+ proto = atoi(argv[5]);
+ if (argc > 6)
+ queue_id = atoi(argv[6]);
+ int que_id = msgget(queue_id, IPC_CREAT | 0666); assert(que_id != -1);
+ que_id = msgget(queue_id+1, IPC_CREAT | 0666); assert(que_id != -1);
+ std::ifstream ifs(fname.c_str()); assert(ifs);
+ DevQue dev(addr, mtu, queue_id);
+ DevQue fwque(addr, DEV_MAX_MTU, queue_id+1);
+ RouteTable table(dev);
+ add_routes(table, ifs, mtu, dev);
+ IPOut ipout(addr, table, fwque, std::cerr);
+ std::string msg;
+ while (std::getline(std::cin, msg))
+ {
+ if (ipout.send(msg, proto, dst))
+ std::cout << "Enviado '" << msg << "' a " << dst << "\n";
+ else
+ std::cout << "NO SE PUDO ENVIAR '" << msg << "' a " << dst << "\n";
+ }
+ return 0;
+}
+
+void add_routes(RouteTable& rt, std::istream& is, size_t mtu, Dev& dev)
+{
+ std::string line;
+ while (std::getline(is, line))
+ {
+ std::istringstream iss(line);
+ std::string net;
+ std::string gw;
+ unsigned metric;
+ iss >> net >> gw >> metric;
+ if (net == "0") net = "0.0.0.0";
+ if (gw == "0") gw = "0.0.0.0";
+ rt.add(net, gw, mtu, metric, dev);
+ }
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "nameserver.h"
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+int main(int argc, char* argv[])
+{
+ std::ifstream ifs("test_nameserver_zones.txt");
+ //FIXME NameServer ns(ifs);
+ //FIXME std::cout << ns << "\n";
+ return 0;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "nameserver.h"
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+int main(int argc, char* argv[])
+{
+ typedef NameServer::Name N;
+ std::ifstream ifs("test_nameserver_zones.txt");
+ /* XXX NameServer ns(ifs);
+ std::cout << ns << "\n";
+ std::cout << ns.resolv_direct(N("tito.mi.super.nombre")) << "\n";
+ std::cout << ns.resolv_direct(N("juan.mi.super.nombre")) << "\n";
+ std::cout << ns.resolv_direct(N("pepe.otro.mi.super.nombre")) << "\n";
+ std::cout << ns.resolv_direct(N("pepe.mas.mi.super.nombre")) << "\n";
+ std::cout << ns.resolv_direct(N("super.nombre")) << "\n";
+ std::cout << ns.resolv_direct(N("nada.que.ver")) << "\n";
+ std::cout << ns.resolv_direct(N("tito.mas.super.nombres")) << "\n";
+ std::cout << ns.resolv_recursive(N("nada.que.ver")) << "\n";*/
+ return 0;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+mi.super.nombre 600 0.0.0.0
+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
+otro NS 10.10.100.100
+otro NS 10.10.100.101
+mas NS 10.10.200.1
+otro NS 10.10.200.2
+
+mas.super.nombres 9500 10.10.10.1
+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
+otro NS 10.1.100.100
+otro NS 10.1.100.101
+mas NS 10.1.200.1
+otro NS 10.1.200.2
+
--- /dev/null
+
+#include "libtcp.h"
+#include <assert.h>
+#include <sys/poll.h>
+
+#define MAX 10
+#define PORT 5000
+
+#define ISSET(var, flag) ((var & flag) == flag)
+
+int main()
+{
+ int ssock = libtcp_open_pasivo(PORT); assert(ssock != -1);
+ struct pollfd pfds[MAX];
+ pfds[0].fd = ssock;
+ pfds[0].events = POLLIN | POLLPRI;
+ int pfds_size = 1;
+ while (1)
+ {
+ int res;
+ res = poll(pfds, pfds_size, 5000); assert(res != -1);
+ if (!res)
+ continue;
+ if (ISSET(pfds[0].revents, POLLIN)
+ || ISSET(pfds[0].revents, POLLPRI))
+ {
+ if (pfds_size == MAX)
+ {
+ printf("Demasiadas conexiones, ignorando...\n");
+ continue;
+ }
+ pfds[pfds_size].fd = accept(ssock, NULL, NULL);
+ assert(pfds[pfds_size].fd != -1);
+ printf("Nueva conexión...\n");
+ pfds[pfds_size].events = POLLIN | POLLPRI;
+ ++pfds_size;
+ }
+ for (int i = 1; i < pfds_size; ++i)
+ {
+ if (ISSET(pfds[i].revents, POLLIN)
+ || ISSET(pfds[i].revents, POLLPRI))
+ {
+ char buf[10];
+ int recibidos = libtcp_receive_bin(pfds[i].fd, buf, 10);
+ //assert(recibidos == 10);
+ if (recibidos)
+ printf("recibido %s\n", buf);
+ }
+ }
+ }
+}
+
--- /dev/null
+
+#include "devque.h"
+#include <iostream>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+int main()
+{
+ DevQue dev(4321);
+ struct msqid_ds minfo;
+ for (msgctl(dev.que_id, IPC_STAT, &minfo); minfo.msg_qnum;
+ msgctl(dev.que_id, IPC_STAT, &minfo))
+ {
+ std::cout << "Quedan " << minfo.msg_qnum << " mensajes en la cola\n";
+ std::string s = dev.receive();
+ std::cout << "Recibido '" << s << "' (len " << s.size() << ")\n";
+ }
+ return 0;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "resolvproto.h"
+#include "libtcp.h"
+#include <iostream>
+#include <cassert>
+
+int main()
+{
+ ResolvProtoRequest req("hola.tito", RP_REQ_RECURSIVE);
+ std::cout << "Request Original: " << req << "\n";
+ ResolvProtoRequest req2 = std::string(req);
+ std::cout << "Request Reconstruido: " << req2 << "\n";
+ ResolvProtoResponse res(RP_RES_A, 600);
+ res.ips.push_back(IPAddr("10.10.10.2"));
+ res.ips.push_back(IPAddr("100.20.45.21"));
+ res.ips.push_back(IPAddr("230.23.62.189"));
+ std::cout << "Response Original: " << res << "\n";
+ ResolvProtoResponse res2 = std::string(res);
+ std::cout << "Response Reconstruido: " << res2 << "\n";
+ return 0;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "resolvproto.h"
+#include "libtcp.h"
+#include <iostream>
+#include <cassert>
+
+int main()
+{
+ int fd = libtcp_open_activo("localhost", 5050); assert(fd != -1);
+ ResolvProtoRequest rpr("hola.mundo.cruel");
+ std::cout << "Vamos a enviar: " << rpr << "\n";
+ rpr.send(fd);
+ ResolvProtoResponse rps(fd);
+ std::cout << "Recibimos: " << rps << "\n";
+ close(fd);
+ return 0;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "resolvproto.h"
+#include "libtcp.h"
+#include <iostream>
+#include <cassert>
+
+int main()
+{
+ int sfd = libtcp_open_pasivo(5050); assert(sfd != -1);
+ int cfd = accept(sfd, NULL, NULL); assert(cfd != -1);
+ close(sfd);
+ ResolvProtoRequest rpr(cfd);
+ std::cout << "Recibimos: " << rpr << "\n";
+ ResolvProtoResponse rps(ResolvProtoResponse::RET_OK);
+ rps.ips.push_back(IPAddr("10.10.10.2"));
+ rps.ips.push_back(IPAddr("100.20.45.21"));
+ rps.ips.push_back(IPAddr("230.23.62.189"));
+ std::cout << "Contestamos: " << rps << "\n";
+ rps.send(cfd);
+ close(cfd);
+ return 0;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+
+#include "devque.h"
+#include <iostream>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+int main()
+{
+ int que_id = msgget(DEVQUE_DEFAULT_KEY, IPC_CREAT | 0666);
+ assert(que_id != -1);
+ DevQue dev(1234);
+ dev.transmit("hola mundo", 4321);
+ std::cout << "Enviado 'hola mundo' a 4321\n";
+ return 0;
+}
+
+// vim: set et sw=4 sts=4 :
--- /dev/null
+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
+
--- /dev/null
+manuk.marge.casa 600 10.10.10.3
+tito A 40.10.100.1
+juan A 40.10.100.2
+juan A 40.10.100.3
+pepe A 40.10.100.4
+juan A 40.10.100.5
+pepe A 40.10.100.6
+
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+