TranslateProject/published/201809/20180706 Anatomy of a Linux DNS Lookup - Part III.md
2018-10-01 21:23:21 +08:00

288 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Linux DNS 查询剖析(第三部分)
============================================================
在 [Linux DNS 查询剖析(第一部分)][1]中,我们介绍了:
* `nsswitch`
* `/etc/hosts`
* `/etc/resolv.conf`
* `ping` 与 `host` 查询方式的对比
而在 [Linux DNS 查询剖析(第二部分)][2],我们介绍了:
* `systemd` 和对应的 `networking` 服务
* `ifup` 和 `ifdown`
* `dhclient`
* `resolvconf`
剖析进展如下:
![linux-dns-2 (2)][4]
_大致准确的关系图_
很可惜,故事还没有结束,还有不少东西也会影响 DNS 查询。在第三部分中,我将介绍 `NetworkManager``dnsmasq`,简要说明它们如何影响 DNS 查询。
### 1) NetworkManager
在第二部分已经提到,我们现在介绍的内容已经偏离 POSIX 标准,涉及的 DNS 解析管理部分在各个发行版上形式并不统一。
在我使用的发行版 Ubuntu有一个名为 [NetworkManager][3] 的<ruby>可用<rt>available</rt></ruby>服务,它通常作为一些其它软件包的依赖被安装。它实际上是 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` 收到的查询、查询被转发到了哪里以及收到的回复。
如果查询被缓存命中(或者说,本地的查询结果还在<ruby>存活时间<rt>time-to-live</rt></ruby> 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`][5] 可知,`4` 代表 `IPV4``6` 代表 `IPV6``C` 代表 `CNAME``S` 代表 `DNSSEC``F` 代表 `FORWARD``R` 代表 `REVERSE``I` 代表 `IMMORTAL``N` 代表 `NEG``X` 代表 `NXDOMAIN``H` 代表 `HOSTS`。更具体的含义需要查看代码或相关文档)
#### dnsmasq 的替代品
`NetworkManager` 配置中的 `dns` 字段并不是只能使用 `dnsmasq`,可选项包括 `none``default``unbound` 和 `dnssec-triggered` 等。使用 `none` 时,`NetworkManager` 不会改动 `/etc/resolv.conf`;使用 `default` 时,`NetworkManager` 会根据当前的<ruby>活跃连接<rt>active connections</rt></ruby>更新 `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][a]
译者:[pinewall](https://github.com/pinewall)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://zwischenzugs.com/
[1]:https://linux.cn/article-9943-1.html
[2]:https://linux.cn/article-9949-1.html
[3]:https://en.wikipedia.org/wiki/NetworkManager
[4]:https://zwischenzugs.files.wordpress.com/2018/06/linux-dns-2-2.png?w=525
[5]:https://github.com/imp/dnsmasq/blob/master/src/cache.c