从一个混杂的networking设备读取

我想写一个无线stream量的实时分析工具。

有谁知道如何从C中的混杂(或嗅探)设备读取?

我知道你需要有root权限才能做到这一点。 我想知道是否有人知道这样做有什么function。 普通套接字在这里似乎没有意义。

在Linux上,使用PF_PACKET套接字从原始设备读取数据,例如以混杂模式运行的以太网接口:

s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) 

这将发送到您的套接字的每个数据包的副本。 不过,很可能你并不需要每一个数据包。 内核可以使用BPF( 伯克利包过滤器)执行第一级过滤 。 BPF本质上是一个基于堆栈的虚拟机:它处理一小组指令,例如:

 ldh = load halfword (from packet) jeq = jump if equal ret = return with exit code 

BPF的退出代码告诉内核是否将数据包复制到套接字中。 可以使用setsockopt(s,SOL_SOCKET,SO_ATTACH_FILTER,)直接编写相对较小的BPF程序。 (警告:内核需要一个struct sock_fprog,而不是一个struct bpf_program,不要混合起来,否则你的程序将不能在某些平台上工作)。

对于任何相当复杂的事情,你真的想使用libpcap。 BPF的功能是有限的,特别是在每个数据包可执行的指令数量方面。 libpcap将负责将复杂的过滤器分成两部分,内核执行第一级过滤,功能更强大的用户空间代码丢弃实际上不想看到的数据包。

libpcap也从应用程序代码中抽象出内核接口。 Linux和BSD使用类似的API,但Solaris需要DLPI,Windows使用其他的东西。

我曾经听过原始的以太网帧,并最终创建了一个包装。 通过使用设备名称调用该函数,ex 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; } 

然后,当你有你的套接字,你可以使用select来处理数据包到达。

您可以使用tcpdump和Wireshark也使用的pcap库(请参阅http://www.tcpdump.org/pcap.htm )。

你为什么不使用WireShark ?

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

Linux上的WireShark能够捕获PLCP(物理层汇聚协议)头信息。