C#的ICMPv6校验和计算 [英] C# ICMPv6 checksum calculation

查看:200
本文介绍了C#的ICMPv6校验和计算的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要计算的ICMPv6校验和。我已经找到正确的手册中的RFC 2460和C#,下面粘贴编写的代码。在代码中你可以看到,我将添加到校验和源IP,数据包的目的IP,比ICMPv6的消息长度(这是邻居广告32字节),然后我添加一个报头ID是58的ICMPv6。再有就是FOR循环,这更增加了整个校验ICMPv6的消息(消息类型,我相信,例如88 00开始......对于邻居通告)。比我做的计算和校验的补充,但它是错误的。我试图计算这个校验真正嗅到邻居通告,也低于,但我不能得到相同的校验。什么可能是错在我的代码?

 静态无效的主要(字串[] args)
{

ICaptureDevice设备=新OfflineCaptureDevice(icmp.pcap);
device.Open();

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


Console.ReadKey();
}

私有静态无效device_OnPacketArrival(对象发件人,SharpPcap.CaptureEventArgs E)
{

{
//数据包转换
VAR包= PacketDotNet.Packet.ParsePacket(e.Packet);
变种ethernetPacket =((PacketDotNet.EthernetPacket)数据包);
INT dlzka_packetu = e.Packet.Data.Length;
串ETH = BitConverter.ToString(ethernetPacket.Bytes);

//现在它的字符串字段格式 - 一根弦产品一个字节,例如FF
的String [] = eth_final2 eth.Split(' - ');
的foreach(在eth_final2字符串的字节){Console.Write(字节+); }
Console.WriteLine();

//取出源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]);

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

串icmp_payload =;

//取出的ICMPv6消息
的for(int i = 54; I< 54 + 32;我++)
{
如果(我== 56 | |我== 57){icmp_payload + =00; }
,否则icmp_payload + = eth_final2 [I]
}

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


//调用函数ICMPchecksum
USHORT总和= ICMPchecksum(src_ip.GetAddressBytes(),dst_ip.GetAddressBytes(),BitConverter.GetBytes(icmpv6_length),BitConverter.GetBytes( next_header),icmp_bytes);

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


}
赶上(异常前)
{
Console.WriteLine(ERROR);
}


}

静态的byte [] GetStringToBytes(字符串值)
{
SoapHexBinary SHB = SoapHexBinary.Parse (值);
返回shb.Value;
}

静态USHORT ICMPchecksum(字节[] src_ip,字节[] dst_ip,字节[]长度字节旁边的[],字节[]负载)
{
USHORT校验= 0;

//字节字段长度
Console.WriteLine(src_ip:+ src_ip.Length +dst_ip:+ dst_ip.Length +长:+ length.Length +next_header: + next.Length +有效载荷:+ payload.Length);

//显示所有字段,将用于校验和计算
Console.WriteLine(BitConverter.ToString(src_ip));
Console.WriteLine(BitConverter.ToString(dst_ip));
Console.WriteLine(BitConverter.ToString(长度));
Console.WriteLine(BitConverter.ToString(下));
Console.WriteLine(BitConverter.ToString(有效负载));


//添加源IPv6地址
校验+ = BitConverter.ToUInt16(src_ip,0);
校验+ = BitConverter.ToUInt16(src_ip,2);
校验+ = BitConverter.ToUInt16(src_ip,4);
校验+ = BitConverter.ToUInt16(src_ip,6);
校验+ = BitConverter.ToUInt16(src_ip,8);
校验+ = BitConverter.ToUInt16(src_ip,10);
校验+ = BitConverter.ToUInt16(src_ip,12);
校验+ = BitConverter.ToUInt16(src_ip,14);

//添加DEST IPv6地址
校验+ = BitConverter.ToUInt16(dst_ip,0);
校验+ = BitConverter.ToUInt16(dst_ip,2);
校验+ = BitConverter.ToUInt16(dst_ip,4);
校验+ = BitConverter.ToUInt16(dst_ip,6);
校验+ = BitConverter.ToUInt16(dst_ip,8);
校验+ = BitConverter.ToUInt16(dst_ip,10);
校验+ = BitConverter.ToUInt16(dst_ip,12);
校验+ = BitConverter.ToUInt16(dst_ip,14);

//添加的ICMPv6包
校验长度+ = BitConverter.ToUInt16(长度,0);
校验+ = BitConverter.ToUInt16(长度,2);

//添加一个报头ID = 58
校验+ = BitConverter.ToUInt16(NEXT,0);
校验+ = BitConverter.ToUInt16(下,2);

//添加全ICMPv6的消息
的for(int i = 0; I< payload.Length; I = I + 2)
{
Console.WriteLine (一世);
校验+ = BitConverter.ToUInt16(有效载荷,I);
}

校验+ =(USHORT)和(checksum>> 16);

回报(USHORT)〜校验;
}



这里是包屏幕。



只有链接: http://img831.imageshack.us/img831/7237 /icmpv6.png



加的链接,在这里你可以下载文件,我使用的测试:



http://www.2shared.com/file/wIETWTWB/icmp。 HTML



感谢您的帮助。


解决方案

有效载荷使用的ICMPv6消息,因为它是在图片签我已经张贴在我的问题。




目前至少这是错误的。当你计算校验和,则应更换代表校验本身0第一个字节。



更新



根据您的icmp.pcap我创建了一个独立的程序来计算校验和。 。请参见下面的完整的源代码



最重要的错误是:



  USHORT校验= 0; 



虽然校验和是16位的,该算法需要临时值至少32位:

  UINT校验= 0; 



校验和计算需要的一补数算术,其中加法的进位回绕。为了提高性能,所有的包装是在年底完成;

 校验+ =(USHORT)和(checksum>> 16) ; 



不过,这只是可能的,如果校验有超过16位。否则,这条线将是无用的。



但有别的东西把帐户。该BitConverter.ToUInt16取决于你的处理器,这可能是小端的字节顺序。这将使结果 A5AB 。这可能不是你期望的,但如果切换字节,你会得到正确的版本。我从插入的这里解决这个问题。这将使结果 ABA5 。在另一方面,如果不计算之前设置校验和为0,ICMPchecksum总会返回0,如果校验是有效的。还注意,功能不能处理有效载荷的奇数长度。

 类节目{
静态无效的主要(字串[] args)
{
字节[] src_ip =新的字节[]
{
0xFE的,0x80的,为0x00,0x00时,为0x00,0x00时,为0x00,0x00时,
0X02,的0x19,将0x55,0xFF的,0xFE时,0×27,0×27 ,0xd0
};

的byte [] dst_ip =新的字节[]
{
0xFE的,0x80的,为0x00,0x00时,为0x00,0x00时,为0x00,0x00时,
0X02,0x22, 0x75,0xFF的,0xFE时,0xd6,0xFE时,为0x50
};
的byte []长度=新的字节[] {0,0,0,32};
字节旁边的[] =新的字节[] {0,0,0,58};
的byte []负载=新的字节[]
{
均为0x88,0x00时,是0xAB,0xA5的,0xe0的,0×00,0×00,0×00,
0xFE的,0x80的,为0x00,0x00时, 0×00,0×00,0×00,0×00,
0X02,的0x19,将0x55,0xFF的,0xFE时,0×27,×27,0xd0,
0X02,为0x01,0x00时的0x19,将0x55,0×27,×27,0xd0
};
的#if真
净荷[2] = 0;
净荷[3] = 0;
#ENDIF

USHORT校验= ICMPchecksum(src_ip,dst_ip,长度,下,负载);

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

公共静态USHORT BitConverterToUInt16(字节[]的价值,诠释了startIndex)
{
#如果假
返回System.BitConverter.ToUInt16(价值,则startIndex);
的#else
返回System.BitConverter.ToUInt16(value.Reverse().ToArray(),value.Length - 的sizeof(UINT16) - 的startIndex);
#ENDIF
}

静态USHORT ICMPchecksum(字节[] src_ip,字节[] dst_ip,字节[]长度字节旁边的[],字节[]负载)
{
UINT校验= 0;

//字节字段长度
Console.WriteLine(src_ip:+ src_ip.Length +dst_ip:+ dst_ip.Length +长:+ length.Length + next_header:+ next.Length +有效载荷:+ payload.Length);

//显示所有字段,将用于校验和计算
Console.WriteLine(BitConverter.ToString(src_ip));
Console.WriteLine(BitConverter.ToString(dst_ip));
Console.WriteLine(BitConverter.ToString(长度));
Console.WriteLine(BitConverter.ToString(下));
Console.WriteLine(BitConverter.ToString(有效负载));


//添加源IPv6地址
校验+ = BitConverterToUInt16(src_ip,0);
校验+ = BitConverterToUInt16(src_ip,2);
校验+ = BitConverterToUInt16(src_ip,4);
校验+ = BitConverterToUInt16(src_ip,6);
校验+ = BitConverterToUInt16(src_ip,8);
校验+ = BitConverterToUInt16(src_ip,10);
校验+ = BitConverterToUInt16(src_ip,12);
校验+ = BitConverterToUInt16(src_ip,14);

//添加DEST IPv6地址
校验+ = BitConverterToUInt16(dst_ip,0);
校验+ = BitConverterToUInt16(dst_ip,2);
校验+ = BitConverterToUInt16(dst_ip,4);
校验+ = BitConverterToUInt16(dst_ip,6);
校验+ = BitConverterToUInt16(dst_ip,8);
校验+ = BitConverterToUInt16(dst_ip,10);
校验+ = BitConverterToUInt16(dst_ip,12);
校验+ = BitConverterToUInt16(dst_ip,14);

//添加的ICMPv6包
校验长度+ = BitConverterToUInt16(长度,0);
校验+ = BitConverterToUInt16(长度,2);

//添加一个报头ID = 58
校验+ = BitConverterToUInt16(NEXT,0);
校验+ = BitConverterToUInt16(下,2);

//添加全ICMPv6的消息
的for(int i = 0; I< payload.Length; I = I + 2){
Console.WriteLine(一);
校验+ = BitConverterToUInt16(有效载荷,I);
}

校验+ =(USHORT)和(checksum>> 16);

回报(USHORT)〜校验;
}
}


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.

解决方案

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;
    }
}

这篇关于C#的ICMPv6校验和计算的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆