Sendto函数无法发送自定义IPv4/TCP头的原始数据包问题排查
自定义IPv4/TCP原始数据包发送失败的问题修复
尝试用C语言的
sendto发送自定义IPv4和TCP头的原始数据包,但代码无法正常工作:
- 怀疑
IP_HDRINCL的setsockopt配置有问题,注释掉这段代码后会发送带两个IPv4头的数据包(自定义的+系统自动添加的)- 无论是否注释该代码段,
sendto都返回40,但实际要么发送了超过40字节的包,要么根本没发送- 已尝试绑定socket、修改协议配置、调整头参数等方法,使用Cygwin编译,运行在Windows 11系统
核心问题与修复步骤
1. 结构体字节对齐问题
Windows默认的结构体字节对齐规则会导致IPV4_HDR和TCP_HDR的实际大小与标准IP/TCP头不一致(标准IP头20字节、TCP头20字节),必须强制1字节对齐以匹配网络协议的字节布局:
#pragma pack(1) // 所有结构体定义放在这里 typedef struct ip_hdr { ... } IPV4_HDR; typedef struct tcp_header { ... } TCP_HDR; struct pseudo_header { ... }; struct pseudoTcpHeader { ... }; #pragma pack()
2. IP校验和计算错误
当前代码错误地使用sizeof(struct pseudo_header)计算IP校验和,IP校验和仅需覆盖IP头部本身,修改为:
v4hdr->ip_checksum = csum( (unsigned short*)v4hdr, sizeof(IPV4_HDR) );
3. TCP校验和计算错误
TCP校验和必须结合伪头部(包含IP层的源/目的地址、协议类型等信息)计算,不能直接对TCP头单独计算:
// 构造TCP伪头部 struct pseudoTcpHeader p_tcp_hdr; p_tcp_hdr.ip_src = v4hdr->ip_srcaddr; p_tcp_hdr.ip_dst = v4hdr->ip_destaddr; p_tcp_hdr.zero = 0; p_tcp_hdr.protocol = IPPROTO_TCP; p_tcp_hdr.tcp_len = htons(sizeof(TCP_HDR) + payload); memcpy(&p_tcp_hdr.tcph, tcphdr, sizeof(TCP_HDR)); // 计算校验和 tcphdr->checksum = csum( (unsigned short*)&p_tcp_hdr, sizeof(struct pseudoTcpHeader) );
4. 套接字与IP_HDRINCL配置问题
- Windows下使用
SOCK_RAW+IPPROTO_RAW时,IP_HDRINCL设置生效后,系统不会自动处理IP头,需确保IP头的所有字段(如总长度、分片标记)完全正确 - 无需绑定socket到源IP,绑定操作可能干扰原始包的发送逻辑,建议删除
bind相关代码
5. 运行权限问题
Windows下发送原始数据包必须以管理员身份运行程序,否则即使代码正确,也会因权限不足无法发送数据包。
6. 其他细节修复
- 避免使用
inet_ntoa的临时指针直接赋值,改用dest.sin_addr.s_addr直接设置目的IP:v4hdr->ip_destaddr = dest.sin_addr.s_addr; - 显式初始化TCP头未赋值的字段:
tcphdr->acknowledge = 0; tcphdr->window = htons(65535); tcphdr->urgent_pointer = 0;
内容的提问来源于stack exchange,提问作者Guy Dror
相关产品推荐
相关产品推荐

