从混杂模式网络设备中读取数据

10

我想编写一个用于无线流量实时分析的工具。

有人知道如何在C语言中从混杂模式(或嗅探)设备读取数据吗?

我知道需要具有root权限才能这样做。我想知道是否有人知道必要的函数是什么。普通的套接字在这里似乎没有意义。


在Linux中?你的帖子没有说明操作系统,但是我们应该假设你使用“root”是指Linux吗? - GEOCHET
5个回答

17
在Linux中,您可以使用PF_PACKET套接字从原始设备(例如以混杂模式运行的以太网接口)读取数据:
s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))

这将向您的套接字发送接收到的每个数据包的副本。但是,您很可能并不需要每个数据包。内核可以使用BPF(Berkeley Packet Filter)执行第一级过滤。BPF本质上是一个基于堆栈的虚拟机:它处理一小组指令,例如:
ldh = load halfword (from packet)  
jeq = jump if equal  
ret = return with exit code  

BPF的退出代码告诉内核是否将数据包复制到套接字。可以直接编写相对简短的BPF程序,使用setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER)。 (警告:内核使用struct sock_fprog而不是struct bpf_program,请勿混淆,否则您的程序将无法在某些平台上运行)。
对于任何相当复杂的内容,确实需要使用libpcap。BPF在其所能执行的每个包含指令数量方面都有限制。 libpcap 将处理将复杂过滤器拆分为两个部分,其中内核执行第一级过滤,更有能力的用户空间代码删除未实际想要查看的数据包。 libpcap还将内核接口从应用程序代码中抽象出来。 Linux和BSD使用类似的API,但Solaris需要DLPI,而Windows使用其他东西。

实际上,libpcap不会将过滤器分成两个部分。但是,是的,libpcap是您想要使用的 - 它知道如何在不同平台上将接口置于混杂模式下(例如,在Linux上仅使用ETH_P_ALL是不够的;这是“SAP混杂”,因为您可以获取所有数据包而不考虑协议类型,但它不是“物理混杂”,因为适配器不会将未发送到主机的单播数据包传递给主机)。 - user862787

8

我曾经需要监听原始以太网帧,最终创建了一个包装器。通过使用设备名称(例如eth0)调用函数,我得到了一个处于混杂模式的套接字。

您需要做的是创建一个原始套接字,然后将其置于混杂模式。这是我的做法:

int raw_init (const char *device)
{
    struct ifreq ifr;
    int raw_socket;

    memset (&ifr, 0, sizeof (struct ifreq));

    /* Open A Raw Socket */
    if ((raw_socket = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
    {
        printf ("ERROR: Could not open socket, Got #?\n");
        exit (1);
    }

    /* Set the device to use */
    strcpy (ifr.ifr_name, device);

    /* Get the current flags that the device might have */
    if (ioctl (raw_socket, SIOCGIFFLAGS, &ifr) == -1)
    {
        perror ("Error: Could not retrive the flags from the device.\n");
        exit (1);
    }

    /* Set the old flags plus the IFF_PROMISC flag */
    ifr.ifr_flags |= IFF_PROMISC;
    if (ioctl (raw_socket, SIOCSIFFLAGS, &ifr) == -1)
    {
        perror ("Error: Could not set flag IFF_PROMISC");
        exit (1);
    }
    printf ("Entering promiscuous mode\n");

    /* Configure the device */

    if (ioctl (raw_socket, SIOCGIFINDEX, &ifr) < 0)
    {
        perror ("Error: Error getting the device index.\n");
        exit (1);
    }

    return raw_socket;
}

今日免费次数已满, 请开通会员/明日再来

2

0

在Linux上,WireShark具有捕获PLCP(物理层汇聚协议)头信息的能力。


0

为什么不使用类似WireShark这样的工具呢?

它是开源的,所以即使你不想直接使用它,至少你可以从中学到一些东西。


我不确定 WireShark 是否能够捕获完整的无线数据包。我认为它只配置了常规 MAC 地址而非无线 MAC 地址。我需要能够查看来自多个 ESSID 的流量。 - jbleners
再次强调,我会从查看Wireshark源代码开始。 - GEOCHET
1
WireShark在Windows上无法使用无线网卡(句号)。 - leppie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接