第4章 深入理解wpa_supplicant · 深入理解Android:Wi-Fi、NFC和GPS卷(完整版) · 看云
本章主要内容
- 介绍wpa_supplicant的初始化
- 介绍EAP和EAPOL
- 介绍wpa_supplicant如何加入无线网络
4.1 概述
wpa_supplicant[1]是一个开源软件项目,它实现了Station[1]对无线网络进行管理和控制的功能。根据官方[2]描述,wpa_supplicant所支持的功能非常多,此处列举其中几个重要的功能点。
1)支持WPA和IEEE 802.11i所定义的大部分功能:
这部分功能集中在安全方面,包括:
- 支持WPA-PSK(即WPA-Personal)和WPA-Enterprise(即利用RAIDUS认证服务器来完成身份认证的情况)。
- 数据加密方面支持CCMP、TKIP、WEP104和WEP40。注意,WEP104和WEP40中的数字代表密钥的长度。104表示密钥长度为104个二进制位(如以ASCII字符个数来计算的话,WEP104支持的密钥长度为13个ASCII字符)。
- 完全支持WPA和WPA2,包括PMKSA缓存,预认证(pre-authentication)等功能。
- 支持IEEE 802.11r和802.11w,其中802.11r规范定义了快速基础服务转移(Fast Transition)功能,而802.11w则新增了对管理帧的安全保护机制。
- 支持WFA制定的Wi-Fi Proctected Setup功能、P2P、TDLS等。
2)支持多种EAP Method:
主要和802.1X中Supplicant的功能有关,wpa_supplicant支持多达25种EAP Method,包括:
- EAP-TLS:TLS(Transport Layer Security)本身是一种传输层安全协议,它利用密钥算法提供端点身份认证与通讯保密,其基础是公钥基础设施(public key infrastructure,简称PKI)。EAP-TLS定义于RFC 5216。
- EAP-PEAP:PEAP(Protected Extensible Authentication Protocol,可扩展EAP)由微软、思科以及RSA Security三个公司共同开发,是一种利用证书加用户名和密码来进行身份验证的方法。
- EAP-TTLS:它是TLS的拓展,全名为Tunneled Transport Layer Security(隧道传输层安全协议),相比TLS,它简化了认证过程中客户端的工作。
- EAP-SIM、EAP-PSK、EAP-GPSK等其他认证方法。
提示:读者可阅读参考资料[1]以了解更多EAP方法的知识。
3)对各种无线网卡和驱动的支持:
- 支持nl80211/cfg80211驱动和Linux Wireless Extension驱动[2]。
- 支持Windows平台中的NDIS驱动。
提示:wpa_supplicant虽然支持Windows平台,但笔者相信绝大多数读者使用的都是Windows自带的无线网络管理程序(或者Intel芯片相关软件提供的无线网络管理程序)。从功能角度来说,读者可认为wpa_supplicant是这些私有程序的一种开源实现。
Android做为开源世界的集大成者,它在无线网络管理和控制方面直接使用了wpa_supplicant。Android 4.1中,external目录下有两个和wpa_supplicant相关的目录,分别是wpa_supplicant_6和wpa_supplicant_8。6和8分别代表对应wpa_supplicant的版本号为0.6.10和2.0-devel。
提示:关于wpa_supplicant的发布历史,请读者参考http://hostap.epitest.fi/releases.html。
本书的分析目标是wpa_supplicant_8,它包含三个主要子目录,分别是:
- hostapd:当手机进入SoftAP模式时,手机将扮演AP的角色,故需要hostapd来提供AP的功能。
- wpa_supplicant:Station模式,也叫Managed模式。它是本书分析的重点。
- src:hostapd和wpa_supplicant中都包含了一些通用的数据结构和处理方法,这些内容都放在此src目录中。注意,hostapd/src和wpa_supplicant/src子目录均链接到此src目录。
wpa_supplicant是Android用户空间中无线网络部分的核心模块,所有Framework层中和Wi-Fi相关的操作最终都将借由wpa_supplicant来完成。另外,wpa_supplicant本身对802.11、802.1X和Wi-Fi Alliance定义的一些规范都有极好的支持。所以,分析它将是加深理解802.11及相关理论知识的一个非常重要的途径。
本章拟打算带领读者从两条分析路线来掌握wpa_supplicant和相关的功能模块。
- 路线一:首先将介绍wpa_supplicant的初始化过程。这条路线将帮助读者了解wpa_supplicant中常见的数据结构及之间的关系。这条路非常难走,请读者做好心理准备。
- 路线二:我们将通过命令行发送命令的方式触发wpa_supplicant进行相关工作,使得手机加入一个利用WPA-PSK进行认证的无线网络。这条路线将帮助读者了解wpa_supplicant中的命令处理、scan、association、4-way handshake等相关处理流程。
提示:后续章节还将围绕Android中无线网络技术开展更多的讨论:
1)第5章将介绍Android Framework中的WifiService及其相关模块。
2)第6、7章节将继续wpa_supplicant之旅,其内容和WPS、Wi-Fi P2P以及WifiP2pService有关。
为了行文方便,本书将用WPAS来表示wpa_supplicant。另外,后文代码分析中还能见到一种重要的数据结构,它也叫wpa_supplicant。请读者根据上下文信息来理解wpa_supplicant的含义。
正式开始分析之旅前,我们先来简单了解下wpa_supplicant。
-
注意,wpa_supplicant项目中还包含一个名为hostapd程序的代码,它实现了AP的功能,本书不讨论。官方地址为http://hostap.epitest.fi/。 ↩︎
-
根据审稿专家的反馈,wpa_supplicant仅支持Linux Wireless Extension V19以后的版本。 ↩︎
上一篇:第4章 深入理解wpa_supplicant下一篇:4.2 初识wpa_supplicant
4.2 初识wpa_supplicant
本节介绍WPAS一些外围知识,包括软件结构、编译配置、控制命令和对应控制API的用法。其中,控制命令的格式和API的用法将在后续介绍WifiService相关模块时会见到。另外,在研究WPAS时,能熟练掌握用git查询历史版本信息也非常关键。WPAS的故事首先从其软件架构开始。
上一篇:4.1 概述下一篇:
4.2.1 wpa_supplicant架构
4.3 wpa_supplicant初始化流程
Android系统中,WPAS启动是通过"setprop ctrl.start wpa_supplicant"来触发init进程去fork一个子进程来完成的。WPAS在init配置文件中被定义为一个service。图4-5所示为Note 2 init.smdk4x12.rc文件中关于wpa_supplicant的定义。
:-:
![](https://i-blog.csdnimg.cn/blog_migrate/73527e36d07518410eb96c8f88aebf6f.jpeg)
图4-5 init配置文件中的wpa_supplicant
图4-5中的黑框展示了wpa_supplicant的启动参数[1]。其众多参数中,最重要的是通过"-c"参数指定的WPAS启动配置文件(图4-5中,该配置文件全路径名为/data/misc/wifi/wpa_supplicant.conf)。
提示 wpa_supplicant源代码中包含一个启动配置文件的模板,该文件对各项配置参数都有说明。其文件路径为external/wpa_supplicant_8/wpa_supplicant/wpa_supplicant.conf。
Note 2中该配置文件的内容如图4-6所示。
:-:
![](https://i-blog.csdnimg.cn/blog_migrate/2d2e1f14a822b28bb5c4ba9c2cae1998.jpeg)
图4-6 wpa_supplicant.conf文件内容
- ctrl_interface指明控制接口unix域socket的文件名。
- update_config表示如果WPAS运行过程中修改了配置信息,则需要把它们保存到此wpa_supplicant.conf文件中。
- 从device_name到config_method都和WPS设置有关。后续章节介绍其作用。
- p2p等选项和Wi-Fi P2P有关。后续章介绍它们的作用。
- WPAS运行过程中得到的无线网络信息都会通过一个"network"配置项保存到此配置文件中。如果该信息完整,一旦WPAS找到该无线网络就会尝试用保存的信息去加入它(这也是为什么用户在settings中打开无线网络后,手机能自动加入周围某个曾经登录过的无线网络的原因)。
- network项包括的内容非常多。图中第二个network项展示了该无线网络的ssid、密钥管理方法(key management)、身份认证方法及密码等信息。network中的priority表示无线网络的优先级。其作用是,如果同时存在多个可用的无线网络,WPAS优先选择priority高的那一个。
下面正式进入WPAS的代码,先来看其入口函数main。
-
关于init.rc文件的解析及setprop的实现,读者可阅读《深入理解Android:卷Ⅰ》第3章。 ↩︎
上一篇:4.2.4 git的使用下一篇:4.3.1 main函数分析
4.4 EAP和EAPOL模块
我们在第3章曾介绍过EAP和EAPOL方面的知识,它们主要和EAP/EAPOL数据包格式以及数据包交互流程有关。在此基础上,本节将进一步讨论WPAS中图4-1所涉及的EAP StateMachine和EAPOL State Machine这两个模块。
提示 虽然图4-1所示这两个模块名字中都带State Machine一词,但笔者更愿意称它们为EAP模块和EAPOL模块,其原因我们后续将会见到。另外,为了行文方便,以后将用SM代表State Machine。
本节先来介绍EAP模块,它和RFC4137协议有关。
上一篇:4.3.4 wpa_supplicant_init_iface函数分析下一篇:4.4.1 EAP模块分析
4.5 wpa_supplicant连接无线网络分析
本节将介绍本章第二条分析路线,即通过命令行发送命令的方式触发wpa_supplicant进行相关工作,使手机加入一个利用WPA-PSK进行认证的无线网络。
以笔者的Note 2为例,整个过程用到的命令如下所示。
命令示例
adb root #获取手机root用户权限。只有root被破解的手机才能成功
adb shell #登录手机shell
#笔者事先已编译wpa_cli并将其放到/system/bin目录中。这个命令用于启动wpa_cli,-i参数指明unix域控制
#socket文件名,它应该和wpa_supplicant启动时设置的控制接口文件名一致
wpa_cli -iwlan0 #该命令执行后,将进入wpa_cli进程,后续操作都在此进程中开展
#发送ADD_NETWORK命令给wpa_supplicant,它将返回一个新网络配置项的编号。请参考4.3.3.1"wpas_ssid结构
#体介绍"一节
ADD_NETWORK #假设wpa_supplicant返回的新网络配置项编号为0
SET_NETWORK 0 ssid "Test" #设置0号网络的ssid为“Test”
SET_NETWORK 0 key_mgmt WPA-PSK #设置0号网络的key_mgmt为“WPA-PSK”
SET_NETWORK 0 psk "12345Test" #设置0号网络的psk为“12345Test”
ENABLE_NETWORK 0 #使能0号网络,它将触发wpa_supplicant扫描、关联等一系列操作直到加入无线网络“Test”
CTRL+C #退出wpa_cli
dhcpcd wlan0 #启动dhcpd,wlan0为无线接口设备名。dhcpcd可为手机从AP那获取一个IP地址
dhcpcd成功执行后,手机将从AP那分配到一个IP地址。至此,手机就可以使用“Test”无线网络了。
注意:上述命令执行前有几个注意事项:
- 先要在Settings中开启无线网络。这个操作完成了wlan驱动及相应固件加载的工作。该工作实际上由netd来完成,而wpa_cli无法完成它。
- 开启无线网络后,WifiService和wpa_supplicant都开始工作了。为了避免WifiService的干扰,可以把Settings中的那些已知的无线网络信息都清除。
- 由于wpa_supplicant支持多个客户端,所以wpa_cli可以和WifiService共同工作。只要不操作Settings中无线网络相关的选项,WifiService就不会干扰wpa_cli。
- 然后按上述步骤执行wpa_cli。
根据前文所述,所有来自客户端的命令都由wpa_supplicant_ctrl_iface_receive函数处理(参考4.3.4中“wpa_supplicant_ctrl_iface_init介绍”一节)。该函数代码非常简单,就是根据客户端发送的命令进行对应处理。
ctrl_iface_unix.c::wpa_supplicant_ctrl_iface_receive
static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,void *sock_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct ctrl_iface_priv *priv = sock_ctx;
char buf[4096]; int res; struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
char *reply = NULL; size_t reply_len = 0; int new_attached = 0;
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &from, &fromlen);
.....
buf[res] = '\0';
//客户端第一次和WPAS连接时,需要发送"ATTACH"命令
if (os_strcmp(buf, "ATTACH") == 0) {
......//略过相关处理
} .....//"DETACH"和"LEVEL"命令处理
else {
#if defined(CONFIG_P2P) && defined(ANDROID_P2P)
......//P2P处理。虽然WPAS编译时打开了CONFIG_P2P和ANDROID_P2P,但本章不讨论P2P相关的内容
#endif
//大部分的命令处理都在wpa_supplicant_ctrl_iface_process函数中
reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,&reply_len);
}
if (reply) {//回复客户端
sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,fromlen);
os_free(reply);
} ......
/*
Client成功ATTACH后,将通知EAPOL模块。因为有些认证流程需要用户的参与(例如输入密码之类的),
所以当客户端连接上后,EAPOL模块将判断是否需要和客户端交互。读者可阅读
eapol_sm_notify_ctrl_attached函数。
*/
if (new_attached)
eapol_sm_notify_ctrl_attached(wpa_s->eapol);
}
如上述代码所示,绝大部分命令都由wpa_supplicant_ctrl_iface_process函数处理。下面将按顺序来分析其处理ADD_NETWORK、SET_NETWORK以及ENABLE_NETWORK的代码。
上一篇:4.4.2 EAPOL模块分析下一篇:4.5.1 ADD_NETWORK命令处理
4.6 本章总结和参考资料说明
上一篇:4.5.3 ENABLE_NETWORK命令处理下一篇:
4.6.1 本章总结