DNS:域名系统(一)

两年前写了《DNS协议及DNS客户端的实现》,最近一段时间计划重新写一个 DNS 客户端库,翻看当初写的文章,觉得太浅、太粗,甚至有错漏。于是决定在写 DNS 库的同时,写一篇博客,算是对以前文章的补充和修正。

将域名系统理解成一个“将 IP 地址和域名相互映射的分布式数据库”是片面的,域名系统面向的是域名和与域名相关联的资源,包括但不仅限于 IP 地址。域名系统的主要设计目标是(在网络中)实现一个统一的名字空间(name space)用于关联名字与其对应的资源(resources)。为了避免尤其是编码方式导致的一些问题,在域名中不应该包含网络 id、地址、路由或类似的其他信息[1]

DNS 是一个分布式的系统,由 Internet 上遍布世界各地的域名服务器组成;分布式域名系统的另一个含义是,在整个系统中,每一个节点的服务器都只存有部分域名的记录。当想要解析一个域名时,可能需要直接或间接地访问多个域名服务器才能得到结果。

DNS 的名字空间是一个树状结构,树中的每一个结点都拥有一个标签(label),规定标签的长度在 0-63 字符之间,其中 0 字符长的标签(NULL)由根结点保留。另外,兄弟结点之间不能有相同的标签,但非兄弟结点(即使是父子结点)之间可以拥有相同的标签。标签由英文字母(a-z, A-Z)、数字(0-9)和连字符(-)组成,不区分大小写,连字符不能连续出现,也不能出现在标签的第一个字符处。例如,label0、label-0 是合法的,而 -label、label–0 是非法的结点标签;label0 与 LABEL0 是等效的标签。每一个结点都对应一个域名,结点的域名由结点与根之间的路径上所有的结点(包括结点和根本身)的标签组成,这些标签从左到右依次排列,用点号(.)连接。下图展示了互联网中真实 DNS 名字空间的一部分,大部分结点还有其他子结点没有画出。

dns图1 互联网中 DNS 域名系统的一部分

根结点的直接子结点所在的域称为顶级域,对应的域名称为顶级域名,顶级域名目前由 ICANN(互联网名称与数字地址分配机构)负责分配和管理,关于域的分配和授权将在下文中讨论。从名称来看,顶级域可以分为以下几种:

  • 普通组织域名,通常为三个字符,是最常见的域名,如 com(商业机构)、net(网络服务)、org(非盈利性组织)等;
  • 国家域名,通常为两个字符,分配给世界各国使用,如 cn(中国)、tw(台湾)、us(美国)、jp(日本)等;
  • 用于地址到名字转换的特殊域 arpa。

最近 ICANN 还分配了一些由汉字组成的顶级域名,如“中国”等。

域名系统的正常运作离不开域名服务器(Server)和域名解析器(Resolver)。域名服务器中存储有它所管辖的域的域名和资源记录数据,并运行着一个域名服务程序,接受网络上的域名查询请求,并查询相应的记录,向查询者返回结果。域名解析器是一个客户端程序,它由应用程序调用,并通过网络接口访问一台或多台域名服务器,最终返回给调用者域名解析结果。

域名系统的中心是根结点,管理根结点所在域的服务器是根域名服务器,是最根本、最重要的域名服务器。全球共有 13 台根域名服务器,它们都有自己的域名,分别是 a.root-servers.net、b.root-servers.net,…,一直到 m.root-servers.net。这里的“一台根域名服务器”指的是逻辑上的数量,并不是指服务器的主机数量,事实上“一台”根域名服务器都由多台主机组成,它们共有同一个域名和 IP 地址。所有的根域名服务器都只存有全部顶级域名的记录,并只能提供对顶级域名的解析服务。

前面讲道,想要解析一个域名可能需要向多个域名服务器发起解析请求,这是由域名系统的层次结构以及授权机制决定的。ICANN 负责管理和分配全部顶级域名,并将顶级域名分别授权给所有这些域名的机构。例如,顶级域名 cn 由 ICANN 授权给 CNNIC(中国互联网络信息中心)管理。这些拥有顶级域名的二级域名机构可以布署域名服务器,并再授权给下一级的其他机构来管理他们的域名或子域名。这样,一个由根结点出发,逐级授权的域名系统就能建立起来了。

所有根域名服务器都是权威的(authoritative)域名服务器,权威域名服务器意味着它的提供的域名记录是“授权的”。同样,由 ICANN 授权的顶级域名管理机构以及它们授权的机构所属的服务器也是权威的域名服务器。权威域名服务器上的授权记录是由管理员通过配置文件设置的,另外,授权域名服务器之间还会定期通过“区域传递”来交换这些记录以保持持续的更新。

一次典型的域名解析是解析器首先向根域名服务器发起请求,请求查询被解析域名所在的顶级域名的信息。根域名服务器通常会返回所有该顶级域名的域名服务器的名称,解析器再向顶级域名所有者服务器发起解析,此时可能收到解析的结果,也可能收到下一个域名服务器的名称。如果是后者,则解析器再次向下一级域名服务器发起请求,直到得到它想要的结果。下面是用 dig 命令跟踪解析域名 work.luodichen.com 的 IP 地址的结果。

MacBook-Air-luodichen:~ luodichen$ dig +trace work.luodichen.com

; <<>> DiG 9.8.3-P1 <<>> +trace work.luodichen.com
;; global options: +cmd
.                       408915  IN      NS      k.root-servers.net.
.                       408915  IN      NS      c.root-servers.net.
.                       408915  IN      NS      l.root-servers.net.
.                       408915  IN      NS      g.root-servers.net.
.                       408915  IN      NS      d.root-servers.net.
.                       408915  IN      NS      f.root-servers.net.
.                       408915  IN      NS      b.root-servers.net.
.                       408915  IN      NS      h.root-servers.net.
.                       408915  IN      NS      i.root-servers.net.
.                       408915  IN      NS      a.root-servers.net.
.                       408915  IN      NS      m.root-servers.net.
.                       408915  IN      NS      e.root-servers.net.
.                       408915  IN      NS      j.root-servers.net.
;; Received 228 bytes from 202.96.128.86#53(202.96.128.86) in 392 ms

com.                    172800  IN      NS      l.gtld-servers.net.
com.                    172800  IN      NS      c.gtld-servers.net.
com.                    172800  IN      NS      e.gtld-servers.net.
com.                    172800  IN      NS      b.gtld-servers.net.
com.                    172800  IN      NS      i.gtld-servers.net.
com.                    172800  IN      NS      j.gtld-servers.net.
com.                    172800  IN      NS      g.gtld-servers.net.
com.                    172800  IN      NS      h.gtld-servers.net.
com.                    172800  IN      NS      k.gtld-servers.net.
com.                    172800  IN      NS      a.gtld-servers.net.
com.                    172800  IN      NS      d.gtld-servers.net.
com.                    172800  IN      NS      m.gtld-servers.net.
com.                    172800  IN      NS      f.gtld-servers.net.
;; Received 508 bytes from 192.36.148.17#53(192.36.148.17) in 413 ms

luodichen.com.          172800  IN      NS      f1g1ns1.dnspod.net.
luodichen.com.          172800  IN      NS      f1g1ns2.dnspod.net.
;; Received 250 bytes from 192.41.162.30#53(192.41.162.30) in 390 ms

work.luodichen.com.     600     IN      NS      ns1.oray.net.
work.luodichen.com.     600     IN      NS      ns2.oray.net.
;; Received 88 bytes from 112.90.82.194#53(112.90.82.194) in 87 ms

work.luodichen.com.     60      IN      A       113.76.146.88
;; Received 52 bytes from 61.174.40.200#53(61.174.40.200) in 81 ms

可以看到在解析 work.luodichen.com 的过程中,经历了如下几个阶段

  1. 向本地配置的 DNS 服务器 202.96.128.86 查询根域名 . 的域名服务器,得到 13 个根域名服务器的域名;
  2. 向其中某个根域名服务器 192.36.148.17 查询顶级域名 com 的域名服务器,得到一些服务器列表;
  3. 向其中某个 com 域名服务器查询 luodichen.com 的域名服务器,得到 f1g1ns1.dnspod.net 和 f1g1ns2.dnspod.net 两个域名服务器的域名;
  4. 向其中某个 luodichen.com 的域名服务器查询 work.luodichen.com 的域名服务器,得到 ns1.oray.net 和 ns2.oray.net 两个域名服务器的域名;
  5. 向其中某个 work.luodichen.com 的域名服务器查询 work.luodichen.com 的 IP 地址,得到最终结果是 113.76.146.88。

在实际的终端应用程序中,可能并不需要像以上的实验那样从根服务器开始一级一级地发起查询请求。如果所有的终端应用程序都这样做,一方面根域名服务器将承担巨大的网络压力;另一方面一次域名解析可能耗费非常长的时间,影响效率。解决这个问题的是缓存(Cache)技术。

除根域名之外的一些域名服务器,它们除了运行着域名服务程序之外,还运行着域名解析器。当这些服务器收到一个不属于它管辖的区域的域名解析请求时,它会尝试以客户端的身份向别的域名服务器发起解析请求,并将最终的解析结果返回给它的客户端,这种服务器称作递归域名服务器,它的客户端发起的解析请求称为递归解析请求。这种服务器同时还可能存在着一个高速缓存(Cache),用来缓存上面提到的这些域名解析的结果,当下次又有相同的域名的请求时,服务器会直接将缓存中的记录返回给客户端,并标记这个记录是“非权威的(non-authoritative)”查询结果。为了确保缓存中的信息能及时更新,每条 DNS 记录都有对应的存活时间(TTL, time to live),当缓存中的信息存在的时间超过它的 TTL 时,这条缓存记录就会过期失效,下次请求这条记录时,服务器又会以递归查询的方式解析这个域名,并再次存入缓存中。

为了解决 DNS 查询效率的问题,通常我们在终端系统中配置的是从 ISP 处获取的 DNS 服务器地址或者一些商业 DNS 服务器地址,如 114.114.114.114、8.8.8.8 等。这些服务器都属于带有缓存的递归服务器,终端解析器只要向这些服务器发送一次递归查询请求就能很快地得到查询结果。

解析器通过 DNS 协议向域名服务器发起查询请求,关于 DNS 协议的细节,以及域名系统多个资源记录作用与格式将在下一篇博文中讨论。

(允许转载本文,转载请注明出处:http://luodichen.com/blog/?p=318 )

参考文献
[1] P. Mockapetris, DOMAIN NAMES – CONCEPTS AND FACILITIES, RFC 1034, November 1987; www.ietf.org/rfc/rfc1034.txt
[2] P. Mockapetris, DOMAIN NAMES – IMPLEMENTATION AND SPECIFICATION, RFC 1035, November 1987; www.ietf.org/rfc/rfc1035.txt
[3] W. Richard Stevens, TCP/IP 详解 卷1:协议[M]. 机械工业出版社, 2000.