我需要计算ICMPv6校验和。我在RFC2460中找到了正确的手册,并在c#中编写了代码,这些代码粘贴在下面。在代码中,您可以看到,我将校验和添加到源IP、数据包的目标IP,而不是ICMPv6消息长度(邻居通告的长度为32字节),然后添加ICMPv6的下一个报头ID ( 58 )。然后是FOR循环,它添加到校验和整个ICMPv6消息(以我相信的消息类型开始,例如88 00 ...用于邻居通告)。然后我做了计算和补码校验,但这是错误的。我正在尝试为实际嗅探的邻居通告计算此校验和,这也在下面,但我无法获得相同的校验和。我的代码中可能有什么错误?
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;
}这是数据包屏幕。
唯一链接:http://img831.imageshack.us/img831/7237/icmpv6.png
加上链接,你可以下载我用来测试的文件:
http://www.2shared.com/file/wIETWTWB/icmp.html
谢谢你的帮助。
发布于 2012-04-09 04:32:21
在ICMPv6消息中使用
有效负载,因为它在我的问题中发布的图片中进行了签名
至少这是错误的。计算校验和时,应首先将表示校验和本身的字节替换为0。
更新
基于你的icmp.pcap,我已经创建了一个独立的程序来计算校验和。完整的源代码见下文。
最重要的错误是:
ushort checksum = 0;虽然校验和为16位,但此算法要求临时值至少为32位:
uint checksum = 0;校验和计算需要ones' complement arithmetic,其中加法进位回绕。为了提高性能,所有的包装都在最后完成;
checksum += (ushort)(checksum >> 16);但这只有在校验和超过16位时才有可能。否则,这一行将是无用的。
但还有一些其他因素需要考虑。BitConverter.ToUInt16取决于处理器的endianness,可能是小端。这将使结果成为A5AB。这可能不是您所期望的,但是如果您交换字节,您将获得正确的版本。我在here中插入了一个函数来修复这个问题。这将使结果成为ABA5。另一方面,如果在计算之前没有将校验和设置为0,则如果校验和有效,则ICMPchecksum将始终为return 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;
}
}https://stackoverflow.com/questions/10042069
复制相似问题