DNS

我们知道,身份证号码可以唯一标识一个人。但我们在相互介绍时通常不会使用身份证号码,而是报上姓名。因特网上的主机也和人类一样,有一个可以唯一标识的 IP 地址,同时它们也有一个主机名(hostname),例如 www.google.comwww.wikipedia.org 等。由于计算机只认识 IP 地址,所以我们需要一种能将主机名转换到 IP 地址的目录服务,这就是 DNS(Domain Name System),又称域名系统。

什么是 DNS

概念

  • 一个由分层的 DNS 服务器(DNS server)实现的分布式数据库。
  • 一个使得主机能够查询分布式数据库的应用层协议。

DNS 服务器通常是运行 BIND(Berkeley Internet Name Domain)软件的 UNIX 机器。DNS 协议运行在 UDP 之上,使用的端口号为 53。

使用场景

DNS 经常被其它应用层协议所使用,包括 HTTP、SMTP 和 FTP 等,用来将用户提供的主机名解析成 IP 地址。举个例子,当某个用户主机上的一个浏览器(即一个 HTTP 客户端)请求 URL www.huminxi.com/index.html 页面时会发生什么?

为了使用户的主机能够将一个 HTTP 请求报文发送到 Web 服务器 www.huminxi.com ,该用户主机必须获得 www.huminxi.com 的 IP 地址。其做法如下:

  • 用户主机上启动 DNS 客户端。
  • 浏览器从上述 URL 中抽取出主机名 www.huminxi.com ,并将这台主机名传给 DNS 客户端。
  • DNS 客户端向 DNS 服务器发送一个包含主机名的查询报文。
  • DNS 客户端最终会收到一份响应报文,其中包含了主机名对应的 IP 地址。
  • 一旦浏览器得到 DNS 客户端解析出来的 IP 地址,它就能够向位于该 IP 地址 80 端口的 HTTP 服务器进程发起一个 TCP 连接。

从这个例子中我们可以看到 DNS 给使用它的因特网带来了额外的时延(而且有时候还不低)。除了进行主机名到 IP 地址的转换之外,DNS 还提供了一些重要的服务:

  • 主机别名(host aliasing))
    • 有着复杂主机名的主机能拥有多个别名。
    • 例如,一台名为 relay1.west-coast.enterprise.com 的主机,可能还有两个别名为 enterprise.com 和 www.enterprise.com 。在这种情况下 relay1.west-coast.enterprise.com 也被称为 规范主机名(canonical hostname)。
    • 别名比规范主机名更加容易记忆。应用程序可以调用 DNS 服务来获取主机别名对应的规范主机名以及主机的 IP 地址。
  • 邮件服务器别名(mail server aliasing)
    • 显而易见,人们也希望电子邮件地址好记忆。
    • 例如,如果 huminxi 在 Gmail 上有一个账户,那邮箱地址就像 huminxi@gmail.com 这样简单。然而,Gmail 邮件服务器的规范主机名可能十分复杂,不像 gmail.com 这样简单好记。
    • 电子邮件应用程序可以调用 DNS 服务,对邮件服务器别名进行解析,以获得该主机的规范主机名及其 IP 地址。
    • MX 记录允许一个公司的邮件服务器和 Web 服务器使用相同的主机别名。例如,一个公司的邮件服务器和 Web 服务器都叫做 enterprise.com。
  • 负载均衡(load distribution)
    • DNS 可以用于冗余服务器之间的负载分配。
    • 繁忙的站点(如 cnn.com)被冗余分布在多台服务器上,每台服务器运行在不同的端系统上,每个都有着不同的 IP 地址。由于这些冗余 Web 服务器的存在,一个规范主机名可能与一个 IP 地址集合相关联。DNS 数据库中存储着这些 IP 地址集合。
    • 当客户发出一个 DNS 请求时,该 DNS 服务器会用 IP 地址的整个集合进行响应,但在每个回答中循环这些地址的次序(客户通常是向排在最前面的 IP 地址服务器发送 HTTP 请求报文)。

DNS 解析代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <netdb.h>
#include <arpa/inet.h>
#include <stdio.h>

int main(int argc, char **argv)
{
char *ptr, **pptr;
struct hostent *hptr;
char str[32];
ptr = argv[1];

if((hptr = gethostbyname(ptr)) == NULL)
{
printf(" gethostbyname error for host:%s\n", ptr);
return 0;
}

printf("official hostname:%s\n",hptr->h_name);
for(pptr = hptr->h_aliases; *pptr != NULL; pptr++)
printf(" alias:%s\n",*pptr);

switch(hptr->h_addrtype)
{
case AF_INET:
case AF_INET6:
pptr=hptr->h_addr_list;
for(; *pptr!=NULL; pptr++)
printf(" address:%s\n",
inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)));
printf(" first address: %s\n",
inet_ntop(hptr->h_addrtype, hptr->h_addr, str, sizeof(str)));
break;
default:
printf("unknown address type\n");
break;
}

return 0;
}

DNS 的原理

DNS 工作过程概述

假设运行在用户主机上的某些应用程序需要将主机名转换为 IP 地址。这些应用程序将调用 DNS 客户端,并指明需要转换的主机名。用户主机上的 DNS 客户端被调用后向网络中发送一个 DNS 请求报文。所有的 DNS 请求和响应报文都用 UDP 发送。经过若干毫秒的时延后,用户主机上的 DNS 客户端接收到包含映射结果的 DNS 响应报文,这个结果将通知到应用程序。

因此,在调用 DNS 服务的应用程序角度看,DNS 服务只是一个提供主机名和 IP 地址转换的黑盒子。事实上,这个黑盒子是非常复杂的,它由分布于全球的大量 DNS 服务器以及定义了 DNS 服务器与 DNS 客户端之间通信方式的应用层协议组成。

DNS 的实现方式

集中式

DNS 的一种简单实现是在因特网上只使用一个 DNS 服务器,该服务器包含所有的映射。在这种集中式设计中,客户将所有查询发往单一的 DNS 服务器,同时该 DNS 服务器直接对所有的查询做出响应。尽管这种设计的简单性十分突出,但它不适用于当今的因特网,因为因特网有着数量巨大(并且持续增长)的主机。这种设计的问题如下:

  • 单点故障(a single point of failure)
    • 如果该 DNS 服务器崩溃,整个因特网随之瘫痪!
  • 通信容量(traffic volume)
    • 单个 DNS 服务器必须要处理所有的 DNS 查询(用于数十亿台主机产生的 HTTP 报文和电子邮件报文等)。
  • 远距离的集中式数据库(distant centralized database)
    • 单个 DNS 服务器不可能临近所有查询客户。如果我们将单台 DNS 服务器放在纽约市,那么所有来自澳大利亚的查询必须传播到地球的另一边,中间也许还要经过低速和拥塞的链路,这将导致严重的时延。
  • 维护(maintenance)
    • 单个 DNS 服务器必须要为所有的因特网主机保留记录。这不仅将使这个中央数据库非常庞大,而且它需要频繁更新(每添加一台主机就需要更新一次)。

总的来说,在单一 DNS 服务器上运行集中式数据库完全没有可扩展能力。因此,DNS 采用了分布式的设计方案。

分布式

层次结构

为了处理扩展性问题,DNS 使用了大量的 DNS 服务器,它们以层次方式组织,并且分布在全世界范围内。大致来说,有 3 种类型的 DNS 服务器:根服务器、顶级域(Top-Level Domain,TLD)服务器和权威服务器。这些服务器以下图所示的层次结构组织起来。

DNS 服务器的层次结构

为了理解这 3 种类型的 DNS 服务器交互的方式,我们来举个例子。假定一个 DNS 客户要查询主机名为 www.amazon.com 的 IP 地址。客户首先与根服务器之一联系,它将返回顶级域名 com 的 TLD 服务器的 IP 地址。该客户则与这些 TLD 服务器之一联系,它将为 amazon.com 返回权威服务器的 IP 地址。最后,客户与 amazon.com 权威服务器之一联系,它将返回主机名 www.amazon.com 的 IP 地址。

各种类型的 DNS 服务器介绍
  • 根 DNS 服务器
  • 顶级域 DNS 服务器
    • 这些服务器负责 顶级域名 如 com、org、net、edu、gov 等,以及所有国家的顶级域名如 uk、fr、jp、cn 等。
  • 权威 DNS 服务器
    • 在因特网上具有公共可访问主机(如 Web 服务器和邮件服务器)的每个组织机构必须提供公共可访问的 DNS 记录,这些记录将这些主机的名字映射为 IP 地址。
    • 一个组织机构能够选择实现它自己的权威 DNS 服务器以保持这些记录;或者支付费用,让这些记录存储在某个服务提供商(如阿里)的一个权威 DNS 服务器中。多数大学和大公司实现和维护他们自己的权威 DNS 服务器。

验证根 DNS 服务器的 IP 地址

本地 DNS 服务器

除了上述几种 DNS 服务器。还有另一类重要的 DNS 服务器,称为本地 DNS 服务器(local DNS server)。一个本地 DNS 服务器严格来说并不属于 DNS 服务器的层次结构,但它却极为重要。每个 ISP(Internet Service Provider,如一个大学、一个公司或一个居民区)都有一台本地 DNS 服务器(也叫默认 DNS 服务器)。

mac 上使用 cat /etc/resolv.conf 命令查看默认的 DNS 服务器地址

一般来说,主机的本地 DNS 服务器通常临近本主机。对于某个 IPS 而言,本地 DNS 服务器可能就与主机在同一个局域网中。对于某居民区 ISP 来说,本地 DNS 服务器通常与主机相隔不超过几台路由器。当主机发出 DNS 请求时,该请求被发往本地 DNS 服务器,它起着代理的作用,并将该请求发送到 DNS 服务器层次结构中。

怎么理解上述这段话,我们来看一个简单的例子。假设主机 cis.poly.edu 想知道主机 gaia.cs.umass.edu 的 IP 地址。同时假设 cis.poly.edu 的本地 DNS 服务器为 dns.poly.edu,gaia.cs.umass.edu 的权威 DNS 服务器为 dns.umass.edu。

图 2-21 各种 DNS 服务器之间的交互

如上图所示,主机 cis.poly.edu 首先向它的本地 DNS 服务器 dns.poly.edu 发送一个 DNS 查询报文,报文中含有待转换的主机名 gaia.cs.umass.edu。

  • 本地 DNS 服务器将该报文转发到根 DNS 服务器。根 DNS 服务器注意到其 edu 前缀并向本地 DNS 服务器返回负责 edu 的 TLD 的 IP 地址列表。
  • 本地 DNS 服务器再向这些 TLD 服务器之一发送查询报文。该 TLD 服务器注意到 umass.edu 前缀,并返回权威 DNS 服务器的 IP 地址列表。
  • 最后,本地 DNS 服务器向 dns.umass.edu 重发查询报文, dns.umass.eud 用 gaia.cs.umass.edu 的 IP 地址进行响应。

注意,在本例中,为了获得一台主机名的映射,共发送了 8 份 DNS 报文:4 份查询报文和 4 份响应报文。 而且例子中的 TLD 服务器知道主机的权威 DNS 服务器的 IP 地址。一般而言,这种假设并不正确。相反,TLD 服务器只是知道中间的某个 DNS 服务器,该中间的 DNS 服务器依次才能知道用于该主机的权威 DNS 服务器。 所以正常情况下,我们发送的 DNS 报文将不止 8 份!

图 2-21 所示的例子利用了递归查询(recursive query)和迭代查询(iterative query)。从 cis.poly.edu 到 dns.poly.edu 发出的查询是递归查询,而后继的 3 个查询是迭代查询。从理论上讲,任何 DNS 查询既可以是迭代的也可能是递归的。例如,图 2-22 显示了一条 DNS 查询链,其中的所有查询都是递归的。实际中,一般都是遵循图 2-21 中的模式。从请求主机到本地 DNS 服务器的查询是递归的,其余的查询是迭代的。

图 2-22 DNS 中的递归查询

DNS 缓存

在图 2-21 的例子中,我们注意到,为了获得一台主机名的映射,我们共发送了 8 份报文,效率实在太低了! 实际上,为了改善时延性能并减少因特网上到处传输的 DNS 报文数量, DNS 广泛使用了缓存技术。

DNS 缓存的原理十分简单。在一个请求链中,当某 DNS 服务器接收到一个 DNS 回答时(例如,包含主机名到 IP 地址的映射),它能将该回答中的信息缓存在自己的存储器中。这样,下次再有相同的 DNS 请求时,可以直接将缓存的内容作为 DNS 回答发送过去,即使它不是该主机名的权威服务器。由于主机名与 IP 地址间的映射并不是永久的,DNS 服务器一般会给缓存设置一个超时时间(通常设置为两天)。这就是本地 DNS 服务器为什么如此重要的原因。

DNS 记录

实现 DNS 分布式数据库的所有 DNS 服务器存储着资源记录(Resource Record,RR),RR 提供了主机名到 IP 地址的映射。每个 DNS 回答报文包含了一条或多条资源记录。资源记录是一个包含了下列字段的 4 元组:

[Name, Value, Type, TTL]

TTL 是该记录的生存时间,它决定了资源记录应当从缓存中删除的时间。Name 和 Value 的值取决于 Type:

  • Type = A,Address Mapping record,则 Name 是个主机名,Value 是该主机名对应的 IP 地址。
    • 例如(relay1.bar.foo.com, 145.37.93.126, A)就是一条类型 A 记录。
  • Type = CNAME,Canonical Name record,则 Value 是别名为 Name 的主机对应的规范主机名。
    • 该记录能够向查询的主机提供一个主机名对应的规范主机名。例如(foo.com, relay1.bar.foo.com, CNAME)就是一条 CNAME 类型的记录。
  • Type = MX,Mail exchanger record,则 Value 是别名为 Name 的邮件服务器的规范主机名。
    • 例如(foo.com, mail.bar.foo.com, MX)就是一条 MX 记录。

阿里提供的 DNS 解析

现在,大家对 DNS 这三个字不陌生了吧。

扩展

hosts 文件 和 DNS 之间是什么关系

hosts 文件(域名解析文件)是一个用于储存计算机网络中各节点信息的计算机文件。这个文件负责将主机名称映射到相应的 IP 地址。hosts 文件通常用于补充或取代网络中 DNS 的功能。和 DNS 不同的是,计算机的用户可以直接对 hosts 文件进行控制。

最初在 Internet 的前身 ARPANET 中,其成员 SRI International 手动维护并分享了一个名为 HOSTS.TXT 的文件,其中就包括主机名称和对应地址。1983 年 DNS 系统开始开发,1984 年得到了发展。在网络快速的发展过程中,DNS 可以自动提供动态的主机名解析。不过在现代操作系统,hosts 文件仍然是一个可以作为备用手段的名称解析机制。

查看 DNS 解析的具体过程

1
dig +trace www.huminxi.com

引用