DNS 域名解析
DNS 解析流程
DNS 缓存层级
DNS 查询会依次经过多级缓存:
- 浏览器缓存(Chrome:
chrome://net-internals/#dns) - 操作系统缓存(
nscd/systemd-resolved) - 路由器缓存
- 递归解析器缓存(ISP DNS / 公共 DNS)
DNS 记录类型
| 记录类型 | 说明 | 示例 | 使用场景 |
|---|---|---|---|
| A | IPv4 地址 | example.com → 93.184.216.34 | 基础域名解析 |
| AAAA | IPv6 地址 | example.com → 2606:2800:... | IPv6 支持 |
| CNAME | 别名 | www → example.com | CDN、别名 |
| MX | 邮件服务器 | example.com → mail.example.com | 邮件路由 |
| TXT | 文本记录 | v=spf1 include:... | SPF/DKIM/域名验证 |
| NS | 域名服务器 | example.com → ns1.dns.com | DNS 授权 |
| SRV | 服务记录 | _sip._tcp.example.com | 服务发现 |
| PTR | 反向解析 | 34.216.184.93 → example.com | 反垃圾邮件 |
| SOA | 起始授权 | 序列号、刷新间隔 | 区域传输 |
| CAA | CA 授权 | 0 issue "letsencrypt.org" | 证书申请限制 |
CNAME 限制
- 根域名(
example.com)不能设 CNAME,必须用 A 记录 - CNAME 不能与其他记录共存(如 MX)
- 解决方案:使用 ALIAS/ANAME(部分 DNS 提供商支持)
DNS 排查工具
dig 命令
# 基本查询
dig example.com
# 查询特定记录类型
dig example.com A # IPv4 地址
dig example.com AAAA # IPv6 地址
dig example.com MX # 邮件服务器
dig example.com NS # 域名服务器
dig example.com TXT # TXT 记录
dig example.com ANY # 所有记录
# 指定 DNS 服务器查询
dig @8.8.8.8 example.com
dig @1.1.1.1 example.com
# 简洁输出(只看结果)
dig +short example.com
# 完整解析链路追踪(排查必备)
dig +trace example.com
# 反向解析
dig -x 93.184.216.34
# 查看 DNSSEC 信息
dig +dnssec example.com
dig +trace 输出解读
$ dig +trace www.example.com
# 1. 根域名服务器
. IN NS a.root-servers.net.
# 2. TLD 服务器
com. IN NS a.gtld-servers.net.
# 3. 权威 DNS
example.com. IN NS ns1.example.com.
# 4. 最终结果
www.example.com. IN A 93.184.216.34
nslookup
# 交互式查询
nslookup
> set type=MX
> example.com
# 非交互式
nslookup example.com
nslookup -type=MX example.com
nslookup example.com 8.8.8.8 # 指定 DNS 服务器
host 命令
host example.com
host -t MX example.com
host -t TXT example.com
DNS 服务器配置
/etc/resolv.conf
/etc/resolv.conf
# DNS 搜索域(短名补全)
search example.com internal.example.com
# DNS 服务器(最多 3 个,按顺序查询)
nameserver 8.8.8.8
nameserver 8.8.4.4
nameserver 1.1.1.1
# 选项
options timeout:2 attempts:3 rotate
# timeout: 超时时间(秒)
# attempts: 重试次数
# rotate: 轮询使用多个 nameserver
resolv.conf 被覆盖
很多系统由 NetworkManager 或 systemd-resolved 自动管理 /etc/resolv.conf:
# systemd-resolved(Ubuntu 18+)
# 查看实际 DNS 配置
resolvectl status
# 修改 DNS
# 编辑 /etc/systemd/resolved.conf
[Resolve]
DNS=8.8.8.8 1.1.1.1
FallbackDNS=8.8.4.4
systemctl restart systemd-resolved
# NetworkManager
nmcli con mod "连接名" ipv4.dns "8.8.8.8 1.1.1.1"
nmcli con up "连接名"
常用公共 DNS
| DNS 服务 | IPv4 | IPv6 | 特点 |
|---|---|---|---|
| 8.8.8.8 / 8.8.4.4 | 2001:4860:4860::8888 | 全球覆盖 | |
| Cloudflare | 1.1.1.1 / 1.0.0.1 | 2606:4700:4700::1111 | 速度快、隐私保护 |
| 阿里 DNS | 223.5.5.5 / 223.6.6.6 | — | 国内优选 |
| 腾讯 DNS | 119.29.29.29 | — | 国内备选 |
DNS 高级配置
本地 DNS 缓存(systemd-resolved)
# 查看缓存统计
resolvectl statistics
# 清除 DNS 缓存
resolvectl flush-caches
# 或
systemd-resolve --flush-caches
# Mac 清除 DNS 缓存
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
/etc/hosts 本地解析
/etc/hosts
# 格式:IP 域名 别名
127.0.0.1 localhost
192.168.1.100 db.internal.example.com db
# 用途:
# 1. 测试环境域名解析
# 2. 屏蔽恶意域名
# 3. 开发环境本地域名
解析优先级
/etc/hosts > DNS 缓存 > DNS 服务器
由 /etc/nsswitch.conf 中的 hosts: 行控制:
hosts: files dns myhostname
# files = /etc/hosts 先查
# dns = DNS 服务器后查
DNS 常见故障排查
常见问题与解决
| 问题 | 可能原因 | 排查命令 |
|---|---|---|
| 解析超时 | DNS 服务器不可达 | dig @8.8.8.8 domain |
| 解析为错误 IP | DNS 缓存污染 / 劫持 | dig +trace domain |
| 部分用户无法解析 | TTL 缓存未过期 | dig +short domain @各地DNS |
| CNAME 循环 | 配置错误 | dig +trace domain |
| NXDOMAIN | 域名不存在或过期 | whois domain |
常见面试问题
Q1: DNS 解析的完整流程?
答案:
- 浏览器先查本地缓存(浏览器 → OS → hosts 文件)
- 未命中则向配置的递归解析器(如 8.8.8.8)发起查询
- 递归解析器如果没缓存,依次向根域名服务器、TLD 服务器、权威 DNS 发起迭代查询
- 权威 DNS 返回最终结果
- 递归解析器缓存结果(按 TTL),返回给客户端
Q2: DNS 记录的 TTL 是什么?如何利用 TTL 做平滑切换?
答案:
TTL(Time To Live)是 DNS 记录的缓存时间,单位是秒。
平滑切换策略:
- 切换前 1-2 天,将 TTL 从默认值(如 3600s)降低到 60s
- 等待旧 TTL 时间过去,确保全网缓存刷新
- 修改 DNS 记录指向新 IP
- 确认切换成功后,将 TTL 恢复到正常值
Q3: DNS 劫持和 DNS 污染的区别?
答案:
- DNS 劫持:中间设备(路由器/ISP)拦截 DNS 请求,返回篡改的结果。通常将域名解析到广告页面或钓鱼网站。解决:使用 HTTPS DNS (DoH) 或 DNS over TLS (DoT)。
- DNS 污染:向 DNS 查询注入虚假响应。攻击者监听 DNS 查询并抢先返回伪造结果。解决:使用 DNSSEC 验证。
Q4: A 记录和 CNAME 记录的区别?什么时候用哪个?
答案:
- A 记录:直接映射域名到 IP 地址。变更 IP 时需要修改 A 记录。
- CNAME 记录:映射域名到另一个域名(别名)。目标域名的 IP 变化时无需修改 CNAME。
使用建议:
- 根域名(
example.com)只能用 A 记录 - CDN 接入通常用 CNAME(指向 CDN 提供的域名)
- 需要固定 IP 时用 A 记录
- 多个子域名指向同一服务时用 CNAME