比较接口的 ipv4 地址和数据包的源地址 (libpcap)

Comparing ipv4 address of interface and source address of packet (libpcap)

我正在使用 libpcap 对 https://www.tcpdump.org/sniffex.c 中的 C 代码进行修改,以打印有关通过接口的 TCP 数据包的信息。

这是我尝试使用的回调代码示例,用于检查接收到的数据包的源字段是否等于当前接口的 IP 地址(以便仅分析传出数据包)。这是一个相当广泛的程序,所以我决定只包括有问题的部分:

// retrieve IP address of interface    
char * dev_name = "eth0";
struct ifreq ifr;
int fd;
char *dev_ip;

fd = socket(AF_INET, SOCK_DGRAM, 0);

// type of address to retrieve (IPv4)
ifr.ifr_addr.sa_family = AF_INET;

// copy the interface name in the ifreq structure
strncpy(ifr.ifr_name , dev_name , IFNAMSIZ-1);

ioctl(fd, SIOCGIFADDR, &ifr);
close(fd);

dev_ip = inet_ntoa(( (struct sockaddr_in *)&ifr.ifr_addr )->sin_addr);

printf("IPv4 address: %s\n", dev_ip);
printf("inet_ntoa: %s\n",inet_ntoa(ip->ip_src));

if (strcmp(dev_ip,inet_ntoa(ip->ip_src)) == 0)
    printf("EQUAL!\n");

但是,正如您在下面的屏幕截图中看到的,即使源 IP (inet_ntoa) 和接口 IP 地址 (IPv4 address) 不同,它们的值始终相等根据程序

可能是什么问题?

inet_ntoa returns 指向在 inet_ntoa 内部的静态内存中构造的字符串的指针。每次调用时它都会重新使用相同的静态内存。当你这样做时:

    dev_ip = inet_ntoa(...);

dev_ip 设置为指向该内部静态缓冲区。此时静态缓冲区包含一个表示接口地址的字符串,因此您的:

    printf("IPv4 address: %s\n", dev_ip);

显示预期结果。但是你这样做:

    printf("inet_ntoa: %s\n",inet_ntoa(ip->ip_src));

并且用代表数据包地址的字符串覆盖inet_ntoa的内部缓冲区。

但请记住 dev_ip 仍指向该内部缓冲区。所以当你这样做时:

    if (strcmp(dev_ip,inet_ntoa(ip->ip_src)) == 0)

(顺便说一句,用已经存在的数据包地址再次覆盖内部缓冲区)传递给 strcmp 的两个参数都是指向 inet_nota 内部缓冲区的指针,因此 strcmp 总是会发现目标字符串匹配——因为两个参数都指向同一个字符串。

要修复,请在调用后立即将 inet_ntoa 生成的字符串复制到本地缓冲区,或者执行类似以下操作:

    dev_ip = strdup(inet_ntoa(...));

(当您不再需要该字符串时,请记住 free(dev_ip))或者更好的是,如果您的平台具有 inet_ntoa_r,则使用 inet_ntoa 的线程安全变体功能。 inet_ntoa_r 不使用(并重复使用)内部缓冲区。它要求其调用者提供放置字符串的缓冲区。