You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用libpcap比较接口IPv4与数据包源地址时判断异常的问题咨询

问题原因:inet_ntoa的静态缓冲区复用陷阱

你遇到的问题根源在于inet_ntoa()函数的一个关键特性——它使用静态分配的缓冲区来存储转换后的IP字符串,每次调用这个函数都会覆盖缓冲区里之前的内容。

让我们拆解一下你的代码执行流程:

  1. 你调用dev_ip = inet_ntoa(...),此时静态缓冲区被填充为网卡的IPv4地址字符串,dev_ip指向这个缓冲区的起始地址。
  2. 接着你调用printf("inet_ntoa: %s\n",inet_ntoa(ip->ip_src)),这时候inet_ntoa会把静态缓冲区里的内容替换成数据包源IP的字符串,然后返回同一个缓冲区的地址。
  3. 当你执行strcmp(dev_ip, inet_ntoa(ip->ip_src))时,dev_ip指向的还是那个静态缓冲区,而第二次调用inet_ntoa(ip->ip_src)又一次覆盖了缓冲区内容,所以此时两个参数指向的是同一个内存地址里的相同字符串,strcmp自然会返回0(判定相等),不管实际IP是否相同。

解决方案:复制字符串到独立缓冲区

要解决这个问题,你需要把inet_ntoa返回的字符串复制到自己分配的内存里,避免静态缓冲区被覆盖。修改代码如下:

// retrieve IP address of interface
char * dev_name = "eth0";
struct ifreq ifr;
int fd;
// 分配独立缓冲区存储网卡IP,长度足够容纳IPv4字符串(最长15字符+1结束符)
char dev_ip[INET_ADDRSTRLEN] = {0}; 
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);
// 将inet_ntoa返回的字符串复制到自己的缓冲区
strcpy(dev_ip, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
printf("IPv4 address: %s\n", dev_ip);

// 同样,先把数据包源IP复制到临时缓冲区再使用
char src_ip[INET_ADDRSTRLEN] = {0};
strcpy(src_ip, inet_ntoa(ip->ip_src));
printf("inet_ntoa: %s\n", src_ip);

if (strcmp(dev_ip, src_ip) == 0)
    printf("EQUAL!\n");

另外,如果你使用的是较新的C标准或系统,更推荐使用**线程安全的inet_ntop()**函数,它不需要依赖静态缓冲区,而是由用户提供缓冲区,从根源上避免这类问题:

char dev_ip[INET_ADDRSTRLEN] = {0};
inet_ntop(AF_INET, &((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr, dev_ip, INET_ADDRSTRLEN);

char src_ip[INET_ADDRSTRLEN] = {0};
inet_ntop(AF_INET, &ip->ip_src, src_ip, INET_ADDRSTRLEN);

if (strcmp(dev_ip, src_ip) == 0)
    printf("EQUAL!\n");

inet_ntop()不仅线程安全,还支持IPv6,是更现代、更可靠的选择。

内容的提问来源于stack exchange,提问作者imll

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:09:37