0%

DNS 原理解析

DNS 是一个分布式的树状命名系统,它就像一个去中心化的分布式数据库,存储着从域名到 IP 地址的映射,本文将介绍 DNS 的原理和常见问题。

工作原理

作为用户访问互联网的第一站,当一台主机想要通过域名访问某个服务的内容时,需要先通过当前域名获取对应的 IP 地址。这时就需要通过一个 DNS 解析器负责域名的解析,下面的图片展示了 DNS 查询的执行过程:

  1. 本地的 DNS 客户端向 DNS 解析器发出解析 houmin.cc 域名的请求;
  2. DNS 解析器首先会向就近的根 DNS 服务器 . 请求顶级域名 DNS 服务的地址;
  3. 拿到顶级域名 DNS 服务 cc. 的地址之后会向顶级域名服务请求负责 houmin.cc. 域名解析的命名服务;
  4. 得到授权的 DNS 命名服务时,就可以根据请求的具体的主机记录直接向该服务请求域名对应的 IP 地址;

DNS 客户端接受到 IP 地址之后,整个 DNS 解析的过程就结束了,客户端接下来就会通过当前的 IP 地址直接向服务器发送请求。

对于 DNS 解析器,有两种常见的查询方式,这里使用的是迭代查询:

  • 迭代查询
    • 每个 DNS 服务并不会直接返回 DNS 信息,而是会返回另一台 DNS 服务器的位置
    • 由客户端依次询问不同级别的 DNS 服务直到查询得到了预期的结果
  • 递归查询
    • DNS 服务器收到客户端的请求之后会直接返回准确的结果
    • 如果当前服务器没有存储 DNS 信息,就会访问其他的服务器并将结果返回给客户端

域名层级

域名层级是一个层级的树形结构,树的最顶层是根域名,一般使用 . 来表示,以ru.wikipedia.org为例,org为顶级域名,wikipedia为二级域名,ru为三级域名,域名树状组织结构如下图所示。一般 ru.wikipedia.org 省略了最后的.,也就是全称域名(FQDN)ru.wikipedia.org.

根域名下面的就是 comnetorg 等顶级域名以及次级域名 wikipedia.org.,我们一般在各个域名网站中购买和使用的都是次级域名、子域名和主机名了。

域名服务器

既然域名的命名空间是树形的,那么用于处理域名解析的 DNS 服务器也是树形的,只是在树的组织和每一层的职责上有一些不同。DNS 解析器从根域名服务器查找到顶级域名服务器的 IP 地址,又从顶级域名服务器查找到权威域名服务器的 IP 地址,最终从权威域名服务器查出了对应服务的 IP 地址。

1
$ dig -t A houmin.cc +trace

我们可以使用 dig 命令追踪 draveness.me 域名对应 IP 地址是如何被解析出来的,首先会向预置的 13 组根域名服务器发出请求获取顶级域名的地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
; <<>> DiG 9.16.1-Ubuntu <<>> -t A houmin.cc +trace
;; global options: +cmd
. 7145 IN NS m.root-servers.net.
. 7145 IN NS b.root-servers.net.
. 7145 IN NS j.root-servers.net.
. 7145 IN NS f.root-servers.net.
. 7145 IN NS i.root-servers.net.
. 7145 IN NS k.root-servers.net.
. 7145 IN NS h.root-servers.net.
. 7145 IN NS g.root-servers.net.
. 7145 IN NS d.root-servers.net.
. 7145 IN NS c.root-servers.net.
. 7145 IN NS e.root-servers.net.
. 7145 IN NS a.root-servers.net.
. 7145 IN NS l.root-servers.net.
;; Received 262 bytes from 127.0.0.53#53(127.0.0.53) in 0 ms

Root DNS Server 是 DNS 中最高级别的域名服务器,这些服务器负责返回 Top Level 地址,这些域名服务器的数量总共有 13 组,域名的格式从上面返回的结果可以看到是 .root-servers.net,每个根域名服务器中只存储了顶级域服务器的 IP 地址,大小其实也只有 2MB 左右,虽然域名服务器总共只有 13 组,但是每一组服务器都通过提供了镜像服务,全球大概也有几百台的根域名服务器在运行。

在这里,我们获取到了以下的 5 条 NS 记录,也就是 4 台 cc. 定义域名 DNS 服务器:

1
2
3
4
5
6
7
cc.			172800	IN	NS	ac4.nstld.com.
cc. 172800 IN NS ac3.nstld.com.
cc. 172800 IN NS ac2.nstld.com.
cc. 172800 IN NS ac1.nstld.com.
cc. 86400 IN DS 519 8 2 E1EC6495ABD34562E6F433DEE201E6C6A52CB10AF69C04D675DA692D 2D566897
cc. 86400 IN RRSIG DS 8 1 86400 20210506050000 20210423040000 14631 . ESeh7IZ4jrvh2cnpHEYdaVlkvhGi+Kpkr3xiqiPK7qKuLFLswNg83KIz Vl/xxGQRCLqIDDMaKSBwPmoxHzVtHe2w2DcwTLuJuUuEnuE0KVuA5E0+ krYheT0D8aQRDi+JbQ5LclZARulNftuLkWMB7f4zdkKV5YAF+CmsjPpO 6oV42IDXx4p+TVh5xoeBBMeoG8u6TxlSplp/xbQ0c2/mD+oVrbmC04vG mIYs9rE18o121ooJTo7pd+qb+guQE/fTQNHxYkmRjJag3bglO+3LBJdN h5G/Oz+9zU9BS2qFXwWirH1E6zOMCftj1lGqqh/jxBMUSktT0knUN1LH ABoqNQ==
;; Received 658 bytes from 192.5.5.241#53(f.root-servers.net) in 40 ms

当 DNS 解析器从根域名服务器中查询到了顶级域名 .cc 服务器的地址之后,就可以访问这些顶级域名服务器其中的一台 ac2.nstld.com 获取权威 DNS 的服务器的地址了:

1
2
3
4
5
6
7
houmin.cc.		172800	IN	NS	dns7.hichina.com.
houmin.cc. 172800 IN NS dns8.hichina.com.
RQGAP5UF6Q1NGVCKFNO8RANVDN5ILRIN.cc. 86400 IN NSEC3 1 1 0 - RQMIELD94LUROQ2ACBTAUSEKHALC67HE NS SOA RRSIG DNSKEY NSEC3PARAM
RQGAP5UF6Q1NGVCKFNO8RANVDN5ILRIN.cc. 86400 IN RRSIG NSEC3 8 2 86400 20210427182007 20210420182007 2625 cc. Gwou8BWmUgOEigHtx/TkuYzWC9qhMVDHb9VeMvII8D4dhv3Z5hoCGHJK RmH89wWhNBut0AbzugizWT8n+cCI7zqj+w/DObSbyoVjrgAMj3+oej9c 8TOETSltsCkWd/Z6Deo0oEPxoSNDh/+z6mztsgClQ7HucKTTJpzIWm7+ aCPaRwW6NiUpDRSLHlo0xVKQuZ0BnB19GKG3EhNQpgwdjw==
6PBL23LFGLBH4BT5UF4255C75BB21CBQ.cc. 86400 IN NSEC3 1 1 0 - 6PV8MOF7637RU868SN9RQDAI02TT9D12 NS DS RRSIG
6PBL23LFGLBH4BT5UF4255C75BB21CBQ.cc. 86400 IN RRSIG NSEC3 8 2 86400 20210429192006 20210422192006 2625 cc. pFEXMVlEK5f5urD3IpiZFGfGaNz4NaZIORuM554peVCwS3PQEJ++HpGy 20nmVgPYOTI2VINID+dteIFyMnBlc5249Hp7bYj9eik6vJwdHr0J5uU7 qGPxmTD2z4l992yqKFNXvwhCa9orey9alZxpAxeaLqj2hydF9A1PD7xH ot+qpLqIebxfHrY4mrz2xUfeUR71/ELE9d94iu+apNidYQ==
;; Received 634 bytes from 192.42.174.30#53(ac2.nstld.com) in 240 ms

这里的权威 DNS 服务是作者在域名提供商进行配置的,当有客户端请求 houmin.cc 域名对应的 IP 地址时,其实会从作者使用的 DNS 服务商 DNSPod 处请求服务的 IP 地址:

1
2
houmin.cc.		600	IN	CNAME	simpcosm.github.io.
;; Received 70 bytes from 140.205.41.14#53(dns8.hichina.com) in 32 ms

最终,DNS 解析器从 dns8.hichina.com 服务中获取了当前博客的 IP 地址 140.205.41.14,浏览器或者其他设备就能够通过 IP 向服务器获取请求的内容了。

从整个解析过程,我们可以看出 DNS 域名服务器大体分成三类,根域名服务、顶级域名服务以及权威域名服务三种,获取域名对应的 IP 地址时,也会像遍历一棵树一样按照从顶层到底层的顺序依次请求不同的服务器。

127.0.0.53

在前面的命令中,我们看到最初访问根域名服务器来自于 127.0.0.53:53 的响应,我们知道,所有的127.x.x.x地址都指向本地机器,并且绑定在lo设备上。那么,是什么服务监听在这个地址呢?

1
2
3
ubuntu@VM-1-5-ubuntu:~$ sudo netstat -apn | grep 53
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 625/systemd-resolve
udp 0 0 127.0.0.53:53 0.0.0.0:* 625/systemd-resolve

可以看到,是 systemd-resolve 作为本机的 DNS Server,查看 /etc/resolve.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ubuntu@VM-1-5-ubuntu:/etc$ cat resolv.conf
# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients to the
# internal DNS stub resolver of systemd-resolved. This file lists all
# configured search domains.
#
# Run "resolvectl status" to see details about the uplink DNS servers
# currently in use.
#
# Third party programs must not access this file directly, but only through the
# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,
# replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.

nameserver 127.0.0.53
options edns0

我们已经在 /etc/resolv.conf 中看到,这个文件并不是手动维护的,也不应该直接修改,而是由systemd服务systemd-resolved来负责维护管理的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ubuntu@VM-1-5-ubuntu:/etc$ systemctl status systemd-resolved.service
● systemd-resolved.service - Network Name Resolution
Loaded: loaded (/lib/systemd/system/systemd-resolved.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2021-04-22 17:29:46 CST; 1 day 17h ago
Docs: man:systemd-resolved.service(8)
https://www.freedesktop.org/wiki/Software/systemd/resolved
https://www.freedesktop.org/wiki/Software/systemd/writing-network-configuration-managers
https://www.freedesktop.org/wiki/Software/systemd/writing-resolver-clients
Main PID: 625 (systemd-resolve)
Status: "Processing requests..."
Tasks: 1 (limit: 9830)
Memory: 9.1M
CGroup: /system.slice/systemd-resolved.service
└─625 /lib/systemd/systemd-resolved

Warning: journal has been rotated since unit was started, output may be incomplete.

可见,当前本机的DNS Server是systemd-resolve,并且后者是一个DNS stub,那么真正的 DNS 服务IP是多少呢?我们可以使用如下的命令查看:

1
2
ubuntu@VM-1-5-ubuntu:/etc$ systemd-resolve --status | grep "DNS Servers"
DNS Servers: 183.60.82.98

胶水记录

假设我们访问 houmin.site,在通过服务器解析域名的过程中,我们看到当请求 site. 顶级域名服务器的时候,其实返回了 e.nic.site. 等域名:

1
2
3
4
5
site.			172800	IN	NS	b.nic.site.
site. 172800 IN NS a.nic.site.
site. 172800 IN NS f.nic.site.
site. 172800 IN NS e.nic.site.
...

就像我们最开始说的,在互联网中想要请求服务,最终一定需要获取 IP 提供服务的服务器的 IP 地址;同理,作为 e.nic.site. 作为一个 DNS 服务器,我也必须获取它的 IP 地址才能获得次级域名的 DNS 信息,但是这里就陷入了一种循环:

  1. 如果想要获取 houmin.site 的 IP 地址,就需要访问 me 顶级域名服务器 e.nic.site
  2. 如果想要获取 e.nic.site 的 IP 地址,就需要访问 me 顶级域名服务器 e.nic.site
  3. 如果想要获取 e.nic.site 的 IP 地址,就需要访问 me 顶级域名服务器 e.nic.site

为了解决这一个问题,我们引入了胶水记录(Glue Record)这一概念,也就是在出现循环依赖时,直接在上一级作用域返回 DNS 服务器的 IP 地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ dig +trace +additional draveness.me

...

site. 172800 IN NS a.nic.site.
site. 172800 IN NS b.nic.site.
site. 172800 IN NS e.nic.site.
site. 172800 IN NS f.nic.site.
site. 86400 IN DS 51676 8 1 90DDBEEEB973B0F8719ED763FB6EEDE97C73ABF5
site. 86400 IN DS 51676 8 2 883175F6F5C68EA81563B62D1B2B79B6A997D60DC6E20CC70AFD0CD6 B7E82F62
site. 86400 IN RRSIG DS 8 1 86400 20210506210000 20210423200000 14631 . ojvp5W0YvB8IPhZ3f3z95bWkhfcu1UgDFgG70p6VuLw2U0uMVfv96dNM RFUase6U307nB2pY/uvFbWQd+/f2o2AVM8CU3e5V9lLlIWdqzXBKXYsd ffjGB33ODczxi+W5Jd5qUzXI1IVrV6+KxKIHW7Pu283xAW5sMyztNJ/J oqkHBYMCSJ26dEJy/0Mujv5NjC5qvnM+hhr8EiyQzt2k+fNIAzmmSzC1 dDtky+3o4BsSO8hEcd5vXLKHd9H7K3d+bDB3jPR0jF2TnhAFEztnOAeW 890gybMD3iZlLamyzMWXu/y64jmcTkG5VKHbUmjBH71aXfQI/Oz6ex20 eA9Yaw==
a.nic.site. 172800 IN A 194.169.218.61
a.nic.site. 172800 IN AAAA 2001:67c:13cc::1:61
b.nic.site. 172800 IN A 185.24.64.61
b.nic.site. 172800 IN AAAA 2a04:2b00:13cc::1:61
e.nic.site. 172800 IN A 212.18.248.61
e.nic.site. 172800 IN AAAA 2a04:2b00:13ee::61
f.nic.site. 172800 IN A 212.18.249.61
f.nic.site. 172800 IN AAAA 2a04:2b00:13ff::61
;; Received 655 bytes from 193.0.14.129#53(k.root-servers.net) in 44 ms

...

也就是同时返回 NS 记录和 A(或 AAAA) 记录,这样就能够解决域名解析出现的循环依赖问题。

域名记录

  • A记录: 将域名指向一个IPv4地址(例如:100.100.100.100),需要增加A记录
  • CNAME记录: 如果将域名指向一个域名,实现与被指向域名相同的访问效果,需要增加CNAME记录。这个域名一般是主机服务商提供的一个域名
  • MX记录: 建立电子邮箱服务,将指向邮件服务器地址,需要设置MX记录。建立邮箱时,一般会根据邮箱服务商提供的MX记录填写此记录
  • NS记录: 域名解析服务器记录,如果要将子域名指定某个域名服务器来解析,需要设置NS记录
  • TXT记录: 可任意填写,可为空。一般做一些验证记录时会使用此项,如:做SPF(反垃圾邮件)记录
  • AAAA记录: 将主机名(或域名)指向一个IPv6地址(例如:ff03:0:0:0:0:0:0:c1),需要添加AAAA记录
  • SRV记录: 添加服务记录服务器服务记录时会添加此项,SRV记录了哪台计算机提供了哪个服务。格式为:服务的名字.协议的类型(例如:_example-server._tcp)。
  • SOA记录: SOA叫做起始授权机构记录,NS用于标识多台域名解析服务器,SOA记录用于在众多NS记录中那一台是主服务器
  • PTR记录: PTR记录是A记录的逆向记录,又称做IP反查记录或指针记录,负责将IP反向解析为域名
  • 显性URL转发记录: 将域名指向一个http(s)协议地址,访问域名时,自动跳转至目标地址。
  • 隐性UR转发记录L: 将域名指向一个http(s)协议地址,访问域名时,自动跳转至目标地址,隐性转发会隐藏真实的目标地址。

参考资料