使用wpa_supplicant连接无线网络
一直以来,我们都会使用发行版默认使用的网络配置工具来设置网络,例如Ubuntu默认使用 netplan网络配置 ,而RedHat或者其他发行版默认使用 NetworkManager
。总之,工具五花八门,特别是设置企业级无线网络WPA2,命令参数更是复杂多变。
然而,实际上不同的网络配置工具在配置无线网络时,最终生成的配置文件和使用的工具其实都是 wpa_supplicant
,所以我们也可以手工编辑 wpa_supplicant
配置文件或者使用 wpa_supplicant
命令来构建初始配置并进行进一步定制。
激活无线网卡
首先我们需要确保无线网卡是激活的,使用工具
rfkill
sudo apt install rfkill
检查无线网卡状态:
rfkill list
检查网卡设备是否被blockrfkill list
如果看到无线网卡状态是 Soft blocked
则表明软件关闭了无线网卡:
rfkill list
输出中有 blocked
状态设备则表明被关闭0: phy0: Wireless LAN
Soft blocked: yes
Hard blocked: no
则使用以下命令启用无线(unblock):
rfkill unblock
恢复rfkill unblock wifi
如果使用桌面版本Ubuntu,默认是启用了NetworkManager,则会和手工设置
wpa_supplicant
冲突,所以需要停止NetworkManager:sudo systemctl stop NetworkManager sudo systemctl disable NetworkManager
如果使用服务器版本Ubuntu,默认是启用了netplan,也会和手工设置
wpa_supplicant
冲突
确定无线网卡
使用
iwconfig
找出无线网卡名字:iwconfig
通常无线网卡名字是 wlan0
,但是也可能看到常见的 wlp3s0
。
如果无线网卡接口是down状态,可以使用
ifconfig
命令启用:sudo ifconfig wlp3s0 up
然后扫描周边无线网络:
sudo iwlist wlp3s0 scan | grep ESSID
使用wpa_supplicant连接无线
安装
wpa_supplicant
sudo apt install wpa_supplicant
创建初始配置:
wpa_passphrase
初始化一个简单配置wpa_passphrase your-ESSID your-passphrase | sudo tee /etc/wpa_supplicant/wpa_supplicant.conf
sudo chmod 600 /etc/wpa_supplicant/wpa_supplicant.conf
备注
对于5G网络连接需要增加 country code 配置(类似于 netplan网络配置 的 REGDOMAIN=CN
):
wpa_supplicant.conf
增加 country=CN
来连接5G WIFIcountry=CN
使用以下命令连接无线:
wpa_supplicant
验证配置(前台执行)sudo wpa_supplicant -c /etc/wpa_supplicant/wpa_supplicant.conf -i wlp3s0
注意,这时是前台运行 wpa_supplicant ,当连接建立以后,请另外开一个终端窗口,执行 iwconfig
命令检查无线是否连接正常,应该看到 wlps3s0
连接到指定的AP。
按下
CTRL+C
终止前台运行的wpa_supplicant
进程,然后加上-B
参数让它后台运行:
wpa_supplicant
的 -B
参数后台运行sudo wpa_supplicant -B -c /etc/wpa_supplicant/wpa_supplicant.conf -i wlp3s0
当完成无线连接之后,我们需要获取DHCP地址,所以我们还要运行
dhclient
:
wpa_supplicant
完成验证运行后,启动 dhclient
获取动态IPsudo dhclient wlp3s0
如果一切正常,使用 ifconfig wlp3s0
将看到无线网卡获得IP地址并能够正常上网。
802.1x和EAP
IEEE8021X是用于有线网络的认证,对应的无线网络认证是WPA-EAP,所以在配置 wpa_supplicant-wired.conf 使用如下配置:
ctrl_interface=/run/wpa_supplicant
ap_scan=0
network={
key_mgmt=IEEE8021X
eap=PEAP
identity="user_name"
password="user_password"
phase2="autheap=MSCHAPV2"
}
而无线网络则替换 IEEE8021X
成 WPA-EAP
并且移除 ap_scan=0
:
/etc/wpa_supplicant/wpa_supplicant.conf
配置 WPA-EAP
(对应有线网络的 IEEE8021X
)ctrl_interface=/var/run/wpa_supplicant
# 配置Country Code支持5G Hz无线连接
country=CN
# ap_scan支持扫描隐藏的SSID
ap_scan=1
network={
ssid="SSID-OFFICE"
key_mgmt=WPA-EAP
eap=PEAP
phase1="peaplabel=0"
phase2="auth=MSCHAPV2"
identity="user_name"
password="user_password"
priority=10
}
简单的wpa_supplicant脚本
一个非常简单的wpa_supplicant脚本,结合前面配置文件启动并连接无线:
1sudo ifconfig wlp3s0 down
2sleep 1
3sudo ifconfig wlp3s0 up
4sudo wpa_supplicant -c /etc/wpa_supplicant/wpa_supplicant-office.conf -i wlp3s0 &
5sleep 5
6sudo dhcpcd wlp3s0
连接隐藏的无线网络
有些无线网络SSID并不广播,所以需要在 /etc/wpa_supplicant.conf
配置中添加(注意,是添加在每一段 network
配置中):
scan_ssid=1
5G Hz无线网络国家代码
如果使用了5G Hz无线AP,一定要在配置中添加 country=CN
或者对应国家Code,否则会导致 wpa_supplicant
运行时错误连接 bssid=00:00:00:00:00:00
的AP,日志显示类似:
Nov 05 16:18:51 pi-worker2 wpa_supplicant[1932]: wlan0: CTRL-EVENT-ASSOC-REJECT bssid=00:00:00:00:00:00 status_code=16
Nov 05 16:10:27 pi-worker2 wpa_supplicant[1849]: wlan0: Trying to associate with SSID 'SSID-OFFICE'
Nov 05 16:10:30 pi-worker2 wpa_supplicant[1849]: wlan0: CTRL-EVENT-ASSOC-REJECT bssid=00:00:00:00:00:00 status_code=16
Nov 05 16:10:30 pi-worker2 wpa_supplicant[1849]: wlan0: CTRL-EVENT-SSID-TEMP-DISABLED id=0 ssid="SSID-OFFICE" auth_failures=1 duration=23 reason=CONN_FAILED
这是因为5GHz是一个受控频率,需要根据不同国家进行调整country code,否则无法连接。
备注
我曾经在 树莓派Ubuntu网络设置 反复折腾了一周时间 排查wpa_supplicant无法连接5GHz无线问题 。
如果使用 netplan网络配置 配置管理 systemd-networkd
,则同样设置 REGDOMAIN=CN
。
NetworkManager 和 wpa_supplicant
NetworkManager 是通过 D-Bus 和 wpa_supplicant
通讯的,我在 Raspbery Pi OS(Raspbian) 上实践( 树莓派Raspberry Pi 5 )发现,当通过 raspi-config
配置无线网络,实际上生成的是 /etc/NetworkManager/system-connections/MY_SSID.nmconnection
(这里假设连接的是 MY_SSID
这个无线AP) :
raspi-config
生成 NetworkManager 无线配置[connection]
id=MY_SSID
uuid=xxxx-xxxx-xxxx-xxxx
type=wifi
interface-name=wlan0
[wifi]
mode=infrastructure
ssid=MY_SSID
[wifi-security]
auth-alg=open
key-mgmt=wpa-psk
psk=MY_PSK
[ipv4]
method=auto
[ipv6]
addr-gen-mode=default
method=auto
[proxy]
此时对应的 /etc/wpa_supplicant/wpa_supplicant.conf
非常简单:
/etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
#update_config=1
#修改成0表示不允许更新配置,因为NetworkManager无需修改这个配置文件
update_config=0
注意, NetworkManager 不会管理 /etc/network/interfaces
配置中列出的接口,所以需要确保这个配置文件中没有包含无线网卡,以便让渡给NetworkManager管理
NetworkManager 和 wpa_supplicant
的无线连接优先级设置
当配置多个无线网络时候,可以设置一个优先级( priority
)来按一定顺序连接无线, NetworkManager 和 wpa_supplicant
都支持传递这个配置参数,但略有不同:
直接编辑
/etc/wpa_supplicant/wpa_supplicant.conf
,可以为每个network
配置不同的priority
(数字越小优先级越低):
/etc/wpa_supplicant/wpa_supplicant.conf
配置 WPA-EAP
(对应有线网络的 IEEE8021X
)ctrl_interface=/var/run/wpa_supplicant
# 配置Country Code支持5G Hz无线连接
country=CN
# ap_scan支持扫描隐藏的SSID
ap_scan=1
network={
ssid="SSID-OFFICE"
key_mgmt=WPA-EAP
eap=PEAP
phase1="peaplabel=0"
phase2="auth=MSCHAPV2"
identity="user_name"
password="user_password"
priority=10
}
如果通过 NetworkManager 来管理无线网络,则在使用
nmcli
命令时就可以指定priority
:
nmcli con add con-name home ifname wlp3s0 type wifi ssid home \
wifi-sec.key-mgmt wpa-psk wifi-sec.psk MYPASSWORD
connection.autoconnect-priority 10
上述 nmcli 命令传递参数会在 /etc/NetworkManager/system-connections/home.nmconnection
配置文件的 [connection]
配置段添加 autoconnect-priority=10
连接没有密码保护的开放网络
对于在机场等公共空间,开放无密码的wifi,可以设置
wpa_supplicant.conf
的network
段落key_mgmt=NONE
:
network={
ssid="public wifi"
key_mgmt=NONE
priority=-999
}
如果上述配置中没有指定 ssid
则会连接无线范围内任意一个开放网络
启动时自动运行
警告
这段配置 systemd
方法虽然可行,但是现在已经没有必要直接修改 wpa_supplicant.service
配置文件了。标准的方法是通过激活 wpa_supplicant@interfice.service
来让服务读取对应的 /etc/wpa_supplicant/wpa_supplicant-interface.conf
。例如,对于 wlan0
,应该执行:
systemctl enable wpa_supplicant@wlan0.service
为了能在操作系统启动时自动连接无线网络,我们需要编辑 wpa_supplicant.service
配置:
sudo cp /lib/systemd/system/wpa_supplicant.service /etc/systemd/system/wpa_supplicant.service
然后编辑 /etc/systemd/system/wpa_supplicant.service
,将以下配置:
ExecStart=/sbin/wpa_supplicant -u -s -O /run/wpa_supplicant
修改成:
ExecStart=/sbin/wpa_supplicant -u -s -c /etc/wpa_supplicant.conf -i wlp3s0
如果在 wpa_supplicant.service
配置中有如下内容:
Alias=dbus-fi.w1.wpa_supplicant1.service
则注释掉(添加 #
):
#Alias=dbus-fi.w1.wpa_supplicant1.service
现在我们可以激活 wpa_supplicant.service
sudo systemctl enable wpa_supplicant.service
我们也需要启动 dhclient 来获得IP,所以创建 /etc/systemd/system/dhclient.service
内容如下:
[Unit]
Description= DHCP Client
Before=network.target
[Service]
Type=simple
ExecStart=/sbin/dhclient wlp3s0 -v
ExecStop=/sbin/dhclient wlp3s0 -r
[Install]
WantedBy=multi-user.target
然后激活服务:
sudo systemctl enable dhclient.service
获得静态IP地址
DHCP客户端也可以向服务器请求分配固定的IP地址,编辑 /etc/dhcp/dhclient.conf
添加以下行内容:
interface "wlp3s0" {
send dhcp-requested-address 192.168.0.122;
}
然后重启dhclient服务:
sudo systemctl restart dhclient
使用主机名访问Ubuntu服务
实际上不需要分配静态IP地址就能够对外提供服务。Ubuntu可以使用 mDNS (Multicast DNS) 来向局域网公告自己的主机名,这样客户端就可以通过主机名来访问这台服务器上的服务。这样主机名可以解析到IP地址,即使你的主机IP地址变化。
要使用mDNS,需要安装 avahi-daemon
,这时一个实现 mDNS/DNS-SD
的开源实现:
sudo apt install avahi-daemon
启动服务:
sudo systemctl start avahi-daemon
激活启动服务:
sudo systemctl enable avahi-daemon
avahi-daemon监听在UDP端口5353,所以防火墙需要打开这个端口。如果你使用UFW,则运行以下命令:
sudo ufw allow 5353/udp
现在你需要设置服务器的唯一主机名,使用 hostnamectl
命令:
sudo hostnamectl set-hostname ubuntubox
注意,此时新设置的 ubuntubox
还不能被其他局域网主机看到,我们需要重启 avahi-daemon
sudo systemclt restart avahi-daemon
检查 avahi-daemon 状态:
systemctl status avahi-daemon
备注
需要注意,mDNS主机名以 .local
结尾,所以上述设置主机名 ubuntubox
在mDNS中显示的名字是 ubuntubox.local
对于要使用avahi的客户端,需要安装 mDNS/DNS-SD
软件:
Linux需要安装
avahi-daemon
Windows需要激活
Bonjour
服务,也就是安装 Bonjour print service 或者直接安装 iTunesmacOS不需要安装任何软件,默认已经激活了Bonjour