C#的ICMPv6校验和计算 [英] C# ICMPv6 checksum calculation
问题描述
我需要计算的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 resultABA5
. 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屋!