From 14bd683fb6462d605cf2f23e1be01aae2c117aeb Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Mon, 14 Nov 2005 02:08:18 +0000 Subject: [PATCH] =?utf8?q?Listo=20el=20c=C3=A1lculo=20de=20checksum=20de?= =?utf8?q?=20IP.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- src/c/eth.c | 2 - src/c/ip.c | 136 ++++++++++++++++++++++++++++++++++---------------- src/c/types.h | 12 +++++ src/c/udp.c | 2 +- 4 files changed, 107 insertions(+), 45 deletions(-) diff --git a/src/c/eth.c b/src/c/eth.c index 83805b7..5c8686f 100644 --- a/src/c/eth.c +++ b/src/c/eth.c @@ -40,8 +40,6 @@ void eth_write_frame_header() { /* variable para iterar */ byte i; - /* tipo de paquete transportado */ - uint16 type = ; /* mandamos como MAC de destino la remota */ for (i = 0; i < ETH_MAC_SIZE; ++i) net_putb(mac_addr_remote[i]); diff --git a/src/c/ip.c b/src/c/ip.c index 44dd1ac..b9f5fb4 100644 --- a/src/c/ip.c +++ b/src/c/ip.c @@ -11,37 +11,55 @@ byte ip_packet_len; bool ip_proto_icmp; +uint16 checksum; + +static void sum(uint16 w) +{ + checksum += w; + if (checksum < w) /* corrección de carry (hubo OV) */ + ++checksum; +} + bool ip_read_packet_header() { - /* variable para utilitaria (iterar y/o buffer) */ - byte c; + /* variables utilitarias (iterar y/o buffer) */ + byte h, l; + /* reseteamos checksum */ + checksum = 0; /* versión y tamaño de cabecera vienen en el 1er byte */ - c = net_getb(); + h = net_getb(); /* sólo soportamos versión 4 */ - if ((c >> 4) != 4) + if ((h >> 4) != 4) return false; /* drop */ /* tamaño de cabecera */ - if ((c & 0x0F) != 5) /* no aceptamos opciones raras =) */ + if ((h & 0x0F) != 5) /* no aceptamos opciones raras =) */ return false; /* drop */ - /* ignoramos el TOS */ - net_getb(); + /* ignoramos el TOS y vamos calculando checksum */ + sum(WORD(h, net_getb())); /* obtenemos tamaño del paquete */ - if (net_getb()) /* tiene más de 255 bytes (no lo soportamos) */ + if (h = net_getb()) /* tiene más de 255 bytes (no lo soportamos) */ return false; /* drop */ ip_packet_len = net_getb(); /* hasta 255 bytes tienen los nuestros */ - /* ignoramos identificación */ - net_getb(); net_getb(); /* 2 bytes */ + /* vamos calculando checksum */ + sum(WORD(h, ip_packet_len)); + /* ignoramos identificación (2 bytes) y vamos calculando checksum */ + sum(net_getw()); /* si tiene prendido el bit de MF (More Fragments, bit 5 del byte, bit 2 * de los flags de la cabecera) o si tiene un offset de fragmento (bits * del 4 al 0 y todos los bits del byte siguiente), dropeamos (no * soportamos fragmentación) */ - if (net_getw() & 0x3FFF) + h = net_getb(); + l = net_getb(); + if ((h & 0x3F) || l) return false; /* drop */ + /* seguimos calculando checksum */ + sum(WORD(h, l)); /* no le damos bola al TTL (no le vamos a hacer lío si ya llegó hasta * acá el pobre =) */ - net_getb(); + h = net_getb(); /* protocolo (sólo soportamos UDP e ICMP) */ - switch (net_getb()) + l = net_getb(); + switch (l) { case ICMP: ip_proto_icmp = true; @@ -52,49 +70,83 @@ bool ip_read_packet_header() default: return false; /* drop */ } - /* checksum */ - net_getb(); net_getb(); /* TODO: verificar checksum */ - /* obtenemos IP de origen */ - for (c = 0; c < IP_ADDR_SIZE; ++c) - ip_addr_remote[c] = net_getb(); - /* vemos si el paquete es para nosotros (ningún soportar broadcast =) */ - for (c = 0; c < IP_ADDR_SIZE; ++c) - if (ip_addr_local[c] != net_getb()) - return false; /* no es para nosotros */ + /* sigo calculando checksum */ + sum(WORD(h, l)); + /* obtenemos checksum y seguimos el cálculo */ + sum(net_getw()); + /* obtenemos IP de origen (mientras seguimos calculando el checksum) */ + for (l = 0; l < IP_ADDR_SIZE; ++l) + { + ip_addr_remote[l] = net_getb(); + if (l % 2) + sum(WORD(h, ip_addr_remote[l])); + else + h = ip_addr_remote[l]; + } + /* vemos si el paquete es para nosotros (ningún soportar broadcast =) + * (mientras seguimos calculando el checksum) */ + for (l = 0; l < IP_ADDR_SIZE; ++l) + { + if (ip_addr_local[l] != net_getb()) + return false; /* drop (no es para nosotros) */ + if (l % 2) + sum(WORD(h, ip_addr_local[l])); + else + h = ip_addr_local[l]; + } + /* verificamos checksum */ + if (~checksum) + return false; /* checksum malo, drop */ return true; } void ip_write_packet_header() { - /* variable para iterar */ - byte i; + /* variables utilitarias (iterar y/o buffer) */ + byte h, l; /* identificador del paquete IP (incrementa con cada paquete) */ - static uint16 id = 0; + static uint16 id; + /* reseteamos checksum */ + checksum = 0; /* versión (4) y tamaño de cabecera (5 words de 4 bytes = 20 bytes) */ - net_putb(0x45); - /* TOS */ - if (ip_proto_icmp) - net_putb(0xc0); /* Precedence: Internetwork Control */ - else - net_putb(0x00); /* Precedence: Normal */ - net_getb(); + net_putb(h = 0x45); + /* TOS (0xc0 = Internetwork Control, 0x00 = normal) */ + l = ip_proto_icmp ? 0xc0 : 0x00; + net_putb(l); + sum(WORD(h, l)); /* actualizamos checksum */ /* escribimos tamaño del paquete */ - net_putb(0x00); /* nunca vamos a mandar algo de más de 255 bytes */ + net_putb(h = 0x00); /* nunca vamos a mandar algo de más de 255 bytes */ net_putb(ip_packet_len); + sum(WORD(h, ip_packet_len)); /* actualizamos checksum */ /* identificación (sirve para reensamblar paquetes) */ net_putw(id); + sum(id); /* actualizamos checksum */ /* pedimos que no se fragmente */ - net_putb(0x40); /* Don't Fragment (DF) = 1 */ - net_putb(0x00); /* offset de fragmento = 0 */ + net_putb(h = 0x40); /* Don't Fragment (DF) = 1 */ + net_putb(l = 0x00); /* offset de fragmento = 0 */ + sum(WORD(h, l)); /* actualizamos checksum */ /* TTL de 64 saltos porque está de moda */ - net_putb(0x40); + net_putb(h = 0x40); /* protocolo (sólo soportamos UDP e ICMP) */ - if (ip_proto_icmp) - net_putb(ICMP); - else - net_putb(UDP); - /* checksum */ - net_putb(0x00); net_putb(0x00); /* TODO: calcular checksum */ + l = ip_proto_icmp ? ICMP : UDP; + net_putb(l); + sum(WORD(h, l)); /* actualizamos checksum */ + /* checksum: antes de poder escribir el checksum hay que terminar de + * calcularlo según las direcciones IP de origen y destino, así que eso + * hacemos */ + for (l = 0; l < IP_ADDR_SIZE; ++l) /* origen = local */ + if (l % 2) + sum(WORD(h, ip_addr_local[l])); + else + h = ip_addr_local[l]; + for (l = 0; l < IP_ADDR_SIZE; ++l) /* destino = remota */ + if (l % 2) + sum(WORD(h, ip_addr_remote[l])); + else + h = ip_addr_remote[l]; + /* ahora sí grabamos el checksum */ + net_putw(~checksum); + /* ahora sí, continuamos poniendo las direcciones */ /* ponemos como dirección IP de origen la nuestra */ for (i = 0; i < IP_ADDR_SIZE; ++i) net_putb(ip_addr_local[i]); diff --git a/src/c/types.h b/src/c/types.h index db65dd0..52b07d1 100644 --- a/src/c/types.h +++ b/src/c/types.h @@ -4,6 +4,18 @@ /** valores posibles de un booleano */ enum { false = 0, true = 1 }; +/** convierte 2 bytes (high, low) en un word */ +#define WORD(high, low) ((high << 8) + low) + +/** convierte un word en 2 bytes */ +#define UNPACK(word, high, low) (high = (word >> 8), low = word) + +/** obtiene parte alta de un word */ +#define HIGH(word) (word >> 8) + +/** obtiene parte baja de un word */ +#define LOW(word) (word) + #if 1 /* i386 */ /** booleano */ diff --git a/src/c/udp.c b/src/c/udp.c index 1c4189e..05dcdb1 100644 --- a/src/c/udp.c +++ b/src/c/udp.c @@ -8,7 +8,7 @@ extern byte udp_dgram_len; bool udp_read_dgram_header() { - /* puerto origen */ + /* puerto origen (remoto) */ udp_port_remote = net_getw(); /* sólo aceptamos datagramas a nuestro puerto */ if (net_getw() != udp_port_local) -- 2.43.0