在Fedora 33 中,systemd-resolved 預設為啟用。大多數用戶可能不會注意到變化,但如果你使用VPN 或依賴DNSSEC,那麼systemd-resolved 可能對你來說非常重要。在測試Fedora 33 時,我們發現了一份錯誤報告,用戶發現systemd-resolved 破壞了他的VPN 設定。在這個錯誤修復後,沒有人報告進一步的問題,我對遷移到systemd-resolved 感到相當自信。然而,當Fedora 33 發佈時,我注意到在Ask Fedora 和Reddit 上有大量用戶請求幫助解決破損的VPN 問題,而這些問題在Fedora 33 測試版中並未被檢測到。這讓我感到非常驚訝,因為Ubuntu 自16.10 版本起就默認啟用了systemd-resolved,意味著我們在這方面落後了四年,這應該有足夠的時間來解決任何問題。那麼,到底發生了什麼事呢?
傳統DNS 的工作方式
在討論systemd-resolved 之前,我們先來看看傳統DNS 的工作方式。首先,我們需要討論兩個重要的設定檔。第一個是/etc/nsswitch.conf
,它控制glibc 在執行名稱解析時呼叫哪些NSS 模組。需要注意的是,這些是glibc 的名稱服務切換模組,與Firefox 的NSS(網路安全服務)無關。值得一提的是,在Fedora(以及Red Hat Enterprise Linux)中, /etc/nsswitch.conf
是由authselect 管理的,不能直接編輯。如果你想更改它,需要編輯/etc/authselect/user-nsswitch.conf
,然後執行sudo authselect apply-changes
。
在Fedora 32 中, /etc/nsswitch.conf
中的hosts 行如下圖所示:
hosts: files mdns4_minimal [NOTFOUND=return] dns myhostname
這意味著:首先呼叫nss-files,這將查看/etc/hosts
檔案以檢查主機名稱是否在其中。如果沒有,則呼叫nss-mdns4_minimal,它使用avahi 實作mDNS 解析。 [NOTFOUND=return] 表示avahi 不必安裝;在這種情況下,它將被忽略。接下來,大多數DNS 解析由nss-dns 執行。最後,我們有nss-myhostname,它的存在是為了確保你的本機主機名稱始終可解析。總之,nss-dns 是關鍵部分,nss-dns 用來讀取/etc/resolv.conf
。
接下來,讓我們來看看/etc/resolv.conf
。該檔案包含最多三個DNS 伺服器的清單。伺服器按順序嘗試。如果清單中的第一個伺服器損壞,則使用第二個伺服器;如果第二個伺服器損壞,則使用第三個伺服器。如果第三個伺服器也損壞,則所有操作失敗,因為無論你在此列出多少伺服器,除了前面三個外,其他都將被忽略。在Fedora 32 中, /etc/resolv.conf
預設是由NetworkManager 管理的普通文件,可能如下所示:
```
nameserver 192.168.122.1 ```
這意味著所有DNS 請求都應發送到我的路由器。我的路由器必須透過DHCP 配置此設置,導致NetworkManager 將其新增至/etc/resolv.conf
。
傳統DNS 的問題
傳統的DNS 在簡單情況下運作良好,但在添加VPN 後,問題就出現了。我們考慮兩種類型的VPN:一種是始終啟用的隱私VPN,它是所有網路流量的預設路由;另一種是僅接收內部公司資源流量的企業VPN。 (要在這兩種不同類型的VPN 配置之間切換,請在系統設定的VPN 配置的IPv4 和IPv6 標籤底部使用「僅將此連接用於其網路上的資源」複選框。)
現在,如果我們同時連接這兩個VPN,會發生什麼事?首先連接的VPN 會在/etc/resolv.conf
中排在第一位,第二個連接的VPN 排在第二位,接著是你的本地DNS 伺服器。假設所有DNS 伺服器都正常運作,這意味著:
- 如果你先連接隱私VPN,然後連接企業VPN,所有DNS 請求都會傳送到隱私VPN,你將無法存取內部企業網站。
- 如果你先連接企業VPN,然後連接隱私VPN,所有DNS 請求將發送到企業VPN,而沒有發送到隱私VPN。這違背了使用隱私VPN 的初衷。
如果你在相反的順序連接VPN,例如,如果一個連接暫時斷開,你需要重新連接,那麼你將得到相反的行為。如果你沒有註意到這些失敗背後的模式,這可能會讓問題難以重現。
當然,你並不需要兩個VPN 才會出現此問題。假設你沒有隱私VPN,只有企業VPN。如果你的雇主注意到它不喜歡的DNS 請求,它可能會解僱你。如果你每小時向facebook.com、youtube.com 或其他網站發送30 個請求,這看起來就像你沒有在認真工作。對於員工來說,向雇主發送不必要的DNS 請求並不總是明智的選擇。
如果你只使用隱私VPN,失敗的情況可能會更加嚴重。假設你的隱私VPN 的DNS 伺服器暫時離線。由於/etc/resolv.conf
是一個列表,glibc 將回退到使用正常的DNS,可能是ISP 的DNS 伺服器,或是將所有內容轉送到ISP 的路由器。現在,您的DNS 查詢已傳送至ISP。如果你在錯誤的國家訪問不利於政府的網站,這可能會導致你被監禁或處決。
最後,任何類型的VPN 都會破壞本地網域的解析,例如fritz.box,因為只有你的路由器能夠正確解析該位址,但你正在將DNS 查詢傳送到VPN 的DNS 伺服器。因此,只要你連接到VPN,本地資源將無法使用。
綜上所述,在systemd-resolved 之前的現況非常糟糕。顯然需要更好的解決方案。現在,讓我們看看systemd-resolved 如何解決這個問題。
使用nss-resolve 的現代DNS
首先,讓我們來看看/etc/nsswitch.conf
,在Fedora 33 中它的樣子有所不同:
hosts: files mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] myhostname dns
nss-myhostname 和nss-dns 的位置發生了變化,但這只是一個小改動,確保即使你的DNS 伺服器認為本地主機名稱不可用,它仍然是本地的。重要的改變是增加了resolve [!UNAVAIL=return]
。 nss-resolve 使用systemd-resolved 來解析主機名,透過其varlink API(使用systemd 247)或D-Bus API(使用舊版的systemd)。
總結
隨著systemd-resolved 的引入,Fedora 33 在DNS 解析方面做出了顯著改進,特別是在使用VPN 時。透過合理配置DNS,使用者能夠避免因VPN 配置錯誤而導致的網路存取問題。這為用戶提供了更安全和高效的網路體驗。