报文校验和计算
计算校验和算法
IP、ICMP、UDP和TCP头都有检验和字段,大小都是16bit,算法基本上是一样的。
发送报文时计算校验和
1、把校验和字段设置为0;
2、把需要校验的数据看成以16位为单位的数字组成,依次进行二进制反码求和;
3、把得到的结果存入校验和字段中。
接收数据时计算检验和
1、把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段;
2、检查结果是否为0;
3、如果等于0,校验和正确;否则,校验和错误,丢弃数据包。
作用范围不同
IP校验和只校验20个字节的IP报头。
ICMP校验和覆盖整个报文(ICMP报头+ICMP数据)。
UDP和TCP校验和不仅覆盖整个报文,还有12个字节的IP伪首部,包括源IP地址(4字节)、目的IP地址(4字节)、协议(2字节)、TCP/UDP包长(2字节)。UDP和TCP报文长度可以是奇数字节,所以在计算校验和时需要在最后增加填充字节0(填充字节只是为了计算校验和,可以不被传送)。
计算tcp校验和代码案例
源IP 10.16.0.9->0x0a100009
目的IP 172.18.0.4->0xac120004
tcp协议是6->0x0006
tcp报文占40字节->0x0028
把tcp校验和e450改成0000,否则结果是0,该场景用于接收端确认校验和是否正确。
#include <stdio.h>
#define data_len 26
unsigned short getChecksum(unsigned short *data) {
unsigned long sum = 0;
int i;
for (i = 0; i < data_len; i++) {
sum += *data;
data++;
sum = (sum >> 16) + (sum & 0xffff);
}
return ~sum;
}
int main() {
unsigned short data[data_len] = {0x0a10, 0x0009, 0xac12, 0x0004, 0x0006, 0x0028,
0xa33e, 0x19f2, 0xab45, 0xfbdc, 0x0000, 0x0000, 0xa002, 0x6a40, 0x0000, 0x0000, 0x0204, 0x0550, 0x0402, 0x080a, 0x04c6, 0xda8a, 0x0000, 0x0000, 0x0103, 0x0307};
printf("%x\t", getChecksum(data));
}
结果是0xe450。
参考资料
https://blog.csdn.net/oceanstudy123/article/details/121677774
https://blog.csdn.net/stone_Yu/article/details/81611067