【问题标题】:Why does pcap_sendpacket fail on Thunderbolt interface?为什么 pcap_sendpacket 在 Thunderbolt 接口上失败?
【发布时间】:2014-06-10 16:11:41
【问题描述】:

在一个多平台项目中,我使用 pcap 来获取所有网络接口的列表,打开每个(用户无法选择要使用的接口)并在每个上发送/接收数据包(以太网类型 0x88e1/HomePlugAV)。这在 Windows 和 Mac OS X 上运行良好,但有时在 Mac OS X 上pcap_sendpacketnetworksetup -listallhardwareports 列为“硬件端口:Thunderbolt 1”的接口上一段时间后会失败。错误是:

发送:没有可用的缓冲区空间

在机器启动后运行程序时,需要一些时间才能发生错误。当错误发生一次并且我停止我的程序时,当我重新启动我的程序而不重新启动机器时会立即发生错误。

ifconfig -v en9:

en9: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500 index 8
    eflags=80<TXSTART>
    options=60<TSO4,TSO6>
    ether b2:00:1e:94:9b:c1 
    media: autoselect <full-duplex>
    status: inactive
    type: Ethernet
    scheduler: QFQ 

networksetup -listallhardwareports(仅相关部分):

Hardware Port: Thunderbolt 1
Device: en9
Ethernet Address: b2:00:1e:94:9b:c1

测试表明,在 OS X 10.9 上,界面最初并未启动,但在 OS X 10.9.2 和 10.9.3 上,界面在启动后启动并运行。

在 OS X 10.9 ifconfig 最初说:

en5: flags=8822<BROADCAST,SMART,SIMPLEX,MULTICAST> mtu 1500 index 8

ifconfig en5 up 之后的问题行为在 OS X 10.9 上是相同的。

  1. 为什么 pcap_sendpacket 在 Thunderbolt 适配器上失败?
  2. 我的程序如何在打开之前检测到这是一个令人不安的界面?我知道我可以打开接口并尝试发送一个数据包,但我更愿意事先进行干净检测。

【问题讨论】:

  • ifconfig en9 在重启后打印什么(以及在关闭它之前?)。我在这里尝试将 Thunderbolt-to-Ethernet 适配器插入 Mavericks 机器,它创建了有问题的接口(编号不同),但“Thunderbolt 1”和“Thunderbolt 2”接口没有启动。
  • @GuyHarris 我已将ifconfig -v en9 的输出添加到我的问题中。您可能已经注意到,我还更新了我的问题:如果从未连接过 Thunderbolt 以太网适配器,问题也会存在。

标签: macos osx-mavericks pcap libpcap


【解决方案1】:

作为一种解决方法,您可以忽略“Thunderbolt 1”界面:

#include <stdio.h>

#include <pcap/pcap.h>

#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SCNetworkConfiguration.h>

const char thunderbolt[] = "Thunderbolt 1";

// Build with -framework CoreFoundation -framework SystemConfiguration
int main(int argc, char * argv[])
{
    // See: https://opensource.apple.com/source/configd/configd-596.13/SystemConfiguration.fproj/SCNetworkInterface.c
    // get Ethernet, Firewire, Thunderbolt, and AirPort interfaces
    CFArrayRef niArrayRef = SCNetworkInterfaceCopyAll();

    // Find out the thunderbolt iface
    char thunderboltInterface[4] = "";
    if(niArrayRef) {
        CFIndex cnt = CFArrayGetCount(niArrayRef);
        for(CFIndex idx = 0; idx < cnt; ++idx) {
            SCNetworkInterfaceRef tSCNetworkInterfaceRef = (SCNetworkInterfaceRef)CFArrayGetValueAtIndex(niArrayRef, idx);
            if(tSCNetworkInterfaceRef) {
                CFStringRef BSDName = SCNetworkInterfaceGetBSDName(tSCNetworkInterfaceRef);
                const char * interfaceName = (BSDName == NULL) ? "none" : CFStringGetCStringPtr(BSDName, kCFStringEncodingUTF8);

                CFStringRef localizedDisplayName = SCNetworkInterfaceGetLocalizedDisplayName(tSCNetworkInterfaceRef);
                const char * interfaceType = (localizedDisplayName == NULL) ? "none" : CFStringGetCStringPtr(localizedDisplayName, kCFStringEncodingUTF8);

                printf("%s : %s\n", interfaceName, interfaceType);

                if(strcmp(interfaceType, thunderbolt) == 0) {
                    // Make a copy this time
                    CFStringGetCString(BSDName, thunderboltInterface, sizeof(thunderboltInterface), kCFStringEncodingUTF8);
                }
            }
        }
    }
    printf("%s => %s\n", thunderbolt, thunderboltInterface);

    CFRelease(niArrayRef);
    return 0;
}

【讨论】:

  • 谢谢,这就是我要找的代码 sn-p。
  • 注意,CFStringGetCStringPtr 不再适用于 Mojave 上的 BSDName,需要 CFStringGetCString
【解决方案2】:

我猜

在机器启动后运行程序时,需要一些时间才能发生错误。当错误发生一次并且我停止我的程序时,当我重新启动程序而不重新启动机器时会立即发生错误。

这里可能发生的情况是接口未处于活动状态,因此没有传输给它发送的数据包(并且释放了它们的 mbuf), t 被丢弃,但只是留在接口的队列中以待传输。最终要么队列被填满,要么尝试为数据包分配一些资源失败,并且接口的驱动程序返回一个 ENOBUFS 错误。

这可能是一个 OS X 错误。

来自

在一个多平台项目中,我使用 pcap 获取所有网络接口的列表,打开每个(用户无法选择要使用的接口)并在每个上发送/接收数据包(以太网类型 0x88e1/HomePlugAV)。

我怀疑您没有在所有接口上发送;并非所有接口都具有具有以太网类型字段的链路层标头类型 - 例如,lo0 没有。

如果您正在构建以太网数据包,您只想在链路层标头类型(由pcap_datalink() 返回)为DLT_EN10MB 的接口上发送(“10MB”是一个历史产物;它指的是所有以太网类型,旧的实验性 3MB Xerox 以太网除外,它具有不同的链路层标头)。

您可能也不想打扰在某种意义上不“活跃”的界面(除了“启动”之外的某种意义上);不幸的是,没有独立于平台的 API 来确定这一点,因此您将不得不在此处使用 #ifdefs。这可能会排除数据包会堆积未发送并最终导致 ENOBUFS 错误的接口。

【讨论】:

  • 它看起来像一个 OS X 错误,但我不确定。我会尝试提交该错误。我正在在所有接口上发送,但我最近更改了它并正在调用 pcap_datalink。 Thunderbolt 适配器返回以太网,因此不会被过滤掉。关于激活状态,这是一个很好的提示,但有一些警告。如果状态发生变化,我想容忍,但出于性能原因,我不敢每次在发送数据包之前检查状态。这也只是一种解决方法 - 驱动程序应该丢弃数据包。
  • 您知道如何检查接口是否处于活动状态吗?就像 ifconfig 在输出 status: activestatus: inactive 作为每个接口的最后一行时所做的那样。
猜你喜欢
  • 1970-01-01
  • 2019-06-28
  • 1970-01-01
  • 2014-01-16
  • 2021-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-15
相关资源
最近更新 更多