53
名稱解析的連接埠,UDP 和 TCP 都用——而在多數現代 Linux 桌面上它早就被 systemd-resolved 占走了,這就是你的 dnsmasq 或 Pi-hole 起不來的原因。
照你的系統挑一行貼上去執行。它會直接印出占著這個連接埠的行程,以及它綁在哪個位址上——通常看到這兩件事答案就出來了。
sudo lsof -nP -i :53這裡刻意不加 `-sTCP:LISTEN`:UDP socket 沒有 LISTEN 狀態,加上那個過濾條件會把 DNS 最重要的那一半藏起來。`-i :53` 兩種協定一起選。協定寫在 NODE 那一欄,會是 `TCP` 或 `UDP`;TYPE 只是位址族(`IPv4` / `IPv6`),所以兩行 TYPE 都是 IPv4,仍然可以一行 TCP、一行 UDP。`UDP` 那行括號裡沒有狀態,`TCP` 那行會顯示 `(LISTEN)`。NAME 欄放的是綁定位址:`127.0.0.1:53` 只服務本機,`*:53` 服務每一張介面。`-n` 和 `-P` 讓主機和連接埠維持數字。不加 `sudo` 的話,root 擁有的解析器完全不會出現。
sudo ss -tulnp 'sport = :53'`-t` 和 `-u` 合起來涵蓋 TCP 和 UDP,`-l` 只留監聽中的 socket,`-n` 讓連接埠維持數字,`-p` 點出行程。位址那一欄就是整個答案:`127.0.0.53:53` 是 systemd-resolved 的 stub,也就是第二個解析器綁不上去的原因;`127.0.0.1:53` 是只服務本機的解析器;`0.0.0.0:53` 或 `[::]:53` 則是對網路開放的伺服器。UDP 那幾行沒有連線狀態,這是正常的,不是錯誤。行程名稱會顯示成 `users:(("systemd-resolve",pid=701,fd=12))`;不加 `sudo` 的話,不屬於你的那些這一欄會是空的。
sudo netstat -tulnp | grep ':53 '沒有 iproute2 的機器用 net-tools 這個寫法,旗標意思一樣。最後那欄 PID/Program name 對不屬於你的 socket 需要超級使用者權限,man page 也註明這個值不可信。樣式最後那個空格留著,不然 `:53` 會連 `:5353` 一起命中,而那是多點傳播 DNS,完全是另一個服務。
netstat -ano | findstr :53`-a` 在這裡比平常更重要:微軟的說明是它會顯示「所有作用中的 TCP 連線,以及電腦正在監聽的 TCP 和 UDP 連接埠」,所以 UDP 那一側是靠它才浮出來的。`-n` 讓欄位維持數字,`-o` 補上所屬 PID,再用 `tasklist /FI "PID eq 1234"` 換成名字。在網域控制站上,持有者是 `dns.exe`,而且它本來就該在那裡。注意子字串比對:`:53` 也會命中 `:5353` 和 `:53000`。
`nmap -Pn -sU -p 53 ns1.example.com` 掃的是 UDP 那一側,也就是真正在跑查詢的那一側。`-sU` 要用 raw socket,所以得加 `sudo`;不加的話 nmap 會在送出任何封包之前就以 `You requested a scan type which requires root privileges.` 停下來。把 `-sU` 拿掉就改測 TCP 53,而兩邊都要測,因為只開一邊的防火牆是經典的間歇性故障製造機。UDP 的結果不像 TCP 那麼明確:沒有回應和被丟掉分不出來,所以 nmap 會報 `open|filtered`、不下定論,而 `closed` 代表回來了一個 ICMP port unreachable。加 `--reason` 可以看到它實際觀察到什麼。不過要拿到真正的答案,與其掃描,不如直接問伺服器一個問題:`dig @ns1.example.com example.com A` 的結果不是回一組記錄、就是逾時、就是被拒絕,資訊一樣但含糊之處少得多。只掃你自己負責的主機。
| 你看到的訊息 | 代表什麼 |
|---|---|
dnsmasq: failed to create listening socket for port 53: Address already in use | 在 systemd 系的發行版上,這幾乎一定是 systemd-resolved 的 stub 監聽者已經占著 127.0.0.53:53。先用上面的 Linux 探測指令確認,然後要嘛在 `/etc/systemd/resolved.conf` 裡設 `DNSStubListener=no` 再重啟 systemd-resolved,要嘛把你的解析器綁到某張介面的特定位址上,不要用萬用位址。直接砍行程是沒用的,重開機它就回來了。 |
;; communications error to 192.0.2.1#53: connection refused | 主機回答了,而且答案是「不」。那個位址上的連接埠 53 沒有任何東西綁著:解析器停了、啟動時就掛了,或是只綁在回送位址上,所以除了伺服器自己以外誰都看不到它。請在解析器那台主機上跑探測指令,而且要看綁定位址,不要只確認有沒有行程存在。 |
;; connection timed out; no servers could be reached | 什麼都沒回來。封包過濾器正在丟掉你的查詢——安全群組、主機上的防火牆,或某條網路 ACL——再不然就是位址根本寫錯了。因為 UDP 是無連線的,不會有 reset 來告訴你別的,所以這段沉默會持續到逾時為止。順便用 `dig +tcp` 測 TCP:如果 TCP 通而 UDP 不通,這道封鎖是針對協定的。 |
;; Truncated, retrying in TCP mode. — then a timeout | 答案超過了 UDP 回應塞得下的長度,伺服器照 RFC 1035 的要求設了 TC 位元,然後用戶端改用 TCP 重試時被擋掉了。這就是「開了 UDP 53、忘了 TCP 53」的防火牆會有的故障樣貌:小查詢都成功,DNSSEC 簽章或記錄很多的大答案就失敗,而且整件事看起來毫無規律,直到你注意到是哪些名稱會壞。 |
REFUSED status in a dig answer, or ;; got answer with no records | 連接埠、網路和 daemon 全都沒問題——伺服器聽懂了你的查詢,然後拒絕回答。通常是你拿遞迴問題去問一台只做權威的伺服器,或是從它允許遞迴的清單以外的位址發問。網路那邊沒有東西要改,要改的是存取政策。 |
bind: Permission denied binding port 53 as a normal user | 連接埠 53 在 1024 以下,屬於特權連接埠,所以不管有沒有人在聽,核心都會用 EACCES 拒絕這次綁定。請透過服務管理員啟動解析器,在 Linux 上授予 `CAP_NET_BIND_SERVICE`,或是用高位連接埠測試,例如 `dig -p 5300 @127.0.0.1`。 |
IANA 把 53 指派給 `domain`,TCP 和 UDP 都有,而且兩邊都真的在用。一般查詢走 UDP,因為一次查詢來回各一個小封包,建立連線的成本比答案本身還貴。TCP 存在是為了 UDP 服務不了的情況:RFC 1035 規定「以 UDP 承載的訊息限制在 512 位元組」,塞不下的回應會被截斷並設上 TC 位元,用戶端接著用 TCP 重問一次。EDNS(0)(RFC 6891)讓用戶端宣告更大的 UDP 緩衝區,把多數大答案留在 UDP 上,但 RFC 7766 把 TCP 支援訂成必要條件而不是選配的後備——一台只在 UDP 上碰得到的解析器是壞的,不只是能力有限。區域轉送(AXFR)一律走 TCP。加密的 DNS 完全不住在這裡:DNS over TLS 是 RFC 7858 登記為 `domain-s` 的 853,DNS over HTTPS 則搭在 443 上。印表機和 AirPlay 用來解析 `.local` 的多點傳播 DNS 是 5353(RFC 6762),所以輸出裡的 `5353` 那一行不是你的解析器。本機最常見的衝突來源是 systemd-resolved,它的手冊寫明 stub 監聽者占用「IPv4 位址 127.0.0.53 與 127.0.0.54 上的連接埠 53」,UDP 和 TCP 都算。這就是為什麼在原廠 Ubuntu 上,dnsmasq、Pi-hole、CoreDNS 和 BIND 全都起不來,除非你在 `/etc/systemd/resolved.conf` 裡設 `DNSStubListener=no`。在 Docker 容器裡,解析器又是另一個位址:`127.0.0.11`。
權威伺服器必須讓人碰得到;遞迴解析器則絕對不行。一台會替整個網際網路回答遞迴查詢的解析器就是一把反射與放大的武器:攻擊者送一個小查詢、把來源位址偽造成受害者,你的伺服器就把大得多的答案寄到受害者那裡。RFC 5358(BCP 140)存在的目的就是告訴維運者不要留下開放的遞迴名稱伺服器,而開放解析器一出現,幾個小時內就會被持續進行的全網掃描找到。把遞迴限制在你自己的位址範圍內,並且讓權威和遞迴兩種角色分別跑在不同伺服器上,權威那台才能對全世界回答而不必替他們遞迴。AXFR 也要限制在你宣告的次要伺服器上——不設限的區域轉送等於一次請求就把你完整的內部命名地圖、主機名稱,常常還包括網路拓撲,全部交出去。回應要做流量限制,並且記得 UDP 是無連線的,查詢裡的來源位址偽造起來毫不費力,所以任何建立在來源位址上的存取控制都比看起來脆弱。不要開了 UDP 53 就忘記 TCP 53:只放 UDP 而擋 TCP,解析會一路正常,直到某個答案超過 UDP 緩衝區才失敗,而且失敗得斷斷續續,看起來毫無規律。
這些全都在你的瀏覽器裡跑,不會上傳任何東西。
查 53 的時候,通常也會順手看一下這幾個。
幾乎都是權限問題。lsof 和 ss 會列出 socket,但別人的行程它不會顯示所有者,所以由系統帳號、容器執行環境或 launchd 啟動的服務,在你補上 sudo 之前就只是一個沒有主人的監聽項。Windows 則是反過來:netstat 什麼都沒有,綁定卻還是失敗,那代表這個號碼落在 Hyper-V、WSL2 或 Docker Desktop 開機時預留的範圍裡。
先看清楚它是什麼。沒收乾淨的開發伺服器砍掉沒事;正在寫入的資料庫不行,其他東西依賴的系統服務也不行。如果持有者是容器,請停容器,不要砍主機看到的那個行程——砍了執行環境只會把它拉起來。遇到真的不能動的,把自己的服務換一個連接埠反而更快。
因為它綁在 127.0.0.1 而不是 0.0.0.0。每一頁的指令之所以會把綁定位址跟行程名一起印出來,就是為了這件事:綁在回送位址上的服務,不管防火牆怎麼設,都只有這台機器自己連得到。現在不少框架是刻意這樣預設的,所以通常是一個參數的問題,不是 bug。如果已經是 0.0.0.0 還是不通,下一個要懷疑的就是主機防火牆或雲端的安全群組。
幾乎沒有幫助。掃全網的機器持續在掃整段範圍,換號碼買到的是幾個小時,不是安全,代價卻是每個同事都得記住它。它確實能讓針對預設埠的無差別掃描少污染一點日誌,這算是實際但有限的好處。真正會改變結果的是認證、限制來源位址的防火牆,以及一開始就不要讓它對外。
連接埠 53 還是卡住嗎?看完整的連接埠對照表,或是回到上面,從你實際看到的那行錯誤往回追。