Linux为何重发并修改RAW Socket发送的802.11帧?
问题:Linux RAW Socket发送802.11帧时被系统修改的原因与解决办法
问题描述
- 在Unix系统中使用
sendto()发送RAW Socket数据包,普通数据包正常,但发送802.11帧时,系统会自动重发并修改数据包:- 原26字节的Radiotap头部被修改为13字节,末尾4字节的FCS(帧校验序列)被删除,总字节数减少17字节
- Radiotap头部标志被修改,比如Channel、dbm Antenna signal字段被移除,data retries、TX标记被添加
- 使用支持监控模式的自定义网卡发送,复制其他程序的认证/ACK帧发送,在Ubuntu 20.04和Kali Linux中均出现此现象
- 若将数据包字节全设为0x01(破坏802.11结构),则不会触发重发
- 尝试去掉Radiotap头部发送,Wireshark提示无Radiotap头部错误;去掉前26字节后数据包畸形,仅发送端网卡能捕获到畸形包
原因分析
Linux内核的mac80211子系统在处理RAW Socket发送的802.11帧时,会默认介入修改数据包,核心原因如下:
- Radiotap头部标准化:内核会校验并重新生成Radiotap头部,若你发送的头部包含非标准字段或格式不符合预期,内核会丢弃自定义字段,仅保留它认可的必要字段,生成简化版头部。
- FCS自动处理:内核默认会为802.11帧计算并添加FCS,因此你手动携带的FCS会被直接删除,替换为内核生成的版本(或直接丢弃你提供的4字节)。
- 合法帧重发机制:当内核识别出这是合法的802.11管理帧(如认证/ACK帧),会触发mac80211的重发逻辑以确保送达;若数据包结构被破坏(全0x01),内核无法识别为合法802.11帧,就不会触发重发和修改逻辑。
解决办法
- 禁用内核自动处理的Socket选项:
- 禁用ACK与重发机制:
int no_ack = 1; setsockopt(sockfd, SOL_IEEE80211, IEEE80211_TXCTL_NO_ACK, &no_ack, sizeof(no_ack)); - 保留自定义FCS,禁用内核自动生成:
int no_fcs = 1; setsockopt(sockfd, SOL_IEEE80211, IEEE80211_TXCTL_NO_FCS, &no_fcs, sizeof(no_fcs));
- 禁用ACK与重发机制:
- 构造标准Radiotap头部:参考Linux内核
include/net/ieee80211_radiotap.h定义,构造符合内核预期的标准头部,避免内核重新生成。 - 改用NL80211接口:通过netlink使用NL80211接口,可绕过mac80211的部分处理逻辑,直接向驱动发送原始帧,适合需要深度底层控制的场景。
深入排查方法
- 启用mac80211调试日志:执行
dmesg -n 8提升日志级别,发送帧后查看dmesg输出,获取内核修改数据包的具体细节。 - 检查自定义网卡驱动代码:查看驱动中关于802.11帧发送的处理逻辑,确认是否有额外的帧修改规则。
- 双向抓包对比:用
tcpdump同时捕获发送端和接收端的帧,直观对比原始发送帧与实际发出帧的差异。
内容的提问来源于stack exchange,提问作者C.Unbay
相关产品推荐
相关产品推荐

