简介
Domain Name System(域名系统),简称DNS,在域名和ip地址之间建立映射关系,让网民通过简单好记的域名即可访问互联网。
域名
域名是一串用点分隔的字符。点把域名分成若干个部分,从右往左分别是 根域名、顶级域名、子域名等。
- 根域名:根域名在书写时通常会省略,大部分人甚至不知道它的存在。比如本博客的域名“blog.oonne.com”,实际真正的域名是“blog.oonne.com.”,最后一个点就是留给根域名.root的。只需要了解这个概念即可,更容易理解为什么CNAME记录中,一定要以点结尾才是一个合法的域名。
- 顶级域名:比如“.com”就是顶级域名。ICANN负责管理顶级域名,分给若干个托管商去管理,最常用的是Verisign公司托管的.com。
- 子域名:顶级域名可以再细分为多级子域名。如本博客的二级域名是“oonne”,三级域名是“blog”。
以上几部分组成了完整的域名。域名里的英文字母不区分大小写,每一级域名长度限制63个字符,总长度不能超过253个字符。后来出现的中文域名之类,也只是把Unicode字符串映射为有效的DNS字符集,本质上是一样的。
DNS记录
DNS是一个映射数据库,有不同的记录类型。常见的有:
- A记录:返回对应IPv4主机地址;
- AAAA记录:返回对应IPv6主机地址;
- CNAME记录:返回另一个域名;
- MX记录:返回电子邮件服务器地址;
- NS记录:返回该域名由哪个DNS服务器来进行解析。
DNS记录类型多达几十种,提供各种各样的功能。
每条DNS记录,除了存有记录类型、主机记录(对应的域名)、记录值(返回的内容),还有一个记录的有效时间TTL(Time To
Live)。DNS服务器会根据TTL缓存查询到的记录,这样下次再访问的时候,只要缓存没有过期,就直接返回,节省了大量查询的时间。TTL设得大,能提高缓存命中率;设置得小,则修改记录时能更快生效。
域名解析过程
负责查找DNS记录的服务器,即DNS服务器(Domain Name Server)。客户端想上网,必须得先指定一个DNS服务器,每次需要查DNS记录的时候,就去找这台DNS服务器。
从客户端出发,浏览器、客户端操作系统、路由器、DNS服务器等节点,都会对DNS的查询记录进行缓存,一旦命中缓存,直接返回结果。此处只讨论没有命中缓存时,DNS服务器如何完成解析的过程。
储存DNS记录的服务器,被称为“权威域名服务器”。DNS是一个分布式的映射数据库,记录储存在不同的权威域名服务器中,想查找记录,首先得找到权威域名服务器。每一级域名都至少有一条NS记录,指向该级域名的权威域名服务器,储存在上一级域名的权威域名服务器中。DNS服务器从根域名服务器开始查,依次查询每级域名的NS记录,最终找到记录有这个域名DNS记录的权威域名服务器。
举个例子,DNS服务器收到本博客域名blog.oonne.com,解析过程如下:
- 找“根域名服务器”(.root),查询“顶级域名服务器”(.com),根域名服务器返回了.com的NS记录,记录了.com权威域名服务器的IP;
- 找“顶级域名服务器”(com),查询“次级域名服务器”(.oonne.com),顶级域名服务器返回了.oonne.com的NS记录,记录了oonne.com权威域名服务器的IP;
- 找“次级域名服务器”(oonne.com),查询主机名(blog.oonne.com),次级域名服务器里存有blog.oonne.com的A记录,直接返回blog.oonne.com的IP地址。至此拿到结果,查询结束。
整个过程由根域名服务器处开始查询。根域名服务器的IP地址很少变化,一般内置在DNS服务器里面,不需要查。早期的DNS受限于UDP数据包512字节的大小限制,只能容纳最多13个服务器地址,因此就规定全世界有13个根域名服务器,由12个组织独立运营。但其实,为了保证根域名服务器的可用性,每个服务器都会部署很多节点,所以根域名服务器不止13台。可以在这个网站查到根域名服务器的信息: https://root-servers.org
分级查询的实现,又分为递归查询和迭代查询,如下图所示。
为什么又使用TCP又使用UDP
DNS会同时占用UDP和TCP的53端口,这种“我全都要”的协议也算是一朵奇葩了。
在绝大多数情况下,DNS使用UDP通信,因为UDP速度快很多。设想一下,用TCP去请求DNS服务器,前后需要三次握手连接、请求和响应、四次挥手断开,共计9个数据包;而用UDP请求只需请求和响应两个数据包,延迟比TCP少了许多。而且UDP协议头内容少,数据包的大小也有优势,传输更快。因此DNS协议设计之初,就推荐优先使用UDP。
不过UDP的数据包有512字节的大小限制,当DNS记录超过512字节时,会被截断。(虽然EDNS机制允许UDP最多传输4096字节,但UDP本身就是不可靠的)。此时根据DNS协议,就会使用TCP进行重试。随着IPv6引入和DNS越来越多的新功能,DNS响应越来越大,TCP三次握手和协议头带来的额外开销就不再那么明显了,反而是可靠传输的优势逐渐体现了出来。
DNS还有一种AXFR类型的特殊查询,叫区传送(zone transfer),用于主域名服务器转移整个区域文件至二级域名服务器。由于数据量大,使用TCP来传输。
DNS劫持
DNS劫持,就是用户DNS解析的时候,返回一个错误的ip,以此骗用户去访问钓鱼网站。
上文提到域名的解析过程,解析的结果要么来源于缓存,要么来源于权威域名服务器。对应的DNS劫持的方式也有两种。一种是污染缓存内容,比如返回给路由器或DNS服务器错误的查询结果,又比如有些病毒直接改host文件,等等。另一种方式则更加过分,入侵权威域名服务器,篡改DNS记录。2010年发生的“史无前例”的百度被黑事件,就是百度域名在美国的注册商,被非法篡改了DNS记录,导致中国网友访问百度都跳转到伊朗网军网站。
防范DNS的思路有以下几种:
- HTTPDNS。使用https协议来请求DNS记录,替代原有的TCP和UDP。不仅需要DNS服务器支持,也需要客户端的支持。iOS和Android都有成熟的集成方案,Chrome浏览器也在83以后的版本中内置了 DoH(DNS over https)。
- 客户端校验。比如很多杀毒软件都会扫描hosts文件防止被恶意修改,访问网银等重要网站会校验一下DNS响应,防止被劫持。
- 给网站设置HSTS。
总结
- DNS是互联网中最重要的协议之一。不仅让我们访问互联网更方便,也是许多技术的基础:
- CDN(Content Delivery Network)通过接管DNS,来实现内容分发网络,提高网络资源访问速度;
- SMTP协议用来校验发件人的 SPF(Sender Policy Framework)和 DKIM(DomainKeys Identified Mail)协议都是基于DNS。可以参考我另一篇博客《电子邮件基础》;
- GFW(中国国家防火墙)通过返回错误的DNS结果,来阻止墙内网民访问一些外国网站。(因此只修改host文件,不用翻墙就能访问到维基百科);
- DNS也常用于校验域名的所有权。
学习DNS原理,不管是开发还是平时上网,都有许多帮助。
参考文献
- https://tools.ietf.org/html/rfc1034
- https://tools.ietf.org/html/rfc1035
本文未经许可禁止转载,如需转载关注微信公众号【工程师加一】并留言。