From: Leandro Lucarella Date: Sun, 25 Jun 2006 01:26:33 +0000 (+0000) Subject: Tag de 2da entrega. X-Git-Tag: svn_import~20 X-Git-Url: https://git.llucax.com/z.facultad/75.74/practicos.git/commitdiff_plain/7a9c776496e52dbed7d6ad152697e52bfe648c3e Tag de 2da entrega. --- diff --git a/practicas/pipi-2da-entrega/ENUNCIADO b/practicas/pipi-2da-entrega/ENUNCIADO new file mode 100644 index 0000000..cfd611c --- /dev/null +++ b/practicas/pipi-2da-entrega/ENUNCIADO @@ -0,0 +1,41 @@ +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). + diff --git a/practicas/pipi-2da-entrega/README b/practicas/pipi-2da-entrega/README new file mode 100644 index 0000000..cc25153 --- /dev/null +++ b/practicas/pipi-2da-entrega/README @@ -0,0 +1,351 @@ +=============================== +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 : diff --git a/practicas/pipi-2da-entrega/TODO b/practicas/pipi-2da-entrega/TODO new file mode 100644 index 0000000..62cecf1 --- /dev/null +++ b/practicas/pipi-2da-entrega/TODO @@ -0,0 +1,24 @@ +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 (!) diff --git a/practicas/pipi-2da-entrega/informe.rtf b/practicas/pipi-2da-entrega/informe.rtf new file mode 100644 index 0000000..eebe262 --- /dev/null +++ b/practicas/pipi-2da-entrega/informe.rtf @@ -0,0 +1,113 @@ +{\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 diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/mi_lan.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/mi_lan.txt new file mode 100644 index 0000000..aa77b5c --- /dev/null +++ b/practicas/pipi-2da-entrega/rutas_ejemplo/mi_lan.txt @@ -0,0 +1,4 @@ +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 diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route.txt new file mode 100644 index 0000000..5efe7da --- /dev/null +++ b/practicas/pipi-2da-entrega/rutas_ejemplo/route.txt @@ -0,0 +1,3 @@ +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 diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.1.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.1.txt new file mode 100644 index 0000000..e74908d --- /dev/null +++ b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.1.txt @@ -0,0 +1,5 @@ +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 diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.141_tcp.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.141_tcp.txt new file mode 100644 index 0000000..98cf91e --- /dev/null +++ b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.141_tcp.txt @@ -0,0 +1,2 @@ +10.10.10.2 0.0.0.0 25 0 +10.10.10.141 0.0.0.0 25 0 diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.2.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.2.txt new file mode 100644 index 0000000..cff2d1b --- /dev/null +++ b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.2.txt @@ -0,0 +1,5 @@ +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 diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.2_tcp.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.2_tcp.txt new file mode 100644 index 0000000..98cf91e --- /dev/null +++ b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.2_tcp.txt @@ -0,0 +1,2 @@ +10.10.10.2 0.0.0.0 25 0 +10.10.10.141 0.0.0.0 25 0 diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.3.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.3.txt new file mode 100644 index 0000000..a4e4cfb --- /dev/null +++ b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.3.txt @@ -0,0 +1,5 @@ +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 diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.4.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.4.txt new file mode 100644 index 0000000..54c7650 --- /dev/null +++ b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.4.txt @@ -0,0 +1,5 @@ +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 diff --git a/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.5.txt b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.5.txt new file mode 100644 index 0000000..c19729c --- /dev/null +++ b/practicas/pipi-2da-entrega/rutas_ejemplo/route_10.10.10.5.txt @@ -0,0 +1,5 @@ +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 diff --git a/practicas/pipi-2da-entrega/src/Makefile b/practicas/pipi-2da-entrega/src/Makefile new file mode 100644 index 0000000..d116c96 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/Makefile @@ -0,0 +1,437 @@ +# 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 diff --git a/practicas/pipi-2da-entrega/src/dev.cpp b/practicas/pipi-2da-entrega/src/dev.cpp new file mode 100644 index 0000000..d9465a6 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/dev.cpp @@ -0,0 +1,71 @@ +#include "dev.h" +#include +#include +#include +#include +#include +#include +#ifdef DEBUG +#include +#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 : diff --git a/practicas/pipi-2da-entrega/src/dev.h b/practicas/pipi-2da-entrega/src/dev.h new file mode 100644 index 0000000..f06e8b1 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/dev.h @@ -0,0 +1,50 @@ +#ifndef _DEV_H_ +#define _DEV_H_ + +#include + +#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 : diff --git a/practicas/pipi-2da-entrega/src/devque.cpp b/practicas/pipi-2da-entrega/src/devque.cpp new file mode 100644 index 0000000..0791354 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/devque.cpp @@ -0,0 +1,90 @@ +#include "devque.h" +#include +#include +#include +#include +#include +#include +#ifdef DEBUG +#include +#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 : diff --git a/practicas/pipi-2da-entrega/src/devque.h b/practicas/pipi-2da-entrega/src/devque.h new file mode 100644 index 0000000..70ddb36 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/devque.h @@ -0,0 +1,43 @@ +#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 : diff --git a/practicas/pipi-2da-entrega/src/devtcp.cpp b/practicas/pipi-2da-entrega/src/devtcp.cpp new file mode 100644 index 0000000..828e0e6 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/devtcp.cpp @@ -0,0 +1,103 @@ +#include "devtcp.h" +#include "ipaddr.h" +#include "libtcp.h" +#include +#include +#include +#include +#include +#include +#include +#ifdef DEBUG +#include +#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 : diff --git a/practicas/pipi-2da-entrega/src/devtcp.h b/practicas/pipi-2da-entrega/src/devtcp.h new file mode 100644 index 0000000..680561f --- /dev/null +++ b/practicas/pipi-2da-entrega/src/devtcp.h @@ -0,0 +1,43 @@ +#ifndef _DEVTCP_H_ +#define _DEVTCP_H_ + +#include "dev.h" +#include +#include +#include + +#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 : diff --git a/practicas/pipi-2da-entrega/src/dns.cpp b/practicas/pipi-2da-entrega/src/dns.cpp new file mode 100644 index 0000000..5b3c66c --- /dev/null +++ b/practicas/pipi-2da-entrega/src/dns.cpp @@ -0,0 +1,128 @@ + +#include "ipout.h" +#include "ipin.h" +#include "ipaddr.h" +#include "routetable.h" +#include "devtcp.h" +#include "devque.h" +#include "nameserver.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 : diff --git a/practicas/pipi-2da-entrega/src/ip.cpp b/practicas/pipi-2da-entrega/src/ip.cpp new file mode 100644 index 0000000..6988169 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/ip.cpp @@ -0,0 +1,140 @@ + +#include "ipout.h" +#include "ipin.h" +#include "ipaddr.h" +#include "routetable.h" +#include "devtcp.h" +#include "devque.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 : diff --git a/practicas/pipi-2da-entrega/src/ipaddr.cpp b/practicas/pipi-2da-entrega/src/ipaddr.cpp new file mode 100644 index 0000000..5d9bfdf --- /dev/null +++ b/practicas/pipi-2da-entrega/src/ipaddr.cpp @@ -0,0 +1,80 @@ + +#include "ipaddr.h" +#include + +/// 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 : diff --git a/practicas/pipi-2da-entrega/src/ipaddr.h b/practicas/pipi-2da-entrega/src/ipaddr.h new file mode 100644 index 0000000..b5c9cea --- /dev/null +++ b/practicas/pipi-2da-entrega/src/ipaddr.h @@ -0,0 +1,46 @@ +#ifndef _IPADDR_H_ +#define _IPADDR_H_ + +#include +#include +#include +#include + +/// 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 : diff --git a/practicas/pipi-2da-entrega/src/ipheader.cpp b/practicas/pipi-2da-entrega/src/ipheader.cpp new file mode 100644 index 0000000..facc22b --- /dev/null +++ b/practicas/pipi-2da-entrega/src/ipheader.cpp @@ -0,0 +1,60 @@ +#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 : diff --git a/practicas/pipi-2da-entrega/src/ipheader.h b/practicas/pipi-2da-entrega/src/ipheader.h new file mode 100644 index 0000000..f22c703 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/ipheader.h @@ -0,0 +1,47 @@ +#ifndef _IPHEADER_H_ +#define _IPHEADER_H_ + +#include "ipaddr.h" +#include +#include +#include + +/// 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 : diff --git a/practicas/pipi-2da-entrega/src/ipin.cpp b/practicas/pipi-2da-entrega/src/ipin.cpp new file mode 100644 index 0000000..1ff0560 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/ipin.cpp @@ -0,0 +1,115 @@ + +#include "ipin.h" +#include "ipheader.h" +#ifdef DEBUG +#include +#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 : diff --git a/practicas/pipi-2da-entrega/src/ipin.h b/practicas/pipi-2da-entrega/src/ipin.h new file mode 100644 index 0000000..8a452b2 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/ipin.h @@ -0,0 +1,71 @@ +#ifndef _IPIN_H_ +#define _IPIN_H_ + +#include "ipaddr.h" +#include "ipheader.h" +#include "dev.h" +#include +#include +#include +#include + +/// 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 : diff --git a/practicas/pipi-2da-entrega/src/ipout.cpp b/practicas/pipi-2da-entrega/src/ipout.cpp new file mode 100644 index 0000000..84a3733 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/ipout.cpp @@ -0,0 +1,116 @@ + +#include "ipout.h" +#include "ipheader.h" +#include +#include +#include +#include +#include +#include +#ifdef DEBUG +#include +#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 : diff --git a/practicas/pipi-2da-entrega/src/ipout.h b/practicas/pipi-2da-entrega/src/ipout.h new file mode 100644 index 0000000..96cbbb6 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/ipout.h @@ -0,0 +1,61 @@ +#ifndef _IPOUT_H_ +#define _IPOUT_H_ + +#include "ipaddr.h" +#include "ipheader.h" +#include "routetable.h" +#include +#include +#include + +/// 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 : diff --git a/practicas/pipi-2da-entrega/src/libtcp.c b/practicas/pipi-2da-entrega/src/libtcp.c new file mode 100644 index 0000000..68a6d2c --- /dev/null +++ b/practicas/pipi-2da-entrega/src/libtcp.c @@ -0,0 +1,207 @@ +/* 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; +} + diff --git a/practicas/pipi-2da-entrega/src/libtcp.h b/practicas/pipi-2da-entrega/src/libtcp.h new file mode 100644 index 0000000..4964c0f --- /dev/null +++ b/practicas/pipi-2da-entrega/src/libtcp.h @@ -0,0 +1,40 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_ + diff --git a/practicas/pipi-2da-entrega/src/nameserver.cpp b/practicas/pipi-2da-entrega/src/nameserver.cpp new file mode 100644 index 0000000..86f18e8 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/nameserver.cpp @@ -0,0 +1,472 @@ +#include "nameserver.h" +#include +#include +#include +#include +#include +#ifdef DEBUG +#include +#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 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 : diff --git a/practicas/pipi-2da-entrega/src/nameserver.h b/practicas/pipi-2da-entrega/src/nameserver.h new file mode 100644 index 0000000..d9b8a4f --- /dev/null +++ b/practicas/pipi-2da-entrega/src/nameserver.h @@ -0,0 +1,129 @@ +#ifndef _NAMESERVER_H_ +#define _NAMESERVER_H_ + +#include "devque.h" +#include "ipaddr.h" +#include "resolvproto.h" +#include +#include +#include +#include +#include +#include + +#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 : diff --git a/practicas/pipi-2da-entrega/src/resolvproto.cpp b/practicas/pipi-2da-entrega/src/resolvproto.cpp new file mode 100644 index 0000000..f55bbf2 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/resolvproto.cpp @@ -0,0 +1,104 @@ +#include "resolvproto.h" +#include +#include +#include + +/// 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 : diff --git a/practicas/pipi-2da-entrega/src/resolvproto.h b/practicas/pipi-2da-entrega/src/resolvproto.h new file mode 100644 index 0000000..2100771 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/resolvproto.h @@ -0,0 +1,104 @@ +#ifndef _RESOLVPROTO_H_ +#define _RESOLVPROTO_H_ + +#include "ipaddr.h" +#include "ipin.h" +#include "ipout.h" +#include +#include +#include +#include + +/// 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 : diff --git a/practicas/pipi-2da-entrega/src/routetable.cpp b/practicas/pipi-2da-entrega/src/routetable.cpp new file mode 100644 index 0000000..40de2d3 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/routetable.cpp @@ -0,0 +1,33 @@ +#include "routetable.h" +#ifdef DEBUG +#include +#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 : diff --git a/practicas/pipi-2da-entrega/src/routetable.h b/practicas/pipi-2da-entrega/src/routetable.h new file mode 100644 index 0000000..20f62e8 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/routetable.h @@ -0,0 +1,46 @@ +#ifndef _ROUTETABLE_H_ +#define _ROUTETABLE_H_ + +#include "dev.h" +#include "ipaddr.h" +#include + +/// 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 : diff --git a/practicas/pipi-2da-entrega/src/test.sh b/practicas/pipi-2da-entrega/src/test.sh new file mode 100755 index 0000000..c97dddd --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test.sh @@ -0,0 +1,25 @@ +#!/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 diff --git a/practicas/pipi-2da-entrega/src/test2.sh b/practicas/pipi-2da-entrega/src/test2.sh new file mode 100755 index 0000000..cd60ac2 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test2.sh @@ -0,0 +1,30 @@ +#!/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 + diff --git a/practicas/pipi-2da-entrega/src/test_devtcp.cpp b/practicas/pipi-2da-entrega/src/test_devtcp.cpp new file mode 100644 index 0000000..c588e62 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_devtcp.cpp @@ -0,0 +1,72 @@ + +#include "ipaddr.h" +#include "devtcp.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 : diff --git a/practicas/pipi-2da-entrega/src/test_ipaddr.cpp b/practicas/pipi-2da-entrega/src/test_ipaddr.cpp new file mode 100644 index 0000000..a34cb28 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_ipaddr.cpp @@ -0,0 +1,29 @@ +#include "ipaddr.h" +#include "ipheader.h" +#include + +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 : diff --git a/practicas/pipi-2da-entrega/src/test_ipin.cpp b/practicas/pipi-2da-entrega/src/test_ipin.cpp new file mode 100644 index 0000000..767db77 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_ipin.cpp @@ -0,0 +1,56 @@ + +#include "ipin.h" +#include "ipaddr.h" +#include "devque.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 : diff --git a/practicas/pipi-2da-entrega/src/test_ipout.cpp b/practicas/pipi-2da-entrega/src/test_ipout.cpp new file mode 100644 index 0000000..1f11fc1 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_ipout.cpp @@ -0,0 +1,76 @@ + +#include "ipout.h" +#include "ipaddr.h" +#include "routetable.h" +#include "devque.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 : diff --git a/practicas/pipi-2da-entrega/src/test_nameserver_file.cpp b/practicas/pipi-2da-entrega/src/test_nameserver_file.cpp new file mode 100644 index 0000000..b6f158d --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_nameserver_file.cpp @@ -0,0 +1,16 @@ + +#include "nameserver.h" +#include +#include +#include +#include + +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 : diff --git a/practicas/pipi-2da-entrega/src/test_nameserver_resolvnext.cpp b/practicas/pipi-2da-entrega/src/test_nameserver_resolvnext.cpp new file mode 100644 index 0000000..1ebf385 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_nameserver_resolvnext.cpp @@ -0,0 +1,25 @@ + +#include "nameserver.h" +#include +#include +#include +#include + +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 : diff --git a/practicas/pipi-2da-entrega/src/test_nameserver_zones.txt b/practicas/pipi-2da-entrega/src/test_nameserver_zones.txt new file mode 100644 index 0000000..655bd40 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_nameserver_zones.txt @@ -0,0 +1,24 @@ +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 + diff --git a/practicas/pipi-2da-entrega/src/test_poll.c b/practicas/pipi-2da-entrega/src/test_poll.c new file mode 100644 index 0000000..31fa213 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_poll.c @@ -0,0 +1,52 @@ + +#include "libtcp.h" +#include +#include + +#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); + } + } + } +} + diff --git a/practicas/pipi-2da-entrega/src/test_recv.cpp b/practicas/pipi-2da-entrega/src/test_recv.cpp new file mode 100644 index 0000000..fb8be43 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_recv.cpp @@ -0,0 +1,24 @@ + +#include "devque.h" +#include +#include +#include +#include +#include +#include + +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 : diff --git a/practicas/pipi-2da-entrega/src/test_resolvproto.cpp b/practicas/pipi-2da-entrega/src/test_resolvproto.cpp new file mode 100644 index 0000000..964240b --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_resolvproto.cpp @@ -0,0 +1,23 @@ + +#include "resolvproto.h" +#include "libtcp.h" +#include +#include + +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 : diff --git a/practicas/pipi-2da-entrega/src/test_resolvprotoc.cpp b/practicas/pipi-2da-entrega/src/test_resolvprotoc.cpp new file mode 100644 index 0000000..4f04686 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_resolvprotoc.cpp @@ -0,0 +1,19 @@ + +#include "resolvproto.h" +#include "libtcp.h" +#include +#include + +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 : diff --git a/practicas/pipi-2da-entrega/src/test_resolvprotos.cpp b/practicas/pipi-2da-entrega/src/test_resolvprotos.cpp new file mode 100644 index 0000000..7286ab3 --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_resolvprotos.cpp @@ -0,0 +1,24 @@ + +#include "resolvproto.h" +#include "libtcp.h" +#include +#include + +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 : diff --git a/practicas/pipi-2da-entrega/src/test_send.cpp b/practicas/pipi-2da-entrega/src/test_send.cpp new file mode 100644 index 0000000..5b78b2c --- /dev/null +++ b/practicas/pipi-2da-entrega/src/test_send.cpp @@ -0,0 +1,21 @@ + +#include "devque.h" +#include +#include +#include +#include +#include +#include +#include + +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 : diff --git a/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.1.txt b/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.1.txt new file mode 100644 index 0000000..5381f9d --- /dev/null +++ b/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.1.txt @@ -0,0 +1,27 @@ +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 + diff --git a/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.141.txt b/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.141.txt new file mode 100644 index 0000000..d75a5d8 --- /dev/null +++ b/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.141.txt @@ -0,0 +1,16 @@ +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 + diff --git a/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.2.txt b/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.2.txt new file mode 100644 index 0000000..4cd1503 --- /dev/null +++ b/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.2.txt @@ -0,0 +1,12 @@ +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 + diff --git a/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.3.txt b/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.3.txt new file mode 100644 index 0000000..dc45182 --- /dev/null +++ b/practicas/pipi-2da-entrega/zonas_ejemplo/10.10.10.3.txt @@ -0,0 +1,28 @@ +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 +