DNS 配置錯誤怎麼修復?伺服器 DNS 異常的排查步驟
DNS 配置錯誤的典型表現是:ping IP 位址通,ping 域名卻報找不到主機。修復按五步走:先確認報錯確實來自域名解析,再看系統實際在用的 DNS 位址,換一個 DNS 對比查詢,檢查 53 連接埠有沒有被防火牆攔截,最後排除 hosts 檔案、nsswitch 和本地快取的干擾。
DNS 配置錯誤怎麼修復?先確認症狀:伺服器能 ping 通外網 IP,卻 ping 不通域名,yum、apt、curl 都報無法解析主機,這就是域名解析出了問題,而不是網路斷了。排查按五步走:一看報錯,確認是解析失敗;二看系統實際在用哪個 DNS 位址;三換一個 DNS 對比查詢,判斷壞的是 DNS 伺服器還是本機;四查 53 連接埠有沒有被防火牆或安全組攔截;五排除 hosts 檔案、nsswitch 和快取的干擾。多數 DNS 異常在前三步就能定位,常見原因是 DNS 位址寫錯、內網 DNS 當機、防火牆攔截 53 連接埠和 systemd-resolved 衝突。下面給出每一步在 Linux 和 Windows 上的命令,最後是原因對照表。
第一步:確認是不是 DNS 的問題(IP 通、域名不通)
用三條命令把“網路不通”和“解析不通”分開:
ping -c 3 223.5.5.5 # 外網 IP 能通,說明網路卡、閘道器、路由都正常
ping -c 3 www.example.com # 域名不通,問題在解析
curl -sI http://203.0.113.10 # 禁 ping 時用 TCP 代替,IP 換成一個確定能存取的網站位址
第一條通、第二條報錯,就可以把注意力集中到 DNS 上;第一條也不通,先查網路本身,DNS 配置改得再對也沒用。
不同程式報出的錯誤文字不一樣,但能看出解析卡在哪種狀態:
| 報錯 | 出現在 | 說明 |
|---|---|---|
Temporary failure in name resolution |
ping、ssh 等呼叫系統解析器的程式 | 沒拿到任何 DNS 應答:DNS 位址不可達、超時,或者根本沒配置 |
Name or service not known |
同上 | 拿到了“不存在”的結論:域名拼錯、DNS 回答 NXDOMAIN,或 nsswitch 裡沒有啟用 dns |
Could not resolve host、Couldn't resolve host name |
curl、yum、dnf | 解析失敗,具體原因用前兩種區分 |
Temporary failure resolving 'archive.ubuntu.com' |
apt | 與第一行相同,DNS 沒有應答 |
Ping 請求找不到主機 |
Windows 的 ping | 系統解析失敗 |
DNS request timed out |
nslookup | 指定的 DNS 伺服器沒有應答 |
Non-existent domain |
nslookup | DNS 伺服器明確回答“域名不存在” |
DNS_PROBE_FINISHED_NXDOMAIN |
Chrome 等瀏覽器 | 解析失敗或域名不存在 |
“沒有應答”和“回答不存在”是兩類問題:前者多半是 DNS 位址或網路路徑的問題,後者要麼是域名寫錯,要麼是這台 DNS 給出的結果本身有問題。
第二步:檢視系統實際在用的 DNS 位址
Linux 上先看 resolv.conf 是什麼、指向哪裡:
ls -l /etc/resolv.conf # 是普通檔案還是連結
cat /etc/resolv.conf
resolvectl status 2>/dev/null | grep -E "Current DNS|DNS Servers"
nmcli device show 2>/dev/null | grep -i dns
逐項對照下面這些情況,任何一條成立,基本就找到原因了:
- 沒有任何 nameserver 行。glibc 此時預設去問本機 127.0.0.1,本機沒跑 DNS 服務,所有查詢都失敗。
- cat 報 No such file or directory。resolv.conf 是一個斷掉的連結,常見於停用了 systemd-resolved,但連結還指向它執行時才有的檔案。
- 只有
nameserver 127.0.0.53。這是 systemd-resolved 的本地入口,要再確認systemctl is-active systemd-resolved輸出 active,並用resolvectl status看它背後真正的上游 DNS。 - 位址本身不對。少寫或多寫了一位、填成了不提供 DNS 服務的閘道器位址、照搬了別的機房的範本,這類錯誤肉眼看很容易漏過,要和機房給出的 DNS 位址逐位核對。
- 只有一個位址,而那台 DNS 正好故障。
Windows 上執行 ipconfig /all,看每塊網路卡的“DNS 伺服器”一行,或者用 PowerShell 只列出配置了 DNS 的網路卡:
ipconfig /all
Get-DnsClientServerAddress | Where-Object { $_.ServerAddresses } |
Select-Object InterfaceAlias, AddressFamily, ServerAddresses
幾個 Windows 上的典型現象:DNS 顯示為 fec0:0:0:ffff::1 這類位址,是系統在 IPv6 沒有配置 DNS 時填的佔位值,不是真正的伺服器;網路卡顯示“DHCP 已啟用”,說明 DNS 是 DHCP 下發的,手工改過後可能又被下發的值覆蓋;多塊網路卡都填了 DNS,其中內網路卡上的 DNS 已經失效,也會讓解析時好時壞。
第三步:換一個 DNS 對比查詢,判斷壞在哪裡
用同一個域名,分別問“系統配置的 DNS”“一個公共 DNS”和“系統解析流程”,三個結果一對比,故障位置就清楚了。
dig www.example.com +tries=1 +time=2 # 問 resolv.conf 裡的第一個 DNS
dig @223.5.5.5 www.example.com +tries=1 +time=2 # 指定一個公共 DNS
getent hosts www.example.com # 走系統解析流程:hosts、nsswitch、快取
nslookup www.example.com # 問系統配置的第一個 DNS
nslookup www.example.com 223.5.5.5 # 指定公共 DNS
Resolve-DnsName www.example.com # 走系統解析流程,含 hosts 檔案與本機快取
dig 和 nslookup 在 RHEL 系由 bind-utils 軟體包提供,在 Debian 系由 dnsutils 提供,命令不存在時先安裝。對照下表下結論:
| 配置的 DNS | 公共 DNS | 系統解析流程 | 結論 | 去哪一步 |
|---|---|---|---|---|
| 超時 | 正常 | 失敗 | 配置的 DNS 位址寫錯了,或者那台 DNS 伺服器故障 | 改正位址,或修復、更換 DNS |
| 超時 | 超時 | 失敗 | 到任何 DNS 的 53 連接埠都不通 | 第四步 |
| 正常 | 正常 | 失敗 | DNS 沒問題,問題在本機的解析流程 | 第五步 |
| 正常 | 正常 | 返回了不同的位址 | hosts 檔案或快取裡有舊條目 | 第五步 |
| status: REFUSED | 正常 | 失敗 | 那台 DNS 拒絕為你遞迴查詢,通常是存取控制沒包含本機網段 | 聯絡 DNS 管理員 |
| SERVFAIL 或 NXDOMAIN | 同樣失敗 | 失敗 | 域名本身有問題 | 用 dig +trace 追查 |
dig 輸出裡 status: 後面的值很關鍵:NOERROR 是正常;NXDOMAIN 是域名不存在;SERVFAIL 是遞迴伺服器沒能拿到可信的結果;REFUSED 是伺服器收到了查詢但拒絕回答。看到 REFUSED 反而說明網路是通的,問題在對方的配置,比如內網 DNS 的遞迴存取控制(BIND 的 allow-recursion)沒有包含這台伺服器所在的網段。
第四步:檢查 53 連接埠有沒有被防火牆攔截
DNS 查詢平時走 UDP 53,應答較大時改走 TCP 53。分別測兩種協議,能直接判斷攔的是哪一種:
dig @223.5.5.5 www.example.com +tries=1 +time=2 # UDP
dig +tcp @223.5.5.5 www.example.com +tries=1 +time=2 # TCP
nc -zv -w 3 223.5.5.5 53 # 只測 TCP 53 能否建立連線
TCP 正常而 UDP 超時,說明 UDP 53 被攔;兩者都超時,說明到 DNS 伺服器的 53 連接埠整體不通。要知道包是沒發出去還是沒回來,抓包看一眼:
tcpdump -nni any port 53 # 在另一個視窗執行查詢,觀察有沒有請求發出、有沒有應答回來
只看到發出的請求、沒有應答,問題在本機之外:雲安全組的出方向規則、機房只允許存取指定的 DNS、上游的 ACL。連請求都看不到,問題在本機:出方向防火牆規則,或解析器根本沒有向這個位址發包。
本機防火牆這樣查:
iptables -S OUTPUT # 預設策略是 DROP 時,要有放行 53 的規則
iptables -S INPUT | grep -i established # 入方向要放行已建立連線的回包
nft list ruleset | grep -n "dport 53"
Get-NetFirewallProfile | Select-Object Name, DefaultOutboundAction # Block 表示預設阻止出站
出方向預設拒絕的伺服器,放行 DNS 要寫兩類規則:出方向允許 UDP 和 TCP 的 53,入方向允許已建立連線的回包。以 iptables 為例:
iptables -I OUTPUT -p udp --dport 53 -j ACCEPT
iptables -I OUTPUT -p tcp --dport 53 -j ACCEPT
iptables -I INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
規則確認有效後,按系統的方式儲存,否則重啟後丟失。只放行了 UDP 而沒放行 TCP 53,平時看不出問題,遇到應答較大的域名(記錄很多、開啟了 DNSSEC)才會偶發失敗,這類問題最難查,兩種協議應一起放行。
第五步:排除 hosts 檔案、nsswitch 與快取
dig 和 nslookup 直接與 DNS 伺服器對話,而程式解析域名要先經過本機的一套流程。DNS 查詢正常、程式還是報錯,就看這三處。
hosts 檔案。裡面寫死的條目優先於 DNS,測試時臨時加的記錄忘了刪,就會讓某個域名一直指向舊位址:
grep -vE '^\s*(#|$)' /etc/hosts
Get-Content C:\Windows\System32\drivers\etc\hosts | Where-Object { $_ -notmatch '^\s*#' -and $_.Trim() }
nsswitch.conf(僅 Linux)。它決定解析時按什麼順序查哪些來源:
grep '^hosts' /etc/nsswitch.conf
# 正常應類似:hosts: files dns myhostname
這一行裡沒有 dns,系統就只查 hosts 檔案,dig 查詢一切正常、所有程式卻都解析失敗,正是表格裡“DNS 正常、系統解析流程失敗”的典型原因。精簡過的容器映象和被安全加固指令碼改過的系統偶爾會出現這種情況,把 dns 加回去即可,不需要重啟。
快取。修好之後,舊的失敗結果可能還留在快取裡:Linux 上使用 systemd-resolved 的執行 resolvectl flush-caches,使用 nscd 的執行 nscd -i hosts;Windows 先用 ipconfig /displaydns | findstr example 看快取裡有沒有這個域名,再用 ipconfig /flushdns 清掉。注意失敗的查詢結果也會被快取一段時間,修復後不清快取,會誤以為沒修好。Java、Nginx 這類自己快取解析結果的程式,要重啟或過載才會重新解析。
systemd-resolved 衝突與 DNS 異常常見原因對照表
Ubuntu 18.04 及之後的版本、Fedora 33 及之後的版本預設啟用 systemd-resolved,其他發行版也可能手動啟用了它。它會帶來幾種特有的故障:
- 服務沒在執行。resolv.conf 裡只有 127.0.0.53,而 systemd-resolved 被停用了,所有查詢都發給一個沒人監聽的位址。執行
systemctl enable --now systemd-resolved恢復;如果確實不想用它,就把 resolv.conf 換成寫有真實 DNS 位址的普通檔案。 - 與本地 DNS 服務搶 53 連接埠。在同一台機器上裝 dnsmasq 等本地 DNS 服務、並讓它監聽所有位址的 53 連接埠時,會和已經佔用 127.0.0.53:53 的 systemd-resolved 衝突,新服務啟動時報 Address already in use。用
ss -lunp 'sport = :53'確認佔用者,在/etc/systemd/resolved.conf裡設定DNSStubListener=no後重啟它,再把 resolv.conf 指向新裝的 DNS 服務。 - 查詢被別的網路卡“搶走”。伺服器接了 VPN 或第二塊網路卡,那塊網路卡上的 DNS 會參與解析,某些域名的查詢被髮到了錯誤的 DNS。
resolvectl status能看到每塊網路卡各自的 DNS,resolvectl query www.example.com會顯示這次結果是經由哪塊網路卡、用了多長時間拿到的。 - 想繞過本地入口。需要讓程式直接使用上游 DNS 時,執行
ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf,這個檔案裡列出的是 systemd-resolved 當前使用的真實上游位址。
把常見原因彙總如下,排查時可以按“典型表現”一列對號入座:
| 原因 | 典型表現 | 怎麼確認 | 怎麼修復 |
|---|---|---|---|
| DNS 位址寫錯 | 所有域名超時 | 對該位址 dig 超時,換公共 DNS 正常 | 改成機房提供的正確位址 |
| 手工配置被覆蓋 | 修好後重啟又壞 | resolv.conf 開頭的生成註釋,網路卡的 DHCP 狀態 | 到 NetworkManager、netplan 或 DHCP 的源頭修改 |
| 內網 DNS 當機 | 同網段多台伺服器同時解析失敗 | 對內網 DNS dig 超時,DNS 伺服器上服務狀態異常 | 恢復服務,並部署第二台互為備份 |
| 內網 DNS 拒絕遞迴 | status: REFUSED | dig 輸出 | 把伺服器網段加入允許遞迴的範圍 |
| 防火牆或安全組攔截 53 | UDP 超時,TCP 可能正常 | dig 與 dig +tcp 對比,tcpdump | 放行出方向 UDP、TCP 53 和回包 |
| systemd-resolved 未執行 | 只有 127.0.0.53 且無應答 | systemctl is-active systemd-resolved |
啟動服務,或改用普通 resolv.conf |
| 53 連接埠被爭用 | 本地 DNS 服務啟動失敗 | ss -lunp 'sport = :53' |
設定 DNSStubListener=no |
| hosts 殘留條目 | 單個域名指向舊位址 | getent 與 dig 的結果不同 | 刪除條目並清快取 |
| nsswitch 缺少 dns | dig 正常,程式全部失敗 | grep '^hosts' /etc/nsswitch.conf |
把 dns 加回去 |
| 不可達的 IPv6 DNS 排在前面 | 每次解析都要多等幾秒才成功 | 看 resolv.conf 的順序,time getent hosts |
調整順序或刪除該位址 |
| 系統時間偏差太大 | 開啟了 DNSSEC 校驗的本機解析器返回 SERVFAIL | date 與實際時間對比 |
校準時間 |
在管理系統裡怎麼落地
“DNS 位址寫錯”和“手工配置被覆蓋”是最常見的兩類原因,根源都是伺服器上該填什麼沒有一個可以核對的依據。Toplink DCIM 的 IP 位址管理 中,每個位址段除了網段、閘道器和 VLAN,還填寫了兩個 DNS 位址:排查時拿伺服器的 resolv.conf 或 ipconfig /all 輸出和這條記錄逐位對照,位址寫錯、照搬了別的機房範本,一眼就能看出來;同一個段的伺服器同時出現解析失敗時,也能馬上確認它們共用的是哪台 DNS。如果排查到第一步就發現連外網 IP 都不通,問題在網路本身,可以在 交換器管理 裡檢視這台伺服器所在的交換器連接埠是否開啟、VLAN 是否正確,或者在瀏覽器裡開啟交換器終端繼續排查。
常見問題
電腦 DNS 異常上不了網怎麼辦?
先執行 ipconfig /flushdns 清快取;再到網路卡屬性裡把 DNS 改為手動填寫,例如 223.5.5.5 和 119.29.29.29。仍然不行,重啟路由器,並檢查代理軟體或安全軟體是否接管了網路;網路元件被改壞時,管理員身份執行 netsh winsock reset 後重啟電腦。
nslookup 顯示 Server: UnKnown,是 DNS 出問題了嗎?
不是。UnKnown 只表示 nslookup 沒能反查到這台 DNS 伺服器 IP 對應的名字(沒有 PTR 記錄),下面能正常返回域名的位址,解析就是正常的。
為什麼只有一個域名解析失敗,其他域名都正常?
多半是這個域名自己出了問題,比如權威伺服器故障、記錄被刪、DNSSEC 簽名過期,這時換公共 DNS 通常也查不到。用 dig +trace 域名 看查詢卡在哪一級,再聯絡域名的管理方。