如何在原始套接字中禁用Linux内核自动插入Radiotap头?
解决Linux内核自动添加Radiotap头的问题
好问题!我来帮你拆解一下你遇到的两个核心问题:内核自动添加Radiotap头的原因,以及如何阻止它,同时修复你当前Radiotap头构造的问题。
一、能不能阻止Linux内核自动添加Radiotap头?
答案是可以,但前提是你需要正确配置套接字选项,并且确保你构造的Radiotap头是符合规范的——内核只有在识别到你发送的帧已经包含一个有效的Radiotap头时,才会跳过自动添加的步骤;如果你的头不符合规范,内核会认为这是一个没有Radiotap头的802.11帧,从而自动补上一个。
要明确控制内核的行为,你需要在创建原始套接字后完成以下配置:
关键套接字配置步骤
- 首先确保你的无线网卡处于监控模式(Monitor Mode),可以通过
SIOCSIWMODEioctl设置:struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, "wlan0", IFNAMSIZ); ifr.ifr_mode = IW_MODE_MONITOR; if (ioctl(sock, SIOCSIWMODE, &ifr) < 0) { perror("Failed to set monitor mode"); close(sock); return -1; } - 然后,设置
PACKET_TX_RADIO套接字选项,告诉内核你会自行处理Radiotap头:
这个选项的作用是允许你在发送的数据包中包含自定义的Radiotap头,内核不会再自动添加。int enable = 1; if (setsockopt(sock, SOL_PACKET, PACKET_TX_RADIO, &enable, sizeof(enable)) < 0) { perror("Failed to set PACKET_TX_RADIO"); close(sock); return -1; }
二、你的Radiotap头构造存在的问题
从你的代码来看,核心问题是没有处理字节序——Radiotap规范明确要求length(16位)和bitmap(32位)字段必须使用小端字节序,而你直接用主机字节序赋值,这会导致内核无法正确解析你的Radiotap头,进而认为这是一个无效的头,于是自动添加了一个新的,而你构造的头被当成了后续数据的一部分(也就是Wireshark中显示的“额外字段值”)。
修复后的Radiotap头构造代码
你需要使用字节序转换函数(htole16、htole32)来确保字段是小端序:
// File headers.h struct radiotap_header { uint8_t version; // 必须为0 uint8_t pad; // 必须为0 uint16_t length; // Radiotap头的总长度(小端序) uint32_t bitmap; // 存在的字段位图(小端序) } __attribute__((packed)); // File main.cpp // main函数中的代码... std::vector<char> packet; // 初始化Radiotap头 radiotap_header radiotap; radiotap.version = 0; radiotap.pad = 0; // 转换为小端序:总长度是8(无额外字段) radiotap.length = htole16(8); // 位图为0表示没有额外字段,同样转换为小端序 radiotap.bitmap = htole32(0); // 确保packet有足够的空间存放Radiotap头 packet.resize(sizeof(radiotap) + /* 后续帧数据的长度 */); // 复制头到数据包起始位置 memcpy(packet.data(), &radiotap, sizeof(radiotap)); // 添加后续的802.1X帧数据... // 发送数据包 int bytesSent = sendto(sock, packet.data(), packet.size(), 0, (sockaddr*)&interface, socketLength); if (bytesSent <= 0) { std::cout << "Failed to send the packet\n"; return -1; } std::cout << "Sent: " << bytesSent << " bytes\n";
额外注意事项
- 如果你需要在Radiotap头中添加额外字段(比如信号强度、信道信息),需要更新
bitmap字段(设置对应的位),同时调整length字段的值,确保它包含所有额外字段的长度,并且所有字段都遵循小端序。 - 发送前确保你的套接字是
PF_PACKET类型,并且协议设置为ETH_P_802_11(避免不必要的帧干扰):int sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_802_11)); if (sock < 0) { perror("Failed to create raw socket"); return -1; }
总结
- 配置网卡为监控模式,并设置
PACKET_TX_RADIO选项,告诉内核你自行处理Radiotap头。 - 修复Radiotap头的字节序问题,确保
length和bitmap是小端序。 - 验证你的头符合Radiotap规范,内核才会认可它并跳过自动添加步骤。
按照上述步骤修改后,Wireshark应该会正确识别你构造的Radiotap头,不会再出现内核额外添加的情况。
内容的提问来源于stack exchange,提问作者Wew Auction
相关产品推荐
相关产品推荐

