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

C++构建原始UDP数据包异常:Wireshark无法正确识别数据

问题排查与修复方案

1. 字节序(端序)错误

IP和UDP头的核心字段(源/目的端口、IP总长度、UDP总长度等)必须使用网络字节序(大端序),如果直接用主机字节序(小端)赋值,会导致Wireshark解析时字节错位,进而错误计算数据偏移,把数据当成头的一部分、或头当成数据。

检查代码中这些字段的赋值,必须用htons()/htonl()转换:

// UDP头字段转换
udp_header.uh_sport = htons(local_port);
udp_header.uh_dport = htons(target_port);
udp_header.uh_ulen = htons(sizeof(UDPHeader) + data_len);

// IP头字段转换
ip_header.ip_len = htons(sizeof(IPHeader) + sizeof(UDPHeader) + data_len);
ip_header.ip_id = htons(12345); // 示例ID,按需修改

2. IP头校验和未正确计算

IP头要求必须计算校验和(仅覆盖IP头部分),校验和错误会让Wireshark判定IP包损坏,进而乱解析后续的UDP头和数据。

用标准校验和算法实现:

unsigned short checksum(unsigned short *buf, int nwords) {
    unsigned long sum = 0;
    for (; nwords > 0; nwords--) sum += *buf++;
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    return ~sum;
}

// 赋值IP头后计算校验和
ip_header.ip_sum = 0; // 先清零
ip_header.ip_sum = checksum((unsigned short *)&ip_header, sizeof(IPHeader)/2);

3. UDP校验和错误(关键可选项)

UDP校验和虽可选,但错误的校验和会让Wireshark标记包损坏。UDP校验和需要覆盖UDP头、数据,还要加上伪IP头(含源IP、目的IP、协议类型、UDP长度)。

实现示例:

#pragma pack(1)
struct PseudoHeader {
    unsigned int src_ip;
    unsigned int dst_ip;
    unsigned char zero;
    unsigned char protocol;
    unsigned short udp_len;
};
#pragma pack()

// 构造伪头并计算校验和
PseudoHeader ph;
ph.src_ip = inet_addr(source_ip);
ph.dst_ip = inet_addr(target_ip);
ph.zero = 0;
ph.protocol = IPPROTO_UDP;
ph.udp_len = htons(sizeof(UDPHeader) + data_len);

// 拼接伪头、UDP头、数据到缓冲区
char checksum_buf[sizeof(PseudoHeader) + sizeof(UDPHeader) + 1024];
memcpy(checksum_buf, &ph, sizeof(PseudoHeader));
memcpy(checksum_buf + sizeof(PseudoHeader), &udp_header, sizeof(UDPHeader));
memcpy(checksum_buf + sizeof(PseudoHeader) + sizeof(UDPHeader), data, data_len);

udp_header.uh_sum = 0;
udp_header.uh_sum = checksum((unsigned short *)checksum_buf, 
    (sizeof(PseudoHeader) + sizeof(UDPHeader) + data_len + 1)/2);

若不想用校验和,直接把uh_sum设为0即可,但部分环境会对0校验和的包做特殊处理。

4. 结构体内存对齐问题

C++结构体默认会有内存填充,若IP/UDP头结构体因对齐产生多余字节,会导致实际发送的头与协议标准结构不符,数据偏移完全错误。

给结构体加上强制对齐属性:

#pragma pack(1)
struct IPHeader {
    unsigned char ip_hl:4, ip_v:4;
    unsigned char ip_tos;
    unsigned short ip_len;
    unsigned short ip_id;
    unsigned short ip_off;
    unsigned char ip_ttl;
    unsigned char ip_p;
    unsigned short ip_sum;
    unsigned int ip_src;
    unsigned int ip_dst;
};
struct UDPHeader {
    unsigned short uh_sport;
    unsigned short uh_dport;
    unsigned short uh_ulen;
    unsigned short uh_sum;
};
#pragma pack()

GCC/Clang也可使用__attribute__((packed))替代#pragma pack。

5. IP头长度字段错误

IP头的ip_hl字段表示头长度(单位是4字节),默认IP头为20字节,所以必须设为5:

ip_header.ip_hl = 5; // 5*4=20字节,标准IPv4头长度
ip_header.ip_v = 4; // 指定IPv4协议

你提到十六进制可见68-69但Wireshark显示ff11,大概率是UDP头长度字段或IP头总长度的字节序错误,导致Wireshark计算数据起始位置时偏移出错,把数据解析成了错误内容。优先检查字节序和头长度的赋值,再验证校验和问题。

内容的提问来源于stack exchange,提问作者ni1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 06:22:38