C# ICMPv6 checksum calculation

吃可爱长大的小学妹 提交于 2019-12-23 02:59:10

问题


I need to compute ICMPv6 checksum. I have found correct manual in RFC 2460 and written code in c#, which is pasted below. In a code you can see that i add to checksum source IP, destination IP of packet, than ICMPv6 message length (which is 32 bytes for Neighbor Advertisement) and then i add next header ID which is 58 for ICMPv6. Then there is FOR cycle, which adds to checksum whole ICMPv6 message (which starts with message type i believe, e.g. 88 00 ... for Neighbor advertisement). Than i made calculations and complements checksum, but it's wrong. I am trying to compute this checksum for real sniffed Neighbor Advertisement, which is also below, but i can't get the same checksum. What could be wrong in my code?

static void Main(string[] args)
    {

        ICaptureDevice device = new OfflineCaptureDevice("icmp.pcap");
        device.Open();

        device.OnPacketArrival += new SharpPcap.PacketArrivalEventHandler(device_OnPacketArrival);
        device.Capture();


        Console.ReadKey();
    }

    private static void device_OnPacketArrival(object sender, SharpPcap.CaptureEventArgs e)
    {
        try
        {
            //packet conversions
            var packet = PacketDotNet.Packet.ParsePacket(e.Packet);
            var ethernetPacket = ((PacketDotNet.EthernetPacket)packet);
            int dlzka_packetu = e.Packet.Data.Length;
            string eth = BitConverter.ToString(ethernetPacket.Bytes);

            //now its in string field format - one string item is one byte, e.g. FF
            string[] eth_final2 = eth.Split('-');
            foreach (string bytes in eth_final2) { Console.Write(bytes + " "); }
            Console.WriteLine();

            //taking out source IP
            IPAddress src_ip = IPAddress.Parse(eth_final2[22]+eth_final2[23]+":"+eth_final2[24]+eth_final2[25]+":"+eth_final2[26]+eth_final2[27]+":"+eth_final2[28]+eth_final2[29]+":"+eth_final2[30]+eth_final2[31]+":"+eth_final2[32]+eth_final2[33]+":"+eth_final2[34]+eth_final2[35]+":"+eth_final2[36]+eth_final2[37]);

            //destination IP
            IPAddress dst_ip = IPAddress.Parse(eth_final2[38] + eth_final2[39] + ":" + eth_final2[40] + eth_final2[41] + ":" + eth_final2[42] + eth_final2[43] + ":" + eth_final2[44] + eth_final2[45] + ":" + eth_final2[46] + eth_final2[47] + ":" + eth_final2[48] + eth_final2[49] + ":" + eth_final2[50] + eth_final2[51] + ":" + eth_final2[52] + eth_final2[53]);

            Console.WriteLine(src_ip);
            Console.WriteLine(dst_ip);
            int icmpv6_length = 32;
            int next_header = 58;
            Console.WriteLine();

            string icmp_payload = "";

            //taking out ICMPv6 message
            for (int i = 54; i < 54 + 32; i++)
            {
                if (i == 56 || i == 57) { icmp_payload += "00"; }
                else icmp_payload += eth_final2[i];
            }

            Console.WriteLine(icmp_payload);
            byte[] icmp_bytes = GetStringToBytes(icmp_payload);


            //CALLING THE FUNCTION ICMPchecksum
            ushort sum = ICMPchecksum(src_ip.GetAddressBytes(), dst_ip.GetAddressBytes(), BitConverter.GetBytes(icmpv6_length), BitConverter.GetBytes(next_header), icmp_bytes);

            Console.WriteLine(sum.ToString("X"));


        }
        catch (Exception ex)
        {
            Console.WriteLine("ERROR");
        }


    }

    static byte[] GetStringToBytes(string value)
    {
        SoapHexBinary shb = SoapHexBinary.Parse(value);
        return shb.Value;
    }

    static ushort ICMPchecksum(byte[] src_ip, byte[] dst_ip, byte[] length, byte[] next, byte[] payload)
    {
        ushort checksum = 0;

        //length of byte fields
        Console.WriteLine("src_ip: "+src_ip.Length+" dst_ip: "+dst_ip.Length+" length: "+length.Length+" next_header: "+next.Length+" payload: "+payload.Length);

        //display all fields, which will be used for checksum calculation
        Console.WriteLine(BitConverter.ToString(src_ip));
        Console.WriteLine(BitConverter.ToString(dst_ip));
        Console.WriteLine(BitConverter.ToString(length));
        Console.WriteLine(BitConverter.ToString(next));
        Console.WriteLine(BitConverter.ToString(payload));


        //ADDS SOURCE IPv6 address
        checksum += BitConverter.ToUInt16(src_ip, 0);
        checksum += BitConverter.ToUInt16(src_ip, 2);
        checksum += BitConverter.ToUInt16(src_ip, 4);
        checksum += BitConverter.ToUInt16(src_ip, 6);
        checksum += BitConverter.ToUInt16(src_ip, 8);
        checksum += BitConverter.ToUInt16(src_ip, 10);
        checksum += BitConverter.ToUInt16(src_ip, 12);
        checksum += BitConverter.ToUInt16(src_ip, 14);

        //ADDS DEST IPv6 address
        checksum += BitConverter.ToUInt16(dst_ip, 0);
        checksum += BitConverter.ToUInt16(dst_ip, 2);
        checksum += BitConverter.ToUInt16(dst_ip, 4);
        checksum += BitConverter.ToUInt16(dst_ip, 6);
        checksum += BitConverter.ToUInt16(dst_ip, 8);
        checksum += BitConverter.ToUInt16(dst_ip, 10);
        checksum += BitConverter.ToUInt16(dst_ip, 12);
        checksum += BitConverter.ToUInt16(dst_ip, 14);

        //ADDS LENGTH OF ICMPv6 packet
        checksum += BitConverter.ToUInt16(length, 0);
        checksum += BitConverter.ToUInt16(length, 2);

        //ADDS NEXT HEADER ID = 58
        checksum += BitConverter.ToUInt16(next, 0);
        checksum += BitConverter.ToUInt16(next, 2);

        //ADDS WHOLE ICMPv6 message
        for (int i = 0; i < payload.Length; i = i + 2)
        {
            Console.WriteLine(i);
            checksum += BitConverter.ToUInt16(payload, i);
        }

        checksum += (ushort)(checksum >> 16);

        return (ushort)~checksum;
    }

And here is packet screen.

only link : http://img831.imageshack.us/img831/7237/icmpv6.png

plus the link, where you can download the file, i am using for testing:

http://www.2shared.com/file/wIETWTWB/icmp.html

Thanks for help.


回答1:


a payload is used the ICMPv6 message, as it is signed in picture i have posted in my question

At least that is wrong. when you calculate the checksum, you should replace the bytes representing the checksum itself with 0 first.

Update

Based on your icmp.pcap I have created a standalone program to calculate the checksum. See below for the full source.

The most important error is:

    ushort checksum = 0;

Although the checksum is 16-bit, this algorithm requires at least 32-bits for temporary values:

    uint checksum = 0;

The checksum calculation requires ones' complement arithmetic where the carry of an addition wraps around. To improve performance, all wrapping is done at the end;

checksum += (ushort)(checksum >> 16);

But that is only possible if checksum has more than 16 bits. Otherwise this line would be useless.

But there is something else to take in account. The BitConverter.ToUInt16 depends on the endianness of your processor, which is probably Little Endian. That will make the result A5AB. Which is probably not as you expect, but if you switch bytes, you get the correct version. I inserted a function from here to fix that. That will make the result ABA5. On the other hand, if you don't set the checksum to 0 before the calculation, the ICMPchecksum will always return 0 if the checksum is valid. Also note that your function cannot handle a odd length of the payload.

class Program {
    static void Main (string [] args)
    {
        byte[] src_ip = new byte[]
                            {
                                0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                0x02, 0x19, 0x55, 0xff, 0xfe, 0x27, 0x27, 0xd0
                            };

        byte[] dst_ip = new byte[]
                            {
                                0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                0x02, 0x22, 0x75, 0xff, 0xfe, 0xd6, 0xfe, 0x50
                            };
        byte[] length = new byte[] {0, 0, 0, 32};
        byte [] next = new byte [] { 0, 0, 0, 58 };
        byte[] payload = new byte[]
                             {
                                 0x88, 0x00, 0xab, 0xa5, 0xe0, 0x00, 0x00, 0x00, 
                                 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                 0x02, 0x19, 0x55, 0xff, 0xfe, 0x27, 0x27, 0xd0,
                                 0x02, 0x01, 0x00, 0x19, 0x55, 0x27, 0x27, 0xd0
                             };
#if true
        payload [2] = 0;
        payload [3] = 0;
#endif

        ushort checksum = ICMPchecksum(src_ip, dst_ip, length, next, payload);

        Console.WriteLine (checksum.ToString ("X"));
        Console.ReadKey ();
    }

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

    static ushort ICMPchecksum (byte [] src_ip, byte [] dst_ip, byte [] length, byte [] next, byte [] payload)
    {
        uint checksum = 0;

        //length of byte fields
        Console.WriteLine ("src_ip: " + src_ip.Length + " dst_ip: " + dst_ip.Length + " length: " + length.Length + " next_header: " + next.Length + " payload: " + payload.Length);

        //display all fields, which will be used for checksum calculation
        Console.WriteLine (BitConverter.ToString (src_ip));
        Console.WriteLine (BitConverter.ToString (dst_ip));
        Console.WriteLine (BitConverter.ToString (length));
        Console.WriteLine (BitConverter.ToString (next));
        Console.WriteLine (BitConverter.ToString (payload));


        //ADDS SOURCE IPv6 address
        checksum += BitConverterToUInt16 (src_ip, 0);
        checksum += BitConverterToUInt16 (src_ip, 2);
        checksum += BitConverterToUInt16 (src_ip, 4);
        checksum += BitConverterToUInt16 (src_ip, 6);
        checksum += BitConverterToUInt16 (src_ip, 8);
        checksum += BitConverterToUInt16 (src_ip, 10);
        checksum += BitConverterToUInt16 (src_ip, 12);
        checksum += BitConverterToUInt16 (src_ip, 14);

        //ADDS DEST IPv6 address
        checksum += BitConverterToUInt16 (dst_ip, 0);
        checksum += BitConverterToUInt16 (dst_ip, 2);
        checksum += BitConverterToUInt16 (dst_ip, 4);
        checksum += BitConverterToUInt16 (dst_ip, 6);
        checksum += BitConverterToUInt16 (dst_ip, 8);
        checksum += BitConverterToUInt16 (dst_ip, 10);
        checksum += BitConverterToUInt16 (dst_ip, 12);
        checksum += BitConverterToUInt16 (dst_ip, 14);

        //ADDS LENGTH OF ICMPv6 packet
        checksum += BitConverterToUInt16 (length, 0);
        checksum += BitConverterToUInt16 (length, 2);

        //ADDS NEXT HEADER ID = 58
        checksum += BitConverterToUInt16 (next, 0);
        checksum += BitConverterToUInt16 (next, 2);

        //ADDS WHOLE ICMPv6 message
        for (int i = 0; i < payload.Length; i = i + 2) {
            Console.WriteLine (i);
            checksum += BitConverterToUInt16 (payload, i);
        }

        checksum += (ushort)(checksum >> 16);

        return (ushort)~checksum;
    }
}


来源:https://stackoverflow.com/questions/10042069/c-sharp-icmpv6-checksum-calculation

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!