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

if updating is enabled.

(增加或覆蓋 IFACE.PROG 記錄,如果開啟更新選項,則運行更新腳本)

故而也許我們可以直接調用該命令增加 namserver:

echo 'nameserver 10.10.10.10' | /sbin/resolvconf -a enp0s8.inet

測試表明確實可以!

$ cat /etc/resolv.conf | grep nameserver

nameserver 10.0.2.3

nameserver 10.10.10.10

是否已經找到答案,這就是 /etc/resolv.conf 更新的邏輯?調用 resolvconf 將 nameserver 添加到某個地方的數據庫,然後(“如果配置了更新”,先不管具體什麼含義)更新 resolv.conf 文件。

並非如此。

$ systemctl restart networking

root@linuxdns1:/etc# 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.3

search home

呃!(網絡服務重啟後)新增的 nameserver 再次消失了。

可見,systemctl restart networking 不僅僅運行了 resolvconf,還在其它地方獲取 nameserver 信息。具體是哪裡呢?

3) ifup/ifdown

繼續深入研究 systemctl restart networking,發現它完成了一系列工作:

cat /lib/systemd/system/networking.service

[...]

[Service]

Type=oneshot

EnvironmentFile=-/etc/default/networking

ExecStartPre=-/bin/sh -c '[ "$CONFIGURE_INTERFACES" != "no" ] && [ -n "$(ifquery --read-environment --list --exclude=lo)" ] && udevadm settle'

ExecStart=/sbin/ifup -a --read-environment

ExecStop=/sbin/ifdown -a --read-environment --exclude=lo

[...]

首先,網絡服務的重啟實質是運行一個 單觸發(oneshot)的腳本,腳本包含如下命令:

/sbin/ifdown -a --read-environment --exclude=lo

/bin/sh -c '[ "$CONFIGURE_INTERFACES" != "no" ] && [ -n "$(ifquery --read-environment --list --exclude=lo)" ] && udevadm settle'

/sbin/ifup -a --read-environment

第一行使用 ifdown 關閉全部的網絡接口,但 本地迴環(local, lo)接口除外。 2

(LCTT 譯註:其實這是因為很快就又啟動了接口,間隔的時間沒有超過 TCP 連接的超時時間,有人在評論中也做了類似回覆)

第二行用於確認系統已經完成關閉網絡接口相關的全部工作,以便下一步使用 ifup 啟動接口。這也讓我們瞭解到,網絡服務實質運行的就是 ifdown 和 ifup。

文檔中沒有找到 --read-environment 參數的說明,該參數為 systemctl 正常工作所需。很多人以文檔不完善為由不喜歡 systemctl。

很好。那麼 ifup (和其成對出現的 ifdown) 到底做了哪些工作呢?長話短說,它運行了 /etc/network/if-pre-up.d/ 和 /etc/network/if-up.d/ 目錄下的全部腳本;期間,這些腳本也可能會調用另外的腳本,依此類推。

其中一件工作就是運行了 dhclient,但我還不完全確定具體的機理,也許 udev 參與其中。

4) dhclient

dhclient 是一個程序,用於與 DHCP 服務器協商對應網絡接口應該使用的 IP 地址的詳細信息。同時,它也可以獲取可用的 DNS 服務器並將其替換到 /etc/resolv.conf 中。

讓我們開始跟蹤並模擬它的行為,但僅在我實驗虛擬機的 enp0s3 接口上。事先已經刪除 /etc/resolv.conf 文件中的 nameserver 配置:

$ sed -i '/nameserver.*/d' /run/resolvconf/resolv.conf

$ cat /etc/resolv.conf | grep nameserver

$ dhclient -r enp0s3 && dhclient -v enp0s3

Killed old client process

Internet Systems Consortium DHCP Client 4.3.3

Copyright 2004-2015 Internet Systems Consortium.

All rights reserved.

For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/enp0s8/08:00:27:1c:85:19

Sending on LPF/enp0s8/08:00:27:1c:85:19

Sending on Socket/fallback

DHCPDISCOVER on enp0s8 to 255.255.255.255 port 67 interval 3 (xid=0xf2f2513e)

DHCPREQUEST of 172.28.128.3 on enp0s8 to 255.255.255.255 port 67 (xid=0x3e51f2f2)

DHCPOFFER of 172.28.128.3 from 172.28.128.2

DHCPACK of 172.28.128.3 from 172.28.128.2

bound to 172.28.128.3 -- renewal in 519 seconds.

$ cat /etc/resolv.conf | grep nameserver

nameserver 10.0.2.3

可見這就是 nameserver 的來源。

但稍等一下,命令中的 /run/resolvconf/resolv.conf 是哪個文件,不應該是 /etc/resolv.conf 嗎?

事實上,/etc/resolv.conf 並不一定只是一個普通文本文件。

在我的虛擬機上,它是一個軟鏈接,指向位於 /run/resolvconf 目錄下的“真實文件”。這也暗示了我們,該文件是在系統啟動時生成的;同時,這也是該文件註釋告訴我們不要直接修改該文件的原因。

(LCTT 譯註:在 CentOS 7 中,沒有 resolvconf 命令,/etc/resolv.conf 也不是軟鏈接)

假如上面命令中 sed 命令直接處理 /etc/resolv.conf 文件,效果是不同的,會有警告消息告知待操作的文件不能是軟鏈接(sed -i 無法很好的處理軟鏈接,它只會創建一個新文件)。

(LCTT 譯註:CentOS 7 測試時,sed -i 命令操作軟鏈接並沒有警告,但確實創建了新文件取代軟鏈接)

如果你繼續深入查看配置文件 /etc/dhcp/dhclient.conf 的 supersede 部分,你會發現 dhclient 可以覆蓋 DHCP 提供的 DNS 服務器。

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

(大致)準確的關係圖


第二部分的結束語

第二部分到此結束。信不信由你,這是一個某種程度上簡化的流程版本,但我儘量保留重要和值得了解的部分,讓你不會感到無趣。大部分內容都是圍繞實際腳本的運行展開的。

但我們的工作還沒有結束,在第三部分,我們會介紹這些之上的更多層次。

讓我們簡要列出我們已經介紹過的內容:

  • nsswitch
  • /etc/hosts
  • /etc/resolv.conf
  • /run/resolvconf/resolv.conf
  • systemd 和網絡服務
  • ifup 和 ifdown
  • dhclient
  • resolvconf

  1. 事實上,這是相對於 POSIX 標準的,故不限於 Linux (我從上一篇文章的一條極好的 回覆 中瞭解到這一點) ↩
  2. 我不明白為何這沒有導致我例子中的 vagrant 會話中斷 (有誰明白嗎?)。 ↩

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

校對: wxy

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


分享到:


相關文章: