From 9581f00645420a7d4edc9cf124df29ba1ef46421 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 13 Jun 2006 03:38:59 +0000 Subject: [PATCH] Tags de entregas. --- .../pipi-1ra-entrega-corregida/ENUNCIADO | 41 +++ practicas/pipi-1ra-entrega-corregida/README | 193 +++++++++++ practicas/pipi-1ra-entrega-corregida/TODO | 6 + .../rutas_ejemplo/route.txt | 3 + .../rutas_ejemplo/route_10.10.10.1.txt | 5 + .../rutas_ejemplo/route_10.10.10.2.txt | 5 + .../rutas_ejemplo/route_10.10.10.3.txt | 5 + .../rutas_ejemplo/route_10.10.10.4.txt | 5 + .../rutas_ejemplo/route_10.10.10.5.txt | 5 + .../pipi-1ra-entrega-corregida/src/Makefile | 189 +++++++++++ .../pipi-1ra-entrega-corregida/src/dev.cpp | 71 ++++ .../pipi-1ra-entrega-corregida/src/dev.h | 46 +++ .../pipi-1ra-entrega-corregida/src/ip.cpp | 139 ++++++++ .../pipi-1ra-entrega-corregida/src/ipaddr.cpp | 71 ++++ .../pipi-1ra-entrega-corregida/src/ipaddr.h | 45 +++ .../src/ipheader.cpp | 60 ++++ .../pipi-1ra-entrega-corregida/src/ipheader.h | 47 +++ .../pipi-1ra-entrega-corregida/src/ipin.cpp | 113 +++++++ .../pipi-1ra-entrega-corregida/src/ipin.h | 71 ++++ .../pipi-1ra-entrega-corregida/src/ipout.cpp | 116 +++++++ .../pipi-1ra-entrega-corregida/src/ipout.h | 61 ++++ .../src/routetable.cpp | 33 ++ .../src/routetable.h | 46 +++ .../pipi-1ra-entrega-corregida/src/test.sh | 25 ++ .../pipi-1ra-entrega-corregida/src/test2.sh | 30 ++ .../src/test_ipaddr.cpp | 29 ++ .../src/test_ipin.cpp | 56 ++++ .../src/test_ipout.cpp | 76 +++++ .../src/test_recv.cpp | 24 ++ .../src/test_send.cpp | 21 ++ practicas/pipi-1ra-entrega/ENUNCIADO | 41 +++ practicas/pipi-1ra-entrega/README | 307 ++++++++++++++++++ .../pipi-1ra-entrega/rutas_ejemplo/route.txt | 3 + .../rutas_ejemplo/route_10.10.10.1.txt | 4 + .../rutas_ejemplo/route_10.10.10.2.txt | 4 + .../rutas_ejemplo/route_10.10.10.3.txt | 4 + .../rutas_ejemplo/route_10.10.10.5.txt | 4 + practicas/pipi-1ra-entrega/src/Makefile | 162 +++++++++ practicas/pipi-1ra-entrega/src/dev.cpp | 71 ++++ practicas/pipi-1ra-entrega/src/dev.h | 46 +++ practicas/pipi-1ra-entrega/src/ipaddr.cpp | 71 ++++ practicas/pipi-1ra-entrega/src/ipaddr.h | 45 +++ practicas/pipi-1ra-entrega/src/ipheader.cpp | 60 ++++ practicas/pipi-1ra-entrega/src/ipheader.h | 47 +++ practicas/pipi-1ra-entrega/src/ipin.cpp | 101 ++++++ practicas/pipi-1ra-entrega/src/ipin.h | 71 ++++ practicas/pipi-1ra-entrega/src/ipout.cpp | 114 +++++++ practicas/pipi-1ra-entrega/src/ipout.h | 58 ++++ practicas/pipi-1ra-entrega/src/routetable.cpp | 32 ++ practicas/pipi-1ra-entrega/src/routetable.h | 45 +++ practicas/pipi-1ra-entrega/src/test.sh | 22 ++ .../pipi-1ra-entrega/src/test_ipaddr.cpp | 29 ++ practicas/pipi-1ra-entrega/src/test_ipin.cpp | 56 ++++ practicas/pipi-1ra-entrega/src/test_ipout.cpp | 76 +++++ practicas/pipi-1ra-entrega/src/test_recv.cpp | 24 ++ practicas/pipi-1ra-entrega/src/test_send.cpp | 21 ++ 56 files changed, 3155 insertions(+) create mode 100644 practicas/pipi-1ra-entrega-corregida/ENUNCIADO create mode 100644 practicas/pipi-1ra-entrega-corregida/README create mode 100644 practicas/pipi-1ra-entrega-corregida/TODO create mode 100644 practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route.txt create mode 100644 practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.1.txt create mode 100644 practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.2.txt create mode 100644 practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.3.txt create mode 100644 practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.4.txt create mode 100644 practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.5.txt create mode 100644 practicas/pipi-1ra-entrega-corregida/src/Makefile create mode 100644 practicas/pipi-1ra-entrega-corregida/src/dev.cpp create mode 100644 practicas/pipi-1ra-entrega-corregida/src/dev.h create mode 100644 practicas/pipi-1ra-entrega-corregida/src/ip.cpp create mode 100644 practicas/pipi-1ra-entrega-corregida/src/ipaddr.cpp create mode 100644 practicas/pipi-1ra-entrega-corregida/src/ipaddr.h create mode 100644 practicas/pipi-1ra-entrega-corregida/src/ipheader.cpp create mode 100644 practicas/pipi-1ra-entrega-corregida/src/ipheader.h create mode 100644 practicas/pipi-1ra-entrega-corregida/src/ipin.cpp create mode 100644 practicas/pipi-1ra-entrega-corregida/src/ipin.h create mode 100644 practicas/pipi-1ra-entrega-corregida/src/ipout.cpp create mode 100644 practicas/pipi-1ra-entrega-corregida/src/ipout.h create mode 100644 practicas/pipi-1ra-entrega-corregida/src/routetable.cpp create mode 100644 practicas/pipi-1ra-entrega-corregida/src/routetable.h create mode 100755 practicas/pipi-1ra-entrega-corregida/src/test.sh create mode 100755 practicas/pipi-1ra-entrega-corregida/src/test2.sh create mode 100644 practicas/pipi-1ra-entrega-corregida/src/test_ipaddr.cpp create mode 100644 practicas/pipi-1ra-entrega-corregida/src/test_ipin.cpp create mode 100644 practicas/pipi-1ra-entrega-corregida/src/test_ipout.cpp create mode 100644 practicas/pipi-1ra-entrega-corregida/src/test_recv.cpp create mode 100644 practicas/pipi-1ra-entrega-corregida/src/test_send.cpp create mode 100644 practicas/pipi-1ra-entrega/ENUNCIADO create mode 100644 practicas/pipi-1ra-entrega/README create mode 100644 practicas/pipi-1ra-entrega/rutas_ejemplo/route.txt create mode 100644 practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.1.txt create mode 100644 practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.2.txt create mode 100644 practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.3.txt create mode 100644 practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.5.txt create mode 100644 practicas/pipi-1ra-entrega/src/Makefile create mode 100644 practicas/pipi-1ra-entrega/src/dev.cpp create mode 100644 practicas/pipi-1ra-entrega/src/dev.h create mode 100644 practicas/pipi-1ra-entrega/src/ipaddr.cpp create mode 100644 practicas/pipi-1ra-entrega/src/ipaddr.h create mode 100644 practicas/pipi-1ra-entrega/src/ipheader.cpp create mode 100644 practicas/pipi-1ra-entrega/src/ipheader.h create mode 100644 practicas/pipi-1ra-entrega/src/ipin.cpp create mode 100644 practicas/pipi-1ra-entrega/src/ipin.h create mode 100644 practicas/pipi-1ra-entrega/src/ipout.cpp create mode 100644 practicas/pipi-1ra-entrega/src/ipout.h create mode 100644 practicas/pipi-1ra-entrega/src/routetable.cpp create mode 100644 practicas/pipi-1ra-entrega/src/routetable.h create mode 100755 practicas/pipi-1ra-entrega/src/test.sh create mode 100644 practicas/pipi-1ra-entrega/src/test_ipaddr.cpp create mode 100644 practicas/pipi-1ra-entrega/src/test_ipin.cpp create mode 100644 practicas/pipi-1ra-entrega/src/test_ipout.cpp create mode 100644 practicas/pipi-1ra-entrega/src/test_recv.cpp create mode 100644 practicas/pipi-1ra-entrega/src/test_send.cpp diff --git a/practicas/pipi-1ra-entrega-corregida/ENUNCIADO b/practicas/pipi-1ra-entrega-corregida/ENUNCIADO new file mode 100644 index 0000000..cfd611c --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/README b/practicas/pipi-1ra-entrega-corregida/README new file mode 100644 index 0000000..cca4337 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/README @@ -0,0 +1,193 @@ +=============================== +Sistemas Distribuidos I (75.74) +=============================== + +---------------------------- +Trabajo práctico de stack IP +---------------------------- + +: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`. +Dentro de este directorio hay también dos scripts de pruebas completas: +`test.sh` (con 1 router) y `test2.sh` (con 2 routers). + +En el directorio `rutas_ejemplo` contiene algunos archivos con descripciones de +rutas de ejemplo para correr los programas. + + +Uso +=== + +El trabajo consta de un programa llamado `ip` (más algunas otras pruebas que no +tiene relevancia). Este programa corre 3 procesos, uno que recibe paquetes IP +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 está 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. + + +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. Utiliza una cola como medio + físico y el id representaría el cable (si 2 dispositivos tienen cola con id + distinto serían como si no compartieran el mismo cable). Por simplicidad a la + cola siempre se envía el tamaño del MTU completo pero se agrega una cabecera + con el tamaño real del frame. + +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 + + +Ejemplo de corrida +================== + +Host 10.10.10.1 +--------------- + +Rutas: + +* 10.10.10.1 0.0.0.0 35 0 +* 10.10.10.3 10.10.10.5 35 1 +* 10.10.10.5 0.0.0.0 35 0 + +Envía "adios mundo cruel!!!" al host 10.10.10.3:: + + $ (echo -e '10.10.10.3\nAdios mundo cruel!!!'; sleep 1) | ./ip 10.10.10.1 0 0 ../rutas_ejemplo/route_10.10.10.1.txt + IPOut::send (10.10.10.1): Fragmento 0 => IPHeader: version=4 total_len=40 id=44919 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=214 src=10.10.10.1 dst=10.10.10.3 + data (15) = Adios mundo cru + IPOut::send (10.10.10.1): Fragmento 1 => IPHeader: version=4 total_len=25 id=44919 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=315 src=10.10.10.1 dst=10.10.10.3 + data (5) = el!!! + Enviado 'Adios mundo cruel!!!' a 10.10.10.3 + + +Router 10.10.10.5 +----------------- + +Rutas: + +* 10.10.10.1 0.0.0.0 35 0 +* 10.10.10.3 0.0.0.0 32 0 +* 10.10.10.5 0.0.0.0 35 0 + +Recibe el mensaje:: + + $ ./ip 10.10.10.5 1 1 ../rutas_ejemplo/route_10.10.10.5.txt + IPIn::recv (10.10.10.5): IPHeader: version=4 total_len=40 id=44919 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=214 src=10.10.10.1 dst=10.10.10.3 + data (15) = Adios mundo cru + IPIn::recv (10.10.10.5): IPHeader: version=4 total_len=25 id=44919 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=315 src=10.10.10.1 dst=10.10.10.3 + data (5) = el!!! + IPOut::forward_loop (10.10.10.5): A forwardear (id 44919) + IPOut::send (10.10.10.5): Fragmento 0 => IPHeader: version=4 total_len=40 id=44919 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=214 src=10.10.10.1 dst=10.10.10.3 + data (12) = Adios mundo + IPOut::send (10.10.10.5): Fragmento 1 => IPHeader: version=4 total_len=28 id=44919 DF=0 MF=1 offset=12 TTL=64 proto=0 checksum=298 src=10.10.10.1 dst=10.10.10.3 + data (3) = cru + IPOut::forward_loop (10.10.10.5): A forwardear (id 44919) + IPOut::send (10.10.10.5): Fragmento 0 => IPHeader: version=4 total_len=25 id=44919 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=315 src=10.10.10.1 dst=10.10.10.3 + data (5) = el!!! + + +Host 10.10.10.3 +--------------- + +Rutas: + +* 10.10.10.1 10.10.10.5 32 1 +* 10.10.10.3 0.0.0.0 32 0 +* 10.10.10.5 0.0.0.0 32 0 + +Finalmente este host recibe todos los fragmentos, reensabla y pasa el + paquete completo a la capa superior:: + + $ ./ip 10.10.10.3 0 0 ../rutas_ejemplo/route_10.10.10.3.txt + IPIn::recv (10.10.10.3): IPHeader: version=4 total_len=40 id=44919 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=214 src=10.10.10.1 dst=10.10.10.3 + data (12) = Adios mundo + IPIn::recv (10.10.10.3): IPHeader: version=4 total_len=28 id=44919 DF=0 MF=1 offset=12 TTL=64 proto=0 checksum=298 src=10.10.10.1 dst=10.10.10.3 + data (3) = cru + IPIn::recv (10.10.10.3): IPHeader: version=4 total_len=25 id=44919 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=315 src=10.10.10.1 dst=10.10.10.3 + data (5) = el!!! + IPIn::recv (10.10.10.3): Paquete completo: data = 'Adios mundo cruel!!!' + Recibido 'Adios mundo cruel!!!' (len 20) de 10.10.10.1 para 10.10.10.3 (proto = 0) + +.. vim: filetype=rst : diff --git a/practicas/pipi-1ra-entrega-corregida/TODO b/practicas/pipi-1ra-entrega-corregida/TODO new file mode 100644 index 0000000..e2ebac8 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/TODO @@ -0,0 +1,6 @@ +- Implementar metricas +- Implementar rutas de redes completas +- 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 diff --git a/practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route.txt b/practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route.txt new file mode 100644 index 0000000..5efe7da --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.1.txt b/practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.1.txt new file mode 100644 index 0000000..e74908d --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.2.txt b/practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.2.txt new file mode 100644 index 0000000..cff2d1b --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.3.txt b/practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.3.txt new file mode 100644 index 0000000..a4e4cfb --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.4.txt b/practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.4.txt new file mode 100644 index 0000000..54c7650 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.5.txt b/practicas/pipi-1ra-entrega-corregida/rutas_ejemplo/route_10.10.10.5.txt new file mode 100644 index 0000000..c19729c --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/Makefile b/practicas/pipi-1ra-entrega-corregida/src/Makefile new file mode 100644 index 0000000..9980baf --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/src/Makefile @@ -0,0 +1,189 @@ +# 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 + +# Opciones para el compilador C++. +CXXFLAGS = $(CFLAGS) -fno-inline + +# Opciones del enlazador. +#LDFLAGS= + +# Compilador. +CC=g++ + +# Programas +targets=ip +tests=test_send test_recv test_ipaddr test_ipin test_ipout + +# Fuentes +fuentes ?= $(wildcard *.cpp) + + +# REGLAS +######### + +.PHONY: all clean + +all: depend $(targets) + +tests: depend $(tests) + +test_send: test_send.o dev.o + +test_recv: test_recv.o dev.o + +test_ipaddr: test_ipaddr.o ipaddr.o ipheader.o + +test_ipin: test_ipin.o ipin.o ipaddr.o ipheader.o dev.o + +test_ipout: test_ipout.o ipout.o ipaddr.o ipheader.o dev.o routetable.o + +ip: ip.o ipout.o ipin.o ipaddr.o ipheader.o dev.o routetable.o + +depend: + @makedepend $(fuentes) > /dev/null 2>&1 + +clean: + @$(RM) -fv *.o Makefile.bak $(targets) + +# DO NOT DELETE + +dev.o: dev.h /usr/include/unistd.h /usr/include/features.h +dev.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h +dev.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h +dev.o: /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h +dev.o: /usr/include/bits/confname.h /usr/include/getopt.h +dev.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h +dev.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h +dev.o: /usr/include/bits/endian.h /usr/include/sys/select.h +dev.o: /usr/include/bits/select.h /usr/include/bits/sigset.h +dev.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h +dev.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h +dev.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h +dev.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h /usr/include/bits/msq.h +ip.o: ipout.h ipaddr.h ipheader.h /usr/include/stdint.h +ip.o: /usr/include/features.h /usr/include/sys/cdefs.h +ip.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h +ip.o: /usr/include/bits/wordsize.h routetable.h dev.h ipin.h +ip.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h +ip.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +ip.o: /usr/include/bits/confname.h /usr/include/getopt.h /usr/include/fcntl.h +ip.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h /usr/include/time.h +ip.o: /usr/include/endian.h /usr/include/bits/endian.h +ip.o: /usr/include/sys/select.h /usr/include/bits/select.h +ip.o: /usr/include/bits/sigset.h /usr/include/bits/time.h +ip.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h +ip.o: /usr/include/bits/sched.h /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 +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 ipheader.h /usr/include/stdint.h +ipin.o: /usr/include/features.h /usr/include/sys/cdefs.h +ipin.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h +ipin.o: /usr/include/bits/wordsize.h dev.h +ipout.o: ipout.h ipaddr.h ipheader.h /usr/include/stdint.h +ipout.o: /usr/include/features.h /usr/include/sys/cdefs.h +ipout.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h +ipout.o: /usr/include/bits/wordsize.h routetable.h dev.h +ipout.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h +ipout.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +ipout.o: /usr/include/bits/confname.h /usr/include/getopt.h +ipout.o: /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 +routetable.o: routetable.h dev.h ipaddr.h +test_ipaddr.o: ipaddr.h ipheader.h /usr/include/stdint.h +test_ipaddr.o: /usr/include/features.h /usr/include/sys/cdefs.h +test_ipaddr.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h +test_ipaddr.o: /usr/include/bits/wordsize.h +test_ipin.o: ipin.h ipaddr.h ipheader.h /usr/include/stdint.h +test_ipin.o: /usr/include/features.h /usr/include/sys/cdefs.h +test_ipin.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h +test_ipin.o: /usr/include/bits/wordsize.h dev.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 ipheader.h /usr/include/stdint.h +test_ipout.o: /usr/include/features.h /usr/include/sys/cdefs.h +test_ipout.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h +test_ipout.o: /usr/include/bits/wordsize.h routetable.h dev.h +test_ipout.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h +test_ipout.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +test_ipout.o: /usr/include/bits/confname.h /usr/include/getopt.h +test_ipout.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h +test_ipout.o: /usr/include/sys/types.h /usr/include/time.h +test_ipout.o: /usr/include/endian.h /usr/include/bits/endian.h +test_ipout.o: /usr/include/sys/select.h /usr/include/bits/select.h +test_ipout.o: /usr/include/bits/sigset.h /usr/include/bits/time.h +test_ipout.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h +test_ipout.o: /usr/include/bits/sched.h /usr/include/sys/ipc.h +test_ipout.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h +test_ipout.o: /usr/include/sys/msg.h /usr/include/bits/msq.h +test_recv.o: 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_send.o: 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 diff --git a/practicas/pipi-1ra-entrega-corregida/src/dev.cpp b/practicas/pipi-1ra-entrega-corregida/src/dev.cpp new file mode 100644 index 0000000..57e1d3d --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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, key_t key, size_t 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"); + 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-1ra-entrega-corregida/src/dev.h b/practicas/pipi-1ra-entrega-corregida/src/dev.h new file mode 100644 index 0000000..bae7e17 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/src/dev.h @@ -0,0 +1,46 @@ +#ifndef _DEV_H_ +#define _DEV_H_ + +#include + +#define DEV_DEFAULT_KEY 0x1abcdef1 +#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; + + /// Identificador de la cola a usar + int que_id; + + /// Constructor + Dev(mac_type mac, key_t key = DEV_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); + + // 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-1ra-entrega-corregida/src/ip.cpp b/practicas/pipi-1ra-entrega-corregida/src/ip.cpp new file mode 100644 index 0000000..dd38b9b --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/src/ip.cpp @@ -0,0 +1,139 @@ + +#include "ipout.h" +#include "ipin.h" +#include "ipaddr.h" +#include "routetable.h" +#include "dev.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Uso: ./test_ipout ip [router forward routes_file queue_id 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; + unsigned proto = 0; + key_t queue_id = DEV_DEFAULT_KEY; + std::string fname = "route.txt"; + if (argc < 2) + { + std::cerr << "Uso: ./test_ipout ip [router forward routes_file " + "queue_id 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) + queue_id = atoi(argv[5]); + if (argc > 6) + proto = atoi(argv[6]); + // Creo colas + int que_id = msgget(queue_id, IPC_CREAT | 0666); assert(que_id != -1); + que_id = msgget(DEV_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 + Dev dev(addr, queue_id); + Dev fwque(addr, DEV_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 = " << 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.c_str(), gw.c_str(), metric, mtu, dev); + } +} + +// vim: set et sw=4 sts=4 : diff --git a/practicas/pipi-1ra-entrega-corregida/src/ipaddr.cpp b/practicas/pipi-1ra-entrega-corregida/src/ipaddr.cpp new file mode 100644 index 0000000..7b153b2 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/src/ipaddr.cpp @@ -0,0 +1,71 @@ + +#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(int ip) +{ + atoms[0] = ip >> 24; + atoms[1] = ip >> 16; + atoms[2] = ip >> 8; + atoms[3] = ip; +} + +/// 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()); + } +} + +/// Constructor +//IPAddr::IPAddr(const std::string& ip) throw (std::logic_error) +//{ +// IPAddr(ip.c_str()); +//} + +/// Operador de casteo a unsigned +IPAddr::operator unsigned () 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-1ra-entrega-corregida/src/ipaddr.h b/practicas/pipi-1ra-entrega-corregida/src/ipaddr.h new file mode 100644 index 0000000..0c0c549 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/src/ipaddr.h @@ -0,0 +1,45 @@ +#ifndef _IPADDR_H_ +#define _IPADDR_H_ + +#include +#include +#include + +/// Dirección IP +struct IPAddr +{ + + /// Átomo de dirección IP + typedef unsigned char atom; + + /// Representación interna + atom atoms[4]; + + /// Constructor + IPAddr(); + + /// Constructor + IPAddr(atom a1, atom a2, atom a3, atom a4); + + /// Constructor + IPAddr(int 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 unsigned () 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-1ra-entrega-corregida/src/ipheader.cpp b/practicas/pipi-1ra-entrega-corregida/src/ipheader.cpp new file mode 100644 index 0000000..facc22b --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/ipheader.h b/practicas/pipi-1ra-entrega-corregida/src/ipheader.h new file mode 100644 index 0000000..f22c703 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/ipin.cpp b/practicas/pipi-1ra-entrega-corregida/src/ipin.cpp new file mode 100644 index 0000000..c8ea64e --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/src/ipin.cpp @@ -0,0 +1,113 @@ + +#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 o es un protocolo distinto, sigo + if (iph.mf || (iph.proto != proto)) + 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; + return data; + } +} + +// vim: set et sw=4 sts=4 : diff --git a/practicas/pipi-1ra-entrega-corregida/src/ipin.h b/practicas/pipi-1ra-entrega-corregida/src/ipin.h new file mode 100644 index 0000000..8620278 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/ipout.cpp b/practicas/pipi-1ra-entrega-corregida/src/ipout.cpp new file mode 100644 index 0000000..c98c4b5 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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 << ")\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-1ra-entrega-corregida/src/ipout.h b/practicas/pipi-1ra-entrega-corregida/src/ipout.h new file mode 100644 index 0000000..96cbbb6 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/routetable.cpp b/practicas/pipi-1ra-entrega-corregida/src/routetable.cpp new file mode 100644 index 0000000..40de2d3 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/routetable.h b/practicas/pipi-1ra-entrega-corregida/src/routetable.h new file mode 100644 index 0000000..20f62e8 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/test.sh b/practicas/pipi-1ra-entrega-corregida/src/test.sh new file mode 100755 index 0000000..c97dddd --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/test2.sh b/practicas/pipi-1ra-entrega-corregida/src/test2.sh new file mode 100755 index 0000000..cd60ac2 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/test_ipaddr.cpp b/practicas/pipi-1ra-entrega-corregida/src/test_ipaddr.cpp new file mode 100644 index 0000000..a34cb28 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/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-1ra-entrega-corregida/src/test_ipin.cpp b/practicas/pipi-1ra-entrega-corregida/src/test_ipin.cpp new file mode 100644 index 0000000..e170b38 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/src/test_ipin.cpp @@ -0,0 +1,56 @@ + +#include "ipin.h" +#include "ipaddr.h" +#include "dev.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; + unsigned proto = 0; + key_t queue_id = DEV_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); + Dev dev(addr, mtu, queue_id); + que_id = msgget(queue_id+1, IPC_CREAT | 0666); + assert(que_id != -1); + Dev 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-1ra-entrega-corregida/src/test_ipout.cpp b/practicas/pipi-1ra-entrega-corregida/src/test_ipout.cpp new file mode 100644 index 0000000..b8e75c9 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/src/test_ipout.cpp @@ -0,0 +1,76 @@ + +#include "ipout.h" +#include "ipaddr.h" +#include "routetable.h" +#include "dev.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, 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 = DEV_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); + Dev dev(addr, mtu, queue_id); + Dev fwque(addr, DEV_MAX_MTU, queue_id+1); + RouteTable table(dev); + add_routes(table, ifs, 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, 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.c_str(), gw.c_str(), metric, dev); + } +} + +// vim: set et sw=4 sts=4 : diff --git a/practicas/pipi-1ra-entrega-corregida/src/test_recv.cpp b/practicas/pipi-1ra-entrega-corregida/src/test_recv.cpp new file mode 100644 index 0000000..2471b4a --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/src/test_recv.cpp @@ -0,0 +1,24 @@ + +#include "dev.h" +#include +#include +#include +#include +#include +#include + +int main() +{ + Dev 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-1ra-entrega-corregida/src/test_send.cpp b/practicas/pipi-1ra-entrega-corregida/src/test_send.cpp new file mode 100644 index 0000000..618b862 --- /dev/null +++ b/practicas/pipi-1ra-entrega-corregida/src/test_send.cpp @@ -0,0 +1,21 @@ + +#include "dev.h" +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + int que_id = msgget(DEV_DEFAULT_KEY, IPC_CREAT | 0666); + assert(que_id != -1); + Dev 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-1ra-entrega/ENUNCIADO b/practicas/pipi-1ra-entrega/ENUNCIADO new file mode 100644 index 0000000..cfd611c --- /dev/null +++ b/practicas/pipi-1ra-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-1ra-entrega/README b/practicas/pipi-1ra-entrega/README new file mode 100644 index 0000000..2243ff3 --- /dev/null +++ b/practicas/pipi-1ra-entrega/README @@ -0,0 +1,307 @@ +=============================== +Sistemas Distribuidos I (75.74) +=============================== + +---------------------------- +Trabajo práctico de stack IP +---------------------------- + +: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. + + +Uso +=== + +El trabajo tiene 2 programas de prueba principales: `test_ipin` y `test_ipout`, +ambos generados en el directorio `src` luego de compilar el código. + +test_ipin +--------- + +Este programa es el proceso que recibe paquetes IP y los procesa. + +Uso:: + + ./test_ipin [ip] [mtu] [router] [forward] [proto] [queue_id] + +ip + IP que utiliza este proceso (default 10.10.10.1) + +mtu + MTU de la capa física de este proceso (default 25) + +router + 0 si es router, 1 si no lo es (default 0) + +forward + 0 si puede hacer forwarding, 1 si no (default 0) + +proto + Protocolo que transporta (default 0) + +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`) + + +test_ipout +---------- + +Este programa es el proceso que envía paquetes IP y rutea. + +Uso:: + + ./test_ipout [ip] [dst] [mtu] [routes_file] [proto] [queue_id] + +ip + IP que utiliza este proceso (default 10.10.10.2) + +dst + IP del destino al cual mandar paquetes (default 10.10.10.1) + +mtu + MTU de la capa física de este proceso (default 25) + +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) y métrica (todavía no se usa), separados + por uno o más espacios o tabs (default `route.txt`) + +proto + Protocolo que transporta (default 0) + +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`) + + +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. Utiliza una cola como medio + físico y el id representaría el cable (si 2 dispositivos tienen cola con id + distinto serían como si no compartieran el mismo cable). Por simplicidad a la + cola siempre se envía el tamaño del MTU completo pero se agrega una cabecera + con el tamaño real del frame. + +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, 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 + * 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 + + +Ejemplo de corrida +================== + +Host 10.10.10.1 +--------------- + +Rutas: + +* 10.10.10.1 0.0.0.0 0 +* 10.10.10.3 10.10.10.5 0 +* 10.10.10.5 0.0.0.0 0 + +Envía "adios mundo cruel!!!" al host 10.10.10.3:: + + $ ./test_ipout 10.10.10.1 10.10.10.3 25 ../rutas_ejemplo/route_10.10.10.1.txt + Se agregó tabla para 10.10.10.1: gw = 0.0.0.0, metric = 0 + Se agregó tabla para 10.10.10.2: gw = 0.0.0.0, metric = 0 + Se agregó tabla para 10.10.10.3: gw = 10.10.10.5, metric = 0 + Se agregó tabla para 10.10.10.5: gw = 0.0.0.0, metric = 0 + adios mundo cruel!!! + IPOut::send: Fragmento 0 => IPHeader: version= total_len=40 id=56121 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=196 src=10.10.10.1 dst=10.10.10.3 + data (5) = adios + Dev::transmit(msgtype/mac = 168430085, size = 25) + IPOut::send: Fragmento 0 => IPHeader: version= total_len=35 id=56121 DF=0 MF=1 offset=5 TTL=64 proto=0 checksum=231 src=10.10.10.1 dst=10.10.10.3 + data (5) = mund + Dev::transmit(msgtype/mac = 168430085, size = 25) + IPOut::send: Fragmento 0 => IPHeader: version= total_len=30 id=56121 DF=0 MF=1 offset=10 TTL=64 proto=0 checksum=266 src=10.10.10.1 dst=10.10.10.3 + data (5) = o cru + Dev::transmit(msgtype/mac = 168430085, size = 25) + IPOut::send: Fragmento 0 => IPHeader: version= total_len=25 id=56121 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=297 src=10.10.10.1 dst=10.10.10.3 + data (5) = el!!! + Dev::transmit(msgtype/mac = 168430085, size = 25) + Enviado 'adios mundo cruel!!!' a 10.10.10.3 + +El proceso test_ipin de este host no tiene relevancia. + +Router 10.10.10.5 +----------------- + +Rutas: + +* 10.10.10.1 0.0.0.0 0 +* 10.10.10.3 0.0.0.0 0 +* 10.10.10.5 0.0.0.0 0 + +Recibe el mensaje:: + + $ ./test_ipin 10.10.10.5 25 1 1 + Quedan 4 mensajes en la cola + Dev::receive(msgtype/mac = 168430085, size = 25) + IPIn::recv: IPHeader: version= total_len=40 id=56121 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=196 src=10.10.10.1 dst=10.10.10.3 + data (5) = adios + Dev::transmit(msgtype/mac = 168430085, size = 25) + Dev::receive(msgtype/mac = 168430085, size = 25) + IPIn::recv: IPHeader: version= total_len=35 id=56121 DF=0 MF=1 offset=5 TTL=64 proto=0 checksum=231 src=10.10.10.1 dst=10.10.10.3 + data (5) = mund + Dev::transmit(msgtype/mac = 168430085, size = 25) + Dev::receive(msgtype/mac = 168430085, size = 25) + IPIn::recv: IPHeader: version= total_len=30 id=56121 DF=0 MF=1 offset=10 TTL=64 proto=0 checksum=266 src=10.10.10.1 dst=10.10.10.3 + data (5) = o cru + Dev::transmit(msgtype/mac = 168430085, size = 25) + Dev::receive(msgtype/mac = 168430085, size = 25) + IPIn::recv: IPHeader: version= total_len=25 id=56121 DF=0 MF=0 offset=15 TTL=64 proto=0 checksum=297 src=10.10.10.1 dst=10.10.10.3 + data (5) = el!!! + Dev::transmit(msgtype/mac = 168430085, size = 25) + +Y lo forwardea (refragmentando porque tiene un MTU más pequeño):: + + $ ./test_ipout 10.10.10.5 10.10.10.1 23 ../rutas_ejemplo/route_10.10.10.5.txt + Se agregó tabla para 10.10.10.1: gw = 0.0.0.0, metric = 0 + Se agregó tabla para 10.10.10.2: gw = 0.0.0.0, metric = 0 + Se agregó tabla para 10.10.10.3: gw = 0.0.0.0, metric = 0 + Se agregó tabla para 10.10.10.5: gw = 0.0.0.0, metric = 0 + a + IPOut::send: Fragmento 0 => IPHeader: version= total_len=21 id=56140 DF=0 MF=0 offset=0 TTL=64 proto=0 checksum=194 src=10.10.10.5 dst=10.10.10.1 + data (1) = a + Dev::transmit(msgtype/mac = 168430081, size = 21) + Enviado 'a' a 10.10.10.1 + a + Dev::receive(msgtype/mac = 168430085, size = 25) + IPOut::send: A forwardear + IPOut::send: Fragmento 0 => IPHeader: version= total_len=40 id=56121 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=196 src=10.10.10.1 dst=10.10.10.3 + data (3) = adi + Dev::transmit(msgtype/mac = 168430083, size = 23) + IPOut::send: Fragmento 0 => IPHeader: version= total_len=37 id=56121 DF=0 MF=1 offset=3 TTL=64 proto=0 checksum=217 src=10.10.10.1 dst=10.10.10.3 + data (2) = os + Dev::transmit(msgtype/mac = 168430083, size = 22) + Dev::receive(msgtype/mac = 168430085, size = 25) + IPOut::send: A forwardear + IPOut::send: Fragmento 0 => IPHeader: version= total_len=35 id=56121 DF=0 MF=1 offset=5 TTL=64 proto=0 checksum=231 src=10.10.10.1 dst=10.10.10.3 + data (3) = mu + Dev::transmit(msgtype/mac = 168430083, size = 23) + IPOut::send: Fragmento 0 => IPHeader: version= total_len=32 id=56121 DF=0 MF=1 offset=8 TTL=64 proto=0 checksum=252 src=10.10.10.1 dst=10.10.10.3 + data (2) = nd + Dev::transmit(msgtype/mac = 168430083, size = 22) + Dev::receive(msgtype/mac = 168430085, size = 25) + IPOut::send: A forwardear + IPOut::send: Fragmento 0 => IPHeader: version= total_len=30 id=56121 DF=0 MF=1 offset=10 TTL=64 proto=0 checksum=266 src=10.10.10.1 dst=10.10.10.3 + data (3) = o c + Dev::transmit(msgtype/mac = 168430083, size = 23) + IPOut::send: Fragmento 0 => IPHeader: version= total_len=27 id=56121 DF=0 MF=1 offset=13 TTL=64 proto=0 checksum=287 src=10.10.10.1 dst=10.10.10.3 + data (2) = ru + Dev::transmit(msgtype/mac = 168430083, size = 22) + Dev::receive(msgtype/mac = 168430085, size = 25) + IPOut::send: A forwardear + IPOut::send: Fragmento 0 => IPHeader: version= total_len=25 id=56121 DF=0 MF=1 offset=15 TTL=64 proto=0 checksum=301 src=10.10.10.1 dst=10.10.10.3 + data (3) = el! + Dev::transmit(msgtype/mac = 168430083, size = 23) + IPOut::send: Fragmento 0 => IPHeader: version= total_len=22 id=56121 DF=0 MF=0 offset=18 TTL=64 proto=0 checksum=62 src=10.10.10.1 dst=10.10.10.3 + data (2) = !! + Dev::transmit(msgtype/mac = 168430083, size = 22) + IPOut::send: Fragmento 0 => IPHeader: version= total_len=21 id=56147 DF=0 MF=0 offset=0 TTL=64 proto=0 checksum=201 src=10.10.10.5 dst=10.10.10.1 + data (1) = a + Dev::transmit(msgtype/mac = 168430081, size = 21) + Enviado 'a' a 10.10.10.1 + +(notar que para que haga el forwarding se tuvo que enviar un paquete +*dummy* para que busque en la cola de paquetes a forwardear (es un error +de diseño que tendré que corregir de alguna forma) + +Host 10.10.10.3 +--------------- + +Rutas: + +* 10.10.10.1 10.10.10.5 0 +* 10.10.10.3 0.0.0.0 0 +* 10.10.10.5 0.0.0.0 0 + +Finalmente este host recibe todos los fragmentos, reensabla y pasa el + paquete completo a la capa superior:: + + $ ./test_ipin 10.10.10.3 23 + Quedan 8 mensajes en la cola + Dev::receive(msgtype/mac = 168430083, size = 23) + IPIn::recv: IPHeader: version= total_len=40 id=56121 DF=0 MF=1 offset=0 TTL=64 proto=0 checksum=196 src=10.10.10.1 dst=10.10.10.3 + data (3) = adi + Dev::receive(msgtype/mac = 168430083, size = 22) + IPIn::recv: IPHeader: version= total_len=37 id=56121 DF=0 MF=1 offset=3 TTL=64 proto=0 checksum=217 src=10.10.10.1 dst=10.10.10.3 + data (2) = os + Dev::receive(msgtype/mac = 168430083, size = 23) + IPIn::recv: IPHeader: version= total_len=35 id=56121 DF=0 MF=1 offset=5 TTL=64 proto=0 checksum=231 src=10.10.10.1 dst=10.10.10.3 + data (3) = mu + Dev::receive(msgtype/mac = 168430083, size = 22) + IPIn::recv: IPHeader: version= total_len=32 id=56121 DF=0 MF=1 offset=8 TTL=64 proto=0 checksum=252 src=10.10.10.1 dst=10.10.10.3 + data (2) = nd + Dev::receive(msgtype/mac = 168430083, size = 23) + IPIn::recv: IPHeader: version= total_len=30 id=56121 DF=0 MF=1 offset=10 TTL=64 proto=0 checksum=266 src=10.10.10.1 dst=10.10.10.3 + data (3) = o c + Dev::receive(msgtype/mac = 168430083, size = 22) + IPIn::recv: IPHeader: version= total_len=27 id=56121 DF=0 MF=1 offset=13 TTL=64 proto=0 checksum=287 src=10.10.10.1 dst=10.10.10.3 + data (2) = ru + Dev::receive(msgtype/mac = 168430083, size = 23) + IPIn::recv: IPHeader: version= total_len=25 id=56121 DF=0 MF=1 offset=15 TTL=64 proto=0 checksum=301 src=10.10.10.1 dst=10.10.10.3 + data (3) = el! + Dev::receive(msgtype/mac = 168430083, size = 22) + IPIn::recv: IPHeader: version= total_len=22 id=56121 DF=0 MF=0 offset=18 TTL=64 proto=0 checksum=62 src=10.10.10.1 dst=10.10.10.3 + data (2) = !! + IPIn::recv: Paquete completo: data = 'adios mundo cruel!!!' + Recibido 'adios mundo cruel!!!' (len 20) de 10.10.10.1 para 10.10.10.3 (proto = 0) + +El proceso test_ipout de este host no tiene relevancia. + + +.. vim: filetype=rst : diff --git a/practicas/pipi-1ra-entrega/rutas_ejemplo/route.txt b/practicas/pipi-1ra-entrega/rutas_ejemplo/route.txt new file mode 100644 index 0000000..3aae5e1 --- /dev/null +++ b/practicas/pipi-1ra-entrega/rutas_ejemplo/route.txt @@ -0,0 +1,3 @@ +10.10.10.1 0.0.0.0 0 +10.10.10.2 0.0.0.0 0 +10.10.10.3 10.10.10.5 0 diff --git a/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.1.txt b/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.1.txt new file mode 100644 index 0000000..cc877c8 --- /dev/null +++ b/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.1.txt @@ -0,0 +1,4 @@ +10.10.10.1 0.0.0.0 0 +10.10.10.2 0.0.0.0 0 +10.10.10.3 10.10.10.5 0 +10.10.10.5 0.0.0.0 0 diff --git a/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.2.txt b/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.2.txt new file mode 100644 index 0000000..cc877c8 --- /dev/null +++ b/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.2.txt @@ -0,0 +1,4 @@ +10.10.10.1 0.0.0.0 0 +10.10.10.2 0.0.0.0 0 +10.10.10.3 10.10.10.5 0 +10.10.10.5 0.0.0.0 0 diff --git a/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.3.txt b/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.3.txt new file mode 100644 index 0000000..11ff580 --- /dev/null +++ b/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.3.txt @@ -0,0 +1,4 @@ +10.10.10.1 10.10.10.5 0 +10.10.10.2 10.10.10.5 0 +10.10.10.3 0.0.0.0 0 +10.10.10.5 0.0.0.0 0 diff --git a/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.5.txt b/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.5.txt new file mode 100644 index 0000000..d57116e --- /dev/null +++ b/practicas/pipi-1ra-entrega/rutas_ejemplo/route_10.10.10.5.txt @@ -0,0 +1,4 @@ +10.10.10.1 0.0.0.0 0 +10.10.10.2 0.0.0.0 0 +10.10.10.3 0.0.0.0 0 +10.10.10.5 0.0.0.0 0 diff --git a/practicas/pipi-1ra-entrega/src/Makefile b/practicas/pipi-1ra-entrega/src/Makefile new file mode 100644 index 0000000..58539ef --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/Makefile @@ -0,0 +1,162 @@ +# 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 + +# Opciones para el compilador C++. +CXXFLAGS = $(CFLAGS) -fno-inline + +# Opciones del enlazador. +#LDFLAGS= + +# Compilador. +CC=g++ + +# Programas +targets=test_send test_recv test_ipaddr test_ipin test_ipout + +# Fuentes +fuentes ?= $(wildcard *.cpp) + + +# REGLAS +######### + +.PHONY: all clean + +all: depend $(targets) + +test_send: test_send.o dev.o + +test_recv: test_recv.o dev.o + +test_ipaddr: test_ipaddr.o ipaddr.o ipheader.o + +test_ipin: test_ipin.o ipin.o ipaddr.o ipheader.o dev.o + +test_ipout: test_ipout.o ipout.o ipaddr.o ipheader.o dev.o routetable.o + +depend: + @makedepend $(fuentes) > /dev/null 2>&1 + +clean: + @$(RM) -fv *.o Makefile.bak $(targets) + +# DO NOT DELETE + +dev.o: dev.h /usr/include/unistd.h /usr/include/features.h +dev.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h +dev.o: /usr/include/bits/posix_opt.h /usr/include/bits/types.h +dev.o: /usr/include/bits/wordsize.h /usr/include/bits/typesizes.h +dev.o: /usr/include/bits/confname.h /usr/include/getopt.h +dev.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h +dev.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h +dev.o: /usr/include/bits/endian.h /usr/include/sys/select.h +dev.o: /usr/include/bits/select.h /usr/include/bits/sigset.h +dev.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h +dev.o: /usr/include/bits/pthreadtypes.h /usr/include/bits/sched.h +dev.o: /usr/include/sys/ipc.h /usr/include/bits/ipctypes.h +dev.o: /usr/include/bits/ipc.h /usr/include/sys/msg.h /usr/include/bits/msq.h +ipaddr.o: ipaddr.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 ipheader.h /usr/include/stdint.h +ipin.o: /usr/include/features.h /usr/include/sys/cdefs.h +ipin.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h +ipin.o: /usr/include/bits/wordsize.h dev.h +ipout.o: ipout.h ipaddr.h ipheader.h /usr/include/stdint.h +ipout.o: /usr/include/features.h /usr/include/sys/cdefs.h +ipout.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h +ipout.o: /usr/include/bits/wordsize.h routetable.h dev.h +ipout.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h +ipout.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +ipout.o: /usr/include/bits/confname.h /usr/include/getopt.h +ipout.o: /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 +routetable.o: routetable.h dev.h ipaddr.h +test_ipaddr.o: ipaddr.h ipheader.h /usr/include/stdint.h +test_ipaddr.o: /usr/include/features.h /usr/include/sys/cdefs.h +test_ipaddr.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h +test_ipaddr.o: /usr/include/bits/wordsize.h +test_ipin.o: ipin.h ipaddr.h ipheader.h /usr/include/stdint.h +test_ipin.o: /usr/include/features.h /usr/include/sys/cdefs.h +test_ipin.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h +test_ipin.o: /usr/include/bits/wordsize.h dev.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 ipheader.h /usr/include/stdint.h +test_ipout.o: /usr/include/features.h /usr/include/sys/cdefs.h +test_ipout.o: /usr/include/gnu/stubs.h /usr/include/bits/wchar.h +test_ipout.o: /usr/include/bits/wordsize.h routetable.h dev.h +test_ipout.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h +test_ipout.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h +test_ipout.o: /usr/include/bits/confname.h /usr/include/getopt.h +test_ipout.o: /usr/include/fcntl.h /usr/include/bits/fcntl.h +test_ipout.o: /usr/include/sys/types.h /usr/include/time.h +test_ipout.o: /usr/include/endian.h /usr/include/bits/endian.h +test_ipout.o: /usr/include/sys/select.h /usr/include/bits/select.h +test_ipout.o: /usr/include/bits/sigset.h /usr/include/bits/time.h +test_ipout.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h +test_ipout.o: /usr/include/bits/sched.h /usr/include/sys/ipc.h +test_ipout.o: /usr/include/bits/ipctypes.h /usr/include/bits/ipc.h +test_ipout.o: /usr/include/sys/msg.h /usr/include/bits/msq.h +test_recv.o: 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_send.o: 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 diff --git a/practicas/pipi-1ra-entrega/src/dev.cpp b/practicas/pipi-1ra-entrega/src/dev.cpp new file mode 100644 index 0000000..932df00 --- /dev/null +++ b/practicas/pipi-1ra-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-1ra-entrega/src/dev.h b/practicas/pipi-1ra-entrega/src/dev.h new file mode 100644 index 0000000..129f78f --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/dev.h @@ -0,0 +1,46 @@ +#ifndef _DEV_H_ +#define _DEV_H_ + +#include + +#define DEV_DEFAULT_KEY 0x1abcdef1 +#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; + + /// Identificador de la cola a usar + int que_id; + + /// Constructor + Dev(mac_type mac, size_t mtu = DEV_MAX_MTU, key_t key = DEV_DEFAULT_KEY) + 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); + + // 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-1ra-entrega/src/ipaddr.cpp b/practicas/pipi-1ra-entrega/src/ipaddr.cpp new file mode 100644 index 0000000..7b153b2 --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/ipaddr.cpp @@ -0,0 +1,71 @@ + +#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(int ip) +{ + atoms[0] = ip >> 24; + atoms[1] = ip >> 16; + atoms[2] = ip >> 8; + atoms[3] = ip; +} + +/// 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()); + } +} + +/// Constructor +//IPAddr::IPAddr(const std::string& ip) throw (std::logic_error) +//{ +// IPAddr(ip.c_str()); +//} + +/// Operador de casteo a unsigned +IPAddr::operator unsigned () 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-1ra-entrega/src/ipaddr.h b/practicas/pipi-1ra-entrega/src/ipaddr.h new file mode 100644 index 0000000..0c0c549 --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/ipaddr.h @@ -0,0 +1,45 @@ +#ifndef _IPADDR_H_ +#define _IPADDR_H_ + +#include +#include +#include + +/// Dirección IP +struct IPAddr +{ + + /// Átomo de dirección IP + typedef unsigned char atom; + + /// Representación interna + atom atoms[4]; + + /// Constructor + IPAddr(); + + /// Constructor + IPAddr(atom a1, atom a2, atom a3, atom a4); + + /// Constructor + IPAddr(int 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 unsigned () 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-1ra-entrega/src/ipheader.cpp b/practicas/pipi-1ra-entrega/src/ipheader.cpp new file mode 100644 index 0000000..0fbfca2 --- /dev/null +++ b/practicas/pipi-1ra-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=" << 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-1ra-entrega/src/ipheader.h b/practicas/pipi-1ra-entrega/src/ipheader.h new file mode 100644 index 0000000..f22c703 --- /dev/null +++ b/practicas/pipi-1ra-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-1ra-entrega/src/ipin.cpp b/practicas/pipi-1ra-entrega/src/ipin.cpp new file mode 100644 index 0000000..15e102c --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/ipin.cpp @@ -0,0 +1,101 @@ + +#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()) + { + 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) + { + drop("Versión IP incorrecta", iph); + continue; + } + if (!iph.check_checksum()) + { + drop("Mal checksum", iph); + continue; + } + // No es para nosotros y no forwardeamos + if (iph.dst != ip && !forward) + { + 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) + { + 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 o es un protocolo distinto, sigo + if (iph.mf || (iph.proto != proto)) + 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; + return data; + } +} + +// vim: set et sw=4 sts=4 : diff --git a/practicas/pipi-1ra-entrega/src/ipin.h b/practicas/pipi-1ra-entrega/src/ipin.h new file mode 100644 index 0000000..8620278 --- /dev/null +++ b/practicas/pipi-1ra-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-1ra-entrega/src/ipout.cpp b/practicas/pipi-1ra-entrega/src/ipout.cpp new file mode 100644 index 0000000..6829d2f --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/ipout.cpp @@ -0,0 +1,114 @@ + +#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) +{ + // Mando todo lo que tengo para forwardear + while (to_forward()) + { + std::string buf = forward_que.receive(); + IPHeader iph(buf); +#ifdef DEBUG + std::cout << "IPOut::send (" << ip << "): A forwardear\n"; +#endif + send(iph, buf.substr(iph.header_len())); + } + // Mando el paquete en sí + // 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); + 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) + { + drop("No existe una ruta para el destino", iph); + return false; + } + // No quieren fragmentar + if (iph.df && (IPHeader::header_len() + data.size() > r->iface->mtu)) + { + drop("Tamaño de paquete más grande que MTU y DF=1", iph); + return false; + } + // Fragmenta (de ser necesario) + int max_payload = r->iface->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; +} + +/// Obtiene un identificador para el paquete +uint16_t IPOut::get_id() const +{ + return time(NULL); +} + +/// Se fija si hay paquetes a forwardear (y devuelve cuantos hay) +unsigned IPOut::to_forward() +{ + struct msqid_ds minfo; + msgctl(forward_que.que_id, IPC_STAT, &minfo); + return minfo.msg_qnum; +} + +// vim: set et sw=4 sts=4 : diff --git a/practicas/pipi-1ra-entrega/src/ipout.h b/practicas/pipi-1ra-entrega/src/ipout.h new file mode 100644 index 0000000..effe150 --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/ipout.h @@ -0,0 +1,58 @@ +#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); + + /// 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-1ra-entrega/src/routetable.cpp b/practicas/pipi-1ra-entrega/src/routetable.cpp new file mode 100644 index 0000000..4a043cd --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/routetable.cpp @@ -0,0 +1,32 @@ +#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 metric, Dev& iface) +{ + table[net] = Route(gw, metric, 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-1ra-entrega/src/routetable.h b/practicas/pipi-1ra-entrega/src/routetable.h new file mode 100644 index 0000000..2fe1586 --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/routetable.h @@ -0,0 +1,45 @@ +#ifndef _ROUTETABLE_H_ +#define _ROUTETABLE_H_ + +#include "dev.h" +#include "ipaddr.h" +#include + +/// Tabla de ruteo +struct RouteTable +{ + + /// Ruta + struct Route + { + IPAddr gateway; + unsigned metric; + Dev* iface; + Route(): gateway(0), metric(0), iface(0) {} + Route(const IPAddr& gateway, unsigned metric, Dev& iface): + gateway(gateway), 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 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-1ra-entrega/src/test.sh b/practicas/pipi-1ra-entrega/src/test.sh new file mode 100755 index 0000000..4493a19 --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/test.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# Host 10.10.10.1 +./test_ipin 10.10.10.5 25 1 1 & +echo 'Adios mundo cruel!!!' | ./test_ipout 10.10.10.1 10.10.10.3 25 \ + ../rutas_ejemplo/route_10.10.10.1.txt + +# Router 10.10.10.5 +./test_ipin 10.10.10.5 25 1 1 & +echo | ./test_ipout 10.10.10.5 10.10.10.1 23 \ + ../rutas_ejemplo/route_10.10.10.5.txt + +# Host 10.10.10.3 +./test_ipin 10.10.10.3 23 0 0 & +echo | ./test_ipout 10.10.10.3 10.10.10.5 25 \ + ../rutas_ejemplo/route_10.10.10.3.txt + +# Limpio +sleep 1 +killall test_ipin +ipcrm -Q 0x1abcdef1 +ipcrm -Q 0x1abcdef2 diff --git a/practicas/pipi-1ra-entrega/src/test_ipaddr.cpp b/practicas/pipi-1ra-entrega/src/test_ipaddr.cpp new file mode 100644 index 0000000..a34cb28 --- /dev/null +++ b/practicas/pipi-1ra-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-1ra-entrega/src/test_ipin.cpp b/practicas/pipi-1ra-entrega/src/test_ipin.cpp new file mode 100644 index 0000000..e170b38 --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/test_ipin.cpp @@ -0,0 +1,56 @@ + +#include "ipin.h" +#include "ipaddr.h" +#include "dev.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; + unsigned proto = 0; + key_t queue_id = DEV_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); + Dev dev(addr, mtu, queue_id); + que_id = msgget(queue_id+1, IPC_CREAT | 0666); + assert(que_id != -1); + Dev 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-1ra-entrega/src/test_ipout.cpp b/practicas/pipi-1ra-entrega/src/test_ipout.cpp new file mode 100644 index 0000000..b8e75c9 --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/test_ipout.cpp @@ -0,0 +1,76 @@ + +#include "ipout.h" +#include "ipaddr.h" +#include "routetable.h" +#include "dev.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, 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 = DEV_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); + Dev dev(addr, mtu, queue_id); + Dev fwque(addr, DEV_MAX_MTU, queue_id+1); + RouteTable table(dev); + add_routes(table, ifs, 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, 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.c_str(), gw.c_str(), metric, dev); + } +} + +// vim: set et sw=4 sts=4 : diff --git a/practicas/pipi-1ra-entrega/src/test_recv.cpp b/practicas/pipi-1ra-entrega/src/test_recv.cpp new file mode 100644 index 0000000..2471b4a --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/test_recv.cpp @@ -0,0 +1,24 @@ + +#include "dev.h" +#include +#include +#include +#include +#include +#include + +int main() +{ + Dev 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-1ra-entrega/src/test_send.cpp b/practicas/pipi-1ra-entrega/src/test_send.cpp new file mode 100644 index 0000000..618b862 --- /dev/null +++ b/practicas/pipi-1ra-entrega/src/test_send.cpp @@ -0,0 +1,21 @@ + +#include "dev.h" +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + int que_id = msgget(DEV_DEFAULT_KEY, IPC_CREAT | 0666); + assert(que_id != -1); + Dev dev(1234); + dev.transmit("hola mundo", 4321); + std::cout << "Enviado 'hola mundo' a 4321\n"; + return 0; +} + +// vim: set et sw=4 sts=4 : -- 2.43.0