一、DNS核心原理深度剖析
1.1 DNS是什么?为什么如此重要?
┌─────────────────────────────────────────────────────────────────┐
│ DNS 在互联网中的位置 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 用户输入 DNS 解析 建立连接 │
│ ┌────────┐ ┌──────────┐ ┌──────────┐ │
│ │ www. │ ───────▶ │ DNS │ ──────▶ │ 192. │ │
│ │ example│ │ Server │ │ 0.2.1 │ │
│ │ .com │ │ │ │ │ │
│ └────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │
│ │ 域名(人类可读) │ 查询请求 │ IP 地址 │
│ │ │ │ │
└─────────────────────────────────────────────────────────────────┘
没有 DNS,互联网将退回到 IP 地址时代!
DNS 的核心作用:
- 域名 → IP 地址映射(正向解析)
- IP 地址 → 域名映射(反向解析)
- 邮件服务器定位(MX 记录)
- 服务发现(SRV 记录)
- 域名别名(CNAME 记录)
1.2 DNS 层次结构
┌─────────┐
│ . │ 根域名
│ (Root) │
└────┬────┘
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ .com │ │ .org │ │ .cn │ 顶级域名 (TLD)
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
│ ┌──────────┴──────────┐ │
│ │ │ │
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ google │ │ example │ │ example │ │ 163 │ 二级域名
└─────────┘ └────┬────┘ └────┬────┘ └─────────┘
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│ www │ │ mail │ 主机名
└─────────┘ └─────────┘
完整域名:www.example.com.
1.3 DNS 记录类型详解
┌─────────────────────────────────────────────────────────────────┐
│ 常见 DNS 记录类型 │
├──────────┬──────────────────────────────────────────────────────┤
│ 记录类型 │ 说明与示例 │
├──────────┼──────────────────────────────────────────────────────┤
│ A │ IPv4 地址记录 │
│ │ example.com. 300 IN A 192.0.2.1 │
├──────────┼──────────────────────────────────────────────────────┤
│ AAAA │ IPv6 地址记录 │
│ │ example.com. 300 IN AAAA 2001:db8::1 │
├──────────┼──────────────────────────────────────────────────────┤
│ CNAME │ 别名记录(Canonical Name) │
│ │ www.example.com. 300 IN CNAME example.com. │
├──────────┼──────────────────────────────────────────────────────┤
│ MX │ 邮件交换记录(Mail Exchange) │
│ │ example.com. 300 IN MX 10 mail.example.com. │
├──────────┼──────────────────────────────────────────────────────┤
│ NS │ 域名服务器记录(Name Server) │
│ │ example.com. 300 IN NS ns1.example.com. │
├──────────┼──────────────────────────────────────────────────────┤
│ TXT │ 文本记录(常用于 SPF、DKIM 验证) │
│ │ example.com. 300 IN TXT "v=spf1 include:_spf.google.com ~all" │
├──────────┼──────────────────────────────────────────────────────┤
│ PTR │ 反向解析记录(Pointer) │
│ │ 1.2.0.192.in-addr.arpa. 300 IN PTR example.com. │
├──────────┼──────────────────────────────────────────────────────┤
│ SRV │ 服务定位记录(Service) │
│ │ _http._tcp.example.com. 300 IN SRV 10 5 80 www.example.com. │
├──────────┼──────────────────────────────────────────────────────┤
│ SOA │ 起始授权记录(Start of Authority) │
│ │ 包含域管的权威信息、序列号、刷新间隔等 │
└──────────┴──────────────────────────────────────────────────────┘
1.4 DNS 查询流程详解
┌─────────────────────────────────────────────────────────────────┐
│ DNS 递归查询完整流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 客户端 │
│ │ │
│ │ 1. 查询 www.example.com │
│ ▼ │
│ ┌─────────┐ │
│ │ 本地 │ 2. 有缓存?───有──▶ 返回结果 │
│ │ DNS 缓存 │ │ │
│ └─────────┘ 无 │
│ │ │ │
│ │ 3. 查询本地 DNS 服务器 │ │
│ ▼ │ │
│ ┌──────────────────────┴──────────────────────────────────┐ │
│ │ 本地 DNS 服务器 │ │
│ │ ┌─────────┐ │ │
│ │ │ 递归 │ 4. 查询根服务器 (.com 在哪里?) │ │
│ │ │ 解析器 │ ▼ │ │
│ │ └─────────┘ ┌─────────┐ │ │
│ │ │ 根服务器 │ 5. .com 在 192.5.6.30 │ │
│ │ └─────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────┐ │ │
│ │ │ .com │ 6. example.com 在 192.0.2.1 │ │
│ │ │ TLD 服务器│ │ │
│ │ └─────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────┐ │ │
│ │ │ 权威 │ 7. www.example.com = 93.184.216.34 │
│ │ │ DNS 服务器│ │ │
│ │ └─────────┘ │ │
│ │ │ │ │
│ │ 8. 返回结果 ◀────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │ │
│ │ 9. 返回结果 + 缓存 │
│ ▼ │
│ 客户端获得 IP: 93.184.216.34 │
│ │
└─────────────────────────────────────────────────────────────────┘
总耗时:通常 20-100ms(有缓存则 <1ms)
二、Linux DNS 配置详解
2.1 /etc/resolv.conf - DNS 配置核心文件
# 查看当前 DNS 配置
cat /etc/resolv.conf
# 典型配置示例
nameserver 8.8.8.8 # 首选 DNS 服务器
nameserver 8.8.4.4 # 备用 DNS 服务器
nameserver 1.1.1.1 # 第三 DNS 服务器(最多 3 个)
search example.com local # 搜索域(域名补全)
options timeout:2 # 查询超时时间(秒)
options attempts:3 # 重试次数
options rotate # 轮询使用 DNS 服务器
options ndots:1 # 点号阈值(决定何时使用搜索域)
配置参数详解
┌─────────────────────────────────────────────────────────────────┐
│ /etc/resolv.conf 参数详解 │
├──────────────────┬──────────────────────────────────────────────┤
│ 参数 │ 说明 │
├──────────────────┼──────────────────────────────────────────────┤
│ nameserver │ DNS 服务器 IP(最多 3 个,按顺序使用) │
│ search │ 搜索域列表(主机名补全用) │
│ domain │ 本地域名(与 search 互斥) │
│ options timeout │ 查询超时,默认 5 秒 │
│ options attempts │ 重试次数,默认 2 次 │
│ options rotate │ 轮询 nameserver(负载均衡) │
│ options ndots │ 点号阈值,决定搜索域使用策略 │
│ options edns0 │ 启用 EDNS0 扩展(支持更大响应) │
│ options single-request │ 串行查询(避免 IPv4/IPv6 竞争) │
└──────────────────┴──────────────────────────────────────────────┘
ndots 参数详解(重要!)
# ndots 决定域名中点号数量达到多少时,直接使用完整域名查询
# 否则先尝试搜索域补全
# 示例:ndots:1
# 查询 “host“(0 个点,小于 ndots)
# 1. 先查 host.example.com
# 2. 再查 host.local
# 3. 最后查 host.
# 查询 “host.sub“(1 个点,等于 ndots)
# 1. 直接查 host.sub.
# 2. 失败后再尝试搜索域
# 生产建议:
options ndots:1 # 默认值,适合大多数场景
options ndots:2 # 减少不必要的搜索域查询
options ndots:0 # 总是使用完整域名
2.2 /etc/nsswitch.conf - 名称解析顺序
# 查看名称解析配置
cat /etc/nsswitch.conf
# hosts 行配置(关键!)
hosts: files dns myhostname
# │ │ │
# │ │ └── 本机主机名
# │ └────── DNS 查询
# └──────────── /etc/hosts 文件
# 解析顺序:/etc/hosts → DNS → 本机主机名
# 常见问题:
# 如果配置为:hosts: dns files
# 会导致即使 /etc/hosts 有配置,也会先查 DNS
# 可能引起解析延迟或失败
2.3 /etc/hosts - 本地主机名映射
# 查看本地 hosts 配置
cat /etc/hosts
# 典型配置
127.0.0.1 localhost localhost.localdomain
::1 localhost localhost.localdomain ip6-localhost ip6-loopback
fe80::1 ip6-allnodes
# 自定义主机名映射
192.168.1.10 api.example.com api
192.168.1.11 db.example.com db
192.168.1.12 cache.example.com cache
# 屏蔽域名(广告拦截)
0.0.0.0 ads.example.com
0.0.0.0 tracker.example.com
hosts 与 DNS 优先级
┌─────────────────────────────────────────────────────────────────┐
│ 名称解析优先级 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. /etc/hosts(本地文件,最快) │
│ │ │
│ ▼ │
│ 2. DNS 查询(网络请求,较慢) │
│ │ │
│ ▼ │
│ 3. mDNS/LLMNR(本地多播,备用) │
│ │
│ 通过 nsswitch.conf 控制顺序: │
│ hosts: files dns # hosts 优先(推荐) │
│ hosts: dns files # DNS 优先(不推荐) │
│ │
└─────────────────────────────────────────────────────────────────┘
2.4 systemd-resolved - 现代 Linux DNS 管理
# 检查 systemd-resolved 状态
systemctl status systemd-resolved
# 查看 DNS 配置状态
resolvectl status
# 查看 DNS 缓存统计
resolvectl statistics
# 刷新 DNS 缓存
resolvectl flush-caches
# 查询特定域名
resolvectl query www.example.com
# 查看当前 DNS 服务器
resolvectl | grep “DNS Servers“
systemd-resolved 配置
# /etc/systemd/resolved.conf
[Resolve]
# DNS 服务器列表(空格分隔)
DNS=8.8.8.8 1.1.1.1 9.9.9.9
# 备用 DNS 服务器
FallbackDNS=208.67.222.222 208.67.220.220
# 搜索域
Domains=example.com local
# LLMNR 支持(本地链路多播名称解析)
LLMNR=yes
# 多播 DNS
MulticastDNS=yes
# DNSSEC 验证
DNSSEC=yes
# DNS over TLS(加密 DNS)
#DNSOverTLS=no
# 缓存大小(0=禁用,其他=条目数)
Cache=yes
CacheSize=15MB
常见问题:/etc/resolv.conf 被覆盖
# 问题:修改 /etc/resolv.conf 后重启被还原
# 原因:systemd-resolved 或 NetworkManager 管理
# 解决方案 1:修改 systemd-resolved 配置
vim /etc/systemd/resolved.conf
# 修改后重启服务
systemctl restart systemd-resolved
# 解决方案 2:创建符号链接
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
# 解决方案 3:禁用 systemd-resolved 管理
# 编辑 NetworkManager 配置
vim /etc/NetworkManager/NetworkManager.conf
[main]
dns=none # 禁用 NM 的 DNS 管理
# 解决方案 4:锁定文件(不推荐)
chattr +i /etc/resolv.conf
2.5 NetworkManager DNS 管理
# 查看当前网络连接
nmcli connection show
# 查看 DNS 配置
nmcli device show eth0 | grep DNS
# 手动设置 DNS
nmcli connection modify eth0 ipv4.dns “8.8.8.8 8.8.4.4“
nmcli connection modify eth0 ipv4.ignore-auto-dns yes
nmcli connection up eth0
# 自动获取 DNS(DHCP)
nmcli connection modify eth0 ipv4.ignore-auto-dns no
nmcli connection up eth0
# 删除 DNS 配置
nmcli connection modify eth0 ipv4.dns ““
三、DNS 解析工具与排查实战
3.1 dig - DNS 查询利器
# 基础查询
dig www.example.com
# 指定 DNS 服务器查询
dig @8.8.8.8 www.example.com
dig @ns1.example.com www.example.com
# 指定记录类型
dig example.com MX # 邮件记录
dig example.com TXT # 文本记录
dig example.com NS # 域名服务器
dig example.com SOA # 起始授权
dig example.com AAAA # IPv6 记录
dig -x 192.0.2.1 # 反向查询
# 简洁输出(适合脚本)
dig +short www.example.com
dig +noall +answer www.example.com
# 完整输出
dig +noall +answer +authority +additional www.example.com
# 追踪解析链
dig +trace www.example.com
# 查询统计
dig +stats www.example.com
# 批量查询
dig -f domains.txt
# 示例输出解析
$ dig www.example.com
; <<>> DiG 9.16.1 <<>> www.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12345
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;www.example.com. IN A
;; ANSWER SECTION:
www.example.com. 300 IN CNAME example.com.
example.com. 300 IN A 93.184.216.34
;; Query time: 25 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sat Jan 15 10:00:00 UTC 2024
;; MSG SIZE rcvd: 68
3.2 nslookup - 传统 DNS 工具
# 基础查询
nslookup www.example.com
# 指定 DNS 服务器
nslookup www.example.com 8.8.8.8
# 交互模式
nslookup
> server 8.8.8.8 # 切换 DNS 服务器
> set type=MX # 设置查询类型
> example.com
> set type=TXT
> example.com
> exit
# 查询所有记录
nslookup -query=ANY example.com
3.3 host - 简洁 DNS 工具
# 基础查询
host www.example.com
# 指定记录类型
host -t MX example.com
host -t TXT example.com
host -t NS example.com
# 反向查询
host 93.184.216.34
# 详细输出
host -a www.example.com
# 简洁输出
host -w www.example.com
3.4 工具对比
┌─────────────────────────────────────────────────────────────────┐
│ DNS 查询工具对比 │
├──────────┬──────────────────────────────────────────────────────┤
│ 工具 │ 特点与适用场景 │
├──────────┼──────────────────────────────────────────────────────┤
│ dig │ ✅ 功能最强大,输出详细 │
│ │ ✅ 支持 +trace 追踪解析链 │
│ │ ✅ 适合故障排查和脚本使用 │
│ │ ⚠️ 输出较复杂,新手不易阅读 │
├──────────┼──────────────────────────────────────────────────────┤
│ nslookup │ ✅ 交互模式方便 │
│ │ ✅ 输出相对简洁 │
│ │ ⚠️ 功能不如 dig 丰富 │
│ │ ⚠️ 已标记为废弃,建议用 dig 替代 │
├──────────┼──────────────────────────────────────────────────────┤
│ host │ ✅ 输出最简洁 │
│ │ ✅ 适合快速查询 │
│ │ ⚠️ 功能有限 │
└──────────┴──────────────────────────────────────────────────────┘
推荐:日常使用 dig +short,故障排查用 dig +trace
3.5 高级排查技巧
# ============================================================
# 技巧 1:追踪完整解析链
# ============================================================
dig +trace www.example.com
# 输出示例:
# . 518400 IN NS a.root-servers.net.
# com. 172800 IN NS a.gtld-servers.net.
# example.com. 172800 IN NS ns1.example.com.
# www.example.com. 300 IN A 93.184.216.34
# ============================================================
# 技巧 2:检查 DNS 传播
# ============================================================
# 在多个公共 DNS 上查询
for dns in 8.8.8.8 1.1.1.1 9.9.9.9 208.67.222.222; do
echo “=== $dns ===“
dig @$dns www.example.com +short
done
# ============================================================
# 技巧 3:检查 DNSSEC
# ============================================================
dig +dnssec example.com
dig +cd example.com # 禁用 DNSSEC 验证
# ============================================================
# 技巧 4:测量解析延迟
# ============================================================
time dig @8.8.8.8 www.example.com +short
# ============================================================
# 技巧 5:批量查询域名
# ============================================================
cat > domains.txt << EOF
www.google.com
www.facebook.com
www.amazon.com
EOF
dig -f domains.txt +short
# ============================================================
# 技巧 6:检查 DNS 缓存
# ============================================================
# 第一次查询(无缓存)
time dig www.example.com +short
# 第二次查询(有缓存)
time dig www.example.com +short
# 查看 systemd-resolved 缓存
resolvectl statistics | grep -A 5 “Cache“
# ============================================================
# 技巧 7:模拟不同地区解析
# ============================================================
# 使用不同地区的 DNS 服务器
dig @8.8.8.8 www.example.com +short # 美国
dig @1.1.1.1 www.example.com +short # 全球
dig @114.114.114.114 www.example.com +short # 中国
四、DNS 缓存机制深度解析
4.1 Linux DNS 缓存层级
┌─────────────────────────────────────────────────────────────────┐
│ Linux DNS 缓存层级 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 应用层缓存 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 浏览器缓存 (Chrome/Firefox) │ │
│ │ glibc DNS 缓存 (getaddrinfo) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 系统层缓存 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ systemd-resolved 缓存 │ │
│ │ nscd (Name Service Cache Daemon) 缓存 │ │
│ │ dnsmasq 缓存 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ 网络层缓存 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 本地 DNS 服务器缓存 │ │
│ │ ISP DNS 服务器缓存 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
4.2 各层缓存刷新方法
# ============================================================
# systemd-resolved 缓存
# ============================================================
# 刷新所有缓存
resolvectl flush-caches
# 刷新特定接口缓存
resolvectl flush-caches eth0
# 查看缓存统计
resolvectl statistics
# ============================================================
# nscd 缓存
# ============================================================
# 刷新 hosts 缓存
nscd -i hosts
# 刷新所有缓存
nscd -i hosts -i passwd -i group
# 重启 nscd 服务
systemctl restart nscd
# 查看缓存状态
nscd -g
# ============================================================
# dnsmasq 缓存
# ============================================================
# 刷新缓存
killall -USR2 dnsmasq
# 或重启服务
systemctl restart dnsmasq
# 查看缓存统计
# dnsmasq 启动时加 --log-queries 参数
tail -f /var/log/syslog | grep dnsmasq
# ============================================================
# 浏览器缓存
# ============================================================
# Chrome: chrome://net-internals/#dns
# Firefox: about:networking#dns
# 命令行刷新 Chrome 缓存
curl http://localhost:9222/json/new?chrome://net-internals/#dns
# ============================================================
# glibc 缓存
# ============================================================
# glibc 2.x 有内置缓存,无法直接刷新
# 重启应用或等待 TTL 过期
4.3 TTL(Time To Live)详解
┌─────────────────────────────────────────────────────────────────┐
│ DNS TTL 详解 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ TTL 定义:DNS 记录在缓存中的存活时间(秒) │
│ │
│ TTL 值选择: │
│ ┌──────────────┬─────────────────────────────────────────┐ │
│ │ TTL 值 │ 适用场景 │ │
│ ├──────────────┼─────────────────────────────────────────┤ │
│ │ 30-300 秒 │ 频繁变更的记录(如 CDN、负载均衡) │ │
│ │ 3600 秒 (1h) │ 一般网站记录 │ │
│ │ 86400 秒 (1d) │ 稳定不变的记录 │ │
│ │ 604800 秒 (7d)│ 极少变更的记录 │ │
│ └──────────────┴─────────────────────────────────────────┘ │
│ │
│ TTL 变更注意事项: │
│ 1. 降低 TTL 需要提前操作(等待旧 TTL 过期) │
│ 2. 迁移 DNS 前先将 TTL 调低 │
│ 3. 迁移完成后可将 TTL 调高 │
│ │
└─────────────────────────────────────────────────────────────────┘
# 查看 DNS 记录 TTL
dig www.example.com | grep “ANSWER SECTION“ -A 2
# 输出示例:
# ;; ANSWER SECTION:
# www.example.com. 299 IN A 93.184.216.34
# ^^^
# 剩余 TTL(秒)
4.4 DNS 缓存优化策略
# ============================================================
# 策略 1:合理设置 TTL
# ============================================================
# 生产环境记录
www.example.com. 3600 IN A 192.0.2.1
# 经常变更的记录(如 CDN)
cdn.example.com. 300 IN CNAME cdn-provider.com.
# 邮件记录(稳定)
example.com. 86400 IN MX 10 mail.example.com.
# ============================================================
# 策略 2:部署本地 DNS 缓存
# ============================================================
# 安装 dnsmasq
apt install dnsmasq
# 配置 dnsmasq
cat > /etc/dnsmasq.conf << EOF
# 监听地址
listen-address=127.0.0.1
# 上游 DNS 服务器
server=8.8.8.8
server=8.8.4.4
# 缓存大小(0=禁用)
cache-size=10000
# 最小 TTL(防止过短 TTL)
min-cache-ttl=60
# 最大 TTL(防止过长 TTL)
max-cache-ttl=86400
# 记录查询日志
log-queries
# 启用 DNSSEC
dnssec
dnssec-check-dummies
EOF
systemctl restart dnsmasq
# 修改系统 DNS 配置
echo “nameserver 127.0.0.1“ > /etc/resolv.conf
# ============================================================
# 策略 3:使用 nscd 缓存
# ============================================================
# 安装 nscd
apt install nscd
# 配置 nscd
cat > /etc/nscd.conf << EOF
persistent hosts yes
shared hosts yes
max-db-size hosts 33554432
positive-time-to-live hosts 3600
negative-time-to-live hosts 20
suggested-size hosts 211
check-files hosts yes
EOF
systemctl restart nscd
# ============================================================
# 策略 4:应用层缓存优化
# ============================================================
# Go 语言 DNS 缓存示例
package main
import (
“context“
“fmt“
“net“
“time“
)
// 带缓存的 DNS 解析器
type CachedResolver struct {
cache map[string]cacheEntry
ttl time.Duration
}
type cacheEntry struct {
ips []string
expireAt time.Time
}
func NewCachedResolver(ttl time.Duration) *CachedResolver {
return &CachedResolver{
cache: make(map[string]cacheEntry),
ttl: ttl,
}
}
func (r *CachedResolver) Lookup(ctx context.Context, host string) ([]string, error) {
// 检查缓存
if entry, ok := r.cache[host]; ok {
if time.Now().Before(entry.expireAt) {
return entry.ips, nil
}
delete(r.cache, host)
}
// DNS 查询
ips, err := net.LookupHost(host)
if err != nil {
return nil, err
}
// 存入缓存
r.cache[host] = cacheEntry{
ips: ips,
expireAt: time.Now().Add(r.ttl),
}
return ips, nil
}
五、DNS 安全与攻击防护
5.1 DNS 安全威胁
┌─────────────────────────────────────────────────────────────────┐
│ DNS 安全威胁全景 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ │
│ │ DNS 欺骗 │ 攻击者伪造 DNS 响应,返回恶意 IP │
│ │ (Spoofing) │ 危害:用户被导向钓鱼网站 │
│ └─────────────┘ │
│ │
│ ┌─────────────┐ │
│ │ DNS 缓存 │ 污染 DNS 服务器缓存,影响所有用户 │
│ │ 投毒 │ 危害:大规模用户被重定向 │
│ │ (Poisoning) │ │
│ └─────────────┘ │
│ │
│ ┌─────────────┐ │
│ │ DNS 隧道 │ 利用 DNS 协议传输数据,绕过防火墙 │
│ │ (Tunneling) │ 危害:数据泄露、C&C 通信 │
│ └─────────────┘ │
│ │
│ ┌─────────────┐ │
│ │ DDoS 攻击 │ 大量 DNS 请求耗尽服务器资源 │
│ │ (Amplification)│ 危害:服务不可用 │
│ └─────────────┘ │
│ │
│ ┌─────────────┐ │
│ │ 域名劫持 │ 篡改域名注册信息或 DNS 配置 │
│ │ (Hijacking) │ 危害:整个域名被控制 │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
5.2 DNSSEC - DNS 安全扩展
┌─────────────────────────────────────────────────────────────────┐
│ DNSSEC 工作原理 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 传统 DNS(无签名): │
│ 客户端 ──▶ DNS 服务器 ──▶ 返回结果(无法验证真伪) │
│ │
│ DNSSEC(数字签名): │
│ 客户端 ──▶ DNS 服务器 ──▶ 返回结果 + 数字签名 │
│ │ │ │
│ │ │ 签名链: │
│ │ │ 根 → TLD → 权威 │
│ │ ▼ │
│ │ ┌───────────┐ │
│ │ │ DNSKEY │ 公钥 │
│ │ │ RRSIG │ 资源记录签名 │
│ │ │ DS │ 委托签名者 │
│ │ └───────────┘ │
│ │ │
│ └──────▶ 验证签名(信任链验证) │
│ │
└─────────────────────────────────────────────────────────────────┘
DNSSEC 配置与验证
# ============================================================
# 检查域名是否启用 DNSSEC
# ============================================================
# 方法 1:使用 dig
dig +dnssec example.com | grep flags
# 输出:flags: qr rd ra ad; # ad 标志表示 DNSSEC 验证通过
# 方法 2:使用 dnssec-analyzer
dnssec-analyzer.com example.com
# 方法 3:使用 Verisign 工具
# https://dnssec-debugger.verisignlabs.com/
# ============================================================
# 启用 DNSSEC(以 Bind 为例)
# ============================================================
# 1. 生成密钥
dnssec-keygen -a RSASHA256 -b 2048 -n ZONE example.com
# 2. 签名区域
dnssec-signzone -S -3 $(head -c 100 /dev/urandom | sha1sum | cut -b 1-16) example.com
# 3. 配置 Bind
cat >> /etc/bind/named.conf << EOF
zone “example.com“ {
type master;
file “/etc/bind/db.example.com.signed“;
auto-dnssec maintain;
inline-signing yes;
};
EOF
# 4. 重启 Bind
systemctl restart bind9
# ============================================================
# 客户端启用 DNSSEC 验证
# ============================================================
# systemd-resolved 配置
cat > /etc/systemd/resolved.conf << EOF
[Resolve]
DNSSEC=yes
DNSOverTLS=yes
EOF
systemctl restart systemd-resolved
# 验证 DNSSEC
resolvectl status | grep DNSSEC
5.3 DNS over TLS/HTTPS - 加密 DNS
┌─────────────────────────────────────────────────────────────────┐
│ 加密 DNS 协议对比 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 传统 DNS (UDP 53): │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 查询:www.example.com │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ 明文传输(可被监听、篡改) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ DNS over TLS (TCP 853): │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 查询:[TLS 加密] www.example.com │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ TLS 加密通道(防监听、防篡改) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ DNS over HTTPS (TCP 443): │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 查询:[HTTPS 加密] www.example.com │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ HTTPS 请求(伪装成普通 Web 流量) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
DoT/DoH 配置
# ============================================================
# systemd-resolved 启用 DNS over TLS
# ============================================================
cat > /etc/systemd/resolved.conf << EOF
[Resolve]
# 支持 DoT 的 DNS 服务器
DNS=1.1.1.1 1.0.0.1 8.8.8.8
# DNS over TLS 模式
DNSOverTLS=yes
# DNSSEC 验证
DNSSEC=yes
EOF
systemctl restart systemd-resolved
# 验证
resolvectl status
# ============================================================
# 使用 stubby(DoT 代理)
# ============================================================
# 安装 stubby
apt install stubby
# 配置 stubby
cat > /etc/stubby/stubby.yml << EOF
resolution_type: GETDNS_RESOLUTION_STUB
dns_transport_list:
- GETDNS_TRANSPORT_TLS
tls_authentication: GETDNS_AUTHENTICATION_REQUIRED
tls_query_padding_blocksize: 256
edns_client_subnet_private: 1
idle_timeout: 10000
listen_addresses:
- 127.0.0.1
- 0::1
round_robin_upstreams: 1
upstream_recursive_servers:
# Cloudflare
- address_data: 1.1.1.1
tls_auth_name: “cloudflare-dns.com“
- address_data: 1.0.0.1
tls_auth_name: “cloudflare-dns.com“
# Google
- address_data: 8.8.8.8
tls_auth_name: “dns.google“
- address_data: 8.8.4.4
tls_auth_name: “dns.google“
EOF
systemctl restart stubby
# 修改系统 DNS
echo “nameserver 127.0.0.1“ > /etc/resolv.conf
# ============================================================
# 使用 dnsmasq + DoH
# ============================================================
# 安装 cloudflared(Cloudflare DoH 代理)
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
chmod +x cloudflared-linux-amd64
mv cloudflared-linux-amd64 /usr/local/bin/cloudflared
# 创建 systemd 服务
cat > /etc/systemd/system/cloudflared.service << EOF
[Unit]
Description=cloudflared DNS over HTTPS proxy
After=network.target
[Service]
Type=simple
User=nobody
ExecStart=/usr/local/bin/cloudflared proxy-dns \
--port 5053 \
--upstream https://1.1.1.1/dns-query \
--upstream https://1.0.0.1/dns-query
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable cloudflared
systemctl start cloudflared
# 配置 dnsmasq 使用 DoH
cat > /etc/dnsmasq.conf << EOF
server=127.0.0.1#5053
EOF
systemctl restart dnsmasq
5.4 DNS 攻击防护
# ============================================================
# 防护 1:防止 DNS 放大攻击
# ============================================================
# 在 Bind 配置中禁用递归查询(对非信任客户端)
cat >> /etc/bind/named.conf.options << EOF
options {
# 限制递归查询
allow-recursion {
127.0.0.1;
192.168.0.0/16;
10.0.0.0/8;
};
# 禁用版本信息
version “not disclosed“;
# 限制查询速率
rate-limit {
responses-per-second 10;
window 5;
};
};
EOF
# ============================================================
# 防护 2:检测 DNS 隧道
# ============================================================
# 使用 dnsdetect 检测异常 DNS 流量
apt install dnsdetect
# 监控 DNS 查询频率
watch -n 1 ‘dig @localhost +short | wc -l‘
# 检查异常长的 DNS 查询
tail -f /var/log/bind9/query.log | grep -E “.{50,}\.example\.com“
# ============================================================
# 防护 3:防止 DNS 劫持
# ============================================================
# 锁定 /etc/resolv.conf
chattr +i /etc/resolv.conf
# 监控 DNS 配置变更
inotifywait -m /etc/resolv.conf -e modify
# 使用静态 DNS 配置
cat > /etc/resolv.conf << EOF
nameserver 8.8.8.8
nameserver 8.8.4.4
EOF
# ============================================================
# 防护 4:监控 DNS 安全
# ============================================================
# 安装 OSSEC(入侵检测系统)
apt install ossec-hids
# 配置 DNS 变更告警
cat >> /var/ossec/etc/ossec.conf << EOF
<syscheck>
<directories check_all=“yes“ report_changes=“yes“>/etc/resolv.conf</directories>
</syscheck>
EOF
# 使用 fail2ban 防止 DNS 暴力破解
apt install fail2ban
cat > /etc/fail2ban/jail.d/dns.conf << EOF
[dns-servers]
enabled = true
filter = dns-servers
logpath = /var/log/bind9/query.log
maxretry = 100
bantime = 3600
EOF
六、DNS 服务器搭建实战
6.1 Bind9 - 经典 DNS 服务器
安装与基础配置
# ============================================================
# 安装 Bind9
# ============================================================
# Debian/Ubuntu
apt update && apt install bind9 bind9utils bind9-doc
# CentOS/RHEL
yum install bind bind-utils
# 检查状态
systemctl status bind9
systemctl enable bind9
# ============================================================
# 基础配置
# ============================================================
# 主配置文件
cat > /etc/bind/named.conf.options << EOF
options {
directory “/var/cache/bind“;
# 监听地址
listen-on port 53 { 127.0.0.1; 192.168.1.1; };
listen-on-v6 port 53 { ::1; };
# 允许查询的客户端
allow-query { localhost; 192.168.1.0/24; };
# 允许递归查询的客户端
allow-recursion { localhost; 192.168.1.0/24; };
# 上游 DNS 服务器
forwarders {
8.8.8.8;
8.8.4.4;
};
# DNSSEC
dnssec-validation auto;
# 日志
querylog yes;
};
EOF
# 重启服务
systemctl restart bind9
# 测试配置
named-checkconf
# ============================================================
# 配置本地域名
# ============================================================
# 添加区域配置
cat >> /etc/bind/named.conf.local << EOF
zone “example.local“ {
type master;
file “/etc/bind/db.example.local“;
};
zone “1.168.192.in-addr.arpa“ {
type master;
file “/etc/bind/db.192“;
};
EOF
# 创建区域文件
cat > /etc/bind/db.example.local << EOF
\$TTL 86400
@ IN SOA ns1.example.local. admin.example.local. (
2024011501 ; Serial
3600 ; Refresh
1800 ; Retry
604800 ; Expire
86400 ) ; Minimum TTL
; 名称服务器
@ IN NS ns1.example.local.
@ IN NS ns2.example.local.
; A 记录
@ IN A 192.168.1.1
ns1 IN A 192.168.1.1
ns2 IN A 192.168.1.2
www IN A 192.168.1.10
api IN A 192.168.1.11
db IN A 192.168.1.12
cache IN A 192.168.1.13
; CNAME 记录
mail IN CNAME @
ftp IN CNAME www
; MX 记录
@ IN MX 10 mail.example.local.
EOF
# 检查配置
named-checkzone example.local /etc/bind/db.example.local
# 重启服务
systemctl restart bind9
# ============================================================
# 测试 DNS 服务器
# ============================================================
# 修改本地 DNS
echo “nameserver 192.168.1.1“ > /etc/resolv.conf
# 查询测试
dig @localhost example.local
dig @localhost www.example.local
dig @localhost -x 192.168.1.10
6.2 dnsmasq - 轻量级 DNS 服务器
# ============================================================
# 安装 dnsmasq
# ============================================================
apt install dnsmasq
# ============================================================
# 基础配置
# ============================================================
cat > /etc/dnsmasq.conf << EOF
# 监听地址
listen-address=127.0.0.1
listen-address=192.168.1.1
# 绑定到特定接口
interface=eth0
except-interface=lo
# 上游 DNS 服务器
server=8.8.8.8
server=8.8.4.4
server=1.1.1.1
# 缓存配置
cache-size=10000
min-cache-ttl=60
max-cache-ttl=86400
# 本地域名
local=/example.local/
domain=example.local
expand-hosts
# 读取 /etc/hosts
addn-hosts=/etc/hosts
# DHCP 配置(可选)
dhcp-range=192.168.1.100,192.168.1.200,12h
dhcp-option=3,192.168.1.1
dhcp-option=6,192.168.1.1
# 日志
log-queries
log-facility=/var/log/dnsmasq.log
# DNSSEC
dnssec
dnssec-check-dummies
EOF
# 重启服务
systemctl restart dnsmasq
# ============================================================
# 添加自定义 DNS 记录
# ============================================================
# 方法 1:添加到 /etc/hosts
cat >> /etc/hosts << EOF
192.168.1.10 www.example.local
192.168.1.11 api.example.local
192.168.1.12 db.example.local
EOF
# 方法 2:使用 addn-hosts
echo “192.168.1.20 test.example.local“ >> /etc/hosts.custom
# 方法 3:直接在配置文件中
cat >> /etc/dnsmasq.conf << EOF
address=/dev.example.local/192.168.1.30
address=/staging.example.local/192.168.1.31
EOF
systemctl restart dnsmasq
# ============================================================
# 测试 dnsmasq
# ============================================================
# 查询测试
dig @localhost www.example.local
dig @localhost +short example.local
# 查看缓存
killall -USR2 dnsmasq
tail -f /var/log/dnsmasq.log
# 监控查询
tail -f /var/log/dnsmasq.log | grep query
6.3 CoreDNS - 云原生 DNS 服务器
# ============================================================
# CoreDNS 特点
# ============================================================
# ✅ 云原生设计,Kubernetes 默认 DNS
# ✅ 插件化架构,灵活扩展
# ✅ 支持多种后端(文件、etcd、Kubernetes 等)
# ✅ 支持 Prometheus 监控
# ✅ 支持 DNS over TLS/HTTPS
# ============================================================
# 安装 CoreDNS
# ============================================================
# 下载二进制
wget https://github.com/coredns/coredns/releases/latest/download/coredns_linux_amd64.tgz
tar xzf coredns_linux_amd64.tgz
mv coredns /usr/local/bin/
# ============================================================
# 基础配置
# ============================================================
cat > /etc/coredns/Corefile << EOF
# 全局配置
{
log
errors
health
prometheus :9153
cache 30
reload
}
# example.local 区域
example.local {
file /etc/coredns/db.example.local
errors
log
}
# 转发其他查询到上游 DNS
. {
forward . 8.8.8.8 8.8.4.4
cache 30
}
EOF
# 创建区域文件
cat > /etc/coredns/db.example.local << EOF
\$TTL 3600
@ IN SOA ns1.example.local. admin.example.local. (
2024011501
3600
1800
604800
86400 )
@ IN NS ns1.example.local.
ns1 IN A 192.168.1.1
www IN A 192.168.1.10
api IN A 192.168.1.11
EOF
# ============================================================
# 创建 systemd 服务
# ============================================================
cat > /etc/systemd/system/coredns.service << EOF
[Unit]
Description=CoreDNS
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/coredns -conf /etc/coredns/Corefile
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable coredns
systemctl start coredns
# ============================================================
# Kubernetes 中的 CoreDNS
# ============================================================
# 查看 CoreDNS 配置
kubectl get configmap coredns -n kube-system -o yaml
# 编辑 CoreDNS 配置
kubectl edit configmap coredns -n kube-system
# 添加自定义域名
# .:53 {
# forward . 8.8.8.8
# cache 30
# }
# example.local {
# kubernetes cluster.local in-addr.arpa ip6.arpa
# forward . 192.168.1.1
# }
# 测试 CoreDNS
kubectl run -it --rm dns-test --image=busybox:1.28 --restart=Never -- nslookup kubernetes
七、故障排查实战案例
7.1 案例 1:域名解析超时
问题现象
# 用户报告:访问网站很慢,有时超时
curl -v https://www.example.com
# 输出:Trying... 长时间等待
# 检查 DNS 解析时间
time dig www.example.com
# 输出:Query time: 5000 msec(异常慢)
排查步骤
# 步骤 1:检查本地 DNS 配置
cat /etc/resolv.conf
# 检查 nameserver 是否可达
# 步骤 2:测试 DNS 服务器连通性
for dns in $(grep nameserver /etc/resolv.conf | awk ‘{print $2}‘); do
echo “Testing $dns...“
time dig @$dns www.example.com +short
done
# 步骤 3:检查 DNS 服务器响应
systemctl status systemd-resolved
resolvectl statistics
# 步骤 4:检查网络连接
ping -c 3 8.8.8.8
mtr 8.8.8.8
# 步骤 5:检查是否有 DNS 污染
dig @8.8.8.8 www.example.com +short
dig @114.114.114.114 www.example.com +short
# 比较结果是否一致
# 步骤 6:检查本地缓存
resolvectl flush-caches
time dig www.example.com +short
解决方案
# 方案 1:更换 DNS 服务器
cat > /etc/resolv.conf << EOF
nameserver 8.8.8.8
nameserver 8.8.4.4
nameserver 1.1.1.1
options timeout:2
options attempts:2
options rotate
EOF
# 方案 2:部署本地 DNS 缓存
apt install dnsmasq
systemctl restart dnsmasq
echo “nameserver 127.0.0.1“ > /etc/resolv.conf
# 方案 3:优化 nsswitch 配置
cat /etc/nsswitch.conf | grep hosts
# 确保:hosts: files dns myhostname
# 方案 4:禁用 IPv6 DNS(如果不需要)
cat > /etc/gai.conf << EOF
precedence ::ffff:0:0/96 100
EOF
7.2 案例 2:内部域名无法解析
问题现象
# 用户报告:内部系统无法访问
curl http://api.internal.example.com
# 输出:Could not resolve host
# 外部域名正常
curl http://www.google.com
# 正常访问
排查步骤
# 步骤 1:检查域名类型
domain=api.internal.example.com
dots=$(echo “$domain“ | tr -cd ‘.‘ | wc -c)
echo “Domain has $dots dots“
# 步骤 2:检查 ndots 设置
grep options /etc/resolv.conf
# 如果 ndots 设置过高,可能导致问题
# 步骤 3:检查搜索域配置
cat /etc/resolv.conf | grep search
# 步骤 4:测试完整域名查询
dig api.internal.example.com +short
# 步骤 5:检查 /etc/hosts
grep “api.internal“ /etc/hosts
# 步骤 6:检查内部 DNS 服务器
dig @internal-dns.example.com api.internal.example.com
解决方案
# 方案 1:添加搜索域
cat > /etc/resolv.conf << EOF
nameserver 192.168.1.1
search internal.example.com example.com
options ndots:2
EOF
# 方案 2:添加到 /etc/hosts
echo “192.168.1.11 api.internal.example.com api“ >> /etc/hosts
# 方案 3:配置 dnsmasq 处理内部域名
cat >> /etc/dnsmasq.conf << EOF
# 内部域名直接转发到内部 DNS
server=/internal.example.com/192.168.1.1
EOF
systemctl restart dnsmasq
# 方案 4:使用 split-horizon DNS
# 在 Bind 中配置视图
cat >> /etc/bind/named.conf << EOF
view “internal“ {
match-clients { 192.168.0.0/16; localhost; };
zone “example.com“ {
file “/etc/bind/db.example.internal“;
};
};
view “external“ {
match-clients { any; };
zone “example.com“ {
file “/etc/bind/db.example.external“;
};
};
EOF
7.3 案例 3:DNS 解析不一致
问题现象
# 不同服务器解析结果不同
# Server 1
dig www.example.com +short
# 输出:192.0.2.1
# Server 2
dig www.example.com +short
# 输出:192.0.2.2
# 用户报告:有时访问正常,有时 404
排查步骤
# 步骤 1:检查多台服务器 DNS 配置
for server in server1 server2 server3; do
echo “=== $server ===“
ssh $server “cat /etc/resolv.conf“
ssh $server “dig www.example.com +short“
done
# 步骤 2:检查 DNS 轮询
dig www.example.com +noall +answer
# 查看是否有多个 A 记录
# 步骤 3:检查 CDN 配置
# CDN 通常会根据地理位置返回不同 IP
# 步骤 4:检查 DNS 缓存
for server in server1 server2 server3; do
ssh $server “resolvectl flush-caches“
done
# 步骤 5:追踪解析链
dig +trace www.example.com
解决方案
# 方案 1:统一 DNS 配置
# 在所有服务器上使用相同的 DNS 配置
cat > /etc/resolv.conf << EOF
nameserver 8.8.8.8
nameserver 8.8.4.4
EOF
# 方案 2:使用 DNS 轮询(负载均衡)
# 在 DNS 服务器配置多个 A 记录
www.example.com. 300 IN A 192.0.2.1
www.example.com. 300 IN A 192.0.2.2
www.example.com. 300 IN A 192.0.2.3
# 方案 3:使用 GeoDNS
# 根据地理位置返回不同 IP
# 需要 DNS 服务商支持
# 方案 4:应用层处理
# 在应用中使用固定的服务发现机制
# 如 Consul、etcd 等
7.4 案例 4:Kubernetes 中 DNS 解析失败
问题现象
# Pod 内无法解析服务名
kubectl exec -it my-pod -- nslookup kubernetes
# 输出:nslookup: can‘t resolve ‘kubernetes‘
# 无法解析外部域名
kubectl exec -it my-pod -- nslookup www.google.com
# 输出:nslookup: can‘t resolve ‘www.google.com‘
排查步骤
# 步骤 1:检查 CoreDNS Pod 状态
kubectl get pods -n kube-system -l k8s-app=kube-dns
# 步骤 2:查看 CoreDNS 日志
kubectl logs -n kube-system -l k8s-app=kube-dns
# 步骤 3:检查 CoreDNS 配置
kubectl get configmap coredns -n kube-system -o yaml
# 步骤 4:检查 Pod DNS 配置
kubectl exec my-pod -- cat /etc/resolv.conf
# 步骤 5:测试 CoreDNS 连通性
kubectl exec -it my-pod -- dig @10.96.0.10 kubernetes
# 步骤 6:检查 NetworkPolicy
kubectl get networkpolicy -A
解决方案
# 方案 1:重启 CoreDNS
kubectl rollout restart deployment coredns -n kube-system
# 方案 2:修复 CoreDNS 配置
kubectl edit configmap coredns -n kube-system
# 确保配置正确
# 方案 3:增加 CoreDNS 副本
kubectl scale deployment coredns -n kube-system --replicas=3
# 方案 4:调整 Pod DNS 策略
cat > pod-dns-config.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: dns-test
spec:
dnsPolicy: ClusterFirst
dnsConfig:
options:
- name: ndots
value: “2“
- name: timeout
value: “2“
containers:
- name: test
image: busybox
command: [“sleep“, “3600“]
EOF
kubectl apply -f pod-dns-config.yaml
# 方案 5:检查节点 DNS 配置
# 确保节点 /etc/resolv.conf 正确
cat /etc/resolv.conf
八、生产环境最佳实践
8.1 DNS 配置检查清单
□ 使用可靠的公共 DNS 或自建 DNS 服务器
□ 配置至少 2 个 DNS 服务器(主备)
□ 启用 DNSSEC 验证
□ 部署本地 DNS 缓存(dnsmasq/systemd-resolved)
□ 合理设置 TTL 值
□ 配置 nsswitch.conf 确保 hosts 优先
□ 监控 DNS 解析延迟和成功率
□ 定期审计 DNS 配置
□ 实施 DNS 查询日志
□ 配置 DNS 告警阈值
8.2 DNS 监控方案
# ============================================================
# 方案 1:使用 Prometheus + Blackbox Exporter
# ============================================================
# 安装 Blackbox Exporter
wget https://github.com/prometheus/blackbox_exporter/releases/latest/download/blackbox_exporter-linux-amd64.tar.gz
tar xzf blackbox_exporter*.tar.gz
mv blackbox_exporter /usr/local/bin/
# 配置
cat > /etc/blackbox_exporter/config.yml << EOF
modules:
dns_tcp:
prober: dns
timeout: 5s
dns:
transport_protocol: “tcp“
query_type: “A“
query_name: “www.example.com“
dns_udp:
prober: dns
timeout: 5s
dns:
transport_protocol: “udp“
query_type: “A“
query_name: “www.example.com“
EOF
# Prometheus 配置
cat >> /etc/prometheus/prometheus.yml << EOF
scrape_configs:
- job_name: ‘blackbox_dns‘
metrics_path: /probe
params:
module: [dns_udp]
static_configs:
- targets:
- 8.8.8.8
- 8.8.4.4
- 1.1.1.1
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9115
EOF
# ============================================================
# 方案 2:自定义 DNS 监控脚本
# ============================================================
cat > /usr/local/bin/dns-monitor.sh << ‘EOF‘
#!/bin/bash
DOMAINS=(“www.example.com“ “api.example.com“ “db.example.local“)
DNS_SERVERS=(“8.8.8.8“ “8.8.4.8“ “1.1.1.1“)
LOG_FILE=“/var/log/dns-monitor.log“
ALERT_THRESHOLD=1000 # ms
log() {
echo “$(date ‘+%Y-%m-%d %H:%M:%S‘) $1“ >> $LOG_FILE
}
for domain in “${DOMAINS[@]}“; do
for dns in “${DNS_SERVERS[@]}“; do
start=$(date +%s%N)
result=$(dig @$dns $domain +short +time=2 2>/dev/null)
end=$(date +%s%N)
latency=$(( (end - start) / 1000000 ))
if [ -z “$result“ ]; then
log “ALERT: $domain resolution failed on $dns“
# 发送告警
# curl -X POST https://alert-webhook/...
elif [ $latency -gt $ALERT_THRESHOLD ]; then
log “WARNING: $domain on $dns latency ${latency}ms > ${ALERT_THRESHOLD}ms“
else
log “OK: $domain on $dns latency ${latency}ms“
fi
done
done
EOF
chmod +x /usr/local/bin/dns-monitor.sh
# 添加到 crontab
echo “*/5 * * * * /usr/local/bin/dns-monitor.sh“ | crontab -
# ============================================================
# 方案 3:使用 datadog/sensu 等监控平台
# ============================================================
# 配置 DNS 检查
cat > /etc/datadog-agent/conf.d/dns_check.d/conf.yaml << EOF
init_config:
instances:
- name: example.com
hostname: www.example.com
nameserver: 8.8.8.8
record_type: A
timeout: 5
tags:
- env:production
- service:dns
EOF
8.3 DNS 性能优化
# ============================================================
# 优化 1:部署本地 DNS 缓存
# ============================================================
# 减少外部 DNS 查询,降低延迟
apt install dnsmasq
cat > /etc/dnsmasq.conf << EOF
cache-size=10000
min-cache-ttl=60
max-cache-ttl=86400
server=8.8.8.8
server=8.8.4.4
EOF
# ============================================================
# 优化 2:使用 Anycast DNS
# ============================================================
# 多个地理位置的 DNS 服务器使用相同 IP
# 用户自动连接到最近的服务器
# ============================================================
# 优化 3:DNS 预取
# ============================================================
# 在 HTML 中添加 DNS 预取提示
# <link rel=“dns-prefetch“ href=“//cdn.example.com“>
# <link rel=“dns-prefetch“ href=“//api.example.com“>
# ============================================================
# 优化 4:减少 DNS 查询次数
# ============================================================
# 使用域名拼接,减少 CNAME 链
# 避免:www → cdn → cloudfront → actual-ip
# 建议:www → actual-ip
# 合并资源到同一域名
# 避免:img1.example.com, img2.example.com
# 建议:img.example.com(使用 CDN)
# ============================================================
# 优化 5:TCP 连接复用
# ============================================================
# 启用 HTTP Keep-Alive
# 减少 DNS 查询后的连接建立时间
8.4 高可用 DNS 架构
┌─────────────────────────────────────────────────────────────────┐
│ 生产环境 DNS 高可用架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 客户端 │
│ │ │
│ ┌────────────┼────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Local │ │ Local │ │ Local │ │
│ │ DNS │ │ DNS │ │ DNS │ │
│ │ Cache │ │ Cache │ │ Cache │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └────────────┼────────────┘ │
│ │ │
│ ┌───────────┴───────────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Primary │ │ Secondary│ │
│ │ DNS │ ◀────────▶│ DNS │ │
│ │ Server │ 区域传输 │ Server │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ └───────────┬───────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ Upstream│ │
│ │ DNS │ │
│ │ (Public)│ │
│ └──────────┘ │
│ │
│ 关键配置: │
│ 1. 本地缓存:dnsmasq/systemd-resolved │
│ 2. 主从 DNS:Bind9 区域传输 │
│ 3. 上游 DNS:多个公共 DNS(8.8.8.8, 1.1.1.1, 9.9.9.9) │
│ 4. 健康检查:监控 DNS 服务器可用性 │
│ 5. 自动故障转移:DNS 轮询 + 健康检查 │
│ │
└─────────────────────────────────────────────────────────────────┘
九、总结
9.1 核心要点回顾
- DNS 是基础设施:看似简单,实则关键,直接影响用户体验
- 理解解析流程:掌握递归查询、缓存机制、TTL 概念
- 合理配置:/etc/resolv.conf、nsswitch.conf、systemd-resolved
- 熟练使用工具:dig、nslookup、host、resolvectl
- 安全防护:DNSSEC、DoT/DoH、防攻击措施
- 监控告警:实时监控 DNS 解析延迟和成功率
- 高可用设计:本地缓存 + 主从 DNS + 上游多 DNS
9.2 常用命令速查
# DNS 查询
dig domain.com # 标准查询
dig +short domain.com # 简洁输出
dig +trace domain.com # 追踪解析链
dig @8.8.8.8 domain.com # 指定 DNS 服务器
# 缓存管理
resolvectl flush-caches # 刷新 systemd-resolved 缓存
nscd -i hosts # 刷新 nscd 缓存
killall -USR2 dnsmasq # 刷新 dnsmasq 缓存
# 状态检查
resolvectl status # 查看 DNS 状态
cat /etc/resolv.conf # 查看 DNS 配置
cat /etc/nsswitch.conf # 查看解析顺序
# 服务管理
systemctl status systemd-resolved
systemctl restart dnsmasq
systemctl restart bind9
9.3 推荐工具
| 工具 |
用途 |
| dig/nslookup |
DNS 查询 |
| Wireshark |
DNS 流量分析 |
| dnsperf |
DNS 性能测试 |
| dnsmasq |
本地 DNS 缓存 |
| CoreDNS |
云原生 DNS |
| Prometheus + Blackbox |
DNS 监控 |
希望这份完整的 Linux DNS 指南能帮助你在生产环境中更好地理解、配置和排查 DNS 相关问题。理论结合实战,是掌握技术的关键。如果你在实践中遇到更多有趣的问题或经验,欢迎到 云栈社区 的 网络/系统 板块与大家一起交流讨论。