Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用pcap进行捕获可以';你跟不上吗?_C++_Objective C_Pcap_Libpcap - Fatal编程技术网

C++ 使用pcap进行捕获可以';你跟不上吗?

C++ 使用pcap进行捕获可以';你跟不上吗?,c++,objective-c,pcap,libpcap,C++,Objective C,Pcap,Libpcap,对于我正在为OSX构建的一个小工具,我想捕获从某个以太网控制器发送和接收的数据包的长度 当我取出以太网卡时,我还得到了额外的信息,比如最大数据包大小、链路速度等 当我启动(我称之为“trafficMonitor”)时,我会这样启动它: static void initializeTrafficMonitor(const char* interfaceName, int packetSize) { char errbuf[PCAP_ERRBUF_SIZE]; pcap_t* ses

对于我正在为OSX构建的一个小工具,我想捕获从某个以太网控制器发送和接收的数据包的长度

当我取出以太网卡时,我还得到了额外的信息,比如最大数据包大小、链路速度等

当我启动(我称之为“trafficMonitor”)时,我会这样启动它:

static void initializeTrafficMonitor(const char* interfaceName, int packetSize) {
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t* sessionHandle = pcap_open_live(interfaceName, packetSize, 1, 100, errbuf);
    if (sessionHandle == NULL)
    {
        printf("Error opening session for device %s: %s\n", interfaceName, errbuf);
        return;
    }

    pcap_loop(sessionHandle, -1, packetReceived, NULL);
}
void packetReceived(u_char* args, const struct pcap_pkthdr* header, const u_char* packet) {

    struct pcap_work_item* item = malloc(sizeof(struct pcap_pkthdr) + header->caplen);
    item->header = *header;
    memcpy(item->data, packet, header->caplen);
    threadpool_add(threadPool, handlePacket, item, 0);
}
提供的
interfaceName
是接口的BSD名称,例如
en0
packetSize
变量是一个整数,我在其中为该以太网适配器提供最大packetSize(当时似乎是合乎逻辑的)。例如,我的WiFi适配器的数据包大小为
1538

我的回调方法称为
packetReceived
,如下所示:

static void initializeTrafficMonitor(const char* interfaceName, int packetSize) {
    char errbuf[PCAP_ERRBUF_SIZE];
    pcap_t* sessionHandle = pcap_open_live(interfaceName, packetSize, 1, 100, errbuf);
    if (sessionHandle == NULL)
    {
        printf("Error opening session for device %s: %s\n", interfaceName, errbuf);
        return;
    }

    pcap_loop(sessionHandle, -1, packetReceived, NULL);
}
void packetReceived(u_char* args, const struct pcap_pkthdr* header, const u_char* packet) {

    struct pcap_work_item* item = malloc(sizeof(struct pcap_pkthdr) + header->caplen);
    item->header = *header;
    memcpy(item->data, packet, header->caplen);
    threadpool_add(threadPool, handlePacket, item, 0);
}
我将数据包的所有属性填充到一个新的结构中,并启动一个工作线程来分析数据包并处理结果。这不是让pcap等待,而是试图解决在添加此工作线程方法之前已经存在的问题

handlePacket
方法如下:

    void handlePacket(void* args) { 

        const struct pcap_work_item* workItem = args;
        const struct sniff_ethernet* ethernet = (struct sniff_ethernet*)(workItem->data);

        u_int size_ip;
        const struct sniff_ip* ip = (struct sniff_ip*)(workItem->data + SIZE_ETHERNET);
        size_ip = IP_HL(ip) * 4;
        if (size_ip < 20) {
            return;
        }
        const u_int16_t type = ether_packet(&workItem->header, workItem->data);
        switch (ntohs(type)) {
            case ETHERTYPE_IP: {

                char sourceIP[INET_ADDRSTRLEN];
                char destIP[INET_ADDRSTRLEN];

                inet_ntop(AF_INET, &ip->ip_src, sourceIP, sizeof(sourceIP));
                inet_ntop(AF_INET, &ip->ip_dst, destIP, sizeof(destIP));

                [refToSelf registerPacketTransferFromSource:sourceIP destinationIP:destIP packetLength:workItem->header.caplen packetType:ethernet->ether_type];

                break;
            }
            case ETHERTYPE_IPV6: {
                // handle v6
                char sourceIP[INET6_ADDRSTRLEN];
                char destIP[INET6_ADDRSTRLEN];

                inet_ntop(AF_INET6, &ip->ip_src, sourceIP, sizeof(sourceIP));
                inet_ntop(AF_INET6, &ip->ip_dst, destIP, sizeof(destIP));

                [refToSelf registerPacketTransferFromSource:sourceIP destinationIP:destIP packetLength:workItem->header.caplen packetType:ethernet->ether_type];

                break;
            }
        }
}
void handlePacket(void*args){
const struct pcap_work_item*workItem=args;
常量结构嗅探以太网*以太网=(结构嗅探以太网*)(工作项->数据);
u_int size_ip;
const struct sniff_ip*ip=(struct sniff_ip*)(工作项->数据+大小\u以太网);
尺寸ip=ip\U HL(ip)*4;
如果(尺寸_ip<20){
返回;
}
const u_int16_t type=以太数据包(&workItem->header,workItem->data);
开关(ntohs(类型)){
案例类型_IP:{
char sourceIP[INET_ADDRSTRLEN];
char destIP[INET_ADDRSTRLEN];
inet_ntop(AF_inet,&ip->ip_src,sourceIP,sizeof(sourceIP));
inet_ntop(AF_inet,&ip->ip_dst,destIP,sizeof(destIP));
[refToSelf RegisterPackageTransferFromSource:sourceIP destinationIP:Destinp packetLength:workItem->header.caplen packetType:ethernet->ethernet_type];
打破
}
案例ETHERTYPE_IPV6:{
//手柄v6
char sourceIP[INET6_ADDRSTRLEN];
char destIP[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6,&ip->ip_src,sourceIP,sizeof(sourceIP));
inet_ntop(AF_INET6,&ip->ip_dst,destp,sizeof(destp));
[refToSelf RegisterPackageTransferFromSource:sourceIP destinationIP:Destinp packetLength:workItem->header.caplen packetType:ethernet->ethernet_type];
打破
}
}
}
根据以太网数据包的类型,我试图确定它是使用IPv4还是IPv6地址发送的数据包。确定之后,我向Objective方法发送一些详细信息(源IP地址、目标IP地址和数据包长度)

我将数据包转换为tcpdump网站上解释的结构(http://www.tcpdump.org/pcap.html)

问题是pcap似乎跟不上接收/发送的数据包。要么我没有嗅探到所有的数据包,要么数据包长度错误

是否有人有任何我需要调整代码以使pcap捕获它们的指针,或者我有某种问题的指针

这些方法是从我的Objective应用程序调用的,
refToSelf
是对objC类的引用


编辑:我在后台线程中调用initializeTrafficMonitor,因为pcap\u循环被阻塞。

这是哪个版本的OS X?在Lion之前的版本中,在使用BPF的系统(如OS X)上,libpcap的默认缓冲区大小为32K字节。在Lion,苹果将libpcap更新为1.1.1版;在libpcap1.1.0中,默认的BPF缓冲区大小增加到512MB(这是大多数(如果不是所有)具有BPF的系统中的最大值)

如果这是雪豹,请尝试切换到新的
pcap\u create()
/
pcap\u activate()
API,并使用
pcap\u set\u buffer\u size()
将缓冲区大小设置为512MB。如果这是狮子或更晚,那不会有什么区别

如果您的程序无法跟上平均数据包速率,这将不会有帮助,但如果存在超过平均值的临时突发,这至少意味着更少的数据包丢失

如果您的程序无法跟上平均数据包速率,那么,如果您只需要数据包的IP地址,请尝试将快照长度(您称之为“packetSize”`)设置为一个足够大的值,以便仅捕获以太网报头以及IPv4和IPv6的IP地址。对于IPv4,34个字节就足够了(libpcap或BPF可能会将其四舍五入到一个更大的值),因为这是14个字节的以太网报头+20个字节的IPv4报头,没有选项。对于IPv6,它是54字节,对于14字节的以太网报头和40字节的IPv6报头。因此,请使用packetSize值54

注意,在这种情况下,您应该使用
struct pcap_pkthdr
len
字段,而不是
caplen
字段来计算数据包长度
caplen
是捕获的数据量,不会大于指定的快照长度
len
是“导线上”的长度


此外,您可能希望尝试在同一线程中运行pcap_loop()和所有处理,并避免为数据包数据分配缓冲区并复制数据包,以查看这是否会加快处理速度。如果您必须在单独的线程中执行这些操作,请确保完成后释放数据包数据。

很抱歉,我没有提到这一点,但目前我只针对Mountain Lion。谢谢你的回答,我会尝试一下。这样你就不需要用
pcap\u set\u buffer\u size()
增加缓冲区大小了。但是,您可能仍然希望使用54的快照长度。