我正在開發一個接收IPv6路由器通告包的Linux用戶空間程序。作爲RFC4861的一部分,我需要驗證ICMPv6校驗和。基於我的研究,如果計算IPv6僞頭的恭維校驗和,並且結果應該是0xffff,那麼大多數都會引用IP校驗和。但我一直得到0x3fff的校驗和。如何驗證ICMPv6校驗和? (爲什麼我一直得到0x3fff的校驗和?)
我的校驗和執行有問題嗎?在將數據包傳遞給用戶空間之前,Linux內核是否驗證ICMPv6校驗和?是否有一個很好的參考資料來源,用於測試已知的良好ICMPv6數據包?
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;
}
這是運行在一個大的還是小的endian機器? – Alnitak
Little endian(x86_64)我讀過的驗證校驗和應該是endian獨立的。 – dlundquist
+1,僅用於「根據我的研究」 – Flexo