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

如何在原始套接字中禁用Linux内核自动插入Radiotap头?

解决Linux内核自动添加Radiotap头的问题

好问题!我来帮你拆解一下你遇到的两个核心问题:内核自动添加Radiotap头的原因,以及如何阻止它,同时修复你当前Radiotap头构造的问题。

一、能不能阻止Linux内核自动添加Radiotap头?

答案是可以,但前提是你需要正确配置套接字选项,并且确保你构造的Radiotap头是符合规范的——内核只有在识别到你发送的帧已经包含一个有效的Radiotap头时,才会跳过自动添加的步骤;如果你的头不符合规范,内核会认为这是一个没有Radiotap头的802.11帧,从而自动补上一个。

要明确控制内核的行为,你需要在创建原始套接字后完成以下配置:

关键套接字配置步骤

  • 首先确保你的无线网卡处于监控模式(Monitor Mode),可以通过SIOCSIWMODE ioctl设置:
    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头:
    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头构造存在的问题

从你的代码来看,核心问题是没有处理字节序——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;
    }
    

总结

  1. 配置网卡为监控模式,并设置PACKET_TX_RADIO选项,告诉内核你自行处理Radiotap头。
  2. 修复Radiotap头的字节序问题,确保length和bitmap是小端序。
  3. 验证你的头符合Radiotap规范,内核才会认可它并跳过自动添加步骤。

按照上述步骤修改后,Wireshark应该会正确识别你构造的Radiotap头,不会再出现内核额外添加的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 12:37:44