查询接口以查找具有libpcap

时间:2015-06-22 21:39:34

标签: c++ pcap libpcap

好的,所以我的系统可以连接到目标计算机上的任意数量的以太网端口。我的目标是遍历每个设备,收集大约20个数据包,或者如果它没有数据然后跳过它,直到我找到我正在寻找的数据,并选择该设备作为我的“捕获设备”。看起来很简单。但是,我很快就知道如果没有数据进入,libpcap不会简单地超时。因此,我尝试使用pcap_setnonblock将捕获设备设置为非阻塞模式。但是,这会导致我读到的目标端口完全被淘汰。这是我的代码。接受有关可能发生的事情的建议,或者甚至是更好的方法。感谢

PS。不要敲打Type1 Type2变量名,它们用于混淆。

pcap_if_t *alldevs;
pcap_if_t *d;
pcap_t *fp;
struct pcap_pkthdr *header;
const u_char *pkt_data;
char errbuf[PCAP_ERRBUF_SIZE];
const int FIND_DEVICE_PACKET_LIMIT = 20;

#ifdef WIN32
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) 
#else
    if (pcap_findalldevs(&alldevs, errbuf) == -1)
#endif
{
    cerr << "Error in pcap_findalldevs_ex: " << errbuf << endl;
    return;
}

// For each device, capture until timeout
//   or until a matching packet is found.
for(d=alldevs; d; d=d->next)
{        
    if ((fp = pcap_open_live(d->name,
                1514 /*snaplen*/,
                1 /*flags, 1=promiscuous, 0=not promiscuous*/,
                20 /*read timeout*/,
                errbuf)
                ) == NULL) 
    {
        cerr << endl << "Unable to open the adapter." << endl;
        continue;
    }

    int res = 0;
    int packetCounter = 0;


    pcap_setnonblock(fp, true, errbuf);

    // Capture at most FIND_DEVICE_PACKET_LIMIT packets
    //    to determine whether scanner is sending packets
    //    or no scanner found.
    while ((res = pcap_next_ex(fp, &header, &pkt_data)) >=0) {
        struct iphdr *iph = (struct iphdr *)(pkt_data +  sizeof(struct ethhdr));
        struct udphdr *udph = (struct udphdr*)(pkt_data + (iph->ihl*4)  + sizeof(struct ethhdr));
        u_int destPort = ntohs(udph->dest);

        if (destPort==TYPE1_DATA_PORT || destPort==TYPE1_GPS_PORT) {
            detectedScanners->type1 = true;
        } else if (destPort==TYPE2_DATA_PORT || destPort==TYPE2_STATUS_PORT || destPort==TYPE2_NMEA_PORT) {
            detectedScanners->type2 = true;
        }

        if (++packetCounter > FIND_DEVICE_PACKET_LIMIT) {
            break;
        }
    }

    if (detectedScanners->type1==true || detectedScanners->type2==true) {
        *interface = d->name;
        break;
    }
}

1 个答案:

答案 0 :(得分:1)

在非阻塞模式下,如果没有可读的数据包,pcap_next_ex()将返回0,并且 NOT 将返回任何数据包信息,因此,如果它返回0,则应该查看headerpacket_data指向的任何内容。

即,

while ((res = pcap_next_ex(fp, &header, &pkt_data)) >=0) {
    if (res != 0) {
        struct iphdr *iph = (struct iphdr *)(pkt_data +  sizeof(struct ethhdr));
        struct udphdr *udph = (struct udphdr*)(pkt_data + (iph->ihl*4)  + sizeof(struct ethhdr));
        u_int destPort = ntohs(udph->dest);

        if (destPort==TYPE1_DATA_PORT || destPort==TYPE1_GPS_PORT) {
            detectedScanners->type1 = true;
        } else if (destPort==TYPE2_DATA_PORT || destPort==TYPE2_STATUS_PORT || destPort==TYPE2_NMEA_PORT) {
            detectedScanners->type2 = true;
        }

        if (++packetCounter > FIND_DEVICE_PACKET_LIMIT) {
            break;
        }
    }
}

但请注意,您的程序将在该循环中持续旋转,消耗CPU,永远。这意味着您永远不会看过第一个设备。

您可能真正想做的是:

  • 打开所有设备,将他们的pcap_t *放入数组中,并将其置于非阻塞模式;
  • 对于每个设备,在UN * X上调用pcap_get_selectable_fd(),在Windows上调用pcap_getevent(),并将该调用的结果保存到数组中(可以使用并行数组或结构数组)使用pcap_t *intHANDLE作为成员);
  • 在循环中,在UN * X上的select()poll()int的所有pcap_get_selectable_fd()上使用WaitForMultipleObjects()HANDLE { {1}}来自Windows上的pcap_getevent(),当select() / poll() / WaitForMultipleObjects()返回时,请尝试从的每个中读取数据包pcap_t *使用pcap_next_ex(),并在收到数据包时对其进行处理。

这样,您可以并行扫描所有设备,并且不会旋转CPU。