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

如何遍历WinDivertReceiveEx接收的连续无分隔符缓冲区中的数据包?求示例

WinDivertReceiveEx 缓冲区多数据包遍历方案

核心逻辑

由于WinDivertReceiveEx会把多个数据包连续无间隙塞进缓冲区,遍历的关键就是靠每个数据包自身的长度字段来分割:先拿到当前数据包的实际长度,处理完后把指针移到下一个包的起始位置,循环直到缓冲区耗尽。

具体遍历步骤

  • 初始化两个变量:当前数据包指针pCurrent指向缓冲区起始地址pPacket,剩余未处理字节数remaining设为WinDivertReceiveEx返回的recvLen
  • 循环处理直到remaining <= 0:
    1. 用WinDivertHelperParsePacket解析当前指针位置的数据,拿到IP头(不管是IPv4还是IPv6)
    2. 通过IP头计算整个数据包的长度:
      • IPv4:取IP头里的Len字段,用ntohs()转成主机字节序
      • IPv6:把IP头的PayloadLen转成主机字节序后,加上IPv6头本身的长度
    3. 检查计算出的长度是否超过剩余字节数,防止越界
    4. 处理当前数据包(比如修改、转发)
    5. 更新指针和剩余字节数: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 20:10:28