Linux DNS 查詢剖析(第一部分) | Linux 中國

2021-03-02 Linux中國

我經常與虛擬機集群打交道(文1[1]、文2[2]、文3[3]、文4[4]、文5[5]、文6[6]),因此最終花費了大量時間試圖掌握 DNS 查詢[7]的工作原理。遇到問題時,我只是不求甚解的使用 StackOverflow 上的「解決方案」,而不知道它們為什麼有時工作,有時不工作。

最終我對此感到了厭倦,決定一併找出所有問題的原因。我沒有在網上找到完整的指南,我問過一些同事,他們不知所以然(或許是問題太具體了)。

既然如此,我開始自己寫這樣的手冊。

結果發現,「Linux 執行一次 DNS 查詢」這句話的背後有相當多的工作。

「究竟有多難呢?」

本系列文章試圖將 Linux 主機上程序獲取(域名對應的) IP 地址的過程及期間涉及的組件進行分塊剖析。如果不理解這些塊的協同工作方式,調試解決 dnsmasq、vagrant landrush和 resolvconf 等相關的問題會讓人感到眼花繚亂。

同時這也是一份有價值的說明,指出原本很簡單的東西是如何隨著時間的推移變得相當複雜。在弄清楚 DNS 查詢的原理的過程中,我了解了大量不同的技術及其發展歷程。

我甚至編寫了一些自動化腳本[8],可以讓我在虛擬機中進行實驗。歡迎讀者參與貢獻或勘誤。

請注意,本系列主題並不是「DNS 工作原理」,而是與查詢 Linux 主機配置的真實 DNS 伺服器(這裡假設查詢了一臺 DNS 伺服器,但後面你會看到有時並不需要)相關的內容,以及如何確定使用哪個查詢結果,或者如何使用其它方式確定 IP 地址。

1) 其實並沒有名為「DNS 查詢」的系統調用

工作方式並非如此

首先要了解的一點是,Linux 上並沒有一個單獨的方法可以完成 DNS 查詢工作;沒有一個有這樣的明確接口的核心系統調用system call。

不過,有一個標準 C 庫函數調用 getaddrinfo[9],不少程序使用了該調用;但不是所有程序或應用都使用該調用!

讓我們看一下兩個簡單的標準程序:ping 和 host:

root@linuxdns1:~# ping -c1 bbc.co.uk | head -1PING bbc.co.uk (151.101.192.81) 56(84) bytes of data.

root@linuxdns1:~# host bbc.co.uk | head -1bbc.co.uk has address 151.101.192.81

對於同一個域名,兩個程序得到的 IP 地址是相同的;那麼它們是使用同樣的方法得到結果的吧?

事實並非如此。

下面文件給出了我主機上 ping 對應的 DNS 相關的系統調用:

root@linuxdns1:~# strace -e trace=open -f ping -c1 google.comopen("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3open("/lib/x86_64-linux-gnu/libcap.so.2", O_RDONLY|O_CLOEXEC) = 3open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 4open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 4open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 4open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4open("/lib/x86_64-linux-gnu/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 4open("/etc/host.conf", O_RDONLY|O_CLOEXEC) = 4open("/etc/hosts", O_RDONLY|O_CLOEXEC)  = 4open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4open("/lib/x86_64-linux-gnu/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = 4open("/lib/x86_64-linux-gnu/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 4PING google.com (216.58.204.46) 56(84) bytes of data.open("/etc/hosts", O_RDONLY|O_CLOEXEC)  = 464 bytes from lhr25s12-in-f14.1e100.net (216.58.204.46): icmp_seq=1 ttl=63 time=13.0 ms[...]

下面是 host 對應的系統調用:

$ strace -e trace=open -f host google.com[...][pid  9869] open("/usr/share/locale/en_US.UTF-8/LC_MESSAGES/libdst.cat", O_RDONLY) = -1 ENOENT (No such file or directory)[pid  9869] open("/usr/share/locale/en/libdst.cat", O_RDONLY) = -1 ENOENT (No such file or directory)[pid  9869] open("/usr/share/locale/en/LC_MESSAGES/libdst.cat", O_RDONLY) = -1 ENOENT (No such file or directory)[pid  9869] open("/usr/lib/ssl/openssl.cnf", O_RDONLY) = 6[pid  9869] open("/usr/lib/x86_64-linux-gnu/openssl-1.0.0/engines/libgost.so", O_RDONLY|O_CLOEXEC) = 6[pid  9869] open("/etc/resolv.conf", O_RDONLY) = 6google.com has address 216.58.204.46[...]

可以看出 ping 打開了 nsswitch.conf 文件,但 host 沒有;但兩個程序都打開了 /etc/resolv.conf 文件。

下面我們依次查看這兩個 .conf 擴展名的文件。

2) NSSwitch 與 /etc/nsswitch.conf

我們已經確認應用可以自主決定選用哪個 DNS 伺服器。很多應用(例如 ping)通過配置文件 /etc/nsswitch.conf (根據具體實現1 )參考 NSSwitch 完成選擇。

NSSwitch 不僅用於 DNS 查詢,例如,還用於密碼與用戶信息查詢。

NSSwitch 最初是 Solaris OS 的一部分,可以讓應用無需硬編碼查詢所需的文件或服務,而是在其它集中式的、無需應用開發人員管理的配置文件中找到。

下面是我的 nsswitch.conf:

passwd:         compatgroup:          compatshadow:         compatgshadow:        fileshosts: files dns myhostnamenetworks:       filesprotocols:      db filesservices:       db filesethers:         db filesrpc:            db filesnetgroup:       nis

我們需要關注的是 hosts 行。我們知道 ping 用到 nsswitch.conf 文件,那麼我們修改這個文件(的 hosts 行),看看能夠如何影響 ping。

修改 nsswitch.conf, hosts 行僅保留 files

如果你修改 nsswitch.conf,將 hosts 行僅保留 files:

hosts: files

此時, ping 無法獲取 google.com 對應的 IP 地址:

$ ping -c1 google.comping: unknown host google.com

但 localhost 的解析不受影響:

$ ping -c1 localhostPING localhost (127.0.0.1) 56(84) bytes of data.64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.039 ms

此外,host 命令正常返回:

$ host google.comgoogle.com has address 216.58.206.110

畢竟如我們之前看到的那樣,host 不受 nsswitch.conf 影響。

修改 nsswitch.conf, hosts 行僅保留 dns

如果你修改 nsswitch.conf,將 hosts 行僅保留 dns:

hosts: dns

此時,google.com 的解析恢復正常:

$ ping -c1 google.comPING google.com (216.58.198.174) 56(84) bytes of data.64 bytes from lhr25s10-in-f174.1e100.net (216.58.198.174): icmp_seq=1 ttl=63 time=8.01 ms

但 localhost 無法解析:

$ ping -c1 localhostping: unknown host localhost

下圖給出默認 NSSwitch 中 hosts 行對應的查詢邏輯:

我的 hosts: 配置是 nsswitch.conf 給出的默認值

3) /etc/resolv.conf

我們已經知道 host 和 ping 都使用 /etc/resolv.conf 文件。

下面給出我主機的 /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 OVERWRITTENnameserver 10.0.2.3

先忽略前兩行,後面我們會回過頭來看這部分(它們很重要,但你還需要一些知識儲備)。

其中 nameserver 行指定了查詢用到的 DNS 伺服器。

如果將該行注釋掉:

#nameserver 10.0.2.3

再次運行:

$ ping -c1 google.comping: unknown host google.com

解析失敗了,這是因為沒有可用的名字伺服器 2。

該文件中還可以使用其它選項。例如,你可以在 resolv.conf 文件中增加如下行:

search com

然後執行 ping google (不寫 .com)

$ ping googlePING google.com (216.58.204.14) 56(84) bytes of data.

程序會自動為你嘗試 .com 域。

第一部分總結

第一部分到此結束,下一部分我們會了解 resolv.conf 文件是如何創建和更新的。

下面總結第一部分涵蓋的內容:

◈ 作業系統中並不存在「DNS 查詢」這個系統調用◈ 不同程序可能採用不同的策略獲取名字對應的 IP 地址◈ 例如, ping 使用 nsswitch,後者進而使用(或可以使用) /etc/hosts、/etc/resolv.conf 以及主機名得到解析結果◈ /etc/resolv.conf 用於決定:◈ 查詢什麼地址(LCTT 譯註:這裡可能指 search 帶來的影響)

如果你曾認為 DNS 查詢很複雜,請跟隨這個系列學習吧。

1.ping 實現的變種之多令人驚嘆。我 不 希望在這裡討論過多。 ↩2. 另一個需要注意的地方: host 在沒有指定 nameserver 的情況下會嘗試 127.0.0.1:53。 ↩

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

作者:dmatech[11] 譯者:pinewall 校對:wxy

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

相關焦點

  • Linux文件的常用操作命令
    linux文件操作常用指令1、系統命令runlevel # 查看當前的運行級別systemctl status firewalld # 開啟網絡服務功能stop # 關閉restart # 重啟# 查看CPU基本信息cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l # 查看CPU個數3、查看內存kill_memory.sh # 編寫一個腳本消耗內存free -m # 查詢內存詳情
  • linux命令大全
    Linux命令大全之所以有存在的必要就是因為,linux作為非主流市場裡面的主流作業系統,不僅是免費的而且它還是一個非常優秀的作業系統,與MS-WINDOWS相比,可靠、 穩定、速度快。且擁有豐富的根據UNIX版本改進的強大功能。
  • linux下的DHCP伺服器的配置
    linux現在主要的應用在伺服器上。而作為伺服器,Web,dhcp,和dns又是網際網路上最主要的服務,這一講,我和朋友們討論dhcp的應用。
  • Linux就該這麼學:RHCE考試經驗分享
    二年前接觸linux, 一步步走來。自己的慢慢進入linux的世界。一點一滴積累,豐富武裝自己。以前自己知識面太窄了,越來越覺得有很多知識,自己聽都沒有聽過。實在慚愧啊!前一段時間,為了給自己的一個階段的總結。報考了紅帽的認證。
  • 在 Linux 下 9 個有用的 touch 命令示例 | Linux 中國
    如下所示:[root@linuxtechi ~]# touch devops.txt[root@linuxtechi ~]# ls -l devops.txt-rw-r--r--. 1 root root 0 Mar 29 22:39 devops.txt示例:2 使用 touch 創建批量空文件可能會出現一些情況
  • Linux Lab 發布 v0.6-rc2,新增首塊真實硬體開發板
    本次合計 64 筆變更:// linux lab$ git log --pretty=oneline v0.6-rc1..v0.6-rc2 | wc -l57// cloud lab$ git log --pretty=oneline v0.4-rc1..v0.4-rc2 | wc -l7本次主要更新如下:Cloud Lab
  • 走進Linux(下)——arch linux的安裝教程
    New走進Linux(下)——arch linux的安裝教程一、為什麼選擇arch Linux?相比Debian/Ubuntu、SUSE、RedHat/Fedora 等其他發行版, Arch Linux 屬於輕量級選手,其簡單的設計讓它容易被輕鬆擴展和配置成為任何想要的系統類型。
  • 深度好文:Linux文件系統剖析
    在註冊新的文件系統時,會把這個文件系統和它的相關信息添加到 file_systems 列表中(見圖 2 和 linux/ include/ linux/ mount.h)。這個列表定義可以支持的文件系統。在命令行上輸入 cat /proc/filesystems,就可以查看這個列表。圖 2. 向內核註冊的文件系統
  • Linux命令 ls 和 ll 的使用方法與基本區別
    1、查詢當前文件夾下的目錄文件[ljs@vm /]$ ls -F |grep "/$" #查詢當前目錄下的文件夾 [linuxidc@linuxidc /]$ ls -F |grep "/"  #查詢當前目錄下的文件夾
  • Manjaro Linux 17.1-rc3,基於 Arch Linux 的作業系統
    目前支持的內核:linux316 3.16.51linux318 3.18.90 [EOL]linux41 4.1.48linux44 4.4.108linux49 4.9.72linux412 4.12.14 [EOL]linux413 4.13.16 [EOL]linux414
  • Linux下diff的操作詳解
    diff命令可以同時輸出成補丁文件,並且Linux中還有一個patch命令,可以依據diff生成的.patch補丁文件,將a.c與b.c兩個文件差異部分更新到需要修改的文件。此外diff在SVN 、GIT、CVS等版本控制工具中也是不可獲取的一部分。
  • Linux常用命令:Linux more命令使用方法
    3.命令參數:linuxidc@linuxidc:~/桌面/Linux公社$ more --help用法: more [選項] <文件>...適合屏幕查看的文件閱讀輸出工具。linuxidc@linuxidc:~/桌面/Linux公社$ 實例逐頁顯示 linuxidc 文檔內容,如有連續兩行以上空白行則以一行空白行顯示。more -s linuxidc
  • Linux RCU原理剖析(一)-初窺門徑
    RCU基礎2.1 RCU基本要素RCU的基本思想是將更新Update操作分為兩個部分:1)Removal移除;2)Reclamation回收。直白點來理解就是,臨界資源被多個讀者讀取,寫者在拷貝副本修改後進行更新時,第一步需要先把舊的臨界資源數據移除(修改指針指向),第二步需要把舊的數據進行回收(比如kfree)。
  • linux學習
    link_name$ ln -s days my_days #一個名為mydays的符號連結指向文本文件days$ ls -l my_days...my_days -> days$ ln -s /usr/locak/share/ local_share$ ls -l local_share... local_share -> /usr/local/share/linux
  • Linux常用命令 - sed
    為了便於演示,我將使用以下文件 file.txt:123 Foo foo foo foo /bin/bash Ubuntu foobar 456如果省略了g 標誌,那麼每行中搜索字符串的第一個實例將被替換:sed -i '''s/foo/linux/' file.txt123 Foo linux foo linux /bin/bash Ubuntu foobar
  • Linux下C應用程式開發
    例如, 下面的兩個命令是不同的:    gcc -p -g test.c  gcc -pg test.c  第一條命令告訴 GCC 編譯 test.c 時為 prof 命令建立剖析(profile)信息並且把調試信息加入到可執行的文件裡. 第二條命令只告訴 GCC 為 gprof 命令建立剖析信息.
  • Linux下利用l7filter封殺迅雷、QQ、MSN
    -2.6.27.tar.gz# cd linux-2.6.27# patch -p1 < ..-2.6.27 /usr/src/linux#cp netfilter-layer7-v2.21/iptables-1.4.1.1-for-kernel-2.6.20forward/libxt_layer7.* iptables-1.4.1.1/extensions/# .
  • Linux系統從入門到放棄?
    Linux是一個命令行組成的作業系統,精髓在命令行,學習如何在Linux環境中執行linux命令,包括有關文件、目錄、文件系統、進程等概念,如何使用相應的命令對文件、目錄、進程等進行管理,了解遇到問題時,如何找到幫助信息等等。都將是我們學習入門Linux的第二大步。
  • Linux系統入門命令學習經驗
    此時此刻我想和大家分享一下我在學習linux過程中的一些經驗和教訓,如果有人能夠正好看到我的這篇文章,希望能夠讓想學習linux的同學多少獲得一點經驗,少走一些彎路。能夠比較簡單、快捷的迅速掌握知識是我們學習的目的,但是我們平常的學習中大部分都有一些人在指導。
  • Linux系統的Linux應該怎麼讀?正確讀法在這裡,很多人都讀錯了!
    1、linux發音五花八門版本頗多,見到和聽到的不下10種。根據linux的創始人Linus Torvalds的說法,Linux的發音和「Minix」是押韻的。3、有人綜合網上和linux自己的讀音,概括出幾個自認為最合適也最通用的讀法:/li'n^ks/(「裡那克斯」)或/'li:nэks/(「裡訥克斯」)或/li'nju:ks/(「裡紐克斯」)。4、這幾個應該是誰都聽得懂的。至於哪個比較正宗,當然是linux的原因。但事實上使用linux哪種讀法的人似乎都不在少數。