如何遍历WinDivertReceiveEx接收的连续无分隔符缓冲区中的数据包?求示例
WinDivertReceiveEx 缓冲区多数据包遍历方案
核心逻辑
由于WinDivertReceiveEx会把多个数据包连续无间隙塞进缓冲区,遍历的关键就是靠每个数据包自身的长度字段来分割:先拿到当前数据包的实际长度,处理完后把指针移到下一个包的起始位置,循环直到缓冲区耗尽。
具体遍历步骤
- 初始化两个变量:当前数据包指针
pCurrent指向缓冲区起始地址pPacket,剩余未处理字节数remaining设为WinDivertReceiveEx返回的recvLen - 循环处理直到
remaining <= 0:- 用
WinDivertHelperParsePacket解析当前指针位置的数据,拿到IP头(不管是IPv4还是IPv6) - 通过IP头计算整个数据包的长度:
- IPv4:取IP头里的
Len字段,用ntohs()转成主机字节序 - IPv6:把IP头的
PayloadLen转成主机字节序后,加上IPv6头本身的长度
- IPv4:取IP头里的
- 检查计算出的长度是否超过剩余字节数,防止越界
- 处理当前数据包(比如修改、转发)
- 更新指针和剩余字节数:
pCurrent向后偏移packetLen,remaining减去packetLen
- 用
可运行示例代码
#include <windivert.h> #include <stdio.h> #define BUFFER_SIZE 0xFFFF // 覆盖绝大多数网络数据包大小 int main() { // 打开Divert句柄,这里以 outbound 流量为例 HANDLE divertHandle = WinDivertOpen("outbound", WINDIVERT_LAYER_NETWORK, 0, 0); if (divertHandle == INVALID_HANDLE_VALUE) { printf("WinDivertOpen failed\n"); return 1; } UINT8 buffer[BUFFER_SIZE]; UINT recvBytes; WINDIVERT_ADDRESS pktAddr; while (WinDivertReceiveEx(divertHandle, buffer, sizeof(buffer), &recvBytes, 0, &pktAddr, NULL)) { UINT8* currentPtr = buffer; UINT remainingBytes = recvBytes; while (remainingBytes > 0) { PVOID ipHeader; UINT pktLength = 0; // 解析当前数据包,获取IP头 if (!WinDivertHelperParsePacket(currentPtr, remainingBytes, &ipHeader, NULL, NULL, NULL, NULL, NULL)) { printf("Parse packet failed, skip\n"); break; } // 根据IP版本计算数据包总长度 if (((PWINDIVERT_IPHDR)ipHeader)->Version == 4) { pktLength = ntohs(((PWINDIVERT_IPHDR)ipHeader)->Len); } else if (((PWINDIVERT_IPV6HDR)ipHeader)->Version == 6) { pktLength = ntohs(((PWINDIVERT_IPV6HDR)ipHeader)->PayloadLen) + sizeof(WINDIVERT_IPV6HDR); } else { printf("Unknown IP version, skip\n"); break; } // 边界检查,避免越界 if (pktLength > remainingBytes) { printf("Packet length exceeds remaining bytes, skip\n"); break; } // ------------------------ // 这里添加你的业务逻辑 // 比如打印数据包长度,或者转发数据包 printf("Processing packet with length: %u\n", pktLength); // WinDivertSend(divertHandle, currentPtr, pktLength, NULL, &pktAddr); // ------------------------ // 移动指针到下一个数据包 currentPtr += pktLength; remainingBytes -= pktLength; } } WinDivertClose(divertHandle); return 0; }
注意要点
- 一定要做边界检查,否则容易出现缓冲区溢出的问题
- 如果解析数据包失败,直接跳过当前段即可,避免影响后续数据包的处理
- 不想用
WinDivertHelperParsePacket的话,也可以直接手动解析IP头的版本和长度字段,逻辑是一样的
内容的提问来源于stack exchange,提问作者Prakash
相关产品推荐
相关产品推荐

