2

我正在尝试在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 地址)。

4

0 回答 0