DNS(Domain Name System,域名系统)也许是我们在网络中最常用到的服务,它把容易记住的域名,如 www.google.com 翻译成人类不易记住的IP地址,如 173.194.127.132,以便在方便人类输入的基础上让计算机能够精确地在网络中找到目标机器。dig(Domain Information Groper)是一个比较常用的 dns 分析及调试工具,一般 Linux 和 Mac 都已默认安装。本文将基于 dig 的使用解释 dns 的基本知识。
解析
如果我们想知道 www.juvenxu.com 被解析到什么 IP 地址,可以用如下命令(我知道可以用ping,但本文主要围绕 dig 讲述):
|
$ dig www.juvenxu.com +noall +answer
; <<>> DiG 9.8.3-P1 <<>> www.juvenxu.com +noall +answer
;; global options: +cmd
www.juvenxu.com. 7803 IN A 98.130.162.53
|
命令行参数 +noall 和 +answer 只是为了输出更精简。
暂时忽略第3、4行,着重看最后一行,它分为5部分,第1部分是我们查询的域名;第2部分是缓存失效时间ttl(秒),暂且不关心;第3部分是 IN,表示类别 Internet,一般也都是这个类别;第4部分很重要,表示这行记录的种类(type),该行种类是 A(Address),说明这是一个A记录,描述域名对应的地址;第5部分好理解,就是地址了。
我们输入了 dig 命令和想查询的域名,得到了结果 IP 地址,本地的 dig 命令自然不可能知道世界上所有域名对应的 IP 地址(或者说A记录),那是谁告诉它的呢?
|
$ dig www.juvenxu.com +noall +answer +stats
; <<>> DiG 9.8.3-P1 <<>> www.juvenxu.com +noall +answer +stats
;; global options: +cmd
www.juvenxu.com. 6182 IN A 98.130.162.53
;; Query time: 4 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Sun Aug 3 22:27:31 2014
;; MSG SIZE rcvd: 49
|
加上 +stats 让 dig 打印基本的统计信息,其中第7行告诉我们 SERVER 是 192.168.1.1,53是DNS使用的 UDP(有时候可以是TCP)端口。dig 默认使用 /etc/resolv.conf 配置的域名服务器:
|
$ cat /etc/resolv.conf
#
# Mac OS X Notice
#
# This file is not used by the host name and address resolution
# or the DNS query routing mechanisms used by most processes on
# this Mac OS X system.
#
# This file is automatically generated.
#
nameserver 192.168.1.1
|
我们可以指定 dig 使用其他域名服务器帮我们解析域名,例如用 8.8.8.8:
|
$ dig @8.8.8.8 www.juvenxu.com +noall +answer +stats
; <<>> DiG 9.8.3-P1 <<>> @8.8.8.8 www.juvenxu.com +noall +answer +stats
; (1 server found)
;; global options: +cmd
www.juvenxu.com. 19008 IN A 98.130.162.53
;; Query time: 77 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sun Aug 3 22:35:36 2014
;; MSG SIZE rcvd: 49
|
这条命令中的 @8.8.8.8 表示使用 8.8.8.8 解析域名。
有些互联网服务部署在全球各个地方,这个时候服务提供方就希望中国的用户访问中国机房IP,美国的用户访问美国机房IP,这个时候两个地方的域名服务器返回的结果就会不一样,我们可以用类似上述的命令验证这一点。读者可以参考国内外DNS服务器地址列表,用各个国家的服务器 dig 一下知名站点如 google.com 试试。
不过即便如此,192.168.1.1 也好,8.8.8.8 也好,都不可能知道全球所有的域名信息,事实上,全世界数以亿次的域名信息分布在无数的域名服务器上,我们可以看一下维护 www.juvenxu.com 域名信息的服务器是什么:
|
$ dig www.juvenxu.com ns +noall +answer
; <<>> DiG 9.8.3-P1 <<>> www.juvenxu.com ns +noall +answer
;; global options: +cmd
|
我们在 dig www.juvenxu.com 后面加了 ns 参数,表示希望得到域名服务器信息(而不是默认的A记录),不过这次查询我们没有得到任何结果。没有关系,这往往表示该域名的上一级域名 (juvenxu.com)的域名服务器管理这个子域名,因此我们 dig juvenxu.com:
|
$ dig juvenxu.com ns +noall +answer
; <<>> DiG 9.8.3-P1 <<>> juvenxu.com ns +noall +answer
;; global options: +cmd
juvenxu.com. 84372 IN NS ns13.ixwebhosting.com.
juvenxu.com. 84372 IN NS ns14.ixwebhosting.com.
|
结果有两行记录,和 dig A记录结果一样,各自分成5部分,第1,2,3部分和A记录结果含义一致,第4部分表示表示种类(type)是 NS(Name Server,域名服务器),第5部分自然就是域名服务器的地址了。
现在我们知道 dig 请求域名服务器 192.168.1.1 juvenxu.com 的域名信息,而 ns13.ixwebhosting.com 和 ns14.ixwebhosting.com 保存了 juvenxu.com 的域名信息,那么 192.168.1.1 怎么知道如何联系上 ns13.ixwebhosting.com 或 ns14.ixwebhosting.com 呢?这就涉及到 DNS 的分布式架构了。
整个 DNS 服务是按照树形的结构分布的,最顶级是根域名,根域名服务器保存了所有定级域名服务器的信息,顶级域名包括 com, net, edu, org, cn 等等,各个定级域名服务器又包含了下一级的域名服务器信息,如 com 域名服务器包含了 microsoft.com, amazon.com 这些域的服务器信息,这样一层层往下:
我们可以使用 dig 的 +trace 选项来仔细查看这个过程:
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
|
$ dig juvenxu.com +trace
; <<>> DiG 9.8.3-P1 <<>> juvenxu.com +trace
;; global options: +cmd
. 209409 IN NS g.root-servers.net.
. 209409 IN NS b.root-servers.net.
. 209409 IN NS a.root-servers.net.
. 209409 IN NS h.root-servers.net.
. 209409 IN NS d.root-servers.net.
. 209409 IN NS j.root-servers.net.
. 209409 IN NS k.root-servers.net.
. 209409 IN NS f.root-servers.net.
. 209409 IN NS l.root-servers.net.
. 209409 IN NS c.root-servers.net.
. 209409 IN NS e.root-servers.net.
. 209409 IN NS i.root-servers.net.
. 209409 IN NS m.root-servers.net.
;; Received 496 bytes from 192.168.1.1#53(192.168.1.1) in 13 ms
com. 172800 IN NS e.gtld-servers.net.
com. 172800 IN NS j.gtld-servers.net.
com. 172800 IN NS c.gtld-servers.net.
com. 172800 IN NS l.gtld-servers.net.
com. 172800 IN NS m.gtld-servers.net.
com. 172800 IN NS a.gtld-servers.net.
com. 172800 IN NS d.gtld-servers.net.
com. 172800 IN NS g.gtld-servers.net.
com. 172800 IN NS i.gtld-servers.net.
com. 172800 IN NS b.gtld-servers.net.
com. 172800 IN NS f.gtld-servers.net.
com. 172800 IN NS k.gtld-servers.net.
com. 172800 IN NS h.gtld-servers.net.
;; Received 501 bytes from 192.58.128.30#53(192.58.128.30) in 45 ms
juvenxu.com. 172800 IN NS ns13.ixwebhosting.com.
juvenxu.com. 172800 IN NS ns14.ixwebhosting.com.
;; Received 112 bytes from 192.35.51.30#53(192.35.51.30) in 529 ms
juvenxu.com. 86400 IN A 98.130.162.53
;; Received 45 bytes from 98.130.253.162#53(98.130.253.162) in 222 ms
|
dig 直接请求的 192.168.1.1 并不知道 juvenxu.com 的 A记录是什么,它就去让 dig 去问根域名服务器,根域名服务器也不知道,让 dig 去问 com 的域名服务器,com 域名服务器也不知道,就让 dig 去问 ns13.ixwebhosting.com 和 ns14.ixwebhosting.com,而我们知道,这两个域名服务器保存了 juvenxu.com 的 A记录。这种一问一答的解析方式,叫做迭代解析(Iterative resolution)。这种方式下,每个域名服务器只是给出它所知道的最佳答案。
另外一种解析方式是递归解析(recursive resolution),如果我们不给 dig 加上 +trace 参数,dig 就会给域名服务器 192.168.1.1 一个递归解析请求,等于告诉是让 192.168.1.1 直接负责去解析到最终答案,然后直接返回给 dig。通常情况下客户端(dig)对域名服务器发起的递归解析请求,而域名服务器对其他域名服务器的请求(如 192.168.1.1 对根域名服务器)是迭代解析请求。
缓存
如果世界上所有网络设备(PC,服务器,手机,平板电脑……)的每次网络请求都要访问 DNS 根服务器,那这个量就实在是太大了,根服务器肯定受不了。考虑到一个域名和其IP的对应关系其实不会太常变化,因此在各个域名服务器缓存之前请求过的域名 A记录就是个不错的策略。基于此,对于一个域名如 douban.com 来说,域名服务器分成两类,一类是切切实实保存该域名信息的服务器,称为权威域名服务器(Authoritative Name Server),其余的仅仅是缓存其域名信息的服务器,就是缓存域名服务器。
例如,如果我很久以来第一次 dig douban.com,就会得到类似这样的输出:
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
|
$ dig douban.com
; <<>> DiG 9.8.3-P1 <<>> douban.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49795
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 10
;; QUESTION SECTION:
;douban.com. IN A
;; ANSWER SECTION:
douban.com. 35 IN A 211.147.4.31
;; AUTHORITY SECTION:
douban.com. 518 IN NS ns3.dnsv4.com.
douban.com. 518 IN NS ns4.dnsv4.com.
;; ADDITIONAL SECTION:
ns3.dnsv4.com. 134679 IN A 221.204.186.6
ns3.dnsv4.com. 134679 IN A 115.236.151.140
ns4.dnsv4.com. 134679 IN A 183.60.57.149
ns4.dnsv4.com. 134679 IN A 183.60.58.173
;; Query time: 19 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Mon Aug 4 10:33:08 2014
;; MSG SIZE rcvd: 246
|
这段输出比较长,我们重点看15-17行,即 AUTHORITY SECTION 部分,由于我们长久以来第一次 dig douban.com,因此就近的域名服务器还没有 192.168.1.1 还没有缓存 douban.com 的 A记录,因此它会解析到 douban.com 的权威域名服务器,再返回给我们结果,这个结果是最新的,是“权威”的。
我们回头在看13行A记录的第二部分 ttl,即缓存失效时间,值是35,表示该缓存35秒后失效,换言之,35秒内我们再请求 douban.com 的话,192.168.1.1 会直接返回缓存的A记录:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
$ dig douban.com
; <<>> DiG 9.8.3-P1 <<>> douban.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4656
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;douban.com. IN A
;; ANSWER SECTION:
douban.com. 31 IN A 211.147.4.31
;; Query time: 1 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Mon Aug 4 10:41:36 2014
;; MSG SIZE rcvd: 44
|
这时就没有 AUTHORITY SECTION 了,说明结果来自缓存域名服务器,而不是权威域名服务器。
如果权威域名服务器改变了A记录信息,而缓存服务器还没有过期,我们怎么去主动了解最新的A记录呢?或者说,怎么主动去权威服务器查找A记录信息呢?简单,解析的时候指定域名服务器即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
$ dig @ns3.dnsv4.com douban.com
; <<>> DiG 9.8.3-P1 <<>> @ns3.dnsv4.com douban.com
; (5 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63971
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 0
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;douban.com. IN A
;; ANSWER SECTION:
douban.com. 10 IN A 211.147.4.31
;; AUTHORITY SECTION:
douban.com. 600 IN NS ns4.dnsv4.com.
douban.com. 600 IN NS ns3.dnsv4.com.
;; Query time: 10 msec
;; SERVER: 180.153.10.166#53(180.153.10.166)
;; WHEN: Mon Aug 4 10:43:29 2014
;; MSG SIZE rcvd: 98
|
缓存机制能够减轻域名服务器尤其是根域名服务器和定级域名服务器的压力,让域名解析过程更快,当然和所有缓存一样,副作用也是有的,当权威服务器修改域名信息的时候,缓存服务器的信息就过时了,要等TTL失效后才能解析到最新正确的信息。