【转载】ip icmp igmp udp tcp 检验和
转载自 https://www.cnblogs.com/embedded-linux/p/7076647.html
计算方法
二进制反码求和
先进行二进制求和,然后对和取反。对一个无符号的数,先求其反码,然后从低位到高位,按位相加,有益处则向高位进1(和一般的二进制法则一样),若最高位有进位,则向最低位进1。
关于二进制反码求和运算需要说明的一点是,先取反后相加与先相加后取反,得到的结果是一样的。
It may look awkword to use a 1's complement addition on 2's complement machines. This method however has its own benefits.
Probably the most important is that it is endian independent. Little Endian computers store hex numbers with the LSB last (Intel processors for example). Big Endian computers put the LSB first (IBM mainframes for example). When carry is added to the LSB to form the 1's complement sum (see the example) it doesn't matter if we add 03 + 01 or 01 + 03. The result is the same.
Other benefits include the easiness of checking the transmission and the checksum calculation plus a variety of ways to speed up the calculation by updating only IP fields that have changed.
优点
a、 不依赖系统是大端小端。即无论你是发送方计算机或者接收方检查校验和时,都不要调用htons或者ntohs,直接通过上面的算法就可以得到正确的结果。这个问题你可以自己举个例子,用反码求和时,交换16位数的字节顺序,得到的结果相同,只是字节顺序相应地也交换了;而如果使用原码或者补码求和,得到的结果可能就不同。
b、 计算和验证校验和比较简单、快递。
具体方法
发送数据时
为了计算数IP据报的校验和。应该按如下步骤:
(1)把IP数据报的首部都置为0,包括校验和字段。
(2)把首部看成以16位为单位的数字组成,依次进行二进制反码求和。
(3)把得到的结果存入校验和字段中。
接收数据时
计算数据报的校验和相对简单,按如下步骤:
(1)把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段。
(2)检查计算出的校验和的结果是否全为1。
(3)如果全为1,说明被整除,校验和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包
接收方计算校验和时的首部与发送方计算校验和时的首部相比,多了一个发送方计算出来的校验和。因此,如果首部在传输过程中没有发生差错,那么接收方计算的结果应该为全一,因为接收方计算除校验和以外的部分得到值是校验和的反码,再加多出来的校验和当然是全一了。
程序
unsigned short cal_chksum(unsigned short *addr, int len) { int nleft = len; int sum = 0; unsigned short *w=addr; unsigned short answer = 0; while(nleft > 1){ // 16bit为单位累加运算 sum += *w++; nleft -= 2; } if(nleft == 1){ //若addr奇数个字节,会剩下最后一字节. sum + =*(unsigned char *)w; } sum = (sum>>16) + (sum&0xffff); sum += (sum>>16); answer = ~sum; return answer; }
示例
IP头:
45 00 00 31
89 F5 00 00
6E 06 00 00(校验字段)
DE B7 45 5D -> 222.183.69.93
C0 A8 00 DC -> 192.168.0.220
计算:
4500 + 0031 +89F5 + 0000 + 6e06+ 0000 + DEB7 + 455D + C0A8 + 00DC =3 22C4
0003 + 22C4 = 22C7
~22C7 = DD38 ->即为应填充的校验和
当接受到IP数据包时,要检查IP头是否正确,则对IP头进行检验,方法同上:
计算:
4500 + 0031 +89F5 + 0000 + 6E06+ DD38 + DEB7 + 455D + C0A8 + 00DC =3 FFFC
0003 + FFFC = FFFF
得到的结果是全一,正确。
IP/UDP/TCP/ICMP校验和异同
1、四种报文的校验和算法一样
2、作用范围存在不同:
2.1 IP校验和只校验20字节的IP报头;
2.2 而ICMP校验和覆盖整个报文(ICMP报头+ICMP数据);
2.3 UDP和TCP校验和不仅覆盖整个报文,而且还有12字节的IP伪首部
包括源IP地址(4字节)、目的IP地址(4字节)、协议(2字节,第一字节补0)和TCP/UDP包长(2字节,包含协议头和数据)。另外UDP、TCP数据报的长度可以为奇数字节,所以在计算校验和时需要在最后增加填充字节0(注意,填充字节只是为了计算校验和,可以不被传送)。
3、UDP 的校验和是可选的
当校验和字段为0时,表明该UDP报文未使用校验和,接收方就不需要校验和检查了!那如果UDP校验和的计算结果是0时怎么办呢?书上有这么一句话:“如果校验和的计算结果为0,则存入的值为全1(65535),这在二进制反码计算中是等效的。”