使用libpcap比较接口IPv4与数据包源地址时判断异常的问题咨询
问题原因:inet_ntoa的静态缓冲区复用陷阱
你遇到的问题根源在于inet_ntoa()函数的一个关键特性——它使用静态分配的缓冲区来存储转换后的IP字符串,每次调用这个函数都会覆盖缓冲区里之前的内容。
让我们拆解一下你的代码执行流程:
- 你调用
dev_ip = inet_ntoa(...),此时静态缓冲区被填充为网卡的IPv4地址字符串,dev_ip指向这个缓冲区的起始地址。 - 接着你调用
printf("inet_ntoa: %s\n",inet_ntoa(ip->ip_src)),这时候inet_ntoa会把静态缓冲区里的内容替换成数据包源IP的字符串,然后返回同一个缓冲区的地址。 - 当你执行
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
相关产品推荐
相关产品推荐

