首页 > 解决方案 > 比较接口的ipv4地址和数据包的源地址(libpcap)

问题描述

我正在使用对https://www.tcpdump.org/sniffex.c中 C 代码的修改来使用 libpcap 打印有关通过接口的 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) 不同,根据程序,它们的值总是相等的。

程序输出

问题可能是什么?

标签: ciplibpcap

解决方案


inet_ntoa返回一个指向字符串的指针,该字符串在 . 内部的静态内存中构造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调用的线程安全变体。不使用(和重复使用)内部缓冲区。它要求其调用者提供将放置字符串的缓冲区。inet_ntoa_rinet_ntoa_r


推荐阅读