第 7 章:DNS 配置
第 7 章:DNS 配置
7.1 NM DNS 管理机制
NetworkManager 通过 DNS 后端(backend)管理系统 DNS 配置,支持多种后端方案。
DNS 后端类型
| 后端 | 配置值 | 说明 | 适用场景 |
|---|---|---|---|
| 内建默认 | default | NM 直接写 /etc/resolv.conf | 简单场景 |
| systemd-resolved | systemd-resolved | 通过 systemd-resolved 管理 | 现代发行版推荐 |
| dnsmasq | dnsmasq | 本地 DNS 缓存 + 转发 | 需要本地缓存 |
| none | none | NM 不管理 DNS | 手动管理 |
查看当前 DNS 后端
# 方法 1:查看配置
cat /etc/NetworkManager/conf.d/*.conf | grep dns
cat /etc/NetworkManager/NetworkManager.conf | grep dns
# 方法 2:NM 输出的 DNS 配置信息
# 查看 NM 管理的 DNS 配置
nmcli device show | grep DNS
# 方法 3:查看 resolv.conf 指向
ls -la /etc/resolv.conf
# 如果是符号链接,说明使用了 resolved 或其他管理器
7.2 默认 DNS 后端(default)
NM 默认后端直接管理 /etc/resolv.conf。
连接级 DNS 配置
# 查看连接的 DNS 设置
nmcli connection show "Wired connection 1" | grep ipv4.dns
# 设置手动 DNS(覆盖 DHCP 获取的)
nmcli connection modify "Wired connection 1" \
ipv4.dns "8.8.8.8 8.8.4.4"
# 添加 DNS(追加到 DHCP 获取的 DNS 之后)
nmcli connection modify "Wired connection 1" \
+ipv4.dns "1.1.1.1"
# 移除手动 DNS(恢复为自动获取)
nmcli connection modify "Wired connection 1" \
ipv4.dns "" \
ipv4.ignore-auto-dns no
# 忽略 DHCP 提供的 DNS
nmcli connection modify "Wired connection 1" \
ipv4.ignore-auto-dns yes
# 设置搜索域
nmcli connection modify "Wired connection 1" \
ipv4.dns-search "example.com internal.example.com"
# IPv6 DNS
nmcli connection modify "Wired connection 1" \
ipv6.dns "2001:4860:4860::8888 2606:4700:4700::1111"
# 生效
nmcli connection up "Wired connection 1"
DNS 优先级
当有多个连接时,NM 根据路由度量值决定 DNS 顺序。也可以手动设置优先级:
# 设置 DNS 优先级(数值越小越优先)
nmcli connection modify "Wired connection 1" \
ipv4.dns-priority 100
nmcli connection modify "VPN-Connection" \
ipv4.dns-priority 50 # VPN 的 DNS 更优先
# 负值表示排除该连接的 DNS
nmcli connection modify "Guest-WiFi" \
ipv4.dns-priority -1
# 查看所有连接的 DNS 配置
nmcli -f NAME,IP4.DNS,IP4.DNS-PRIORITY connection show
resolv.conf 管理
# NM 管理 resolv.conf 的行为由 rc-manager 配置
# 查看当前 resolv.conf
cat /etc/resolv.conf
# 检查是否为符号链接
ls -la /etc/resolv.conf
# NM 的 rc-manager 选项
# /etc/NetworkManager/conf.d/dns.conf
[main]
dns=default
# rc-manager=auto # 默认,自动选择
# rc-manager=symlink # 创建符号链接到 NM 管理的文件
# rc-manager=file # 直接写入 /etc/resolv.conf
# rc-manager=resolvconf # 使用 resolvconf 工具
# rc-manager=unmanaged # 不管理
# 如果 /etc/resolv.conf 被其他程序锁定
# 解决:删除并让 NM 管理
sudo rm /etc/resolv.conf
sudo systemctl restart NetworkManager
7.3 systemd-resolved 后端
systemd-resolved 是现代 Linux 发行版推荐的 DNS 解析服务。
启用 systemd-resolved
# 安装(如果未安装)
sudo apt install systemd-resolved # Debian/Ubuntu(通常已安装)
# 配置 NM 使用 systemd-resolved
sudo tee /etc/NetworkManager/conf.d/dns.conf << 'EOF'
[main]
dns=systemd-resolved
EOF
# 确保 systemd-resolved 运行
sudo systemctl enable --now systemd-resolved
# 创建 resolv.conf 符号链接
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
# 重载 NM
sudo nmcli general reload conf
sudo systemctl restart NetworkManager
# 验证
resolvectl status
systemd-resolved 管理
# 查看全局 DNS 状态
resolvectl status
# 查看特定接口的 DNS
resolvectl status wlan0
# 查看 DNS 统计信息
resolvectl statistics
# 查看 DNS 缓存
resolvectl statistics
# 缓存命中/未命中会显示在输出中
# 清除 DNS 缓存
resolvectl flush-caches
# 查询 DNS(使用 resolved)
resolvectl query example.com
resolvectl query 192.168.1.1 # 反向解析
# 查看 DNSSEC 状态
resolvectl status | grep -i dnssec
systemd-resolved 配置文件
# /etc/systemd/resolved.conf
[Resolve]
# 全局 DNS 服务器(连接未指定时使用)
DNS=8.8.8.8 1.1.1.1
FallbackDNS=8.8.4.4 1.0.0.1
# 搜索域
Domains=~.
# DNSSEC 设置
# yes = 启用
# no = 禁用
# allow-downgrade = 允许降级
DNSSEC=allow-downgrade
# DNS over TLS
# yes = 强制
# opportunistic = 尝试
# no = 禁用
DNSOverTLS=opportunistic
# 缓存
Cache=yes
CacheFromLocalhost=no
# LLMNR(本地链路多播名称解析)
LLMNR=yes
# MulticastDNS
MulticastDNS=yes
# DNS Stub 监听器
DNSStubListener=yes
# DNSStubListenerExtra=udp:10.0.0.1:53
# 修改后重启
sudo systemctl restart systemd-resolved
7.4 dnsmasq 后端
dnsmasq 提供本地 DNS 缓存和 DHCP 服务。
# 安装 dnsmasq
sudo apt install dnsmasq-base # 只需要 base,不需要独立服务
# 配置 NM 使用 dnsmasq
sudo tee /etc/NetworkManager/conf.d/dns.conf << 'EOF'
[main]
dns=dnsmasq
EOF
# 重载
sudo nmcli general reload conf
sudo systemctl restart NetworkManager
# dnsmasq 由 NM 自动启动和管理
# 查看 dnsmasq 进程
ps aux | grep dnsmasq
# dnsmasq 配置(NM 管理时通过 NM 配置)
# 自定义 dnsmasq 配置
sudo tee /etc/NetworkManager/dnsmasq.d/custom.conf << 'EOF'
# 缓存大小
cache-size=1000
# 日志查询
log-queries
log-facility=/var/log/dnsmasq.log
# 自定义域名解析
address=/internal.example.com/10.0.0.1
# 转发特定域名到特定 DNS
server=/vpn.example.com/10.0.0.53
EOF
# 重载 NM 生效
sudo nmcli general reload conf
三种 DNS 后端对比
| 特性 | default | systemd-resolved | dnsmasq |
|---|---|---|---|
| 缓存 | ❌ | ✅ | ✅ |
| DNSSEC | ❌ | ✅ | ❌ |
| DNS over TLS | ❌ | ✅ | ❌ |
| LLMNR/mDNS | ❌ | ✅ | ❌ |
| 自定义域名 | ❌ | ❌ | ✅ |
| 内存占用 | 极低 | 低 | 低 |
| 复杂度 | 低 | 中 | 中 |
| 推荐场景 | 简单/容器 | 桌面/服务器 | 需要本地缓存 |
7.5 DNSSEC
# 查看 DNSSEC 状态
resolvectl status | grep -i "DNSSEC"
# 启用 DNSSEC(systemd-resolved)
sudo tee /etc/systemd/resolved.conf.d/dnssec.conf << 'EOF'
[Resolve]
DNSSEC=allow-downgrade
EOF
sudo systemctl restart systemd-resolved
# DNSSEC 模式说明:
# yes - 严格验证,验证失败则拒绝
# allow-downgrade - 尝试验证,不支持时降级
# no - 不验证
# 测试 DNSSEC 验证
resolvectl query dnssec-failed.org
# 如果 DNSSEC 工作正常,这个域名应该解析失败
# 查看 DNSSEC 验证详情
resolvectl query --statistics example.com
# 手动验证 DNSSEC
dig +dnssec example.com
dig +dnssec example.com DNSKEY
DNSSEC 故障处理
# 问题:某些域名无法解析(DNSSEC 验证失败)
# 临时方案:禁用 DNSSEC
sudo tee /etc/systemd/resolved.conf.d/no-dnssec.conf << 'EOF'
[Resolve]
DNSSEC=no
EOF
sudo systemctl restart systemd-resolved
# 更好的方案:使用 allow-downgrade
sudo tee /etc/systemd/resolved.conf.d/dnssec.conf << 'EOF'
[Resolve]
DNSSEC=allow-downgrade
EOF
7.6 DNS over TLS (DoT)
# 启用 DNS over TLS(systemd-resolved)
sudo tee /etc/systemd/resolved.conf.d/dot.conf << 'EOF'
[Resolve]
DNSOverTLS=opportunistic
# 可选值:
# yes - 强制 TLS(服务器必须支持)
# opportunistic - 尝试 TLS(不支持则回退明文)
# no - 禁用
EOF
sudo systemctl restart systemd-resolved
# 使用支持 DoT 的 DNS 服务器
# Cloudflare: 1.1.1.1, 1.0.0.1
# Google: 8.8.8.8, 8.8.4.4
# Quad9: 9.9.9.9, 149.112.112.112
# 测试 DoT 是否工作
resolvectl query example.com
# 查看输出中的 "Protocols:" 字段
7.7 搜索域配置
搜索域用于简化域名输入,当输入不完整域名时自动补全。
# 设置搜索域
nmcli connection modify "Wired connection 1" \
ipv4.dns-search "example.com internal.example.com"
# 多个连接的不同搜索域
nmcli connection modify "VPN-Connection" \
ipv4.dns-search "corp.example.com"
# 查看当前搜索域
nmcli connection show "Wired connection 1" | grep dns-search
# 生效
nmcli connection up "Wired connection 1"
# 验证
cat /etc/resolv.conf
# search example.com internal.example.com
# 测试搜索域
# 如果搜索域是 example.com
# 输入 "server1" 会自动查询 "server1.example.com"
nslookup server1
resolvectl query server1
搜索域 vs DNS 域路由
# 搜索域:补全域名
nmcli connection modify "Office" \
ipv4.dns-search "example.com"
# DNS 域路由:将特定域名的解析交给特定 DNS
# 在 systemd-resolved 中
# ~example.com 表示该连接负责解析 example.com 域
nmcli connection modify "VPN-Connection" \
ipv4.dns-search "~corp.example.com"
7.8 DNS 问题排查
# 1. 查看当前使用的 DNS 服务器
resolvectl status
cat /etc/resolv.conf
# 2. 测试 DNS 解析
nslookup example.com
dig example.com
host example.com
resolvectl query example.com
# 3. 指定 DNS 服务器测试
nslookup example.com 8.8.8.8
dig @8.8.8.8 example.com
# 4. 查看 NM 管理的 DNS
nmcli device show | grep DNS
# 5. 清除 DNS 缓存
resolvectl flush-caches # systemd-resolved
sudo systemctl restart dnsmasq # dnsmasq
# 6. DNS 解析延迟测试
time nslookup example.com
# 7. 详细 DNS 调试
resolvectl query --legend=no example.com
dig +trace example.com
# 8. 检查 DNS 配置冲突
# 可能的问题:多个服务同时管理 resolv.conf
ls -la /etc/resolv.conf
# 检查是否有 symlink 指向错误的目标
7.9 常见 DNS 场景配置
场景 1:公司内网 + 公网 DNS
# 公网 DNS 作为默认
nmcli connection modify "Office-LAN" \
ipv4.dns "8.8.8.8 8.8.4.4" \
ipv4.dns-search "example.com" \
ipv4.ignore-auto-dns yes
# 内网 DNS 用于公司域名
# 使用 systemd-resolved 的路由 DNS 功能
nmcli connection modify "Office-LAN" \
+ipv4.dns "10.0.0.53" \
+ipv4.dns-search "~internal.example.com"
场景 2:VPN 完整 DNS 隧道
# VPN 连接时使用 VPN 的 DNS
nmcli connection modify "Corp-VPN" \
ipv4.dns "10.0.0.53" \
ipv4.dns-search "corp.example.com" \
ipv4.dns-priority -50 \
ipv4.ignore-auto-dns no
场景 3:开发环境自定义 DNS
# 本地开发域名解析
# 使用 dnsmasq 后端
sudo tee /etc/NetworkManager/dnsmasq.d/dev.conf << 'EOF'
address=/dev.local/127.0.0.1
address=/api.dev.local/127.0.0.1
address=/db.dev.local/10.0.0.50
EOF
sudo nmcli general reload conf
7.10 本章小结
| 要点 | 说明 |
|---|---|
| DNS 后端 | default(直接写 resolv.conf)、systemd-resolved、dnsmasq、none |
| 推荐后端 | 现代系统推荐 systemd-resolved |
| 连接 DNS | ipv4.dns 设置手动 DNS,ipv4.ignore-auto-dns 忽略 DHCP DNS |
| DNS 优先级 | ipv4.dns-priority,负值排除 |
| 搜索域 | ipv4.dns-search,~ 前缀表示域路由 |
| DNSSEC | systemd-resolved 支持,建议 allow-downgrade |
| DNS over TLS | systemd-resolved 支持 opportunistic 模式 |