You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Raw Socket手动构造TCP数据包收发内容不一致问题排查咨询

手动构造Raw Socket TCP数据包收发不匹配问题排查

问题背景

通过Raw Socket手动构造包含IP头、TCP头及Payload的TCP数据包,发送后接收端收到的数据包与发送包完全不匹配,具体差异包括:

  • IP头部长度字段不一致
  • TCP头部长度及标志位不匹配
  • Payload缺失(预期为Hello, World!)

发送数据包(十六进制)

45 00 00 35 00 00 00 00 FF 06 3C C2 00 00 00 00 7F 00 00 01 31 D4 39 30 29 00 00 00 00 00 00 00 50 18 FF FF A5 71 00 00 48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21

接收数据包(十六进制)

45 00 00 3C F8 A9 00 00 80 FF 00 00 7F 00 00 01 7F 00 00 01 45 00 00 28 00 00 00 00 FF 06 BD CD 7F 00 00 01 7F 00 00 01 31 D4 39 30 29 00 00 00 00 00 00 2A 50 12 FF FF 1B BF 00 00

已执行操作

  • 手动构造IP、TCP头部,设置源/目的IP、端口、序列号等字段
  • 计算并设置IP和TCP头部的校验和
  • 使用recv函数接收数据包

问题解答

1. 收发数据包不一致的可能原因

  • 系统自动修改/响应数据包:接收包为嵌套IP结构,大概率是系统返回的ICMP错误封装包,说明发送的数据包不符合TCP/IP规范,被网络栈拦截并返回错误
  • Socket选项未正确配置:未开启IP_HDRINCL选项时,系统会自动添加IP头部,导致实际发送的数据包与构造的包重复头部
  • 数据包构造错误:IP/TCP头部字段(如总长度、头部长度、校验和)计算或填充错误,导致网络栈无法正确解析
  • 接收端过滤失效:Raw Socket默认接收所有匹配的数据包,误收到了系统自动生成的响应包或其他进程的数据包

2. 数据包构造/接收流程的常见问题

构造阶段

  • IP头部字段错误:
    • 版本/头部长度字段(首字节45):4表示IPv4,5代表头部长度为20字节,若实际头部长度与该值不符,会导致解析错位
    • IP总长度字段:发送包中为00 35(53字节),若实际总长度(IP头+TCP头+Payload)与该值不匹配,网络栈会丢弃或修改数据包
    • 校验和计算错误:IP校验和仅覆盖IP头部,TCP校验和需包含伪头部(IP源/目的地址、协议号、TCP长度),伪头部构造错误会直接导致校验和无效
  • TCP头部字段错误:
    • TCP头部长度字段(TCP头第13字节高4位):设置错误会导致Payload偏移计算错误,无法正确读取内容
    • 标志位与状态机不匹配:发送包标志位为18(PSH+ACK),若未建立TCP连接就发送该标志位的包,系统会返回错误响应
  • 字节序错误:IP/TCP头部的多字节字段(端口、序列号、长度、校验和)必须使用网络字节序(大端序),误用主机字节序会导致字段值完全错误

接收阶段

  • 未设置过滤规则:Raw Socket未绑定源/目的IP、端口的过滤条件,导致收到无关数据包
  • 接收缓冲区不足:recv函数的缓冲区大小小于数据包长度,导致数据被截断
  • 回环测试特殊处理:本地回环场景下,系统网络栈会对Raw Socket数据包进行特殊封装处理,返回错误包而非原始发送包

3. 有效调试方法

发送端验证

  • 抓包对比实际发送包:用Wireshark/tcpdump在发送端抓包,对比构造的包与实际发出的包是否一致,确认是构造错误还是系统修改问题
  • 强制自定义IP头部:开启IP_HDRINCL选项(Windows/Linux均支持),禁止系统自动添加或修改IP头部
  • 重新校验字段值:
    • IP校验和:将IP头部校验和字段设为0,对头部按16位累加后取反得到正确值
    • TCP校验和:构造伪头部(源IP、目的IP、0、协议号6、TCP总长度),拼接TCP头部与Payload,将校验和字段设为0后按16位累加取反
    • 所有多字节字段用htons()/htonl()转换为网络字节序
  • 逐字段验证构造结果:打印create_data_packet函数生成的数据包十六进制,与预期发送包逐字节对比

接收端验证

  • 添加数据包过滤规则:通过setsockopt设置BPF过滤规则,仅接收源/目的IP、端口匹配的数据包
  • 解析接收包结构:手动解析接收包的IP头、协议字段,确认是否为目标包或系统错误响应包
  • 扩大接收缓冲区:将recv的缓冲区大小设置为至少1500字节(MTU最大值),避免数据截断
  • 抓包验证传输链路:在接收端抓包,确认网络中传输的数据包是否正确,再对比接收代码的输出,排查是否为接收逻辑问题

附:相关代码片段

接收端代码

recv_len = receive_packet(sock, packet);
if (recv_len < 0) {
    std::cerr << "Failed to receive packet: " << WSAGetLastError() << std::endl;
    return false;
}

// Output for debugging
std::cout << "Raw packet data (hex): ";
for (int i = 0; i < recv_len; ++i) {
    printf("%02X ", static_cast<unsigned char>(packet[i]));
}

发送端代码

// Create the data packet
create_data_packet(saddr, daddr, seq, ack, data, data_len, packet, packet_len);

// Send the data packet to the destination address
if (sendto(sock, packet.get(), packet_len, 0, reinterpret_cast<sockaddr*>(&daddr), sizeof(daddr)) == SOCKET_ERROR) {
    std::cerr << "Failed to send data packet: " << WSAGetLastError() << std::endl;
    closesocket(sock); // Close the socket before exiting
    WSACleanup();      // Clean up Winsock before exiting
    return 1; // Exit with an error code if sending the packet fails
}
std::cout << "Data packet sent successfully." << std::endl;

内容的提问来源于stack exchange,提问作者נהוראי יפרח

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 09:04:51