我正在尝试在C#中计算 ICMPv6 数据包的校验和。我遵循了此处发布的建议,但似乎仍然存在细微差别。
这就是我计算校验和的方式:
//Note: Initial checksum in payload is set to 0x00, 0x00
//Add ip source bytes (16 bytes)
checksum += Utilities.BitConverterToUInt16(IpV6SourceBytes, 0);
checksum += Utilities.BitConverterToUInt16(IpV6SourceBytes, 2);
checksum += Utilities.BitConverterToUInt16(IpV6SourceBytes, 4);
checksum += Utilities.BitConverterToUInt16(IpV6SourceBytes, 6);
checksum += Utilities.BitConverterToUInt16(IpV6SourceBytes, 8);
checksum += Utilities.BitConverterToUInt16(IpV6SourceBytes, 10);
checksum += Utilities.BitConverterToUInt16(IpV6SourceBytes, 12);
checksum += Utilities.BitConverterToUInt16(IpV6SourceBytes, 14);
//Add ip destination bytes (16 bytes)
checksum += Utilities.BitConverterToUInt16(IpV6DestinationBytes, 0);
checksum += Utilities.BitConverterToUInt16(IpV6DestinationBytes, 2);
checksum += Utilities.BitConverterToUInt16(IpV6DestinationBytes, 4);
checksum += Utilities.BitConverterToUInt16(IpV6DestinationBytes, 6);
checksum += Utilities.BitConverterToUInt16(IpV6DestinationBytes, 8);
checksum += Utilities.BitConverterToUInt16(IpV6DestinationBytes, 10);
checksum += Utilities.BitConverterToUInt16(IpV6DestinationBytes, 12);
checksum += Utilities.BitConverterToUInt16(IpV6DestinationBytes, 14);
//Add length (2 bytes) - tested, value is correct (32 for {0x00, 0x20})
checksum += Utilities.BitConverterToUInt16(ip6.PayloadLength, 0);
//Add next-header (1 byte) - tested, value is correct (58)
checksum += (byte)ip6.NextProtocol;
//Add ICMPv6 message
for (int i = 0; i < buffer.Length; i +=2) {
checksum += Utilities.BitConverterToUInt16(buffer, i);
}
checksum += (ushort)(checksum >> 16);
checksum = (ushort)~checksum;
Console.WriteLine(checksum);
Checksum = BitConverter.GetBytes((UInt16)checksum).Reverse().ToArray();
Utilities.BitConverterToUint16方法:
public static ushort BitConverterToUInt16(byte[] value, int startIndex) {
return BitConverter.ToUInt16(value.Reverse().ToArray(),
value.Length - sizeof(UInt16) - startIndex);
}
Wireshark对此的看法: 校验和:0x4201 [不正确,应为 0x4209]
我错过了什么?
编辑:注意: Utilities.BitConverterToUInt16 检索接下来的 2 个字节(16 位)。我引用的帖子使用 4 个字节(32 位)作为有效负载长度,即使该字段是 2 个字节长。我不知道为什么其他帖子使用 4 个字节,这就是我如此困惑的原因。
Edit2:好的,我几乎到处搜索,但无法确定问题所在。
- 来自wiki: 校验和是根据IPv6标准从IPv6头域的伪头开始计算的,它由源地址和目标地址、数据包长度和下一个头域组成,后者设置为值58. 在这个伪报头之后,校验和与 ICMPv6 消息一起继续,其中校验和最初设置为零。
- 来自ietf: 校验和是整个 ICMPv6 消息的反码和的 16 位反码,以 ICMPv6 消息类型字段开头,前缀为 IPv6 标头字段的“伪标头”
- 从这个问题: “......这是不必要的。len 始终是 16 位。” “...常数总是 00 00 00 58,所以只需加上 58。”
这让我发疯。同样,如果有人能指出我正确的方向,我将不胜感激。我完全不知道为什么校验和是错误的。再次感谢。
Edit3:不确定这是否有帮助,但似乎校验和总是小 8 (即使我更改了 IPv6 标头中的所有值,例如 IP 地址)。