mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
288 lines
11 KiB
Markdown
288 lines
11 KiB
Markdown
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
|