在TUN设备上收到TCP重传而非ACK的问题排查
TCP校验和错误导致SYN-ACK不被响应的排查要点
1. 伪头部构造错误
TCP校验和计算依赖IP伪头部,这是最常见的出错点:
- 伪头部必须包含源IP(你的TUN设备IP:192.168.20.99)、目的IP(NC客户端的IP)、协议号(固定为6,对应TCP)、TCP报文总长度(头部+数据的字节数,不是IP包总长度)
- 确认伪头部的字段类型和长度符合要求:IP是32位、协议号是8位、TCP长度是16位,不要出现字段长度或值的错误
2. 字节序不匹配
RFC1071要求所有参与计算的字段必须是网络字节序(大端):
- 检查TCP头部的序列号、确认号、窗口大小等字段,是否在计算前已经通过
htons()/htonl()转换为大端 - 伪头部中的IP地址、TCP长度必须是大端格式,不能直接使用主机字节序的数值
- 累加过程中,每个16位块要确保是网络字节序后再加入总和
3. 校验和计算细节遗漏
严格按照RFC1071的步骤检查:
- 如果TCP报文长度是奇数,必须在末尾补一个0字节(仅用于计算,不发送),否则会漏掉最后一个字节的校验
- 累加时的溢出处理:每次累加后,要将高16位的值加到低16位,循环直到没有溢出
- 最终校验和是累加结果的按位取反,不要直接使用累加值或取反错误
- 若TCP头部包含选项字段,必须将选项部分纳入计算,不能只计算固定头部
4. TUN报文封装问题
TUN设备处理三层IP报文,需确认:
- 你构造的SYN-ACK是否封装成了完整合法的IP包,IP头部自身的校验和是否正确计算(IP校验和错误会导致报文被丢弃,间接引发TCP重传)
- 检查TUN设备的MTU设置,避免报文被截断导致校验和计算的原始数据与实际发送数据不一致
5. 计算后报文被修改
- 校验和计算完成后,是否修改过TCP头部的字段(比如SYN/ACK标志位),但未重新计算校验和
- 确保发送的二进制报文与计算校验和时的原始数据完全一致,无字节丢失、篡改或顺序错误
参考校验和计算伪代码(对照排查)
uint16_t tcp_checksum(uint8_t *tcp_data, size_t tcp_len, uint32_t src_ip, uint32_t dst_ip) { // 构造伪头部并累加 uint32_t sum = 0; sum += (src_ip >> 16) + (src_ip & 0xFFFF); sum += (dst_ip >> 16) + (dst_ip & 0xFFFF); sum += htons(6); // TCP协议号 sum += htons(tcp_len); // TCP报文总长度 // 累加TCP报文数据 while (tcp_len > 1) { sum += htons(*(uint16_t*)tcp_data); tcp_data += 2; tcp_len -= 2; } // 处理奇数长度的剩余字节 if (tcp_len > 0) { sum += htons(*tcp_data << 8); } // 处理溢出 while (sum >> 16) { sum = (sum & 0xFFFF) + (sum >> 16); } // 取反得到最终校验和 return (uint16_t)~sum; }
内容的提问来源于stack exchange,提问作者Iman Seyed
相关产品推荐
相关产品推荐

