一、DNS 解决什么问题
人类记名字,机器用地址。DNS(Domain Name System)就是这两者之间的翻译层。
但它做的不止翻译,一共四件事:
| 功能 | 说明 |
|---|---|
| 主机名到 IP 的转换 | www.example.com → 93.184.216.34 |
| 主机别名(aliasing) | 规范名 relay1.west.example.com ← 别名 www.example.com |
| 邮件服务器别名 | [email protected] 的邮件该投给哪台机器(MX 记录) |
| 负载分配 | 一个域名对应多个 IP,轮转返回;CDN 的节点选择就建在这上面(第 6 讲) |
⚠️ DNS 本身是一个应用层协议,运行在 UDP 53 端口(响应超过 512 字节或做区域传送时用 TCP 53)。
它是一个「为其他应用提供核心服务」的应用层协议——这个定位很特别:几乎所有网络活动都以一次 DNS 查询开始。
二、为什么不能集中式
假设全世界只有一台 DNS 服务器,存着所有域名。会出什么问题?
- 单点故障:它挂了,整个互联网失去可用性
- 查询流量:每天数万亿次查询,任何单机都扛不住
- 距离:无论放在哪,对地球另一端的用户都是几百毫秒的时延
- 维护:数亿条记录的更新集中在一处,更新冲突与授权管理不可行
📌 这四条理由(单点故障、流量、距离、维护)几乎是所有「为什么要分布式」问题的标准答案模板,考试里直接用。
根本上,DNS 是互联网上规模最大、最成功的分布式数据库。
三、三级层次结构
┌────────────────┐
│ 根 DNS 服务器 │ 13 个逻辑标识 a~m.root-servers.net
└────────┬───────┘ 实际由 anycast 分散为 1500+ 物理实例
┌───────────────┼───────────────┐
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ com TLD │ │ org TLD │ │ cn TLD │ ← 顶级域服务器
└────┬────┘ └─────────┘ └─────────┘
┌──────┴──────┐
┌────▼────┐ ┌─────▼─────┐
│yahoo.com│ │amazon.com │ ← 权威 DNS 服务器
└─────────┘ └───────────┘
3.1 根 DNS 服务器
- 全球有 13 个逻辑根服务器(标识为 a 到 m),由 12 家机构运营
- ⚠️ 不是 13 台机器。通过 anycast(第 19 讲会讲这个概念)技术,同一个 IP 在全球部署了 1500+ 个物理实例,你的查询会被路由到最近的一个
- 职责:不知道任何域名的 IP,只知道「.com 的 TLD 服务器在哪里」
📌 **为什么是 13 个?**因为早期 DNS 响应必须放进一个 512 字节的 UDP 包,13 个 IPv4 地址加上其他字段恰好装得下。一个 1980 年代的字节数限制,永久塑造了互联网的根结构。
3.2 TLD 服务器
负责顶级域:com、org、net、edu、gov 以及国家域 cn、uk、jp 等。
- Verisign 运营
.com和.net - 职责:知道
example.com的权威服务器在哪里,但不知道www.example.com的 IP
3.3 权威 DNS 服务器
由域名所有者(或其托管商,如 Cloudflare、Route 53)运营,存放该域下真正的记录。
3.4 本地 DNS 服务器(Local DNS / Resolver)
⚠️ 严格来说它不属于上述层次结构,但它是你实际打交道的那一个。
- 由 ISP、公司或公共服务(8.8.8.8、1.1.1.1)提供
- 主机通过 DHCP 获知它的地址(第 18 讲)
- 它是代理:接收你的查询,代你去问层次结构,并缓存结果
四、递归查询 vs 迭代查询
这是本讲最重要的考点。
4.1 迭代查询(Iterative)—— 实际主流
「我不知道,但你可以去问它。」
┌─────────────┐
│ 根 DNS │
└──▲───┬──────┘
②│ │③「去问 com TLD」
│ ▼
┌─────┴────────┐ ④ ┌──────────┐
│ 本地 DNS │─────────────▶│ com TLD │
│ 服务器 │◀─────────────└──────────┘
└──▲───┬───────┘ ⑤「去问 dns.example.com」
①│ │⑧ ⑥│ ▲
│ ▼ ▼ │⑦
┌──┴──────┐ ┌────────────────┐
│ 主机 │ │ example.com │
└─────────┘ │ 权威 DNS │
└────────────────┘
8 个报文:主机→本地(①),本地↔根(②③),本地↔TLD(④⑤),本地↔权威(⑥⑦),本地→主机(⑧)。
负担在本地 DNS 服务器身上,它跑完全程。
4.2 递归查询(Recursive)
「你等着,我帮你问到底。」
主机 → 本地DNS → 根 → TLD → 权威
↑ ↑ ↑
每一级都替下一级去问,结果层层回传
负担逐级向上传递。⚠️ 根服务器和 TLD 服务器通常拒绝递归查询——否则它们会被压垮。
4.3 实际混合模式
现实中最常见的组合是:
主机 → 本地 DNS: 递归查询(「帮我搞定」)
本地 DNS → 层次结构: 迭代查询(「告诉我下一步问谁」)
💡 一句话记忆:主机偷懒(递归),本地 DNS 干活(迭代)。
五、缓存与 TTL
⭐ DNS 之所以能工作,缓存的贡献不亚于层次结构。
任何 DNS 服务器在收到一条记录后,都会把它缓存一段时间。缓存时长由记录自带的 TTL(Time To Live)指定。
效果:
- 绝大多数查询根本到不了根服务器——TLD 记录几乎总是命中本地缓存
- 根服务器实际承受的查询量,远低于「每次上网查一次」的量级
TTL 的取舍:
| TTL 设置 | 优点 | 缺点 |
|---|---|---|
| 长(如 86400 秒) | 查询少、时延低、抗攻击 | 改 IP 后要等一天才全网生效 |
| 短(如 60 秒) | 切换快、便于故障转移和 CDN 调度 | 查询量大、时延高、更依赖 DNS 可用性 |
📌 工程实践:计划要迁移服务器时,提前 24–48 小时把 TTL 调短,迁移完成后再调回去。这是运维中的标准操作,也是常见的面试题。
⚠️ 缓存的代价:一条记录被投毒(第七节),会在整个缓存 TTL 期间持续伤害所有用户。缓存放大了错误的影响范围。
六、资源记录(Resource Records, RR)
DNS 数据库的每一条记录是一个四元组:
(Name, Value, Type, TTL)
Type 决定了 Name 和 Value 分别是什么意思:
| Type | Name 是 | Value 是 | 用途 |
|---|---|---|---|
| A | 主机名 | IPv4 地址 | 最基本的解析 |
| AAAA | 主机名 | IPv6 地址 | IPv6 解析 |
| NS | 域名 | 该域权威服务器的主机名 | 把查询委派下去 |
| CNAME | 别名 | 规范主机名 | 别名指向;CDN 的核心机制 |
| MX | 域名 | 邮件服务器主机名(带优先级) | 邮件投递(第 8 讲) |
| TXT | 域名 | 任意文本 | SPF/DKIM 反垃圾、域名所有权验证 |
| PTR | IP 的反向名 | 主机名 | 反向解析,邮件反垃圾常用 |
| SOA | 域名 | 该区的元信息 | 主服务器、序列号、刷新周期 |
| SRV | _服务._协议.域名 | 主机名 + 端口 | 服务发现(SIP、XMPP、Kubernetes) |
实例:读一份 dig 输出
$ dig www.example.com
;; QUESTION SECTION:
;www.example.com. IN A
;; ANSWER SECTION:
www.example.com. 3600 IN CNAME edge.cdn-provider.net.
edge.cdn-provider.net. 60 IN A 104.18.32.7
edge.cdn-provider.net. 60 IN A 104.18.33.7
;; AUTHORITY SECTION:
cdn-provider.net. 172800 IN NS ns1.cdn-provider.net.
读法:
- 问的是 A 记录,但先拿到一条 CNAME——说明这个域名托管在 CDN 上(第 6 讲)
- CNAME 的 TTL 是 3600 秒(1 小时),而最终 A 记录的 TTL 只有 60 秒——CDN 需要频繁调度节点
- 返回了两个 A 记录:客户端会挑一个,这是最朴素的负载分配
⚠️ CNAME 的一条规则:一个域名有 CNAME 记录时,不能同时有其他记录(包括 MX、NS)。因此根域名(example.com 而非 www.example.com)不能用 CNAME——因为它必须有 SOA 和 NS。各家 DNS 托管商用非标准的 ALIAS / ANAME / CNAME flattening 绕过这个限制。这是真实工作中会踩的坑。
七、DNS 与安全
DNS 设计于 1983 年,没有任何认证机制——这是第 4 讲说的「诞生于相互信任环境」的又一个例证。
7.1 攻击面
1️⃣ 针对根服务器的 DDoS
历史上多次发生(2002、2007、2015)。从未成功过,原因是:anycast 分散、本地缓存使大多数查询到不了根、根服务器过度配置。
更有效的攻击目标其实是 TLD 服务器,或某个大型托管商。2016 年针对 Dyn 的 DDoS 让 Twitter、Netflix、GitHub 同时不可用——攻击的不是这些网站,而是它们的 DNS。
2️⃣ DNS 缓存投毒(Cache Poisoning)
攻击者抢在真实响应之前,向解析器发送一个伪造的响应。若被接受,该错误记录会在整个 TTL 期间毒害所有用户。
DNS 用什么防伪造?只有:
- 16 位的事务 ID(必须匹配)
- 源/目的端口与地址
⚠️ 16 位 = 65536 种可能。2008 年 Kaminsky 攻击证明了这远远不够,通过巧妙的构造可以在很短时间内暴力猜中。
紧急缓解措施是源端口随机化(把熵从 16 位提到约 32 位),但这只是提高了难度,没有根本解决问题。
3️⃣ DNS 放大攻击(Amplification)
利用两点:UDP 无握手(可伪造源 IP,第 4 讲)+ 响应远大于请求。
攻击者 ──60 字节查询,源 IP 伪造成受害者──→ 开放的 DNS 解析器
│
受害者 ←────── 3000+ 字节的响应 ──────────────┘
放大倍数可达 50 倍以上
防御:关闭开放递归解析器、响应速率限制(RRL)、ISP 部署入口过滤(BCP 38)。
4️⃣ 隐私泄露
传统 DNS 是明文的。你访问的每一个域名,路径上的每一个网络(咖啡店 WiFi、ISP)都能看到——即使你用了 HTTPS。
7.2 防御机制
DNSSEC(DNS Security Extensions)
给 DNS 记录加数字签名(第 27 讲会讲原理),形成从根开始的信任链:
根签名 → 签署 .com 的密钥 → 签署 example.com 的密钥 → 签署具体记录
- ✅ 提供来源认证和完整性——能识别伪造和篡改
- ❌ 不提供机密性——记录仍然是明文的
- ⚠️ 部署率长期偏低(复杂、密钥轮转易出错、响应变大加剧放大攻击)
DoT / DoH(DNS over TLS / over HTTPS)
把 DNS 查询装进加密通道:
| DoT | DoH | |
|---|---|---|
| 端口 | 853 | 443(与普通 HTTPS 混在一起) |
| 可被网络管理员识别 | ✅ 容易 | ❌ 难以区分 |
| 争议 | 较小 | 大 |
📌 DoH 的争议值得理解:它保护了用户隐私,但同时把 DNS 的可见性和控制权从网络运营者转移到了浏览器厂商和少数几家公共解析服务。企业网络的安全策略、家长控制、恶意域名拦截都建立在能看到 DNS 之上。这是一个隐私与可控性之间没有标准答案的权衡,也是网络课上少见的、明确涉及政策与治理的议题。
八、例题(Worked Example)
题目:主机 H 首次访问 www.cs.university.edu,本地 DNS 缓存为空,采用「主机→本地递归、本地→层次迭代」模式。RTT 如下:
- H ↔ 本地 DNS:2 ms
- 本地 DNS ↔ 根:80 ms
- 本地 DNS ↔ edu TLD:40 ms
- 本地 DNS ↔ university.edu 权威:20 ms
- 本地 DNS ↔ cs.university.edu 权威:10 ms
(a) 画出报文序列,计算 H 获得 IP 所需的总时间。
(b) 5 分钟后另一台主机 H2(同一本地 DNS)访问同一域名,总时间是多少?假设所有 TTL 都大于 5 分钟。
(c) 若 H2 访问的是 www.ee.university.edu(不同子域),总时间是多少?
解答:
(a)
① H → 本地DNS 1 ms(单向)
② 本地DNS ↔ 根 80 ms
③ 本地DNS ↔ edu TLD 40 ms
④ 本地DNS ↔ university 20 ms
⑤ 本地DNS ↔ cs 权威 10 ms
⑥ 本地DNS → H 1 ms(单向)
总计 = 2 + 80 + 40 + 20 + 10 = 152 ms
(b) 本地 DNS 已缓存最终的 A 记录,直接返回:
总计 = 2 ms
76 倍的差距——这就是缓存的价值。
(c) 本地 DNS 已缓存根、edu TLD、university.edu 的 NS 记录,但没有 ee.university.edu 的记录。设该子域权威服务器 RTT 也是 10 ms:
总计 = 2(H)+ 20(问 university.edu 权威拿 ee 的委派)+ 10(问 ee 权威)
= 32 ms
📌 注意 (c) 的启示:缓存是分层生效的。即使是全新域名,只要上层记录已缓存,也能省掉大部分往返。这就是为什么互联网上第一次访问任何网站,通常也只要几十毫秒而不是几百毫秒。
九、随堂自测
- 给出 DNS 不能集中式的四条理由。
- 「全球只有 13 台根 DNS 服务器」这句话哪里错了?为什么是 13 这个数字?
- 递归查询和迭代查询各自的负担落在谁身上?为什么根服务器拒绝递归?
- 一家公司要在周末把网站迁移到新 IP,运维应当在什么时候做什么?
- 为什么根域名
example.com不能配置 CNAME 记录? - DNS 放大攻击利用了 DNS 的哪两个特性?
- DNSSEC 提供机密性吗?如果不提供,那 DoH 和 DNSSEC 是替代关系还是互补关系?
十、本讲要点回顾
- DNS 做四件事:名字解析、主机别名、邮件服务器别名、负载分配。
- 不能集中式的四条理由:单点故障、流量、距离、维护。
- 层次:根(13 个逻辑标识 + anycast)→ TLD → 权威;本地 DNS 是代理,不在层次内。
- 主机对本地 DNS 用递归,本地 DNS 对层次结构用迭代。
- 缓存与 TTL 是 DNS 可扩展性的关键,也是错误影响面被放大的原因。
- 记录类型:A / AAAA / NS / CNAME / MX / TXT / PTR / SOA / SRV。
- DNS 没有内建认证:缓存投毒、放大攻击、明文泄露。
- DNSSEC 管真伪,DoH/DoT 管隐私,二者互补而非替代。
十一、自测答案
1. ① 单点故障;② 查询流量巨大,单机无法承载;③ 集中式数据库对远处用户时延不可接受;④ 数亿条记录的维护与授权无法集中管理。
2. 错在把「13 个逻辑根服务器标识」当成 13 台物理机器。实际上通过 anycast,同一个根服务器 IP 在全球有 1500+ 个物理实例,BGP 会把查询路由到最近的一个。13 这个数字来源于早期约束:DNS 响应要装进 512 字节的 UDP 报文,13 个 IPv4 地址的 NS + A 记录恰好是能塞下的上限。
3. 递归查询的负担逐级向上传递,最终落在被查询的服务器身上;迭代查询的负担落在本地 DNS 服务器(发起者)身上。根服务器拒绝递归,是因为它每秒要处理海量查询,若还要替所有人跑完全程去问 TLD 和权威服务器,将立刻被压垮——拒绝递归是一种自我保护的架构决策。
4. 迁移前 24–48 小时(即至少超过当前 TTL 一个周期)把该记录的 TTL 从例如 3600 秒调低到 60 秒,等旧的长 TTL 缓存全部过期;迁移时更新 A 记录,此时全网在 60 秒内切换完成;确认稳定后再把 TTL 调回长值以降低查询量。
5. 因为 CNAME 记录不能与同名的其他记录共存(RFC 1034),而根域名必须拥有 SOA 和 NS 记录。托管商用 ALIAS / ANAME / CNAME flattening 等非标准手段在服务端做展开来绕开这一限制。
6. ① UDP 无连接、无握手,因此源 IP 可以随意伪造(IP 欺骗,第 4 讲);② 响应报文远大于请求报文(尤其是启用 DNSSEC 或查询 ANY 时),构成流量放大。两者结合可让攻击者用小流量打出几十倍的攻击流量。
7. 不提供。DNSSEC 只签名,不加密,记录内容仍然明文可见。因此 DNSSEC 与 DoH/DoT 是互补关系:DNSSEC 保证「这条记录确实来自权威服务器且未被篡改」(真实性与完整性),DoH/DoT 保证「路径上的人看不到你查了什么」(机密性)。理想部署是两者同时启用。