ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux命令行连接WiFi:wpa_cli实战指南与高频排错全解

Linux命令行连接WiFi:wpa_cli实战指南与高频排错全解 在Linux终端里连WiFiwpa_cli和nmcli是两条最常见的命令行路子。绝大多数人只会点右上角的图形网络图标可一旦你面对的是无桌面环境的服务器、一块只有串口和SSH的嵌入式板卡又或者图形网络管理器自己崩了那点图形入口全都没用。我经常在机房维护无头Linux机器有一次机器断电重启后网卡没自动拉起手边还没有网线靠的就是wpa_cli在纯命令行里把WiFi连起来。wpa_cli是wpa_supplicant自带的命令行控制工具负责无线扫描、网络配置、认证连接全部操作脱离图形界面完成报错信息也直白可查。这篇文章我按实际操作顺序把完整链路捋一遍从驱动检查到开机自连再到高频报错的定位方法适合运维、嵌入式开发和所有在Linux上被无线网卡折腾过的人。1. wpa_supplicant和wpa_cli的分工先搞清你在操作的到底是谁用wpa_cli之前必须弄明白这套体系里其实有两个程序在配合。wpa_supplicant是一个常驻后台的守护进程它负责802.11无线协议里最核心的认证和密钥协商包括WPA/WPA2/WPA3、802.1X企业认证以及连接后的漫游和重连逻辑这些状态机全由它维护。wpa_cli只是一个前端控制工具它通过UNIX socket和wpa_supplicant通信把你敲进去的命令转成控制信令发给守护进程执行。这个架构理解透了排错思路会清晰很多。比如wpa_cli报“Could not connect to wpa_supplicant”很多时候并不是你的命令输错了而是后面的守护进程压根没起来或者它监听的socket路径和你指定的接口对不上。默认情况下控制接口socket在/var/run/wpa_supplicant/目录下如果守护进程看守的是wlan0就会有/var/run/wpa_supplicant/wlan0这个文件。很多教程直接让你用wpa_cli -i wlan0却没说这个-i参数必须和wpa_supplicant启动时的接口名一致。1.1 为什么不用iwconfig或者直接改配置文件早期Linux配无线网卡常用iwconfig但那个工具属于WEP时代的wireless-tools。现在内核的无线子系统基本都切换到cfg80211/nl80211架构新网卡的驱动也主要基于这个接口实现iwconfig对WPA2、WPA3这类新认证协议的支持非常有限很多时候你iwconfig设置完key驱动根本不买账表面上没报错实际根本没有发起认证。nmcli本身是个好工具功能很全而且带补全和漂亮的状态输出。可它依赖NetworkManager这一整套网络管理框架最小化系统、容器里或者嵌入式环境里根本没有装都没有必要。更重要的是当NetworkManager和手动启动的wpa_supplicant同时想去管理同一个无线接口时会产生激烈的竞争这就是后面要说的“接口被占用”问题。wpa_cli的优势在于它贴近wpa_supplicant本身Linux里所有主流网络管理器包括NetworkManager和systemd-networkd底层做WiFi认证时其实都绕不开wpa_supplicant你用wpa_cli等于直接操作底层认证引擎权限和灵活性都更大。1.2 wpa_cli交互模式下常用的命令速览wpa_cli支持两种用法直接带参数执行单条命令或者不带参数进入交互模式。我强烈推荐排错时进交互模式因为可以一条一条观察状态变化而且按两下Tab键能补全命令误操作概率低。下面这张表是交互模式里最常用到的命令背熟这几条日常连WiFi已经完全够用。命令作用status查看当前连接状态wpa_state字段最关键scan触发一次无线扫描scan_results显示上一次扫描的结果列表list_networks列出配置文件里所有已保存的网络add_network添加一个新网络返回网络编号set_network设置指定编号网络的参数比如ssid和pskenable_network启用指定编号的网络select_network直接选择并连接指定编号的网络save_config把当前内存中的配置写回配置文件remove_network删除指定编号的网络disconnect / reconnect断开当前连接 / 重新连接这里有个新手容易懵的地方add_network返回的编号是wpa_supplicant自己分配的一般从0开始递增如果之前删除过网络编号不一定是连续的。后面所有set_network、enable_network操作都要带上这个编号操作完记得再list_networks确认一下我见过太多人add_network后不管返回的编号直接对着0号一顿配置结果配了别人已经删掉的那条网络记录。2. 动手之前的必修课无线网卡驱动、接口名和NetworkManager的纠葛一切命令行操作都建立在系统能看到无线网卡的前提下。很多用户上来就敲wpa_cli结果提示找不到接口其实第一步应该检查驱动和接口状态。这个环节花五分钟做一遍后面能省一小时。先看网卡硬件有没有被内核识别。PCIe接口的无线网卡用lspci -k | grep -A3 -i networkUSB的用lsusb。关键是看内核有没有为它加载驱动模块如果lspci输出里出现“Kernel driver in use”后面有具体驱动名说明驱动加载了如果显示“Kernel modules”但没有任何驱动绑定或者干脆没有这一行那需要先解决驱动问题。Intel的无线网卡一般主线内核自带只需要安装linux-firmware包补上固件就能工作。Realtek的芯片就比较折腾比如RTL8852BE在Ubuntu 22.04下经常出现“无WiFi图标”或者连上后测速中断的问题因为部分版本内核没有稳定的驱动支持要靠厂商闭源驱动或者后援维护的驱动模块才能稳定运行。这个我不打算展开编译细节只是提醒你驱动这层不通后面所有命令都是白搭。接口名用ip link查看常见的是wlan0也有wlp2s0、wlx001122334455这类可预测命名或USB网卡专属命名。记住你机器的实际接口名下面所有命令都围绕它来执行。有些系统里无线接口明明存在但状态是DOWN需要用ip link set wlan0 up把它拉起来。如果这一步报错说操作不支持马上查一下rfkill list看是不是被射频开关拦住了这个后面第5节有详细处理。2.1 NetworkManager和手动wpa_supplicant怎么避免打架桌面环境或者带NetworkManager的服务器上最典型的坑是接口已经被NetworkManager接管你手动启动wpa_supplicant去操作同一个接口两边抢网卡表现就是wpa_cli里login状态来回跳或者认证到一半就被踢掉。先用nmcli dev status看一眼接口归属如果state是connected或者disconnected说明NetworkManager认为这个接口归它管。这时候有三种处理路径。第一干脆全程用nmcli享受它自动管理wpa_supplicant的服务不需要手动干预。第二把NetworkManager停掉自己拉起wpa_supplicant。但有个细节很多发行版的NetworkManager服务在启动时会连带拉起wpa_supplicant.service你直接systemctl stop NetworkManager后再启动自己的wpa_supplicant实例可能发现端口被之前那个wpa_supplicant占着需要先systemctl stop wpa_supplicant或者干脆让NetworkManager的wpa_supplicant继续跑自己的wpa_cli连上去操作也行。第三保留NetworkManager但把特定接口设置为unmanaged让它不要碰这个网卡配置写在/etc/NetworkManager/NetworkManager.conf里。对于无桌面环境的最小化服务器我建议直接走第二条路停掉NetworkManager用systemd管理wpa_supplicant配合systemd-networkd拿IP。这样依赖少排错直观而且对嵌入式场景也适用。2.2 先把wpa_supplicant跑起来最小启动命令确认驱动和接口没问题后安装wpa_supplicant。Debian/Ubuntu系是apt install wpasupplicantRHEL系是dnf install wpa_supplicantArch是pacman -S wpa_supplicant。装好之后先写一个极简配置文件内容只有三行ctrl_interfaceDIR/var/run/wpa_supplicant GROUPnetdev update_config1 countryCNctrl_interface指定了控制socket的目录和允许访问的组把用户加进netdev组后wpa_cli就不需要每次sudo了这个必须配否则后面wpa_cli连不上或者权限报错。country字段填上国家码有些驱动依赖这个才能启用对应频段。update_config1允许wpa_cli的save_config命令把运行时配置写回文件没有这个字段你折腾半天配好的网络是存不下来的。启动命令通常长这样sudo wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf -D nl80211-B表示后台运行-i指定接口-c指定配置文件-D指定驱动后端现在绝大多数网卡用nl80211老古董网卡才需要换成wext。第一次排错时我个人建议不要加-B直接前台跑sudo wpa_supplicant -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf -D nl80211这样所有日志直接打到终端你能实时看到扫描、关联、四次握手的每一步。确认正常运行后CtrlC停掉再用-B方式后台启动这是排错效率最高的习惯。3. 三步之内连上网络扫描、配置、拿IP的完整实操环境准备就绪后正式走一遍连接流程。我以最常见的家庭路由器WPA/WPA2-PSK为例把交互模式下的完整操作和每一步的预期输出都写出来。你照着敲正常情况下三分钟内能连上。先进入交互模式wpa_cli -i wlan0如果连接成功会进入一个带提示符的交互环境。第一步输入status确认当前状态。关键看wpa_state字段初始状态一般是DISCONNECTED或者SCANNING。再看interface字段是否是你指定的wlan0避免连错socket。接着输入scan触发一次扫描等一两秒再输入scan_results。输出会有一张表包含bssid、frequency、signal、flags和ssid。flags那列能看出网络是WPA2还是WPA3signal是负数越接近0信号越强。确认你要连接的那个SSID出现在列表里并且拼写完全一致。这里有个很容易踩的坑家里路由器SSID里如果有空格、特殊符号或者你记混了大写字母扫到的结果和你想连的完全是两个网络后面密码再对也连不上。3.1 交互模式从添加到连接完整的命令序列看到目标SSID后按顺序执行下面这组命令 add_network 0 set_network 0 ssid MyWiFi set_network 0 psk MyPassword set_network 0 key_mgmt WPA-PSK enable_network 0add_network返回0表示新建的网络编号是0。set_network设置SSID和密码注意SSID和密码都要用英文双引号包起来wpa_supplicant会按字符串解析不带引号会被当成参数解析失败。key_mgmt WPA-PSK指定认证方式对应日常说的WPA2个人版。如果你的路由器是新款WiFi 6开启了WPA3这里要换成SAE。enable_network 0执行后wpa_supplicant会立刻开始连接流程几秒后再次输入status看到wpa_stateCOMPLETEDpairwise_cipher和group_cipher字段不为空说明无线认证已经打通。连接成功后输入save_config把这条网络记录写进配置文件下次启动wpa_supplicant会自动加载。最后输入quit退出交互模式。3.2 开放式网络、隐藏网络和特殊场景配置不是所有网络都是WPA2-PSK。逛商场、住酒店常遇到的那种网页认证WiFi通常本身是开放式网络只是连上后需要浏览器认证。这种网络在wpa_cli里的配置不同key_mgmt要设成NONE不需要psk add_network set_network 1 ssid FreeWiFi set_network 1 key_mgmt NONE enable_network 1隐藏SSID的路由器正常扫描不到需要额外加一个参数让网卡主动探测set_network 2 scan_ssid 1。这个参数告诉wpa_supplicant针对这个网络不要等信标帧主动发Probe Request去询问特定SSID。家里或者公司开了SSID隐藏的话不加这一行可能一直连不上或者需要等很久才触发关联。WEP加密的老古董路由器也有但我不建议你再用它传任何数据毕竟WEP已经被彻底攻破。如果实在要连wpa_supplicant配置里key_mgmtWEP-40或WEP-104IEE8021X之类的也能配但现在主流发行版的wpa_supplicant对WEP支持已经逐步弱化遇到问题别死磕换设备吧。3.3 拿IP是单独一步wpa_supplicant不管地址分配在3.1结束时无线链路已经通了但你的网卡还没有IP地址。很多人卡在这一步看到wpa_stateCOMPLETED以为大功告成结果ping不通任何东西。wpa_supplicant只负责无线认证和关联IP地址的获取是DHCP客户端或网络管理服务的事它完全不管。传统方式用dhclient或者dhcpcdsudo dhclient wlan0或者sudo dhcpcd wlan0跑完用ip addr show wlan0看有没有拿到IP。如果你是systemd系的发行版更推荐用systemd-networkd来管这块写一个/etc/systemd/network/20-wireless.network文件[Match] Namewlan0 [Network] DHCPyes然后让systemd-networkd重新加载systemctl restart systemd-networkd。这种方式的好处是开机自启时不用额外起一个dhclient进程systemd会统一管理。拿到IP后先ping一下默认网关的IP通了说明局域网没问题再ping 223.5.5.5这种公网IP通了说明路由和NAT正常最后ping一个域名如果域名解析不了看一下/etc/resolv.conf里的DNS配置通常NetworkManager或systemd-resolved会自动维护手动配置的话确保nameserver那行不是空白的。4. 让配置落盘从临时连接到开机自连的持久化方案刚在wpa_cli里连好的网络是存在内存里的重启后就没了。想要下次开机自动连要么把配置写进wpa_supplicant.conf要么依赖systemd服务自动拉起这两件事最好一起做。最省事的落盘方式就是前面说的在wpa_cli交互模式里执行save_config。它会把你当前配置的所有网络、以及ctrl_interface等运行时参数写回启动时指定的配置文件。执行完cat /etc/wpa_supplicant/wpa_supplicant.conf看一眼应该能看到类似这样的network块ctrl_interfaceDIR/var/run/wpa_supplicant GROUPnetdev update_config1 countryCN network{ ssidMyWiFi pskMyPassword key_mgmtWPA-PSK }这种明文保存密码的方式在个人PC上问题不大但如果你要给客户交付设备或者配置文件会被很多人看到建议用wpa_passphrase命令生成哈希密文而不是直接摆明文密码wpa_passphrase MyWiFi MyPassword /etc/wpa_supplicant/wpa_supplicant.confwpa_passphrase会输出一个network块里面psk字段是64位十六进制哈希而不是明文这样配置文件泄露了也不会直接暴露WiFi密码。这个方法只适用于WPA-PSK网络企业802.1X网络不能这样加密。4.1 多网络配置和优先级实际使用中你手上可能有家里、公司、手机热点好几个网络。wpa_supplicant支持在同一个配置文件里放多个network块按priority字段决定优先连哪个。数字越大优先级越高如果当前优先网络不可用自动往下找第一个能连的。一个典型的多网络配置长这样network{ ssidCompanyWiFi pskcompany-pass key_mgmtWPA-PSK priority10 } network{ ssidHomeWiFi pskhome-pass key_mgmtWPA-PSK priority5 } network{ ssidPhoneHotspot pskhotspot-pass key_mgmtWPA-PSK priority1 }wpa_supplicant每次启动时会评估所有network块选出当前可用的最高优先级网络。这里有个细节默认情况下它不会自动切换比如你人在家里优先连上了HomeWiFi这时如果CompanyWiFi信号也扫得到但因为优先级更高wpa_supplicant会在后台扫描时发现它并切过去这是很多人觉得“明明连着WiFi怎么突然断了”的原因之一。不想自动漫游的话可以在network块里加bgscan参数关闭后台扫描。4.2 用systemd实现开机自连现代发行版一般自带wpa_supplicant的systemd模板服务。以Arch和Debian为例常见的模板叫wpa_supplicantwlan0.service不过不同发行版对配置文件路径的处理有差异。Debian系的模板服务默认读取/etc/wpa_supplicant/wpa_supplicant-wlan0.confArch系的模板服务默认读取/etc/wpa_supplicant/wpa_supplicant-wlan0.conf两者类似但Systemd版本不同可能有点差别。最保险的办法是先把配置文件放到对应路径然后sudo systemctl enable wpa_supplicantwlan0.service sudo systemctl start wpa_supplicantwlan0.service如果系统加载了这个服务wpa_supplicant会随开机启动并读取对应配置文件里的所有network块自动连接。但要注意只启动wpa_supplicant服务还不够IP地址分配需要另一个服务兜底。如果你不想引入NetworkManager推荐启用systemd-networkd配合前面的.network文件或者把dhcpcd设成开机自启dhcpcdwlan0.service。这两者配合起来才能真正实现拔掉网线开机自动连WiFi。企业网络的配置我也简单提一句wpa_supplicant对WPA2-Enterprise的支持很完善network块里要指定key_mgmtWPA-EAPeapPEAP或eapTTLSidentity填用户名password填密码。公司网络连不上时很大概率是证书验证或者phase2参数没配对这个后面排查部分会提。5. 高频坑的定位链路七类典型报错从现象到根因这一节是全文的重头戏。我把实际使用中遇到频率最高、论坛里问得最多的几类报错按“现象-排查链路-修复方案”的结构整理出来。记住排错的核心思路是分层先确认驱动层通不通再确认接口和射频开关然后是wpa_supplicant进程本身最后才是认证参数和DHCP。跳层排查往往会绕远路。5.1 wpa_cli连不上守护进程Could not connect to wpa_supplicant这是最基础也最容易解决的一个。报错原文通常是Could not connect to wpa_supplicant: wlan0 - re-trying排查链路第一步ps aux | grep wpa_supplicant看看进程活着没有。如果压根没有进程按2.2节的方式把它启动起来。第二步如果进程在查看启动参数里的-i接口名是什么wpa_cli -i后面的接口必须和它一致。有人wpa_supplicant守护的是wlo1wpa_cli却在操作wlan0那肯定连不上。第三步如果进程和接口都对查一下当前用户是不是在netdev组里不在就sudo usermod -aG netdev $USER然后重新登录。这三步走完九成问题都能解决。5.2 扫描不到任何网络空的scan_results列表wpa_cli能进但scan_results输出空列表或者只有几个BSSID却没有SSID列。这条链路要仔细走。第一步确认接口是UP状态ip link show wlan0看到状态是DOWN就先ip link set wlan0 up。第二步查rfkill list如果无线网卡被soft block或hard block网卡根本不会去扫描全列显示blocked就按下面的5.5处理。第三步用iw命令对比看看sudo iw wlan0 scan。如果iw也扫不到问题出在驱动、固件或硬件层和wpa_supplicant无关方向转到dmesg | grep -i firmware去查固件加载日志。第四步如果iw扫得到但wpa_cli扫不到考虑是不是NetworkManager占用了接口导致wpa_supplicant没有真正拿到网卡控制权nmcli dev status确认一下。还有一个经常被忽略的点隐藏SSID的网络scan_results里本来就看不到它的SSID显示为空的BSS条目。这时候要确认bssid对应的flags和信号强度直接配置网络加scan_ssid1而不是卡在“扫描不到”上死磕。5.3 4-Way Handshake failed密码错还是参数错日志里出现4-Way Handshake failed或者WRONG_KEY提示时第一反应通常是密码错了。这确实是最常见的原因但不止这一种可能。排查链路第一步重新set_network设置一次密码排除手滑输错的情况。注意SSID的大小写和特殊符号wpa_supplicant会把SSID当二进制字符串处理完全区分大小写。第二步确认key_mgmt和路由器实际认证方式匹配。老路由器开了WPA/WPA2混合模式PSK没问题如果路由器只开了WPA3而你配的是WPA-PSK握手必然失败改成key_mgmtSAE。第三步看信号强度signal值如果低于-80dBm握手超时很常见手机都能正常上网不代表网卡能稳定握手毕竟天线功率和灵敏度不同。第四步如果上面都对看日志确认具体卡在哪一步。最直接的方式是前台跑wpa_supplicant输出里会详细打印Authentication、Association、4-Way Handshake每一步的结果。第五步缩小范围用手机开个热点用同样的参数连一下。手机热点能连上说明网卡和密钥没问题问题出在原AP侧比如AP开了802.11r快速漫游而你的网卡驱动对FT支持不好这种就去路由器管理页把802.11r关掉再试。5.4 连接成功但没有IPNo DHCPOFFERS receivedwpa_cli状态显示COMPLETED但ip addr一看wlan0没有IP跑dhclient报No DHCPOFFERS received。这说明无线链路没问题卡在DHCP这一层。排查链路第一步先看AP是不是开了Client隔离或MAC过滤这两个功能如果启用了DHCP广播可能根本到不了路由器。第二步手动配置一个静态IP测试数据链路通不通sudo ip addr add 192.168.1.100/24 dev wlan0 sudo ip route add default via 192.168.1.1如果加完静态IP能ping通网关说明无线链路和AP转发都正常问题定位在DHCP。第三步检查DHCP请求是不是被什么防火墙拦了或者等几秒再跑一次dhclient有些AP的DHCP响应慢。第四步查一下NetworkManager是不是在你配置IP后又把接口抢回去了nmcli dev status看一眼。无线认证和IP配置是两个独立层面这类问题按这条链路走基本都能定位到具体环节。5.5 RTNETLINK answers: Operation not possible due to RF-kill启动接口或扫描时报这个错说明无线网卡被内核的射频开关锁住了。处理链路rfkill list查看所有无线设备的block状态。如果显示soft blocked执行sudo rfkill unblock all或者只解锁无线设备rfkill unblock wifi。unblock后马上再rfkill list确认状态变回unblocked。如果是hard blocked软件层面解锁没用去检查笔记本机身侧面的物理无线开关或者用Fn无线快捷键打开。有些笔记本的BIOS里也有无线开关选项得进去改。我遇到过一台ThinkPad系统里hard blocked一直存在最后发现是BIOS里Wireless Radio已经关闭开机按F1进去打开就好了。解锁后重新ip link set wlan0 up再执行扫描就正常了。5.6 Driver does not support authentication / nl80211接口异常日志报这个说明驱动层不支持当前请求的认证方式或者驱动模块本身对nl80211支持不完整。这类问题在部分Realtek芯片上出现频率很高因为有些闭源驱动只实现了内核老接口的一部分。排查链路先dmesg | grep -i firmware看看固件加载有没有报错没有就确认驱动模块是否真的绑定成功。如果驱动本身没问题可以试试在启动wpa_supplicant时把-D参数换成wext这个老后端能兼容一部分只实现WEXT接口的驱动。不过新版内核里WEXT已经被移除了所以这条只对老内核或老驱动有效。更务实的方案有两个升级到更新的内核版本很多无线驱动在主线内核更新后兼容性大幅改善或者干脆换一块Linux支持成熟的Intel无线网卡这个我在多台机器上实测下来比找Realtek闭源驱动的性价比高太多。做嵌入式开发的话尽量选方案商提供了完整linux驱动的模组别只看硬件参数。5.7 连接成功后立刻断开反复循环日志里反复出现CTRL-EVENT-CONNECTED紧接着又出现CTRL-EVENT-DISCONNECTED循环往复看着特别折磨人。这个问题通常发生在关联成功后、DHCP还没完成时AP主动把客户端踢掉了。排查链路第一步先关注计数器看每次断开发生在关联后的第几秒如果每次都发生在DHCP正要进行时优先怀疑AP的“客户端未获取IP即剔除”策略。可以先手动配静态IP试一试如果静态IP不再断线说明DHCP阶段有问题。第二步有些AP和网卡之间的WMM/QoS协商不兼容导致连接不稳定可以在network块里加一行disable_wmm1再重新连接network{ ssidMyWiFi pskMyPassword key_mgmtWPA-PSK disable_wmm1 }第三步现代路由器默认开启了802.11ax的各种新特性比如OFDMA、BSS Coloring某些较老的网卡驱动和这些特性组合在一起会有兼容性问题。去路由器后台把无线模式强制改成802.11n或802.11ac信道宽度固定到20MHz或40MHz这个问题通常就能缓解。第四步关注PMFProtected Management Frames设置如果AP强制开启PMF而网卡驱动不支持连接也会反复失败可以在network块里显式设置ieee80211w0或ieee80211w1绕开PMF协商失败的死结。这套链路走完反复断线问题基本能解决。我个人的建议是每次调试都把wpa_supplicant前台跑起来把所有日志保存下来结合journalctl -u wpa_supplicant -f看实时输出日志比任何图形化状态工具都诚实错误原因往往就藏在最新几行里。这几年用wpa_cli下来最大的感受是无线排错不能凭感觉东一下西一下。只要按“驱动层-射频层-进程层-认证参数层-DHCP层”的顺序一层层查大部分问题都能在十分钟内定位到具体环节。趁着网络正常的时候把配置文件路径、日志查看命令、rfkill状态检查都过一遍真到无头服务器失联那天你才知道这台机器能不能靠命令行把无线捞回来。如果你也被某个特定网卡的坑卡住过欢迎按这个链路对照一遍很多时候解不开的结只是还没找到正确的那一层。
返回列表