ConnMan

出自 Arch Linux 中文维基

ConnMan 是一個命令行網絡管理器,為嵌入式設備和快速響應設計。ConnMan 通過 插件 擴展,但內置了 DHCPNTP 支持。[1]

安裝[編輯 | 編輯原始碼]

安裝 connman 軟件包。 wpa_supplicantbluezopenvpn 是對應 Wi-Fi、藍牙與 VPN 功能的可選依賴。

啟用 connman.service 之前,確保禁用所有已安裝的網絡配置

ConnMan 自帶 connmanctl(1) 命令行界面。各種 #前端 也可以使用。

前端[編輯 | 編輯原始碼]

  • cmst — ConnMan 的 QT GUI。
https://github.com/andrew-bibb/cmst || cmstAUR
  • connman-ncurses — ConnMan 的簡單 ncurses UI;沒有實現 ConnMan 的全部功能,但是可以用(有沒有 X 都可以運行),參考 wiki
https://github.com/eurogiciel-oss/connman-json-client || connman-ncurses-gitAUR
  • ConnMan-UI — GTK3 客户端托盤程序。
https://github.com/tbursztyka/connman-ui || connman-ui-gitAUR
  • connman_dmenu — dmenu 客户端/前端。
https://github.com/taylorchu/connman_dmenu || connman_dmenu-gitAUR
  • Econnman — Enlightenment 桌面托盤程序。
https://www.enlightenment.org || econnmanAUR
  • LXQt-Connman-Applet — LXQt 桌面托盤程序。
https://github.com/lxqt/lxqt-connman-applet || lxqt-connman-appletAUR
  • connman-gtk — GTK 客户端。
https://github.com/jgke/connman-gtk || connman-gtkAUR
  • 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
提示:網絡名稱可以用 tab 補全。

你現在應該已經連上網絡了,使用 connmanctl stateip 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

然後啟用/開始 connman_iwd 服務。

使用 iwd 代替 wpa_supplicant 的好處是:ping 時間似乎會更加一致,並且連接會更加可靠。

設置[編輯 | 編輯原始碼]

對於用户經常連接的網絡,ConnMan 會自動創建設置與配置文件。這些文件包括了密碼短語、essid 和其他信息。配置文件存放在 /var/lib/connman/ 內,以服務為名的文件夾下。要查看所有的網絡配置文件,在 root shell 內執行:

# cat /var/lib/connman/*/settings
注意: VPN 設置存放在 /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
警吿: connman 會監聽 rfkill 事件。使用 connman 時,儘管硬件鎖可能可以正常工作,但基本無法使用 rfkillbluetoothctl 來開關設備。 [2] 請使用 connmanctl enable|disable

提示與技巧[編輯 | 編輯原始碼]

避免改變 hostname[編輯 | 編輯原始碼]

ConnMan 默認會更改臨時 hostname。與 X authority 一起使用時會有問題:如果用舊的 hostname 生成了 xauth magic coookie 之後,ConnMan 改變了你的 hostname,那麼將無法創建新的窗口,會顯示諸如 No protocol specifiedCan'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=user@foo.edu
AnonymousIdentity=anonymous@foo.edu
Passphrase=password

重啟 wpa_supplicant.serviceconnman.service 來連接到新網絡上。

注意:
  • 選項是大小寫敏感的,比如應該用 EAP = ttls 而不是 EAP = TTLS[3]
  • 請向提供 eduroam 網絡的機構諮詢各種設置,比如用户名、密碼、EAPPhase2output和需要的憑證。

更多信息請參考 connman-service.config(5)Wireless network configuration#eduroam.

避免與本地 DNS 服務衝突[編輯 | 編輯原始碼]

如果你在運行本地的 DNS 服務,在安裝了 ConnMan 之後,你很可能會遇到 53 端口(TCP 和/或 UDP)被佔用的問題。這是因為 ConnMan 內置的 DNS 代理也會嘗試綁定 53 端口。如果你看到了來自 BINDdnsmasq 的日誌諸如:

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 默認會屏蔽以 vmnetvboxnetvirbrifb 開頭的接口,所以配置新的黑名單時也要加入這些接口。

屏蔽接口還可以避免競態條件:在 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,enablestart 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][失效連結 2022-09-17 ⓘ] 如果在滿足了這些條件後還未解決,請在禁用其他網絡管理器,並重啟系統之後再嘗試。

也可能僅僅是因為無線接口被 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) § ERRORSsetdomainname(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][失效連結 2022-09-17 ⓘ] 詳細信息,包括 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[失效連結 2022-09-17 ⓘ]

另請參見[編輯 | 編輯原始碼]