描述
systemd-resolved 为本地应用程序提供了网络名字解析服务。 它不但提供了传统的 DNS/DNSSEC 解析与本地缓存功能,还提供了 LLMNR 与 MulticastDNS 的解析 (resolver)与应答 (responder)的功能。
- 第一种,通过D-Bus总线上的本地全功能API systemd-resolved (详见 API Documentation)。 这是首选方法,因为它是异步的并且功能最全。 此种方式可以正确返回 DNSSEC 的有效状态,以及支持 link-local 网络所必需的地址的网口范围(interface scope)。
- 第二种,通过 glibc 的 getaddrinfo(3), gethostbyname(3) 等相关API(RFC3493)。 这些API受到了广泛的支持(包括非Linux平台)。此种方法不能检查 DNSSEC 的有效状态,并且是同步的。 此种方法由 glibc Name Service Switch (nss(5)) 支持。 必须使用 glibc NSS 模块 nss-resolve(8) 才能让 glibc NSS 使用 systemd-resolved 提供的名字解析功能。
- 第三种,通过 systemd-resolved 在本地回环网口 127.0.0.53 上提供的本地DNS服务器。 应用程序可以直接向 127.0.0.53 发送DNS请求,从而直接使用 systemd-resolved 提供的解析服务。 除非确实无法使用前面的 glibc NSS 或 D-Bus API 两种方法, 否则应该尽量避免使用此种方式, 因为无法将各种网络解析功能(例如 link-local 地址或 LLMNR Unicode 域名)全部映射到 单播DNS协议中。
DNS服务器来自于 全局配置文件(/etc/systemd/resolved.conf)、 针对单个连接的静态配置文件(/etc/systemd/network/*.network)(当使用 systemd-networkd.service(8) 管理网络时)、 针对单个连接的动态配置(从DHCP服务器、resolvectl(1)、其他系统服务得到的DNS服务器)。参见 resolved.conf(5) 与 systemd.network(5) 以了解 systemd 自身的DNS服务器配置。为了提高兼容性, 仅在 /etc/resolv.conf 不是一个 指向 /run/systemd/resolve/stub-resolv.conf, /usr/lib/systemd/resolv.conf, /run/systemd/resolve/resolv.conf 之一的软连接 的情况下,才会从 /etc/resolv.conf 读取 全局DNS服务器。
合成记录(Synthetic Record)
systemd-resolved 会为下列特殊域名合成DNS资源记录(RR):
- 本机的主机名将按如下规则解析: 如果配置了本机IP地址, 那么将被解析为所有本机IP地址(按范围排序)。 如果不存在本机IP地址, 那么将被解析为本地回环上的 127.0.0.2 与 ::1
- “localhost” 与 “localhost.localdomain” 以及所有以 “.localhost” 或 “.localhost.localdomain” 结尾的主机名, 都将被解析为 127.0.0.1 与 ::1
- “_gateway” 将被解析为所有当前路由表中的默认网关IP地址(按数字大小排序)。 通过给网关分配一个固定的名称, 方便了应用程序对网关地址的引用, 应用程序不再需要关心网络的具体配置。
在 /etc/hosts 中定义的映射关系(正向解析与反向解析)。 不过需要注意的是, 这些映射关系对非IP地址类解析(例如MX记录)无效。
协议与路由
在将查询请求路由到DNS服务器、LLMNR 与 MulticastDNS 接口时, 遵守下面的规则:
对 “localhost” 系列特殊域名的查询 永远不会路由到网络上去。
- 单标签主机名(不含”.”的主机名)使用LLMNR协议路由到所有支持IP多播的本地接口。 对 IPv4 地址的查询只通过 LLMNR 在 IPv4 上查询;对 IPv6 地址的查询只通过 LLMNR 在 IPv6 上查询。 对本机的主机名、”_gateway” 以及 /etc/hosts 中定义的域名的查询 永远不会路由到 LLMNR 接口。
- 带有 “.local” 后缀的多标签主机名(含有”.”的主机名)使用多播DNS(MulticastDNS)协议 路由到所有支持IP多播的本地接口。 与 LLMNR 一样,IPv4 地址只在 IPv4 上查询;IPv6 地址只在 IPv6 上查询。
- 其他多标签主机名(含有”.”的主机名)使用DNS协议路由到所有配置了DNS服务器的本地接口。 如果配置了全局DNS服务器,那么还会路由到全局DNS服务器。从 link-local 地址范围发起的查询永远不会路由到DNS服务器。 默认情况下,除非 “.local” 被显式的指定为DNS服务器和网络接口的路由域或搜索域, 否则不会将带有 “.local” 后缀的主机名路由到DNS服务器。 这意味着,如果在特定网络环境中的DNS服务器中定义了 “.local” 域, 那么就必须显式的配置搜索域或路由域,以确保可以正常在此DNS域中进行查找。 注意,应该避免在DNS服务器中定义 “.local” 域, 因为 RFC6762 已将此域专门保留给 多播DNS(MulticastDNS)使用。
如果查询被发送到了多个接口, 那么将只返回第一个成功的应答。 如果所有接口上的查询全部失败, 那么将只返回最后一个失败的应答。
针对特定网络接口配置的域名以及其他一些设置都会影响对域名查询的路由。详见 systemd.network(5) 与 resolvectl(1) 手册。 单播DNS查询遵守如下路由逻辑:
- 如果查询的名称匹配(等于或具有后缀) 任何链接上的域(搜索域或路由域)、或全局DNS配置中的域, 那么,匹配到最多标签的域(搜索域或路由域),将被视为”最佳匹配域”。 查询将被发送到与”最佳匹配域”关联的所有DNS服务器(包括来自针对每个链接的DNS服务器以及全局DNS服务器)。 注意,可能有多个连接都配置了”最佳匹配域”, 在这种情况下,查询将被同时发送给这些连接。
- 如果查询的名称不匹配任何已配置的域(既不匹配任何链接上的域、也不匹配全局DNS配置中的域), 那么将会被发送到设置了”DNS默认路由”选项的连接(可能有多个这样的连接)上的DNS服务器、 以及全局配置的DNS服务器。
- 如果既没有在任何连接上设置”DNS默认路由”选项,也没有配置全局DNS服务器, 那么将使用编译时内置的替补DNS服务器。
- 否则查询失败,因为无法确定合适的DNS服务器。
“DNS默认路由”选项是一个布尔值,可以使用 resolvectl 配置, 也可在 .network 文件中配置。若未设置,则隐含的基于为链接配置的DNS域推断: 如果存在任何路由域(不匹配 “~.”),那么默认为 no , 否则默认为 yes
从效果上看,这意味着,为了更好的将未显式匹配任何域的DNS查询路由到指定的连接, 可以在该连接上配置一个 “~.” 路由域。 这样就可以确保不会使用其他连接(除非也带有这样的路由域)。 为了确保仅在没有其他更合适连接的情况下,才会将所有此类DNS查询路由到指定的链接, 应该将该连接的”DNS默认路由”选项设为 yes , 并且确保那个连接上没有 “~.” 路由域。 最后,为了确保特定的连接永远不会收到任何与其配置的域(搜索域与路由域)不匹配的DNS流量, 应该将该连接的”DNS默认路由”选项设为 no 。
参见 resolved D-Bus API Documentation 以了解 systemd-resolved 所提供的编程接口。
/etc/resolv.conf
有四种处理 /etc/resolv.conf 文件(参见 resolv.conf(5)) 的方式:
- systemd-resolved 实时更新 /run/systemd/resolve/stub-resolv.conf 文件以确保兼容传统的 Linux 程序。 将软连接 /etc/resolv.conf 指向该文件。该文件将 127.0.0.53 设为唯一的 DNS 服务器,并包含 systemd-resolved 使用的搜索域列表。 搜索域列表将会始终保持实时更新。注意,应用程序不应该直接使用 /run/systemd/resolve/stub-resolv.conf 文件, 而应该继续使用 /etc/resolv.conf 文件(指向它的软连接)。 这样,未使用本地 D-Bus DNS API 的客户端,既可以与 systemd-resolved 通信、又可以正确使用搜索域。 这是推荐的首选方式。
- 一个静态 /usr/lib/systemd/resolv.conf 文件, 此文件仅包含一个唯一的 127.0.0.53 DNS服务器。将软连接 /etc/resolv.conf 指向该静态文件。这样,未使用本地 D-Bus DNS API 的客户端,也可以与 systemd-resolved 通信。此文件不包含任何搜索域。
- systemd-resolved 实时更新 /run/systemd/resolve/resolv.conf 文件以确保兼容传统的 Linux 程序。 将软连接 /etc/resolv.conf 指向该文件。 注意,此文件只包含所有已知的全局DNS服务器, 而不包含针对特定网络接口设置的DNS服务器。注意,应用程序不应该直接使用 /run/systemd/resolve/resolv.conf 文件, 而应该继续使用 /etc/resolv.conf 文件(指向它的软连接)。 这样,未使用本地 D-Bus DNS API 的客户端,也将同时绕开 systemd-resolved 服务, 直接与已知的全局DNS服务器通信。
- 由其他软件包或系统管理员维护 /etc/resolv.conf 的内容。 在这种情况下, systemd-resolved 将会从中读取全局DNS配置。也就是说, systemd-resolved 只是一个 /etc/resolv.conf 文件的使用者, 而非此文件的提供者。
注意,上述四种处理方式是自动感知的(不需要特别的配置),完全取决于 /etc/resolv.conf 是否为软连接, 以及该软连接指向的目标。
信号
SIGUSR1
让 systemd-resolved 将所有的DNS资源记录缓存以及DNS服务器特性(例如是否支持DNSSCE) 转储到系统日志中。
SIGUSR2
让 systemd-resolved 刷新所有缓存。 因为 systemd-resolved 会在网络配置发生变化时自动刷新缓存,所以,除非出于调试目的,否则一般不需要发送此信号。 虽然发送此信号相当于执行 resolvectl —flush-caches 命令, 但是仍然建议使用命令而不是发送此信号,因为命令是以同步方式执行的。
SIGRTMIN+1
让 systemd-resolved 忘记所有已缓存的DNS服务器特性,特别是DNS服务器对于各种技术标准的支持。 这样,在执行下一次DNS查询的时候,将会重新检测DNS服务器的各项特性。 因为 systemd-resolved 会在DNS配置发生变化时自动刷新缓存的DNS服务器特性, 所以,除非出于调试目的,否则一般不需要发送此信号。虽然发送此信号相当于执行 resolvectl —reset-server-features 命令, 但是仍然建议使用命令而不是发送此信号,因为命令是以同步方式执行的。
使用
1、查看 DNS 服务状态
$ systemd-resolve --status
Global
DNSSEC NTA: 10.in-addr.arpa
16.172.in-addr.arpa
168.192.in-addr.arpa
17.172.in-addr.arpa
18.172.in-addr.arpa
19.172.in-addr.arpa
20.172.in-addr.arpa
21.172.in-addr.arpa
22.172.in-addr.arpa
23.172.in-addr.arpa
24.172.in-addr.arpa
25.172.in-addr.arpa
26.172.in-addr.arpa
27.172.in-addr.arpa
28.172.in-addr.arpa
29.172.in-addr.arpa
30.172.in-addr.arpa
31.172.in-addr.arpa
corp
d.f.ip6.arpa
home
internal
intranet
lan
local
private
test
Link 2 (ens3)
Current Scopes: DNS
LLMNR setting: yes
MulticastDNS setting: no
DNSSEC setting: no
DNSSEC supported: no
DNS Servers: 192.168.0.1
2、解析域名的的 IP
jiangzl@jiangzl:~$ systemd-resolve baidu.com
baidu.com: 220.181.38.148
39.156.69.79
-- Information acquired via protocol DNS in 159.3ms.
-- Data is authenticated: no
也可以使用 nslookup domain 来解析,如下示例:
$ nslookup baidu.com
Server: 127.0.0.53
Address: 127.0.0.53#53
Non-authoritative answer:
Name: baidu.com
Address: 39.156.69.79
Name: baidu.com
Address: 220.181.38.148
3、设置网卡的 DNS Server
systemd-resolve 命令可以用来设置指定网卡的 DNS Server,如下systemd-resolve --set-dns={DNS_SERVER_IP} --interface {ITERFACE_NAME}
$ sudo systemd-resolve --set-dns '8.8.8.8' --interface ens3
$
$ systemd-resolve --status | grep 'DNS Servers'
DNS Servers: 8.8.8.8
4、重置网卡的 DNS 设置
systemd-resolve --revert --interface {ITERFACE_NAME}
$ sudo systemd-resolve --revert --interface=ens33
注:该命令会清除指定网上的所有 DNS Server 的设置,请慎用。
5、刷新本地 DNS 缓存
如果有时候某些域名解析出现了问题,可尝试清除本地 DNS 缓存试试。
$ sudo systemd-resolve --flush-caches
6、查看 DNS 相关数据
$ systemd-resolve --statistics
DNSSEC supported by current servers: no
Transactions
Current Transactions: 0
Total Transactions: 420
Cache
Current Cache Size: 0
Cache Hits: 0
Cache Misses: 0
DNSSEC Verdicts
Secure: 0
Insecure: 0
Bogus: 0
Indeterminate: 0
注:可以看到的是清除缓存后,本地的 Cache 大小已经是 0 了,而如果我们使用 systemd-resolve domain 解析了域名,Cache 便会增加。
如下示例:
$ systemd-resolve baidu.com
baidu.com: 220.181.38.148
39.156.69.79
-- Information acquired via protocol DNS in 19.5ms.
-- Data is authenticated: no
$
$ systemd-resolve taobao.com
taobao.com: 140.205.94.189
140.205.220.96
-- Information acquired via protocol DNS in 10.1ms.
-- Data is authenticated: no
$
$ systemd-resolve --statistics
DNSSEC supported by current servers: no
Transactions
Current Transactions: 0
Total Transactions: 431
Cache
Current Cache Size: 2
Cache Hits: 0
Cache Misses: 34
DNSSEC Verdicts
Secure: 0
Insecure: 0
Bogus: 0
Indeterminate: 0
附录
resolvectl 常用参数及命令:
resolvectl [OPTIONS...] COMMAND ...
Send control commands to the network name resolution manager, or
resolve domain names, IPv4 and IPv6 addresses, DNS records, and services.
Commands:
query HOSTNAME|ADDRESS... Resolve domain names, IPv4 and IPv6 addresses
service [[NAME] TYPE] DOMAIN Resolve service (SRV)
openpgp EMAIL@DOMAIN... Query OpenPGP public key
tlsa DOMAIN[:PORT]... Query TLS public key
status [LINK...] Show link and server status
statistics Show resolver statistics
reset-statistics Reset resolver statistics
flush-caches Flush all local DNS caches
reset-server-features Forget learnt DNS server feature levels
dns [LINK [SERVER...]] Get/set per-interface DNS server address
domain [LINK [DOMAIN...]] Get/set per-interface search domain
default-route [LINK [BOOL]] Get/set per-interface default route flag
llmnr [LINK [MODE]] Get/set per-interface LLMNR mode
mdns [LINK [MODE]] Get/set per-interface MulticastDNS mode
dnsovertls [LINK [MODE]] Get/set per-interface DNS-over-TLS mode
dnssec [LINK [MODE]] Get/set per-interface DNSSEC mode
nta [LINK [DOMAIN...]] Get/set per-interface DNSSEC NTA
revert LINK Revert per-interface configuration
Options:
-h --help Show this help
--version Show package version
--no-pager Do not pipe output into a pager
-4 Resolve IPv4 addresses
-6 Resolve IPv6 addresses
-i --interface=INTERFACE Look on interface
-p --protocol=PROTO|help Look via protocol
-t --type=TYPE|help Query RR with DNS type
-c --class=CLASS|help Query RR with DNS class
--service-address=BOOL Resolve address for services (default: yes)
--service-txt=BOOL Resolve TXT records for services (default: yes)
--cname=BOOL Follow CNAME redirects (default: yes)
--search=BOOL Use search domains for single-label names
(default: yes)
--raw[=payload|packet] Dump the answer as binary data
--legend=BOOL Print headers and additional info (default: yes)
See the resolvectl(1) man page for details.