简介:hostapd-2.10源码包面向Linux无线开发与嵌入式网络工程师,用于在Linux系统上以软件方式创建和管理WiFi热点,替代硬件AP实现主机模式接入点。包内共655个文件,以363个C源文件和235个头文件为核心,覆盖nl80211驱动、IEEE 802.11协议栈、WPA认证与P2P等模块,另含20个Makefile及mk、conf、rules等构建与配置脚本,整体约2.33MB,结构完整便于二次编译与裁剪。源码中可深入研读hostapd.conf配置解析、WPA/WPA2/WPA3安全协议实现、多频段与负载均衡策略,以及hostapd_cli命令行工具和日志排错机制,是理解无线接入点底层原理的实用参考。目前已有920人学习下载,适合需要定制热点功能、调试驱动兼容性或研究802.11n/ac协议细节的开发者。
1. 拿到 hostapd-2.10 源码后,我建议先跑通再谈改造
很多人第一次接触 hostapd-2.10 源码,是因为手里有一块支持 AP 模式的无线网卡,想把它变成一台能自己控制的软 AP。但直接翻源码很容易迷路:目录里既有驱动适配层,又有 WPA 状态机,还有 EAP 认证服务器,一眼看过去不知道从哪下手。我的习惯是先把它编译出来,用最小配置跑起一个热点,再回头拆模块。hostapd 本质是一个运行在用户态的守护进程,负责管理 802.11 的认证、关联、密钥协商和桥接,配合内核的 nl80211/mac80211 完成数据面转发。它适合做无线开发、嵌入式网关、测试仪表,也适合想深入理解 WPA/WPA2/WPA3 握手流程的人。这份 2.10 源码是完整的 C 工程,包含 hostapd、wpa_supplicant、hwsim 测试框架等,能直接编译出可执行文件。
2. 工程结构与构建系统:从 Makefile 到可执行文件
2.1 顶层目录到底放了什么
解压后第一层目录并不复杂,但每个目录职责分明。src/是核心代码,hostapd/是 AP 主程序入口,wpa_supplicant/是客户端程序,tests/里是 hwsim 测试脚本,hs20/是热点 2.0 相关。真正要改 AP 行为,重点看src/ap/、src/drivers/、src/eap_server/和src/crypto/。
| 目录 | 作用 | 改造频率 |
|---|---|---|
| src/ap | AP 管理、认证、关联、WPA 状态机 | 高 |
| src/drivers | 驱动适配层,nl80211 等 | 中 |
| src/eap_server | EAP 服务端方法 | 中 |
| src/crypto | 加密算法封装 | 低 |
| hostapd/ | main 入口、配置解析 | 高 |
| tests/ | hwsim 自动化测试 | 低 |
常见做法是先在hostapd/下看main.c和config_file.c,这两个文件决定了程序怎么启动、配置怎么读。src/ap/里的hostapd.c是事件循环和接口初始化,ieee802_11.c处理管理帧,wpa_auth.c是密钥协商核心。
2.2 编译前必须确认的依赖
hostapd 默认用make构建,但 2.10 的 Makefile 依赖.config文件。源码里自带defconfig,复制成.config后按需打开选项。最小依赖是 libnl 或 libnl-3、openssl 或 mbedtls。如果只做基础 WPA2-PSK,openssl 就够。
# 进入源码根目录 cp defconfig .config # 打开 nl80211 驱动和 WPA2 支持 sed -i 's/#CONFIG_DRIVER_NL80211=y/CONFIG_DRIVER_NL80211=y/' .config sed -i 's/#CONFIG_IEEE80211N=y/CONFIG_IEEE80211N=y/' .config sed -i 's/#CONFIG_IEEE80211AC=y/CONFIG_IEEE80211AC=y/' .config # 编译 hostapd make -j$(nproc) hostapd这段命令先复制默认配置,再打开 nl80211 驱动和 802.11n/ac 支持。CONFIG_DRIVER_NL80211是必须的,否则程序找不到现代 Linux 无线驱动接口。CONFIG_IEEE80211N和CONFIG_IEEE80211AC决定是否支持 HT/VHT 速率。编译完成后,hostapd/hostapd就是可执行文件。如果报错找不到libnl-3.0,装libnl-3-dev和libnl-genl-3-dev即可。
2.3 最小配置文件怎么写
hostapd 的配置文件是纯文本键值对,最简可用配置只需要指定接口、驱动、SSID 和密码。
# /etc/hostapd/hostapd.conf interface=wlan0 driver=nl80211 ssid=MyTestAP hw_mode=g channel=6 wpa=2 wpa_passphrase=12345678 wpa_key_mgmt=WPA-PSK rsn_pairwise=CCMPinterface是无线网卡名,driver=nl80211固定写死,hw_mode=g表示 2.4GHz,channel=6是信道。wpa=2启用 WPA2,wpa_key_mgmt=WPA-PSK用预共享密钥,rsn_pairwise=CCMP指定 AES 加密。启动命令是sudo ./hostapd/hostapd /etc/hostapd/hostapd.conf。如果网卡被 NetworkManager 占用,先nmcli dev set wlan0 managed no或直接停掉 NetworkManager。
提示:第一次跑建议用
-dd参数打开调试日志,能看到驱动能力和状态机迁移,排查问题非常直观。
3. 核心模块拆解:一个客户端从扫描到上网的完整链路
3.1 驱动适配层怎么把帧收上来
hostapd 不直接操作硬件,而是通过src/drivers/driver_nl80211.c与内核 mac80211 交互。初始化时调用nl80211_init,注册事件回调。当客户端发来认证帧,内核通过 netlink 上报NL80211_CMD_FRAME,hostapd 在process_event里分发到handle_auth。
// src/drivers/driver_nl80211.c 简化片段 static int process_event(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; // 解析 netlink 消息头 genlmsg_parse(nlmsg_hdr(msg), 0, tb, NL80211_ATTR_MAX, NULL); // 根据命令类型分发 switch (gnl->cmd) { case NL80211_CMD_FRAME: // 收到管理帧,交给 AP 层处理 handle_frame(drv, tb); break; case NL80211_CMD_NEW_STATION: // 新客户端关联 handle_station(drv, tb); break; } return NL_OK; }这段代码是 netlink 事件入口。genlmsg_parse把原始消息拆成属性表,gnl->cmd区分是收到帧还是新客户端。handle_frame会进一步判断帧类型是认证、关联还是探测请求。参数drv是驱动上下文,保存了接口索引和回调函数指针。改驱动适配时,重点看NL80211_CMD_FRAME和NL80211_CMD_NEW_STATION两个分支,前者决定管理帧怎么进状态机,后者决定客户端表怎么维护。
3.2 WPA 状态机与四次握手
WPA2-PSK 的核心是四次握手,代码在src/ap/wpa_auth.c。当客户端通过认证和关联后,hostapd 发起 EAPOL-Key 帧交换。wpa_auth_sm_event是状态机入口,处理WPA_AUTH_EAPOL_KEY_FRAME事件。
// src/ap/wpa_auth.c 简化片段 void wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) { switch (event) { case WPA_AUTH_EAPOL_KEY_FRAME: // 收到客户端 EAPOL-Key 帧 if (sm->wpa == WPA_VERSION_WPA2) { // 处理四次握手消息 2/4 或 4/4 wpa_sm_step(sm); } break; case WPA_AUTH_PMK_CACHE: // PMK 缓存命中,跳过完整握手 wpa_sm_step(sm); break; } }sm是每个客户端独立的状态机实例,保存了 ANonce、SNonce、PTK 等中间值。WPA_AUTH_EAPOL_KEY_FRAME表示收到密钥帧,wpa_sm_step根据当前状态决定发消息 1/4、3/4 还是完成。WPA_AUTH_PMK_CACHE是快速漫游场景,命中缓存可以省去完整握手。改这里通常是为了加自定义密钥派生或调试握手失败,建议在wpa_sm_step里加日志打印sm->state。
3.3 管理帧处理与客户端表
src/ap/ieee802_11.c负责解析认证和关联请求。handle_auth检查算法号和序列号,handle_assoc解析能力信息和速率集。客户端表在src/ap/sta_info.c,每个struct sta_info保存 MAC、AID、能力、密钥状态。
// src/ap/ieee802_11.c 简化片段 static void handle_auth(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt, size_t len) { u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg); u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction); // 只支持开放系统和共享密钥 if (auth_alg != WLAN_AUTH_OPEN && auth_alg != WLAN_AUTH_SHARED_KEY) { return; } // 分配或查找客户端状态 sta = ap_get_sta(hapd, mgmt->sa); if (!sta) { sta = ap_sta_add(hapd, mgmt->sa); } // 发送认证响应 send_auth_reply(hapd, sta, mgmt, auth_trans); }auth_alg区分开放系统和共享密钥,现代网络基本只用开放系统。ap_get_sta按 MAC 查找客户端,找不到就ap_sta_add新建。send_auth_reply构造响应帧。改这里常见需求是加 MAC 白名单或自定义认证算法,建议在ap_get_sta之后插入过滤逻辑,不要直接改send_auth_reply的帧结构。
4. 避坑与排查:编译、启动、握手失败怎么查
4.1 编译报错找不到 libnl
现象是make时报fatal error: netlink/netlink.h: No such file or directory。原因是系统没装 libnl 开发包。解决是apt install libnl-3-dev libnl-genl-3-dev,然后确认.config里CONFIG_DRIVER_NL80211=y没有被注释。如果还报错,检查CFLAGS是否包含/usr/include/libnl3,有些发行版头文件路径不同。
4.2 启动后提示 Could not set interface flags
现象是nl80211: Could not set interface flags或Failed to set interface up。原因是网卡被其他进程占用,或者接口名写错。解决是先ip link show确认接口存在,再nmcli dev set wlan0 managed no释放 NetworkManager,最后ip link set wlan0 up。如果用的是虚拟接口,确认iw dev能看到。
4.3 客户端连不上但日志显示认证成功
现象是 hostapd 日志里认证和关联都成功,但客户端拿不到 IP 或无法上网。原因是 hostapd 只负责二层,不负责 DHCP 和路由。解决是配置bridge=br0把无线接口加入网桥,再在网桥上跑 dnsmasq 或 udhcpd。常见做法是brctl addbr br0,brctl addif br0 wlan0,然后给 br0 配 IP 并开 DHCP。
4.4 四次握手卡在消息 2/4
现象是日志停在WPA: Sending EAPOL-Key 1/4后没有后续。原因是客户端不响应或加密套件不匹配。解决是检查rsn_pairwise是否包含客户端支持的 CCMP,wpa_key_mgmt是否匹配。如果客户端只支持 TKIP,把rsn_pairwise=CCMP TKIP加上。另外确认wpa_passphrase长度在 8 到 63 之间。
4.5 修改源码后 make 不重新编译
现象是改了src/ap/wpa_auth.c但make说 nothing to do。原因是 hostapd 的 Makefile 依赖.d文件,有时时间戳没更新。解决是make clean后重新make hostapd,或者直接touch src/ap/wpa_auth.c再编译。更稳妥的做法是改完先make -C src/ap再链接。
5. 二次开发改造:从改配置到加自定义认证模块
5.1 先确定改哪一层
hostapd 的改造分三个层次:配置层、驱动层、状态机层。配置层最简单,改hostapd.conf就能调信道、加密、SSID。驱动层改src/drivers/,适合换硬件或加私有 ioctl。状态机层改src/ap/,适合加自定义认证、计费、限速。我一般先用-dd跑一遍,看日志里哪个模块打印最多,再决定动哪里。
5.2 加一个 MAC 白名单过滤
最实用的改造是在认证前加白名单。在src/ap/ieee802_11.c的handle_auth里,ap_get_sta之后插入检查。
// 自定义白名单检查 static int is_mac_allowed(const u8 *addr) { // 这里可以从文件或数据库读取 const u8 allowed[] = {0x00,0x11,0x22,0x33,0x44,0x55}; return os_memcmp(addr, allowed, ETH_ALEN) == 0; } // 在 handle_auth 中调用 if (!is_mac_allowed(mgmt->sa)) { wpa_printf(MSG_INFO, "MAC " MACSTR " not allowed", MAC2STR(mgmt->sa)); return; // 直接丢弃,不回复 }is_mac_allowed是自定义函数,实际项目里会读配置文件或查数据库。os_memcmp是 hostapd 封装的比较函数,ETH_ALEN是 6 字节 MAC 长度。MACSTR和MAC2STR是日志格式化宏。注意直接return不回复认证响应,客户端会超时,比回复拒绝帧更省事。改完记得make hostapd并重启。
5.3 用 hwsim 做自动化验证
改完代码不能只靠手动连,tests/里有 hwsim 框架可以模拟多客户端。先编译mac80211_hwsim内核模块,再跑./tests/hwsim/run-tests.py。常见做法是写一个自定义测试脚本,调用hostapd和wpa_supplicant的测试接口,验证白名单是否生效。
# 加载 hwsim 模块,创建两个虚拟无线接口 modprobe mac80211_hwsim radios=2 # 启动 hostapd 测试实例 ./hostapd/hostapd -B -dd /tmp/hostapd.conf # 用 wpa_supplicant 模拟客户端连接 ./wpa_supplicant/wpa_supplicant -Dnl80211 -iwlan1 -c/tmp/wpa.confradios=2创建两个虚拟接口,一个做 AP 一个做 STA。-B让 hostapd 后台运行,-dd打开调试。wpa_supplicant用 nl80211 驱动连接。验证白名单时,把允许的 MAC 写进配置,看客户端能否拿到 EAPOL-Key。如果连不上但日志显示 MAC not allowed,说明过滤生效。
5.4 改造时的几个习惯
我每次改 hostapd 都会先git diff看改了哪些文件,再make clean && make hostapd全量编译,避免增量编译漏掉依赖。调试握手问题时,会在wpa_auth.c的wpa_sm_step入口加一行wpa_printf(MSG_DEBUG, "state=%d", sm->state),这样日志里能直接看到状态迁移。还有一点,hostapd 的配置文件解析在hostapd/config_file.c,加自定义配置项要同时改struct hostapd_config和解析函数,否则配置写了也不生效。从那以后我每次加新配置项都强制走一遍「结构体 → 解析 → 使用」三步,少一步都会翻车。希望帮到你。
本文还有配套的精品资源,点击获取