【问题标题】:static const uint8_t inside function changes value函数内部的静态 const uint8_t 更改值
【发布时间】:2017-12-08 10:05:42
【问题描述】:

我正在使用 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 还向我显示,这些端口上没有一个数据包不属于该特定类型。

【问题讨论】:

  • 很可能是由于您尚未粘贴的代码中存在一些未定义的行为。
  • 嗯,出了点问题,这不是因为您在上面所做的简单比较和分配。
  • @TacoVox:你没有粘贴的部分包括整个程序的其余部分,而不仅仅是这个函数中的代码。一些错误可能会覆盖basepacket。您甚至没有显示printf 语句,因此我们看不到您打印的这些数字来自哪里。 (某些错误可能会更改数据包的序列号。)我们看不到nextpacket 是什么。我们看不到这个程序是否是多线程的。你遗漏了重要的事情。
  • 仍然不是一个完整的例子。您将一个指向 packet_loop() 的指针传递给您将其保存到 static 值中,然后在以后的迭代中取消引用。 packetdata 指针指向哪里?在调用packet_loop() 之间,该内存会发生什么变化。你已经把这一切都排除在外了。
  • @TacoVox 我实际上并没有忽略它。是的,你做到了。

标签: c network-programming libpcap


【解决方案1】:

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 数据包,等等您尝试解码的所有层。

【讨论】:

  • 感谢您的澄清!这就是我要找的:)
猜你喜欢
  • 1970-01-01
  • 2011-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-04
  • 1970-01-01
  • 1970-01-01
  • 2013-11-10
相关资源
最近更新 更多