编译程序时<linux/if_arp.h>出现重复声明错误求助
编译用户空间程序时,<linux/if_arp.h>头文件引发重复声明错误,涉及IFF_UP、IFF_BROADCAST等枚举值,以及ifmap、ifreq、ifconf等结构体的重定义,导致无法编译。
编译错误信息
In file included from /usr/include/linux/netdevice.h:29, from /usr/include/linux/if_arp.h:27, from rcping.c:6: /usr/include/net/if.h:44:5: error: redeclaration of enumerator 'IFF_UP' 44 | IFF_UP = 0x1, /* Interface is up. */ | ^~~~~~ /usr/include/linux/if.h:83:9: note: previous definition of 'IFF_UP' with type 'enum net_device_flags' 83 | IFF_UP = 1<<0, /* sysfs */ | ^~~~~~ ...(省略其余重复错误) /usr/include/net/if.h:176:8: error: redefinition of 'struct ifconf' 176 | struct ifconf | ^~~~~~ /usr/include/linux/if.h:284:8: note: originally defined here 284 | struct ifconf {
待编译代码
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <linux/if_arp.h> #include <net/if.h> #include <asm/types.h> #include <libcap.h> #include <string.h> #define RCP 49152 #define sizepkt 512 struct RCP_packet { uint16_t srcport; uint16_t extport; char* payload; }; int main(int argc, char* argv[]) { int intextport = atoi(argv[1]); cap_t caps = cap_init(); cap_value_t *capvl = 0; cap_set_flag(caps, CAP_NET_RAW, 1, capvl, CAP_SET); int sockfd = socket(AF_PACKET, SOCK_RAW, RCP); if (sockfd < 0) { printf("Socket not created\n"); printf("%d\n", sockfd); return -1; } else { printf("Socket Created successfully\n"); } struct sockaddr_in *dst_addr; char buffer[sizepkt]; dst_addr->sin_family = AF_INET; dst_addr->sin_port = htons(intextport); inet_pton(AF_INET, "127.0.0.1", &dst_addr->sin_addr); struct sockaddr_ll *src_addr; src_addr->sll_family = AF_PACKET; src_addr->sll_protocol = htons(1560); src_addr->sll_ifindex = if_nametoindex("wlan0"); struct sockaddr *addr = (struct sockaddr *)&dst_addr; struct sockaddr *interlcal = (struct sockaddr *)&src_addr; struct RCP_packet *packet; packet->srcport = htons(49152); packet->extport = htons(intextport); strcpy(packet->payload, "This packet was sent using RCPing under the Really Crappy Protocol"); memcpy(buffer, &packet->srcport, sizeof(packet->srcport)); memcpy(buffer + sizeof(packet->srcport), &packet->extport, sizeof(packet->extport)); memcpy(buffer + sizeof(packet->srcport) + sizeof(packet->extport), packet->payload, 8); struct RCP_packet *rcp; rcp->srcport = htons(1560); rcp->extport = htons(intextport); int miku = bind(sockfd, interlcal, sizeof(interlcal)); if (miku < 0) { printf("Local interface couldn't be set up\n"); printf("%d", miku); return -1; } int jumanji = connect(sockfd, addr, sizeof(addr)); if (jumanji < 0) { printf("Couldn't establish a connection using RCP, unsurprisingly\n"); printf("%d", jumanji); return -1; } else { while (main) { ssize_t senresult = send(sockfd, buffer, sizeof(buffer), 0); if (senresult < 0) { printf("Package wasn't sent"); } } } }
1. 解决头文件冲突问题
错误根源是混合使用了内核头文件和用户空间标准头文件:
- 手动包含的
<net/if.h>是用户空间POSIX标准头文件,而<linux/if_arp.h>(内核头文件)会间接引入<linux/if.h>(内核版本的同名头文件),两者定义了完全重复的枚举和结构体,导致编译冲突。
修复方法:
将代码中的#include <linux/if_arp.h>替换为用户空间标准头文件#include <net/if_arp.h>,保留#include <net/if.h>即可。两个头文件属于同一标准体系,不会出现重复定义。
2. 修复代码中的其他致命问题
除头文件冲突外,代码还有多处会导致运行崩溃或逻辑错误的问题,需一并修复:
未初始化指针问题:
dst_addr、src_addr、packet、rcp均为未分配内存的野指针,直接访问其成员会触发段错误。改为声明结构体变量而非指针,或手动分配内存:// 示例:将指针改为栈变量 struct sockaddr_in dst_addr; struct sockaddr_ll src_addr; struct RCP_packet packet;CAP权限设置错误:
cap_value_t *capvl = 0;传入cap_set_flag会导致错误,需初始化包含目标权限的数组并将权限应用到进程:cap_value_t capvl[] = {CAP_NET_RAW}; cap_set_flag(caps, CAP_EFFECTIVE, 1, capvl, CAP_SET); cap_set_flag(caps, CAP_PERMITTED, 1, capvl, CAP_SET); cap_set_proc(caps); // 将权限应用到当前进程RCP_packet的payload未分配内存:payload是指针,直接strcpy会写入未知内存。改为固定大小数组:struct RCP_packet { uint16_t srcport; uint16_t extport; char payload[128]; // 改为固定大小数组 };while(main)逻辑错误:main是函数名,会被视为非零常量导致死循环,改为while(1)或添加终止条件。AF_PACKET套接字不支持
connect:
AF_PACKET是链路层套接字,无法使用connect建立连接,应改用sendto并指定目标链路层地址。sizeof(interlcal)和sizeof(addr)错误:
这两个是指针,sizeof得到的是指针长度而非结构体长度,应改为sizeof(src_addr)和sizeof(dst_addr)。
修复后的示例代码片段(关键部分)
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <net/if_arp.h> // 替换为用户空间标准头文件 #include <net/if.h> #include <asm/types.h> #include <libcap.h> #include <string.h> #include <unistd.h> #define RCP 49152 #define sizepkt 512 struct RCP_packet { uint16_t srcport; uint16_t extport; char payload[128]; // 改为固定大小数组 }; int main(int argc, char* argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s <port>\n", argv[0]); return 1; } int intextport = atoi(argv[1]); // 修复CAP权限设置 cap_t caps = cap_init(); cap_value_t capvl[] = {CAP_NET_RAW}; cap_set_flag(caps, CAP_EFFECTIVE, 1, capvl, CAP_SET); cap_set_flag(caps, CAP_PERMITTED, 1, capvl, CAP_SET); if (cap_set_proc(caps) == -1) { perror("cap_set_proc failed"); return 1; } cap_free(caps); int sockfd = socket(AF_PACKET, SOCK_RAW, htons(RCP)); // 协议号需用htons转换 if (sockfd < 0) { perror("Socket not created"); return -1; } printf("Socket Created successfully\n"); // 改用栈变量,避免野指针 struct sockaddr_ll src_addr = {0}; src_addr.sll_family = AF_PACKET; src_addr.sll_protocol = htons(RCP); src_addr.sll_ifindex = if_nametoindex("wlan0"); if (src_addr.sll_ifindex == 0) { perror("if_nametoindex failed"); close(sockfd); return 1; } int miku = bind(sockfd, (struct sockaddr*)&src_addr, sizeof(src_addr)); if (miku < 0) { perror("Local interface couldn't be set up"); close(sockfd); return -1; } struct RCP_packet packet = {0}; packet.srcport = htons(49152); packet.extport = htons(intextport); strncpy(packet.payload, "This packet was sent using RCPing under the Really Crappy Protocol", sizeof(packet.payload)-1); char buffer[sizepkt] = {0}; size_t offset = 0; memcpy(buffer + offset, &packet.srcport, sizeof(packet.srcport)); offset += sizeof(packet.srcport); memcpy(buffer + offset, &packet.extport, sizeof(packet.extport)); offset += sizeof(packet.extport); memcpy(buffer + offset, packet.payload, strlen(packet.payload)); offset += strlen(packet.payload); // AF_PACKET使用sendto发送,需设置目标链路层地址(示例用广播地址) struct sockaddr_ll dst_addr = {0}; dst_addr.sll_family = AF_PACKET; dst_addr.sll_protocol = htons(RCP); dst_addr.sll_ifindex = src_addr.sll_ifindex; unsigned char broadcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; memcpy(dst_addr.sll_addr, broadcast_mac, 6); dst_addr.sll_halen = 6; while (1) { ssize_t senresult = sendto(sockfd, buffer, offset, 0, (struct sockaddr*)&dst_addr, sizeof(dst_addr)); if (senresult < 0) { perror("Package wasn't sent"); } else { printf("Sent %zd bytes\n", senresult); } sleep(1); // 避免发送过快 } close(sockfd); return 0; }
内容的提问来源于stack exchange,提问作者The QNX girl

