2

I'm trying to calculate the checksum of an ICMPv6 packet in C#. I followed the suggestions posted here but there still seems to be a slight difference.

This is how I'm calculating the checksum:

        //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();

The Utilities.BitConverterToUint16 method:

    public static ushort BitConverterToUInt16(byte[] value, int startIndex) {
        return BitConverter.ToUInt16(value.Reverse().ToArray(),
          value.Length - sizeof(UInt16) - startIndex);
    }

Wireshark's opinion on this: Checksum: 0x4201 [incorrect, should be 0x4209]

What am I missing?

Edit: Note: Utilities.BitConverterToUInt16 retrieves the next 2 bytes (16 bits). The post I referenced uses 4 bytes (32 bits) for the payload length, even though the field is 2 bytes long. I don't know why the other post is using 4 bytes, that's why I'm so confused.

Edit2: Ok I've searched pretty much everywhere and was unable to identify the problem.

  • From wiki: The checksum is calculated starting with a pseudo-header of IPv6 header fields according to the IPv6 standard, which consists of the source and destination addresses, the packet length and the next header field, the latter of which is set to the value 58. Following this pseudo header, the checksum is continued with the ICMPv6 message in which the checksum is initially set to zero.
  • From ietf: The checksum is the 16-bit one's complement of the one's complement sum of the entire ICMPv6 message starting with the ICMPv6 message type field, prepended with a "pseudo-header" of IPv6 header fields
  • From this question: "...This is unnecessary. len is always 16-bit." "...The constant is always 00 00 00 58, so just add 58."

This is driving me mad. Again, I'd greatly appreciate it if someone could point me to the right direction. I absolutely have no clue on why the checksum is wrong. Thanks again.

Edit3: Not sure if this is helpful but it seems that the checksum is always by 8 smaller (even if I change all the values such as IP addresses in the IPv6 header).

Community
  • 1
  • 1
Orestis P.
  • 805
  • 7
  • 27
  • The part adding the length and the header looks certainly different in the link you've posted. – istepaniuk Mar 30 '13 at 13:47
  • Utilities.BitConverterToUInt16 retrieves the next 2 bytes (16 bits). The post I referenced uses 4 bytes (32 bits), even though the field is 2 bytes long. I don't know why the other post is using 4 bytes, that's why I'm so confused. – Orestis P. Mar 30 '13 at 18:19

0 Answers0