前段时间theerrorlog.com和我的另一个域名在国内的解析速度开始变慢,后来甚至 到了完全解析不了的状态,而翻墙之后却一点问题都没有;上网一搜发现可能是 Godaddy的name server被墙了,于是找了个月黑风高的夜里把域名全都转移到 DNSPod去解析。效果么?和原来的速度比起来,简直快得丧心病狂啊……

转移教程到处都有而且操作很简单,问题是name server是个神马?为什么会对域名 解析有这么大影响?我也不知道,于是找来RFCmanpage还有奇怪小网 页若干,研究了一遍。

DNS简介

DNS的全称是Domain Name System,有时候也会被解释为 Domain Name Server;这里我们只用第一种含义,第二种含义其实和 “Name Server”是一个意思。

从最高的抽象级别来介绍DNS的话,只用一句话就够了:DNS是一个分布式键-值对数 据库。没错就是RedisRiak那类东西,只不过DNS拥有无与伦比的冗余 性和世界级的分布。

不过光这样说的话是略坑爹啦,所以我们从这个抽象往下走一层,看看这个系统里 的两个要素:数据结构和算法。

DNS处理的数据

DNS包括两种数据:名字(“name”)和名字所映射的资源(“resource”)。这里的 “名字”就是我们平常说的域名,但是“资源”却不一定是IP. DNS的常用资源类型有 这些:

  • A: 主机地址,一般就是主机的IP
  • NS: 负责解析域名的Name Server,必须是域名
  • CNAME: 别名指向的另一个域名
  • MX: 邮件服务器的域名
  • TXT: 任意字符串

可见资源的内容可以是IP、域名甚至任意字符串。而名字到资源的映射被RFC定义 为一对多的关系,也就是说一个域名可以用来指向4个IP、5个name server、6个 邮件服务器,等等。

DNS数据的存储和查找

既然是数据库,首要任务自然就是存储和查找数据了。

和许多分布式数据库一样,DNS根据键值——也就是域名——来决定数据的存储位置。 鉴于这是个动态的过程,我们也用DNS调试神器nslookup动态一把好了。

首先运行nslookup命令,进入debug模式,并禁止递归解析:

1
2
3
4
$ nslookup
> set debug
> set norecursive
> _

假设我想知道blog.theerrorlog.com对应的IP地址,于是我向系统的默认 name server(通常就称为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
> blog.theerrorlog.com
Server:     192.168.2.1
Address:    192.168.2.1#53

------------
    QUESTIONS:
    blog.theerrorlog.com, type = A, class = IN
    ANSWERS:
    AUTHORITY RECORDS:
    ->  com
    nameserver = g.gtld-servers.net.
    ttl = 6034
    ->  com
    nameserver = h.gtld-servers.net.
    ttl = 6034
    ->  com
    nameserver = i.gtld-servers.net.
    ttl = 6034
    ->  com

    ....这里省去record若干....

    ADDITIONAL RECORDS:
    ->  g.gtld-servers.net
    internet address = 192.42.93.30
    ttl = 6034
    ->  h.gtld-servers.net
    internet address = 192.54.112.30
    ttl = 6034
    ->  i.gtld-servers.net
    internet address = 192.43.172.30
    ttl = 6034

    ....这里又省去record若干....

------------
Non-authoritative answer:
*** Can't find blog.theerrorlog.com: No answer
> _

nslookup的输出标注了当前使用的name server是192.168.2.1,这是我 的TP-LINK路由器的地址,它会把发给它的DNS查询直接forward给电信的 name server——别问我怎么知道的——所以这里相当于是直接在问电信的 server这个域名的地址在哪里。

结果电信那边给的回复是——他们不知道,因为这个域名不是由他们管理 的,但是可以去问AUTHORITY RECORDS里面那些服务器,因为那些服务器 是负责管理.com域名的。

ADDITIONAL RECORDS那边还很贴心地附带了.com name server的IP地址, 既然有人说它们有线索,我们就直接向这些IP继续发请求看看吧:

 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
> server 192.42.93.30
Default server: 192.42.93.30
Address: 192.42.93.30#53
> blog.theerrorlog.com
Server:     192.42.93.30
Address:    192.42.93.30#53

------------
    QUESTIONS:
    blog.theerrorlog.com, type = A, class = IN
    ANSWERS:
    AUTHORITY RECORDS:
    ->  theerrorlog.com
    nameserver = f1g1ns1.dnspod.net.
    ttl = 172800
    ->  theerrorlog.com
    nameserver = f1g1ns2.dnspod.net.
    ttl = 172800
    ADDITIONAL RECORDS:
    ->  f1g1ns1.dnspod.net
    internet address = 119.167.195.3
    ttl = 172800
    ->  f1g1ns1.dnspod.net
    internet address = 122.225.217.192
    ttl = 172800
    ->  f1g1ns2.dnspod.net
    internet address = 112.90.143.29
    ttl = 172800
    ->  f1g1ns2.dnspod.net
    internet address = 122.225.217.191
    ttl = 172800

    ....这里也省去record若干....

------------
Non-authoritative answer:
*** Can't find blog.theerrorlog.com: No answer
> _

很可惜这台服务器回复说虽然它是管.com的,但是下一级的theerrorlog.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
> server 119.167.195.3
Default server: 119.167.195.3
Address: 119.167.195.3#53
> blog.theerrorlog.com
Server:     119.167.195.3
Address:    119.167.195.3#53

------------
    QUESTIONS:
    blog.theerrorlog.com, type = A, class = IN
    ANSWERS:
    ->  blog.theerrorlog.com
    canonical name = l04m33.github.io.
    ttl = 10
    AUTHORITY RECORDS:
    ->  theerrorlog.com
    nameserver = f1g1ns1.dnspod.net.
    ttl = 600
    ->  theerrorlog.com
    nameserver = f1g1ns2.dnspod.net.
    ttl = 600
    ADDITIONAL RECORDS:
------------
blog.theerrorlog.com    canonical name = l04m33.github.io.
> _

呕耶~终于有人肯告诉我们了泪流满面啊……只不过这里的答案是说, blog.theerrorlog.com只有CNAME记录,指向l04m33.github.io. 虽然还没 找到IP但是就此打住吧,因为接下去的过程其实大同小异,就是到处去找 负责域名管理的name server问问看。

现实世界的DNS存储和查找

上面介绍的查找过程基本上八九不离十啦,不过细心的同学应该有留意到, 我们在一开始用set norecursive将递归解析禁用掉了,这是为什么呢? 你可以试试set recursive再向电信(或者其他ISP)的name server查一 下域名,会发现马上就能得到结果;如果你打开Wireshark抓一下包,也只 能看见一个查询包和一个回复包。

这说明在递归解析模式下,ISP的name server帮你把上面我们用nslookup 手动做的许多次查询都做掉了,然后直接给了你结果。

实际上,网上的name server可以分为两种:一种是负责具体域名信息存储 的,只解析自己负责管理的域名信息,此外的信息一概回答“不知道”, DNSPod和Godaddy提供的name server就属于这种,其上存储的是域名信息 的“真身”,所以被称为“权威服务器”(Authoritative Servers);另一种是 负责查询和缓存域名信息的,通常这种name server并不参与域名信息管理, 当有客户端过来查询的时候——不管查的是什么域名——如果它们的缓存里有 未过期的对应信息,就会马上返回,反之如果没有,则会向其他权威服务器 查询,直到找到或者确认找不到为止,像OpenDNS、Google的8.8.8.8,还有 各大ISP自己提供的name server,都属于这种类型,它们会进行递归解析, 所以被称为“递归服务器”(Recursive Servers)。

通常管理一个域名的权威服务器会有不止一台,它们之间会互相同步并且 互为备份,再加上各种离线备份和分布在世界各地的递归服务器上的缓存, DNS应该是冗余度最高的分布式系统之一了吧,除了世界末日应该没有什么 自然灾害能完全摧毁这货了;但是DNS系统内成千上万台机器都在默默地同 步其他机器,这也导致在其自身内部出现的错误会很快被扩散开来……果然 无论多牛逼的家伙,最大的敌人都是自己呀XD.