Linux DNS 查询剖析(第三部分)

Linux DNS 查询剖析(第三部分)

Linux DNS 查询剖析(第一部分)中,我们介绍了:

  • nsswitch
  • /etc/hosts
  • /etc/resolv.conf
  • pinghost 查询方式的对比

而在 Linux DNS 查询剖析(第二部分),我们介绍了:

  • systemd 和对应的 networking 服务
  • ifupifdown
  • dhclient
  • resolvconf

剖析进展如下:

linux-dns-2 (2)

(大致)准确的关系图

很可惜,故事还没有结束,还有不少东西也会影响 DNS 查询。在第三部分中,我将介绍 NetworkManagerdnsmasq,简要说明它们如何影响 DNS 查询。

1) NetworkManager

在第二部分已经提到,我们现在介绍的内容已经偏离 POSIX 标准,涉及的 DNS 解析管理部分在各个发行版上形式并不统一。

在我使用的发行版 (Ubuntu)中,有一个名为 NetworkManager 可用 available 服务,它通常作为一些其它软件包的依赖被安装。它实际上是 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 收到的查询、查询被转发到了哪里以及收到的回复。

如果查询被缓存命中(或者说,本地的查询结果还在 存活时间 time-to-live 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 可知,4 代表 IPV46 代表 IPV6C 代表 CNAMES 代表 DNSSECF 代表 FORWARDR 代表 REVERSEI 代表 IMMORTALN 代表 NEGX 代表 NXDOMAINH 代表 HOSTS。更具体的含义需要查看代码或相关文档)

dnsmasq 的替代品

NetworkManager 配置中的 dns 字段并不是只能使用 dnsmasq,可选项包括 nonedefaultunbounddnssec-triggered 等。使用 none 时,NetworkManager 不会改动 /etc/resolv.conf;使用 default 时,NetworkManager 会根据当前的 活跃连接 active connections 更新 resolv.conf;使用 unbound 时,NetworkManager 会与 unbound 服务通信;dnssec-triggered 与 DNS 安全相关,不在本文讨论范围。

第三部分总结

第三部分到此结束,其中我们介绍了 NetworkManager 服务及其 dns=dnsmasq 的配置。

下面简要罗列一下我们已经介绍过的全部内容:

  • nsswitch
  • /etc/hosts
  • /etc/resolv.conf
  • /run/resolvconf/resolv.conf
  • systemd 及对应的 networking 服务
  • ifupifdown
  • dhclient
  • resolvconf
  • NetworkManager
  • dnsmasq

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

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

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