Published on

Fedora 33 中的 systemd-resolved DNS resolver

Authors
  • avatar
    Name
    ttyS3
    Twitter

Fedora 33 中的 DNS resolver 已经由 nss-dns 默认切换成了 systemd-resolved 简单来说,这意味着 systemd-resolved 将作为daemon程序运行。所有想要将域名转换为网络地址的程序都将与之通信。 这取代了当前默认的查找机制--每个程序单独与远程服务器交谈,并且没有共享缓存。

如有必要, systemd-resolved 将查询远程DNS服务器。 systemd-resolved 是一个“stub resolver” - 它本身不会解析任何域名(通过从根DNS开始并按标签一路径往下查询),而是将查询转发到远程DNS服务器。 其实这种类型的程序我们经常用,比如我们通常用的路由器上一般会用 dnsmasq 做“stub resolver”, 其下的局域网机器,通过DHCP自动获取到DNS后通常是这个路由器自己的LAN IP, 比如常见的 192.168.1.1 等。dnsmasq 自带缓存功能,也就是说一个域名已经解析过了,它不会每次都需要通过与远程DNS服务器通信来解析,而是可以在命中缓存结果的情况下直接返回。 systemd-resolved 的引入,相当于每台 Linux 机器本身已经有了一个类似 dnsmasq 的东西在跑。同时,每台机器对于跑在上面的程序的DNS查询配置,可以更加灵活了(因为split DNS)。

单个daemon程序处理域名解析提供了显著的好处。由于daemon进程会缓存响应结果,因而可以快速响应高频请求的域名。守护进程记得哪些服务器是非响应的,而预先每个程序都必须在超时后自己弄清楚这一点。个别程序仅在本地传输上与守护程序交谈,并从网络中孤立。守护程序支持花哨的规则,该规则指定应使用哪些名称服务器用于哪些域名 - 事实上,本文的其余部分是关于这些规则。

技术相关

来自 https://fedoraproject.org/wiki/Changes/systemd-resolved#Detailed_Description

Enable systemd-resolved by default. glibc will perform name resolution using 'nss-resolve' rather than 'nss-dns'.

systemd-resolved has been enabled by default in Ubuntu since Ubuntu 16.10, but please note we are doing this differently than Ubuntu has. Ubuntu does not use nss-resolve. Instead, Ubuntu uses the traditional nss-dns provided by glibc upstream, so glibc on Ubuntu continues to read /etc/resolv.conf, as is traditional. This extra step is not useful and not recommended by upstream. We want to follow upstream recommendations in using nss-resolve instead.

服务和命令行工具

查看服务状态:

❯ systemctl status systemd-resolved
● systemd-resolved.service - Network Name Resolution
     Loaded: loaded (/usr/lib/systemd/system/systemd-resolved.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2020-12-20 10:08:05 CST; 11h ago
       Docs: man:systemd-resolved.service(8)
             https://www.freedesktop.org/wiki/Software/systemd/resolved
             https://www.freedesktop.org/wiki/Software/systemd/writing-network-configuration-managers
             https://www.freedesktop.org/wiki/Software/systemd/writing-resolver-clients
   Main PID: 2695 (systemd-resolve)
     Status: "Processing requests..."
      Tasks: 1 (limit: 38311)
     Memory: 13.0M
        CPU: 8.384s
     CGroup: /system.slice/systemd-resolved.service
             └─2695 /usr/lib/systemd/systemd-resolved

查看当前状态:

❯ resolvectl status
Global
         Protocols: LLMNR=resolve -mDNS -DNSOverTLS DNSSEC=no/unsupported
  resolv.conf mode: stub
Current DNS Server: 127.0.0.1:5354
       DNS Servers: 127.0.0.1:5354

DNS解析(老灯这里特意查询了两次,主要是通过二者的消耗时间对比cache的效果):

❯ resolvectl query 163.com
163.com: 123.58.180.7
         123.58.180.8

-- Information acquired via protocol DNS in 7.7ms.
-- Data is authenticated: no
❯ resolvectl query 163.com
163.com: 123.58.180.7
         123.58.180.8

-- Information acquired via protocol DNS in 624us.
-- Data is authenticated: no

resolvectl statistics 可查询统计信息,比如缓存命中率,缓存条目数量等

resolvectl flush-caches 可清除查询缓存

其它参数可通过resolvectl -h 查看.

特别注意

systemd-resolved 不能当作局域网DNS cache服务器使用,它只能用于本机,因为它监听的是lo (loopback网卡)

stackoverflow上已经有大佬回复了,甚至把相关的代码都贴出来了. https://unix.stackexchange.com/a/549315/405754

You can't. As cristian-rodríguez mentioned above, it was strictly designed to provide services to loopback only. Not even an alternative solution using net.ipv4.conf.all.route_localnet=1 + iptables NAT (such as https://serverfault.com/questions/211536/iptables-port-redirect-not-working-for-localhost), https://superuser.com/questions/594163/how-do-i-route-a-port-range-in-a-linux-host-to-a-guest-vm), and https://stackoverflow.com/questions/18580637/iptables-redirect-from-external-interface-to-loopbacks-port) will work, since systemd-resolve explicitly inspects if the destination is outside the loopback network. See the code below for static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p)

    if (in_addr_is_localhost(p->family, &p->sender) <= 0 ||
        in_addr_is_localhost(p->family, &p->destination) <= 0) {
            log_error("Got packet on unexpected IP range, refusing.");
            dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false);
            goto fail;
    }

参考文档

https://fedoramagazine.org/systemd-resolved-introduction-to-split-dns/ https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html https://fedoraproject.org/wiki/Changes/systemd-resolved