Loading episodes…
0:00 0:00

DNS递归查询揭秘:从客户端到权威服务器

00:00
BACK TO HOME

DNS递归查询揭秘:从客户端到权威服务器

10xTeam January 22, 2026 3 min read

在本DNS系列中,我们正在涵盖所有关于DNS的内容。 从客户端的第一个查询一直到后端的所有过程。 DNS如何被保护,TCP、UDP等等所有相关的东西。

在本例中,我们将探讨当一个请求到达递归服务器后,后端会发生什么。 递归服务器究竟是如何完整查找一个域名的?

为什么这很重要

记住这一点至关重要,因为 DNS 是分层的。 世界上没有任何一个单一的服务器拥有所有这些域名,或者知道所有从名称到IP的映射。

所以,我们不能只去一个服务器就获取到信息。 相反,递归服务器会查询其他几台不同的机器,来帮助它完全解析我们正在寻找的名称。

DNS递归查询的工作原理

为了向你展示这个系统是如何工作的,我们先看看这个流程。 我们的客户端会向它的递归名称服务器发出请求。

对于你我来说,很多时候,如果我们在家,这个服务器可能是我们的本地网关。 或者是在我们的实验环境中一个非常简单的系统。

那个设备并没有存储所有已知的查询结果。 相反,它必须为我们执行一些后端的查询工作。

所以,我们向它发送我们的请求,比如 example.com。 我们说:“嘿,如果你缓存里没有,就帮我查一下。” “如果你缓存里有,就直接把IP地址给我。” “但如果你没有,那就开始你的工作吧。”

第一步:查询根服务器

那个服务器做的第一件事是,它有一个内置的、它已经知道的根服务器列表。 它会说,我什么都不知道。 我准备去和那个根服务器谈谈。

我们假设这个递归名称服务器的缓存里什么都没有。 它刚从午睡中醒来,必须查找整个链条。

好的,所以我们把 example.com 的请求发送到一个根名称服务器。 这些根名称服务器,它知道的名字只有13个。 当然,这不一定是13台物理服务器。 根名称服务器有数百个,但只有到其中13个的命名连接。

我们进入数据包分析时会讨论这意味着什么。

根服务器收到请求“嘿,给我 example.com”,它会回应说: “什么?我不认识什么 example。我从来没听说过这个域名。” “我不是负责这个的。” “但我知道的是,我知道 .com 域的顶级域(TLD)服务器是谁,或者说这些服务器的列表。” “好了,去和这些服务器谈谈,它们会给你进一步的指引。”

graph TD;
    A[客户端] --> B(递归名称服务器);
    B --> C{根服务器};
    C -- "我不知道 example.com, <br/>但我知道 .com 的 TLD 服务器" --> B;

第二步:查询顶级域 (TLD) 服务器

递归名称服务器说:“太好了,非常棒。” 然后我把我的请求发送给它。 我会说:“嘿,example.com 怎么样?”

顶级域服务器的工作也不是知道天下所有的域名。 所以,它回复我说:“什么?我是顶级域服务器,但我不是你正在寻找的域名的权威名称服务器。”

graph TD;
    B(递归名称服务器) --> D{顶级域 (TLD) 服务器};
    D -- "我不知道 example.com, <br/>但我知道它的权威服务器" --> B;

第三步:查询权威名称服务器

它会回复我说:“什么?这是权威名称服务器。去和它谈。” “它才是那个拥有你正在寻找的 A 记录的服务器,无论是什么记录。”

那个权威名称服务器把IP地址返回给我。 然后那个IP地址最终被转发给客户端。

graph TD;
    B(递归名称服务器) --> E{权威名称服务器};
    E -- "这是 example.com 的 IP 地址" --> B;
    B --> A[客户端];

我们刚刚看过的这个图表演示,其实是相当简化的。 很多过程都发生在我们的视野之外,因为我们大多数人都在客户端这一端。

我们只看到我们和递归名称服务器之间发生了什么。 这就是为什么很多时候在Wireshark中捕获DNS解析时,你只看到一个请求发往你的递归服务器,然后它带着一个地址回来。 所以,你只看到那两个数据包。

很多时候你并不知道后端这里发生了什么,所有这些对话。 甚至你的递归名称服务器,很多时候在本地,你的本地设备,可能是你的网关,你的设备,无论是什么,它可能只是一个转发器。 它把请求发送到你ISP中的名称服务器,而那台服务器才是做这些后端工作的。

所以,除非你身处DNS的世界,否则你可能永远不会看到这些对话。 但理解它的工作原理真的非常重要。

深入分析数据包

好了,数据包爱好者们,我们开始吧。 在下面的描述中,我提供了pcap文件,你可以跟着我一起操作。 这个文件叫做 DNS full recursion。 我这样命名是为了让我们能看到后端发生了什么。

初始客户端请求

这里我们有第一个数据包。 顺便说一句,这里有太多东西要解开。 我可以在这个数据包捕获上花好几节课的时间,所以你会有问题,这很正常。

第一个问题,这是我们的终端客户端向其本地递归服务器发出的请求。 让我们看看。

我展开这个,进入查询部分。 我们正在寻找 infoblocks.com

所以,b2b.info.com,这是我想要的查询。 类型是,我想要一个主机地址。 我想要一个 IPv4 地址

让我们看看附加记录。 如果我们展开这个,UDP 负载大小。 这里我在说:“嘿,别给我发比这更大的东西。如果超过了,我就得转到TCP。”

递归服务器开始工作

我们发送了那个请求,下一个数据包下来了。 这是来自同一个服务器。 它用IPv4与客户端通信。 但当它进入下一跳时,它用的是 IPv6

这里是它与 12D0D 通信的地方。它在和谁说话? 让我们看看数据包2。

如果你看一下数据包1,我喜欢Wireshark的这个功能。 你看到,对1的请求,你看到这些虚线,一直延伸到数据包31。 所以,数据包31中的响应是针对数据包1中发出的请求的。 所有这些额外的事情都发生在后端,以使DNS能够做它所做的事情。

[!TIP] 在Wireshark中,你可以通过 编辑 -> 首选项 -> 名称解析,并勾选“使用捕获的DNS数据包数据进行名称解析”来查看解析后的名称,而不是IP地址。这使得分析更容易。

我给解析器起了个名字叫 resolver。 现在我可以看到解析器和它通信的服务器,而不用看那些长长的地址。

与根服务器的对话

所以,这是我的第一个请求,从 resolver 发出。 我出去,只是在查找 infoblocks.com

如果我进入数据包2,resolver -> g.root-servers.net。 这是我的查询。我把它发送到那个根服务器。 附加记录。现在看看我的UDP负载大小:512

这是从解析器到那个根服务器的。 很有趣。 它确实接受DNS安全RR。

现在,当我和那个服务器通话时,我做的另一件有趣的事情是。 这有点无关紧要,但我们谈谈。 我正在做一个完整的根查询,权威名称服务器。 “嘿,根服务器,趁着我和你说话,我有没有你最新的信息?” “我的 g.rootservers.net 信息正确吗?”

因为我的解析器是根据它本地已有的列表来工作的。 递归服务器会做的是,它们知道根服务器是谁以及那些IP。 这个系统正在做的是验证,就像,“嘿,给我最新的。你变了吗?G在别的地方吗?你现在在用不同的IP吗?我应该和谁谈?” 所以,它只是在验证自己的信息。

UDP 到 TCP 的切换

第一个回来的数据包是对第一个根服务的响应。 但看看这个。我转到数据包4。 我们发现了什么?我展开标志。Truncated(已截断)

哇哦。哇哦。 根服务器回来说:“对不起,我要给你的响应,我要说的一切,远远超过了UDP能处理的范围。” “我得把这个转到 TCP。”

实际上,我甚至不打算开始给你发东西,因为我有太多话要说。 数据包5怎么样?同样的事情。 那个根服务器回来说:“嘿,你想要一些关于 info 的东西,我有很多话要说,而且我会突破我们设定的限制。” “所以,我得把这个转到TCP。”

解析器领会了,说:“酷。没问题。我不想破坏这些大小规则。” 所以,让我们转到数据包6。 这里我们向那个DNS解析器发起了两个 TCP SYN

通过 TCP 获取根服务器信息

这是一个很好的过滤时机。 我只想看TCP的对话。

tcp.port == 44653

如果我下到数据包15,这里是好东西。 这是响应。这不再是截断的了。 “嘿,你只是想知道最新的根服务器是什么情况等等。”

有趣的是,这个响应回来了,它给了你所有根服务器的名字。 这是历史性的DNS,但那些根服务器的名字已经很久没变了。 而且它们也很短。它们只是一个字母。

[!NOTE] 根服务器的名称(A、B、C…)之所以这么短,一个原因是为了确保即使包含所有13个根服务器的名称,DNS响应也能保持在 512字节 的限制之内。如果名字更长,就会超出数据报的大小。

好的,所以A、B、C、D等等。 我正在做的是,我只是在更新和刷新这个解析器。 “嘿,看看这个。这是M的IPv4。这是它的IPv4地址。” “这是这些根服务器的所有最新地址。” 不仅是IPv4,我们还要获取v6的。

查询顶级域 (TLD) 服务器

好的,这些信息很棒,但在我的pcap里有点乱。 所以,我要把这些TCP更新流量从视图中移除,专注于主要的查询流程。

我们来看数据包7。 这里是我们的 SYN-ACK。我们进行握手。 然后我们发出一个请求。 我们对根服务器说:“嘿,给我 infoblocks.com。这是我们想要得到的。”

在DNS信息中,这是我们的请求。 infoblocks.com。给我那个A记录。 我的UDP负载大小是1220。

服务器回来说:“好的,这是你的东西。没有截断。给你。” 这里的查询是 infoblocks。 这里我们得到了一些有趣的东西。

根服务器说:“很好。你在请求一个 .com 域名。” “我不在乎那些 b2b.info 的废话。我只看第一部分。” “所以是 .com。你想知道和谁谈?谁更了解 .com?” “你得和这些顶级域服务器谈。”

  • E.gtld-servers.net
  • L.gtld-servers.net
  • K.gtld-servers.net
  • H.gtld-servers.net

“你不必和所有这些服务器谈。这里是你的所有选项。” 这里是实际的名字。

附加记录。 这里是所有的名字。但现在我要给你IP地址,让你去和它们谈。 这是你的V4地址。这是那些TLD服务器的V4地址。 如果我再往下展开一点,我还会给你 AAAA 记录(IPv6)。

这个客户端,或者说解析器,正在使用V6。 所以它会想用下面的一个。 它会随机选择一个。

我最终选择了 g.gtld-servers.net。 在数据包19中,这是来自根服务器的响应。 它告诉我:“嘿,g.gtld-servers.net,你下一步要去的那个顶级域服务器。这是地址:EA330。” 我的解析器说:“酷。让我去和那个谈谈。”

查询权威名称服务器

解析器确认了。它说谢谢。 但看数据包21。这里我进入了下一步。 现在我完成了TCP的部分。

数据包19是通过TCP的。它说我选择了顶级域G。 解析器说:“好的,顶级域,我接下来和你谈。” 这是通过 UDP 的,这是我同样的请求 infoblocks.com,给我一个A记录。 我被限制在512字节,所以要注意。

7毫秒后,服务器回来了。这是顶级域服务器。 它说:“我看到你的 info.com 了。” “现在,我不是那个知道 infobox 的。我知道 .com,但我不知道 infobox。” “所以,我要把你转到权威名称服务器,那个保持信息最新、保持更新的服务器。” “那才是你想谈的那个。”

然后它给了我们下一步的记录。 你有 ns5.infoblocks.comns6.infoblocks.comns7ns1。 如果我往下看一些附加记录,那里我可以看到那些不同服务器的地址。

我选择了 NS5。 看这里,NS5。这是那个知道最终答案的权威名称服务器的完整地址。 那个是不断更新的。 TLD就像是说:“看,我只知道 .com。我只能把你送到那家伙那里。他才是知道的。”

获得最终答案

下一个数据包24。我进入下一步。 现在我到了最后一步,权威名称服务器。 我联系它,说:“嘿,我被告知来找你。” “仍然限制在那个512字节。如果你愿意,可以给我发DNSSEC。”

数据包30回来了,看看我们。 这里我们有了我们实际的答案资源记录。 终于,我们不再是寻找那个知道答案的家伙了。我们终于找到他了。

现在,查询 infoblocks.com 的答案。 这是你的IP:8.39.143.138

然后解析器转过身来说:“好的,终于,这是响应。” “这是你请求的,终端客户端,infobox.com。” “这是那个A记录。这是你请求的IP地址:8.39.143.138。” “现在去吧。去发起那个TCP连接。去做那个ping。去做任何你想做的事。” “这就是你寻找的地址。”

结论

后端有很多步骤,不是吗? DNS超级有趣。我喜欢看到所有这些实际操作。 我们去了根服务器,我们去了顶级域,我们去了权威名称服务器。

现在这个过程,正如我们提到的,对最终用户来说通常是不可见的。 他们看不到后端这么多事情。 但后端发生了这么多事,难道不有趣吗?

[!WARNING] 这也是为什么我们不应该在DNS环境中阻塞TCP的另一个原因。这会给我们带来麻烦,因为如果一个记录大于负载允许的大小,解析器必须使用TCP来传输它。所以要小心,对阻塞TCP要非常谨慎。实际上,这根本不是一个好做法。DNS不仅仅是通过UDP工作的

好了,这就是你的完整递归查询。 如果需要,可以再看一遍这篇文章。

接下来我们去哪里? 下一步,安全。 不仅仅是保护数据本身,还要保护协议。 今天这是怎么做的?有什么后果? 我们应该真正理解DNSSEC、DNS over TLS,甚至DNS over HTTPS之间有什么区别? 那将是我们下一篇文章的内容。


Join the 10xdev Community

Subscribe and get 8+ free PDFs that contain detailed roadmaps with recommended learning periods for each programming language or field, along with links to free resources such as books, YouTube tutorials, and courses with certificates.

Audio Interrupted

We lost the audio stream. Retry with shorter sentences?