大家好！前段时间我写了一篇关于“如何用 Go 语言建立一个简易的 DNS 解析器”的帖子。那篇帖子里我没写有关“如何生成以及解析 DNS 查询请求”的内容，因为我觉得这很无聊，不过一些伙计指出他们不知道如何解析和生成 DNS 查询请求，并且对此很感兴趣。我开始好奇了——解析 DNS 能 花多大功夫？事实证明，编写一段 120 行精巧的 Ruby 语言代码组成的程序就可以做到，这并不是很困难。所以，在这里有一个如何生成 DNS 查询请求，以及如何解析 DNS 响应报文的速成教学！我们会用 Ruby 语言完成这项任务，主要是因为不久以后我将在一场 Ruby 语言大会上发表观点，而这篇博客帖的部分内容是为了那场演讲做准备的。?（我尽量让不懂 Ruby 的人也能读懂，我只使用了非常基础的 Ruby 语言代码。）最后，我们就能制作一个非常简易的 Ruby 版本的 dig 工具，能够查找域名，就像这样：$ ruby dig.rb example.com example.com 20314 A 93.184.216.34 整个程序大概 120 行左右，所以 并不 算多。（如果你想略过讲解，单纯想去读代码的话，最终程序在这里：dig.rb。）我们不会去实现之前帖中所说的“一个 DNS 解析器是如何运作的？”，因为我们已经做过了。那么我们开始吧！如果你想从头开始弄明白 DNS 查询是如何格式化的，我将尝试解释如何自己弄明白其中的一些东西。大多数情况下的答案是“用 Wireshark 去解包”和“阅读 RFC 1035，即 DNS 的规范”。生成 DNS 查询请求步骤一：打开一个 UDP 套接字我们需要实际发送我们的 DNS 查询，因此我们就需要打开一个 UDP 套接字。我们会将我们的 DNS 查询发送至 8.8.8.8，即谷歌的服务器。下面是用于建立与 8.8.8.8 的 UDP 连接，端口为 53（DNS 端口）的代码。require 'socket' sock = UDPSocket.new sock.bind('0.0.0.0', 12345) sock.connect('8.8.8.8', 53) 关于 UDP 的说明关于 UDP，我不想说太多，但是我要说的是，计算机网络的基础单位是“ 数据包 packet ”（即一串字节），而在这个程序中，我们要做的是计算机网络中最简单的事情：发送 1 个数据包，并接收 1 个数据包作为响应。所以 UDP 是一个传递数据包的最简单的方法。它是发送 DNS 查询最常用的方法，不过你还可以用 TCP 或者 DNS-over-HTTPS。步骤二：从 Wireshark 复制一个 DNS 查询下一步：假设我们都不知道 DNS 是如何运作的，但我们还是想尽快发送一个能运行的 DNS 查询。获取 DNS 查询并确保 UDP 连接正常工作的最简单方法就是复制一个已经正常工作的 DNS 查询！所以这就是我们接下来要做的，使用 Wireshark （一个绝赞的数据包分析工具）。我的操作大致如下：打开 Wireshark，点击 “ 捕获 capture ” 按钮。在搜索栏输入 udp.port == 53 作为筛选条件，然后按下回车。在我的终端运行 ping example.com（用来生成一个 DNS 查询）。点击 DNS 查询（显示 “Standard query A example.com”）。 （“A”：查询类型；“example.com”：域名；“Standard query”：查询类型描述）右键点击位于左下角面板上的 “ 域名系统（查询） Domain Name System (query) ”。点击 “ 复制 Copy ” ——> “ 作为十六进制流 as a hex stream ”。现在 b96201000001000000000000076578616d706c6503636f6d0000010001 就放到了我的剪贴板上，之后会用在我的 Ruby 程序里。好欸！步骤三：解析 16 进制数据流并发送 DNS 查询现在我们能够发送我们的 DNS 查询到 8.8.8.8 了！就像这样，我们只需要再加 5 行代码：hex_string = "b96201000001000000000000076578616d706c6503636f6d0000010001" bytes = [hex_string].pack('H*') sock.send(bytes, 0) # get the reply reply, _ = sock.recvfrom(1024) puts reply.unpack('H*') [hex_string].pack('H*') 意思就是将我们的 16 位字符串转译成一个字节串。此时我们不知道这组数据到底是什么意思，但是很快我们就会知道了。我们还可以借此机会运用 tcpdump ，确认程序是否正常进行以及发送有效数据。我是这么做的：在一个终端选项卡下执行 sudo tcpdump -ni any port 53 and host 8.8.8.8 命令在另一个不同的终端指标卡下，运行 这个程序（ruby dns-1.rb）以下是输出结果：$ sudo tcpdump -ni any port 53 and host 8.8.8.8 08:50:28.287440 IP 192.168.1.174.12345 > 8.8.8.8.53: 47458+ A? example.com. (29) 08:50:28.312043 IP 8.8.8.8.53 > 192.168.1.174.12345: 47458 1/0/0 A 93.184.216.34 (45) 非常棒 —— 我们可以看到 DNS 请求（”这个 example.com 的 IP 地址在哪里？“）以及响应（“在93.184.216.34”）。所以一切运行正常。现在只需要（你懂的）—— 搞清我们是如何生成并解析这组数据的。步骤四：学一点点 DNS 查询的格式现在我们有一个关于 example.com 的 DNS 查询，让我们了解它的含义。下方是我们的查询（16 位进制格式）：b96201000001000000000000076578616d706c6503636f6d0000010001 如果你在 Wireshark 上搜索，你就能看见这个查询它由两部分组成：请求头：b96201000001000000000000语句本身：076578616d706c6503636f6d0000010001步骤五：制作请求头我们这一步的目标就是制作字节串 b96201000001000000000000（借助一个 Ruby 函数，而不是把它硬编码出来）。（LCTT 译注： 硬编码 hardcode 指在软件实现上，将输出或输入的相关参数（例如：路径、输出的形式或格式）直接以常量的方式撰写在源代码中，而非在运行期间由外界指定的设置、资源、数据或格式做出适当回应。）那么：请求头是 12 个字节。那些个 12 字节到底意味着什么呢？如果你在 Wireshark 里看看（亦或者阅读 RFC-1035），你就能理解：它是由 6 个 2 字节大小的数字串联在一起组成的。这六个数字分别对应查询 ID、标志，以及数据包内的问题计数、回答资源记录数、权威名称服务器记录数、附加资源记录数。我们还不需要在意这些都是些什么东西 —— 我们只需要把这六个数字输进去就行。但所幸我们知道该输哪六位数，因为我们就是为了直观地生成字符串 b96201000001000000000000。所以这里有一个制作请求头的函数（注意：这里没有 return，因为在 Ruby 语言里，如果处在函数最后一行是不需要写 return 语句的）：def make_question_header(query_id) # id, flags, num questions, num answers, num auth, num additional [query_id, 0x0100, 0x0001, 0x0000, 0x0000, 0x0000].pack('nnnnnn') end 上面内容非常的短，主要因为除了查询 ID ，其余所有内容都由我们硬编码写了出来。什么是 nnnnnn?可能能想知道 .pack('nnnnnn') 中的 nnnnnn 是个什么意思。那是一个向 .pack() 函数解释如何将那个 6 个数字组成的数据转换成一个字节串的一个格式字符串。.pack 的文档在 这里，其中描述了 n 的含义其实是“将其表示为” 16 位无符号、网络（大端序）字节序’”。（LCTT 译注： 大端序 Big-endian ：指将高位字节存储在低地址,低位字节存储在高地址的方式。）16 个位等同于 2 字节，同时我们需要用网络字节序，因为这属于计算机网络范畴。我不会再去解释什么是字节序了（尽管我确实有 一幅自制漫画尝试去描述它）。测试请求头代码让我们快速检测一下我们的 make_question_header 函数运行情况。puts make_question_header(0xb962) == ["b96201000001000000000000"].pack("H*") 这里运行后输出 true 的话，我们就成功了。好了我们接着继续。步骤六：为域名进行编码下一步我们需要生成 问题本身（“example.com 的 IP 是什么？”）。这里有三个部分：域名（比如说 example.com）查询类型（比如说 A 代表 “IPv4 Address”）查询类（总是一样的，1 代表 INternet）最麻烦的就是域名，让我们写个函数对付这个。example.com 以 16 进制被编码进一个 DNS 查询中，如 076578616d706c6503636f6d00。这有什么含义吗？如果我们把这些字节以 ASCII 值翻译出来，结果会是这样：076578616d706c6503636f6d00 7 e x a m p l e 3 c o m 0 因此，每个段（如 example）的前面都会显示它的长度（7）。下面是有关将 example.com 翻译成 7 e x a m p l e 3 c o m 0 的 Ruby 代码：def encode_domain_name(domain) domain .split(".") .map { |x| x.length.chr + x } .join + "\0" end 除此之外，，要完成问题部分的生成，我们只需要在域名结尾追加上（查询）的类型和类。步骤七：编写 make\_dns\_query下面是制作一个 DNS 查询的最终函数：def make_dns_query(domain, type) query_id = rand(65535) header = make_question_header(query_id) question = encode_domain_name(domain) + [type, 1].pack('nn') header + question end 这是目前我们写的所有代码 dns-2.rb —— 目前仅 29 行。接下来是解析的阶段现在我尝试去解析一个 DNS 查询，我们到了硬核的部分：解析。同样的，我们会将其分成不同部分：解析一个 DNS 的请求头解析一个 DNS 的名称解析一个 DNS 的记录这几个部分中最难的（可能跟你想的不一样）就是：“解析一个 DNS 的名称”。步骤八：解析 DNS 的请求头让我们先从最简单的部分开始：DNS 的请求头。我们之前已经讲过关于它那六个数字是如何串联在一起的了。那么我们现在要做的就是：读其首部 12 个字节将其转换成一个由 6 个数字组成的数组为方便起见，将这些数字放入一个类中以下是具体进行工作的 Ruby 代码：class DNSHeader attr_reader :id, :flags, :num_questions, :num_answers, :num_auth, :num_additional def initialize(buf) hdr = buf.read(12) @id, @flags, @num_questions, @num_answers, @num_auth, @num_additional = hdr.unpack('nnnnnn') end end 注： attr_reader 是 Ruby 的一种说法，意思是“使这些实例变量可以作为方法使用”。所以我们可以调用 header.flags 来查看@flags变量。我们也可以借助 DNSheader(buf) 调用这个，也不差。让我们往最难的那一步挪挪：解析一个域名。步骤九：解析一个域名首先，让我们写其中的一部分：def read_domain_name_wrong(buf) domain = [] loop do len = buf.read(1).unpack('C')[0] break if len == 0 domain << buf.read(len) end domain.join('.') end 这里会反复读取一个字节的数据，然后将该长度读入字符串，直到读取的长度为 0。这里运行正常的话，我们在我们的 DNS 响应头第一次看见了域名（example.com）。关于域名方面的麻烦：压缩！但当 example.com 第二次出现的时候，我们遇到了麻烦 —— 在 Wireshark 中，它报告上显示输出的域的值为含糊不清的 2 个字节的 c00c。这种情况就是所谓的 DNS 域名压缩，如果我们想解析任何 DNS 响应我们就要先把这个实现完。幸运的是，这没那么难。这里 c00c 的含义就是：前两个比特（0b11.....）意思是“前面有 DNS 域名压缩！”而余下的 14 比特是一个整数。这种情况下这个整数是 12（0x0c），意思是“返回至数据包中的第 12 个字节处，使用在那里找的域名”如果你想阅读更多有关 DNS 域名压缩之类的内容。我找到了相关更容易让你理解这方面内容的文章： 关于 DNS RFC 的释义。步骤十：实现 DNS 域名压缩因此，我们需要一个更复杂的 read_domain_name 函数。如下所示：domain = [] loop do len = buf.read(1).unpack('C')[0] break if len == 0 if len & 0b11000000 == 0b11000000 # weird case: DNS compression! second_byte = buf.read(1).unpack('C')[0] offset = ((len & 0x3f) << 8) + second_byte old_pos = buf.pos buf.pos = offset domain << read_domain_name(buf) buf.pos = old_pos break else # normal case domain << buf.read(len) end end domain.join('.') 这里具体是：如果前两个位为 0b11，那么我们就需要做 DNS 域名压缩。那么：读取第二个字节并用一点儿运算将其转化为偏移量。在缓冲区保存当前位置。在我们计算偏移量的位置上读取域名在缓冲区存储我们的位置。可能看起来很乱，但是这是解析 DNS 响应的部分中最难的一处了，我们快搞定了！一个关于 DNS 压缩的漏洞有些人可能会说，有恶意行为者可以借助这个代码，通过一个带 DNS 压缩条目的 DNS 响应指向这个响应本身，这样 read_domain_name 就会陷入无限循环。我才不会改进它（这个代码已经够复杂了好吗！）但一个真正的 DNS 解析器确实会更巧妙地处理它。比如，这里有个 能够避免在 miekg/dns 中陷入无限循环的代码。如果这是一个真正的 DNS 解析器，可能还有其他一些边缘情况会造成问题。步骤十一：解析一个 DNS 查询你可能在想：“为什么我们需要解析一个 DNS 查询？这是一个响应啊！”但每一个 DNS 响应包含它自己的原始查询，所以我们有必要去解析它。这是解析 DNS 查询的代码：class DNSQuery attr_reader :domain, :type, :cls def initialize(buf) @domain = read_domain_name(buf) @type, @cls = buf.read(4).unpack('nn') end end 内容不是太多：类型和类各占 2 个字节。步骤十二：解析一个 DNS 记录最让人兴奋的部分 —— DNS 记录是我们的查询数据存放的地方！即这个 “rdata 区域”（“记录数据字段”）就是我们会在 DNS 查询对应的响应中获得的 IP 地址所驻留的地方。代码如下：class DNSRecord attr_reader :name, :type, :class, :ttl, :rdlength, :rdata def initialize(buf) @name = read_domain_name(buf) @type, @class, @ttl, @rdlength = buf.read(10).unpack('nnNn') @rdata = buf.read(@rdlength) end 我们还需要让这个 rdata 区域更加可读。记录数据字段的实际用途取决于记录类型 —— 比如一个“A” 记录就是一个四个字节的 IP 地址，而一个 “CNAME” 记录则是一个域名。所以下面的代码可以让请求数据更可读：def read_rdata(buf, length) @type_name = TYPES[@type] || @type if @type_name == "CNAME" or @type_name == "NS" read_domain_name(buf) elsif @type_name == "A" buf.read(length).unpack('C*').join('.') else buf.read(length) end end 这个函数使用了 TYPES 这个哈希表将一个记录类型映射为一个更可读的名称：TYPES = { 1 => "A", 2 => "NS", 5 => "CNAME", # there are a lot more but we don't need them for this example } read.rdata 中最有趣的一部分可能就是这一行 buf.read(length).unpack('C*').join('.') —— 像是在说：“嘿！一个 IP 地址有 4 个字节，就将它转换成一组四个数字组成的数组，然后数字互相之间用 ‘.’ 联个谊吧。”步骤十三：解析 DNS 响应的收尾工作现在我们正式准备好解析 DNS 响应了！工作代码如下所示：class DNSResponse attr_reader :header, :queries, :answers, :authorities, :additionals def initialize(bytes) buf = StringIO.new(bytes) @header = DNSHeader.new(buf) @queries = (1..@header.num_questions).map { DNSQuery.new(buf) } @answers = (1..@header.num_answers).map { DNSRecord.new(buf) } @authorities = (1..@header.num_auth).map { DNSRecord.new(buf) } @additionals = (1..@header.num_additional).map { DNSRecord.new(buf) } end end 这里大部分内容就是在调用之前我们写过的其他函数来协助解析 DNS 响应。如果 @header.num_answers 的值为 2，代码会使用了 (1..@header.num_answers).map 这个巧妙的结构创建一个包含两个 DNS 记录的数组。（这可能有点像 Ruby 魔法，但我就是觉得有趣，但愿不会影响可读性。）我们可以把这段代码整合进我们的主函数中，就像这样：sock.send(make_dns_query("example.com", 1), 0) # 1 is "A", for IP address reply, _ = sock.recvfrom(1024) response = DNSResponse.new(reply) # parse the response!!! puts response.answers[0] 尽管输出结果看起来有点辣眼睛（类似于 #<DNSRecord:0x00000001368e3118>），所以我们需要编写一些好看的输出代码，提升它的可读性。步骤十四：对于我们输出的 DNS 记录进行美化我们需要向 DNS 记录增加一个 .to_s 字段，从而让它有一个更良好的字符串展示方式。而者只是做为一行方法的代码在 DNSRecord 中存在。def to_s "#{@name}\t\t#{@ttl}\t#{@type_name}\t#{@parsed_rdata}" end 你可能也注意到了我忽略了 DNS 记录中的 class 区域。那是因为它总是相同的（IN 表示 “internet”），所以我觉得它是个多余的。虽然很多 DNS 工具（像真正的 dig）会输出 class。大功告成！这是我们最终的主函数：def main # connect to google dns sock = UDPSocket.new sock.bind('0.0.0.0', 12345) sock.connect('8.8.8.8', 53) # send query domain = ARGV[0] sock.send(make_dns_query(domain, 1), 0) # receive & parse response reply, _ = sock.recvfrom(1024) response = DNSResponse.new(reply) response.answers.each do |record| puts record end 我不觉得我们还能再补充什么 —— 我们建立连接、发送一个查询、输出每一个回答，然后退出。完事儿！$ ruby dig.rb example.com example.com 18608 A 93.184.216.34 你可以在这里查看最终程序：dig.rb。可以根据你的喜好给它增加更多特性，就比如说：为其他查询类型添加美化输出。输出 DNS 响应时增加“授权”和“可追加”的选项重试查询确保我们看到的 DNS 响应匹配我们的查询（ID 信息必须是对的上的！）另外如果我在这篇文章中出现了什么错误，就 在推特和我聊聊吧。（我写的比较赶所以可能还是会有些错误）（题图：MJ/449d049d-6bdd-448b-a61d-17138f8551bc）via: https://jvns.ca/blog/2022/11/06/making-a-dns-query-in-ruby-from-scratch/作者：Julia Evans 选题：lujun9972 译者：Drwhooooo 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
我经常写关于我发现难以学习的技术的文章。不久前，我的朋友 Sumana 向我提出了一个有趣的问题 - 为什么这些东西学起来那么难？为什么它们看起来如此神秘？以 DNS 为例。我们从 80 年代 开始使用 DNS（已经超过 35 年了！）。它在互联网上的每个网站中都使用。而且它相当稳定 - 在很多方面，它的工作方式与 30 年前完全相同。但是我花了好几年的时间才弄清楚如何自信地调试 DNS 问题，我也见过很多其他程序员在调试 DNS 问题上苦苦挣扎。那么到底发生了什么呢？以下是关于为什么学习排除 DNS 问题很困难的几点思考。（我不会在这篇文章中详细解释 DNS，更多关于 DNS 如何工作的信息，请参阅 《用一个周末实现一个 DNS》 或 我的 DNS 方面的博文）并不是因为 DNS 非常难当我最终学会如何排除 DNS 问题时，我的反应是“什么，就这样吗？？？这并不难！”我感觉有点被骗了！我可以在 几个小时 内向你解释关于 DNS 令我感到困惑的一切事情。那么 - 如果 DNS 并不是那么复杂，为什么我花了这么多年的时间才弄清楚如何排除相当基本的 DNS 问题（比如“即使我已经正确设置了，我的域名仍无法解析”或者“dig 命令和我的浏览器的 DNS 结果不一致，为什么？”）？而且，在发现 DNS 学习困难方面，我并不孤单！我与许多经验丰富的程序员朋友讨论过多年来的 DNS 问题，其中很多人要么：不敢轻易对其网站进行简单的 DNS 更改或对 DNS 工作原理的基本事实感到困惑（比如记录是 拉取的而非推送的）或对 DNS 基础知识了解得很好，但却和我一样存在一些知识盲点（负缓存和 dig 命令及浏览器如何以不同方式进行 DNS 查询的细节）因此，如果我们都面临着 DNS 的相同困扰，到底发生了什么？为什么对许多人来说学习 DNS 如此困难？以下是我的一些看法。很多系统是隐藏的当你在计算机上发起 DNS 请求时，基本的过程如下：你的计算机向一个名为“解析器”的服务器发起请求。解析器检查其缓存，并向一些称为“权威名称服务器”的其它服务器发起请求。以下是你看不到的一些内容：解析器的缓存。里面有什么内容？在你的计算机上进行 DNS 请求的库代码是哪个（是否是 libc 的 getaddrinfo 函数？如果是，它是来自 glibc、musl 还是苹果？是你的浏览器的 DNS 代码吗？还是其他自定义的 DNS 实现？）所有这些选项的行为略有不同，并且有不同的配置、缓存方法、可用功能等等。例如，musl DNS 直到 2023 年初 才支持 TCP。解析器与权威名称服务器之间的对话。如果你能够神奇地获得一个准确记录你的请求期间向下游查询的每个权威名称服务器以及它们的响应的追踪，我认为很多 DNS 问题将变得非常简单。（比如，如果你能运行 dig +debug google.com 并获得一些额外的调试信息会怎么样？）如何和隐藏系统打交道以下是几个处理隐藏系统的方法：向人们传授隐藏系统的知识会产生重大影响。很长一段时间里，我不知道我的计算机有多个不同的 DNS 库，它们在不同情况下使用，我对此感到困惑了好几年。这是我的重要排错方法。通过 Mess With DNS，我们尝试了一种“鱼缸”的方法，展示了通常隐藏的系统（与解析器和权威名称服务器的对话）的一些部分。我觉得将 DNS 扩展以包括一个“调试信息”部分会非常酷。（注：似乎这已经有了！它被称为“扩展 DNS 错误”，即 EDE，各种工具正在逐渐添加对它的支持。）扩展 DNS 错误看起来不错扩展 DNS 错误是 DNS 服务器提供额外调试信息的一种新方式。以下是一个示例：$ dig @8.8.8.8 xjwudh.com ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 39830 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ; EDE: 12 (NSEC Missing): (Invalid denial of existence of xjwudh.com/a) ;; QUESTION SECTION: ;xjwudh.com. IN A ;; AUTHORITY SECTION: com. 900 IN SOA a.gtld-servers.net. nstld.verisign-grs.com. 1690634120 1800 900 604800 86400 ;; Query time: 92 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) (UDP) ;; WHEN: Sat Jul 29 08:35:45 EDT 2023 ;; MSG SIZE rcvd: 161 这里我请求了一个不存在的域名，并收到了扩展错误信息 EDE: 12 (NSEC Missing): (Invalid denial of existence of xjwudh.com/a)。我不太确定这是什么意思（它与 DNSSEC 有关），但能看到这样额外的调试信息真的很酷。为了能看到上述内容，我确实需要安装更新版本的 dig。令人困惑的工具尽管很多 DNS 的细节被隐藏起来，但你可以通过使用 dig 工具来找出发生了什么事情。例如，你可以使用 dig +norecurse 来确定给定的 DNS 解析器是否在其缓存中具有特定的记录。如果响应没有被缓存，8.8.8.8 看起来会返回 SERVFAIL 响应。以下是对 google.com 进行该操作的示例：$ dig +norecurse @8.8.8.8 google.com ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 11653 ;; flags: qr ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;google.com. IN A ;; ANSWER SECTION: google.com. 21 IN A 172.217.4.206 ;; Query time: 57 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Fri Jul 28 10:50:45 EDT 2023 ;; MSG SIZE rcvd: 55 这是对 homestarrunner.com 的示例：$ dig +norecurse @8.8.8.8 homestarrunner.com ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 55777 ;; flags: qr ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 512 ;; QUESTION SECTION: ;homestarrunner.com. IN A ;; Query time: 52 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Fri Jul 28 10:51:01 EDT 2023 ;; MSG SIZE rcvd: 47 在这里，你可以看到我们对于 google.com 得到了一个正常的 NOERROR 响应（8.8.8.8 的缓存中有该记录），但对于 homestarrunner.com 得到了 SERVFAIL 响应（没有缓存）。这并不意味着 homestarrunner.com 没有 DNS 记录（实际上有！），它只是没有被缓存。但如果你不熟悉这样的输出，它确实很难阅读！以下是我认为其中一些奇怪的地方：标题很奇怪（有 ->>HEADER<<-、flags:、OPT PSEUDOSECTION:、QUESTION SECTION:、ANSWER SECTION:）。空格排版很奇怪（OPT PSEUDOSECTION 和 QUESTION SECTION 之间为什么没有换行符？）。MSG SIZE rcvd: 47 很奇怪（MSG SIZE 中是否还有其他字段，而不仅仅是 rcvd？它们是什么？）。它说有 1 个记录在 ADDITIONAL 部分，但没有显示它，你必须以某种方式神奇地知道OPT PSEUDOSECTION 记录实际上在 ADDITIONAL 部分。总的来说，dig 的输出给人的感觉是一个以临时方式编写并随着时间的推移逐渐发展起来的脚本，而不是经过有意设计的东西。处理令人困惑的工具的一些想法：解释输出结果。例如，我写了一篇 如何使用 dig 的文章，解释了 dig 的输出结果以及如何配置它以默认给出更简短的输出。创建新的、更友好的工具。例如，在 DNS 方面，有 dog、doggo 和 我的 DNS 查询工具。我认为这些工具非常酷，但我个人不使用它们，因为有时我想做一些稍微高级一点的操作（比如使用 +norecurse），据我所知，无论是 dog 还是 doggo 都不支持 +norecurse。我更愿意使用一个工具来完成所有任务，所以我坚持使用 dig。要替换 dig，其功能广度是一项庞大的工作。使 dig 的输出更加友好。如果我在 C 编程方面更好一些，我可能会尝试编写一个 dig 的拉取请求，添加一个 +human 标志以以更结构化和易读的方式格式化长格式的输出，可能类似于以下形式：$ dig +human +norecurse @8.8.8.8 google.com HEADER: opcode: QUERY status: NOERROR id: 11653 flags: qr ra records: QUESTION: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 QUESTION SECTION: google.com. IN A ANSWER SECTION: google.com. 21 IN A 172.217.4.206 ADDITIONAL SECTION: EDNS: version: 0, flags:; udp: 512 EXTRA INFO: Time: Fri Jul 28 10:51:01 EDT 2023 Elapsed: 52 msec Server: 8.8.8.8:53 Protocol: UDP Response size: 47 bytes 这样可以更清晰地呈现 DNS 响应的结构-包括标题、问题、答案和附加部分。而且它并不是“简化”了什么！它是完全相同的信息，只是以更结构化的方式进行了格式化。我对替代的 DNS 工具最大的不满是它们经常为了清晰起见而删除信息。虽然这些工具肯定有其用武之地，但我想要看到所有的信息！我只是希望它能够以清晰明了的方式呈现。在过去的 40 年中，我们已经学到了很多关于如何设计更用户友好的命令行工具的知识，我认为将其中一些知识应用到我们那些有些陈旧的工具中将会很棒。dig +yaml关于 dig 的一个简单备注：较新版本的 dig 支持 +yaml 输出格式，对我来说更加清晰，但有些冗长（一个相当简单的 DNS 响应都无法在屏幕上完整显示）。一些奇怪的陷阱DNS 存在一些相对常见但很难通过自学了解到的奇怪问题。以下是一些例子（有更多可在 导致 DNS 中断的一些方式 中找到）：负缓存：我在 这篇演讲 中提到过，我大约花了 5 年时间才意识到不应该访问没有 DNS 记录的域名，因为该记录的 不存在 信息将被缓存，并且该缓存在几个小时内不会被更新，这真的很烦人。getaddrinfo 实现的差异：直到 2023 年初，musl 不支持 TCP DNS。忽略 TTL 的解析器：如果你在 DNS 记录上设置了 TTL（比如“5 分钟”），一些解析器完全会忽略这些 TTL 设置，并将记录缓存更长时间，比如可能是 24 小时。如果你错误地配置了 Nginx（像这样），它将永久缓存 DNS 记录。ndots 如何导致 Kubernetes DNS 缓慢。如何应对奇怪的陷阱对此，我没有像我希望的那样完美的答案。对奇怪陷阱的了解非常难以获得（再次强调，我花了多年的时间才弄清楚负缓存！），对我而言，人们不得不一次又一次地自己重新发现它们感觉很愚蠢。以下是一些想法：当有人在解释一个主题时提到了一些棘手的问题，这是非常有帮助的。例如（离开 DNS 一下），Josh Comeau 的 Flexbox 入门解释了这个 最小尺寸的陷阱，在找到解释之前，我多年来遇到过很多次这个问题。我希望看到更多的社区整理的常见陷阱。比如说，对于 Bash，shellcheck 是一个非常不错的常见陷阱集合。关于记录 DNS 陷阱的一个棘手问题是，不同的人会遇到不同的陷阱。如果你只是每三年为个人域名配置一次 DNS，你可能会遇到不同的问题，而那些管理高流量域名的人则可能会遇到其他问题。还有一些更简单的原因：不经常接触很多人非常少接触 DNS。如果你只在每三年才处理一次 DNS，学习起来就会更加困难！我认为备忘单（比如“这是更改你的名称服务器的步骤”）可以在这方面起到很大的帮助。难以进行实验DNS 在进行实验时可能会让人感到害怕，因为你不想搞砸自己的域名。我们建立了 Mess With DNS 来使这个过程变得更容易一些。目前就这些我很想听听其他关于什么让 DNS（或你最喜欢的神秘技术）难以学习的想法。（题图：MJ/96c5d8fb-f4a5-4710-8f91-c71617120675）via: https://jvns.ca/blog/2023/07/28/why-is-dns-still-hard-to-learn/作者：Julia Evans 选题：lujun9972 译者：ChatGPT 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
当我第一次知道 DNS 时，我想它应该不会很复杂。不就是一些存储在服务器上的 DNS 记录罢了。有什么大不了的？但是教科书上只是介绍了 DNS 的原理，并没有告诉你实际使用中 DNS 可能会以多少种方式破坏你的系统。这可不仅仅是缓存问题！所以我 在 Twitter 上发起了一个提问，征集人们遇到的 DNS 问题，尤其是那些一开始看起来与 DNS 没什么关系的问题。（“总是 DNS 问题”这个梗）我不打算在这篇文章中讨论如何解决或避免这些问题，但我会放一些讨论这些问题的链接，在那里可以找到解决问题的方法。问题：网络请求缓慢如果你的网络比预期的要慢，这是因为某些原因导致 DNS 解析器变慢了。这可能是解析器负载过大或者存在内存泄漏等原因导致的。我的路由器的 DNS 转发器曾遇到过这个问题，导致我的所有 DNS 请求很慢。我通过重启路由器解决了这个问题。问题：DNS 超时一些网友提到由于 DNS 查询超时，他们的网络请求需要耗时 2 秒多甚至 30 秒。这跟“网络请求缓慢”问题类似，但情况要更糟糕，因为 DNS 请求就会消耗掉几秒钟时间。Sophie Haskins 有一篇关于 Kubernete DNS 超时的博客文章 一次 Kube DNS 踩坑经历。问题：ndots 设置一些网友提到在 /etc/resolv.conf 中设置 ndots:5 时会出现问题。下面是从 这篇《Kubernetes 容器荚中 /etc/resolv.conf 里设置 ndots:5 为什么会拖慢你的程序性能》中引用的 /etc/resolv.conf文件。 nameserver 100.64.0.10 search namespace.svc.cluster.local svc.cluster.local cluster.local eu-west-1.compute.internal options ndots:5 如果你用上面的配置文件，想要查询得域名是 google.com，那么你的程序会调用 getaddrinfo 函数，而它会依次查询以下域名：google.com.namespace.svc.cluster.local.google.com.svc.cluster.local.google.com.cluster.local.google.com.eu-west-1.compute.internal.google.com.简单来说，它会检查 google.com 是不是 search 这一行中的某个子域名。所以每发起一次 DNS 查询，你都得先等待前 4 次查询失败后才能获取到最终查询结果。问题：难以判断系统使用的 DNS 解析器这本身并不是一个问题，但当你遇到 DNS 问题时，一般都会跟 DNS 解析器有关。我没有一种判断 DNS 解析器的万能方法。下面是我知道的方法：在 Linux 系统上，最常见的是通过 /etc/resolv.conf 来选择 DNS 解析器。但是也有例外，比如浏览器可能会忽略 /etc/resolv.conf，而是使用 基于 HTTPS 的 DNS DNS-over-HTTPS 服务。如果你使用的是 UDP DNS，你可以通过 sudo tcpdump port 53 来查看 DNS 请求被发送到了哪里。但如果你使用的是基于 HTTPS 的 DNS 或 基于 TLS 的 DNS DNS over TLS ，这个方法就不行了。我依稀记得这在 MacOS 系统上会更加令人迷惑，我也不清楚原因。问题：DNS 服务器返回 NXDOMAIN 而不是 NOERROR这是我曾经遇到过的一个 Nginx 不能解析域名的问题。我设置 Nginx 使用一个特定的 DNS 服务器来解析 DNS 查询当访问这个域名时，Nginx 做了两次查询，第一次是对 A 的，第二次是对 AAAA 的对于 A 的查询，DNS 服务器返回 NXDOMAINNginx 认为这个域名不存在，然后放弃查询对于 AAAA 的查询 DNS 服务器返回了成功但 Nginx 忽略了对 AAAA 返回的查询结果，因为它前面已经放弃查询了问题出在 DNS 服务器本应该返回 NOERROR 的——那个域名确实存在，只是没有关于 A 的记录罢了。我报告了这个问题，然后他们修复了这个问题。我自己也写出过这个问题，所以我理解为什么会发生这种情况——很容易想当然地认为“没有要查询的记录，就应该返回 NXDOMAIN 错误码”。问题：自动生效的 DNS 缓存如果你在生成一个域名的 DNS 记录之前就访问这个域名，那么这个记录的缺失会被缓存起来。当你第一次遇到这个问题时一定会非常吃惊——我也是去年才知道有这个问题。缓存的 TTL 就是域名的 起始权限记录 Start of Authority （SOA） 记录的 TTL ——比如对于 jvns.ca ，这个值是一个小时。问题：Nginx 永久缓存 DNS 记录如果你在 Nginx 中使用下面的配置： location / { proxy_pass https://some.domain.com; } Nginx 只会在启动的时候解析一次 some.domain.com，以后不会再对其进行解析。这是非常危险的操作，尤其是对于那些 IP 地址经常变动的域名。它可能平安无事地运行几个月，然后突然在某个凌晨两点把你从床上纠起来。针对这个问题已经有很多众所周知的方法了，但由于本文不是关于 Nginx 的，所以我不打算深入探讨它。但你第一次遇到它时一定会很惊讶。这是一篇关于这个问题发生在 AWS 负载均衡器上的 博客文章。问题：Java 永久缓存 DNS 记录跟上面类似的问题，只是出现在 Java 上：据说 这与你 Java 的配置有关。“JVM 的默认 TTL 设置可能会导致只有 JVM 重启时才会刷新 DNS 记录。”我还没有遇到过这个问题，不过我那些经常写 Java 的朋友遇到过这个问题。当然，任何软件都可能存在永久缓存 DNS 的问题，但据我所知它经常出现在 Nginx 和 Java 上。问题：被遗忘的 /etc/hosts 记录这是另一种缓存问题：/etc/hosts 中的记录会覆盖你的常规 DNS 设置！让人迷惑的是 dig 命令会忽略 /etc/hosts 文件。所以当你使用 dig whatever.com 来查询 DNS 信息时，它会告诉你一切正常。问题：电子邮件未发送 / 将成为垃圾邮件电子邮件是通过 DNS（MX 记录, SPF 记录, DKIM 记录）来发送和验证的，所以有些电子邮件问题其实是 DNS 问题。问题：对国际化域名无效你可以使用非 ASCII 字符甚至是表情符来注册域名，比如 拉屎网 https://?.la。DNS 能够处理国际化域名是因为 ?.la 会被用 punycode 编码将转换为 xn--ls8h.la。尽管已经有了 DNS 处理国际化域名的标准，很多软件并不能很好地处理国际化域名。Julian Squires 的 干掉 Chrome 浏览器的表情符！！ 就是一个非常有趣的例子。问题：TCP DNS 被防火墙拦截有人提到一些防火墙会允许在 53 端口上使用 UDP 协议，但是禁止 TCP 协议。然而很多 DNS 查询需要在 53 端口上使用 TCP，这可能会导致很难排查的间歇性的问题。问题：musl 不支持 TCP DNS很多应用程序使用 libc 的 getaddrinfo 来做 DNS 查询。musl 是用在 Alpine Docker 容器上的 glibc 替代品。而它不支持 TCP DNS。如果你的 DNS 查询的响应数据超过 DNS UDP 数据包的大小（512 字节）就会出现问题。我对此仍然不太清楚，我下面我的理解也可能是错的:musl 的 getaddrinfo 发起一个 DNS 请求DNS 服务器发现请求的响应数据太大了，没法放入一个 DNS 数据包中DNS 服务器返回一个 空截断响应 empty truncated response ，并期望客户端通过 TCP DNS 重新用发起查询但 musl 不支持 TCP DNS，所以根本不会重试关于这个问题的文章：在 Alpine Linux 上的 DNS 解析问题。问题：getaddrinfo 不支持轮询 DNS 轮询 round robin DNS 是一种 负载均衡 load balancing 技术，每次 DNS 查询都会获得一个不同的 IP 地址。显然如果你使用 gethostbyname 做 DNS 查询不会有任何问题，但是用 getaddrinfo 就不行了。因为 getaddrinfo 会对获得的 IP 地址进行排序。在你从 gethostbyname 切换到 getaddrinfo 时可能完全不会意识到这可能会引起负载均衡问题。这个问题可能会非常隐蔽，如果你不是用 C 语言编程的话，这些函数调用被隐藏在各种调用库背后，你可能完全意识不到发生了这种改变。所以某次看似人畜无害的升级就可能导致你的 DNS 负载均衡失效。下面是讨论这个的一些文章：getaddrinfo 导致轮询 DNS 失效getaddrinfo，轮询 DNS 和 happy eyeballs 算法问题：启动服务时的竞争条件有人 提到 使用 Kubernete DNS 时遇到的问题：他们有两个同时启动的容器，一旦启动就会立即尝试解析对方的地址。由于 Kubernete DNS 还没有改变，所以 DNS 查询会失败。这个失败会被缓存起来，所以后续的查询会一直失败。写在最后我所列举的不过是 DNS 问题的冰山一角，期待大家告诉我那些我没有提到的问题和相关链接。我希望了解这些问题在实际中是如何发生的以及如何被解决的。（题图：MJ/f512f18e-2e1d-4614-bed1-b0a0c373e14d）via: https://jvns.ca/blog/2022/01/15/some-ways-dns-can-break/作者：Julia Evans 选题：lujun9972 译者：toknow-gh 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
如何设置自己的保护隐私的 DNS 服务器
通过开源项目 AdGuard Home 运行你自己的 DNS 服务器来控制你的互联网隐私。域名服务器（DNS）将域名（如 example.com）与 IP 地址（如 93.184.216.34）相关联。这就是当你输入 URL 或搜索引擎返回 URL 供你访问时，你的网络浏览器如何知道在世界的哪个地方寻找数据。DNS 为互联网用户提供了极大的便利，但也并非没有缺点。例如，付费广告会出现在网页上，因为你的浏览器会自然的使用 DNS 来解析这些广告在互联网上“存在”的位置。同样，跟踪你在线活动的软件通常由通过 DNS 解析的服务启用。你不想完全关闭 DNS，因为它非常有用。但是你可以运行自己的 DNS 服务，以便更好地控制它的使用方式。我相信运行自己的 DNS 服务器至关重要，这样你就可以阻止广告并保持你的浏览隐私，远离试图分析你的在线交互的提供商。我过去用过 Pi-hole，今天仍然推荐它。然而，最近，我一直在我的网络上运行开源项目 AdGuard Home。我发现它有一些值得探索的独特功能。AdGuard Home在我使用过的开源 DNS 软件中，AdGuard Home 是最容易设置和维护的。你可以在一个项目中获得许多 DNS 解析解决方案，例如 DNS over TLS、DNS over HTTPS 和 DNS over QUIC。你可以使用一个脚本将 AdGuard 设置为容器或本地服务：$ curl -s -S -L \ https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh 查看这个脚本以便了解它的作用。了解了它的工作过程后，再运行它：$ sh ./install.sh 我最喜欢 AdGuard Home 的一些功能：一个简单的管理界面使用 AdGuard 阻止列表来阻止广告和恶意软件单独配置网络上每个设备的选项强制在特定设备上进行安全搜索为管理界面设置 HTTPS，这样与它的远程交互是完全加密的我发现 AdGuard Home 为我节省了时间。它的黑名单比 Pi-hole 上的黑名单更强大。你可以快速轻松地将其配置为 DNS over HTTPS。没有更多的恶意软件恶意软件是你计算机上不需要的内容。它并不总是对你有直接危险，但它可能会为第三方带来危险活动。这不是互联网最初的目的。我认为你应该托管自己的 DNS 服务，以保护你的互联网历史记录的私密性，并避免被微软、谷歌和亚马逊等已知跟踪器掌握。在你的网络上试用 AdGuard Home 吧。via: https://opensource.com/article/23/3/open-source-dns-server作者：Amar Gandhi 选题：lkxed 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
硬核观察 #886 谷歌公共 DNS 服务正在推行大小写混杂查询
谷歌公共 DNS 服务正在推行大小写混杂查询在 DNS over TLS 之前，DNS 查询由于技术原因会被投毒，从而导致客户端访问到投毒者设置的假冒地址。为了避免这种安全风险，最好的方式是使用 DNS over TLS 这样的加密查询通道。但是仍然有大量的 DNS 服务器没有或不能使用加密查询。谷歌从 2009 年就在小范围实验一种名为 0x20 的做法，它可以将查询的域名随机改变字母大小写，这可以有效的提高 DNS 投毒的难度。现在谷歌已经扩大了该方案，已经覆盖了 90% 没有使用加密查询的 DNS 服务器。消息来源：The Register老王点评：以后在你的权威 DNS 服务器上看到类似 liNUx.cN 这样的查询不要惊奇。290 款微星主板的安全启动默认被绕过安全启动是 UEFI 主板固件中的一项安全功能，确保在启动过程中只有受信任的（签名）软件可以执行。研究发现，微星公司在 2021 年 9 月至 2022 年 1 月期间发布的固件更新，改变了微星主板上的一个默认安全启动设置，该设置允许任何操作系统镜像运行，无论其是否有错误或丢失的签名。受影响的主板超过了 290 款，包括最新的用于英特尔和 AMD CPU 的微星主板。消息来源：Bleeping Computer老王点评：我觉得讨厌安全启动功能的人会喜欢这个默认设置。USB4 2.0 规格正式发布，USB-C 可达 120GbpsUSB-C 是令人困惑的，一个 USB-C 端口或电缆可以支持一系列的速度、电源能力和其他功能，它支持的数据传输速率，可以从 USB 2.0 的 0.48Gbps 一直到 USB4 和雷电 3/4 的 40Gbps。USB 实施者论坛（USB-IF）今天发布了 USB4 2.0 规范，它增加了对 80Gbps 双向带宽的可选支持，以及以高达 120Gbps 速度发送或接收数据的可选能力。但预计在至少 12 到 18 个月内不会看到支持新规格的产品出现。消息来源：USB-IF老王点评：都是一种样子的接口，但是有的电缆就特别优秀。?回音自去年 9 月 宣布 以来，谷歌今天正式 关闭 了其 Stadia 云游戏平台。除了对用户购买的软硬件退款之外，他们还使其游戏手柄能够使用蓝牙，以便在其他游戏平台上使用。
硬核观察 #837 20 个企业控制了一半的域名解析
20 个企业控制了一半的域名解析据分析，来自 20 个域名的 255 台 DNS 服务器控制了 52% 的域名解析，100 个域名的 DNS 服务器控制了 75% 的域名解析，6000 个域名的 DNS 服务器控制了 99% 的域名解析。控制域名解析的前 20 个域名来自互联网巨头，其中 15 个是美国科技巨头，如 GoDaddy、谷歌、Cloudflare 和亚马逊。其中 34% 的域名解析的 IP 地址属于 Cloudflare 的自治系统 AS13335。消息来源：Netmeister老王点评：互联网其实不是去中心化的，而是分布式的。Mastodon 的安全性并不可靠自从 Twitter 被收购后，Mastodon 引来了大量注意，用户数量激增，两周内总用户达到 870 万。有安全专家发现多个存在安全漏洞的 Mastodon 实例。Mastodon 项目缺乏专门的安全团队，甚至软件也没有自动更新或检查更新的功能。消息来源：Ars Technica老王点评：随着用户增多，安全问题就成了大问题，好在 Mastodon 本身并不收集太多用户数据。Let's Encrypt 签发了逾三十亿证书目前全球有数以百万计的网站依赖 Let's Encrypt 作为安全保障。其 2022 年年度报告中称，截至 2022 年 11 月 1 日，它为超过 3.09 亿个域名提供了证书，仅 2022 年增加了逾 3300 万个域名。Let's Encrypt 在 2017 年 6 月签发了第一亿个证书。三年后的 2020 年 2 月签发了第 10 亿个证书。消息来源：Let's Encrypt老王点评：Let's Encrypt 功莫大焉，要是一直由 CA 公司把持 SSL 证书的签发，HTTPS 的普及可能会慢得多。
大家好！今年早些时候，我在写《DNS 是如何工作的》 时，有人问我——为什么人们有时在域名的末尾加一个点？例如，如果你通过运行 dig example.com 查询 example.com 的 IP，你会看到一下内容：$ dig example.com example.com. 5678 IN A 93.184.216.34 执行完 dig 命令后，example.com 有一个 . ——变成了 example.com.！发生了什么？有些 DNS 工具也要求传给它的域名后加一个 .：如果你在使用 miekg/dns 时传给它 example.com，它会报错：// trying to send this message will return an error m := new(dns.Msg) m.SetQuestion("example.com", dns.TypeA) 最初我以为我知道这个问题的答案（“呃，末尾的点意味着域名是完全限定的？”）。这是对的 —— 一个 完全限定域名 fully qualified domain name （FQDN）是一个末尾有 . 的域名！但是为什么末尾的点是有用且重要的呢？在 DNS 的请求/响应中，域名的末尾并没有 “.”我曾经（错误地）认为 “为什么末尾有一个点？”的答案可能是 “在 DNS 请求/响应中，域名末尾有一个 .，所以我们把它放进去，以匹配你的计算机实际发送/接收的内容”。但事实并不是这样！当计算机发送 DNS 请求/响应时，域名的末尾并没有点。实际上，域名中没有点。域名会被编码成一系列的长度/字符串对。例如，域名 example.com 被编码为这 13 个字节。7example3com0 编码后的内容一个点也没有。一个 ASCII 域名（如 example.com）被转成了各种 DNS 软件的 DNS 请求/响应中使用的格式。今天我们来讨论域名被转成 DNS 响应的一个地方：区域文件。区域文件中域名末尾的 “.”一些人管理域名的 DNS 记录的方法是创建一个被称为 “区域文件” 的文本文件，然后配置一些 DNS 服务器软件（如 nsd 或 bind）来为该区域文件中指定的 DNS 记录提供服务。下面是一个对应 example.com 的示例区域文件：orange 300 IN A 1.2.3.4 fruit 300 IN CNAME orange grape 3000 IN CNAME example.com. 在这个文件中，任何不以 . 结尾的域名（比如 orange）后都会自动加上 .example.com。所以 orange 成了 orange.example.com 的简称。DNS 服务器从它的配置中得知这是一个 example.com 的区域文件，所以它知道在所有不以点结尾的名字后面自动添加 example.com。我想这里的想法只是为了少打几个字符——如果要打出全称，区域文件会是这样： orange.example.com. 300 IN A 1.2.3.4 fruit.example.com. 300 IN CNAME orange.example.com. grape.example.com. 3000 IN CNAME example.com. 确实多了很多字符。你也可以不通过区域文件来使用 DNS尽管官方的 DNS RFC（RFC 1035）中定义了区域文件格式，但你也可以不通过区域文件来使用 DNS。例如，AWS Route 53 就不用区域文件来存储 DNS 记录！你可以通过 Web 界面或 API 来创建记录，我猜他们是用某种数据库而不是一堆文本文件来存储记录。不过，Route 53（像许多其他 DNS 工具一样）确实支持导入和导出区域文件，这个功能或许在你更换 DNS 提供商时很有用。dig 命令输出中末尾的 “.”现在我们来讨论下 dig 命令的输出：$ dig example.com ; <<>> DiG 9.18.1-1ubuntu1.1-Ubuntu <<>> +all example.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10712 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 65494 ;; QUESTION SECTION: ;example.com. IN A ;; ANSWER SECTION: example.com. 81239 IN A 93.184.216.34 有一件奇怪的事是，几乎每一行都以 ;; 开头，这是怎么回事？; 是区域文件中的注释字符！我想 dig 以这种奇怪的方式输出的原因可能是为了方便你粘贴这些内容到区域文件时，不用修改就可以直接用。这也是 example.com 末尾有个 . 的原因 —— 区域文件要求域名末尾必须有点（否则它们会被解释为是相对于该区域的）。因此 dig 也这么处理了。我真的希望 dig 有一个 +human 选项，以更人性化的方式打印出这些信息，但现在我太懒了，懒得花工夫去实际贡献代码来做这件事（而且我并不擅长 C），所以我只能在我的博客上抱怨一下 :smiley:curl 命令输出中末尾的 “.”我们来看下另一个末尾有 . 的例子：curl！我家里有台计算机名为 grapefruit，其上运行着 Web 服务器。当我执行 curl grapefruit 时，会输出：$ curl grapefruit ...... 这样运行没问题！但是如果我在域名后加一个 . 会怎样呢？它报错了：$ curl grapefruit. curl: (6) Could not resolve host: grapefruit. 发生了什么？为了搞清楚，我们需要先来学习下搜索域：初识搜索域当我执行 curl grapefrult 时，它是怎么被转成一个 DNS 请求的？你可能会认为我的计算机会向域名 grapefruit 发送一个请求，对吗？但事实并不是这样。让我们用 tcpdump 来看看到底是什么域名在被查询。$ sudo tcpdump -i any port 53 [...] A? grapefruit.lan. (32) 实际上是向 grapefruit.lan. 发送的请求。为什么呢？解释一下：curl 调用函数 getaddrinfo 来查询 grapefruitgetaddrinfo 查询了我计算机上的文件 /etc/resolv.conf/etc/resolv.conf 包含两行内容：nameserver 127.0.0.53 search lan 因为有 search lan 这行内容，所以 getaddrinfo 在 grapefruit 的末尾添加了一个 lan，去查询 grapefruit.lan什么时候搜索域被使用?现在我们知道了一些奇怪的事情：当我们查询一个域名时，有时会有一个额外的东西（如 lan）被加到最后。但是什么时候会发生这种情况呢？如果我们在域名末尾添加一个 .，那么这时不会用到搜索域如果域名中间包含一个 .（如 example.com），那么默认也不会用到搜索域。但是可以通过修改配置来改变处理逻辑（在 ndots 里有更详细的说明）我们现在知道了 curl grapefruit. 与 curl grapefruit 结果不一样的原因——因为一个查询的是 grapefruit.，而另一个查询的是 grapefruit.lan.。我的计算机怎么知道使用哪个搜索域呢？当我连接路由时，它会通过 DHCP 告诉我它的搜索域是 lan —— 它也是通过这个方式给我的计算机分配 IP。所以为什么要在域名末尾加一个点呢？现在我们已经了解了区域文件和搜索域，下面是我认为的人们要在域名末尾加点的原因：有两种情况下，域名会被修改，并在末尾添加其他东西。在 example.com 的区域文件中，grapefruit 会被转为 grapefruit.example.com在我的本地网络（我的计算机已经配置了使用搜索域 lan），grapefruit 被转为 grapefruit.lan因此，由于域名在某些情况下实际上可能被转成其他名字，人们就在结尾处加一个 .，以此来表示 “这是域名，末尾不需要添加任何东西，这就是全部内容”。否则会引起混乱。“这就是全部内容”的技术术语是**“完全限定域名”，简称为“FQDN”**。所以 google.com. 是一个完全限定域名，而 google.com 不是。我总是要提醒自己这样做的原因，因为我很少使用区域文件和搜索域，所以我经常觉得——“我当然是指 google.com 而不是 google.com.something.else! 我为什么要指其他东西？那太傻了！”但是有些人确实在使用区域文件和搜索域（例如 Kubernetes 中使用了搜索域！），所以结尾的 . 很有用，可以让人确切的知道，不应该再添加其他东西。什么时候在末尾添加 “.”？以下是关于何时在域名末尾加 ". " 的几个简单说明：需要添加：配置 DNS 时在配置 DNS 时，使用完全限定域名从来都不是坏事。你不一定要这样做：非完全限定域名通常也能正常工作，但我从来没有遇到过不接受完全限定域名的 DNS 软件。有些 DNS 软件需要这样做：现在我为 jvns.ca 使用的 DNS 服务器让我在域名的末尾加上 .（例如在 CNAME 记录中），并提示如果我不添加，它将在我输入的内容末尾加上 .jvns.ca。我不同意这个设计决定，但这不是什么大问题，我只是在最后加一个 .。不需要加：在浏览器中令人困惑的是，在浏览器中，在域名结尾处加一个 . 不能正常运行。例如，如果我在浏览器中输入 https://twitter.com.，它就会报错。它会返回 404。我认为这里发生的事情是，它将 HTTP Host 标头设置为 Host：twitter.com.，而对端的 Web 服务器则期望 Host：twitter.com。同样地，https://jvns.ca. 由于某种原因，返回了一个 SSL 错误。我认为相对域名在过去是比较常见的最后一件事：我认为“相对”域名（比如我用 grapefruit 来指代我家的另一台计算机 grapefruit.lan）在过去更常用，因为 DNS 是在大学或其他有大型内部网络的大机构中开发的。在今天的互联网上，使用“绝对”域名（如 example.com）似乎更为普遍。via: https://jvns.ca/blog/2022/09/12/why-do-domain-names-end-with-a-dot-/作者：Julia Evans 选题：lujun9972 译者：lxbwolf 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
Fedora 38 考虑提供面向手机的版本虽然 Fedora 37 还没有发布，但是开发人员已经在计划下一个版本。一个新的提案建议提供一个面向移动设备的 Phosh 镜像，用于运行专注于智能手机和平板电脑的 Wayland shell，同时提供一个良好的基于 GNOME 的体验。另外预计也会引入一个带有 KDE Plasma Mobile 的镜像。Fedora 38 预计明年春天发布。消息来源：Phoronix老王点评：期待看到 Fedora 运行在手机上。罗马法院要求 Cloudflare 的 DNS 封锁 BT 网站罗马法院已经确认，Cloudflare 必须通过其公共的 1.1.1.1 DNS 解析器阻止三个 BT 网站。Cloudflare 并不反对阻止针对其客户网站的请求，但认为干扰其 DNS 解析器是有问题的，因为这些措施不容易在地理上加以限制，将影响封锁该政府管辖范围以外的终端用户。消息来源：Slashdot老王点评：DNS 作为互联网流量入口的方向标，屡屡被用来做各种滥用。已经习惯了，不是吗？15000 个网站被黑帽 SEO 利用安全专家发现，有 15000 个网站（其中大部分是 WordPress 网站），这些网站被重定向到虚假的问答讨论区。恶意威胁者的目标是产生足够的索引页面，以增加虚假问答网站的权重，从而在搜索引擎中获得更好的排名。消息来源：Bleeping Computer老王点评：WordPress 这样的 CMS 系统越流行，其被一网打尽的可能越多，尤其是都采用了某些存在缺陷的插件或主题时。
使得 DNS 难以理解的事情之一是它是 分布式的。有成千上万（也许是几十万？我不知道！）的 权威性域名服务器 authoritative nameserver ，以及至少 1000 万个解析器。而且它们正在运行许多不同的软件！不同服务器运行着不同的软件意味着 DNS 的工作方式有很多不一致的地方，这可能导致各种令人沮丧的问题。但是，与其谈论这些问题，我更感兴趣的是弄清楚 —— 为什么 DNS 是分布式的是一件好事？为什么 DNS 是分布式的是件好事？一个原因是 可扩展性 —— DNS 的分布式设计使其更容易扩展，对故障的恢复能力更强。我发现，尽管 DNS 已经有近 40 年的历史，但它的扩展性仍然很好，这真是令人惊讶。这一点非常重要，但这并不是这篇文章的主题。相反，我想说的是，它是分布式的意味着你可以 控制 你的 DNS 的工作方式。你可以向巨大而复杂的 DNS 服务器中添加更多的服务器！添加你控制的服务器！昨天我 在 Twitter 上问 为什么你要运行自己的 DNS 服务器，我得到了很多很好的答案，我想在这里总结一下。你可以运行 2 种类型的 DNS 服务器你可以运行 2 种主要类型的 DNS 服务器：如果你拥有一个域名，你可以为该域名运行一个 权威名称服务器如果你有一台电脑（或一个有很多电脑的公司），你可以运行一个 解析器 来为这些电脑解析 DNS。DNS 不是静态数据库我经常看到 DNS 的 “电话簿” 比喻，域名就像人名，IP 地址就像电话号码。这是一个不错的思维模型。但是，“电话簿” 思维模型可能会使你认为，如果你对 google.com 进行 DNS 查询，你将永远得到相同的结果。而这是不正确的。你在 DNS 查询中得到的记录可能取决于：你在世界的哪个地方（也许你会得到一个离你更近的服务器的 IP 地址）你是否在企业网络里（你可以在其中解析内部域名）该域名是否被你的 DNS 解析器认为是 “坏” 的（它可能被封锁！）之前的 DNS 查询（也许 DNS 解析器正在做基于 DNS 的负载平衡，每次给你一个不同的 IP 地址）你是否在使用机场 Wi-Fi 专属门户（机场 Wi-Fi 会在你登录前以不同的方式解析 DNS 记录，它会给你发送一个特殊的 IP 来重定向你）随便什么你可能想控制你自己的服务器的很多原因都与 DNS 不是一个静态数据库这一事实有关 —— 对于如何处理 DNS 查询，你可能会有不同的选择（无论是为你的域名还是为你的组织）。运行权威性名称服务器的理由这些原因并没有任何特定的顺序。对于其中一些原因，你不一定必须要运行你自己的权威名称服务器，你只需选择提供了该功能的权威名称服务器服务就行了。要明确的是：有很多理由 不 运行自己的权威名称服务器 —— 我就没有运行，我也不想说服你应该这样做。它需要时间来维护，你的服务可能不那么可靠，等等。原因：安全这条推文说的很好：[存在] 攻击者通过你的 DNS 供应商的客户支持人员获得 DNS 变更权限的风险，客服本来只应该提供帮助。他们可以被你的 DNS 阻止（也许就是因为缺少这个）。内部可能更容易审计和验证内容。原因：你喜欢运行 bind/nsd有几个人提到的一个原因是：“我习惯于编写区域文件和运行 bind 或 nsd ，对我来说这样做更容易。”如果你喜欢 bind/nsd 的方式，但又不想运维自己的服务器，有几个人提到，你也可以通过运行一个 “隐藏的主服务器” 来获得 bind 的优势，该服务器存储记录，但从一个 “辅助” 服务器提供所有的实际 DNS 查询。这里有一些我发现的关于配置辅助 DNS 的网页，以 NS1、cloudflare 和 Dyn 作为示例。我真的不知道什么是最佳的权威 DNS 服务器。我想我只在工作中使用过 nsd。原因：你可以使用新的记录类型并非所有的 DNS 服务都支持某些较新的 DNS 记录类型，但如果你运行你自己的 DNS，你就可以支持任何你想要的记录类型。原因：用户界面你可能不喜欢你正在使用的 DNS 服务的用户界面（或 API，或干脆没有 API）。这与 “你喜欢运行 BIND ”的原因差不多，也许你喜欢编写区域文件的方式。原因：你可以自己修复问题当问题出现时，能够自己解决，有一些明显的优点和缺点（优点：你可以解决问题，缺点：你必须解决问题）。原因：做一些奇怪的、自定义的事情你可以写一个 DNS 服务器，做任何你想做的事情，它不一定要只返回一组静态记录。有几个例子：Replit 有一篇博文介绍了 为什么他们编写自己的权威性 DNS 服务器来处理路由nip.io 将 10.0.0.1.nip.io 映射为 10.0.0.1我为 乱用 dns 而写了一个自定义 DNS 服务器原因：省钱权威名称服务器似乎一般按每百万次 DNS 查询收费。比如，似乎 Route 53 每百万次查询收费 0.5 美元，NS1 每百万次查询收费约 8 美元。我对一个大型网站的权威 DNS 服务器实际需要解决多少次查询没有概念（哪些类型的网站会对其权威 DNS 服务器进行 10 亿次 DNS 查询？可能是很多，但我没有这方面的经验）。但是有几个人在回复中提到成本是一个原因。原因：你可以改变你的注册商如果你为你的域名使用一个单独的权威名称服务器，而不是你的注册商的名称服务器，那么当你转移到一个不同的注册商时，你所要做的就是把你的权威 DNS 服务器设置为正确的值，从而使你的 DNS 恢复正常。你不需要迁移你所有的 DNS 记录，那非常痛苦。但你不需要为此而运行你自己的名字服务器。原因：地理 DNS你可能想根据客户的位置为你的域名返回不同的 IP 地址，给他们一个离他们很近的服务器。这是很多权威的域名服务器服务所提供的服务，你不需要为此而专门运行名字服务器。原因：避免针对他人的拒绝服务攻击许多权威 DNS 服务器是共享的。这意味着，如果有人攻击 google.com 或其他的 DNS 服务器，而你恰好在使用同一个权威 DNS 服务器，你可能会受到影响，即使攻击不是针对你。例如，2016 年的这次 对 Dyn 的 DDoS 攻击。原因：把所有的配置放在一个地方有一个人提到，他们喜欢把所有的配置（DNS 记录、let's encrypt、nginx 等）放在一台服务器上的同一个地方。另类原因：把 DNS 当作 VPN 使用显然，iodine 是一个可以让你通过 DNS 隧道传输流量的权威 DNS 服务器，它可以让你像 VPN 一样与外界联系，运行解析器的原因原因：隐私如果有人能看到你所有的 DNS 查询，他们就有你（或你组织中的每个人）正在访问的所有域名的完整列表！你可能更愿意保持这种隐私。你可能更愿意保持这种隐私。原因：阻止恶意网站如果你运行你自己的解析器，你可以（通过不返回任何结果）拒绝解析你认为 “坏” 的域名的 DNS 查询。几个你可以自己运行（或只是使用）的解析器的例子：Pi-Hole 阻止广告商Quad9 阻止做恶意软件/网络钓鱼/间谍软件的域名。 Cloudflare 似乎有一个 类似的服务我想也有一些企业安全软件会阻止那些托管恶意软件的域名的 DNS 查询DNS 不是静态数据库。它是非常动态的，答案往往实时取决于查询的 IP 地址、内容服务器的当前负载等。除非你将这些记录的服务委托给做出这些决定的实体，否则很难实时实现。DNS 委派控制使访问控制非常简单。从区域中切下的部分都由控制委派服务器的人控制，所以对一个主机名的责任是隐含在 DNS 委派中的。原因：在 nginx 中获得动态代理这里有一个很酷的故事，来自 这条推文：我在一个应用程序中写了一个 DNS 服务器，然后把它设置为 nginx 的解析器，这样我就可以获得动态的后端代理，而不需要 nginx 运行 lua。Nginx 向应用程序发送 DNS 查询，应用程序查询 Redis 并作出相应的反应。这对我正在做的事情来说，效果非常好。原因：避免恶意解析器一些 ISP 运行的 DNS 解析器会做一些不好的事情，比如把不存在的域名指向他们控制的 IP，向你显示广告或他们控制的奇怪的搜索页面。使用你控制的解析器或你信任的另一个解析器可以帮助你避免这种情况。原因：解析内部域名你可能有一个内部网络，其域名（比如 blah.corp.yourcompany.com）并不在公共互联网上。为内部网络中的机器运行你自己的解析器，就有可能访问这些域名。无论是访问只在本地的服务，还是为公共互联网上的服务获得本地地址，你都可以在家庭网络中做同样的事情。原因：避免你的 DNS 查询被中间人劫持有一个人 说：我在我的局域网路由器上运行了一个解析器，它的上游使用了基于 HTTPS 的 DNS（DoH），所以物联网和其他不支持 DoH 或 DoT 的设备不会在外面喷射明文 DNS 查询。就是这样对我来说，探索 DNS 的 “原因” 感觉很重要，因为它是一个如此复杂凌乱的系统，我认为大多数人如果不理解为什么这些复杂的东西是有用的，就很难有动力去学习这么复杂的主题。感谢 Marie 和 Kamal 对这篇文章的讨论，也感谢 Twitter 上提供这些原因的所有人。via: https://jvns.ca/blog/2022/01/05/why-might-you-run-your-own-dns-server-/作者：Julia Evans 选题：lujun9972 译者：wxy 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
你好！最近我和几个朋友聊天，他们提到希望知道如何使用 dig 来进行 DNS 查询，所以这是一篇关于它的速读博文。当我第一次使用 dig 时，我发现它有点吓人 —— 有这么多的选项！我打算把大部分的选项省略。在这篇文章中，我打算不谈 dig 的大部分选项，只谈我实际使用的选项。我最近还了解到，你可以设置一个 .digrc 配置文件，让它的输出更容易阅读，这让它的使用变得更加轻松。几年前我还画了一个关于 dig 的 zine 页，但我想写这篇文章来包括更多的信息。两种类型的 dig 参数：查询和格式化有两种主要的参数可以传递给 dig：告诉 dig 要进行什么 DNS 查询的参数。告诉 dig 如何 格式化响应的参数。首先，让我们看一下查询选项。主要的查询选项你通常想控制 DNS 查询的 3 件事是：名称（如 jvns.ca）。默认情况下，查询的是空名称（.）。DNS 查询类型（如 A 或 CNAME）。默认是 A。发送查询的 服务器（如 8.8.8.8）。默认是 /etc/resolv.conf 中的内容。其格式是：dig @server name type 这里有几个例子：dig @8.8.8.8 jvns.ca 向谷歌的公共 DNS 服务器（8.8.8.8）查询 jvns.ca。dig ns jvns.ca 对 jvns.ca 进行类型为 NS 的查询。-x：进行反向 DNS 查询我偶尔使用的另一个查询选项是 -x，用于进行反向 DNS 查询。下面是输出结果的样子。$ dig -x 172.217.13.174 174.13.217.172.in-addr.arpa. 72888 IN PTR yul03s04-in-f14.1e100.net。 -x 不是魔术。dig -x 172.217.13.174 只是对 174.13.217.172.in-addr.arpa. 做了一个 PTR 查询。下面是如何在不使用 `-x’ 的情况下进行完全相同的反向 DNS 查询。$ dig ptr 174.13.217.172.in-addr.arpa. 174.13.217.172.in-addr.arpa. 72888 IN PTR yul03s04-in-f14.1e100.net。 我总是使用 -x，因为它可以减少输入。格式化响应的选项现在，让我们讨论一下你可以用来格式化响应的参数。我发现 dig 默认格式化 DNS 响应的方式对初学者来说是很难接受的。下面是输出结果的样子：; <<>> DiG 9.16.20 <<>> -r jvns.ca ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28629 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ; COOKIE: d87fc3022c0604d60100000061ab74857110b908b274494d (good) ;; QUESTION SECTION: ;jvns.ca. IN A ;; ANSWER SECTION: jvns.ca. 276 IN A 172.64.80.1 ;; Query time: 9 msec ;; SERVER: 192.168.1.1#53(192.168.1.1) ;; WHEN: Sat Dec 04 09:00:37 EST 2021 ;; MSG SIZE rcvd: 80 如果你不习惯看这个，你可能需要花点时间来筛选，找到你要找的 IP 地址。而且大多数时候，你只对这个响应中的一行感兴趣（jvns.ca. 180 IN A 172.64.80.1）。下面是我最喜欢的两种方法，可以使 dig 的输出更容易管理：方式 1 : +noall +answer这告诉 dig 只打印 DNS 响应中的“答案”部分的内容。下面是一个查询 google.com 的 NS 记录的例子：$ dig +noall +answer ns google.com google.com. 158564 IN NS ns4.google.com. google.com. 158564 IN NS ns1.google.com. google.com. 158564 IN NS ns2.google.com. google.com. 158564 IN NS ns3.google.com. 这里的格式是：NAME TTL TYPE CONTENT google.com 158564 IN NS ns3.google.com. 顺便说一下：如果你曾经想知道 IN 是什么意思，它是指“查询类”，代表“ 互联网 internet ”。它基本上只是上世纪 80、90 年代的遗物，当时还有其他网络与互联网竞争，如“ 混沌网络 chaosnet ”。方式 2：+short这就像 dig +noall +answer，但更短：它只显示每条记录的内容。比如说：$ dig +short ns google.com ns2.google.com. ns1.google.com. ns4.google.com. ns3.google.com. 你可以在 digrc 中设置格式化选项如果你不喜欢 dig 的默认格式（我就不喜欢！），你可以在你的主目录下创建一个 .digrc 文件，告诉它默认使用不同的格式。我非常喜欢 +noall +answer 格式，所以我把 +noall +answer 放在我的 ~/.digrc 中。下面是我使用该配置文件运行 dig jvns.ca 时的情况。$ dig jvns.ca jvns.ca. 255在172.64.80.1中 这样读起来就容易多了！如果我想回到所有输出的长格式（我有时会这样做，通常是因为我想看响应的权威部分的记录），我可以通过运行再次得到一个长答案。$ dig +all jvns.ca dig +trace我使用的最后一个 dig 选项是 +trace。dig +trace 模仿 DNS 解析器在查找域名时的做法 —— 它从根域名服务器开始，然后查询下一级域名服务器（如 .com），以此类推，直到到达该域名的权威域名服务器。因此，它将进行大约 30 次 DNS 查询。（我用 tcpdump 检查了一下，对于每个根域名服务器的 A / AAAA 记录它似乎要进行 2 次查询，所以这已经是 26 次查询了。我不太清楚它为什么这样做，因为它应该已经有了这些 IP 的硬编码，但它确实如此。）我发现这对了解 DNS 的工作原理很有用，但我不认为我用它解决过问题。为什么要用 dig尽管有一些更简单的工具来进行 DNS 查询（如 dog 和 host），我发现自己还是坚持使用 dig。我喜欢 dig 的地方实际上也是我 不喜欢 dig 的地方 —— 它显示了大量的细节！我知道，如果我运行 dig +all，它将显示 DNS 响应的所有部分。例如，让我们查询 jvns.ca 的一个根名称服务器。响应有 3 个部分，我可能会关心：回答部分、权威部分和附加部分。$ dig @h.root-servers.net. jvns.ca +all ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 18229 ;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 9 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 1232 ;; QUESTION SECTION: ;jvns.ca. IN A ;; AUTHORITY SECTION: ca. 172800 IN NS c.ca-servers.ca. ca. 172800 IN NS j.ca-servers.ca. ca. 172800 IN NS x.ca-servers.ca. ca. 172800 IN NS any.ca-servers.ca. ;; ADDITIONAL SECTION: c.ca-servers.ca. 172800 IN A 185.159.196.2 j.ca-servers.ca. 172800 IN A 198.182.167.1 x.ca-servers.ca. 172800 IN A 199.253.250.68 any.ca-servers.ca. 172800 IN A 199.4.144.2 c.ca-servers.ca. 172800 IN AAAA 2620:10a:8053::2 j.ca-servers.ca. 172800 IN AAAA 2001:500:83::1 x.ca-servers.ca. 172800 IN AAAA 2620:10a:80ba::68 any.ca-servers.ca. 172800 IN AAAA 2001:500:a7::2 ;; Query time: 103 msec ;; SERVER: 198.97.190.53#53(198.97.190.53) ;; WHEN: Sat Dec 04 11:23:32 EST 2021 ;; MSG SIZE rcvd: 289 dog 也显示了 “附加” 部分的记录，但它没有明确指出哪个是哪个（我猜 + 意味着它在附加部分？） ，但它似乎没有显示“权威”部分的记录。$ dog @h.root-servers.net. jvns.ca NS ca. 2d0h00m00s A "c.ca-servers.ca." NS ca. 2d0h00m00s A "j.ca-servers.ca." NS ca. 2d0h00m00s A "x.ca-servers.ca." NS ca. 2d0h00m00s A "any.ca-servers.ca." A c.ca-servers.ca. 2d0h00m00s + 185.159.196.2 A j.ca-servers.ca. 2d0h00m00s + 198.182.167.1 A x.ca-servers.ca. 2d0h00m00s + 199.253.250.68 A any.ca-servers.ca. 2d0h00m00s + 199.4.144.2 AAAA c.ca-servers.ca. 2d0h00m00s + 2620:10a:8053::2 AAAA j.ca-servers.ca. 2d0h00m00s + 2001:500:83::1 AAAA x.ca-servers.ca. 2d0h00m00s + 2620:10a:80ba::68 AAAA any.ca-servers.ca. 2d0h00m00s + 2001:500:a7::2 而 host 似乎只显示“答案”部分的记录（在这种情况下没有得到记录）：$ host jvns.ca h.root-servers.net Using domain server: Name: h.root-servers.net Address: 198.97.190.53#53 Aliases: 总之，我认为这些更简单的 DNS 工具很好（我甚至自己做了一个 简单的网络 DNS 工具），如果你觉得它们更容易，你绝对应该使用它们，但这就是为什么我坚持使用 dig 的原因。drill 的输出格式似乎与 dig 的非常相似，也许 drill 更好！但我还没有真正试过它。就这些了我最近才知道 .digrc，我非常喜欢使用它，所以我希望它能帮助你们中的一些人花更少的时间来整理 dig 的输出！有人在 Twitter 上指出，如果有办法让 dig 显示响应的简短版本，其中也包括响应的状态（如 NOERROR、NXDOMAIN、SERVFAIL 等），那就更好了！我同意这个观点！不过我在手册中没有找到这样的选项。via: https://jvns.ca/blog/2021/12/04/how-to-use-dig/作者：Julia Evans 选题：lujun9972 译者：wxy 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出