C#ICMPv6校验和计算

我需要计算ICMPv6校验和。 我在RFC 2460中找到了正确的手册,并在c#中编写了代码,该代码粘贴在下面。 在代码中,您可以看到我添加到校验和源IP,数据包的目标IP,而不是ICMPv6消息长度(对于Neighbor Advertisement为32字节),然后我添加下一个标头ID,即ICMPv6为58。 然后是FOR循环,它将校验和添加到整个ICMPv6消息(以我相信的消息类型开头,例如88 00 …用于邻居广告)。 比我做计算和补充校验和,但这是错误的。 我正在尝试为真正嗅探的Neighbor Advertisement计算这个校验和,它也在下面,但我无法获得相同的校验和。 我的代码可能有什么问题?

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, eg 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 > 16); return (ushort)~checksum; } 

这是包屏幕。

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

加上链接,你可以在那里下载文件,我用于测试:

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

感谢帮助。

有效载荷用于ICMPv6消息,因为它已在我的问题中发布的图片中签名

至少那是错的。 计算校验和时,应首先将表示校验和本身的字节替换为0。

更新

基于你的icmp.pcap,我创建了一个独立的程序来计算校验和。 请参阅下面的完整来源。

最重要的错误是:

  ushort checksum = 0; 

虽然校验和是16位,但此算法至少需要32位用于临时值:

  uint checksum = 0; 

校验和计算需要加法运算 ,其中加法的进位包围。 为了提高性能,所有包装都在最后完成;

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

但这只有在校验和超过16位时才有可能。 否则这条线就没用了。

但还有其他事情要考虑。 BitConverter.ToUInt16取决于处理器的字节顺序 ,可能是Little Endian。 那将是结果A5AB 。 这可能与您预期的不同,但如果切换字节,则会得到正确的版本。 我从这里插入一个函数来修复它。 这将使结果ABA5 。 另一方面,如果在计算之前未将校验和设置为0,则如果校验和有效,则ICMPchecksum将始终返回0 。 另请注意,您的函数无法处理有效负载的奇数长度。

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