强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

systemd 教程 / DNS 解析(systemd-resolved)

DNS 解析(systemd-resolved)

概述

systemd-resolved 是 systemd 提供的 DNS 解析守护进程,提供域名解析、DNS 缓存、mDNS/LLMNR 支持等功能。它支持 DNS-over-TLS(DoT)加密、多链路 DNS(Split DNS)等现代 DNS 特性,是 systemd 网络栈的重要组成部分。


架构概览

┌──────────────┐
│  应用程序     │  getaddrinfo() / NSS
├──────────────┤
│  glibc NSS   │  nss-resolve
├──────────────┤
│  systemd-    │  D-Bus 接口
│  resolved    │  本地 DNS stub (127.0.0.53)
├──────────────┤
│  上游 DNS    │  递归解析器 / DoT / DoH
└──────────────┘

resolvectl 命令

resolvectlsystemd-resolved 的管理工具,功能非常丰富。

基本查询

# 查询域名
resolvectl query www.example.com

# 查询特定类型的 DNS 记录
resolvectl query --type=MX example.com
resolvectl query --type=TXT example.com
resolvectl query --type=AAAA example.com

# 反向查询(IP → 域名)
resolvectl query 8.8.8.8

查看状态

# 查看全局 DNS 配置
resolvectl status

# 查看特定链路的 DNS 配置
resolvectl status eth0

# 查看 DNS 缓存统计
resolvectl statistics

# 输出示例:
# DNSSEC supported: current no
#
#         Cache: hit: 150 miss: 23
#   Positive hits: 120
#   Negative hits: 30
#     Miss (DNS): 23

DNS 缓存管理

# 清除 DNS 缓存
resolvectl flush-caches

# 重置统计信息
resolvectl reset-statistics

# 查看缓存大小
resolvectl show-cache-size

DNSSEC 验证

# 查看 DNSSEC 状态
resolvectl show-dnssec

# 验证域名的 DNSSEC
resolvectl query --legend=no --verify=yes example.com

DNS 配置

全局配置

# /etc/systemd/resolved.conf
[Resolve]
# 配置上游 DNS 服务器
DNS=8.8.8.8 8.8.4.4 1.1.1.1

# 备用 DNS 服务器
FallbackDNS=9.9.9.9 149.112.112.112

# 搜索域
Domains=~.

# DNSSEC 模式
DNSSEC=allow-downgrade

# DNS-over-TLS
DNSOverTLS=opportunistic

# 缓存设置
Cache=yes
CacheFromLocalhost=no

# LLMNR 支持
LLMNR=yes

# mDNS 支持
MulticastDNS=yes

# DNS stub 监听
DNSStubListener=yes
# DNSStubListenerExtra=udp:127.0.0.54:53

[Resolve] 段参数详解

参数说明默认值可选值
DNS上游 DNS 服务器-IP 地址列表
FallbackDNS备用 DNS各发行版不同IP 地址列表
Domains搜索域-域名列表,~. 表示全局
DNSSECDNSSEC 模式allow-downgradeyes / no / allow-downgrade
DNSOverTLSDoT 模式opportunisticyes / no / opportunistic
Cache启用缓存yesyes / no / no-negative
CacheFromLocalhost缓存本地响应noyes / no
LLMNRLLMNR 支持yesyes / no / resolve
MulticastDNSmDNS 支持yesyes / no / resolve
DNSStubListener监听 DNS stubyesyes / no / udp / tcp
ReadEtcHosts读取 /etc/hostsyesyes / no
ResolveUnicastSingleLabel解析单标签域名noyes / no

⚠️ 注意:修改配置后需要重启 systemd-resolved 才能生效。


DNS-over-TLS(DoT)

DNS-over-TLS 通过 TLS 加密 DNS 查询,防止 DNS 窥探和篡改。

配置 DoT

# /etc/systemd/resolved.conf
[Resolve]
# 严格模式:强制使用 TLS
DNS=1.1.1.1#cloudflare-dns.com 8.8.8.8#dns.google
DNSOverTLS=yes

DoT 模式

模式说明
no不使用 DoT
opportunistic尝试 DoT,失败则回退明文
yes(strict)强制 DoT,连接失败则查询失败

⚠️ 注意:严格模式需要 DNS 服务器支持 TLS,且服务器名称需正确配置(DNS=IP#hostname)。

验证 DoT

# 查看 DoT 状态
resolvectl status | grep -i "DNSOverTLS"

# 测试查询
resolvectl query www.example.com

多链路 DNS(Split DNS)

systemd-resolved 支持按网络接口路由 DNS 查询,即 Split DNS。

工作原理

当不同网络接口配置了不同 DNS 服务器时,查询会根据搜索域路由到对应 DNS:

eth0: DNS=10.0.0.1, Domains=internal.corp
eth1: DNS=8.8.8.8, Domains=~.

查询 app.internal.corp → 通过 eth0 (10.0.0.1)
查询 www.google.com   → 通过 eth1 (8.8.8.8)

配置示例

# /etc/systemd/network/20-eth0.network
[Match]
Name=eth0

[Network]
Address=10.0.0.100/24
DNS=10.0.0.1
Domains=internal.corp
# /etc/systemd/network/20-eth1.network
[Match]
Name=eth1

[Network]
Address=192.168.1.100/24
DNS=8.8.8.8
Domains=~.

💡 提示~. 前缀表示该 DNS 服务器作为全局默认。没有前缀的域表示精确匹配。

查看路由规则

# 查看各链路的 DNS 配置
resolvectl status

# 测试特定域的解析
resolvectl query app.internal.corp
# 输出应显示通过 eth0 解析

DNS 缓存

systemd-resolved 内建 DNS 缓存,减少对上游 DNS 的查询。

缓存行为

配置说明
Cache=yes缓存所有 DNS 响应(默认)
Cache=no禁用缓存
CacheFromLocalhost=yes缓存来自 127.0.0.1 的响应

管理缓存

# 查看缓存命中统计
resolvectl statistics

# 清除缓存
resolvectl flush-caches

# 清除特定域名的缓存
resolvectl query --flush-caches www.example.com

mDNS 与 LLMNR

mDNS(Multicast DNS)

mDNS 用于局域网内的名称解析,使用 .local 域名:

# 查询 mDNS 名称
resolvectl query myhost.local

# 查看 mDNS 状态
resolvectl status | grep -i mDNS

LLMNR 是 Microsoft 的本地链路名称解析协议:

# 查看 LLMNR 状态
resolvectl status | grep -i LLMNR
参数说明
yes启用同时提供解析和响应
no禁用不参与 LLMNR
resolve仅解析只做客户端,不响应

⚠️ 注意:在生产环境中,建议禁用 LLMNR(存在安全风险),mDNS 按需启用。


与 /etc/resolv.conf 兼容

连接方式

systemd-resolved 通过 127.0.0.53 的 DNS stub 监听器提供兼容性:

# 查看当前 resolv.conf
cat /etc/resolv.conf

# 推荐的符号链接
ls -la /etc/resolv.conf
# /etc/resolv.conf -> /run/systemd/resolve/stub-resolv.conf

resolv.conf 文件

文件路径说明
/run/systemd/resolve/stub-resolv.conf指向 127.0.0.53(推荐)
/run/systemd/resolve/resolv.conf直接指向上游 DNS

配置符号链接

# 创建正确的符号链接
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

# 验证
ls -la /etc/resolv.conf

⚠️ 注意:某些 VPN 客户端可能会覆盖 /etc/resolv.conf,导致 DNS 解析异常。建议使用符号链接方式。


实际场景

场景 1:VPN DNS 配置

当连接 VPN 时,需要将内部域名路由到 VPN 的 DNS 服务器:

# VPN 配置自动下发的 .network 文件
[Match]
Name=tun0

[Network]
DNS=10.8.0.1
Domains=~internal.corp ~vpn.corp
# 验证内部域名解析
resolvectl query wiki.internal.corp

# 应通过 VPN 解析

场景 2:容器 DNS

为容器配置专用 DNS:

# /etc/systemd/network/30-cni0.network
[Match]
Name=cni0

[Network]
DNS=10.96.0.10
Domains=~cluster.local

场景 3:企业内部 DNS + 公网 DNS

# /etc/systemd/resolved.conf
[Resolve]
# 公网 DNS
DNS=1.1.1.1#cloudflare-dns.com 8.8.8.8#dns.google

# 内部 DNS 通过 .network 文件配置
Domains=~.
DNSOverTLS=opportunistic
# /etc/systemd/network/20-eth0.network
[Match]
Name=eth0

[Network]
DNS=10.0.0.1
Domains=internal.corp ~intranet.corp

调试 DNS 解析

常用调试命令

# 查看完整状态
resolvectl status

# 查询域名并查看详细信息
resolvectl query www.example.com

# 查看 DNS 缓存统计
resolvectl statistics

# 清除缓存后重新查询
resolvectl flush-caches
resolvectl query www.example.com

# 查看日志
journalctl -u systemd-resolved

# 实时监控
journalctl -fu systemd-resolved

使用 dig/nslookup 对比

# 使用 resolvectl
resolvectl query www.example.com

# 使用 dig(通过 systemd-resolved)
dig @127.0.0.53 www.example.com

# 使用 nslookup
nslookup www.example.com 127.0.0.53

常见问题排查

问题原因解决方案
DNS 解析缓慢缓存被禁用确认 Cache=yes
无法解析内部域名Split DNS 配置错误检查 .network 文件的 Domains
VPN DNS 不工作resolv.conf 被覆盖重新创建符号链接
DoT 连接失败服务器不支持 TLS改用 opportunistic 模式
DNSSEC 验证失败域名无 DNSSEC 记录使用 allow-downgrade

实用命令汇总

# 状态查看
resolvectl status
resolvectl statistics

# DNS 查询
resolvectl query example.com
resolvectl query --type=MX example.com
resolvectl query 8.8.8.8

# 缓存管理
resolvectl flush-caches
resolvectl reset-statistics

# 服务管理
sudo systemctl restart systemd-resolved
sudo systemctl status systemd-resolved
journalctl -u systemd-resolved

# 配置文件
sudo vim /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved

扩展阅读