[概念] 我还以为我懂 DNS

发布: (2026年1月4日 GMT+8 01:39)
11 min read
原文: Dev.to

I’m happy to translate the article for you, but I need the text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source line and all formatting exactly as you requested.

介绍

我们都知道 DNS 是如何工作的——有无数文章和博客对此进行了解释。
在更深入的挖掘中,我发现了几条对我而言全新的信息,于是决定把它们记下来。

注意: 有许多优秀的 DNS 资源,但我希望你能在这里发现一些新东西。

Source:

为什么要创建 DNS?

在 DNS 之前,基于名称的通信依赖于一个 HOSTS.TXT 文件,该文件在计算机之间复制。每个站点维护自己的文件,以一种简单、可读的格式将主机名映射到网络地址。

  • 保持多个 hosts 文件的副本被证明 低效容易出错
  • RFC 623 和 RFC 625 将 斯坦福研究所网络信息中心 (NIC) 指定为主 hosts 文件的官方来源。

DNS 的诞生

Paul Mockapetris 及其团队的任务是创建一个更友好的网络,使用户不必记住 IP 地址。
他们提出主机名应由以下部分组成:

组件示例
名称IBM
类别 / 用途.com(商业)

一年后,首批通用顶级域 (gTLD) 被引入:

  • .com.edu.net.org.int.gov.mil

到 1985 年底,已有六个新的 .com 域名。首个注册的域名 Symbolics.com 至今仍在使用。

趣闻

DNS拦截器

  • 用于优化审查、捕获门户等。
  • 由于DNS是通往互联网的网关,控制它即可控制查询和请求。

隐私

  • RFC 7816 – QNAME最小化提升了隐私。
  • 解析器可以仅发送最小必要信息,而不是将完整查询发送给权威名称服务器。

DNS 简要概述

DNS 是一个 全局分布式标识符数据库,取代了静态的 /etc/hosts 文件。
要了解其分布式模型,让我们追踪一次典型的查询过程。

Source:

DNS 解析过程

1. 浏览器缓存

当你请求 https://google.com 时,浏览器首先检查它的 本地缓存。如果答案已存在,则会立即返回。

2. 存根解析器

如果缓存未命中,操作系统中的 存根解析器(例如 gethostbyname()getaddrinfo())会接管并将查询发送给 递归解析器

存根解析器是一个轻量客户端,代表应用程序将查询转发给递归解析器。

3. 递归解析器

递归解析器负责完成繁重的工作:

  1. 缓存检查 – 如果它已有缓存的答案(且仍在 TTL 有效期内),则直接返回。
  2. 根提示文件 – 若未命中缓存,它会从 根提示文件(包含 13 台根服务器 IP 的列表)开始。
  3. 根查询(Priming Query) – 向根服务器发送 根查询,获取根名称服务器的列表。
  4. 迭代查询 – 按 DNS 层级依次查询:根 → 顶级域(TLD) → 域的权威名称服务器。
  5. 缓存 – 将答案连同其 TTL(生存时间) 一起缓存。

TTL 细节

  • TTL 是对记录可以被缓存多长时间的 建议
  • 某些解析器会强制 最大 TTL;超过该值的 TTL 会被忽略。
  • 为了遵守 TTL,解析器在将结果缓存给下游客户端之前,会减去已经花费的解析时间。

4. 转发器与代理(可选)

在存根解析器和递归解析器之间,你可能会遇到 转发器代理服务器,它们将查询转发给递归解析器。这通常用于:

  • 安全(隐藏内部网络细节)
  • 集中缓存

5. 解析器类型

类型描述
存根应用程序使用的轻量客户端。
递归代表存根完成完整解析。
转发器将查询转发给另一解析器,常用于安全或策略需求。
验证执行 DNSSEC 验证。
付费墙限制对某些域名的访问。

大多数 ISP 都运营自己的递归解析器,并各自维护独立的缓存。

根区域

  • ICANNVerisign根服务器运营商 管理根区域。
  • 对根域(.)的查询返回 13 个根名称服务器

Glue 记录

  • Glue 记录硬编码的 A(或 AAAA)记录,用于消除循环依赖。
  • 循环引用发生在权威名称服务器的名称位于其所服务的区域内部时(例如 ns.example.com 位于 example.com 中)。如果没有 glue,解析器将永远无法到达该服务器,因为它还不知道其 IP。
  • 在委派区域时,域名注册商 会添加 glue 记录,互联网上的每个名称服务器都有其所有者为该域创建的 glue 记录。

摘要

  • DNS 用 分布式层次结构数据库 替代了静态 hosts 文件。
  • 解析流程从 浏览器缓存 → 存根解析器 → 递归解析器 → 根服务器 → 顶级域 (TLD) → 权威服务器 移动。
  • 缓存TTL 控制记录在每个层级的存储时长。
  • 根服务器粘合记录(glue records)和 转发器 使系统高效可靠。
  • 通过扩展和最佳实践来应对现代关注点,如 隐私(QNAME 最小化)拦截(审查、优化)

欢迎进一步探索每个组件——DNS 是一个深奥且引人入胜的主题!

名称服务器

现在,负责大部分工作的 Recursive Resolver(递归解析器)会找到 Authoritative Name Server(权威名称服务器),获取查询的答案(包括剩余的 TTL),并将其交给 Stub Resolver(存根解析器),这就是我们将域名解析为 IP 地址的方式。

快速伪代码概述

var cache = map[string]string{}

func stubResolver(domain string) string {
    var (
        ipAddress string
        cacheHit  bool
    )
    ipAddress, cacheHit = cache[domain]
    if !cacheHit {
        ipAddress = recursiveResolver(domain)
    }
    return ipAddress
}

func recursiveResolver(domain string) string {
    // … 递归地尝试通过获取每个元素的
    // **Authoritative Name Server**(权威名称服务器)来识别它
    // **Name Servers**(名称服务器)。
    // 它甚至可能一直追溯到根区域(".")。
    return ipAddress
}

注意: 实际过程要复杂得多;上面的代码仅是一个高层次的示例。

什么是 DNS 查询?

DNS 查询是一个 元组(称为 查询元组),其包含:

字段描述
查询名称正在查询的域名
TTL回答的生存时间
通常为 IN(Internet)
查询类型AAAAAMX
RDATA资源记录数据(在响应中出现)

请求方会请求 整个元组——它不能单独请求其中的某一部分。在网络传输中(RFC 1035),查询由类似 ASCII 的标签和二进制数据混合组成,使用历史悠久的 标签压缩 方案。

Trivia Details

TopicDetails
传输DNS 更倾向使用 UDP。如果响应大于 512 字节,或服务器进行区域传输,则会回退到 TCP。
In‑billiwick vs. Out‑of‑billiwickIn‑billiwick 服务器位于委派的区域内部,并依赖 glue recordsOut‑of‑billiwick 服务器位于区域之外。
数据包演进早期数据包的 RCODE 字段只有 4 位。通过 EDNS0(RFC 6891)添加了 OPT 伪资源记录,将 RCODE 扩展到 12 位,并引入了新的标志和扩展(例如,扩展错误 – RFC 8914,客户端子网 – RFC 7871)。
截断当 UDP 响应超过客户端缓冲区时,会设置 TC(truncated) 位。客户端可以改用 TCP 重试,或服务器可以删除非必要的部分以适配。
响应速率限制(RRL)一种基于查询频率限制响应的 DDoS 缓解技术。
反向 DNS(PTR)要通过 IP 地址查找名称,需要将八位字节倒序,追加 .in‑addr.arpa,并查询 PTR 记录。例如:142.250.72.196 → 196.72.250.142.in‑addr.arpa
根节点、终端节点与失效委派Apex – 区域的根节点(例如 example.com)。Terminal – 区域中的最后一个节点。Lame delegation – 父级 NS 记录指向已不再提供该区域服务的子级。
Happy Eyeballs现代客户端会 并行发送 A 和 AAAA 查询(RFC 8305)。先收到的响应获胜,从而提升用户体验。
不存在类型NXDOMAIN – 域名不存在。NOERROR 且答案为空 – 表示查询的记录类型在已存在的名称下不存在。
.com ↔ .net 依赖许多 .com 名称服务器本身被委派给 .net 名称服务器。
CNAME 与 DNAMECNAME – 单个名称的别名(可指向任意区域)。DNAME – 整个子树(区域)的别名。
通配符记录通配符在 RFC 4592 中定义。像 foo*.some-domain.com 这样的查询 无效;星号只能出现在最左侧标签(*.example.com)。

结束语

希望这篇“博客式”笔记能让您更清晰地了解 DNS 内部工作原理以及一些有趣的琐事。

学习愉快!

Back to Blog

相关文章

阅读更多 »

📞 DNS 像5岁小孩一样解释

互联网的电话簿 149天中的第7天 – 👉 完整深度剖析并附代码示例 记得电话簿吗?问问你的父母! 📚 你想打电话给Pizza Hut,但……

TCP/IP 网络模型概述

引言 TCP/IP模型是现代网络的支柱。它定义了广泛的协议,使设备能够在庞大的网络中进行通信……

2026年如何成为 iOS 开发者

引言 在本文中,我将详细说明在2026年成为 iOS 开发者需要做些什么。本文面向两个群体:绝对初学者——那些没有…