共计 1795 个字符,预计需要花费 5 分钟才能阅读完成。
IP 数据报首部校验和算法详解
简介
IP/ICMP/IGMP/TCP/UDP 等协议的校验和算法都是相同的,算法如下:
在发送数据时,为了计算数 IP 据报的校验和。应该按如下步骤:
- 把 IP 数据报的首部都置为 0,包括校验和字段。
- 把首部看成以 16 位为单位的数字组成,依次进行二进制反码求和。
- 把得到的结果存入校验和字段中。
在接收数据时,计算数据报的校验和相对简单,按如下步骤:
- 当接收 IP 包时,需要对报头进行确认,检查 IP 头是否有误,算法同上 2、3 步,然后判断取反的结果是否为 0,是则正确,否则有错。
生成和校验
发送方(生成)
- 将校验和字段置为 0, 然后将 IP 包头按 16 比特分成多个单元,如包头长度不是 16 比特的倍数,则用 0 比特填充到 16 比特的倍数;
- 对各个单元采用反码加法运算 (即高位溢出位会加到低位, 通常的补码运算是直接丢掉溢出的高位), 将得到的和的反码填入校验和字段;
- 发送数据包。
接收方(校验)
- 将 IP 包头按 16 比特分成多个单元,如包头长度不是 16 比特的倍数,则用 0 比特填充到 16 比特的倍数;
- 对各个单元采用反码加法运算,检查得到的和是否符合是全 1(有的实现可能对得到的和会取反码,然后判断最终值是不是全 0);
- 如果是全 1 则进行下步处理, 否则意味着包已变化从而丢弃之。需要强调的是反码和是采用高位溢出加到低位的,如 3 比特的反码和运算:
100b+101b=010b(因为 100b+101b=1001b, 高位溢出 1,其应该加到低位,即 001b+1b( 高位溢出位)=010b)
。
实例
请看我用 ominipeek 的抓包
发送方(生成)
I. 将校验和字段置为 0, 然后将 IP 包头按 16 比特分成多个
校验和 Header Checksum:0x618D 将其重置为 0X0000
将 IP 包头分段:
1. 0x4500
2. 0x0029
3. 0x44F1
4. 0x4000
5. 0x8006
6. 0x0000 -------> 这个为 Header Checksum 的值,我们前面将其重置为 0 了
7. 0xC0A8
8. 0x01AE
9. 0x4A7D
10. 0x477D
\-------------------------------------------------------
将 1 至 10 相加求出来的和为:0x29E70
II. 对各个单元采用反码加法运算(即高位溢出位会加到低位, 通常的补码运算是直接丢掉溢出的高位 ), 将得到的和的反码填入校验和字段
0x0002+0x9E70=0x9E72
0x9E72 二进制为:1001 1110 0111 0010
反码为:0110 0001 1000 1101
0110 0001 1000 1101 的 16 进制为:0x618D
看看这个 是否与 IP 包头中的 Checksum 相同
接收方(校验)
当接收到 IP 对其进行检测
I. 对各个单元采用反码加法运算,检查得到的和是否符合是全 1(有的实现可能对得到的和会取反码,然后判断最终值是不是全 0)
当收到 IP 数据局包的时候,要验证 IP 头是否正确,则可以这样进行
1. 0x4500
2. 0x0029
3. 0x44F1
4. 0x4000
5. 0x8006
6. 0x618D -------> 这个为 Header Checksum 的值
7. 0xC0A8
8. 0x01AE
9. 0x4A7D
10. 0x477D
\-------------------------------------------------------
将 1 至 10 相加求出来的和为:0x2FFD
II. 对各个单元采用反码加法运算 (即高位溢出位会加到低位, 通常的补码运算是直接丢掉溢出的高位), 将得到的和的反码填入校验和字段:
0x0002+0x0FFD=0xFFFF
0xFFFF 二进制为:1111 1111 1111 1111
1111 1111 1111 1111 反码为:0
====================================================
关于这一部的补充说明,
将 IP 包头分段:
1. 0x4500
2. 0x0029
3. 0x44F1
4. 0x4000
5. 0x8006
6. 0x0000 -------> 这个为 Header Checksum 的值,我们前面将其重置为 0 了
7. 0xC0A8
8. 0x01AE
9. 0x4A7D
10. 0x477D