当前位置: 代码迷 >> 综合 >> IPv4、TCP和UDP的校验和计算
  详细解决方案

IPv4、TCP和UDP的校验和计算

热度:96   发布时间:2024-01-09 09:56:13.0

分组头的校验和(checksum)算法是16累加和后的反码,TCPUDP数据报头也使用相同的校验算法,但参与运算的数据与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 01
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type ofService| TotalLength |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | HeaderChecksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SourceAddress |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| DestinationAddress |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

其中的"Header Checksum"域即为头校验和部分。当要计算IPv4分组头校验和时,发送方先将其置为0,然后按16位逐一累加至IPv4分组头结束,累加和保存于一个32位的数值中。如果总的字节数为奇数,则最后一个字节单独相加。累加完毕将结果中高16位再加到低16位上,重复这一过程直到高16位为全0。下面用实际截获的IPv4分组(数据连路层DLC的包)来演示整个计算过程:

0x0000: 00 60 47 41 11 c900 09 6b 7a 5b 3b 0800 45 00
0x0010: 00 1c 74 68 0000 80 11 59 8f c0 a8 64 01 ab 46
0x0020: 9c e9 0f 3a04 05 00 08 7f c5 00 0000 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,则校验正确。

对于TCPUDP的数据报,其头部也包含16位的校验和,校验算法与IPv4分组头完全一致,但参与校验的数据不同。这时校验和不仅包含整个TCP/UDP数据报,还覆盖了一个虚头部。虚头部的定义如下:

0 7 8 1516 23 24 31
+--------+--------+--------+--------+
| sourceaddress |
+--------+--------+--------+--------+
| destinationaddress |
+--------+--------+--------+--------+
| zero |protocol| TCP/UDP length |
+--------+--------+--------+--------+

其中有IP源地址,IP目的地址,协议号(TCP:6/UDP:17)TCPUDP数据报的总长度(头部+数据)。将虚头部加入校验的目的,是为了再次核对数据报是否到达正确的目的地,并防止IP欺骗攻击(spoofing)。上述报文在0x0018处的协议类型=十六进制11,即该报文是一个UDP报文,其长度存放在0x0027开始的两个字节(含源目端口地址4字节+UDP长度2字节+校验和2字节=8字节,以及UDP数据的长度:故本数据包UDP数据的长度实际为0字节)IP源目地址存放在0x0x1a0x0x21共八个字节中,先将校验和0x002a处的两个字节置0,计算UDP的校验和如下:

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

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

(3) 0xFFFF-0x803A=0x7FC5

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

  相关解决方案