C++使用Npcap统计pcap文件TCP/UDP数量与Wireshark结果不符
TCP/UDP统计值与Wireshark不一致的核心原因
- 未过滤IPv4非首片分片,错误统计分片报文
IPv4网络传输中大于MTU的报文会被切分为多个分片发送,每个分片都是独立的IPv4报文,因此你的IPv4总报文数统计和Wireshark完全一致。但只有片偏移为0的首个分片才携带TCP/UDP协议头,后续分片仅承载上层载荷、无TCP/UDP头。Wireshark统计TCP/UDP报文时,仅统计携带上层协议头的首片报文,不会将后续分片计入TCP/UDP计数。你的代码只要识别到IP头proto字段为6(TCP)或17(UDP)就直接累加计数,把所有IPv4分片都纳入了统计,导致结果偏大。 - 协议头结构体未强制1字节对齐,存在偏移风险
网络链路中的协议报文是紧凑连续存储的,不会按照编译器默认的对齐规则插入填充字节。你自定义的协议头结构体没有添加对齐约束,同时在ipv4_header末尾硬编码了u_int op_pad字段,不同编译选项、不同运行架构下编译器可能自动插入填充字节,导致结构体成员的内存偏移和实际报文字段位置不匹配,存在读错proto字段值的可能。 - 缺少基础报文合法性校验
你直接硬编码偏移量定位IPv4头,没有校验IP版本号是否为4,也没有根据IP头实际长度(ver_ihl低4位取值*4)判断报文捕获长度是否足够承载协议头,遇到畸形、截断报文时会出现误计数。
修正方案
- 为所有自定义协议头添加1字节对齐约束,避免编译器填充偏移:
#pragma pack(push, 1) // 此处放置ethernet_header、ip_address、ipv4_header、ipv6_header所有协议结构体定义 #pragma pack(pop) - 增加IPv4分片判断逻辑:读取
flags_fo字段后通过ntohs()转换为主机字节序,仅当片偏移为0(即(flags_fo_host & 0x1FFF) == 0,0x1FFF是片偏移字段的掩码)时,才根据proto字段值累加TCP/UDP计数。 - 补充基础校验:解析IPv4头时先确认版本号为4,同时校验当前捕获的报文长度足够容纳以太网头、IPv4头,避免越界访问和畸形包误判。
内容的提问来源于stack exchange,提问作者Nikhil Pradhan
相关产品推荐
相关产品推荐

