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 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.
+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::
- ./test_ipin [ip] [mtu] [router] [forward] [proto] [queue_id]
+ ./ip ip [router [forward [route_file [queue_id [proto]]]]]
ip
- IP que utiliza este proceso (default 10.10.10.1)
-
-mtu
- MTU de la capa física de este proceso (default 25)
+ 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)
-proto
- Protocolo que transporta (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
(`test_ipout`) para hacer forwarding, que será queue_id + 1 (default
`DEV_DEFAULT_KEY` obtenido de `dev.h`)
+proto
+ Protocolo que transporta (default 0)
-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`)
+El programa se queda esperando la entrada del usuario, y sale cuando está se
+termina (Ctrl-D). El formato de entrada es::
-proto
- Protocolo que transporta (default 0)
+ IP DESTINO
+ MENSAJE
-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`)
+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
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).
+ 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
* 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
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
+* 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::
- $ ./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
+ $ (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!!!
- Dev::transmit(msgtype/mac = 168430085, size = 25)
- Enviado 'adios mundo cruel!!!' a 10.10.10.3
+ 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
+* 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::
- $ ./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
+ $ ./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!!!
- 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)
+ 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 0
-* 10.10.10.3 0.0.0.0 0
-* 10.10.10.5 0.0.0.0 0
+* 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::
- $ ./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.
-
+ $ ./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 :
--- /dev/null
+
+#include "ipout.h"
+#include "ipin.h"
+#include "ipaddr.h"
+#include "routetable.h"
+#include "dev.h"
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <string>
+#include <cassert>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <signal.h>
+
+// Uso: ./test_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 :