藤和艾莉欧壁纸:文章 IPv4、TCP和UDP的校验和计算

来源:百度文库 编辑:九乡新闻网 时间:2024/05/02 21:19:31

分组头的校验和 (checksum) 算法是 16 位 累加和后的反码, TCP 和 UDP 数据报头也使用相同的校验算法,但参与运算的数据与 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 分组(数据连路层 DLC 的包)来演示整个计算过程:

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 帧 (DLC 包 ) 的开头。 IPv4 分组头从地址偏移量 0x000e开始,第一个字节为 0x45 ,最后一个字节为 0xe9 ,即 IPv4 分组头到目标 IP 地址为止。根据以上的算法描述,我们可以作如下计算:

(1) 0x4500 + 0x001c + 0x7468 + 0x0000 + 0x8011 + 0x0000( 累加和位置先置0) + 0xc0a8 + 0x6401 + 0xab46 + 0x9ce9 = 0x3a66d

(2) 0xa66d + 0x3 = 0xa670

(3) 0xffff - 0xa670 = 0x598f

注意在第一步我们用 0x0000设置头校验和部分。可以看出这一分组头的校验和与收到的值完全一致。以上的过程仅用于发送方计算初始的校验和,实际中对于中间转发的路由器和最终接收方,可将收到的 IPv4 分组头校验和部分直接按同样算法相加,如果结果为 0xffff ,则校验正确。

对于 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) 。上述报文在0x0018 处的协议类型 = 十六进制 11 ,即该报文是一个 UDP 报文,其长度存放在 0x0027 开始的两个字节 ( 含源目端口地址4 字节 +UDP 长度 2 字节 + 校验和 2 字节 =8 字节,以及 UDP 数据的长度:故本数据包 UDP 数据的长度实际为 0 字节) , IP 源目地址存放在 0x0x1a 到 0x0x21 共八个字节中,先将校验和 0x002a 处的两个字节置 0 ,计算 UDP包的校验 和如下:

(1) 0xc0a8+0x6401( 前为源IP)+0xab46+ 0x9ce9 ( 前为目IP)+0x0011( 即Zero和Protocol)+ 0x0008(UDP 长度)+ 0x0f3a( 源端口)+0x0405( 目端口)+0x0008(UDP长度)+0x0000 (校验和预置为0 )+…( 这里没有任何数据了:UDP 数据的长度实际为0 字节)=0x2803 8

(2) 0x28038=>0x8038+0x0002=0x803A

(3) 0xFFFF-0x803A=0x7FC5

计算结果和 0x0028 处的结果相同,注意 UDP 长度出现了两次。