Mike Zhang

DNS DevOps CISSP CISA Security+ 摄影 程序员 北京

RFC1035 域名实施及规范

12 Nov 2018 » dns, rfc

1. RFC1035介绍

本篇RFC主要介绍域名系统和协议的实施细节, 并且假设读者已经掌握了RFC1034中关于DNS的相关概念。 域名系统本身是一个混合了多种功能和数据类型的系统,部分功能和实现仍旧处于实验阶段。 由于DNS的可扩展性,一些新的功能实现或者数据类型可能超出了官方协议的定义范围。 官方协议仅包含标准查询,响应以及Internet 资源记录类型格式, 部分定义在之前RFC给出的,可能已经过期,不在被使用。

本篇RFC中的部分实例仅用作教学使用,读者应谨慎使用

2. 简介

2.1 背景回顾

域名系统目的是提供一种命名资源的机制,且系统本身应该兼容不同类型的主机,网络或者协议族。用户使用域名系统只需要通过本地的代理(解析器Resolver)发送特定的查询即可,整个的域名树形结构对用户来说是一个单一的信息空间, 解析器负责隐藏整个的分布式的数据结构,通过多次查询获得用户的数据。

对于解析器,整个的树形结构以及数据是分散在多个不同的域名服务器上的, 不同的域名空间存储在不同的服务器上(多台域名服务器可提供相同的解析服务)。 解析器本身需要至少一个域名服务器的配置(根服务器或其他内网的独立域服务器),才能开始整个的查询流程。解析器帮助处理多层的域名查询,以及错误处理,比如当单个域名服务器不可用的时候,重新发送新的查询到其他冗余的服务器上。

域名服务器管理两种数据, 第一种数据为区数据,这种数据是整体树形结构中的一部分子树的相关数据内容。这部分数据也属于权威数据,域名服务器周期性检查存放在本地的区数据文件或者其他的主服务器,一旦发生变化则复制一份新的数据并加载到内存中,等待查询。 另一种数据为缓存数据,数据可能不完整,只包含之前查询被缓存下来的,但是通过这种方式,可以提升整体的查询效率,数据本身根据TTL设置一定的到期时间,随着时间到期即在缓存中被删除。通过不同功能的切分,使得不同部分出现的问题得到很好的隔离,排查更加容易

2.2 常规配置

下图为一个典型的DNS系统图,用户程序通过解析器向DNS权威服务器进行查询,并等待响应。解析器内部的缓存提供用户重复域名查询的直接响应。 同时解析器也可以不在同一台机器,而是作为一个开放式的递归服务器,提供多个用户同时查询使用。

                 Local Host                        |  Foreign
                                                   |
    +---------+               +----------+         |  +--------+
    |         | user queries  |          |queries  |  |        |
    |  User   |-------------->|          |---------|->|Foreign |
    | Program |               | Resolver |         |  |  Name  |
    |         |<--------------|          |<--------|--| Server |
    |         | user responses|          |responses|  |        |
    +---------+               +----------+         |  +--------+
                                |     A            |
                cache additions |     | references |
                                V     |            |
                              +----------+         |
                              |  cache   |         |
                              +----------+         |

域名服务器通过读取权威数据提供本区域名的查询服务,并接收解析器的查询,同时域名服务器要求冗余配置,因此至少有一台主服务器,一台二级服务器,二级服务器通过查询SOA进行比较,如果发现数据发生变化则执行区传送完成数据的更新

下图代表了一个具有二级服务器的配置图:

             Local Host                        |  Foreign
                                               |
  +---------+                                  |
 /         /|                                  |
+---------+ |             +----------+         |  +--------+
|         | |             |          |responses|  |        |
|         | |             |   Name   |---------|->|Foreign |
|  Master |-------------->|  Server  |         |  |Resolver|
|  files  | |             |          |<--------|--|        |
|         |/              |          | queries |  +--------+
+---------+               +----------+         |
                            A     |maintenance |  +--------+
                            |     +------------|->|        |
                            |      queries     |  |Foreign |
                            |                  |  |  Name  |
                            +------------------|--| Server |
                         maintenance responses |  +--------+

有时候查询服务可将缓存集中起来管理,建立中央缓存数据中心来减少分散的缓存服务。配置如下图所示, 其中StubResolver是一个可以看做系统上的简单的DNS查询接口,发送查询到递归服务器并等待服务器器响应。

               Local Hosts                     |  Foreign
                                               |
+---------+                                    |
|         | responses                          |
| Stub    |<--------------------+              |
| Resolver|                     |              |
|         |----------------+    |              |
+---------+ recursive      |    |              |
            queries        |    |              |
                           V    |              |
+---------+ recursive     +----------+         |  +--------+
|         | queries       |          |queries  |  |        |
| Stub    |-------------->| Recursive|---------|->|Foreign |
| Resolver|               | Server   |         |  |  Name  |
|         |<--------------|          |<--------|--| Server |
+---------+ responses     |          |responses|  |        |
                          +----------+         |  +--------+
                          |  Central |         |
                          |   cache  |         |
                          +----------+         |

2.3 规范

域名系统有很多已经形成的规范来处理底层和基础的问题, 尽管具体实施人员可以自由打破这些约束,但是应该理解这些规范,这对于与其他主机沟通上至关重要。

2.3.1 域名语法规范

域名组成中依赖下面的规则进行定义,其中域名包含多个label组成,不同label使用(.)进行隔离,每个label必须满足ARPANET主机名规则,字母开始,结束必须是字母或者数字,组成内容必须是字符,数字和-符号,长度必须小于等于63。 域名中大小写无关,因此域名仅仅字符的大小写拼写不同认为是相同的域名.

以下为域名定义规范说明, 该定义充分考虑了不同应用的约束,并防止出现任何的字符问题。

<domain> ::= <subdomain> | " "

<subdomain> ::= <label> | <subdomain> "." <label>

<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]

<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>

<let-dig-hyp> ::= <let-dig> | "-"

<let-dig> ::= <letter> | <digit>

<letter> ::= any one of the 52 alphabetic characters A through Z in
upper case and a through z in lower case

<digit> ::= any one of the ten digits 0 through 9

2.3.2 数据传输顺序

DNS包数据传输的顺序按照八位组的方式进行处理,当一个数据包展示一组组八位组的时候,传输这些数据按照正常的读写顺序进行,例如下面图展示的多个八位组,顺序如描述的顺序123456进行:

     0                   1
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |       1       |       2       |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |       3       |       4       |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |       5       |       6       |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

在一个8位组里面,读写的顺序是按照高阶序进行,也就是下面的存储值为十进制的170

     0 1 2 3 4 5 6 7
    +-+-+-+-+-+-+-+-+
    |1 0 1 0 1 0 1 0|
    +-+-+-+-+-+-+-+-+

2.3.3 字符约定

DNS域名是不区分大小写的,任何域名具有相同的字符但是不同的大小写,将被认为是一样的域名。因此数据 x.y 和 X.Y将被存储在相同的位置,并且任何时候只有一个会被保留下来,比较查询的时候也按照不区分大小写进行比较,内部统一使用强制一致的标准完成(统一大写或者小写的方式处理)。

2.3.4 大小限制

  • 标签: 0-63个字符
  • 名称: 255字符
  • TTL : 32字节的有符号正整数
  • UDP消息: 512字节

3. 域名空间和RR定义

3.1 域名空间定义

域名在消息存储的时候使用一系列的标签组成,每一个标签使用一个8位代表标签的长度后面紧跟的是组成标签的多个8位组。由于每一个域名最后都是以为null的根标签作为结尾,因此后面跟的是一个0(一个字节长度)代表结束符号,由于每个标签长度不能超过63,因此每个代表长度的字节位的8位中前两位均为0,总长度被限制到255个字符长度以内。

尽管每个标签字符可以是任何8位组成的值,但是为了兼容性,还是尽量需要满足之前定义的规范来命名,字符比较的时候,字符要按照大小写不敏感的方式进行比较,其他的字符比如数字和-应该按照精确匹配完成。

3.2 RR定义

3.2.1 格式

所有的资源记录具有相同的格式如下图所示,其中的RDLENGTH代表了整个的RDATA(实际指定类型的数据)的长度, RDATA的格式按照类型和类别不同而不同

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                                               |
    /                                               /
    /                      NAME                     /
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      TYPE                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     CLASS                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      TTL                      |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                   RDLENGTH                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
    /                     RDATA                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

3.2.2 查询类型

下表列举的是服务器可以接收的查询类型列表,其中中间的数字代表实际存储在字段中的值,使用不同的值来区分不同类型。

A               1 主机地址

NS              2 权威服务器

MD              3 邮件目的地址 (Obsolete - use MX)

MF              4 邮件中转器地址 (Obsolete - use MX)

CNAME           5 域名别名

SOA             6 作为权威区数据的起始资源类型

MB              7 邮箱域名 (EXPERIMENTAL)

MG              8 邮件组成员(EXPERIMENTAL)

MR              9 邮件重命名域名 (EXPERIMENTAL)

NULL            10 Null资源记录 (EXPERIMENTAL)

WKS             11 已知的服务描述

PTR             12  域名指针

HINFO           13 主机信息

MINFO           14 邮件或邮件列表信息

MX              15 邮件交换地址

TXT             16 文本符号

3.2.3 QTYPE集合

除了以上的类型外,DNS协议支持的QTYPE 是上述Type类型的超集,也是有效的查询类型

AXFR            252 区传输请求

MAILB           253 查询邮箱相关的记录(MB, MG or MR)

MAILA           254 查询邮件代理记录 (已废弃 - see MX)

*               255 查询所有记录

3.2.4 CLASS类别集合

类别集合作为查询中的一个字段,定义查询的所属类别,下面的所有类别的定义值:

IN              1 Internet类别

CS              2 CSNET类别 (已废弃)

CH              3 CHAOS类别

HS              4 Hesiod类别

3.2.5 QCLASS类别定义

上述的CLASS都是有效的QCLASS, 而且QCLASS还支持的的是查询所有类别的方式

*               255 任意类别

3.3 查询标准资源记录

下面将给出不同类型的查询下RDATA的格式,其中NS,SOA,CNAME以及PTR记录在不同类别中的格式都是同意的。是一个由一系列的label组成的域名,最终结尾是一个空label代表了根节点。是一个单一的代表长度位的字节和具体长度字节的字符。 所有的域名在不同的类型中可能是压缩存储的,具体的压缩算法将在后面给出。

3.3.1 CNAME类型

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                     CNAME                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

CNAME定义了域名的别名,本身的RDATA不包含任何其他的数据内容,但是名称服务器在检查到用户的域名是CNAME的时候,可能会发送其他的查询类型,比如根据用户实际查询的是A类型,则将用户的查询域名换为新的域名后重新查询。

3.3.2 HINFO类型

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                      CPU                      /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                       OS                      /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

HINFO类型代表了域名服务器的一些系统信息,具体的可参考RFC1010(已过期),DNS服务器很少实现这一类型,主要用于类似于FTP的服务器来对于不同类型的主机进行通信使用。

3.3.3 MB类型(实验性)

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                   MADNAME                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

其中的域名代表了查询的邮箱的主机名称,服务器可根据域名继续查找当前邮箱主机的IP地址,也就是继续查找A类型的数据

3.3.4 MD类型(已废弃)

已不再使用,由MX记录替代,域名服务器推荐的策略是在区文件中将其替换位MX记录且设置其Preference(优先级)为0

3.3.5 MF类型(同上)

3.3.6 MG类型(实验性)

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                   MGMNAME                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

邮件服务器中一个邮箱所归属的邮件组的域名, 不会再产生任何多余的查询。

3.3.7 MINFO类型(实验性)

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                    RMAILBX                    /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                    EMAILBX                    /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

其中的RMAILBX代表了一个负责邮件列表或者邮箱管理地址。EMAILBX则定义一个邮箱来接收错误消息的, 尽管定义MINFO可以是一个单一的邮箱,但是一般都是一些邮件列表。

3.3.8 MR类型

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                   NEWNAME                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

返回一个邮箱对应的新的名称,MR记录不会再进行其他类型的数据查询。

3.3.9 MX类

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                  PREFERENCE                   |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                   EXCHANGE                    /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

Preference代表了一个优先级,数值越低优先级越高,使用16bit(两个字节表示),Exchange则代表了一个主机地址(作为邮件交换服务器)

MX记录会进一步的查询域名所对应的A地址,具体的使用MX记录可以参考RFC-974

~ dig icann.org. mx
icann.org.		599	IN	MX	10 pechora1.icann.org.
icann.org.		599	IN	MX	10 pechora2.icann.org.
icann.org.		599	IN	MX	10 pechora6.icann.org.
icann.org.		599	IN	MX	10 pechora8.icann.org.

3.3.10 NULL类型(实验性)

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                  <anything>                   /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

Null类型查询可能返回任何的东西(只要不要超过最大的65535字节长度)

3.3.11 NS类型

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                   NSDNAME                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

NSDATA数据代表了一个针对特殊类别和域名的权威服务器,NS记录一般需要继续查询额外A记录(如果是当前区数据的子区则一般是直接作为glue记录存储)放在DNS的Additional字段。 另外查询的类别可能并不是实际主机通信需要的协议类别, 比如主机同时包含IN和HS类别的域名服务信息查询,一般都是使用IN类别进行查询。

3.3.12 PTR类型

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                   PTRDNAME                    /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

PTR记录不会产生额外的查询, PTRDNAME指向一些域名空间中的相关域名,存储在IN-ADDR.ARPA区文件中。查询结果实例:

dig -x 8.8.8.8
8.8.8.8.in-addr.arpa.	71604	IN	PTR	google-public-dns-a.google.com.

3.3.13 SOA类型

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                     MNAME                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                     RNAME                     /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    SERIAL                     |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    REFRESH                    |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     RETRY                     |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    EXPIRE                     |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    MINIMUM                    |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

SOA记录代表了查询的区数据的相关管理信息, 其中的字段定义如下:

  • MNAME: 区文件的主要域名服务器地址
  • RNAME: 区文件管理的相关邮箱地址
  • SERIAL: 32bit序列号, 区传输时候进行比较使用(使用序列空间算法)
  • REFRESH: 32bit间隔,定义区刷新的间隔
  • RETRY: 32bit定义刷新失败后重试的间隔
  • EXPRIRE: 32bit定义最大的有效时间,当无法刷新的时候多久可用。
  • MINIMUM: 无符号32bit, 代表了资源记录的缓存有效期

SOA记录也不会再触发其他的查询 , 所有时间均是按照秒来计算,大部分的参数是用于区文件管理,但MINUMUM则用于所有查询资源记录时候使用的,一个典型的查询实例如下:

~ dig com soa +multiline
com.			895 IN SOA a.gtld-servers.net. nstld.verisign-grs.com. (
				1541918435 ; serial
				1800       ; refresh (30 minutes)
				900        ; retry (15 minutes)
				604800     ; expire (1 week)
				86400      ; minimum (1 day)
				)

3.3.14 TXT类型

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    /                   TXT-DATA                    /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

TXT类型用于保存任何的文本字符串使用

3.4 Internet特有的资源类型

3.4.1 A类型

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ADDRESS                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

A类型返回的地址是一个32bit长度的IP地址,主机可能同时由多个A地址,则此处也将包含多个记录。RDATA在区文件中保存的是由四个十进制数字组成且由逗号隔离开的比如“192.168.1.1”

3.4.2 WKS类型

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ADDRESS                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |       PROTOCOL        |                       |
    +--+--+--+--+--+--+--+--+                       |
    |                                               |
    /                   <BIT MAP>                   /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

WKS记录用来描述一些基于某些协议的服务信息,以及相关的地址。 地址是一个32bit的IP地址组成,协议使用8个bit表示,已经后面可变长度的bitmap(必须是8bit一组), Bitmap中使每一个bit代表一个端口号,比如第26个bit位设置位1,则代表了这个IP上具有SMTP服务,如果同时支持TCP和UDP,或者有多个英特网地址,则应该设置多个WKS记录。

在区文件中,保存的任何信息都是基于10进制。

3.5 IN-ADDR.ARPA域

Internet使用一个特殊的域来支持网关位置以及互联网地址到主机的映射,其他的类别可能使用不同的方式进行管理。 IN-ADDR.ARPA域的主要目的就是为了保证能实现主机地址到主机名的映射,并且充分利用查询区定位在一个特殊网络内的所有的网关。

IN-ADDR.ARPA域的域名空间使用一个依赖于IP地址的结构构造完成,因此可以保证不需要花费很多的时间即可找到适当的数据。

IN-ADDR.ARPA域中的域名,可以由四个标签外加IN-ADDR.ARPA组成,每一个标签代表了一个8位组(0-255范围内的数字),且以十进制的方式表示。比如主机IP地址10.2.0.52 对应的域为52.0.2.10.IN-ADDR.ARPA. 尽管反向比较难以阅读,但是允许使用不同的区代表不同的网络。比如10.IN-ADDR.ARPA.区包含ARPANET网络的数据,而26.IN-ADDR.ARPA.则包含MILNET网络的数据。

下面是一些具体的区数据配置, 我们可以看到的是:10.IN-ADDR.ARPA.具有多个PTR记录,一个域名网关可能连接多个网段比如GW.LCS.MIT.EDU.则同时包含10和18网段,且GW.LCS.MIT.EDU.的具体地址也在后面给出

    10.IN-ADDR.ARPA.           PTR MILNET-GW.ISI.EDU.
    10.IN-ADDR.ARPA.           PTR GW.LCS.MIT.EDU.
    18.IN-ADDR.ARPA.           PTR GW.LCS.MIT.EDU.
    26.IN-ADDR.ARPA.           PTR MILNET-GW.ISI.EDU.
    22.0.2.10.IN-ADDR.ARPA.    PTR MILNET-GW.ISI.EDU.
    103.0.0.26.IN-ADDR.ARPA.   PTR MILNET-GW.ISI.EDU.
    77.0.0.10.IN-ADDR.ARPA.    PTR GW.LCS.MIT.EDU.
    4.0.10.18.IN-ADDR.ARPA.    PTR GW.LCS.MIT.EDU.
    103.0.3.26.IN-ADDR.ARPA.   PTR A.ISI.EDU.
    6.0.0.10.IN-ADDR.ARPA.     PTR MULTICS.MIT.EDU.

当查询QTYPE=PTR, QCLASS=IN, QNAME=10.IN-ADDR.ARPA.的时候,客户端将接收到两个ARPA地址:

    10.IN-ADDR.ARPA.           PTR MILNET-GW.ISI.EDU.
    10.IN-ADDR.ARPA.           PTR GW.LCS.MIT.EDU.

当用户查询地址10.0.0.6所指向的域名的时候其实是发送了如下的查询记录:QTYPE=PTR, QCLASS=IN, QNAME=6.0.0.10.IN-ADDR.ARPA, 实际接收到的数据如下:

6.0.0.10.IN-ADDR.ARPA.     PTR MULTICS.MIT.EDU.

使用PTR查询的时候应该注意一下几个方面:

  1. 由于针对IN-ADDR.ARPA域名所指向的特殊主机或者网管可能在不同的区文件中,因此数据可能不一致。
  2. 具有多个名字(不同域中不同)的网关,仅有一个可以作为主要域名
  3. 系统使用域名数据库来初始化他们的路由表的时候要小心,确保足够的路由信息来确保访问适当的域名服务器
  4. 这些信息只能反应已经存在的网关信息,不能替代动态生成的信息比如使用EGP协议获得的信息

3.6 新的类,类别和域名空间

除了之前定义的类别,类型已经在使用外,允许定义新的类型,类别等。一些推荐的邮件列表比如:NAMEDROPPERS@SRI-NIC可以使用去讨论一些设计上面的问题。

设计人员应该设计适用于所有类别的数据类型,且防止任何的重复信息。当前的系统尝试区减少重复行的数据来防止不一致的数据的出现,比如为了找到邮件交换地址,需要用户查找对应邮件域名的主机名,再去查找主机名到对应的主机地址。这种方式可以避免出现不一致(邮件主机名也是一个独立的记录)

4. 消息

4.1 消息格式

所有域名协议数据都被封装到消息之中,消息的格式分为五个部分(传输中有可能部分数据为空),定义如下, 其中消息头部始终存在,头部包含一些查询的类型以及相关代码。Question 部分包含要查询的名称(QTYPE代表查询的类型,QCLASS代表查询的类别,QNAME查询的名称)最后的三个部分格式基本一致:

  • Answer: 包含查询类型的资源记录
  • Authority: 包含指向权威域名服务器的资源记录
  • Additional: 包含与查询相关的一些记录,但是又不是和查询问题直接相关的应答
    +---------------------+
    |        Header       |
    +---------------------+
    |       Question      | the question for the name server
    +---------------------+
    |        Answer       | RRs answering the question
    +---------------------+
    |      Authority      | RRs pointing toward an authority
    +---------------------+
    |      Additional     | RRs holding additional information
    +---------------------+

4.1.1 头部信息格式

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      ID                       |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    QDCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ANCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    NSCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ARCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

头部信息包含的字段比较多,而且很多定义共享一个字节存储,部分字段只占用一个bit存储空间。具体的定义如下:

  • ID: 16bit代表了查询的ID号,响应数据的时候需要复制对应的ID到响应包中来做到匹配。
  • QR: 定义数据包是查询(0)或者响应(1)数据包
  • OPCode: 4bit存储查询的种类,服务器响应的时候直接复制该字段具体的类型如下
    • 0: 标准查询
    • 1: 反向查询
    • 2: 服务器状态请求
    • 3-15: 保留
  • AA: 权威应答,服务器设置,用来代表该数据是否是权威的数据,但是有时候数据会包含多个所有者,比如当查询的域名具有CNAME的时候,AA权威对应查询名称是否是权威应答,或者在响应字段的第一个所有者是否是权威应答。
  • TC: 描述消息是否被截断(长度超过了最大的信道传输大小)
  • RD: 客户端设置, 如果RD被设置代表了期望域名服务器帮助进行递归查询
  • RA: 服务器端设置,代表服务器是否可以进行递归查询
  • Z : 保留(暂时为0)
  • RCode: 响应状态码,4bit存储空间(0-15)分别代表如下的定义:
    • 0 : 没有错误
    • 1 : 格式错误
    • 2 : 服务器错误
    • 3 : 域名错误(不存在)
    • 4 : 没有实施不支持的查询
    • 5:拒绝响应,比如区传输或者针对某些域名的查询
    • 6-15: 保留未使用
  • QDCOUNT: 无符号16字节,定义查询字段的数量
  • ANCOUNT: 无符号16字节,定义响应资源记录的数量
  • NSCOUNT: 无符号16字节,定义域名服务器资源记录的数量
  • ARCOUNT: 无符号16字节,定义additional字段的数量

4.1.2 查询字段格式

查询字段包含待查询的域名的信息,总计包含QDCOUNT数量个查询,每一个查询的格式如下:

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                                               |
    /                     QNAME                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     QTYPE                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     QCLASS                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

QNAME: 代表查询的一个域名,通过一系列的标签组成,每个标签最开始位置保存查询的当前标签的长度,最后一个结束以0结尾,代表最后的label长度是0(根域名),域名可能包含奇数个字节,不需要追加补齐

QTYPE: 两个字节代表的查询类型,具体如上面介绍类型的定义

QCLASS: 两个字节代表的查询类别,具体如上面介绍类别的定义

4.1.3 RR资源记录格式

所有的响应,权威应答,以及additinal字段包含相同的格式,一个可变长度的资源记录,资源的数量于Header中定义的数量一致。包含的格式如下:

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                                               |
    /                                               /
    /                      NAME                     /
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      TYPE                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     CLASS                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      TTL                      |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                   RDLENGTH                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
    /                     RDATA                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

每个字段的定义如下:

  • NAME: 资源记录相关的域名
  • TYPE: 两个字节代表,当前资源记录所属的类型
  • CLASS: 两个字节代表,当前资源记录所属的类别
  • TTL: 无符号32bit整数,代表了缓存时间,0代表不缓存
  • RDLENGTH: 无符号16bit整数,代表了实际传输的RDATA的长度
  • RDATA: 基于不同的查询类型,返回不同的数据内容,比如如果查询的CLASS是IN,查询的类型是A,则RDATA是一个4字长度存储的IP地址

4.1.4 消息压缩格式

为了缩减消息的尺寸,域名系统利用了一种压缩算法减少实际域名数据中重复的内容。利用这种方式, 一个完整的域,或者一组标签后面出现的重复字段将使用指针的方式代替。具体的方式如下:

    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    | 1  1|                OFFSET                   |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

指针本身存储占用两个字节,前两个比特位两个1, 后面跟具体的偏移量(每个标签长度必须是小于64,因此前两位都是0,前两位位10和01的保留位将来使用)偏移量依赖于消息开始的位置(数据包头部信息中ID开始的位置,也就是如果偏移量是0则代表ID字段位置)

压缩算法允许消息存储的域名:

  • 一个指针
  • 一系列的标签且以0字节结尾
  • 一系列的标签且以指针结尾

为了方便计算,RDATA的长度RDLENGTH存储的时候是存储的压缩过的,而不是扩展开的长度;程序本身可以不去使用压缩算法,但是必须能够处理其他服务器响应的包含压缩数据的DNS数据包

如下图所示,给出一个具体的压缩算法的域名实例,比如域名F.ISI.ARPA 以及FOO.F.ISI.ARPA, ARPA, 和根. 忽略其他的消息字段,域名的封装格式如下:

       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    20 |           1           |           F           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    22 |           3           |           I           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    24 |           S           |           I           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    26 |           4           |           A           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    28 |           R           |           P           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    30 |           A           |           0           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    40 |           3           |           F           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    42 |           O           |           O           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    44 | 1  1|                20                       |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    64 | 1  1|                26                       |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    92 |           0           |                       |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

如上述压缩算法所示, 开始的F.ISI.ARPA出现在偏移量位20的位置,域名FOO.F.ISI.ARPA出现在偏移量为40的位置,后者只是保存了前面的第一个标签FOO,紧随后面的是一个偏移量字段。域名ARPA定义在偏移量位26的位置,最后一个0代表了根域名,并且根并没有任何标签。

4.2 传输

互联网支持使用TCP协议来完成域名的查询和响应,也支持使用UDP来完成,具体的描述则在RFC793和RFC768中定义,区传输为了保证数据的可靠传输,一般使用TCP完成。

4.2.1 使用UDP传输

消息通过UDP的端口53来进行传输,消息传输被限定在512个字节(不包含任何IP和UDP的头部开销)更长的消息将设置TC比特位来对消息进行截断。使用UDP来传输数据的时候,可能丢包,因此必须考虑一定的重传策略。同时udp传输上是不保证传输次序的,因此不能依赖于任何数据包的到达次序

重传策略依赖于性能和客户端的需要,但是推荐的策略如下:

  1. 客户端应该尝试其他的不同域名服务器地址
  2. 重传间隔设置应该基于统计来设置,太频繁的重传讲造成不必要的负载压力,最小的重传间隔位2-5秒

4.2.2 使用TCP传输

使用TCP传输数据也是使用端口53完成,消息前追加两个字节的长度域,且长度不包含长度域本身仅仅是消息的长度, 使用tcp传输可以允许低级别的处理来传输整个数据包后再去解析它。

一些连接管理策略如下:

  1. 服务器不应该封锁等待TCP数据的活跃连接
  2. 服务器应该支持多个连接
  3. 服务器应该假设客户端可以处理连接关闭的操作,并且应该延迟自身的连接关闭直到所有客户端连接已经处理完成
  4. 如果服务器需要关闭一个不活跃的连接去回收资源,应该等待直到这个连接已经空闲超过2分钟,并且服务器应该允许soa和axfr查询在一个单一的连接上。当服务器不能响应查询的时候应该重置或者单边关闭连接,而不是优雅关闭。

5 区文件

区文件以文本方式包含资源记录,首先介绍下资源记录存储的格式,以及为了从文件读取数据创建一个区需要特殊的考虑的问题。

5.1 格式

文件的格式包含一系列的资源记录,这些资源记录是按照行来规划,尽管使用括号可以连接不同的行的内容,且文字中可以包含CRLF. 任何使用空格或者tab符号分割的内容都看成是一个记录内容,每一行都可以使用;来代表一些注释内容

格式中允许任何地方出现空行!

两个控制记录: $ORIGIN 和 $INCLUDE, 其中$ORIGIN用来重新设置当前名称的相对域名。$INCLUDE则插入一个文件到当前行,并且同样可以针对文件内容的相对域名(但是无法修改父级别的相对域名)。

如果任何的资源记录以空格开头,则资源记录的拥有者同上面的资源记录保持一直,如果资源记录以域名开头,则重置资源记录的所有者信息。

资源记录的内容由两个形式组成

[<TTL>] [<class>] <type> <RDATA>
[<class>] [<TTL>] <type> <RDATA>

其中带中括号代表了该字段为可选字段,类型和类别都是以字符串而不是对应的代码组成,TTL是一个十进制数字,占据了区文件中大量的内容,每一个域名都是以字符串和点好进行隔离,如果包含最后的点好,这个域名成为绝对域名,否则域名成为相当域名,相对域名将当前域名和之前设置的$ORIGIN进行组合,如果没有设置$ORIGIN,则报错。

其中的一些符号定义如下:

  • @  用来定义当前的$ORIGIN
  • \X 这里的X是除了数字之外的字符,用来表示该字符具有特殊的意义,比如(\.)用来在label中加入一个点
  • \DDD 每一个D代表了一个8位长度代表的数字或者字符,代表了这里看作是一个文本而不去检查他的特殊含义。
  • () 用来设置跨越多行的内容
  • ; 作为注释符号

5.2 使用区文件来定义区

当一个区文件被载入进来的时候,任何报错都应该是的整个的程序操作终止。主要是任何一处的错误,都有可能导致多条记录数据出现问题。比如一个区数据代理出去的子区的定义包含语法错误,则整个子区的数据在解析的时候都可能导致错误发生。

为了保证文件语法正确,一些验证错误的方式如下:

  1. 所有的资源记录在一个文件中的应该具有相同的类
  2. 一个SOA记录应该总是在区文件的头部
  3. 如果一个代理区出现在区文件中,对应glue记录应该存在
  4. 区中出现的非权威信息应是glue信息,而不是原始记录或者其他相似的错误

5.3 区文件实例

以下是一个区文件的实例,载入的origin是isi.edu因此@代表了isi.edu,同时在定义区管理员邮箱地址的时候使用转义字符转义,获得的最后的邮箱地址是Action.domains@ISI.EDU

@   IN  SOA     VENERA      Action\.domains (
                                 20     ; SERIAL
                                 7200   ; REFRESH
                                 600    ; RETRY
                                 3600000; EXPIRE
                                 60)    ; MINIMUM

        NS      A.ISI.EDU.
        NS      VENERA
        NS      VAXA
        MX      10      VENERA
        MX      20      VAXA

A       A       26.3.0.103

VENERA  A       10.1.0.52
        A       128.9.0.32

VAXA    A       10.2.0.27
        A       128.9.0.33


$INCLUDE <SUBSYS>ISI-MAILBOXES.TXT

其中包含的另外的ISI-MAILBOXES.TXT文件内容如下:

    MOE     MB      A.ISI.EDU.
    LARRY   MB      A.ISI.EDU.
    CURLEY  MB      A.ISI.EDU.
    STOOGES MG      MOE
            MG      LARRY
            MG      CURLEY

6. 域名服务器的实现

6.1 架构设计

域名服务器的实现依赖于主机操作系统,以及是否集成了解析器的功能,是否支持递归服务,是否域解析器同时共享数据。这一部分讨论的实施内容考虑了一个域名服务器和解析器共享一个数据库,但是本章大部分内容也同样适用于其他的域名服务器。

6.1.1 控制

域名服务器必须能够同时处理多项并发的任务,不管实施是使用分离的任务还是复用的方式。比如进行tcp传输等待的时候,必须仍旧可以进行udp的查询;在执行区传输或刷新区数据,重新加载区文件的时候也不能显著的延迟请求的处理;同样也不能在无法提供查询的并行处理的时候尝试提供递归服务。

6.1.2 数据库

尽管域名服务器实施可以使用任何的数据结构,但是有一些建议可以供参考,包含如下三个方面:

  1. 一个目录数据结构列举所有可用的区,指针指向所对应的区数据结构,主要目的用来查找所查询数据最接近的锚点。
  2. 为每个区数据使用分离的数据结构
  3. 使用一个数据结构来保存缓存的数据

所有这些数据结构可以实施使用相同的树型结构,将节点链接在一起。在设计熟行结构的时候,应该识别查询流程需要便利这个树使用大小写不敏感的比对方式,并且要知道在树形结构中,大部分的节点分支较少,但是却有个别的节点具有很多的分支(100-1000个或者更多)

解决大小写问题的一种方式是将标签存储分为两个内容,一个是标准化后的标签,所有字符都使用一种大小写方式,另外一部分则是bit掩码来表示哪一个字符是不同的大小写。节点分支可以使用一个简单的链表结构来存储,当数量超过一定的门限值后转换位hash结构存储。同时要注意任何情况下,hash结构用来存储树型结构必须确保hash函数和处理能够保留DNS的大小写惯例

使用分离的结构来定义不同的部分主要由以下几个因素:

  1. 目录结构基本很少变化,一般只有管理员改变所支持的区数据的时候才变化,这个结构可以使用来存储相关的参数,比如用于控制区数据刷新
  2. 为每一个区设置单独的数据结构可以允许区数据替换的时候仅仅只需要在目录结构中修改一个指针即可,刷新过程中,可以创建一个新的数据结构,并在结束之后切换下目录内容(保证刷新操作不会影响区数据的重传)
  3. 区数据和缓存数据的分离,可调整适当的搜索过程,设置区数据相对于缓存数据优先进行选择。
  4. 一个区中出现的问题,不会影响其他的区
  5. 缓存由于经常发生变化,并且在系统重启的时候很脆弱,而且它可能包含很多到期的资源记录,删除这些区缓存数据也不会影响区数据。

数据库设计的其中一个主要方面是允许一个名称服务器能够处理域名服务器崩溃的情况,崩溃时当前状态信息应当被有效的保存下来,比如刷新的状态和区数据本身

6.1.3 时间

对于缓存时间和刷新时间推荐的设置策略是存储时间使用两种方式,作为一个相对增加的值和作为一个绝对的时间。区数据中的资源记录使用相对时间,缓存时间和刷新时间则使用绝对时间。绝对时间在响应的时候被转化为相对的值,同时允许程序在定时任务的时候进行判断是否超过了范围,来完成数据的清理工作。

6.2 标准查询流程

标准查询流程的主要算法在rfc-1034中已经给出。

当查询的类为QCLASS=*或者查询的类是多个类的时候,服务器不应该回应rr(权威应答),因为无法保证服务器是包含所有的类别的权威响应。

当组合一个响应的时候,资源记录被插入到additional字段,但是如果包含与权威和应答字段重复的资源记录应当被删除。

当一个响应大小由于太长需要被截断处理的时候,截断的内容应当在响应结束的位置,依然可以保持整个的数据包的一致性,也就响应部分内容仍旧是唯一的,不会与任何权威应答部分的数据发生重复。

存储在SOA中的MINUMUM值,应当利用floor函数设置成分布在区数据中的TTL最小值,且应该区数据被复制到响应之前被调用,允许将来动态更新协议去修改该值。

6.3 区刷新和重载

域名服务器可能在区文件语法错误的情况下出现载入失败,或者无法刷新区数据(超出最大的到期参数),在上述情况下,域名服务器应当不响应任何该区的权威查询。 如果一个主服务器正在利用AXFR发送一个区传输数据,一个新的版本数据被载入,主服务器应当继续完成传输原来的数据。不能出现新旧数据混合传输的情况,如果无法完成传输,主服务器应当重置区传输的连接。

6.4 反向查询

反向查询是DNS服务中的可选配置,任何域名服务器无法处理该类型的查询的时候,应当至少返回一个未实施的错误信息。注意此处的反向查询不同于PTR查询。

6.4.1 反向查询和响应内容

反向查询定义一个资源到域名的查询,比如一个标准查询映射一个域名到主机地址,但是反向查询则映射主机地址到域名。反向查询将利用一个资源记录来进行查询,资源记录中的所有者和TTL一般不太重要,Question部分为空,响应内容则将对应的查询内容放置于Question部分返回客户端。反向查询主要用于调试和数据库管理使用,不能用来替代地址到域名的反向查询,应当使用IN-ADDR.ARPA域名进行查询。

使用反向查询同样应该保持大小写不敏感来处理, 服务器接收到反向查询的时候返回的内容可以是如下的格式:

  • 0,1或者多个域名(保存在QuestionSection)
  • 错误代码,服务器不支持反向查询

当响应的域名包含多个的时候,域名所有者及TTL应该与第一个资源记录严格匹配, 响应的资源记录不能使用之前的缓存机制进行处理,因为可能存在多个相同类型的资源记录,但是缓存却只出现了一个地址。

6.4.2 反向查询实例

以下是一个反向查询的实例,查询对应的域名,其A地址为10.1.0.52,查询类别为Internet类

                         +-----------------------------------------+
           Header        |          OPCODE=IQUERY, ID=997          |
                         +-----------------------------------------+
          Question       |                 <empty>                 |
                         +-----------------------------------------+
           Answer        |        <anyname> A IN 10.1.0.52         |
                         +-----------------------------------------+
          Authority      |                 <empty>                 |
                         +-----------------------------------------+
         Additional      |                 <empty>                 |
                         +-----------------------------------------+

对于上述查询的响应数据定义如下, QTYPE设置为对应的类型A,当反向查询的时候,Question部分可能包含多个内容,不止一个Question 对象。

                         +-----------------------------------------+
           Header        |         OPCODE=RESPONSE, ID=997         |
                         +-----------------------------------------+
          Question       |QTYPE=A, QCLASS=IN, QNAME=VENERA.ISI.EDU |
                         +-----------------------------------------+
           Answer        |  VENERA.ISI.EDU  A IN 10.1.0.52         |
                         +-----------------------------------------+
          Authority      |                 <empty>                 |
                         +-----------------------------------------+
         Additional      |                 <empty>                 |
                         +-----------------------------------------+

6.4.3 反向查询处理

域名服务器可以通过对于数据库的搜索来完成反向查询, 但是当数据库数据越来越多的时候,反向查询需要的资源明显会增加,可选的方式通过搜索键来对于数据库树形结构进行反向处理。如果域名服务器具有多个区数据,每个区数据都包含一个独立的反向的数据结构,当区数据修改的时候,反向数据结构也需要进行修改。

对于这种反向数据结构的数据传输可以在将来的版本中实现

6.5 完整的查询和响应

此部分内容在rfc-882和rfc-883中删除,未来考虑重新设计

7. 解析器实施

顶层的实施架构可以参考rfc-1034, 此部分包含一些具体的实施细节内容(依赖于之前介绍的数据库结构建议)

7.1 转换用户请求到DNS查询

解析器第一步工作是接收一个客户端发送的请求内容(格式依赖于操作系统)到一个具体的查询,包含必要的查询类别(QCLASS),查询类型(QTYPE)和域名信息。如果可以的话,尽量保持查询类别和查询类型是属于单一的类型,这样服务器在缓存的时候会更容易处理。 如果查询的类别是QCLASS=*,则不会返回权威应答,因为查询IN类的权威,不能保证同样是HS或者CH的权威应答。

每个解析器都可以复用多个请求去并发响应多个查询,每个查询的请求中通常包含了一些当前查询的信息内容,这个信息内容一般包含

  • 一个时间戳,代表请求开始的时间。资源记录存储在缓存和区数据中的时间戳使用绝对时间(参考前文)资源记录的TTL将和查询请求时间进行比对来查看是否过期。
  • 解析器内部需要对一些资源查询进行限制,比如单一查询的重传次数,可以设置一个最大值,依次递减完成,用来处理网络不可达等错误问题。如果解析器需要产生一些额外的查询的时候也要保证传递的计数器递减,防止资源的不断消耗。
  • SLIST数据结构在RFC1034中有详细的介绍,这个结构体可以用来追踪查询请求的状态(比如,等待外部服务器的响应操作)

7.2 发送查询

解析器的任务是组合一个查询,并帮助客户端查询域名服务器,返回给客户所需要的信息。解析器本身一般配置有一些服务器用于提供初始的查询。解析器将向最有可能响应查询的域名服务器发送消息,并减少查询使用时间,避免额外的的传输花费,主要的算法是使用请求的信息来决定下一个发送的域名服务器地址,计算超时时间,对于超时的服务器则在下次发送的时候转用其他的服务器。

为了完成SLIST的初始化,解析器借助所有发送到这些服务器的历史信息,来设置不同权重给这些服务器(比如服务器响应请求的次数),另外这些信息应该基于IP地址,而不是域名服务器,因为域名服务器本身可能具有多个地址,这些地址可能是不同的响应效率。同时源地址也有可能有多个,比如解析器同时多个网卡使用查询等等, 因此保存的记录应该是解析器IP和域名服务器IP的配对。每一个子域的代理,都需要初始化一组新的SLIST结构。

这些信息建立起一个排序好的域名服务器,每次服务器选择且无法工作的时候,应该修改列表状态,防止重新被选择,直到其他的服务器都已经被尝试过。设置的服务器超时时间应该比平均时间长50%或者100%左右

一些需要注意的地方:

  • 解析器无可用的地址去发送查询,这种情况一般出现在当这个Glue记录比NS记录要短,或者
  • 解析器获得一个服务器错误信息或者一些奇怪的应答,应当将该服务器删除,并从其他的域名服务器上重新获取结果。

7.3 处理响应

处理响应数据包的第一步需要解析数据包,包含如下多个步骤

  • 检查响应数据包的头部信息,删除有问题的数据包(比如在等待响应的时候却接收到的是查询包)
  • 解析消息部分,确保所有的资源记录格式正确
  • 作为一个可选择的步骤,检查到达的数据的TTL, 对于资源记录如果TTL超过了一周时间,应该删除整个响应,或者限制到1周时间。

下一步是匹配查询和响应消息,推荐的策略是先去完成DNS数据包中ID值的匹配, 然后验证查询部分的请求内容是否一致。使用ID来标示一个唯一的查询请求,同时还有一些需要明确的地方如下:

  • 一些域名服务器使用不同的服务器来接收和发送响应,一个解析器不能依赖于一个响应是否来自于相同的地址来辨识查询。
  • 如果一个解析器重传查询请求到域名服务器,它选择服务器基于一定的优先级,如果简单的基于查询时间,则应该可以识别到底是哪个服务器发送的查询响应的时间更快。或者只是基于最初的查询时间来设置优先级。
  • 域名服务器可能偶尔无法提供当前区数据查询,解析器应该能够从SLIST结构中移除这个查询的NS

7.4 使用缓存

解析器缓存所有已查询的信息(定期执行删除过期数据),用于将来的客户查询,但是部分数据不应该被缓存:

  • 当同一个类型的域名查询获得的多个资源记录被返回的时候,缓存要么不执行缓存要么缓存所有记录,特别是如果响应被截断,且解析器不能获得或者无法得知是否数据是完整的时候,不能去缓存数据
  • 缓存数据不能优先权威数据被使用,如果可能导致这种问题的话,应该设置不去产生对应数据的缓存内容
  • 反向查询结果不应该被缓存
  • 标准查询的域名包含(*)的数据不应该被缓存,因为这是一个通配符,缓存可能无法包含所有的区域数据边界信息。
  • 资源记录数据不可靠的时候不进行缓存,当一个解析器接收到未主动发起的请求响应的时候,需要丢弃该数据包,所有的数据包在缓存之前都应该进行必要的安全检查

当解析器拥有一些列的资源记录去响应给客户端的时候,同时想要缓存这部分信息,应该检查缓存是否已经存在,另外任何出现在权威部分的数据,都应该优先与缓存数据。

8. 邮件支持

域名系统定义了标准的邮箱到域名的映射,有两种方式可以用来传递邮箱的路由信息;第一种方式是使用邮件交换(MX记录)绑定,另一种是邮箱绑定。 使用邮件交换绑定是官方支持的一种,也是推荐的使用方式。 邮箱绑定则属于实验性特征,可能未来会发生变化。

邮箱编码标准假设邮箱名称格式是:@ 其中前半部分的作为一个独立的标签,如果标签中具有点号则使用转移字符来处理,比如邮件地址Action.domains@ISI.EDU 则被标示为Action\\\.domains.ISI.EDU.

8.1 MX绑定

邮件交换绑定使用邮件地址中的《mail-domain》部分作为查询的内容,获得具体的邮件交换服务器地址,来发送邮件。RFC-974定义了详细的实施细节,这种方式的优势是解耦了邮件的目的

8.2 邮箱绑定(实验性)

使用这一方式的时候,发送邮件的一方使用整个的邮件地址去构造一个域名,新的域名查询的时候,查询类型设置为MAILB类型,查询的可能结果如下:

  1. 域名查询失败,域名不存在, 但是除非普及开来使用,否则一般情况下代表的是查询类型不支持,此时应该转换为对应的MX交换绑定方式
  2. 查询返回一个MR(Mail Rename)记录 ,类似于CNAME,因此发送者应该重新发送接收到的新的邮件域名查询其MAILB类型
  3. 查询返回一个MB类型, 发送者接收到这种类型后应该发送邮件信息(SMTP或者其他协议)到接收到的域名主机
  4. 查询返回一个MG(Mail Group)类型, 接收到的不是单一的主机,而是多个主机,属于同一个主机组,发送邮件应该将邮件消息重复发送到每一个组成员
  5. 查询返回一个MB记录同时返回一个或者多个MG记录,发送邮件方应该发送邮件给MB记录所代表的主机,这个主机将负责发送到所有的其他组成员,或者发送人使用MG记录直接自己发送给邮件组成员。

任何情况下,响应信息都有可能包含一个MINFO信息,这个资源记录通常与邮件组相关,且允许与一个MB记录同时存在。 MINFO信息包含两个邮箱,一个用来定义原始发送的邮箱的负责人邮箱地址,另一个用来定义错误信息的接收邮箱地址,对于向一组成员发送时邮件出现错误的情况,不需要重复发送给每一个成员,而是直接发送到这个错误邮箱即可。


Related Posts