3 /** protocolos soportados */
4 enum { ICMP = 0x01, UDP = 0x11 };
6 byte ip_addr_local[IP_ADDR_SIZE];
8 byte ip_addr_remote[IP_ADDR_SIZE];
14 /* para calcular checksum */
17 /* agrega un word al checksum calculado */
18 static void sum(uint16 w)
21 if (checksum < w) /* corrección de carry (hubo OV) */
25 bool ip_read_packet_header()
27 /* variables utilitarias (iterar y/o buffer) */
29 /* reseteamos checksum */
31 /* versión y tamaño de cabecera vienen en el 1er byte */
33 /* sólo soportamos versión 4 */
35 return false; /* drop */
36 /* tamaño de cabecera */
37 if ((h & 0x0F) != 5) /* no aceptamos opciones raras =) */
38 return false; /* drop */
39 /* ignoramos el TOS y vamos calculando checksum */
40 sum(WORD(h, net_getb()));
41 /* obtenemos tamaño del paquete */
42 if (h = net_getb()) /* tiene más de 255 bytes (no lo soportamos) */
43 return false; /* drop */
44 ip_packet_len = net_getb(); /* hasta 255 bytes tienen los nuestros */
45 /* vamos calculando checksum */
46 sum(WORD(h, ip_packet_len));
47 /* ignoramos identificación (2 bytes) y vamos calculando checksum */
49 /* si tiene prendido el bit de MF (More Fragments, bit 5 del byte, bit 2
50 * de los flags de la cabecera) o si tiene un offset de fragmento (bits
51 * del 4 al 0 y todos los bits del byte siguiente), dropeamos (no
52 * soportamos fragmentación) */
56 return false; /* drop */
57 /* seguimos calculando checksum */
59 /* no le damos bola al TTL (no le vamos a hacer lío si ya llegó hasta
62 /* protocolo (sólo soportamos UDP e ICMP) */
70 ip_proto_icmp = false;
73 return false; /* drop */
75 /* sigo calculando checksum */
77 /* obtenemos checksum y seguimos el cálculo */
79 /* obtenemos IP de origen (mientras seguimos calculando el checksum) */
80 for (l = 0; l < IP_ADDR_SIZE; ++l)
82 ip_addr_remote[l] = net_getb();
84 sum(WORD(h, ip_addr_remote[l]));
86 h = ip_addr_remote[l];
88 /* vemos si el paquete es para nosotros (ningún soportar broadcast =)
89 * (mientras seguimos calculando el checksum) */
90 for (l = 0; l < IP_ADDR_SIZE; ++l)
92 if (ip_addr_local[l] != net_getb())
93 return false; /* drop (no es para nosotros) */
95 sum(WORD(h, ip_addr_local[l]));
99 /* verificamos checksum */
100 if ((uint16)~checksum)
101 return false; /* checksum malo, drop */
105 void ip_write_packet_header()
107 /* variables utilitarias (iterar y/o buffer) */
109 /* identificador del paquete IP (incrementa con cada paquete) */
111 /* reseteamos checksum */
113 /* versión (4) y tamaño de cabecera (5 words de 4 bytes = 20 bytes) */
115 /* TOS (0xc0 = Internetwork Control, 0x00 = normal) */
116 l = ip_proto_icmp ? 0xc0 : 0x00;
118 sum(WORD(h, l)); /* actualizamos checksum */
119 /* escribimos tamaño del paquete */
120 net_putb(h = 0x00); /* nunca vamos a mandar algo de más de 255 bytes */
121 net_putb(ip_packet_len);
122 sum(WORD(h, ip_packet_len)); /* actualizamos checksum */
123 /* identificación (sirve para reensamblar paquetes) */
125 sum(id); /* actualizamos checksum */
126 /* pedimos que no se fragmente */
127 net_putb(h = 0x40); /* Don't Fragment (DF) = 1 */
128 net_putb(l = 0x00); /* offset de fragmento = 0 */
129 sum(WORD(h, l)); /* actualizamos checksum */
130 /* TTL de 64 saltos porque está de moda */
132 /* protocolo (sólo soportamos UDP e ICMP) */
133 l = ip_proto_icmp ? ICMP : UDP;
135 sum(WORD(h, l)); /* actualizamos checksum */
136 /* checksum: antes de poder escribir el checksum hay que terminar de
137 * calcularlo según las direcciones IP de origen y destino, así que eso
139 for (l = 0; l < IP_ADDR_SIZE; ++l) /* origen = local */
141 sum(WORD(h, ip_addr_local[l]));
143 h = ip_addr_local[l];
144 for (l = 0; l < IP_ADDR_SIZE; ++l) /* destino = remota */
146 sum(WORD(h, ip_addr_remote[l]));
148 h = ip_addr_remote[l];
149 /* ahora sí grabamos el checksum */
151 /* ahora sí, continuamos poniendo las direcciones */
152 /* ponemos como dirección IP de origen la nuestra */
153 for (l = 0; l < IP_ADDR_SIZE; ++l)
154 net_putb(ip_addr_local[l]);
155 /* IP de destino, la remota */
156 for (l = 0; l < IP_ADDR_SIZE; ++l)
157 net_putb(ip_addr_remote[l]);