libpcap:如何获取活动网络接口(Mac OSX)

Posted

技术标签:

【中文标题】libpcap:如何获取活动网络接口(Mac OSX)【英文标题】:libpcap: how to get active network interface (Mac OSX) 【发布时间】:2010-12-05 10:09:55 【问题描述】:

我正在使用 libpcap 来嗅探流量。我想在当前活动的网络设备上执行此操作(例如,具有分配 IP 地址的设备等)。最好的方法是什么?我假设我必须执行以下操作:

pcap_findalldevs(&alldevs, errbuf)

获取所有网络设备,然后循环并检查当前处于活动状态的设备。


编辑:以下函数

(pcap_lookupnet(dev, &net, &mask, errbuf) 

返回网络设备的网络地址和子网掩码。我在计算机上使用不同的以太网适配器运行了一些测试,当我在未连接到网络的适配器上调用它时,它返回 -1。这会是获得活动界面的防弹方法吗?是否会遗漏任何边缘情况?

【问题讨论】:

如果我同时使用两个不同的网络,或者甚至只是连接到同一个网络的两个适配器怎么办?我实际上定期使用这种方案,将适配器分配给不同的进程。 回到adirau's answer,如果我在连接了 2 个网络适配器的情况下运行 netstat -nr (unix),它会显示默认路由的两个适配器吗? 【参考方案1】:

pcap 用于查找符合某些用户定义规则的接口的 API 是微不足道的。您确实可以使用 pcap_findalldevs() 对所有适合使用的网络设备进行交互,或者使用 pcap_lookupdev() 来获取可以与 pcap 一起使用的下一个网络设备。在具有多个网络设备的系统上,定义要与嗅探器一起使用的接口可能会出现问题(代码方面),并且您希望为选择此类接口定义更明确的规则。此类规则通常是静态定义的(例如“安装了默认路由的活动接口”)。但是,您可能有多个默认路由(考虑负载平衡),在这里您可能想要嗅探所有路由,或者(例如)仅在 ppp 接口上嗅探。因此,我会说选择目标接口是在嗅探器之外解决的任务,而不是在运行时在嗅探器代码中解决的任务。

例如:

如果通过“活动接口”我们了解安装默认路由的接口(我这里假设是 linux 系统):

ip route show 0.0.0.0/0 | awk '  print $5 ;  ' | xargs ./sniffer

如果你想从你的嗅探器代码中获取安装了默认路由的活动接口,你宁愿使用 netlink(7) 或 proc(5) (/proc/net/route) 而不是 pcap 的设备查找 api,但是复杂度很高。

总之,接口查找逻辑可以很容易地编写到任何系统上的一些包装程序中,并将结果作为参数传递给您的嗅探器。

【讨论】:

我已经更新了我的问题,pcap_lookupnet 就足够了吗?理想情况下,我想检查嗅探器代码。 如果您使用 pcap_findalldevs() 循环遍历所有接口,则不需要 pcap_lookupnet() 来获取前者返回的每个设备上的 ipv4 信息。此信息包含在 pcap_findalldevs() 返回的设备信息中。同样,这实际上取决于您对“活动界面”的理解。如果它只是任何已启动并配置了 ipv4 地址的接口,那么是的。我不清楚 pcap_lookupnet() 如果在同一个接口上加载多个别名(没有虚拟接口,将返回 prolly 第一个 ip)在某些系统(如 FreeBSD)上会返回什么【参考方案2】:

为什么不在“任何”设备上捕获(在所有接口上捕获的伪设备)?

无论如何,这里有一个小 sn-p 可以帮助您找到“活动”接口

#include <stdio.h>
#include <pcap.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

static void
dump_addresses (pcap_addr_t *addresses)

 pcap_addr_t *addr = addresses;
 printf("(");
 while (addr) 
  struct sockaddr_in *ip = (struct sockaddr_in *)addr->addr;
  struct sockaddr_in *nm = (struct sockaddr_in *)addr->netmask;
  if (ip && nm)
   printf("%s/%s ",
     inet_ntoa(ip->sin_addr), inet_ntoa(nm->sin_addr));
  addr = addr->next;
 
 printf(")");


static void
devs_dump (pcap_if_t *devs)

 pcap_if_t *dev = devs;
 while (dev) 
  printf("dev: %s - %s - ",
    dev->name, dev->description);
  dump_addresses(dev->addresses);
  printf("\n");
  dev = dev->next;
 


int
main(int argc, char *argv[])

 int r;
 char errbuf[PCAP_ERRBUF_SIZE];
 pcap_if_t *devs;

 r = pcap_findalldevs (&devs, errbuf);
 if (r) 
  printf("Findalldevs: %d (%s)\n", r, errbuf);
  return -1;
 
 devs_dump(devs);
 pcap_freealldevs (devs);

 return 0;

【讨论】:

在所有设备上进行捕获是否存在重大开销?我希望嗅探器以最少的资源使用在后台运行。我问是因为我读到嗅探所有设备的唯一方法是在单独的线程上嗅探每个网络接口。这是真的吗? 我认为在“任何”而不是 eth0,1...N 上捕获更有效 你将如何捕捉'any;设备? 您能详细说明一下吗? “any”不是受支持的关键字。 pcap_open_live("any", SNAP_LEN, 1, 1000, errbuf) 给出错误“could not open device any” 根据我对另一个答案的评论,“any”仅适用于 Linux,并且使用 system-supplied libpcap,适用于 OS X Mavericks 及更高版本。【参考方案3】:

我以前曾多次走这条路,但通常发现自己回退到添加-i 开关以允许用户精确识别界面。

它使您的工作更简单,并避免任何边缘条件。

【讨论】:

【参考方案4】:

根据pcap_open_live(3):

DESCRIPTION
pcap_open_live() is used to obtain a packet capture handle to
   look at packets on the network.   device  is  a  string  that
   specifies  the  network device to open; on Linux systems with
   2.2 or later kernels, a device argument of "any" or NULL  can
   be used to capture packets from all interfaces.

但它现在似乎已被弃用,你应该使用 pcap_create(3)

【讨论】:

对不起,我忘了说我在 OS X 上做这个。那会很方便! pcap_create() 也支持“任何”设备 - 但是,在pcap_open_live()pcap_create() 中,它仅在 Linux 和 OS X Mavericks 或更高版本上受支持,并且只有 system libpcap(不是来自 tcpdump.org 的版本)支持 OS X Mavericks 及更高版本上的“任何”设备。

以上是关于libpcap:如何获取活动网络接口(Mac OSX)的主要内容,如果未能解决你的问题,请参考以下文章

sh macOS:获取当前活动的网络设备名称,接口,mac

Tcpdump抓包命令

#yyds干货盘点# 如何优雅的获取 Mac OS 系统 IP 地址?

Mac OS X网络接口

如何获取WiFi网络接口的MAC地址?

基于Libpcap实现一个网络数据包嗅探器