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

Ubuntu 22.04虚拟机中C程序无法捕获自定义MAC原始数据包问题

原始套接字无法捕获非本网段MAC地址数据包的解决方法

问题背景

VMware Workstation环境下,两台同网段Ubuntu 22.04虚拟机,其中一台发送带非本网段MAC地址的原始数据包,另一台可通过Wireshark捕获该数据包,但自行编写的C原始套接字程序无法捕获。已确认iptables无原始数据包拦截规则,libpcap可正常捕获但因架构限制无法替换,两台虚拟机可正常通信。

核心原因

网卡未开启混杂模式。默认状态下,网卡仅接收目标MAC为本机、广播或多播的数据包,非本网段MAC的数据包会被网卡硬件过滤丢弃。Wireshark启动时会自动将网卡切换为混杂模式,因此能捕获所有经过网卡的流量;而手动编写的原始套接字程序默认不开启该模式,无法获取这类数据包。

解决方案

  1. 开启网卡混杂模式
    通过ioctl调用设置网卡的IFF_PROMISC标志位,让网卡接收所有经过的数据包。
  2. 修正main函数参数错误
    原代码中main函数参数格式错误,需调整为标准格式。
  3. 处理非阻塞read的返回值
    非阻塞模式下无数据可读时,read会返回-1并设置errno为EAGAIN,需添加判断避免无意义报错。

修正后的代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <linux/filter.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc, char** argv)
{
    int s, stat, cc;                          
    unsigned char buf[ETH_FRAME_LEN];                                           
    struct sockaddr_ll saddr;
    struct ifreq ifr;
    char *interface = "ens33";

    s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (s < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // 获取网卡索引
    strncpy(ifr.ifr_name, interface, IFNAMSIZ);
    if(ioctl(s, SIOGIFINDEX, &ifr))
    {
        perror("ioctl get index");
        close(s);
        exit(EXIT_FAILURE);
    }

    // 开启混杂模式
    if(ioctl(s, SIOCGIFFLAGS, &ifr))
    {
        perror("ioctl get flags");
        close(s);
        exit(EXIT_FAILURE);
    }
    ifr.ifr_flags |= IFF_PROMISC;
    if(ioctl(s, SIOCSIFFLAGS, &ifr))
    {
        perror("ioctl set promisc");
        close(s);
        exit(EXIT_FAILURE);
    }

    saddr.sll_family = AF_PACKET;
    saddr.sll_ifindex = ifr.ifr_ifindex;
    saddr.sll_protocol = htons(ETH_P_ALL);

    if (bind(s, (struct sockaddr *)&saddr, sizeof(saddr)))
    {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    // 设置非阻塞模式
    stat = fcntl (s, F_SETFL, O_NONBLOCK);
    if (stat < 0)
        perror ("fcntl non-block");

    while(1)
    {
        cc = read (s, buf, sizeof(buf));
        if(cc < 0)
        {
            if(errno != EAGAIN)
            {
                perror("read");
                close(s);
                exit(EXIT_FAILURE);
            }
            // 无数据时短暂休眠,避免占用过高CPU
            usleep(1000);
            continue;
        }
        printf("Captured %d bytes\n", cc);
        // 处理数据包逻辑
    }

    close(s);
    return 0;
}

额外说明

  • 开启混杂模式需要root权限,运行程序时需使用sudo
  • 若不再需要混杂模式,程序退出前可恢复网卡原有标志位(移除IFF_PROMISC),避免影响网卡默认行为

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 01:05:37