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

Windows下使用C++与Npcap库区分IPv4和IPv6数据包的方法问询

如何用C++和Npcap判断捕获的数据包是IPv4还是IPv6

原代码的问题

  • EtherType注释与值不匹配:比如0x0806是ARP协议,并非Wi-Fi WEP;0x888E是802.1X认证协议,不是Wi-Fi加密帧,错误的注释和条件会导致误判。
  • 逻辑错误:将加密协议(WEP/WPA)的EtherType直接作为IPv4/IPv6的判断条件,实际上加密帧内部才封装IP包,不能直接通过这些字段判断IP版本。
  • 未区分链路层类型:没有考虑以太网、Wi-Fi等不同链路层的帧结构差异,统一用固定位置判断EtherType会失效。

正确实现思路

Npcap捕获的数据包链路层类型可通过pcap_datalink()获取,不同链路层的帧结构不同,需分情况解析:

  1. 以太网链路层(DLT_EN10MB):
    • 标准以太网头部为14字节,EtherType字段位于第12、13字节(大端序),0x0800对应IPv4,0x86DD对应IPv6。
    • 若为802.3帧(长度字段<1500),需解析LLC+SNAP封装,SNAP中的EtherType字段对应IP版本。
  2. Wi-Fi链路层(DLT_IEEE802_11):
    • 先解析802.11帧头的Frame Control字段,确认是数据帧。
    • 若帧加密(WEP/WPA),需确保Npcap已配置自动解密(或自行处理解密),之后找到SNAP封装中的EtherType字段判断IP版本。

示例代码

#include <pcap.h>
#include <stdint.h>
#include <arpa/inet.h>

// 以太网头部结构
typedef struct ethernet_header {
    uint8_t dst_mac[6];
    uint8_t src_mac[6];
    uint16_t ether_type; // 大端序
} ethernet_header_t;

// LLC+SNAP头部结构(用于802.3帧)
typedef struct llc_snap_header {
    uint8_t dsap;
    uint8_t ssap;
    uint8_t control;
    uint8_t oui[3];
    uint16_t ether_type; // 大端序
} llc_snap_header_t;

// 802.11帧控制字段结构
typedef struct ieee80211_frame_control {
    uint8_t protocol_version : 2;
    uint8_t type : 2;
    uint8_t subtype : 4;
    uint8_t to_ds : 1;
    uint8_t from_ds : 1;
    uint8_t more_frag : 1;
    uint8_t retry : 1;
    uint8_t pwr_mgmt : 1;
    uint8_t more_data : 1;
    uint8_t wep : 1;
    uint8_t order : 1;
} ieee80211_frame_control_t;

// 判断是否为IPv4数据包
bool IsIpv4Packet(const u_char* packetData, int datalink_type) {
    switch (datalink_type) {
        case DLT_EN10MB: { // 以太网链路层
            ethernet_header_t* eth_hdr = (ethernet_header_t*)packetData;
            uint16_t ether_type = ntohs(eth_hdr->ether_type);
            
            if (ether_type == 0x0800) { // IPv4
                return true;
            } else if (ether_type <= 1500) { // 802.3帧,解析LLC+SNAP
                llc_snap_header_t* llc_snap = (llc_snap_header_t*)(packetData + sizeof(ethernet_header_t));
                // 检查是否为SNAP封装(DSAP=SSAP=0xAA,Control=0x03)
                if (llc_snap->dsap == 0xAA && llc_snap->ssap == 0xAA && llc_snap->control == 0x03) {
                    return ntohs(llc_snap->ether_type) == 0x0800;
                }
            }
            break;
        }
        case DLT_IEEE802_11: { // Wi-Fi链路层
            ieee80211_frame_control_t* fc = (ieee80211_frame_control_t*)packetData;
            // 仅处理数据帧(Type=2)
            if (fc->type != 2) {
                return false;
            }
            
            // 计算802.11头部长度:根据地址字段数量调整
            int hdr_len = 24; // 基本数据帧头部长度
            if (fc->to_ds && fc->from_ds) {
                hdr_len += 6; // 包含地址4字段
            }
            
            // 跳过加密部分(Npcap已自动解密时),解析LLC+SNAP
            llc_snap_header_t* llc_snap = (llc_snap_header_t*)(packetData + hdr_len);
            if (llc_snap->dsap == 0xAA && llc_snap->ssap == 0xAA && llc_snap->control == 0x03) {
                return ntohs(llc_snap->ether_type) == 0x0800;
            }
            break;
        }
        // 可扩展支持其他链路层类型,如DLT_IP等
        default:
            break;
    }
    return false;
}

// 判断是否为IPv6数据包
bool IsIpv6Packet(const u_char* packetData, int datalink_type) {
    switch (datalink_type) {
        case DLT_EN10MB: { // 以太网链路层
            ethernet_header_t* eth_hdr = (ethernet_header_t*)packetData;
            uint16_t ether_type = ntohs(eth_hdr->ether_type);
            
            if (ether_type == 0x86DD) { // IPv6
                return true;
            } else if (ether_type <= 1500) { // 802.3帧,解析LLC+SNAP
                llc_snap_header_t* llc_snap = (llc_snap_header_t*)(packetData + sizeof(ethernet_header_t));
                if (llc_snap->dsap == 0xAA && llc_snap->ssap == 0xAA && llc_snap->control == 0x03) {
                    return ntohs(llc_snap->ether_type) == 0x86DD;
                }
            }
            break;
        }
        case DLT_IEEE802_11: { // Wi-Fi链路层
            ieee80211_frame_control_t* fc = (ieee80211_frame_control_t*)packetData;
            if (fc->type != 2) {
                return false;
            }
            
            int hdr_len = 24;
            if (fc->to_ds && fc->from_ds) {
                hdr_len += 6;
            }
            
            llc_snap_header_t* llc_snap = (llc_snap_header_t*)(packetData + hdr_len);
            if (llc_snap->dsap == 0xAA && llc_snap->ssap == 0xAA && llc_snap->control == 0x03) {
                return ntohs(llc_snap->ether_type) == 0x86DD;
            }
            break;
        }
        default:
            break;
    }
    return false;
}

使用说明

  • 在捕获数据包前,通过pcap_datalink(handle)获取当前设备的链路层类型,传入判断函数。
  • Wi-Fi帧的处理需确保Npcap已启用“Monitor Mode”并配置自动解密(若需处理加密帧),否则需自行实现解密逻辑。
  • 可根据实际需求扩展其他链路层类型的支持,如DLT_IP(直接IP数据包)等。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 18:43:09