DNS(Domain Name System)是互联网最基础的服务之一,负责将域名解析为 IP 地址。DNS 故障会导致用户无法访问网站、应用无法连接后端服务、邮件无法发送等问题。
常见 DNS 故障表现:
ping 域名失败,但 ping IP 成功DNS 故障排查需要理解 DNS 工作原理、记录类型、查询流程、缓存机制,以及掌握常用排查工具和方法。
本文适用于以下场景:
本文涵盖 DNS 基础原理、记录类型、查询流程、常用工具、故障排查方法和安全防护。
域名结构:
域名是分层结构,从右到左依次为:
www.example.com. . 根域(Root Domain)com 顶级域(Top-Level Domain, TLD)example 二级域(Second-Level Domain)www 三级域或主机名(Subdomain / Hostname)DNS 服务器类型:
.com、.org)的权威服务器地址DNS 解析类型:
常见 DNS 记录类型:
| 记录类型 | 说明 | 示例 |
|---|---|---|
| A | 将域名解析为 IPv4 地址 |
example.com -> 192.0.2.1 |
| AAAA | 将域名解析为 IPv6 地址 |
example.com -> 2001:1 |
| CNAME | 将域名指向另一个域名(别名) |
www.example.com -> example.com |
| MX | 邮件交换记录,指定邮件服务器 |
example.com -> mail.example.com |
| TXT | 文本记录,用于 SPF、DKIM、域名验证等 |
example.com -> "v=spf1 ..." |
| NS | 指定域名的权威服务器 |
example.com -> ns1.example.com |
| SOA | 起始授权记录,包含域名管理信息 | 序列号、刷新时间、重试时间、过期时间、TTL |
| PTR | 反向解析,IP 地址到域名 |
1.2.0.192.in-addr.arpa -> example.com |
| SRV | 服务记录,指定服务的主机和端口 |
_http._tcp.example.com -> server.example.com:80 |
| CAA | 证书颁发机构授权记录 |
example.com -> issue "letsencrypt.org" |
完整的 DNS 查询流程(以查询 www.example.com 为例):
.com 顶级域服务器地址.com 服务器查询,返回 example.com 权威服务器地址example.com 权威服务器查询,返回 www.example.com 的 A 记录客户端 → 递归服务器 → 根服务器 → TLD 服务器 → 权威服务器 → 递归服务器 → 客户端 DNS 缓存存在于多个层级:
TTL(Time To Live):
轮询(Round Robin):
地理位置解析(GeoIP):
智能解析:
DNS 故障排查流程:
确认现象 → 本地排查 → 递归服务器排查 → 权威服务器排查 → 网络路径排查 → 缓存排查 → 配置排查 → 验证修复 关键步骤:
bash
ping www.example.com 如果提示"无法解析主机名"或"Name or service not known",可能是 DNS 问题。
bash
curl http://www.example.com 如果提示"Could not resolve host",可能是 DNS 问题。
假设 www.example.com 的 IP 是 192.0.2.1:
bash
ping 192.0.2.1
如果 ping IP 成功,但 ping 域名失败,说明是 DNS 问题。
bash
curl http://192.0.2.1 如果访问 IP 成功,但访问域名失败,说明是 DNS 问题。
bash
nslookup www.example.com 如果返回"Non-existent domain"或"NXDOMAIN",说明域名不存在或 DNS 记录未配置。
如果返回"Timeout"或"Connection timed out",说明 DNS 服务器无响应。
如果返回 IP 地址,说明解析成功。
bash
dig www.example.com 观察输出:
status: NOERROR:解析成功status: NXDOMAIN:域名不存在status: SERVFAIL:服务器故障status: REFUSED:服务器拒绝查询如果没有 ANSWER SECTION,说明没有解析到记录。
Linux:
bash
cat /etc/resolv.conf 输出示例:
nameserver 8.8.8.8 nameserver 8.8.4.4
nameserver 指定 DNS 服务器地址。
Windows:
cmd
ipconfig /all 查看"DNS 服务器"项。
macOS:
bash
scutil --dns 查看 DNS 配置。
bash
ping 8.8.8.8 确认 DNS 服务器网络可达。
bash
nslookup www.example.com 8.8.8.8 指定 DNS 服务器查询,确认服务器是否可用。
Linux/macOS:
bash
cat /etc/hosts Windows:
cmd
type C:WindowsSystem32driversetchosts
hosts 文件中的记录优先级高于 DNS,检查是否有错误配置。
示例:
127.0.0.1 localhost 192.0.2.1 www.example.com
如果 hosts 文件中有错误记录,会导致解析错误。
确认防火墙没有阻止 DNS 查询(UDP 53 和 TCP 53):
bash
iptables -L -n | grep 53 如果有 DROP 或 REJECT 规则,可能会阻止 DNS 查询。
基本用法:
bash
nslookup www.example.com 指定 DNS 服务器:
bash
nslookup www.example.com 8.8.8.8 查询特定记录类型:
bash
nslookup -type=MX example.com nslookup -type=TXT example.com nslookup -type=NS example.com 交互模式:
bash
nslookup > server 8.8.8.8 > set type=A > www.example.com > exit 基本用法:
bash
dig www.example.com 输出解析详细信息,包括查询时间、服务器地址、应答记录。
指定 DNS 服务器:
bash
dig @8.8.8.8 www.example.com 查询特定记录类型:
bash
dig example.com MX dig example.com TXT dig example.com NS dig example.com SOA 简化输出:
bash
dig www.example.com +short 仅输出解析结果。
追踪查询路径:
bash
dig www.example.com +trace 显示完整的递归查询过程,从根服务器开始。
查看 TTL:
bash
dig www.example.com +noall +answer 基本用法:
bash
host www.example.com 输出简洁的解析结果。
指定 DNS 服务器:
bash
host www.example.com 8.8.8.8 查询特定记录类型:
bash
host -t MX example.com host -t TXT example.com host -t NS example.com 反向解析:
bash
host 192.0.2.1 查询域名注册信息:
bash
whois example.com 输出域名注册商、注册时间、过期时间、NS 服务器等信息。
如果域名过期,会显示"Domain Status: clientHold"或类似状态。
使用在线工具从不同地理位置查询 DNS:
这些工具可以检测 DNS 解析在全球的传播情况。
bash
dig @8.8.8.8 www.example.com 指定公共 DNS 服务器(例如 Google DNS 8.8.8.8)查询。
如果公共 DNS 可以解析,但本地 DNS 不能,说明本地 DNS 服务器有问题。
常见公共 DNS 服务器:
如果使用自建 DNS 服务器(例如 BIND、dnsmasq、unbound),检查配置文件。
BIND 配置文件:
bash
cat /etc/named.conf cat /etc/bind/named.conf 检查:
dnsmasq 配置文件:
bash
cat /etc/dnsmasq.conf 检查:
BIND 日志:
bash
tail -f /var/log/named.log tail -f /var/log/syslog | grep named dnsmasq 日志:
bash
tail -f /var/log/dnsmasq.log tail -f /var/log/syslog | grep dnsmasq 查找错误信息、查询失败记录。
bash
dig @localhost www.example.com | grep "Query time" 查看查询时间,如果超过 100ms,可能存在性能问题。
检查服务器资源使用:
bash
top -p $(pidof named) top -p $(pidof dnsmasq) 检查 CPU 和内存使用率。
查询域名的 NS 记录:
bash
dig example.com NS +short 输出示例:
ns1.example.com. ns2.example.com. 查询 NS 服务器的 IP:
bash
dig ns1.example.com +short bash
dig @ns1.example.com www.example.com 如果权威服务器返回正确结果,但递归服务器返回错误结果,说明递归服务器缓存有问题或配置错误。
bash
dig example.com SOA +short 输出示例:
ns1.example.com. admin.example.com. 2024010101 3600 1800 604800 86400 SOA 记录包含:
序列号格式通常为 YYYYMMDDNN,修改 DNS 记录后序列号应增加。
如果使用主从 DNS 架构,检查从服务器是否同步:
bash
dig @ns1.example.com example.com SOA dig @ns2.example.com example.com SOA 比较两个服务器的 SOA 序列号,如果不一致,说明从服务器未同步。
检查从服务器日志:
bash
tail -f /var/log/named.log | grep "zone transfer" bash
dig www.example.com A +short dig www.example.com AAAA +short 确认返回的 IP 地址是否正确。
bash
dig www.example.com +noall +answer 如果域名是 CNAME,输出会显示 CNAME 记录和最终的 A 记录。
注意:
example.com)通常不能使用 CNAMEbash
dig example.com MX +short 输出示例:
10 mail.example.com. 20 mail2.example.com. 数字表示优先级,数值越小优先级越高。
确认 MX 记录指向的主机有 A 记录:
bash
dig mail.example.com A +short bash
dig example.com TXT +short TXT 记录常用于:
v=spf1 ...v=DMARC1; ...bash
dig www.example.com +noall +answer 输出示例:
www.example.com. 300 IN A 192.0.2.1
300 是 TTL,单位为秒(5 分钟)。
TTL 设置建议:
Chrome:
访问 chrome://net-internals/#dns,点击"Clear host cache"。
Firefox:
关闭浏览器重新打开,或访问 about:networking#dns,点击"Clear DNS Cache"。
Linux(使用 systemd-resolved):
bash
systemd-resolve --flush-caches systemd-resolve --statistics Linux(使用 nscd):
bash
systemctl restart nscd macOS:
bash
sudo dscacheutil -flushcache sudo killall -HUP mDNSResponder Windows:
cmd
ipconfig /flushdns BIND:
bash
rndc flush 清除所有缓存。
bash
rndc flushname example.com 清除特定域名缓存。
dnsmasq:
bash
systemctl restart dnsmasq 重启服务清除缓存。
unbound:
bash
unbound-control flush example.com BIND:
bash
rndc dumpdb -cache cat /var/cache/bind/named_dump.db 查看缓存的记录。
bash
ping 8.8.8.8 确认网络可达。
bash
traceroute 8.8.8.8 查看路由路径,定位网络中断点。
DNS 使用 UDP 53 和 TCP 53 端口。
测试 UDP 53:
bash
nc -u -v 8.8.8.8 53 测试 TCP 53:
bash
nc -v 8.8.8.8 53 如果无法连接,可能被防火墙阻止。
本地防火墙:
bash
iptables -L -n | grep 53 确认没有阻止 DNS 端口。
云服务器安全组:
检查云平台控制台的安全组规则,确保允许出站 UDP/TCP 53。
部分网络运营商会劫持 DNS 查询,返回错误结果或广告页面。
测试方法:
bash
dig @8.8.8.8 www.nonexistentdomain12345.com
正常情况应返回 NXDOMAIN。
如果返回 IP 地址或被重定向到广告页面,说明存在 DNS 劫持。
解决方法:
bash
whois example.com | grep -i "expir" 查看域名过期时间。
如果域名过期,需要续费后等待 DNS 恢复(通常 24-48 小时)。
bash
whois example.com | grep -i "status" 常见状态码:
ok:正常clientHold:域名被暂停serverHold:域名被注册商暂停redemptionPeriod:域名在赎回期pendingDelete:域名即将删除如果状态异常,联系域名注册商解决。
bash
whois example.com | grep -i "name server" 确认 NS 服务器地址与实际配置一致。
如果修改了 NS 服务器,需要等待 24-48 小时全球生效。
症状:
排查方法:
bash
dig @8.8.8.8 www.example.com dig @1.1.1.1 www.example.com 比较多个公共 DNS 服务器的结果。
如果本地递归服务器返回错误结果,但公共 DNS 返回正确结果,可能是缓存投毒。
解决方法:
症状:
排查方法:
bash
tcpdump -i eth0 -n port 53 | head -100 抓取 DNS 查询包,分析来源 IP 和查询内容。
如果发现大量对同一域名的 ANY 查询,可能是放大攻击。
解决方法:
DNSSEC 用于验证 DNS 响应的真实性,防止缓存投毒。
检查域名是否启用 DNSSEC:
bash
dig example.com +dnssec
如果返回 RRSIG 记录,说明启用了 DNSSEC。
验证 DNSSEC 签名:
bash
dig example.com +dnssec +multiline
如果验证失败,会显示 SERVFAIL。
症状:
bash
dig www.example.com
返回 NXDOMAIN。
原因:
排查步骤:
whois example.comdig example.com NSdig @ns1.example.com www.example.com症状:
bash
dig www.example.com +short 返回错误的 IP 地址。
原因:
排查步骤:
症状:
bash
dig www.example.com 长时间无响应,最后超时。
原因:
排查步骤:
ping 8.8.8.8nc -u -v 8.8.8.8 53症状:
部分地区用户可以访问,部分地区无法访问。
原因:
排查步骤:
症状:
bash
dig www.example.com 返回 CNAME 记录,但没有 A 记录。
原因:
排查步骤:
dig cdn.example.com症状:
邮件发送失败,提示无法解析 MX 记录。
原因:
排查步骤:
dig example.com MXdig mail.example.com Abash
# 基本查询 nslookup www.example.com dig www.example.com host www.example.com # 指定 DNS 服务器 nslookup www.example.com 8.8.8.8 dig @8.8.8.8 www.example.com host www.example.com 8.8.8.8 # 查询特定记录类型 dig example.com A dig example.com AAAA dig example.com MX dig example.com TXT dig example.com NS dig example.com SOA dig example.com CNAME # 简化输出 dig www.example.com +short # 追踪查询路径 dig www.example.com +trace # 反向解析 dig -x 192.0.2.1 host 192.0.2.1 # 查询 DNSSEC dig example.com +dnssec bash
# 清除本地缓存 # Linux (systemd-resolved) systemd-resolve --flush-caches # Linux (nscd) systemctl restart nscd # macOS sudo dscacheutil -flushcache sudo killall -HUP mDNSResponder # Windows ipconfig /flushdns # 清除 BIND 缓存 rndc flush rndc flushname example.com # 清除 dnsmasq 缓存 systemctl restart dnsmasq # 查看 BIND 缓存 rndc dumpdb -cache cat /var/cache/bind/named_dump.db bash
# 启动/停止/重启 DNS 服务 # BIND systemctl start named systemctl stop named systemctl restart named systemctl status named # dnsmasq systemctl start dnsmasq systemctl stop dnsmasq systemctl restart dnsmasq systemctl status dnsmasq # 检查配置文件语法 # BIND named-checkconf /etc/named.conf named-checkzone example.com /var/named/example.com.zone # 重新加载配置 # BIND rndc reload bash
# 查看 DNS 日志 # BIND tail -f /var/log/named.log tail -f /var/log/syslog | grep named # dnsmasq tail -f /var/log/dnsmasq.log tail -f /var/log/syslog | grep dnsmasq # systemd 日志 journalctl -u named -f journalctl -u dnsmasq -f bash
# 测试 DNS 服务器可达性 ping 8.8.8.8 traceroute 8.8.8.8 # 测试 DNS 端口 nc -u -v 8.8.8.8 53 # UDP nc -v 8.8.8.8 53 # TCP # 抓包分析 tcpdump -i eth0 -n port 53 tcpdump -i eth0 -n udp port 53 -w dns.pcap bash
# DNS 服务器 nameserver 8.8.8.8 nameserver 8.8.4.4 # 搜索域 search example.com # 查询超时时间(秒) options timeout:2 # 查询重试次数 options attempts:3 注意:
nameserver 最多可以配置 3 个search 用于补全短域名,例如查询 www 会自动尝试 www.example.com
主配置文件 /etc/named.conf:
options { listen-on port 53 { 127.0.0.1; 192.168.1.1; }; directory "/var/named"; dump-file "/var/named/data/cache_dump.db"; statistics-file "/var/named/data/named_stats.txt"; memstatistics-file "/var/named/data/named_mem_stats.txt"; recursion yes; allow-query { localhost; 192.168.1.0/24; }; allow-transfer { none; }; forwarders { 8.8.8.8; 8.8.4.4; }; dnssec-enable yes; dnssec-validation yes; }; zone "example.com" IN { type master; file "example.com.zone"; allow-update { none; }; }; zone "1.168.192.in-addr.arpa" IN { type master; file "1.168.192.rev"; allow-update { none; }; };
正向解析区域文件 /var/named/example.com.zone:
$TTL 3600 @ IN SOA ns1.example.com. admin.example.com. ( 2024010101 ; Serial 3600 ; Refresh 1800 ; Retry 604800 ; Expire 86400 ) ; Minimum TTL @ IN NS ns1.example.com. @ IN NS ns2.example.com. @ IN A 192.0.2.1 @ IN MX 10 mail.example.com. ns1 IN A 192.0.2.10 ns2 IN A 192.0.2.11 www IN A 192.0.2.1 mail IN A 192.0.2.20 ftp IN CNAME www
反向解析区域文件 /var/named/1.168.192.rev:
$TTL 3600 @ IN SOA ns1.example.com. admin.example.com. ( 2024010101 ; Serial 3600 ; Refresh 1800 ; Retry 604800 ; Expire 86400 ) ; Minimum TTL @ IN NS ns1.example.com. @ IN NS ns2.example.com. 1 IN PTR example.com. 10 IN PTR ns1.example.com. 11 IN PTR ns2.example.com. 20 IN PTR mail.example.com.
配置文件 /etc/dnsmasq.conf:
# 监听接口 interface=eth0 # 不监听回环接口(安全考虑) bind-interfaces # 上游 DNS 服务器 server=8.8.8.8 server=8.8.4.4 # 缓存大小 cache-size=10000 # 本地域名解析 address=/example.local/192.168.1.1 # 本地 hosts 文件 addn-hosts=/etc/dnsmasq.hosts # 日志 log-queries log-facility=/var/log/dnsmasq.log # 防止上游 DNS 泄露 no-resolv
配置文件 /etc/systemd/resolved.conf:
[Resolve] DNS=8.8.8.8 8.8.4.4 FallbackDNS=1.1.1.1 1.0.0.1 Domains=~. DNSSEC=yes DNSOverTLS=opportunistic Cache=yes 重启服务:
bash
systemctl restart systemd-resolved 使用 cloudflared 配置 DoH:
安装:
bash
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 运行:
bash
cloudflared proxy-dns --port 5353 --upstream https://1.1.1.1/dns-query 配置本地 DNS:
编辑 /etc/resolv.conf:
nameserver 127.0.0.1
配置 systemd 服务 /etc/systemd/system/cloudflared.service:
[Unit] Description=Cloudflare DNS over HTTPS proxy After=network.target [Service] Type=simple ExecStart=/usr/local/bin/cloudflared proxy-dns --port 53 --upstream https://1.1.1.1/dns-query Restart=on-failure [Install] WantedBy=multi-user.target 启动服务:
bash
systemctl daemon-reload systemctl start cloudflared systemctl enable cloudflared 默认日志路径:
/var/log/named.log/var/log/syslog 或 /var/log/messages关键日志信息:
# 查询日志 query: info: client 192.168.1.100#54321 (www.example.com): query: www.example.com IN A # 响应日志 query: info: client 192.168.1.100#54321 (www.example.com): query: www.example.com IN A response: NOERROR # 区域传输日志 zone example.com/IN: Transfer started. zone example.com/IN: Transfer completed: 15 messages, 50 records, 2048 bytes, 0.123 secs # 错误日志 zone example.com/IN: loading from master file example.com.zone failed: file not found 配置日志:
编辑 /etc/dnsmasq.conf:
log-queries log-facility=/var/log/dnsmasq.log 关键日志信息:
# 查询日志 query[A] www.example.com from 192.168.1.100 # 转发日志 forwarded www.example.com to 8.8.8.8 # 响应日志 reply www.example.com is 192.0.2.1 # 缓存日志 cached www.example.com is 192.0.2.1 使用 Prometheus 监控 DNS:
安装 bind_exporter:
bash
wget https://github.com/prometheus-community/bind_exporter/releases/latest/download/bind_exporter-linux-amd64.tar.gz tar -xzf bind_exporter-linux-amd64.tar.gz mv bind_exporter /usr/local/bin/ 运行:
bash
/usr/local/bin/bind_exporter --bind.stats-url=http://localhost:8053/ --bind.stats-groups=server,view,tasks 配置 Prometheus:
yaml
scrape_configs: - job_name: 'bind' static_configs: - targets: ['localhost:9119'] 关键指标:
bind_query_recursion_total:递归查询次数bind_query_duplicates_total:重复查询次数bind_responses_total:响应次数(按响应码分类)bind_resolver_cache_hits_total:缓存命中次数bind_resolver_cache_misses_total:缓存未命中次数
使用 dnsperf 测试 DNS 性能:
安装:
bash
apt install dnsperf -y # Debian/Ubuntu yum install dnsperf -y # CentOS/RHEL
准备测试数据 queries.txt:
www.example.com A api.example.com A cdn.example.com A 执行测试:
bash
dnsperf -s 8.8.8.8 -d queries.txt -c 10 -l 30 参数说明:
-s:DNS 服务器地址-d:查询数据文件-c:并发查询数-l:测试时长(秒)输出示例:
Queries sent: 15000 Queries completed: 15000 Queries lost: 0 Response codes: NOERROR 15000 Average Latency (s): 0.010 排查路径:
ping 8.8.8.8cat /etc/resolv.confdig @8.8.8.8 www.example.comcat /etc/hostsdig @ns1.example.com www.example.comwhois example.com排查路径:
dig @ns1.example.com www.example.com排查路径:
ping 8.8.8.8nc -u -v 8.8.8.8 53traceroute 8.8.8.8排查路径:
dig example.com NS排查路径:
dig example.com MXdig mail.example.com Adig example.com TXTbash
# 验证 A 记录 dig www.example.com A +short # 验证 MX 记录 dig example.com MX +short # 验证 TXT 记录 dig example.com TXT +short # 验证 NS 记录 dig example.com NS +short 使用在线工具:
检查不同地区的解析结果是否一致。
bash
# 第一次查询,记录 TTL dig www.example.com +noall +answer # 等待几秒后再次查询 dig www.example.com +noall +answer TTL 应该递减,到期后会重新查询。
bash
# 清除缓存 rndc flush # 查询,记录响应时间 dig www.example.com | grep "Query time" # 再次查询,验证缓存命中 dig www.example.com | grep "Query time" 缓存命中后查询时间应显著减少。
bash
# 验证 DNSSEC 签名 dig example.com +dnssec +multiline # 检查验证状态 dig example.com +dnssec | grep "flags"
应显示 ad 标志,表示签名验证成功。
如果修改 DNS 记录后出现问题,立即回滚:
rndc flush如果修改 NS 服务器后出现问题:
如果修改 DNS 服务器配置后出现问题:
bash
# 恢复配置文件备份 cp /etc/named.conf.bak /etc/named.conf # 检查配置语法 named-checkconf /etc/named.conf # 重启服务 systemctl restart named # 验证服务状态 systemctl status named DNS 是互联网基础服务,故障排查需要系统性方法。
核心排查流程:
确认现象 → 本地排查 → 递归服务器排查 → 权威服务器排查 → 网络路径排查 → 缓存排查 → 配置排查 → 验证修复 关键工具:
dig:功能最强大,输出详细nslookup:交互式查询host:输出简洁whois:查询域名信息常见故障:
安全防护:
生产环境操作:
DNS 故障影响面广,排查要快速准确,修复要稳妥可靠。
全部0条评论
快来发表一下你的评论吧 !