使用 systemd 自動切換路由至 USB 網路分享

配合 udev 以及 systemd-networkd 在接上 Adnroid USB 網路分享時自動切換路由

前面的文章有說明了如何改用 systemd-networkd 進行系統的網路管理,但是在沒有另外設定的情況下並不會自動幫你切路由,所以必須要手動把裝置的設定檔寫好,讓系統自動去設定。
配合之前的文章《使用 systemd-networkd 設定網路組態》要重新寫一個針對手機的 .link 檔以及 .network 檔,再外加一個 udev rule 讓手機插上去時可以自動重新啟動 systemd-networkd 服務達成目的。

準備

首先,你要是 Android 手機,如果不是的話,那這篇就不是給你看的了,iPhone 好像不適用,手邊沒有 iPhone 我也無從測試。
然後拿出你的傳輸線,把手機插上電腦,手機選擇什麼模式都不影響(應該是可以不要理它),接著開啟 terminal 後輸入 lsusb,接著找到自己的手機。

這邊我們需要的是手機的那條,我的是 Sony 手機,所以位於圖片中第一條。接著找到 ID 後方的 0fce:01ba,前四碼是 vendor ID,後四碼是 product ID,基本上同樣的廠商會是一樣的 vendor ID,所以同品牌手機愛好者就有福了,不過先假設只有這隻手機需要拿來分享網路,所以請記住 vender ID ,後面會需要它。

設定 systemd-networkd

知道手機 vendor ID 後,接著要設定手機接上電腦後的裝置辨識,因為 systemd 的緣故,NIC 命名都是 enpxxxx 之類的,然後每次插手機後裝置名稱都會不一樣,所以要先來固定住 NIC 名稱。

當然名稱隨便填都可以,但是數字可以往後安排一點(數字影響讀取的順序),以下給一個範例:

[Match]
Driver=rndis_host

[Link]
Description=Adnroid Rndis Link
NamePolicy=keep
Name=rndis
MACAddressPolicy=persistent

[Match] 中,可以選擇使用 MACAddress= 來指令沒錯,但是考量到可能會更換手機的關係,所以使用驅動程式來作為判斷標準,rndis_host 也就是 RNDIS 在 Linux 下的驅動,多數情況都是手機網路分享才會用到這個驅動,如果讀者會有其他情況用到 RNDIS 的話就自己更改一下匹配規則囉。
NamePolicy=keep 讓他不會被系統自動命名,然後下行的 Name=可以自己取名字,這裡就會成為之後在系統中對於手機 NIC 的辨識名稱。
MACAddressPolicy=persisten 就是使用原本的 Mac 位置,除非無法取得就隨機產生一個,基本上不會影響使用。

然後這段就完成了。

編寫 30-rndis.network

名稱盡量跟前面一樣,可以做一組配對方便辨識,以下給一組範例:

[Match]
Name=rndis

[Network]
DHCP=true

[DHCP]
RouteMetric=10

[Match 的話採用 Name= 匹配裝置,因為前面已經有指定裝置名稱了,所以可以這樣用,當然如果名稱設定不一樣請記得做更改。
[Network] 部份,DHCP 一般來說是 yes,手機自己會做分配。
[DHCP] 底下的 RouteMetric= 是重點,這邊設定為 10,代表權重,數字越小權重越大,之後會用到。
到這邊就算完成了讓系統在手機接上去後可以自動連接設定網路的部份。

修改原本的網路

因為原本有連線存在,如果沒有的話就可以略過這段。
假設原本的網路是 enp3s0 好了,設定檔在 20-enp3s0.network(這時候的 20-enp3s0.link 不重要,因為這是管理硬體連線用的),打開設定檔後,在 [DHCP] 下多加一條:

[DHCP]
RouteMetric=20

這邊的 RouteMetric= 基本上只要比前面設定的小就可以了,這會影響到路由的權重,所以看起來會像這樣:

NIC RouterMetric
RNDIS 10
enp3s0 20

當然,只有 enp3s0 存在時也只有它可以走,權重就不影響了,只有在兩者同時存在時才會有權重問題。

測試設定

這時候把手機插上電腦,手機選擇「USB 數據連線」,然後重新啟動 systemd-networkd:
# systemctl restart systemd-networkd
這時候可以用查詢 IP 位置的方式看看是不是有改變,如果沒有的話可以看是不是裝置沒有被變更到:
$ ip l s 應該要出現 rndis,像是這樣:

如果有出現裝置,但是名稱不對的話,應該是設定檔沒有寫好,再看看是不是打錯了什麼。

設定 udev

前面的部份如果插入拔出的話都要自己手動重新啟動 systemd-networkd 才能套用網路,但是這裡可以透過 udev 來偵測裝置行為後進行動作,還記的前面的 vendor ID 嗎?這時候派上用場了!
我們要先新增一個 udev rule,要放置在 /etc/udev/rules.d/ 底下,名稱的話也是隨便取,這邊就叫它 90-android-tethering.rules,裡面長這樣:

ACTION=="add|remove", SUBSYSTEM=="net", ATTR{idVendor}=="18d1" ENV{ID_USB_DRIVER}=="rndis_host", SYMLINK+="android", RUN+="/usr/bin/systemctl restart systemd-networkd.service"

其中的 18d1 要改成自己的 vendor ID,所以實際上會像這樣:

ACTION=="add|remove", SUBSYSTEM=="net", ATTR{idVendor}=="0fce" ENV{ID_USB_DRIVER}=="rndis_host", SYMLINK+="android", RUN+="/usr/bin/systemctl restart systemd-networkd.service"

然後保存,接著再重新把手機插上去,這次就不要手動下指令重新啟動 systemd-networkd 了,看看是不是可以正常切換呢?
如果可以的話,恭喜你完成了這樣方便的功能!

結論

筆者之前都沒有這樣的需求,是後來租屋處的網路竟然是 cable 網路還只有 12/3,根本要人命啊,只好拿手機 4G 網路出來壓壓驚,但是有線網路在,手機插上去又不會自動改順序,只好自己看一下要怎樣處理這個問題了,也順便分享給大家,如果遇到這樣的情況也可以輕鬆解決。
然後讚嘆 ArchLinux Wiki 可以方便查資料。
附上資料來源囉:Android tethering,裡面還有很多種方法,筆者自己覺得這樣是最好用最方便的,推薦給大家。

文章於 2023-05-08 01:06 更新

 Share!