Linux DNS 查询剖析(第一部分)
创始人
2024-03-01 23:56:23
0

我经常与虚拟机集群打交道(文1文2文3文4文5文6),因此最终花费了大量时间试图掌握 DNS 查询的工作原理。遇到问题时,我只是不求甚解的使用 StackOverflow 上的“解决方案”,而不知道它们为什么有时工作,有时不工作。

最终我对此感到了厌倦,决定一并找出所有问题的原因。我没有在网上找到完整的指南,我问过一些同事,他们不知所以然(或许是问题太具体了)。

既然如此,我开始自己写这样的手册。

结果发现,“Linux 执行一次 DNS 查询”这句话的背后有相当多的工作。

linux-dns-0

“究竟有多难呢?”

**本系列文章试图将 Linux 主机上程序获取(域名对应的) IP 地址的过程及期间涉及的组件进行分块剖析。**如果不理解这些块的协同工作方式,调试解决 dnsmasqvagrant landrushresolvconf 等相关的问题会让人感到眼花缭乱。

同时这也是一份有价值的说明,指出原本很简单的东西是如何随着时间的推移变得相当复杂。在弄清楚 DNS 查询的原理的过程中,我了解了大量不同的技术及其发展历程。

我甚至编写了一些自动化脚本,可以让我在虚拟机中进行实验。欢迎读者参与贡献或勘误。

请注意,本系列主题并不是“DNS 工作原理”,而是与查询 Linux 主机配置的真实 DNS 服务器(这里假设查询了一台 DNS 服务器,但后面你会看到有时并不需要)相关的内容,以及如何确定使用哪个查询结果,或者如何使用其它方式确定 IP 地址。

1) 其实并没有名为“DNS 查询”的系统调用

工作方式并非如此

首先要了解的一点是,Linux 上并没有一个单独的方法可以完成 DNS 查询工作;没有一个有这样的明确接口的核心 系统调用 system call 。

不过,有一个标准 C 库函数调用 getaddrinfo,不少程序使用了该调用;但不是所有程序或应用都使用该调用!

让我们看一下两个简单的标准程序:pinghost

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

对于同一个域名,两个程序得到的 IP 地址是相同的;那么它们是使用同样的方法得到结果的吧?

事实并非如此。

下面文件给出了我主机上 ping 对应的 DNS 相关的系统调用:

root@linuxdns1:~# strace -e trace=open -f ping -c1 google.com
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libcap.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 4
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 4
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 4
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
open("/lib/x86_64-linux-gnu/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 4
open("/etc/host.conf", O_RDONLY|O_CLOEXEC) = 4
open("/etc/hosts", O_RDONLY|O_CLOEXEC)  = 4
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
open("/lib/x86_64-linux-gnu/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = 4
open("/lib/x86_64-linux-gnu/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 4
PING google.com (216.58.204.46) 56(84) bytes of data.
open("/etc/hosts", O_RDONLY|O_CLOEXEC)  = 4
64 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) = 6
google.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:         compat
group:          compat
shadow:         compat
gshadow:        files
hosts: files dns myhostname
networks:       files
protocols:      db files
services:       db files
ethers:         db files
rpc:            db files
netgroup:       nis

我们需要关注的是 hosts 行。我们知道 ping 用到 nsswitch.conf 文件,那么我们修改这个文件(的 hosts 行),看看能够如何影响 ping

修改 nsswitch.confhosts 行仅保留 files

如果你修改 nsswitch.conf,将 hosts 行仅保留 files

hosts: files

此时, ping 无法获取 google.com 对应的 IP 地址:

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

localhost 的解析不受影响:

$ ping -c1 localhost
PING 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.com
google.com has address 216.58.206.110

毕竟如我们之前看到的那样,host 不受 nsswitch.conf 影响。

修改 nsswitch.confhosts 行仅保留 dns

如果你修改 nsswitch.conf,将 hosts 行仅保留 dns

hosts: dns

此时,google.com 的解析恢复正常:

$ ping -c1 google.com
PING 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 localhost
ping: unknown host localhost

下图给出默认 NSSwitch 中 hosts 行对应的查询逻辑:

linux-dns-2 (1)

我的 hosts: 配置是 nsswitch.conf 给出的默认值

3) /etc/resolv.conf

我们已经知道 hostping 都使用 /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 OVERWRITTEN
nameserver 10.0.2.3

先忽略前两行,后面我们会回过头来看这部分(它们很重要,但你还需要一些知识储备)。

其中 nameserver 行指定了查询用到的 DNS 服务器。

如果将该行注释掉:

#nameserver 10.0.2.3

再次运行:

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

解析失败了,这是因为没有可用的名字服务器 2 。

该文件中还可以使用其它选项。例如,你可以在 resolv.conf 文件中增加如下行:

search com

然后执行 ping google (不写 .com

$ ping google
PING 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 服务器执行查询

如果你曾认为 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/

作者:ZWISCHENZUGS 译者:pinewall 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

DNS

相关内容

DNS、ICMP协议、NA...
目录 DNS 使用dig工具分析DNS过程  当在浏览器输入ur...
2025-06-01 17:57:52
【sqlmap渗透进阶】D...
目录 注入说明 利用条件 注意事项 源码分析 DNS-domain...
2025-05-30 07:54:44
Chrome 浏览器获取网...
解析阶段详细流程说明 步骤说明①浏览器输入:http...
2025-05-28 07:01:35
如何在CentOS系统上部...
作为Linux系统中广泛使用的DNS服务软件,BIND(Berke...
2025-05-25 13:47:28
Linux系统下如何调整D...
文章标题:域名解析记录变更时,TTL值调整的重要性及其对DNS缓存...
2025-04-18 22:46:29
不同命名空间中Kubern...
在Kubernetes中,不同命名空间中服务的DNS名称的格式是 ...
2025-01-09 11:31:18

热门资讯

Helix:高级 Linux ... 说到 基于终端的文本编辑器,通常 Vim、Emacs 和 Nano 受到了关注。这并不意味着没有其他...
使用 KRAWL 扫描 Kub... 用 KRAWL 脚本来识别 Kubernetes Pod 和容器中的错误。当你使用 Kubernet...
JStock:Linux 上不... 如果你在股票市场做投资,那么你可能非常清楚投资组合管理计划有多重要。管理投资组合的目标是依据你能承受...
Epic 游戏商店现在可在 S... 现在可以在 Steam Deck 上运行 Epic 游戏商店了,几乎无懈可击! 但是,它是非官方的。...
《Apex 英雄》正式可在 S... 《Apex 英雄》现已通过 Steam Deck 验证,这使其成为支持 Linux 的顶级多人游戏之...
从 Yum 更新中排除特定/某... 作为系统更新的一部分,你也许需要在基于 Red Hat 系统中由于应用依赖排除一些软件包。如果是,如...
通过 SaltStack 管理... 我在搜索Puppet的替代品时,偶然间碰到了Salt。我喜欢puppet,但是我又爱上Salt了:)...
如何在 Github 上创建一... 学习如何复刻一个仓库,进行更改,并要求维护人员审查并合并它。你知道如何使用 git 了,你有一个 G...
Opera 浏览器内置的 VP... 昨天我们报道过 Opera 浏览器内置了 VPN 服务,用户打开它可以防止他们的在线活动被窥视。不过...
如何检查你的 Linux 系统... 不知道在使用哪个初始化系统?以下是方法。每个主流 Linux 发行版(包括 Ubuntu、Fedor...