Network · #network#dns#resolution

DNS解析全链路分析

2025.05.17 7 min 2.7k
// 目录 · contents

前言

DNS(Domain Name System)是互联网的”电话簿”,将人类可读的域名转换为IP地址。看似简单的域名解析背后,涉及复杂的分层查询、缓存策略、安全机制。本文将从DNS层级结构出发,深入分析DNS解析的完整链路。

DNS层级结构

graph TB
    ROOT[". (Root)<br>13组根服务器"] --> COM[".com"]
    ROOT --> ORG[".org"]
    ROOT --> NET[".net"]
    ROOT --> CN[".cn"]

    COM --> GOOGLE["google.com"]
    COM --> EXAMPLE["example.com"]
    COM --> GITHUB["github.com"]

    CN --> BAIDU["baidu.com"]

    EXAMPLE --> WWW["www.example.com"]
    EXAMPLE --> API["api.example.com"]
    EXAMPLE --> MAIL["mail.example.com"]

    style ROOT fill:#d32f2f,color:#fff
    style COM fill:#f57c00,color:#fff
    style ORG fill:#f57c00,color:#fff
    style NET fill:#f57c00,color:#fff
    style CN fill:#f57c00,color:#fff

DNS采用树形层级结构: - 根域(Root):全球13组根服务器(a.root-servers.net 到 m.root-servers.net),通过Anycast部署了上千个实例 - 顶级域(TLD).com.org.cn等 - 权威域(Authoritative):具体的域名如example.com - 子域名www.example.comapi.example.com

DNS查询流程

递归查询 vs 迭代查询

sequenceDiagram
    participant App as Application
    participant Stub as Stub Resolver<br>(OS)
    participant Local as Local DNS<br>(Recursive Resolver)
    participant Root as Root DNS
    participant TLD as TLD DNS (.com)
    participant Auth as Authoritative DNS<br>(example.com)

    App->>Stub: gethostbyname("www.example.com")
    Note over Stub: 检查 /etc/hosts 和本地缓存

    Stub->>Local: 递归查询: www.example.com?
    Note over Local: 检查缓存,未命中

    Local->>Root: 迭代查询: www.example.com?
    Root-->>Local: 返回 .com TLD 服务器地址

    Local->>TLD: 迭代查询: www.example.com?
    TLD-->>Local: 返回 example.com 权威服务器地址

    Local->>Auth: 迭代查询: www.example.com?
    Auth-->>Local: 返回 A 记录: 93.184.216.34

    Local-->>Stub: www.example.com = 93.184.216.34
    Note over Local: 缓存结果 (TTL=300)

    Stub-->>App: 93.184.216.34

关键区别: - 递归查询:客户端发出请求,DNS服务器负责完成所有查找,返回最终结果 - 迭代查询:DNS服务器返回”下一步该去哪里问”的信息,让查询者自己继续

完整的解析路径

flowchart TB
    START[应用请求解析域名] --> CACHE1{浏览器DNS缓存?}
    CACHE1 -->|命中| DONE[返回IP]
    CACHE1 -->|未命中| CACHE2{OS DNS缓存?}
    CACHE2 -->|命中| DONE
    CACHE2 -->|未命中| HOSTS{/etc/hosts?}
    HOSTS -->|命中| DONE
    HOSTS -->|未命中| RESOLVER[本地递归解析器<br>如 8.8.8.8]
    RESOLVER --> CACHE3{解析器缓存?}
    CACHE3 -->|命中| RETURN[返回缓存结果]
    CACHE3 -->|未命中| ROOT_Q[查询根服务器]
    ROOT_Q --> TLD_Q[查询TLD服务器]
    TLD_Q --> AUTH_Q[查询权威服务器]
    AUTH_Q --> CACHE_STORE[缓存结果]
    CACHE_STORE --> RETURN
    RETURN --> DONE

DNS记录类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 查看各种记录类型

# A记录 - IPv4地址
dig example.com A +short
# 93.184.216.34

# AAAA记录 - IPv6地址
dig example.com AAAA +short
# 2606:2800:220:1:248:1893:25c8:1946

# CNAME记录 - 别名
dig www.github.com CNAME +short
# github.com.

# MX记录 - 邮件服务器
dig gmail.com MX +short
# 5 gmail-smtp-in.l.google.com.
# 10 alt1.gmail-smtp-in.l.google.com.

# TXT记录 - 文本信息(SPF、DKIM等)
dig google.com TXT +short
# "v=spf1 include:_spf.google.com ~all"

# NS记录 - 域名服务器
dig example.com NS +short
# a.iana-servers.net.
# b.iana-servers.net.

# SRV记录 - 服务定位
dig _sip._tcp.example.com SRV +short
# 10 60 5060 sipserver.example.com.

# SOA记录 - 起始授权
dig example.com SOA +short
# ns.icann.org. noc.dns.icann.org. 2024012345 7200 3600 1209600 3600

# CAA记录 - 证书颁发授权
dig example.com CAA +short
# 0 issue "letsencrypt.org"

记录类型速查表

记录类型 用途 示例值
A IPv4地址映射 93.184.216.34
AAAA IPv6地址映射 2606:2800:220:1::
CNAME 域名别名 www.example.com -> example.com
MX 邮件路由 10 mail.example.com
TXT 文本记录 SPF、DKIM、域名验证
NS 域名服务器 ns1.example.com
SRV 服务发现 _http._tcp.example.com
SOA 区域授权信息 序列号、刷新间隔
CAA 证书授权 0 issue "letsencrypt.org"
PTR 反向解析 IP -> 域名

DNS缓存机制

graph TB
    subgraph "缓存层级"
        L1[浏览器缓存<br>Chrome: chrome://net-internals/#dns<br>TTL: 通常60s]
        L2[OS缓存<br>macOS: mDNSResponder<br>Linux: systemd-resolved]
        L3[路由器缓存]
        L4[ISP递归解析器缓存<br>遵循TTL]
    end

    L1 --> L2 --> L3 --> L4

TTL管理

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查看记录的TTL
dig example.com A

;; ANSWER SECTION:
;example.com. 300 IN A 93.184.216.34
# ^^^
# TTL=300秒

# 不同场景的TTL建议
# 静态网站: 3600-86400 (1小时-1天)
# 动态服务: 60-300 (1-5分钟)
# 故障切换: 30-60 (30秒-1分钟)
# 迁移前: 先降低TTL到60秒,等待旧TTL过期后再切换
1
2
3
4
5
6
7
# DNS迁移的正确步骤
migration_plan = {
"T-48h": "将TTL从3600降到60",
"T-0h": "等待旧缓存过期后,修改DNS记录指向新IP",
"T+1h": "监控流量,确认切换完成",
"T+24h": "将TTL恢复到3600",
}

DNSSEC安全扩展

DNSSEC通过数字签名保护DNS响应的完整性和真实性,防止DNS劫持和缓存投毒。

graph TB
    ROOT_KSK[Root KSK<br>Key Signing Key] --> ROOT_ZSK[Root ZSK<br>Zone Signing Key]
    ROOT_ZSK --> |DS记录| COM_KSK[.com KSK]
    COM_KSK --> COM_ZSK[.com ZSK]
    COM_ZSK --> |DS记录| EX_KSK[example.com KSK]
    EX_KSK --> EX_ZSK[example.com ZSK]
    EX_ZSK --> |RRSIG| RECORDS[DNS Records<br>A, AAAA, MX...]

    style ROOT_KSK fill:#d32f2f,color:#fff
    style ROOT_ZSK fill:#e57373,color:#fff
1
2
3
4
5
6
7
8
9
10
11
# 验证DNSSEC
dig example.com A +dnssec

# 检查DS记录
dig example.com DS

# 完整的DNSSEC验证链
dig +sigchase +trusted-key=./root.keys example.com A

# 使用delv验证(BIND工具)
delv @8.8.8.8 example.com A +rtrace

DNSSEC记录类型

1
2
3
4
5
RRSIG  - 资源记录签名
DNSKEY - 公钥(KSK和ZSK)
DS - 委派签名者(父区域指向子区域的KSK哈希)
NSEC - 证明不存在(下一个安全记录)
NSEC3 - NSEC的哈希版本(防止区域遍历)

DNS over HTTPS/TLS

传统DNS使用明文UDP/TCP传输,存在隐私泄露和中间人篡改风险。

graph LR
    subgraph "传统DNS (端口53)"
        C1[Client] -->|明文UDP| R1[Resolver]
        R1 -->|可被窃听/篡改| NOTE1[ISP/中间人]
    end

    subgraph "DoT (端口853)"
        C2[Client] -->|TLS加密| R2[Resolver]
    end

    subgraph "DoH (端口443)"
        C3[Client] -->|HTTPS加密| R3[Resolver]
        NOTE3[与正常HTTPS流量混合<br>难以识别和封锁]
    end

DNS over HTTPS (DoH)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 使用curl测试DoH
curl -s -H 'accept: application/dns-json' \
'https://cloudflare-dns.com/dns-query?name=example.com&type=A' | jq

# 响应示例
{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": true,
"Answer": [
{
"name": "example.com",
"type": 1,
"TTL": 300,
"data": "93.184.216.34"
}
]
}

DNS over TLS (DoT)

1
2
3
4
5
6
7
8
# 使用kdig测试DoT
kdig -d @1.1.1.1 +tls-ca example.com A

# 系统级配置(systemd-resolved)
# /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1#cloudflare-dns.com
DNSOverTLS=yes

主要DoH/DoT提供商

提供商 DoH URL DoT地址
Cloudflare https://cloudflare-dns.com/dns-query 1.1.1.1:853
Google https://dns.google/dns-query 8.8.8.8:853
Quad9 https://dns.quad9.net/dns-query 9.9.9.9:853

DNS故障排查

dig命令详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 基本查询
dig example.com

# 简洁输出
dig example.com +short

# 指定DNS服务器
dig @8.8.8.8 example.com

# 跟踪完整解析链路
dig example.com +trace

# 输出示例(trace):
# . 518400 IN NS a.root-servers.net.
# com. 172800 IN NS a.gtld-servers.net.
# example.com. 172800 IN NS a.iana-servers.net.
# example.com. 86400 IN A 93.184.216.34

# 反向解析
dig -x 8.8.8.8

# 查询所有记录
dig example.com ANY

# TCP查询(大响应或验证用)
dig example.com +tcp

# 查看完整响应包
dig example.com +all

nslookup常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 基本查询
nslookup example.com

# 指定DNS服务器
nslookup example.com 8.8.8.8

# 查询特定类型
nslookup -type=MX example.com
nslookup -type=TXT example.com

# 交互模式
nslookup
> server 8.8.8.8
> set type=NS
> example.com

常见问题排查流程

flowchart TB
    ISSUE[DNS解析失败] --> CHECK1{ping IP是否通?}
    CHECK1 -->|通| DNS_ISSUE[DNS问题]
    CHECK1 -->|不通| NET_ISSUE[网络问题]

    DNS_ISSUE --> CHECK2{dig @8.8.8.8 能解析?}
    CHECK2 -->|能| LOCAL_DNS[本地DNS服务器问题]
    CHECK2 -->|不能| CHECK3{dig @权威NS 能解析?}

    CHECK3 -->|能| PROPAGATION[DNS传播未完成<br>等待TTL过期]
    CHECK3 -->|不能| AUTH_ISSUE[权威DNS配置问题<br>检查DNS记录]

    LOCAL_DNS --> FIX1[检查 /etc/resolv.conf<br>尝试更换DNS服务器]
    PROPAGATION --> FIX2[等待或清除缓存<br>ipconfig /flushdns]
    AUTH_ISSUE --> FIX3[登录DNS控制面板<br>检查记录配置]
1
2
3
4
5
6
7
8
9
10
11
12
# 清除DNS缓存
# macOS
sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder

# Linux (systemd-resolved)
sudo systemd-resolve --flush-caches

# Windows
ipconfig /flushdns

# Chrome浏览器
# 访问 chrome://net-internals/#dns 点击 "Clear host cache"

DNS性能测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 使用dnsperf测试DNS服务器性能
dnsperf -s 8.8.8.8 -d queryfile.txt -c 100 -T 10

# queryfile.txt格式:
# example.com A
# google.com AAAA
# github.com A

# 使用dnstop监控DNS流量
sudo dnstop eth0

# 测量解析时间
time dig example.com @8.8.8.8

# 批量测试多个DNS服务器
for dns in 8.8.8.8 1.1.1.1 9.9.9.9; do
echo "Testing $dns:"
dig @$dns example.com +stats | grep "Query time"
done

企业DNS架构建议

graph TB
    subgraph "Internal"
        APP[Applications] --> INTERNAL_DNS[Internal DNS<br>CoreDNS / BIND]
        INTERNAL_DNS --> |内部域名| INT_ZONE[Internal Zones<br>*.internal.company.com]
        INTERNAL_DNS --> |外部域名| FORWARDER[Forwarder]
    end

    subgraph "External"
        FORWARDER --> RECURSIVE[Recursive Resolver<br>Unbound]
        RECURSIVE --> PUBLIC_DNS[Public DNS<br>Root/TLD/Auth]
    end

    subgraph "Public Facing"
        USERS[Users] --> CDN_DNS[CDN DNS<br>CloudFlare / Route53]
        CDN_DNS --> ORIGIN[Origin Servers]
    end

总结

DNS虽然是最基础的互联网服务,但深入理解其机制对于故障排查和性能优化至关重要:

  1. 层级结构:根、TLD、权威三级架构,递归与迭代查询协同工作
  2. 缓存:多级缓存(浏览器、OS、路由器、ISP)减少查询延迟,TTL控制缓存时间
  3. 安全:DNSSEC保护数据完整性,DoH/DoT保护隐私
  4. 排查dig +trace是最强大的DNS调试工具,能展示完整的解析链路
  5. 记录类型:A、AAAA、CNAME、MX、TXT等各有用途,选择正确的记录类型至关重要

对于新系统部署,建议启用DNSSEC和DoH/DoT,并根据场景合理设置TTL值。

作者 · authorzt
发布 · date2025-05-17
篇幅 · length2.7k 字 · 7 min
许可 · licenseCC BY-SA 4.0
$ echo "comments" · 评论