Linux DNS 查詢剖析(第三部分)

Zwischenzugs發表於2018-09-01

Linux DNS 查詢剖析(第三部分)

在 Linux DNS 查詢剖析(第一部分)中,我們介紹了:

  • nsswitch
  • /etc/hosts
  • /etc/resolv.conf
  • ping 與 host 查詢方式的對比

而在 Linux DNS 查詢剖析(第二部分),我們介紹了:

  • systemd 和對應的 networking 服務
  • ifup 和 ifdown
  • dhclient
  • resolvconf

剖析進展如下:

linux-dns-2 (2)

(大致)準確的關係圖

很可惜,故事還沒有結束,還有不少東西也會影響 DNS 查詢。在第三部分中,我將介紹 NetworkManagerdnsmasq,簡要說明它們如何影響 DNS 查詢。

1) NetworkManager

在第二部分已經提到,我們現在介紹的內容已經偏離 POSIX 標準,涉及的 DNS 解析管理部分在各個發行版上形式並不統一。

在我使用的發行版 (Ubuntu)中,有一個名為 NetworkManager可用available服務,它通常作為一些其它軟體包的依賴被安裝。它實際上是 RedHat 在 2004 年開發的一個服務,用於幫助你管理網路介面。

它與 DNS 查詢有什麼關係呢?讓我們安裝這個服務並找出答案:

$ apt-get install -y network-manager

對於 Ubuntu,在軟體包安裝後,你可以發現一個新的配置檔案:

$ cat /etc/NetworkManager/NetworkManager.conf
[main]
plugins=ifupdown,keyfile,ofono
dns=dnsmasq

[ifupdown]
managed=false

看到 dns=dnsmasq 了吧?這意味著 NetworkManager 將使用 dnsmasq 管理主機上的 DNS。

2) dnsmasq

dnsmasq 程式是我們很熟悉的程式:只是 /etc/resolv.conf 之上的又一個間接層。

理論上,dnsmasq 有多種用途,但主要被用作 DNS 快取伺服器,快取到其它 DNS 伺服器的請求。dnsmasq 在本地所有網路介面上監聽 53 埠(標準的 DNS 埠)。

那麼 dnsmasq 執行在哪裡呢?NetworkManager 的執行情況如下:

$ ps -ef | grep NetworkManager
root     15048     1  0 16:39 ?        00:00:00 /usr/sbin/NetworkManager --no-daemon

但並沒有找到 dnsmasq 相關的程式:

$ ps -ef | grep dnsmasq
$

令人迷惑的是,雖然 dnsmasq 被配置用於管理 DNS,但其實並沒有安裝在系統上!因而,你需要自己安裝它。

安裝之前,讓我們檢視一下 /etc/resolv.conf 檔案的內容:

$ cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 10.0.2.2
search home

可見,並沒有被 NetworkManager 修改。

如果安裝 dnsmasq

$ apt-get install -y dnsmasq

然後啟動執行 dnsmasq

$ ps -ef | grep dnsmasq
dnsmasq  15286     1  0 16:54 ?        00:00:00 /usr/sbin/dnsmasq -x /var/run/dnsmasq/dnsmasq.pid -u dnsmasq -r /var/run/dnsmasq/resolv.conf -7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new --local-service --trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5

然後,/etc/resolv.conf 檔案內容又改變了!

root@linuxdns1:~# cat /etc/resolv.conf 
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 127.0.0.1
search home

執行 netstat 命令,可以看出 dnsmasq 在所有網路介面上監聽 53 埠:

$ netstat -nlp4
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address     Foreign Address State   PID/Program name
tcp        0      0 127.0.0.1:53      0.0.0.0:*       LISTEN  15286/dnsmasq 
tcp        0      0 10.0.2.15:53      0.0.0.0:*       LISTEN  15286/dnsmasq
tcp        0      0 172.28.128.11:53  0.0.0.0:*       LISTEN  15286/dnsmasq
tcp        0      0 0.0.0.0:22        0.0.0.0:*       LISTEN  1237/sshd
udp        0      0 127.0.0.1:53      0.0.0.0:*               15286/dnsmasq
udp        0      0 10.0.2.15:53      0.0.0.0:*               15286/dnsmasq  
udp        0      0 172.28.128.11:53  0.0.0.0:*               15286/dnsmasq  
udp        0      0 0.0.0.0:68        0.0.0.0:*               10758/dhclient
udp        0      0 0.0.0.0:68        0.0.0.0:*               10530/dhclient
udp        0      0 0.0.0.0:68        0.0.0.0:*               10185/dhclient

3) 分析 dnsmasq

在目前的情況下,所有的 DNS 查詢都會使用 127.0.0.1:53 這個 DNS 伺服器,下一步會發生什麼呢?

我再次檢視 /var/run 目錄,可以發現一個線索:resolvconf 目錄下 resolv.conf 檔案中的配置也相應變更,變更為 dnsmasq 對應的 DNS 伺服器:

$ cat /var/run/resolvconf/resolv.conf 
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 127.0.0.1
search home

同時,出現了一個新的 dnsmasq 目錄,也包含一個 resolv.conf 檔案:

$ cat /run/dnsmasq/resolv.conf
nameserver 10.0.2.2

(LCTT 譯註:這裡依次提到了 /var/run/run,使用 Ubuntu 16.04 LTS 驗證發現,/var/run 其實是指向 /run/ 的軟連結)

該檔案包含我們從 DHCP 獲取的 nameserver

雖然可以推匯出這個結論,但如何檢視具體的呼叫邏輯呢?

4) 除錯 dnsmasq

我經常思考 dnsmasq (在整個過程中)的功能定位。幸運的是,如果你將 /etc/dnsmasq.conf 中的一行做如下調整,你可以獲取大量 dnsmasq 狀態的資訊:

#log-queries

修改為:

log-queries

然後重啟 dnsmasq

接下來,只要執行一個簡單的命令:

$ ping -c1 bbc.co.uk

你就可以在 /var/log/syslog 中找到類似的內容(其中 [...] 表示行首內容與上一行相同):

Jul  3 19:56:07 ubuntu-xenial dnsmasq[15372]: query[A] bbc.co.uk from 127.0.0.1
[...] forwarded bbc.co.uk to 10.0.2.2
[...] reply bbc.co.uk is 151.101.192.81
[...] reply bbc.co.uk is 151.101.0.81
[...] reply bbc.co.uk is 151.101.64.81
[...] reply bbc.co.uk is 151.101.128.81
[...] query[PTR] 81.192.101.151.in-addr.arpa from 127.0.0.1
[...] forwarded 81.192.101.151.in-addr.arpa to 10.0.2.2
[...] reply 151.101.192.81 is NXDOMAIN

可以清晰看出 dnsmasq 收到的查詢、查詢被轉發到了哪裡以及收到的回覆。

如果查詢被快取命中(或者說,本地的查詢結果還在存活時間time-to-live TTL 內,並未過期),日誌顯示如下:

[...] query[A] bbc.co.uk from 127.0.0.1
[...] cached bbc.co.uk is 151.101.64.81
[...] cached bbc.co.uk is 151.101.128.81
[...] cached bbc.co.uk is 151.101.192.81
[...] cached bbc.co.uk is 151.101.0.81
[...] query[PTR] 81.64.101.151.in-addr.arpa from 127.0.0.1

如果你想了解快取中有哪些記錄,可以向 dnsmasq 程式 id 傳送 USR1 訊號,這樣 dnsmasq 會將快取記錄匯出並寫入到相同的日誌檔案中:

$ kill -SIGUSR1 $(cat /run/dnsmasq/dnsmasq.pid)

(LCTT 譯註:原文中命令執行報錯,已變更成最接近且符合作者意圖的命令)

匯出記錄對應如下輸出:

Jul  3 15:08:08 ubuntu-xenial dnsmasq[15697]: time 1530630488
[...] cache size 150, 0/5 cache insertions re-used unexpired cache entries.
[...] queries forwarded 2, queries answered locally 0
[...] queries for authoritative zones 0
[...] server 10.0.2.2#53: queries sent 2, retried or failed 0
[...] Host             Address         Flags      Expires
[...] linuxdns1        172.28.128.8    4FRI   H
[...] ip6-localhost    ::1             6FRI   H
[...] ip6-allhosts     ff02::3         6FRI   H
[...] ip6-localnet     fe00::          6FRI   H
[...] ip6-mcastprefix  ff00::          6FRI   H
[...] ip6-loopback     :               6F I   H
[...] ip6-allnodes     ff02:           6FRI   H
[...] bbc.co.uk        151.101.64.81   4F         Tue Jul  3 15:11:41 2018
[...] bbc.co.uk        151.101.192.81  4F         Tue Jul  3 15:11:41 2018
[...] bbc.co.uk        151.101.0.81    4F         Tue Jul  3 15:11:41 2018
[...] bbc.co.uk        151.101.128.81  4F         Tue Jul  3 15:11:41 2018
[...]                  151.101.64.81   4 R  NX    Tue Jul  3 15:34:17 2018
[...] localhost        127.0.0.1       4FRI   H
[...] <Root>           19036   8   2   SF I
[...] ip6-allrouters   ff02::2         6FRI   H

在上面的輸出中,我猜測(並不確認,? 代表我比較無根據的猜測)如下:

  • 4 代表 IPv4
  • 6 代表 IPv6
  • H 代表從 /etc/hosts 中讀取 IP 地址
  • I ? “永生”的 DNS 記錄 ? (例如,沒有設定存活時間數值 ?)
  • F
  • R
  • S
  • N
  • X

(LCTT 譯註:檢視 dnsmasq 的原始碼 cache.c 可知,4 代表 IPV46 代表 IPV6C 代表 CNAMES 代表 DNSSECF 代表 FORWARDR 代表 REVERSEI 代表 IMMORTALN 代表 NEGX 代表 NXDOMAINH 代表 HOSTS。更具體的含義需要檢視程式碼或相關文件)

dnsmasq 的替代品

NetworkManager 配置中的 dns 欄位並不是只能使用 dnsmasq,可選項包括 nonedefaultunbounddnssec-triggered 等。使用 none 時,NetworkManager 不會改動 /etc/resolv.conf;使用 default 時,NetworkManager 會根據當前的活躍連線active connections更新 resolv.conf;使用 unbound 時,NetworkManager 會與 unbound 服務通訊;dnssec-triggered 與 DNS 安全相關,不在本文討論範圍。

第三部分總結

第三部分到此結束,其中我們介紹了 NetworkManager 服務及其 dns=dnsmasq 的配置。

下面簡要羅列一下我們已經介紹過的全部內容:

  • nsswitch
  • /etc/hosts
  • /etc/resolv.conf
  • /run/resolvconf/resolv.conf
  • systemd 及對應的 networking 服務
  • ifup 和 ifdown
  • dhclient
  • resolvconf
  • NetworkManager
  • dnsmasq

via: https://zwischenzugs.com/2018/07/06/anatomy-of-a-linux-dns-lookup-part-iii/

作者:ZWISCHENZUGS 譯者:pinewall 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出

相關文章