解析IPv4和IPv6分组的校验和算法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
解析IPv4和IPv6分组的校验和算法
77 发表于 2005-10-26 10:02:00
关于IP分组头的校验和(checksum)算法,简单的说就是16位累加的反码运算,但具体是如何实现的,许多资料不得其详。
TCP和UDP数据报头也使用相同法,的校验算但参与运算的数据与IP分组头不一样。
此外,IPv6对校验和的运算与IPv4又有些许不同。
因此有必要对IP分组的校验和算法作全面的解析。
IPv4分组头的结构如下所示:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Version| IHL |Type of Service| Total Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identification |Flags| Fragment Offset | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time to Live | Protocol | Header Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
其中的"Header Checksum"域即为头校验和部分。
当要计算IPv4分组头校验和时,发送方先将其置为全0,然后按16位逐一累加至IPv4分组头结束,累加和保存于一个32位的数值中。
如果总的字节数为奇数,则最后一个字节单独相加。
累加完毕将结果中高16位再加到低16位上,重复这一过程直到高16位为全0。
下面用实际截获的IPv4分组来演示整个计算过程:
0x0000: 00 60 47 41 11 c9 00 09 6b 7a 5b 3b 08 00 45 00
0x0010: 00 1c 74 68 00 00 80 11 59 8f c0 a8 64 01 ab 46
0x0020: 9c e9 0f 3a 04 05 00 08 7f c5 00 00 00 00 00 00
0x0030: 00 00 00 00 00 00 00 00 00 00 00 00
在上面的16进制采样中,起始为Ethernet帧的开头。
IPv4分组头从地址偏移量0x000e开始,第一个字节为0x45,最后一个字节为0xe9。
根据以上的算法描述,我们可以作如下计算:
(1) 0x4500 + 0x001c + 0x7468 + 0x0000 + 0x8011 +
0x0000 + 0xc0a8 + 0x6401 + 0xab46 + 0x9ce9 = 0x3a66d
(2) 0xa66d + 0x3 = 0xa670
(3) 0xffff - 0xa670 = 0x598f
注意在第一步我们用0x0000设置头校验和部分。
可以看出这一分组头的校验和与收到的值完全一致。
以上的过程仅用于发送方计算初始的校验和,实际中对于中间转发的路由器和最终接收方,可将收到的IPv4分组头校验和部分直接按同样算法相加,如果结果为0xffff,则校验正确。
如何编写产生IPv4头校验和的C程序?RFC1071(Computing the Internet Checksum)给出了一个参考实现:
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
register long sum = 0;
while( count > 1 ) {
/* This is the inner loop */
sum += * (unsigned short) addr++;
count -= 2;
}
/* Add left-over byte, if any */
if( count > 0 )
sum += * (unsigned char *) addr;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
checksum = ~sum;
}
对于TCP和UDP的数据报,其头部也包含16位的校验和,校验算法与IPv4分组头完全一致,但参与校验的数据不同。
这时校验和不仅包含整个TCP/UDP数据报,还覆盖了一个虚头部。
虚头部的定义如下:
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| source address |
+--------+--------+--------+--------+
| destination address |
+--------+--------+--------+--------+
| zero |protocol| TCP/UDP length |
+--------+--------+--------+--------+
其中有IP源地址,IP目的地址,协议号(TCP:6/UDP:17)及TCP或UDP数据报的总长度(头部+数据)。
将虚头部加入校验的目的,是为了再次核对数据报是否到达正确的目的地,并防止IP欺骗攻击(spoofing)。