原网站:https://powerdns.org/hello-dns/
本页原地址:https://powerdns.org/hello-dns/basic.md.html

1 DNS基础


DNS主要用于提供IP地址和邮件服务器的详细信息,但它也可以包含任意数据。DNS就是关于名字的。每个名称都可以有几种 类型 (type)的数据。最著名的外部有用类型是用于IPv4地址的A记录,用于IPv6地址的AAAA记录和用于邮件服务器详细信息的MX记录。DNS也有自己使用的类型,如NS、CNAME和SOA
常用域名解析记录DNS名词解释

当我们问DNS问题时,我们称之为查询(query)。我们将应答称为响应(response)。这些查询和响应包含在DNS消息(message)中。当使用UDP协议时,消息也是数据包。注意,2018年起DNS必须支持TCP。

一个DNS消息包含:

  • 头部(header)
  • 查询名(query name) 和 查询类型(query type)
  • 回答部分(answer section)
  • 权威/授权部分(authority section)
  • 附加部分(additional section)

在基本的DNS中,查询消息应该有空的回答、权威和附加部分。

消息头部有以下字段,对查询和应答是有用的:

  • ID:在查询和响应匹配过程中的16位标识符
  • QR:查询请求/响应的标志信息。查询请求时,值为 0;响应时,值为 1。
  • OPCODE(操作码):0 表示标准查询;1 表示反向查询;2 表示服务器状态请求。
  • RD:设置这个值来表明是否需要递归

和应答(response)相关的字段:
DNS报文

  • AA:这个应答有权威回答(Authoritative Answers)

    授权应答,该字段在响应报文中有效。值为 1 时,表示名称服务器是权威服务器;值为 0 时,表示不是权威服务器。

  • RA(Recursion Available):递归服务可用

    可用递归。该字段只出现在响应报文中。当值为 1 时,表示服务器支持递归查询。

  • TC(Truncated):UDP中不含有全部的应答(response)所需字段

    表示是否被截断。值为 1 时,表示响应已超过 512 字节并已被截断,只返回前 512 个字节。

  • RCODE(reply code):结果代码。0表示连接成功,2表示连接失败(SERVFAIL),3表示不存在(NXDOMAIN)

    返回码字段,表示响应的差错状态。当值为 0 时,表示没有错误;当值为 1 时,表示报文格式错误(Format error),服务器不能理解请求的报文;当值为 2 时,表示域名服务器失败(Server failure),因为服务器的原因导致没办法处理这个请求;当值为 3 时,表示名字错误(Name Error),只有对授权域名解析服务器有意义,指出解析的域名不存在;当值为 4 时,表示查询类型不支持(Not Implemented),即域名服务器不支持查询类型;当值为 5 时,表示拒绝(Refused),一般是服务器由于设置的策略拒绝给出应答,如服务器不希望对某些请求者给出应答。

DNS查询大都通过UDP发送,但UDP数据包很容易被欺骗。要识别对查询(query)的真实响应,重要的是ID字段必须是随机的,或者至少是不可预测的。然而,这样的保护还不够,所以UDP DNS查询的源端口也必须是不可预知的。

DNS消息(dns message)也可以通过 TCP/IP 发送。由于 TCP 不是面向数据报的协议,因此 TCP/IP 中的每条 DNS 消息前面都有一个 16 位网络端长字段。

DNS服务器必须同时侦听UDP和TCP端口53。

有关www.ietf.org的IPv6地址的查询的头如下:

image.png
请注意,我们没有花时间在字段Z上,因为这个字段始终定义为0。 该数据包不请求递归。 QDCOUNT = 1表示有1个查询请求。 从理论上讲,DNS在一条消息中支持多个查询请求,但这尚未实现。 ANCOUNT,NSCOUNT和ARCOUNT均为零,表示此查询包中没有响应。

这是实际的查询
image.png
它由以DNS有线格式编码的“ www.ietf.org”(见下文)组成,后跟16位类型字段。 对于表示IPv6地址的AAAA记录,它是28。然后是问题的“类”(class)。 DNS记录原本打算存在于不同的“类”中,但是其语义并未完全指定,也未真正实现。 现在,始终将class设置为1。

查询名称,类型和类也分别称为“ qname”,“ qtype”和“ qclass”。

需要特别注意的是,域名“ www.ietf.org”在DNS中序列化的方式有些不寻常。 “ www.ietf.org”由3个长度分别为3、4和3的“标签”组成。 在DNS消息中,其编码为值3,然后是www,然后是值4,然后是ietf,然后是3,后跟org。 然后有一个结尾的0,表示这是结束。

这种格式是不寻常的,但是具有一些极具吸引力的特性。 例如,它是二进制安全的,不需要转义。 在编写DNS软件时,可能很想将DNS名称作为“ ASCII”传递。 然后,这导致在许多地方转义和转义代码。 强烈建议使用本机DNS编码来存储DNS名称。 处理带有空格或点的DNS名称时,这将省去很多麻烦。

最后,DNS查询不区分大小写。 但是,这是相当机械地定义的,并且仅限于ASCII。 当不区分大小写进行比较时,操作员无需知道Ü在某些编码中等于ü。 出于DNS的目的,在比较a-z和A-Z中的八位字节时,将忽略第五位(0×20)。

请注意,名称的各个标签的长度限制在63个八位组(octet)。

接下来,是一个DNS响应。 请注意,这又是一条DNS消息,它看起来很像原始DNS查询。 这是响应的开始:
image.png
请注意,QR现在设置为1表示响应。 设置“ AA”位是因为此响应来自该名称的权威服务器。

此外,ANCOUNT现在设置为’1’,表示在消息中找到一个回答,就在原始问题之后,该问题已经在查询消息中重复了。

要识别正确的响应,需检查ID字段与查询中的ID字段相同,并确保响应到达正确的源端口,并且查询名称和类型与原始查询匹配。 此外,请确保在仍等待响应时不要发出多个同等查询,因为这样做会带来安全漏洞。

在头部和原始问题之后,我们找到了回答:
image.png
前两个字节(0xc0 0x0c)看起来很神秘。 创建DNS时,认为512个八位位组是UDP数据报的最大大小,因此不使用(慢速)TCP协议传输的DNS消息的最大大小。

为了将尽可能多的信息压缩到512字节中,可以压缩DNS名称(通常必须)。 这种压缩的细节很神秘,很容易出错,从而导致无限循环或缓冲区溢出。 所以要非常小心。 如果您还记得一件事,请确保始终将指针移到数据包中的较低位置。 也要注意有符号/无符号算术。

在这种情况下,答案的DNS名称被编码为0xc0 0x0c。 c0部分设置了两个最高有效位,表示接下来的6 + 8位是指向消息中较早位置的指针。 在这种情况下,它指向数据包中紧靠DNS头的位置12(= 0x0c十六进制)。 在那里我们可以找到“ www.ietf.org”。

这意味着DNS名称www.ietf.org的回答也被称为www.ietf.org。(这句看不懂)

然后在数据包中紧随其后的是’28’,它表示AAAA 记录(IPv6),和通常的’class’为1。然后整个32位用于记录的生存时间(TTL),然后是一个16位长度的字段。因为这是一个IPv6地址,所以实际的应答有效负载长度是16字节(或128位)。

2400:cb00:2048:1::6814:55 就是www.ietf.org的IPv6地址的二进制表示。

如果有更多的回答,它们会跟随第一个,并且ANCOUNT会高于1。如果在“权威”和“附加”部分有数据,那么在这里也会有相应的调整“NSCOUNT”和“ARCOUNT”字段。稍后将详细介绍这些部分。

1.1 RRSETs


在上面的例子中,关于“www.ietf.org”的AAAA记录的问题只有一个相应的资源记录。以一种符合人类阅读习惯的“区域文件”,这将被存储为:

  1. www.ietf.org IN AAAA 3600 2400:cb00:2048:1::6814:55

但是,同一名称可能有多个AAAA记录。即使只有一条记录,DNS规范也会讨论“资源记录集”或RRSETs。它们在统一中运作。因此,即使DNS包中的编码允许在单个RRSET中使用不同的TTL值,也不应该发生这种情况。

1.2 Zone files


区域文件是存储DNS数据的一种方式,但它们不是名称服务器操作的组成部分。区域文件格式是标准化的(RFC 1035的第5节),但是它的解析并不简单。完全有可能写有用的名称服务器,但不读取或写入DNS区域文件。在开始解析区域文件时,不要轻易这样做。例如,单行中的各个字段可以以多种顺序出现。大多数字段是可选的,有些字段将从前面的行复制过来。但并不是所有。

需要特别注意的是,许多人都试图为zonefile编写语法(比如用Yacc编写),但这几乎是不可能的。

1.3 DNS Names


DNS 名称的概念不是微不足道的,而且经常被误解。尽管从左到右www.ietf.org写”www.ietf.org”,但 DNS 中将其描述为根节点下方的”org”更合适,在”org”节点下方,一个名为”ietf”的节点。最后,将”ietf”节点附加到名为”www”的节点。

用流程图的形式来描述
image.png
如上所示的节点“树”是真实的,而不仅仅是另一种可视化DNS名称的方式。例如,这意味着如果有一个名为’ns1.ord.ietf.org’的名称,并且有一个关于’ns2.fra.ietf.org’的查询,这个名称存在-即使可能没有记录被分配给它。

‘org’区域可能会像如下所示
image.png
注意:这意味着任何将 DNS 视为简单”密钥/值”存储的实现,其中只有存在的记录可以匹配,则只会遇到问题。DNS 标准允许实现假定如果”ord.ietf.org”不存在,则 ns1 也不存在。这将保存查询,但会杀死您的域名,如果你弄错了。

1.4 Zones


如前所述,DNS 比简单的键/值存储更为复杂。这不仅因为名称的树样式性质,还因为相同的数据可以位于多个位置,但始终生活在”区域”中。

随着时间的推移,各种DNS实现已经发现,对于简单的名称服务器或负载均衡器,你基本上可以忽略“区域”的概念,但不正确地实现区域将最终绊倒你。

让人困惑的是,“www.ietf.org”可以在四个不同的地方定义。它可能在“根”区本身,完全写出来

  1. www.ietf.org IN AAAA 3600 2400:cb00:2048:1::6814:55

也可以在组织区,看起来像这样

  1. $origin ORG
  2. www.ietf IN AAAA 3600 2400:cb00:2048:1::6814:55

或者(实际上就是这样),这个名称可以存在于’ietf.org’区域中

  1. $origin ietf.org
  2. www IN AAAA 3600 2400:cb00:2048:1::6814:55

最后,甚至有可能存在一个名为“www.ietf.org”的区域,记录就保存在这里

  1. $origin www.ietf.org
  2. @ IN AAAA 3600 2400:cb00:2048:1::6814:55

1.4.1 Start of Authority

区域始终以 SOA 或授权开始记录(Start of Authority)开头。SOA 记录是 DNS 元数据。它存储对区域可能感兴趣的各种内容,例如维护者的电子邮件地址、最权威服务器的名称。它还具有描述如何或是否需要复制区域的值。最后,SOA 记录有一个影响不存在名称的 TTL 值的数字。

确保只有一种SOA存在于Internet上,这是用于根区域的SOA(称为“.”)。
截至2018年,它看起来像这样:

  1. . 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2018032802 1800 900 604800 86400

有关所有这些字段的含义的详细信息,请参阅权威服务器文档

但是,最终数字在这里很重要。 86400表示如果响应说不存在名称或RRSET,则第二天将继续不存在该名称或RRSET,并且该信息可能会被缓存。

1.4.2 Zone cuts

如前所述,“ www.ietf.org”可以存在于四个地方。 如果它住在当前所在的位置,则在“ ietf.org”区域中进行两次区域切割:从’.’到’org’,从’org’到’ietf.org’。
当权威服务器接收到一个关于“www.ietf.org”的查询时,它会查询它知道的那些区域,并从它可用的最特定的区域给出答案。

对根服务器而言,它只知道根区域,这意味着查找’.’区域。如前文所述,’www.ietf.org’是树状结构,’org’->’ietf’->’www’。幸运的是,第一个节点’org’出现在根区域中。

附加到该节点的是一个NS RRSET,其中包含托管ORG区域的命名服务器的名称。。

如果我们向这些服务器询问“ www.ietf.org”,它们也会找到最佳答案,在这种情况下为“ org”。然后在’org’区域中找到’ietf’节点,该节点同样包含一个NS RRSET。

当我们向该RRSET中命名的服务器询问有关“ www.ietf.org”时,它们会找到一个名为“ www”的节点,上面带有多个RRSET,其中一个用于AAAA,并包含我们正在寻找的IPv6地址。

任何不以这种方式实现“区域”的权威服务器最终都会遇到麻烦。 仅查询已知名称列表并回答附加在这些名称上的记录是不够的。

1.4.3 NS Records

这些是区域的必需部分,位于“顶点”。 “ apex”是区域的名称,这时还有一条SOA记录。 因此,典型的区域将像这样开始:

  1. $ORIGIN ietf.org.
  2. @ IN SOA ns1 admin 2018032802 1800 900 604800 86400
  3. IN NS ns1
  4. IN NS ns2

注意,在这个区域文件示例中,文件名不是以’.’结尾的。都被解释为ietf.org的一部分。“@”是指定顶点名称的一种方式。第二行和第三行省略了一个名称,因此它们默认也为’@’。

该区域列出了ns1.ietf.org和ns2.ietf.org作为其名称服务器。 作为区域的一部分,此数据具有权威性。 发送到此名称服务器的“ ietf.org”的NS RRSET的任何查询都将收到带有AA位置1的响应。

但是请注意,上面我们了解到,父区域“ org”还需要列出example.org的名称服务器,如下:

  1. $ORIGIN org.
  2. ...
  3. ietf IN NS ns1.ietf
  4. ietf IN NS ns2.ietf

如果我们向“org”名称服务器索要“ ietf.org”的NS RRSET,则会收到AA = 0的响应,表明“org”服务器知道它们不是ietf.org的“权威”。

1.4.4 Glue records

精明的读者会在这里发现先有鸡还是先有蛋的问题。 如果ns1.ietf.org是ietf.org的名称服务器…我们在哪里获取ns1.ietf.org的IP地址?

为了解决这个问题,父区域会提供一只免费的“鸡”,在’org’区域,可以找到:

  1. $ORIGIN org.
  2. ...
  3. ietf IN NS ns1.ietf
  4. ietf IN NS ns2.ietf
  5. ns1.ietf IN A 192.0.2.1
  6. ns2.ietf IN A 198.51.100.1

这些条目被镜像到托管在ns1.ietf.org和ns2.ietf.org上的“ietf.org”区域中。与NS记录一样,发送到org服务器的任何对ns1.ietf.org的查询都会收到AA=0的回答,而ns1.ietf.org本身的回答是AA=1。

注意,由于各种原因,来自父区域的AA=0的答案可能与AA=1的答案不同,并且解析器必须意识到这种差异。

2 Further aspects


到目前为止的描述是正确的,但即使对于基本的DNS,功能也远远不够完整。以下部分描述了基本DNS的其他方面

2.1 CNAME


CNAME为DNS提供了另外一个“规范名称”,例如:

  1. www IN CNAME www.ietf.org.cdn.cloudflare.net.

这通常用于重定向到内容分发网络。CNAME用于名称,而不是用于类型。这意味着对www.ietf.org的任何查询都被发送到Cloudflare。这同时意味着每个人都想要的是不可能的:

  1. $ORIGIN ietf.org
  2. @ IN CNAME this.does.not.work.int.

这会与SOA和NS记录发生冲突,这些记录也会被重定向,但无法找到。通常,使用这个“apex CNAME”似乎有用,但实际上并没有。

事后看来,应该对CNAME进行“类型化”,使其仅适用于特定的查询类型。

当服务器遇到CNAME时,其名称就是它所寻找的名称,它将“跟随”它所指向的链。 并且请注意,这可能会循环。

2.2 Wildcards


允许下列通配符:

  1. $ORIGIN ietf.org.
  2. * IN A 192.0.2.1
  3. IN AAAA 2001:db8:85a3::8a2e:0370:7334
  4. smtp IN A 192.0.2.222

对“smtp.ietf.org”的A记录的查询将返回192.0.2.222。然而,查询“www.ietf.org”将返回192.0.2.1。

有趣的是,作为DNS树状结构的另一个示例,对smtp.ietf.org的AAAA记录的查询将返回……没有任何结果。 这是因为节点“ smtp.ietf.org”确实存在,并且处理在那里结束。 通配符匹配不会继续到“ *”条目。

通配符可以合成新的应答。这意味着,除非显式查询,否则不会提供’*.ietf.org’记录。相反,一个’www.ietf.org’记录是动态创建的。

2.3 Truncation


如果不实现可选的EDNS协议扩展,所有UDP响应必须适合512字节的有效负载。如果服务器在写应答时发现自己超过了这个限制,它必须截断数据包并将TC位设置为1。

然后,查询的发起者将通过TCP重新发送查询。

有时DNS响应包含可以省略的可选数据,这样做可以保持在512字节限制下。

但是,建议保持简单,当达到字节限制时,发送一个TC=1的空响应包。

2.4 Names and nodes that do not exist


两种情况下DNS请求会匹配失败:整个节点不存在,或者,请求的类型在节点上不存在。

第一种情况的示例:’doesnotexist.ietf.org’不存在,这导致响应带有RCODE NXDOMAIN,并且没有应答记录。
第二种情况的示例:’www.ietf.org’确实存在,但没有MX记录。RCODE正常,但是没有应答记录。

然而,空的应答很难缓存。为了缓解这种情况,在这些情况下,权威服务器将在响应的授权部分发送SOA记录的副本。该记录的TTL告诉我们“no such name”或“no such data”的信息可以缓存多长时间。

2.5 Query types that are not RRSET types