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

基于libpcap开发嗅探器时pcap_set_rfmon()调用始终失败如何解决

libpcap嗅探器pcap_set_rfmon()调用失败解决方案

问题现象

  • 基于libpcap开发底层网络嗅探器时,仅pcap_set_rfmon()相关断言始终触发失败,其余功能运行正常
  • 自查未发现代码编写错误,更换多款网卡、无线适配器后,所有设备均无法成功配置监听模式
  • 原核心代码片段:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <pcap.h>

#define JUMBO_FRAMES_MTU 9000

#define BIGGER_THAN_ALL_MTUS    (64*1024)

#define ERR(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)

int main(int argc, char **argv)
{

    char errbuf[PCAP_ERRBUF_SIZE]; 

    pcap_t *handle; 

    if (argc < 2){
        ERR("usage : ./prog itf-name\n");
    }

    /* exiting if strlen of itf > 14 */
    if (strlen(argv[1]) > IFNAMSIZ){
        ERR("Interface name too long");
    }

    strncpy(opt_args->device, argv[1], strlen(argv[1]) + 1); 
    handle = pcap_create(opt_args->device, errbuf); 

    if (handle == NULL){
        (void)fprintf(stderr, "FATAL ERROR : couldn't create sock handle : %s\n", errbuf); 
        goto fatal_error; 
    }

    /* setting snaplen to 1500 */
    assert(pcap_set_snaplen(handle, ETHERNET_MTU) == 0); 

    assert(pcap_setnonblock(handle, -1, errbuf) != -1); 

    /* if we can't put the device in monitor mode, so we display a warning 
    but keep doing the capture */

    /* I have a warning here */
    if (pcap_can_set_rfmon(handle) != 1){
        (void)fprintf(stderr, "WARNING : device can't be set up in monitor mode : %s\n", 
            pcap_geterr(handle)); 
    } else{
        assert(pcap_set_rfmon(handle, 1) == 0); 
    }

    /* we need now to launch the session capture */
    if (pcap_activate(handle) < 0){

        (void)fprintf(stderr, "FATAL ERROR : couldn't activate PCAP sock : %s\n", 
            pcap_geterr(handle)); 

        goto fatal_error; 
    }

    /* pcap loop ... */

    pcap_close(handle);

    return 0;

fatal_error;

    pcap_close(handle);

    return 1;
}

根因分析

问题由代码错误、调用时序错误、环境配置问题三类原因共同导致:

  • 代码本身存在硬错误
    1. 引用未定义变量:代码中未定义opt_args结构体,直接对opt_args->device执行拷贝属于野指针内存访问,会破坏进程内存空间,干扰后续libpcap句柄的配置逻辑
    2. 头文件缺失:使用了IFNAMSIZ、ETHERNET_MTU、assert但未引入<net/if.h>、<net/ethernet.h>、<assert.h>头文件,宏值、函数声明异常会直接导致参数错误
    3. 接口参数非法:pcap_setnonblock()第二个参数为布尔类型,仅接受0/1两个合法值,传入-1会直接调用失败
    4. 错误处理存在空指针风险:如果pcap_create()返回NULL,goto到错误分支后会对空指针执行pcap_close(),直接触发段错误
  • libpcap接口调用时序错误
    pcap_can_set_rfmon()必须在pcap_activate()执行成功后调用,才能返回准确的设备能力值。原代码在句柄未激活状态下调用该接口,返回值完全不可靠,后续pcap_set_rfmon()的执行分支判断本身就是错的。
  • 环境与适配问题
    1. 权限不足:配置射频监听模式需要CAP_NET_ADMIN权限,普通用户运行程序时,所有模式切换请求都会被内核直接拒绝
    2. 设备/驱动不兼容:有线网卡本身不支持无线专属的rfmon监听模式;部分消费级无线网卡的驱动不支持libpcap自动切换模式的接口,无法通过pcap_set_rfmon()完成配置
    3. 版本兼容问题:1.9以前的旧版本libpcap在Linux 4.x+内核上存在rfmon配置逻辑的已知bug,无法正常下发模式切换请求

注意:不要在release版本中使用assert做核心逻辑校验,编译时添加-DNDEBUG参数会直接移除所有assert代码,导致参数校验逻辑完全失效。

修复步骤

  1. 修复代码逻辑错误,调整接口调用时序
    修正后的可运行核心代码参考:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pcap.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <assert.h>

#define ERR(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)

int main(int argc, char **argv)
{
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t *handle;

    if (argc < 2){
        ERR("usage : ./prog itf-name\n");
    }

    if (strlen(argv[1]) >= IFNAMSIZ){
        ERR("Interface name too long");
    }

    // 移除不存在的opt_args逻辑,直接使用命令行传入的设备名
    handle = pcap_create(argv[1], errbuf);
    if (handle == NULL){
        fprintf(stderr, "FATAL ERROR : couldn't create sock handle : %s\n", errbuf);
        return 1;
    }

    // 所有set类配置必须在activate之前调用
    int ret = pcap_set_snaplen(handle, ETHERNET_MTU);
    if (ret != 0) {
        fprintf(stderr, "set snaplen failed: %s\n", pcap_geterr(handle));
        pcap_close(handle);
        return 1;
    }
    // 修正pcap_setnonblock参数,需要非阻塞传1,阻塞传0
    ret = pcap_setnonblock(handle, 1, errbuf);
    if (ret != 0) {
        fprintf(stderr, "set nonblock failed: %s\n", errbuf);
        pcap_close(handle);
        return 1;
    }
    // 提前下发rfmon配置请求,激活时生效
    pcap_set_rfmon(handle, 1);

    // 激活抓包句柄
    ret = pcap_activate(handle);
    if (ret < 0){
        fprintf(stderr, "FATAL ERROR : couldn't activate PCAP sock : %s\n", 
            pcap_geterr(handle));
        pcap_close(handle);
        return 1;
    }

    // 激活后再检查监听模式是否生效
    if (pcap_can_set_rfmon(handle) != 1){
        fprintf(stderr, "WARNING : device not running in monitor mode, will capture in managed mode : %s\n",
            pcap_geterr(handle));
    }

    // 后续pcap_loop等抓包逻辑...

    pcap_close(handle);
    return 0;
}
  1. 排查运行环境问题
  • 必须使用root权限运行程序,例如执行sudo ./sniffer wlan0
  • 确认测试设备为支持监听模式的无线网卡,不要在有线网卡上尝试开启rfmon模式
  • 如果网卡驱动不支持libpcap自动切模式,先手动通过系统命令将网卡切换为监听模式再启动程序:
# 关闭网卡
sudo ip link set wlan0 down
# 切换为监听模式
sudo iw dev wlan0 set type monitor
# 启动网卡
sudo ip link set wlan0 up

手动切换完成后,即使不在代码中调用pcap_set_rfmon(),抓包也会工作在监听模式下。
3. 版本兼容修复
如果以上步骤完成后仍无法正常配置,将libpcap升级到1.10及以上的稳定版本,修复旧版本对新内核的兼容问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 02:33:06