如何验证ICMP回显数据包校验和?附实现相关疑问
问题1:Wireshark中ICMP包出现的22字节额外数据来源
这22字节并非被主动添加到ICMP数据包中,大概率是你用RAW Socket接收数据时未剥离IPv4头部导致的。在Linux等系统中,使用SOCK_RAW类型的Socket接收ICMP包时,默认会返回包含IPv4头部的完整数据包(IPv4头部最小长度为20字节,若带有可选字段会更长,你看到的22字节就是带选项的IPv4头部)。你需要先读取IPv4头部的IHL字段(值乘以4即为头部字节数),剥离这部分后,剩下的才是真正的ICMP消息。
问题2:验证校验和是否需要包含这些字节
不需要将这些IPv4头部字节纳入ICMP校验和计算。ICMP校验和的计算范围是整个ICMP消息(ICMP头部 + ICMP负载),正确流程是:
- 剥离IPv4头部,取出纯ICMP数据;
- 将ICMP包的
Checksum字段置为0; - 对整个ICMP消息(头部+负载)重新计算校验和;
- 比较计算结果与原包的
Checksum字段,一致则校验通过。
另外补充:你提到发送的ICMP包无负载,但实际回复中出现了负载数据,这是因为部分系统会在处理无负载的ICMP Echo请求时,自动添加填充数据(或复用内存数据),并按照RFC792要求原封不动返回,这部分负载必须纳入校验和计算。
问题3:请求与回复Type字段不同导致校验和不匹配的解决
这是完全正常的情况——ICMP Echo请求(Type=8)和回复(Type=0)本身就是不同的消息,校验和自然不同。你不需要拿请求包的校验和对比回复包的校验和,而是针对回复包自身做校验:取出回复的纯ICMP数据后,按上述步骤单独计算它的校验和,再与回复包自带的Checksum字段对比即可。
关于iputils ping未处理csfailed的补充
iputils的ping实现并非不处理校验和,而是将校验和失败的逻辑放在了底层包处理流程中,或依赖系统内核在接收时完成初步校验。你可以查看其代码中icmp_checksum相关实现,核心逻辑依然是剥离IP头部后对ICMP消息计算校验和。
内容的提问来源于stack exchange,提问作者Swagnik Dutta

