我正在使用libpcap编写一个小型分析工具,该工具可以嗅探以太网设备上的流量,并对接收到的数据包执行某种分析。为了做到这一点,我有一个明显的libpcap循环:

void packet_loop(u_char *args, const struct pcap_pkthdr *header,
        const u_char *packetdata) {
    int size = (int)header->len;

    //Before we map the buffer to the ethhdr struct,
    //we check if the size fits
    if (ETHER_HDR_LEN > size)
        return;

    const struct ethhdr *ethh = (const struct ethhdr *)(packetdata);

    //If this protocol is IPv4 and the packet size is bigger than
    //ETH hdr size
    if (ETHERTYPE_IP == ntohs(ethh->h_proto)) {

        //Before we map the buffer to the iph struct,
        //we check if the size fits
        if (ETHER_HDR_LEN + (int)sizeof(struct iphdr) > size)
            return;

        const struct iphdr *iph = (const struct iphdr*)
            (packetdata + sizeof(struct ethhdr));

        //If this protocol isn't UDP and the header length
        //isn't 5 (20bytes)
        if (IPPROTO_UDP != iph->protocol && 5 != iph->ihl)
            return;

        //eval_udp(packetdata, size);
        const struct udphdr *udph = (const struct udphdr*)
            (packetdata + sizeof(struct ethhdr) +
             sizeof(struct iphdr));

        if (DATA_SRCPORT == ntohs(udph->uh_sport) &&
            DATA_DESTPORT == ntohs(udph->uh_dport)) {
            analyse_data(packetdata);
        }
    }
}


会在收到特定数据包类型时调用以下代码。如您所见,我正在使用静态变量来跟踪前一个数据包,以便比较两个数据包。

void analyse_data(const uint8_t *packet)
{
    if (!packet)
        return;

    static const uint8_t *basepacket;

    //If there was no packet to base our analysis on, we will wait for one
    if (!basepacket) {
        basepacket = packet;
        return;
    }

    const struct dataheader *basedh = (const struct dataheader *)
          (__OFFSETSHERE__ + basepacket);
    const struct dataheader *dh = (const struct dataheader *)
          (__OFFSETSHERE__ + packet);

    printf("%d -> %d\n", ntohs(basedh->sequenceid),
                         ntohs(dh->sequenceid));

    basepacket = packet;
    return;
}


struct dataheader是常规结构,就像etthdr一样。我希望打印输出像这样:

0 -> 1
1 -> 2
2 -> 3


不幸的是,我得到了不同的打印输出,这基本上是正确的。但是大约每20-40个数据包,我看到以下行为(示例):

12->13
13->14
0->15
15->16
...


可能有趣的是,这不会发生,当我只收到我要照顾的特定类型的数据包(8-10 Mbit / s)时。但是,只要在“常规”网络环境(大约100Mbit / s)中使用我的工具,就会出现这种情况。我检查了我的if语句,该语句过滤了可以正常工作的数据包(检查UDP源和目标端口)。 Wireshark还向我展示了那些端口上没有一个不是该特定类型的数据包。

最佳答案

libpcap控制它传递到您的packet_loop的数据包数据。一旦packet_loop返回,就无法保证包数据的指针指向什么-libpcap可能会将包丢掉,或者它会为新包重用相同的空间。

这意味着如果要比较2个数据包,则必须复制1个数据包-无法将一次调用中的指针保存到packet_loop,并且希望该指针有效并在以后的调用中指向同一数据包packet_loop。因此您的代码可以更改为

void analyse_data(const uint8_t *packet, int size )
{
    if (!packet)
        return;

    static const uint8_t basepacket[1024*64];
    static int has_basepacket;

    //If there was no packet to base our analysis on, we will wait for one
    if (!has_basepacket){
        if (size < sizeof basepacket) {
            memcpy(basepacket, packet, size);
            has_basepacket = 1;
         }
        return;
    }
    ...


另外,请确保在各处验证尺寸。仅仅因为以太网类型说它是一个IPv4数据包,并不意味着您可以信任它包含完整的IP数据包。 IP标头说它是20个字节,并不意味着您可以信任它包含完整的IP数据包,对于尝试解码的所有层,依此类推。

关于c - 函数内部的静态const uint8_t更改值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47711963/

10-12 15:05