Estoy trabajando en un programa de espacio de usuario Linux que recibe paquetes de publicidad de enrutador IPv6. Como parte de RFC4861, necesito verificar la suma de comprobación ICMPv6. Basado en mi investigación, la mayoría de los cuales se refiere a la suma de comprobación de IP en general si calcula los complementos de suma de comprobación del pseudo encabezado de IPv6 y el contenido del paquete el resultado debe ser 0xffff. Pero sigo obteniendo una suma de comprobación de 0x3fff.¿Cómo valido la suma de comprobación ICMPv6? (¿Por qué sigo recibiendo una suma de comprobación de 0x3fff?)
¿Hay algún problema con la implementación de mi suma de comprobación? ¿el kernel de Linux verifica la suma de comprobación de ICMPv6 antes de pasar los paquetes al espacio de usuario? ¿Existe una buena fuente de referencia para los buenos paquetes ICMPv6 conocidos para probar?
uint16_t
checksum(const struct in6_addr *src, const struct in6_addr *dst, const void *data, size_t len) {
uint32_t checksum = 0;
union {
uint32_t dword;
uint16_t word[2];
uint8_t byte[4];
} temp;
// IPv6 Pseudo header source address, destination address, length, zeros, next header
checksum += src->s6_addr16[0];
checksum += src->s6_addr16[1];
checksum += src->s6_addr16[2];
checksum += src->s6_addr16[3];
checksum += src->s6_addr16[4];
checksum += src->s6_addr16[5];
checksum += src->s6_addr16[6];
checksum += src->s6_addr16[7];
checksum += dst->s6_addr16[0];
checksum += dst->s6_addr16[1];
checksum += dst->s6_addr16[2];
checksum += dst->s6_addr16[3];
checksum += dst->s6_addr16[4];
checksum += dst->s6_addr16[5];
checksum += dst->s6_addr16[6];
checksum += dst->s6_addr16[7];
temp.dword = htonl(len);
checksum += temp.word[0];
checksum += temp.word[1];
temp.byte[0] = 0;
temp.byte[1] = 0;
temp.byte[2] = 0;
temp.byte[3] = 58; // ICMPv6
checksum += temp.word[0];
checksum += temp.word[1];
while (len > 1) {
checksum += *((const uint16_t *)data);
data = (const uint16_t *)data + 1;
len -= 2;
}
if (len > 0)
checksum += *((const uint8_t *)data);
printf("Checksum %x\n", checksum);
while (checksum >> 16 != 0)
checksum = (checksum & 0xffff) + (checksum >> 16);
checksum = ~checksum;
return (uint16_t)checksum;
}
¿funciona en una máquina endian grande o pequeña? – Alnitak
Little endian (x86_64), pero desde lo que he leído verificando la suma de comprobación debe ser endian independiente. – dlundquist
+1, simplemente para "Basado en mi investigación" – Flexo