ConnMan (简体中文)
ConnMan 是一个命令行网络管理器,为嵌入式设备和快速响应设计。ConnMan 通过 插件 扩展,但内置了 DHCP 与 NTP 支持。[1]
安装
安装 connman 软件包。 wpa_supplicant、bluez 与 openvpn 是对应 Wi-Fi、蓝牙与 VPN 功能的可选依赖。
在启用 connman.service
之前,确保禁用所有已安装的网络配置。
ConnMan 自带 connmanctl(1) 命令行界面。各种 #前端 也可以使用。
前端
- cmst — ConnMan 的 QT GUI。
- connman-ncurses — ConnMan 的简单 ncurses UI;没有实现 ConnMan 的全部功能,但是可以用(有没有 X 都可以运行),参考 wiki。
- ConnMan-UI — GTK3 客户端托盘程序。
- connman_dmenu — dmenu 客户端/前端。
- Econnman — Enlightenment 桌面托盘程序。
- LXQt-Connman-Applet — LXQt 桌面托盘程序。
- connman-gtk — GTK 客户端。
- gnome-extension-connman — ConnMan 的 Gnome3 扩展;如果不安装 connman-gtk,提供的功能很少。
- https://github.com/jgke/gnome-extension-connman || https://extensions.gnome.org/extension/981/connman-extension/
用法
ConnMan 自带 connmanctl
命令行界面,参考 connmanctl(1)。
如果你不提供任何命令,直接运行 connmanctl
,将会启动一个交互式终端。
ConnMan 会自动处理有线连接。
Wi-Fi
启用与禁用 wifi
执行 connmanctl technologies
来检查 wifi 是否开启,查看类似 Powered: True/False
的输出。
执行 connmanctl enable wifi
来开启 wifi,或者执行 connmanctl disable wifi
来禁用 wifi。
其他启用 wifi 的方法包括使用笔记本电脑上的 Fn
键,或者执行 ip link set <interface> up
。
连接到公开的接入点
connmanctl
接受简单的 technologies 名称来扫描网络,要扫描附近的 Wi-Fi 网络:
$ connmanctl scan wifi
在扫描之后,列出可用的网络(示例输出):
$ connmanctl services
*AO MyNetwork wifi_dc85de828967_68756773616d_managed_psk OtherNET wifi_dc85de828967_38303944616e69656c73_managed_psk AnotherOne wifi_dc85de828967_3257495245363836_managed_wep FourthNetwork wifi_dc85de828967_4d7572706879_managed_wep AnOpenNetwork wifi_dc85de828967_4d6568657272696e_managed_none
要连接到公开的网络,使用以 wifi_
开头的第二个参数:
$ connmanctl connect wifi_dc85de828967_4d6568657272696e_managed_none
你现在应该已经连上网络了,使用 connmanctl state
或 ip addr
来检查。
连接到受保护的接入点
你需要提供更多的信息,起码是密码或者密码短语,给 ConnMan 守护程序来连接受保护的接入点。
这一节的命令展示了如何在交互模式执行 connmanctl
,只有交互模式下才能使用 agent
命令。要开启交互模式,只需要输入:
$ connmanctl
接下来的操作和之前的类似,首先扫描所有的 Wi-Fi technologies:
connmanctl> scan wifi
列出服务:
connmanctl> services
现在你需要注册一个 agent 来处理用户请求,命令是:
connmanctl> agent on
现在连接到受收保护的服务,使用 tab 补全来输入 wifi_ 服务,比如要连接到上面例子中的 OtherNET, 输入:
connmanctl> connect wifi_dc85de828967_38303944616e69656c73_managed_psk
Agent 会向你询问守护进程连接到网路需要的一切信息,这些信息会依据与你要连接的网络类型的不同而变化。 Agent 也会像下面一样显示有关信息的额外数据:
Agent RequestInput wifi_dc85de828967_38303944616e69656c73_managed_psk Passphrase = [ Type=psk, Requirement=mandatory ] Passphrase?
提供要求的信息,在这个例子里是密码短语,然后输入:
connmanctl> quit
如果你提供的信息正确,那么你应该已经连接到受保护的接入点了。
使用 iwd 代替 wpa_supplicant
ConnMan 可以使用 iwd 连接无线网络。Community 中提供的的软件包已经支持使用 iwd 来连接无线网络。因为只要 connman 找到 wpa_supplicant 就会启动它,这里建议卸载 wpa_supplicant。
目前 iwd 的 -i
选项似乎会导致 connman 无法找到 Wi-Fi 接口。
创建下面两个服务文件,可以让 connman 无论是否安装了wpa_supplicant,都一律使用 iwd 来连接无线网络。
/etc/systemd/system/iwd.service
[Unit] Description=Internet Wireless Daemon (IWD) Before=network.target Wants=network.target [Service] ExecStart=/usr/lib/iwd/iwd [Install] Alias=multi-user.target.wants/iwd.service
/etc/systemd/system/connman_iwd.service
[Unit] Description=Connection service DefaultDependencies=false Conflicts=shutdown.target RequiresMountsFor=/var/lib/connman After=dbus.service network-pre.target systemd-sysusers.service iwd.service Before=network.target multi-user.target shutdown.target Wants=network.target Requires=iwd.service [Service] Type=dbus BusName=net.connman Restart=on-failure ExecStart=/usr/bin/connmand --wifi=iwd_agent -n StandardOutput=null CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SYS_TIME CAP_SYS_MODULE ProtectHome=true ProtectSystem=true [Install] WantedBy=multi-user.target
使用 iwd 代替 wpa_supplicant 的好处是:ping 时间似乎会更加一致,并且连接会更加可靠。
设置
对于用户经常连接的网络,ConnMan 会自动创建设置与配置文件。这些文件包括了密码短语、essid 和其他信息。配置文件存放在 /var/lib/connman/
内,以服务为名的文件夹下。要查看所有的网络配置文件,在 root shell 内执行:
# cat /var/lib/connman/*/settings
/var/lib/connman-vpn/
。Technologies
ConnMan 将各种硬件接口称为 Technologies。
要列出所有可用的 Technologies,执行:
$ connmanctl technologies
只列出 Technologies 类型的名字,可以使用这一行命令:
$ connmanctl technologies | awk '/Type/ { print $NF }'
Type = tech_name
里的“tech_name”,就是 connmanctl
命令所使用的 technology 类型要与这些接口交互,必须使用 technology 的类型。要开启或关闭 Technologies 可以用:
$ connmanctl enable technology_type
与:
$ connmanctl disable technology_type
比如要关闭 wifi:
$ connmanctl disable wifi
rfkill
或 bluetoothctl
来开关设备。 [2] 请使用 connmanctl enable|disable
提示与技巧
避免改变 hostname
ConnMan 默认会更改临时 hostname。与 X authority 一起使用时会有问题:如果用旧的 hostname 生成了 xauth magic coookie 之后,ConnMan 改变了你的 hostname,那么将无法创建新的窗口,会显示诸如 No protocol specified
和 Can't open display: :0.0
的错误。手动重置 hostname 可以解决这个问题,但根本的解决办法是从一开始就防止 ConnMan 改变你的 hostname。把下面的配置加入 /etc/connman/main.conf
即可:
[General] AllowHostnameUpdates=false
改变这个文件后记得重启 connman.service
。
要测试的话,建议一边观察 systemd 日志,一边插拔几次网线接口。
有线网络与无线网络共存时,优先使用有线网络
ConnMan 默认不会优先使用有线网络,这会导致 ConnMan 即使在可以使用有线网络时,也只使用慢速的无线网络。你可以将下面的配置加入 /etc/connman/main.conf
,让 ConnMan 优先使用有线网络。
[General] PreferredTechnologies=ethernet,wifi
互斥连接
ConnMan 允许你同时连接有线与无线网络。这样允许程序在通过 wifi 建立了连接后,再连接到有线网络,通过 wifi 建立的连接也不会中断。但有些人更喜欢同一时间只使用一种网络,将下面的配置加入 /etc/connman/main.conf
可以实现这一点:
[General] SingleConnectedTechnology=true
连接到 eduroam (802.1X)
在连接到诸如 eduroam 的 WPA2 企业模式网络之前,需要建立单独的配置文件。 比如,创建 /var/lib/connman/eduroam.config
:
eduroam.config
[service_eduroam] Type=wifi Name=eduroam EAP=peap CACertFile=/etc/ssl/certs/certificate.cer Phase2=MSCHAPV2 Identity=[email protected] AnonymousIdentity=[email protected] Passphrase=password
重启 wpa_supplicant.service
和 connman.service
来连接到新网络上。
- 选项是大小写敏感的,比如应该用
EAP = ttls
而不是EAP = TTLS
。[3] - 请向提供 eduroam 网络的机构咨询各种设置,比如用户名、密码、
EAP
、Phase2output
和需要的凭证。
更多信息请参考 connman-service.config(5) 和 Wireless network configuration (简体中文)#eduroam.
避免与本地 DNS 服务冲突
如果你在运行本地的 DNS 服务,在安装了 ConnMan 之后,你很可能会遇到 53 端口(TCP 和/或 UDP)被占用的问题。这是因为 ConnMan 内置的 DNS 代理也会尝试绑定 53 端口。如果你看到了来自 BIND 或 dnsmasq 的日志诸如:
named[529]: could not listen on UDP socket: address in use
就是这个问题引起的。要确认是哪个应用占用了 53 端口,可以以 root 身份执行 ss -tulpn
。
要修复这个问题,可以修改 systemd 服务文件,以 -r
或 --nodnsproxy
选项启动 connmand。
创建文件夹 /etc/systemd/system/connman.service.d/
并新增文件 disable_dns_proxy.conf
:
/etc/systemd/system/connman.service.d/disable_dns_proxy.conf
[Service] ExecStart= ExecStart=/usr/bin/connmand -n --nodnsproxy
确保在新增此文件后 reload systemd 守护程序,并 restart connman.service
和你的 DNS 代理。
/etc/resolv.conf
如果你既想知道从 DHCP 获得的 DNS 服务器地址,同时又想保留自定义的 /etc/resolv.conf
,那么就在上面的文件里追加 RuntimeDirectory=connman
(如果不需要 ExecStart
,就去掉 ExecStart 行)。这样 connman 就会把从 DHCP 获得的 DNS 服务器地址写入 /var/run/connman/resolv.conf
。
记得在增加这个文件之后重载 systemd 守护程序,并重启 connman.service
和你的 DNS 代理。
屏蔽接口
如果有 Docker (简体中文) 之类的的程序创建了虚拟接口,当网络连接中断时,ConnMan 可能会尝试连接这些虚拟接口,而不是真实的硬件接口。简单的解决办法是将你不想要 ConnMan 连接的接口加入黑名单。 ConnMan 默认会屏蔽以 vmnet
、vboxnet
、virbr
与 ifb
开头的接口,所以配置新的黑名单时也要加入这些接口。
屏蔽接口还可以避免竞态条件:在 systemd/udev 改变接口名称到形如 enp4s0
的可预测的网络接口名称之前,connman 可能就会去连接接口。屏蔽惯用(且不可预测)的接口前缀可以让 connman 在接口重命名之后再连接。
把下面的配置加入 /etc/connman/main.conf
(如果不存在就创建这个文件):
[General] NetworkInterfaceBlacklist=vmnet,vboxnet,virbr,ifb,docker,veth,eth,wlan
重启 connman.service
之后,在 Econnman 这样的 GUI 工具中,所有形如 veth#######
的接口也都会被隐藏。
疑难杂症
Error /net/connman/technology/wifi: Not supported
目前,connman 不支持用 iwd 扫描 Wi-Fi 网络,这个功能暂时只能由 wpa_supplicant
提供(参考 [4])。要用 iwd连接 wifi,enable 并 start iwd.service
,然后参考 Iwd 中的指示,或者使用#前端的其中之一。为了让 connman 能扫描 Wi-Fi,安装 wpa_supplicant 软件包,并在停用 iwd.service
之后重启connman.service
。
Error /net/connman/technology/wifi: No carrier
在你使用这条命令启用 wifi 后:
$ connmanctl enable wifi
如果扫描无线网络时产生了这条错误,这可能是因为一个未解决的 Bug。[5] 如果在满足了这些条件后还未解决,请在禁用其他网络管理器,并重启系统之后再尝试。
也可能仅仅是因为无线接口被 rfkill 关闭了,重启 wpa_supplicant 时有可能会这样。使用 rfkill list
来检查。
"Not registered", or "Method "Connect" with signature ... doesn't exist"
在执行命令时你可能会看到这样的错误:
来自 connmanctl
提示符:
connmanctl> connect service_id
Error /net/connman/service/SSID: Method "Connect" with signature "" on interface "net.connman.Service" doesn't exist
来自终端:
# connmanctl connect service_id
Error /net/connman/service/service_id: Not registered
这些错误是由于没有运行 agent。在 connmanctl
提示符里执行 agent on
来启动 agent,然后再试一试。
Error Failed to set hostname/domainname
Connman 可能会因没有 CAP_SYS_ADMIN
而无法设置 hostanme 或 domainname。
你需要编辑 connman.service
(以及其他类似的文件,如 connman-vpn.service
)来修改 CapabilityBoundingSet
行,增加 CAP_SYS_ADMIN
。
更多细节请参考 EPERM
下的 sethostname(2) § ERRORS 或 setdomainname(2) § ERRORS。
连接时出现未知路由
每次连接完成后,日志中可能出现未知的路由,比如:
... connmand[473]: wlp2s0 {add} route 82.165.8.211 gw 10.20.30.4 scope 0 <UNIVERSE> connmand[473]: wlp2s0 {del} route 82.165.8.211 gw 10.20.30.4 scope 0 <UNIVERSE> ...
这可能是由于 ConnMan 在通过检查与 ipv4.connman.net 的连接,来测试网络(在本例里,82.165.8.211
就是 ipv4.connman.net 被解析后的 IP地址)。[6] 详细信息,包括 ConnMan 为什么要这么做,以及 ConnMan 除了连接 IP 还传递了什么信息,请参考 ConnMan README。
该行为可以通过在 /etc/connman/main.conf
中增加下面的配置来阻止:
[General] EnableOnlineCheck=false
这项配置也会导致默认设备状态不会从 READY 切换到 ONLINE。connman.conf(5) 但网络连接是正常的。
也可以用防火墙规则阻止连接检查,这不会影响正常的网络连接(除非有 captive portal):
# ip6tables -A OUTPUT -d ipv6.connman.net -j REJECT # iptables -A OUTPUT -d ipv4.connman.net,ipv6.connman.net -j REJECT
File /proc/net/pnp doesn't exist
如果你在错误日志中看到了这个,这是由 connman 的 bug 引起的 [7],可以无视。Bug Report
另请参见
- Git 仓库文档 —— 更多细节文档