如何求解网络报文中的checksum?
最近在学习计算机网络,在运输层和网络层部分存在各种协议TCP、UDP、IP、ICMP等等,而在这些报文中都存在一个公共的字段——检验和(checksum)。接下来,我将从什么是检验和、检验和怎么算、检验和计算示例、python代码计算检验和这几个部分详细介绍。
什么是检验和?
检验和是存在于各种报文中的一个字段,它存在的目的是验证报文在网络传输过程中的完整性(有的数据可能在链路传输时发生0-1数据翻转,从而导致报文出错)。因此,在报文的发送端,会根据报文中的首部或数据来计算一个检验和(IP报文的检验和只对首部进行计算,ICMP报文对报文首部和数据都进行计算),然后一旦接收端接受到相应报文,接收端也会对报文的首部或数据进行一次检验和计算,如果接收端算出来的检验和和发送端发送的不一样,那么对不起,接收端认为报文在传输过程中出了错,于是就丢掉该报文。
算法归纳
待检验部分从头开始,每16比特进行一次加法计算(如果最后有8位剩余,最后加上这8位),这样最终计算出来的和进行一次反码运算,就是检验和。
注意:如果求和过程中遇到了任何溢出,都进行回卷(即加回到最低位)
example
IP报文各字段
看完上面还迷迷糊糊的?没关系,在这里,就以IP报文为例,介绍更多的细节。首先,还是先把IP报文的各个字段信息回顾一下,如下图。如果你看到这个,有些字段忘记了它的意思,就百度回忆一下吧,这里我就不多说了。
IP首部检验和示例
现在假设有一个IP报文的首部如下所示(都是16进制数):
4500 003c 1c46 4000 4006 b1e6 ac10 0a63 ac10 0a0c
ok,我们将这个报文的各个字段一一来匹配一下
45 —— 对应IP首部前8位,4是version字段,表示IPV4,5是首部长度字段,但注意,首部长度是以每4个字节为1个单位的,所以这里就是5*4=20个字节 (这也说明IP报文首部的option字段和padding字段没用上)
00 —— 对应服务类型(TOS,type of service)字段,00表明是正常操作
003C —— 对应total length字段,说明改IP报文首部加数据段一共是60字节(也就是说,数据段部分占了40字节)
1C46 —— 对应报文标识符字段
4000 —— 对应flags和fragment offset字段,其中flag字段占3位,分片偏移占13位
40 —— 对应TTL字段(Time to live),表明该报文可以经过40跳(hops)
06 —— 对应IP报文封装的上层协议代码,这里是6,表明是TCP报文
b1e6 —— 这就是发送端即将求出来的检验和
ac10 0a63 —— 对应IP报文的源IP地址
ac10 0a0c —— 对应IP报文的目的IP地址
发送端
说明:在计算检验和字段之前,我们先把检验和的16位全部置0。
我们现在把16进制数全部转为二进制,如下:
4500 -> 0100010100000000 003c -> 0000000000111100 1c46 -> 0001110001000110 4000 -> 0100000000000000 4006 -> 0100000000000110 0000 -> 0000000000000000 // 先全部置零,最后再把算出来的结果附加上 ac10 -> 1010110000010000 0a63 -> 0000101001100011 ac10 -> 1010110000010000 0a0c -> 0000101000001100
然后我们每16位进行一次加法运算:
4500 -> 0100010100000000 003c -> 0000000000111100 453C -> 0100010100111100 // 第一次计算结果 453C -> 0100010100111100 // 第一次计算结果 加 后16位 1c46 -> 0001110001000110 6182 -> 0110000110000010 // 第二次计算结果 6182 -> 0110000110000010 // 第二次计算结果 加 后16位 4000 -> 0100000000000000 A182 -> 1010000110000010 // 第三次计算结果 A182 -> 1010000110000010 // 第三次计算结果 加 后16位 4006 -> 0100000000000110 E188 -> 1110000110001000 E188 -> 1110000110001000 AC10 -> 1010110000010000 18D98 -> 11000110110011000 // 这里产生了一次溢出,根据回卷规则,把溢出位加到最后 18D98 -> 11000110110011000 8D99 -> 1000110110011001 // 进行类似16位加法。。。就不再重述了 8D99 -> 1000110110011001 0A63 -> 0000101001100011 97FC -> 1001011111111100 97FC -> 1001011111111100 AC10 -> 1010110000010000 1440C -> 10100010000001100 // 由产生了进位,继续回卷 1440C -> 10100010000001100 440D -> 0100010000001101 440D -> 0100010000001101 0A0C -> 0000101000001100 4E19 -> 0100111000011001
Well,终于加完了,别急还没完!!!还要求一次反码,别忘了哈~~
4E19 -> 0100111000011001 B1E6 ->1011000111100110 // 检验和
好了,这样我们再把b1e6这个检验和放进到IP报文的checksum字段,检验的工作也就此完成。
接收端
接收端就比较简单了,把所有的二进制位每16位进行一次加法,最后求一次补码(同样也要溢出回卷),如果结果全部是1,那就稳了,没出错;只要有一位是0,那就说明出现了错误。