Windows 名稱解析的順序 ── hosts、DNS 快取、LLMNR/mDNS 與 DoH

· 更新日期: · · Windows, DNS, 名稱解析, 網路, 故障排查, PowerShell, TCP/IP, 資訊部門

「設定一樣,偏偏這台電腦連不上內部伺服器」「瀏覽器可以開,業務應用程式卻名稱解析失敗」「寫進 hosts 也沒用」。

排查這類問題時,最先要確認的是是哪一套機制在回答這個名稱。Windows 有快取、hosts、DNS 伺服器、LLMNR、NetBIOS、mDNS 這幾條路徑,而有些應用程式還會走與 Windows 不同的路徑。

本文先建立整體圖像,整理名稱的形態與各條路徑的差別,再進入實際的排查步驟。想盡快開始調查的讀者,可以從下表跳到對應位置。

遇到的問題 首先要確認的 閱讀的位置
hosts 沒生效/只有部分電腦回傳舊 IP 快取的內容,以及所用工具走的路徑 快取與 hosts步驟 2
app01 這種短名稱時,只有部分電腦失敗 尾碼補完,以及有沒有 LLMNR 與 NetBT 名稱的形態單一標籤名稱的典型例子
一連 VPN 結果就變 多網卡的優先順序與 NRPT 多網卡NRPT
等幾秒就連得上 無回應的 DNS 伺服器與重傳時間 逾時
瀏覽器與業務應用程式結果不同 內建解析器、安全 DNS、Proxy 應用程式的入口瀏覽器的 DoH
不知道該從哪查起 從名稱的形態開始,限定路徑逐一比較 排查步驟

本文的前提

項目 內容
目標讀者 排查「解析不了名稱」「只有部分電腦連不上」的資訊部門人員,以及設計與維護業務應用程式通訊的 Windows 應用程式開發者
前提知識 IP 位址與 DNS 的基礎(A 記錄、FQDN),能以系統管理員權限執行 PowerShell 的 Cmdlet
前提環境 Windows 10 / Windows 11。DoH 一節需要 Windows 11 或 Windows Server 2022 以上1。確認用的命令來自 DnsClient 模組(Windows 8 / Windows Server 2012 以上)2
不涵蓋的內容 DNS 伺服器那側(Windows Server DNS 的區域、轉寄站、遞迴)的設定與故障。Zero Trust DNS(ZTDNS)的部署步驟

封包擷取文章講的是線路上流動的封包,Proxy 文章講的是「讀誰的 Proxy 設定」。本文則依據 Microsoft 的第一手資料,整理它們之前的那一步:「目的地的 IP 位址是從哪裡來的」。

1. 先講結論

要記住的是下面三點。

  • Windows 的名稱解析並不總是沿著一條佇列依序前進。快取與 hosts 在前,但對單一標籤名稱,預設情況下 DNS 與 LLMNR、NetBT 是平行運作的。34
  • 同一個名稱,只要電腦的設定與應用程式的路徑不同,結果就會不同。要把尾碼、VPN、NRPT、瀏覽器的內建解析器分開考慮。567
  • 調查時要限定所用的路徑再比較結果。Resolve-DnsName 的參數把快取、DNS、連結本機分開,再透過與連得上的電腦做設定差異比對和擷取封包來確認。8

先把下面這張圖當作整體的示意圖來用。

名稱解析是層的堆疊名稱解析的要求從應用程式的 API 交給 DNS 用戶端服務,先看快取與 hosts,接著是 DNS 伺服器;只有單一標籤名稱才會嘗試 LLMNR、NetBIOS(預設與 DNS 平行)。對 .local 名稱,除了已設定的 DNS 之外還會加上 mDNS 這條路徑。瀏覽器在這條佇列之外擁有自己的解析器沒有則沒有則・單一標籤名稱(預設與 DNS 平行).local 名稱(額外的路徑)自有解析器・DoH應用程式(getaddrinfo)DNS 用戶端服務快取(含 hosts)向 DNS 伺服器查詢LLMNR / NetBIOSmDNS瀏覽器另一條路徑

先看快取,再往前是 DNS;若是單一標籤名稱,LLMNR 與 NetBIOS 會平行運作。瀏覽器另有一條路徑。

以下把「誰來回答」放在第 3~5 章,「怎麼送出」放在第 6 章,「怎麼確認」放在第 7~8 章。DoH 是把通往 DNS 伺服器的傳輸通道換成 HTTPS 的功能,並不取代 hosts、快取、NRPT 的順序。9

圖中實線表示始終成立的關係,虛線表示附帶條件的關係(成立條件寫在詳細頁面中各關係的說明中)。關係的完整清單(共 48 條,附依據與可信度)以及主要概念的定義,彙整在知識地圖詳細頁面(日文)。資料:JSON-LD / Turtle

2.「名稱解析」不是單一的處理

回到應用程式手上的只有位址或錯誤

當應用程式用 www.example.com 這樣的名稱連線時,會呼叫 Winsock 的 getaddrinfo(Unicode 版是 GetAddrInfoW)。這個函式針對 NS_DNS 命名空間,透過 DNS、本機的 hosts 檔案以及其他機制把名稱轉換成位址。若有多個命名空間提供者回應,它會彙整後回傳。10

也就是說,應用程式只是收到了結果,並不知道是哪一層回答的

.NET 的 Dns.GetHostAddresses 在 Windows 上同樣使用 getaddrinfo。對於寫在 hosts 裡的主機,它不會去問 DNS 伺服器就直接回傳那個位址。HttpClient 也建立在這個 Dns 類別之上,因此直接連線目的地的 .NET 應用程式會沿用 Windows 的名稱解析順序。11

經 HTTP Proxy 時,被解析的名稱會變。在本機解析的是 Proxy 的名稱,目的地的名稱由 Proxy 那側解析。這種情況下,本機的 hosts、快取、尾碼、NRPT 都不參與目的地的解析。實際使用哪一套 Proxy 設定,在 Proxy 文章中有講。

2.1 DNS 用戶端服務決定順序

getaddrinfo 之下運作的是 DNS 用戶端服務(服務名稱 Dnscache)。Microsoft 的資料把基本順序說明如下。3

  1. 檢視快取。
  2. 檢視 hosts 檔案。
  3. 向 DNS 伺服器查詢。

由於 hosts 的內容會在服務啟動時讀入快取,本文把前兩項合起來當作第 1 層「快取與 hosts」處理。5

再往後,就要看名稱與原則了。

職責 讀順序時的注意點
第 1 層: 快取與 hosts 回傳電腦內部已有的答案 這裡出了答案就不會去問 DNS 伺服器
第 2 層: DNS 伺服器 透過向 DNS 查詢取得答案 牽涉尾碼、多網卡、NRPT 等
第 3 層: LLMNR・NetBT 用另外的手段解析單一標籤名稱 預設與第 2 層平行。只有停用最佳化時才會在 DNS 失敗後串列

預設的「智慧型多重主目錄名稱解析」會把 DNS、LLMNR、NetBT 的查詢平行送往所有網路。採用哪個回應,由 4.3 節與 5.2 節的規則決定。4

因此,「什麼時候送出查詢」和「回來的答案依什麼優先順序採用」是兩回事。擷取封包裡看到 LLMNR 或 NetBT,並不能光憑這一點就說「DNS 失敗了」。本文的「三層」是為了整理而做的劃分,並不表示它們總是依時間順序串列運作。

2.2 位在佇列之外的東西

特別容易混淆的是下面兩個。

工具・應用程式 與 Windows 路徑的差別 調查時的注意點
nslookup 不使用作業系統的解析器,繞過快取、hosts、NRPT,直接問第一台 DNS 伺服器123 ping 或業務應用程式結果不同並不奇怪
Microsoft Edge 預設使用內建 DNS 用戶端。DoH 也一律由內建解析器處理7 「瀏覽器開得起來」不能證明作業系統的名稱解析是健康的

使用 Edge 的內建用戶端本身並不代表更換了 DNS 伺服器。這與選擇別的提供者的安全 DNS 設定要分開,我們在 6.2 節確認。

3. 第 1 層 ── 快取與 hosts

這一層想知道的是電腦內部還留著什麼樣的答案。快取裡不只有正確的答案,也會留下舊的答案和「沒有這個名稱」的答案。

3.1 hosts 會被讀入快取

hosts 檔案位於 C:\Windows\System32\drivers\etc\hosts。DNS 用戶端服務啟動時,名稱與 IP 位址的對應會被讀入解析器快取。透過 DNS 查詢取得的記錄,也會在 TTL(存留時間)期間保存在同一個快取中。5

ipconfig /displaydns 會同時顯示從 hosts 讀入的項目與最近的 DNS 查詢取得的項目。13 Microsoft 的範例中也是:只要在 hosts 裡寫上 contoso.comResolve-DnsName contoso.com 就會回傳那個位址,不會有 DNS 通訊流出。3

看不到 DNS 封包時怎麼讀

在沒有 DoH、DoT 的情況下查詢 FQDN,名稱解析成功卻沒有 53 埠的查詢,那多半是快取或 hosts 給出了答案。不過要先排除下面這些其他路徑。

名稱・設定 除 53 埠外要確認的通訊
.local 名稱 mDNS(UDP 5353)
單一標籤名稱 LLMNR(5355)、NetBT 的名稱服務(UDP 137)
已啟用 DoH HTTPS(443)
已啟用 DoT TLS(853)

不要只憑「沒有 53 埠」就斷定是快取,要把可能被用到的路徑一併看過。開發機上殘留的一行驗證用 hosts,也可能把調查帶偏。

編輯 hosts 需要系統管理員權限,資安產品有時還會偵測到這類變更。應該避免讓業務應用程式的維運依賴 hosts 的設計。

3.2 否定回應也會被快取

「找不到」也是會被快取的答案之一。DNS 用戶端不只保存肯定回應,也保存否定回應。5

如果 ipconfig /displaydns 中對應名稱顯示為「Name does not exist」,表示 DNS 伺服器的否定回應還留在用戶端上。Microsoft 的步驟是用 ipconfig /flushdns 把它丟掉。1413

否定快取的保留時間由 HKLM\SYSTEM\CurrentControlSet\Services\Dnscache\ParametersMaxNegativeCacheTtl 決定,預設是 5 秒。15 在 DNS 中剛加完記錄,那台電腦仍會在幾秒內回傳失敗,原因就在這裡。

3.3 TTL 與「只有部分電腦是舊的」

肯定回應也會在 TTL 期間留存。在變更伺服器 IP 位址之前查過這個名稱的電腦會繼續用舊答案,而變更之後才第一次查詢的電腦則會得到新答案。就算用的是同一台 DNS 伺服器,查詢的時刻不同結果就不同。5

Clear-DnsClientCacheipconfig /flushdns 行為相同,會刪除包含否定回應在內的全部快取內容。16Get-DnsClientCache 則可以把快取當成物件取出,檢視記錄類型與剩餘 TTL。17

# 某個名稱是否在快取中,剩餘 TTL 是幾秒
Get-DnsClientCache -Entry 'app01.corp.example.com' |
    Select-Object Entry, Type, Status, TimeToLive, Data

# 一併檢視 hosts 與快取的內容
ipconfig /displaydns | Select-String -Pattern 'app01' -Context 0,6

# 丟棄快取(包含否定回應)
Clear-DnsClientCache

只要第 1 層給出答案,這次查詢在到達 DNS 伺服器之前就已經定了。不過,錯誤的答案原本就是從 DNS 伺服器學來的這種可能性仍然存在。不要刪完就收工,還要依第 8 章的步驟 3 確認重新取得的答案。

4. 第 2 層 ── 向 DNS 伺服器查詢

第 1 層沒有答案就前進到 DNS。這裡要把用什麼名稱、送往哪台伺服器、在什麼時機送出分開來考慮。

4.1 單一標籤名稱與尾碼

首先確認應用程式交過來的名稱是什麼形態。5

名稱的形態 例子 送往 DNS 的方式
結尾帶點的 FQDN(絕對名稱) www.contoso.com. 原樣送出
含點但結尾沒有點的名稱 www.contoso.com 預設在結尾加點後送出。如果啟用了允許對多標籤名稱附加尾碼的原則,也會嘗試尾碼4
不含點的單一標籤名稱 www 用電腦的尾碼設定補完後送出

尾碼就是補在短名稱後面的網域部分。給 app01 加上 corp.example.com,查詢的名稱就成了 app01.corp.example.com

有搜尋清單的情況

從 DNS 尾碼搜尋清單的開頭依序附加尾碼,並送出結尾加了點的名稱。一旦設定了搜尋清單,就只會使用這個清單。主要尾碼、連線特定尾碼以及名稱遞減都不會被使用。18

沒有搜尋清單的情況

附加主要 DNS 尾碼後送出。如果啟用了名稱遞減(devolution),每失敗一次就去掉最左邊的標籤再試。例如從 www.test.contoso.com 前進到 www.contoso.com。若介面卡有連線特定的 DNS 尾碼,也會附加它送出。5

因此,在用群組原則派送搜尋清單的環境和靠加入網域取得主要尾碼的環境中,同樣是 server01,展開結果也不同。

長清單也會增加等待時間

如果正確的尾碼排在清單後面的位置,到達它之前的查詢時間就會累積起來。Microsoft 也用嘗試 6 個尾碼的例子說明了這種延遲。若只想嘗試某個特定的展開結果,就像 internal.contoso.com. 那樣在結尾加點。3

# 全域設定: 搜尋清單與遞減
Get-DnsClientGlobalSetting

# 依介面: 連線特定尾碼與註冊設定
Get-DnsClient | Select-Object InterfaceAlias, ConnectionSpecificSuffix, UseSuffixWhenRegistering

# 依介面的 DNS 伺服器(IPv4 與 IPv6 兩者)
Get-DnsClientServerAddress | Where-Object ServerAddresses | Select-Object InterfaceAlias, AddressFamily, ServerAddresses

Get-DnsClientGlobalSetting 回傳搜尋清單、是否遞減及其層級等全域設定,Get-DnsClient 回傳依介面的設定。1920

4.2 多台 DNS 伺服器的順序與逾時

當出現「不失敗但要等幾秒」時,就該懷疑是向無回應的 DNS 伺服器重傳。對設定在一張網卡上的 DNS 伺服器,把預設的重傳時機排出來是這樣的。21

從開始起 1 台設定 2 台設定 3 台以上設定
0 秒 向伺服器查詢 向第 1 台 向第 1 台
1 秒 重傳 向第 2 台 向第 2 台
2 秒 重傳 向第 2 台重傳 向第 3 台
4 秒 重傳 同時向全部伺服器 同時向全部伺服器
8 秒 重傳 同時向全部伺服器 同時向全部伺服器
10 秒 放棄 放棄 放棄

這是沒有回應時的表。特別不要把下面兩者混為一談。

伺服器的反應 是否嘗試下一台伺服器 怎麼讀
無回應 嘗試 重傳與逾時的問題
回傳「沒有這個名稱」的否定回應 到此為止 已經收到「沒有這個名稱」的答案

當「停掉了一台卻沒有切換過去」時,如果一台持有舊區域的伺服器仍在運作並回傳否定回應,就不會往下走。21

第 4 位以後的伺服器,要等 4 秒之後才輪到

如果會回應的伺服器排在清單第 4 位以後,那麼從第一次查詢算起至少要等 4 秒。若應用程式的期限比這更短,就會在名稱解析階段失敗。想讓查詢提前,就得把它挪到前 3 位中的某一位,但根本對策是修好前面那台不通的伺服器,或把它從設定中拿掉。同時也要重新檢視應用程式那側的逾時。21

Microsoft 的範例中,4 台裡只有 1 台可達的設定,完成也要約 4 秒。可以用 Measure-Command 測耗時,該資料把 1 秒以內視為可接受範圍。3

# 只用 DNS 直接問某台伺服器,並以毫秒取得耗時
(Measure-Command {
    Resolve-DnsName -Name 'app01.corp.example.com' -Server 10.0.1.2 -DnsOnly
}).TotalMilliseconds

這條命令固定了伺服器,因此測的是那台伺服器單獨的回應時間。到達清單第 4 位之前的延遲,要用不帶 -Server 的查詢或它的擷取封包來確認。

另外,DNS 用戶端會把回應快的伺服器往上挪,並記住無回應的伺服器定期重試。首次逾時也會依過去的實績在 25~1,000 毫秒的範圍內調整。上表只是預設的骨架,實測有偏差正是因為如此。5

4.3 多網卡與「智慧型多重主目錄名稱解析」

在同時擁有有線與 Wi-Fi 的電腦,或者又加上 VPN 介面卡的電腦上,除了 DNS 伺服器的清單,還要確認網路之間的查詢與回應的選擇

向多個介面卡重傳

在 Microsoft 的查詢流程中,先向偏好介面卡的第一台 DNS 伺服器送出並等 1 秒。沒有回應就向仍在候選中的全部介面卡的第一台伺服器送出並等 2 秒,之後向全部介面卡的全部伺服器送出,等待時間依序取 2 秒、4 秒、8 秒。某個介面卡的伺服器回傳否定回應時,該介面卡的其他伺服器就退出候選。5

控制平行查詢的原則

群組原則「關閉智慧型多重主目錄名稱解析」控制的是下面這些行為。4

原則 行為
預設(未設定) 把 DNS、LLMNR、NetBT 平行送往所有網路。若有多個肯定回應,依網路的繫結順序採用
已啟用 停止該最佳化。先在所有網路上嘗試 DNS,失敗後是 LLMNR,再失敗是 NetBT,變成串列

這項原則的名字是「關閉…」,所以要注意啟用原則等於停用該最佳化

VPN 改變結果的例子

查詢內部名稱時,VPN 那側的 DNS 回傳內部位址,而家裡路由器那側的 DNS 也可能回傳另一個肯定回應。例如與內部同名網域的公開位址,或是把不存在的名稱替換成廣告頁面的位址。

有兩個肯定回應時,採用哪一個由繫結順序決定。在現今的 Windows 上,這個優先順序由介面度量決定,Get-NetIPInterfaceInterfaceMetric 越小越優先。各台電腦順序上的差異,就變成了結果上的差異。22

另一方面,如果家裡那側回傳否定回應,那麼該介面卡會退出候選,採用 VPN 那側的答案。5 VPN 產品之所以派送 NRPT 或「關閉智慧型多重主目錄名稱解析」,正是為了控制這類差異。

4.4 NRPT ── 依命名空間改變查詢對象

NRPT(Name Resolution Policy Table,名稱解析原則表)是一張表,依 .corp.contoso.com 之類的命名空間指定要使用的 DNS 伺服器以及 DirectAccess、DNSSEC 的設定。DirectAccess 與 Always On VPN 的設定檔會寫入規則,做出「只把內部名稱指向內部 DNS」這樣的行為。236

Get-DnsClientNrptPolicy -Effective 可以確認實際生效的規則。

# 實際生效的 NRPT 規則
Get-DnsClientNrptPolicy -Effective

# 只顯示特定命名空間的規則。-Namespace 只依 Namespace 屬性篩選,不做與名稱的比對判定。
# 傳入 'app01.corp.example.com' 也不會回傳 '.corp.example.com' 的尾碼規則。
# 某個名稱由哪條規則生效,要像第 8 章步驟 4 那樣自行列舉規則並比對
Get-DnsClientNrptPolicy -Effective -Namespace '.corp.example.com'

NRPT 只對使用 Windows DNS API 的應用程式生效。自備 DNS 實作的應用程式會繞過那條路徑。VPNv2 CSP 的資料以 nslookup 為例,要求確認 NRPT 時使用 Resolve-DnsName。瀏覽器的內建解析器與 DoH 同樣在 Windows DNS API 之外。6

5. 第 3 層 ── 單一標籤名稱的退路: LLMNR、NetBIOS,以及 mDNS

5.1 三種協定的差別

LLMNR 與 NetBIOS over TCP/IP(NetBT)是解析 app01 這類單一標籤名稱的另外手段。預設與 DNS 平行運作,就算 DNS 回傳了肯定回應,也可能採用連結本機的回應。只有停用智慧型多重主目錄名稱解析時,才會變成 DNS 失敗後的串列。4

mDNS 與此不同,它是加在 .local 名稱上的一條路徑。它不是單一標籤名稱的 DNS 解析失敗之後的接手者。24

協定 連接埠 到達範圍 定位
LLMNR UDP 5355 的多播。TCP 5355 用於單播重傳2526 同一子網路內的連結 不設定 DNS 也能用的次要名稱解析4
mDNS UDP 5353 的多播24 多播能到達的本機網路 解析 .local 名稱。Microsoft 選定的今後主軸27
NetBT UDP 137 的名稱服務28 廣播,或向 WINS 伺服器查詢29 舊有技術。建議從 WINS 移轉到 DNS30

即使是 .local,也別跳過 DNS 的確認

.local 並不會變成 mDNS 專用。當 Active Directory 網域是 corp.local 之類時,這個名稱仍會由已設定的 DNS 伺服器或 NRPT 解析。RFC 6762 也認可與單播 DNS 併用。調查 .local 名稱時,同樣要確認 DNS 與 VPN 的原則。24

NetBT 會隨 WINS 的有無與節點類型而變

節點類型 名稱解析的方式
B-node 只有廣播
P-node 只向 WINS 查詢
M-node 先廣播後 WINS
H-node 先 WINS 後廣播

未設定 WINS 時預設為 B-node,只要設定了一台就預設為 H-node。29 LLMNR 與 NetBT 的廣播不能跨越子網路,但向 WINS 的查詢是單播,因此可以跨越。

nbtstat -c 可以顯示 NetBIOS 名稱快取,用 nbtstat -R 可以清除快取並重新讀入 LMHOSTS。31

5.2 哪一個優先

平行查詢之後,優先採用哪個回應也會隨原則變化。4

條件 單一標籤名稱的回應優先順序
預設・不屬於網域的網路 LLMNR 與 NetBT 的連結本機回應優先於 DNS
網域的網路 DNS 回應優先
啟用「關閉智慧型通訊協定重新排序」 在所有網路上依 DNS→LLMNR→NetBT 的順序優先

在家裡或外出時的網路上,附近同名裝置的答案有可能優先於 DNS。這裡同樣重要的是,把回應的優先順序與查詢是串列還是平行分開來讀

5.3 Microsoft 的方針: 向 mDNS 靠攏

Microsoft 在 2022 年 4 月公布了向 mDNS 靠攏、逐步收斂 NetBIOS 名稱解析與 LLMNR 的方針。27 像 Computer Browser 這類古老且不安全的裝置探索通訊協定也已被淘汰。32 用多播或廣播來補足單一標籤名稱的設計,正朝著收斂的方向走。

關於 LLMNR 弱點的 Microsoft 資訊中,把阻擋 TCP/UDP 5355 以及啟用群組原則「關閉多點傳送名稱解析」列為因應措施。同時也明確寫出其影響:電腦可能不再被其他電腦看到。25 啟用這項原則後,DNS 用戶端的所有介面卡上 LLMNR 都會被停用。4

停用這個方向本身是正確的判斷,但必須在 DNS 中為消失的那條路徑準備替代。未在 DNS 登錄的裝置要登錄 A 記錄,或啟用透過 DHCP 的動態註冊,並把目的地改成 FQDN。支援 mDNS 的裝置可以用 .local 名稱,但到達範圍僅限多播能通的範圍。

5.4「只有部分電腦連不上」的典型: 單一標籤名稱

當設定檔或捷徑裡寫著 \\fileserver01http://app01/ 時,同一個名稱也會出現下面這些差別。

電腦的環境 可能發生的情況
加入網域的桌機 被尾碼補完為 app01.corp.example.com,可由內部 DNS 解析
經 VPN 的筆記型電腦 補完與否取決於 VPN 設定檔。若沒有補完,且同一子網路內也沒有對象,LLMNR 與 NetBT 就會落空
位於其他子網路的辦公室 若 DNS 中沒有登錄,LLMNR 與 NetBT 的廣播就到不了。不過若 WINS 中有登錄,有時仍可解析2930
同時停用 LLMNR 與 NetBT 的電腦 DNS 裡沒有的名稱就解析不了。若只停用 LLMNR,還留有用 NetBT 或 WINS 解析的餘地

Resolve-DnsName app01 -LlmnrOnly 能知道的是「能否用 LLMNR 解析」,並不能知道平時的查詢採用的答案出自哪裡。與不帶參數的結果比較以及擷取封包,放在第 8 章的步驟 5 裡做。8

根本對策是 FQDN 化與 DNS 登錄

把依賴單一標籤名稱的目的地改成 FQDN,把名稱解析集中到 DNS。

SMB2 以上透過 TCP 445 直接連線,不使用 NetBIOS 的工作階段。33 但那說的是傳輸通道。在解析 \\fileserver01\share 這個目的地名稱的階段,仍可能用到 LLMNR 或 NetBT。像 \\fileserver01.corp.example.com\share 這樣用 FQDN 指定,才能擺脫對單一標籤名稱路徑的依賴。

不過 FQDN 也仍有下面的注意點。結尾沒有點的 FQDN,在啟用了對多標籤名稱附加尾碼的原則時也會被嘗試補完。以 .local 結尾的名稱有可能併用 mDNS。要無條件固定,絕對名稱要寫成結尾帶點的形式。實務上把「FQDN 就會固定在 DNS 上」當作前提,成立的條件是上述原則未啟用,且內部網域名稱沒有使用 .local

6. 通往 DNS 伺服器的傳輸通道 ── DoH 不改變順序

6.1 Windows 11 / Windows Server 2022 的 DoH

Windows 的 DoH 是把送往 DNS 伺服器的查詢以 HTTPS 送出的功能。它與既有的 hosts、快取、NRPT,以及依介面卡、依設定檔指定解析器的機制整合在一起,並不取代第 3~4 章的順序。9

Windows 11 的 DNS 用戶端支援 DoH,較新的版本還支援 DoT(DNS over TLS)。不過 Microsoft 的說明沒有寫明 DoT 的支援版本,所以未必在本文的全部前提環境中都能使用。以下只講 DoH。9

首先確認已知 DoH 伺服器清單

在沒有啟用 DDR 的情況下,能用的是列在已知 DoH 伺服器清單上的伺服器。預設清單裡有 Cloudflare、Google、Quad9,可以用 Get-DnsClientDohServerAddress 確認。內部 DNS 之類需要登錄 DoH 範本以及回復與自動升級的設定。134

# 已知 DoH 伺服器清單
Get-DnsClientDohServerAddress

# 把內部 DNS 登錄為 DoH 伺服器(不回復為明文・啟用自動升級)
Add-DnsClientDohServerAddress -ServerAddress '10.0.1.2' `
    -DohTemplate 'https://dns.corp.example.com/dns-query' `
    -AllowFallbackToUdp $false -AutoUpgrade $true

也可以用 netsh dnsclient add encryption 登錄。全域的 netsh dnsclient set global doh=yes|no|auto 與依伺服器的 autoupgrade 是不同的設定。35

全域設定 意義
doh=no 禁止 DoH
doh=yes 依伺服器或介面卡的設定允許 DoH
doh=auto 自動把送往已知 DoH 伺服器的查詢強制為 DoH

光有 auto 並不禁止回到明文。失敗時是否回到 UDP,由依伺服器的 udpfallback(PowerShell 中是 -AllowFallbackToUdp)另行決定。若要只限加密,就把回復也停用。35

啟用了 DDR,還有動態探索的路徑

在支援 DDR(Discovery of Designated Resolvers)的版本中,以明文設定的解析器可以通告加密 DNS 的端點。由於無需登錄到靜態清單也可能被升級為加密,因此不能斷言「不在清單裡就不是 DoH」。35

DDR 要生效,需要全域的 netsh dnsclient set global ddr=yes 與依介面卡的 set interface <名稱> ddr=yes 兩者兼備。用 DDR 取得的加密解析失敗後是否回到明文由 ddrfallback 決定,預設是停用。

調查時除了已知清單,還要確認 netsh dnsclient show globalnetsh dnsclient show state,以及對持有 DNS 伺服器的介面卡用 set interface 設定的值。資料中定義的 showencryptionglobalstate,沒有介面卡專用的顯示子命令。35

把「允許」「要求」與回到明文分開

在設定應用程式中把 DNS 設定改為手動,只有當慣用 DNS 伺服器在已知清單中時才能選擇「慣用 DNS 加密」。選項有下面三個。1

設定應用程式的選項 行為
僅加密(DNS over HTTPS) 只使用加密
優先加密,也允許未加密的通訊 DoH 失敗時不作通知地回到明文
僅未加密的通訊 以明文送出

群組原則「設定 DNS over HTTPS (DoH) 名稱解析」有允許、禁止、要求三種。選允許時,除了登錄到已知清單,還要滿足自動升級、介面卡的加密設定、全域 doh=auto 等條件才會使用 DoH。選「要求」時,不支援 DoH 的伺服器會導致名稱解析本身失敗。135

不要在加入網域的電腦上套用「要求 DoH」。Microsoft 有明確提醒。因為 Active Directory Domain Services 強烈依賴 DNS,而 Windows Server 內建的 DNS 伺服器服務並不支援 DoH 查詢。1

擷取封包時,要把設定與實際通訊分開讀

實際用 DoH 送出的查詢不在 UDP 53,而是進入 443 埠的 TLS。不過就算「允許 DoH」,送往不在已知清單的伺服器的查詢,以及加密失敗後的回復,仍會以明文流出。只是有 DoH 的設定,並不代表 53 埠的通訊就消失了。

看不到 DNS 查詢時,除了 hosts、快取,還要確認 DoH 與 DoT(853 埠)。採集方法請參考封包擷取文章

6.2 瀏覽器的 DoH 與作業系統是兩回事

Edge 的內建 DNS 用戶端,與透過安全 DNS 變更查詢對象,分成兩段來看會更容易理解。

設定 查詢的主體・對象
預設的內建 DNS 用戶端 由 Edge 而不是作業系統的 DNS 用戶端來查詢。所用的 DNS 伺服器本身不變
安全 DNS 使用目前的提供者 向目前的提供者加密查詢。失敗則以明文重試
安全 DNS 選擇別的提供者 向選定的 DoH 解析器查詢。失敗也不回到明文

內建用戶端由 BuiltInDnsClientEnabled 控制,DoH 的查詢一律由內建解析器進行。7 安全 DNS 在受組織管理的電腦上預設停用,用 DnsOverHttpsMode(off / automatic / secure)與 DnsOverHttpsTemplates 設定。3637

選了別的提供者的 Edge,可能查得到外部網站卻查不到只有內部 DNS 才知道的名稱。反過來,就算作業系統的 DNS 不正常,也可能只有 Edge 開得起來。若維持目前的提供者,查詢對象並不會改變。

結論是,不要把瀏覽器的成功與業務應用程式的成功當成同一條路徑的證據。作業系統的路徑要用 Resolve-DnsNameping 來確認。

7. 應用程式走的是哪一條路徑

在選擇調查用的工具之前,先把看的路徑對齊。

呼叫 走的路徑 hosts 快取 NRPT LLMNR/NetBT
getaddrinfo / Dns.GetHostAddresses / HttpClient(直接連線時)1011 作業系統的 DNS 用戶端服務。經 Proxy 的 HttpClient 只在本機解析 Proxy 名稱,目的地由 Proxy 解析 生效 單一標籤名稱時使用(預設與 DNS 平行。失敗後的串列僅限停用最佳化時)
ping 作業系統的 DNS 用戶端服務 生效 單一標籤名稱時使用(預設與 DNS 平行。失敗後的串列僅限停用最佳化時)
Resolve-DnsName8 作業系統的 DNS 用戶端服務(可用參數選擇層) 可用 -NoHostsFile 排除 -CacheOnly 限定 生效 可用 -DnsOnly 排除
nslookup123 直接送往第一台 DNS 伺服器 不看 不看 不生效 不使用
Microsoft Edge(預設)76 內建 DNS 用戶端(不經過作業系統的 DNS 用戶端) 與作業系統的路徑不同 與作業系統的快取不同 不生效(在 Windows DNS API 之外) 與作業系統的路徑不同

依調查目的整理 Resolve-DnsName 的主要參數,如下所示。8

想確認的事 參數
只靠本機快取能否得到答案 -CacheOnly
想排除 hosts 再試 -NoHostsFile
只用 DNS 通訊協定,不想送出 LLMNR、NetBIOS -DnsOnly
想問特定的 DNS 伺服器 -Server
只想試 LLMNR -LlmnrOnly
只想試 LLMNR 或 NetBIOS -LlmnrNetbiosOnly
想允許 DNS 失敗時回到 NetBIOS -NetbiosFallback
想選擇記錄類型 -Type。預設是同時問 A 與 AAAA 的 A_AAAA

7.1 A 與 AAAA,IPv6 先回來

即使名稱解析成功,之後的位址選擇也可能讓連線變慢。

DNS 用戶端會同時查詢 A(IPv4)與 AAAA(IPv6)。擷取封包中也能看到兩者成對的查詢。3 回傳答案之後,getaddrinfo 與連線那側的堆疊會選擇要用的位址。Windows Vista 以後使用 RFC 3484 的前置詞表,預設讓 IPv6 的全域單播優先於 IPv4。38

不過,光是回傳了 AAAA,並不代表一定會嘗試 IPv6 連線。在目的地選擇時,會先排除沒有 IPv6 來源位址或路由等不可用的目的地,再排列候選。39

會成為問題的是這種環境:IPv6 的來源位址與路由看似存在,實際卻不通。名稱解析成功了,卻在連線上損失時間。IPv6 是否真的被嘗試過,不能只看 DNS 回應,還要用連線記錄或擷取封包確認。

Microsoft 不建議用停用 IPv6 來因應,因為 Windows 的一部分元件會無法運作。取而代之,它介紹的方法是把 DisabledComponents 設為 0x20,在前置詞原則中讓 IPv4 優先。38 localhost 被解析為 ::1、與假設 127.0.0.1 的調查產生衝突的例子,封包擷取文章中也有講。

8. 排查步驟 ── 從上往下逐層剝離

在連不上的電腦上,依下面的順序執行。各條命令都是為了限定路徑,光是成功並不能證明平時的解析路徑也是如此。要結合結果的比較與最後的擷取封包。

步驟 要確認的事
1 應用程式交過來的名稱的形態
2 快取與 hosts 的答案
3 排除 hosts、LLMNR、NetBIOS 後的 DNS 結果
4 實際解析路徑上依 DNS 伺服器分別的結果
5 單一標籤名稱用 LLMNR、NetBT 的解析
6 連得上與連不上的電腦之間的設定差異
7 有沒有送出封包,回來了什麼

步驟 1: 確認名稱的形態

在記錄檔或設定檔中確認應用程式實際交過來的名稱。是單一標籤名稱、以 .local 結尾、還是結尾帶點,路徑都會不同。像 http://app01/ 這樣的短名稱,就要從 4.1 節的補完與 5.4 節各台電腦的差別查起。

步驟 2: 只靠快取與 hosts 能否解析

Resolve-DnsName -Name 'app01.corp.example.com' -CacheOnly
Get-DnsClientCache -Entry 'app01.corp.example.com'
Get-Content "$env:SystemRoot\System32\drivers\etc\hosts" | Select-String -Pattern 'app01'
結果 怎麼讀與下一步確認
出了正確的答案 這次在到達 DNS 伺服器之前答案就定了
出了舊的、錯誤的答案 若來自 hosts 就改那一行。若來自快取,就在清除後依步驟 3 確認重新取得的答案
「Name does not exist」 否定快取。Clear-DnsClientCache 之後進入步驟 3
沒有答案 有可能是普通的快取未命中。進入步驟 3

-CacheOnly 只是把這次查詢限定在本機快取。若錯誤的答案本來就是從 DNS 伺服器學來的,清除後同樣的值還會回來。在快取中存在,並不能證明 DNS 伺服器與此無關。8

步驟 3: 只用 DNS 能否解析

# 排除 hosts,不送出 LLMNR/NetBIOS,只用已設定的 DNS 伺服器查詢
Resolve-DnsName -Name 'app01.corp.example.com' -NoHostsFile -DnsOnly

如果步驟 2 沒有答案而這裡成功了,多半只是普通的快取未命中。能說是快取或 hosts 的問題的,是步驟 2 中出現了舊答案、錯誤答案或否定快取的情況。

如果這裡也失敗,就要查通往 DNS 伺服器的路徑、伺服器那側以及用戶端那側的原則。進入步驟 4 之前,請確認下面這些。

  • Get-DnsClientNrptPolicy -Effective: 有沒有把查詢指向別的 DNS 伺服器的規則。
  • Get-DnsClientDohServerAddress 與 DoH 的群組原則: 有沒有對不支援的伺服器「要求 DoH」。

若有 NRPT,步驟 4 的對象伺服器就會變。如果原因是「要求 DoH」,那麼路徑和伺服器都健全,唯獨名稱解析失敗。請先完成 4.4 節、6.1 節的確認。

步驟 4: 逐台伺服器直接查詢

收集正在連線的介面卡的 DNS 伺服器;若目標名稱上有 NRPT 生效,就換成該規則的伺服器。只用 IPv6 設定的 DNS 伺服器也要納入對象。

$name = 'app01.corp.example.com'
# 從 IPv4 與 IPv6 兩側收集正在連線的介面的 DNS 伺服器。
# 已中斷的 VPN 或虛擬交換器上殘留設定的伺服器與目前的解析路徑無關,所以排除(只用 IPv6 設定的伺服器不要漏掉)
$connected = @((Get-NetIPInterface -ConnectionState Connected).ifIndex | Select-Object -Unique)
$servers = @((Get-DnsClientServerAddress |
    Where-Object { $_.ServerAddresses -and ($connected -contains $_.InterfaceIndex) }).ServerAddresses)
# 對這個名稱生效的 NRPT 規則的伺服器(Always On VPN 或 DirectAccess 寫入的那些)不會出現在介面卡的設定裡,所以從實效原則中選取。
# Get-DnsClientNrptPolicy 的 -Namespace 只依規則的 Namespace 屬性篩選,不做與名稱的比對判定。
# 因此要自行比對 Any 規則(.)、尾碼規則(以點開頭。對命名空間本身及其子網域生效)、FQDN 規則、前置詞規則(主機名稱部分,也可以是 web* 這種萬用字元),
# 並採用更具體(更長)的規則。Any 規則最短,所以只有在沒有其他相符規則時才會被選中
# Namespace 是字串的集合(顯示為 Namespace : {.corp.example.com} 這樣),所以要依規則展開元素來比對,並依相符的命名空間長度排序
# 結尾帶點的絕對名稱(app01.corp.example.com.)只在比對時去掉點。傳給 Resolve-DnsName 的仍是原本的 $name
$matchName = $name.TrimEnd('.')
$label = $matchName.Split('.')[0]
$matched = foreach ($policy in @(Get-DnsClientNrptPolicy -Effective)) {
    foreach ($ns in @($policy.Namespace)) {
        if (-not $ns) { continue }
        $hit = if ($ns -eq '.') { $true }
               elseif ($ns.StartsWith('.')) { $matchName.Equals($ns.TrimStart('.'), [System.StringComparison]::OrdinalIgnoreCase) -or $matchName.EndsWith($ns, [System.StringComparison]::OrdinalIgnoreCase) }
               elseif ($ns.Contains('.')) { $matchName.Equals($ns, [System.StringComparison]::OrdinalIgnoreCase) }
               else { $label -like $ns }
        if ($hit) { [pscustomobject]@{ Namespace = $ns; Policy = $policy } }
    }
}
$rule = $matched | Sort-Object { $_.Namespace.Length } -Descending | Select-Object -First 1
$policyServers = @()
if ($rule) { $policyServers = @(@($rule.Policy.NameServers) + @($rule.Policy.DirectAccessDnsServers) | Where-Object { $_ }) }
if ($policyServers.Count -gt 0) {
    # 如果 NRPT 為這個命名空間指定了伺服器,那麼步驟 3 的查詢就是送往那台伺服器。介面卡的伺服器在路徑之外,所以替換掉
    $servers = $policyServers
}
$servers = $servers | Where-Object { $_ } | Select-Object -Unique
foreach ($server in $servers) {
    $sw = [System.Diagnostics.Stopwatch]::StartNew()
    try {
        $r = Resolve-DnsName -Name $name -Server $server -DnsOnly -ErrorAction Stop
        $status = 'OK'
        # 多筆記錄的排列會隨回應變化,所以排序後再比較
        $answer = ($r.IPAddress | Sort-Object) -join ','
    } catch {
        # 否定回應(沒有這個名稱)、SERVFAIL、逾時都會走到這裡。不要丟掉原因,保留下來
        $status = $_.Exception.Message
        $answer = ''
    }
    [pscustomobject]@{ Server = $server; Status = $status; Answer = $answer; Milliseconds = [int]$sw.ElapsedMilliseconds }
}

首先,把要比較的伺服器對齊

NRPT 的 NameServersDirectAccessDnsServers 有時不會出現在介面卡的 DNS 設定中。如果步驟 3 問的是 NRPT 的伺服器,而步驟 4 只查介面卡的伺服器,那就比較了不同的路徑。

NRPT 有尾碼、FQDN、前置詞、Any(.)等規則,更具體的規則優先。40 -Namespace 只依規則的屬性篩選,不做與主機名稱的比對判定。因此上面的程式碼展開規則的命名空間,與目標名稱做比對。23

在分割 DNS 的 VPN 中,家裡那側的解析器對內部名稱回傳否定回應、只有 NRPT 那側回傳肯定回應,這是正常的。若要把路徑之外的伺服器也拿來比較,就當作「對照」單獨記錄,不要混進區域是否一致的判定裡。對已中斷介面卡上殘留伺服器的逾時,也與目前解析路徑的延遲無關。

接著,分辨結果

結果 要查的東西
只有特定伺服器逾時 那台伺服器變成無回應的原因
「名稱不存在」等否定回應 與逾時區分開,確認名稱與區域的內容
回應的 IP 位址不同 確認它們是不是同一角色的伺服器,並依記錄集合比較
只是記錄的順序不同 可能是輪詢。若排序後的集合相同,就不要光憑順序判定區域不一致

若集合也不同,就確認區域的內容與序號。另外,這裡是用 -Server 固定了對象的測量。4.2 節所說的「到第 4 位為止要 4 秒」這種由清單位置帶來的延遲,要在步驟 3 或它的擷取封包中確認。

步驟 5: 確認連結本機這一層

Resolve-DnsName -Name 'app01' -LlmnrOnly          # 只用 LLMNR
Resolve-DnsName -Name 'app01' -LlmnrNetbiosOnly   # 只用 LLMNR 或 NetBIOS(不使用 DNS)
nbtstat -c                                        # NetBIOS 名稱快取

這項確認針對的是單一標籤名稱。-NetbiosFallback 只在 DNS 失敗時才回到 NetBIOS,因此對能用 DNS 解析的名稱來說,它並不能確認 NetBIOS。8

結果依下面的方式讀。

結果 能知道的/仍然不知道的
-LlmnrOnly 成功 能用 LLMNR 解析。不過平時是否也採用了那個答案並不一定
-LlmnrOnly 失敗而 -LlmnrNetbiosOnly 成功 不能斷定是 NetBIOS 回答的。也可能是因為漏接或對方的啟動時機,在後一次嘗試中由 LLMNR 回答了
連得上的電腦只有這一層成功,連不上的電腦失敗 懷疑對單一標籤名稱路徑的依賴。根本對策是 FQDN 化與 DNS 登錄

到底是哪個通訊協定回答的,要在擷取封包中透過 UDP 5355(LLMNR)與 UDP 137(NetBT)來分辨。要確認平時的解析路徑,還要與不帶參數的 Resolve-DnsName 回傳的位址比較;若不一致,就用擷取封包確認被採用的回應。因為預設情況下 DNS 也在平行查詢。

步驟 6: 取設定傾印的差異

在「只有部分電腦」的調查中,要在連得上與連不上的電腦上執行同一個指令碼再比較。

# name-resolution-dump.ps1 -- 以系統管理員權限執行,把兩台的輸出檔並排比較
$out = "$env:COMPUTERNAME-name-resolution.txt"
$sections = [ordered]@{
    'Get-DnsClientServerAddress' = { Get-DnsClientServerAddress | Format-Table -AutoSize | Out-String -Width 200 }
    'Get-DnsClientGlobalSetting' = { Get-DnsClientGlobalSetting | Format-List | Out-String }
    'Get-DnsClient'              = { Get-DnsClient | Format-Table InterfaceAlias, ConnectionSpecificSuffix, UseSuffixWhenRegistering -AutoSize | Out-String -Width 200 }
    'Get-DnsClientNrptPolicy'    = { Get-DnsClientNrptPolicy -Effective | Format-List | Out-String }
    'Get-DnsClientDohServerAddress' = { Get-DnsClientDohServerAddress | Format-Table -AutoSize | Out-String -Width 200 }
    'netsh dnsclient show state' = { netsh dnsclient show state 2>&1 | Out-String }
    'Get-NetIPInterface'         = { Get-NetIPInterface | Sort-Object AddressFamily, InterfaceMetric | Format-Table InterfaceAlias, AddressFamily, InterfaceMetric, ConnectionState, Dhcp -AutoSize | Out-String -Width 200 }
    'DNSClient policy registry'  = { Get-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient' -ErrorAction SilentlyContinue | Format-List | Out-String }
    'ipconfig /all'              = { ipconfig /all | Out-String }
}
$sections.GetEnumerator() | ForEach-Object {
    "===== $($_.Key) ====="
    try { & $_.Value } catch { "ERROR: $($_.Exception.Message)" }  # 不存在的項目(如 Windows 10 的 DoH)當成錯誤保留下來
} | Set-Content -Path $out -Encoding UTF8
Write-Host "wrote $out"

要比較的是 DNS 伺服器的排列、搜尋清單、連線特定尾碼、NRPT、DoH、介面度量、原則值。

HKLM\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient 中有「關閉多點傳送名稱解析」的 EnableMulticast、「關閉智慧型多重主目錄名稱解析」的 DisableSmartNameResolution,以及搜尋清單和主要尾碼等。4 把差異與前面整理過的各層作用對照著看。

步驟 7: 用封包擷取取得佐證

Microsoft 的資料收集步驟是:在用戶端和伺服器兩側啟動 netsh trace start capture=yes,用 ipconfig /flushdns 丟掉快取後重現問題,再用 netsh trace stop 停止。41

在 Wireshark 中用 dns.qry.name == "app01.corp.example.com"dns.qry.name contains "app01" 篩選,確認向哪台伺服器問了什麼、回來了什麼。

擷取封包中看到的 要查的位置
沒有送出查詢 除了快取、hosts,以及 DoH、DoT 或連結本機等其他路徑,還要確認傳送端防火牆是否阻擋了 UDP 53
送出了查詢但沒有回應 通往 DNS 伺服器的路徑、防火牆、伺服器無回應
回來了否定回應 查詢的名稱與伺服器那側的記錄
回來了肯定回應 名稱解析之後的連線那側。也確認所用的位址與 IPv6

當傳送端防火牆阻擋了 UDP 53 時,Resolve-DnsName 會逾時,擷取封包中也不會出現 DNS 查詢。不只要區分「名稱解析成功但通訊沒出去」,也要區分「失敗且通訊沒出去」。3

DNS 之外,LLMNR 看 5355,mDNS 看 UDP 5353,NetBT 的名稱服務看 UDP 137。DoH 是 443,DoT 是 853。擷取封包的採集與讀法彙整在封包擷取文章中。

9. 業務應用程式那側的設計 ── 讓它扛得住名稱解析問題

要讓調查變輕鬆,應用程式那側能留下「用什麼名稱、解析成了什麼、在哪裡失敗」是很關鍵的。把應用程式的記錄與資訊部門採集的設定傾印、擷取封包對上,就更容易決定從第 8 章的哪一步查起。

目的地用 FQDN 保存,不依賴 hosts

設定檔的預設值、捷徑、UNC 路徑都改成 FQDN,以擺脫單一標籤名稱的尾碼補完以及對 LLMNR、NetBT 的依賴。不過 5.4 節提到的注意點仍在:.local 名稱會併用 mDNS,結尾沒有點的名稱會受附加尾碼原則的影響。

hosts 對開發過程中的暫時覆寫很方便,但需要系統管理員權限與手動操作,既不好散布也不好管理變更歷程,而且有的解析器根本不看它(nslookup 就不看12)。目的地的切換應該在設定檔中進行。

記錄名稱解析的結果、耗時與失敗原因

在啟動時等時機,記錄主要目的地的 IPv4、IPv6 位址與耗時。Dns.GetHostAddresses 回傳的結果與 getaddrinfo 相同,因此可以追溯「哪台電腦、從什麼時候起、解析成了什麼」。11

// 啟動時記錄主要目的地的名稱解析結果(.NET 6 以上)
static async Task LogNameResolutionAsync(ILogger logger, string host)
{
    var sw = System.Diagnostics.Stopwatch.StartNew();
    try
    {
        var addresses = await System.Net.Dns.GetHostAddressesAsync(host);
        logger.LogInformation("名稱解析 {Host} -> {Addresses} ({Elapsed} ms)",
            host, string.Join(",", addresses.Select(a => a.ToString())), sw.ElapsedMilliseconds);
    }
    catch (System.Net.Sockets.SocketException ex)
    {
        logger.LogError(ex, "名稱解析失敗 {Host} 錯誤 {Code} ({Elapsed} ms)",
            host, ex.SocketErrorCode, sw.ElapsedMilliseconds);
        throw;
    }
}

失敗要寫進記錄檔並重新擲回。因為若悄悄換成別的名稱或固定 IP,調查時就看不出實際的路徑了。有了錯誤碼與耗時,資訊部門就能判斷該從步驟 2~4 的哪一步開始。

把逾時與 IPv6 的答案考慮進去

DNS 用戶端對無回應的伺服器,每個查詢候選最多要用 10 秒。21 若尾碼搜尋使候選變成多個,整體就可能超過 10 秒。

把連線逾時壓到 2~3 秒後,在會回答的伺服器排在第 4 位以後的設定裡,名稱解析就趕不上期限。不過因為第 2 台是在 1 秒後、第 3 台是在 2 秒後被查詢,所以只掉一台並不一定就會失敗。要結合 4.2 節的重傳時間來設計。

另外,如果回傳了 AAAA,而且存在 IPv6 的來源位址與路由,Windows 預設會讓 IPv6 優先。38 只考慮 IPv4 的連線程式碼,可能出現名稱解析成功卻連線失敗的情況。要把名稱解析的成功與連線的成功分開,並讓程式碼能處理兩種位址。

10. 總結

Windows 的名稱解析首先要分清的是名稱的形態、給出答案的層、以及應用程式走的路徑

快取與 hosts 先回答,對單一標籤名稱則預設由 DNS 與 LLMNR、NetBT 平行運作。.local 還會加上 mDNS。進入 DNS 之後,尾碼、重傳時間、多網卡、NRPT 都會改變結果。DoH 是替換其傳輸通道的功能,要與瀏覽器的內建解析器分開考慮。

調查依 -CacheOnly-NoHostsFile -DnsOnly-Server-LlmnrOnly 的順序限定路徑,再用設定傾印的差異與擷取封包來確認。重要的是不要漏掉否定快取、無回應與否定回應的差別,以及用戶端那側的原則。

遇到「只有這台電腦連不上」時,請先確認下面兩點。

那個名稱是以什麼形態被交過來的?在那台電腦上,是哪條路徑在回答?

把這兩點對齊,就能縮小要查的範圍。

相關文章

相關的諮詢領域

小村軟體有限公司承接「只有部分電腦的業務應用程式連不上內部伺服器」「瀏覽器開得起來、應用程式卻名稱解析失敗」這類由名稱解析引起的通訊問題的原因調查,業務應用程式能否承受停用 LLMNR、DoH、VPN 等環境變更的設計審查,以及記錄名稱解析結果與逾時的通訊層實作。如果能附上連得上與連不上的電腦的設定傾印再來諮詢,調查的切入點會更快確定。

參考連結

  1. Microsoft Learn, Secure DNS Client over HTTPS (DoH). 關於只有慣用/替代 DNS 伺服器在已知 DoH 伺服器清單中時才能設定 DoH、設定應用程式的三個加密選項以及「優先加密」會不作通知地回到明文、群組原則「設定 DNS over HTTPS (DoH) 名稱解析」的 Allow/Prohibit/Require、不得在加入網域的電腦上啟用 Require 的理由、已知伺服器清單(Cloudflare・Google・Quad9)與 Get-DnsClientDohServerAddress、用 Add-DnsClientDohServerAddress 新增,以及與 NRPT 的併用。  2 3 4 5

  2. Microsoft Learn, MSFT_DNSClientGlobalSetting class. 關於作為 DnsClient Cmdlet 基礎的 WMI 類別,其最低支援的作業系統是 Windows 8 / Windows Server 2012。 

  3. Microsoft Learn, Troubleshoot DNS client name resolution issues. 關於 DNS 用戶端依快取→hosts 檔案→DNS 伺服器的順序解析、hosts 中有對應項時不會有 DNS 通訊、擋住 UDP 53 會讓 Resolve-DnsName 逾時、多台伺服器中可達的少時約需 4 秒、nslookup 只問第一台 DNS 伺服器、長尾碼搜尋清單帶來的延遲、用結尾的點做特定查詢,以及用 Measure-Command 測量耗時。  2 3 4 5 6 7 8 9

  4. Microsoft Learn, Policy CSP - ADMX_DnsClient. 關於「關閉智慧型多重主目錄名稱解析」(預設把 DNS・LLMNR・NetBT 平行送往所有網路,多個肯定回應依繫結順序採用;啟用後變為 DNS→LLMNR→NetBT 的串列)、「關閉智慧型通訊協定重新排序」(預設在非網域網路上單一標籤名稱優先採用連結本機回應)、「關閉多點傳送名稱解析」(LLMNR 是次要通訊協定且會在所有介面卡上被停用,登錄值 EnableMulticast)、DNS 尾碼搜尋清單與遞減、「允許對多標籤的未限定名稱查詢附加 DNS 尾碼」(對含點但結尾無點的名稱也附加尾碼查詢的原則)、主要 DNS 尾碼、連線特定尾碼,以及登錄機碼 Software\Policies\Microsoft\Windows NT\DNSClient。  2 3 4 5 6 7 8 9

  5. Microsoft Learn, DNS queries and lookups. 關於 hosts 的內容在 DNS 用戶端服務啟動時讀入快取、DNS 回應也在 TTL 期間保存於快取、FQDN 與多標籤名稱與單一標籤名稱的查詢建構方式不同且會依序使用尾碼搜尋清單・主要尾碼・遞減・連線特定尾碼、肯定與否定回應都會被快取、多介面卡下的查詢順序與因否定回應而排除介面卡、自適應逾時與無回應伺服器的快取。  2 3 4 5 6 7 8 9 10

  6. Microsoft Learn, VPNv2 CSP. 關於 VPN 設定檔的 DomainNameInformationList 就是 NRPT 的規則、只有使用 Windows DNS API 的應用程式才能用到 NRPT 而自備 DNS 實作的應用程式會繞過、其例子是 nslookup,以及確認 NRPT 時務必使用 Resolve-DnsName。  2 3 4

  7. Microsoft Learn, Microsoft Edge policy: BuiltInDnsClientEnabled. 關於 Edge 預設使用內建 DNS 用戶端、該原則不影響使用哪台 DNS 伺服器,以及 DoH 的查詢一律由內建解析器進行。  2 3 4

  8. Microsoft Learn, Resolve-DnsName. 關於 -CacheOnly(僅本機快取)、-DnsOnly(僅 DNS 通訊協定,不送出 LLMNR・NetBIOS)、-NoHostsFile(跳過 hosts)、-LlmnrOnly、-LlmnrNetbiosOnly、-LlmnrFallback、-NetbiosFallback、-Server、-Type(預設 A_AAAA)、-QuickTimeout、-TcpOnly 各參數。  2 3 4 5 6

  9. Microsoft Learn, Windows security book: Network security. 關於 Windows 11 的 DNS 用戶端支援 DoH 與 DoT、可透過群組原則與程式設定 DoH,以及加密 DNS 的支援與 NRPT・系統的 hosts 檔案・依介面卡或依設定檔的解析器指定等既有 DNS 設定整合在一起。  2 3

  10. Microsoft Learn, getaddrinfo function (ws2tcpip.h). 關於針對 NS_DNS 命名空間用 DNS・本機 hosts 檔案・其他機制把名稱轉換成位址、彙整多個命名空間提供者的回應,以及 Unicode 版是 GetAddrInfoW。  2

  11. Microsoft Learn, Dns.GetHostAddresses Method. 關於它由底層作業系統的名稱解析 API(Windows 上是 getaddrinfo)實作,以及寫在 hosts 檔案中的主機不會去問 DNS 伺服器而直接回傳那個位址。  2 3

  12. Microsoft Learn, Troubleshoot Azure DNS. 關於 nslookup 不使用作業系統的本機 DNS 解析器程式庫,繞過本機 DNS 快取・hosts 檔案・NRPT,以及這些層相關時應使用 Resolve-DnsName。  2 3

  13. Microsoft Learn, ipconfig. 關於 /displaydns 顯示包含從 hosts 讀入的項目與最近解析的記錄在內的 DNS 用戶端解析器快取、/flushdns 丟棄包含否定快取項目在內的快取,以及 /registerdns 的動態註冊。  2

  14. Microsoft Learn, Troubleshooting DNS clients. 關於 ipconfig /displaydns 中失敗的名稱顯示「Name does not exist」即表示 DNS 伺服器的否定回應被快取在用戶端、用 ipconfig /flushdns 解決,以及 nslookup 不使用用戶端的 DNS 快取。 

  15. Microsoft Learn, Windows Firewall profile doesn’t always switch to Domain when you use a third-party VPN client. 關於 Dnscache\Parameters 的 MaxNegativeCacheTtl 預設值為 5 秒,設為 0 可停用否定快取。 

  16. Microsoft Learn, Clear-DnsClientCache. 關於刪除 DNS 用戶端快取的全部內容,等同於 ipconfig /flushdns。 

  17. Microsoft Learn, Get-DnsClientCache. 關於取得本機 DNS 用戶端快取的內容,並可依 Name・Type・TimeToLive・Section 等篩選。 

  18. Microsoft Learn, How to configure a domain suffix search list on the Domain Name System clients. 關於一旦設定了網域尾碼搜尋清單就只使用該清單,主要 DNS 尾碼、連線特定尾碼與遞減都不再使用。 

  19. Microsoft Learn, Get-DnsClientGlobalSetting. 關於取得不與介面繫結的 DNS 用戶端全域設定(UseSuffixSearchList・SuffixSearchList・UseDevolution・DevolutionLevel)。 

  20. Microsoft Learn, Get-DnsClient. 關於取得依介面的 ConnectionSpecificSuffix・RegisterThisConnectionsAddress・UseSuffixWhenRegistering。 

  21. Microsoft Learn, DNS client resolution timeouts. 關於 DNS 伺服器為 1 台、2 台、3 台以上時的重傳時機(開始後 1・2・4・8 秒重傳,10 秒放棄)、收到否定回應就停止而只有無回應時才嘗試下一台,以及第 4 位以後的伺服器最少要 4 秒之後才被問到。  2 3 4

  22. Microsoft Learn, Automatic interface metric. 關於現今 Windows 中介面的優先順序由介面度量決定,可用 Get-NetIPInterface 檢視與變更度量。 

  23. Microsoft Learn, Get-DnsClientNrptPolicy. 關於取得 NRPT 中依命名空間設定的內容(DNS 用戶端的名稱伺服器、DirectAccess、DNSSEC 等),用 -Effective 顯示實效原則、用 -Namespace 顯示特定命名空間的部分。  2

  24. IETF, RFC 6762: Multicast DNS. 關於 mDNS 是以 UDP 連接埠 5353 的多播在同一連結內解析 .local 名稱的通訊協定。  2 3

  25. Microsoft Learn, Microsoft Security Bulletin MS11-030. 關於 LLMNR 使用 TCP/UDP 5355、作為因應措施在防火牆上阻擋 5355 與啟用群組原則「關閉多點傳送名稱解析」,以及其影響是電腦可能不再被其他電腦看到。  2

  26. IETF, RFC 4795: Link-Local Multicast Name Resolution (LLMNR). 關於 LLMNR 的查詢以 UDP 多播(連接埠 5355)送出,TCP 用於被截斷的回應等單播往來。 

  27. Microsoft Tech Community, Networking Blog, Aligning on mDNS: ramping down NetBIOS name resolution and LLMNR. 關於 Microsoft 於 2022 年 4 月公布的、向 mDNS 靠攏並逐步收斂 NetBIOS 名稱解析與 LLMNR 的方針。  2

  28. Microsoft Learn, How to configure TCP/IP networking while NetBIOS is turned off. 關於 NetBIOS 名稱服務使用 UDP 137、資料包服務使用 UDP 138、工作階段服務使用 TCP 139,以及停用 NetBT 後就不再接聽這些連接埠。 

  29. Microsoft Learn, Windows security baseline (Azure Policy guest configuration). 關於 NetBT 的節點類型(B-node 只有廣播、P-node 只有 WINS、M-node 先廣播後 WINS、H-node 先 WINS 後廣播)、未設定 WINS 時預設 B-node 而已設定時預設 H-node,以及建議 P-node。  2 3

  30. Microsoft Learn, Windows Internet Name Service (WINS). 關於 WINS 是把 NetBIOS 名稱對應到 IP 位址的舊有服務,建議不再新建部署而使用 DNS,已部署的則移轉到 DNS 後廢止。  2

  31. Microsoft Learn, nbtstat. 關於 /c 顯示 NetBIOS 名稱快取、/R 清除快取並重新讀入 Lmhosts 中預先標記的項目、/RR 釋放並重新向 WINS 註冊。 

  32. Microsoft Learn, Features removed or no longer developed in Windows Server. 關於 Computer Browser 服務作為過時且不安全的裝置探索通訊協定被淘汰,以及 WINS 等舊有名稱解析相關功能的處置。 

  33. Microsoft Learn, Direct host SMB over TCP/IP. 關於 Windows Vista / Windows Server 2008 以後的 SMB 2.0.2 需要 TCP 445 且不使用 NetBIOS 工作階段傳輸。該資料把可以把名稱解析標準化到 DNS 列為其優點,但那說的是 SMB 的傳輸通道,並不會阻止用戶端的 DNS 用戶端用 LLMNR 或 NetBT 解析單一標籤名稱(正文 5.4 節)。 

  34. Microsoft Learn, Add-DnsClientDohServerAddress. 關於把 DoH 伺服器設定新增到已知伺服器清單,並用 -DohTemplate・-AllowFallbackToUdp・-AutoUpgrade 指定加密失敗時的回復與自動升級。 

  35. Microsoft Learn, netsh dnsclient. 關於用 add/set encryption 登錄 DoH・DoT 伺服器(dohtemplate・dothost・autoupgrade・udpfallback)、用 set global 做 doh/dot/ddr 的全域設定,以及 show encryption・show global・show state。  2 3 4 5

  36. Microsoft Learn, User data and privacy in Microsoft Edge: Secure DNS. 關於安全 DNS 預設使用目前的提供者、加密連線失敗時以明文重試、選擇特定提供者則不回到明文,以及在受組織管理的電腦上預設停用。 

  37. Microsoft Learn, Microsoft Edge policy: DnsOverHttpsMode. 關於 off・automatic・secure 三種模式,以及在受管理裝置上未設定時不送出 DoH 查詢。 

  38. Microsoft Learn, Guidance for configuring IPv6 in Windows for advanced users. 關於 Windows Vista 以後用 RFC 3484 的前置詞表決定使用哪個位址、預設讓 IPv6 全域單播優先於 IPv4,以及不建議停用 IPv6 而應使用 DisabledComponents 的 0x20 來「優先 IPv4」。  2 3

  39. IETF, RFC 3484: Default Address Selection for Internet Protocol version 6 (IPv6). 關於目的地位址選擇規則的第 1 條是「避開不可用的目的地」,先排除沒有來源位址或路由的目的地,再依前置詞原則的優先度排列候選。 

  40. Microsoft Learn, Configure DNSSEC rules using the Name Resolution Policy Table. 關於 NRPT 的命名空間種類(尾碼・前置詞・FQDN・子網路・Any)、尾碼是包含子網域的結尾比對,以及更具體的規則優先於更一般的規則。 

  41. Microsoft Learn, Troubleshooting Domain Name System (DNS) issues: Data collection. 關於在用戶端與伺服器上啟動 netsh trace start capture=yes、用 ipconfig /flushdns 丟掉快取後重現、再用 netsh trace stop 停止的資料收集步驟。 

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

本文連結到以下服務頁面,歡迎從最接近的入口查看。

常見問題

整理諮詢這個主題時常見的問題。

我改了 hosts 檔案卻沒有生效,為什麼?
Windows 的 hosts 檔案內容會在 DNS 用戶端服務啟動時讀入快取,名稱解析依快取→hosts→DNS 伺服器的順序推進。沒有生效時,請先用 ipconfig /displaydns 檢視該名稱的項目,如果還留著舊的回應,就用 ipconfig /flushdns 丟掉它。接著要懷疑你使用的工具是否走了 Windows 的解析器。nslookup 不使用作業系統的解析器,它會繞過快取、hosts 與 NRPT 直接向 DNS 伺服器查詢,因此 hosts 的內容完全不會反映出來。要看包含 hosts 在內的實際解析結果,請用 Resolve-DnsName 或 ping。如果仍然沒有生效,就確認這個應用程式是否像瀏覽器那樣自備解析器或 DoH。
瀏覽器可以開啟網站,但只有業務應用程式名稱解析失敗。
這多半是瀏覽器和應用程式走了不同的路徑去查名稱。Microsoft Edge 預設不使用作業系統的 DNS 用戶端,而是用內建的 DNS 用戶端與 DNS 伺服器通訊;若在安全 DNS(DoH)中選了別的提供者,它就會向外部解析器查詢。另一方面,.NET 的 Dns.GetHostAddresses 以及直接連線目的地的 HttpClient 會走作業系統的 getaddrinfo,因此會完整受到 hosts、DNS 快取、NRPT 與尾碼搜尋清單的影響(經 HTTP Proxy 的要求中,目的地的名稱由 Proxy 那側解析)。當兩者給出不同答案時,用 Resolve-DnsName 與封包擷取把「哪條路徑向哪台 DNS 伺服器問了什麼」對上,是最快的辦法。
設定應該一樣,卻只有部分電腦連不上內部伺服器。該比較什麼?
比較名稱的形態,以及那台電腦是在哪一層得到答案的。單一標籤名稱(像 server01 這種不含點的名稱)會被電腦的 DNS 尾碼搜尋清單或連線特定尾碼補完後送往 DNS,而且預設還會平行地向 LLMNR、NetBIOS 廣播這類僅限同一子網路的手段查詢(只有在停用最佳化之後,才會在 DNS 失敗後依序嘗試。若設定了 WINS,NetBIOS 可以用單播跨越子網路)。加入網域的電腦可能因為尾碼補完為 FQDN 而解析成功,但經 VPN 或位於其他子網路的電腦,以及停用了 LLMNR 與 NetBIOS 的電腦,同一個名稱就解析不了。可靠的做法是在連得上與連不上的兩台電腦上都採集 Get-DnsClientServerAddress、Get-DnsClientGlobalSetting、Get-DnsClient、Get-DnsClientNrptPolicy -Effective 的輸出並做差異比對。根本對策是把設定檔與捷徑裡的目的地改成 FQDN。
名稱解析不是失敗,而是等了幾秒才終於連上。原因是什麼?
這是 DNS 用戶端的逾時與重試機制顯現了出來。對於沒有回應的 DNS 伺服器,Windows 會在開始後的 1 秒、2 秒、4 秒、8 秒時重傳,10 秒時放棄。就算設定了多台 DNS 伺服器,只要會回應的那台排在清單第 4 位以後,就至少要等 4 秒才會去問它。另外,很長的 DNS 尾碼搜尋清單也會因為解析單一標籤名稱時逐一嘗試尾碼而累積延遲。請用 Measure-Command 測量 Resolve-DnsName 的耗時,並在 Wireshark 中以 dns.qry.name 篩選,看看是對哪台伺服器的查詢沒有得到回應。
為了資安停用了 LLMNR 與 NetBIOS,結果有些裝置用名稱連不上了。
這是可以預期的副作用。LLMNR 與 NetBIOS over TCP/IP 是在同一子網路內解析未登錄到 DNS 的裝置的單一標籤名稱的次要手段,停用它們就等於拿掉了那條路徑。Microsoft 自己也在 2022 年提出向 mDNS 靠攏、逐步收斂 NetBIOS 名稱解析與 LLMNR 的方針,所以停用這個方向本身是正確的判斷。對策是把名稱解析集中到 DNS:在內部 DNS 中登錄裝置的 A 記錄,或啟用透過 DHCP 的動態註冊,並把應用程式與共用的目的地改寫成 FQDN。支援 mDNS 的裝置可以用 .local 名稱解析,但這條路徑同樣只限於多播能到達的範圍。
在 Windows 11 上啟用 DoH(DNS over HTTPS)後,內部的名稱解析會怎樣?
DoH 是把 DNS 用戶端向已設定的 DNS 伺服器查詢時的傳輸通道換成 HTTPS 的功能,hosts、快取、NRPT 這些既有順序照舊有效。如果沒有啟用 DDR(Discovery of Designated Resolvers),能用 DoH 的只有列在已知 DoH 伺服器清單中的伺服器;要用內部 DNS,就需要系統管理員以 Add-DnsClientDohServerAddress 登錄。若把群組原則「設定 DNS over HTTPS (DoH) 名稱解析」設為「要求 DoH」,那麼在不支援 DoH 的伺服器上名稱解析本身就會失敗。Microsoft 明確寫明不要在加入網域的電腦上啟用這項設定,因為 Active Directory 依賴的 Windows Server 內建 DNS 伺服器服務並不支援 DoH 查詢。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽