Linux系统下搭建DNS服务器——DNS原理总结

740 阅读19分钟
原文链接: zhuanlan.zhihu.com

正文

2017-01-07 整理

  • DNS原理
  • 域名到IP地址的解析过程
  • IP地址到域名的反向域名解析过程
  • 抓包分析DNS报文和具体解析过程
  • DNS服务器搭建和配置

这个东东也是今年博主参见校招的时候被很多公司问过的,虽然理论性比较强,但是作为一个程序员,个人认为熟悉DNS是非常重要的,要理解它并能帮助解决一些实际问题。

面试实录

  • 打开一个URL,在网络层面都发生了哪些事情?(当中说到了DNS原理,这个是绕不过的)
  • 用过 Linux 么?你用它平时都做什么事情啊?(首先是在该环境下写代码,搭建过一些集群,当然还有一些服务器的搭建,比如本文内容)
  • DNS 是基于 TCP 还是 UDP 的?端口号是多少?
  • 具体忘了,说到了负载均衡的请求分发(聊了DNS的分发功能)
  • 什么是DNS劫持?

虽然当时回答了,但是还是感觉得系统总结下,备忘。

DNS原理和理解

DNS的本质是什么?

Domain Name System = DNS(域名系统)其实是一个数据库,是用于 TCP/IP 程序的分布式数据库,同时也是一种重要的网络协议。DNS储存了网络中的 IP 地址与对应主机的信息,邮件路由信息和其他网络应用方面的信息,用户通过询问解决库(解决库发送询问并对DNS回应进行说明)在 DNS 上查询信息。

DNS的作用是什么?

DNS是网络分层里的应用层协议,事实上他是为其他应用层协议工作的,简单说就是把域名,或者说主机名转化为IP地址(同时也提供反向域名查询的功能),类似字典,比如访问 www.baidu.com,实际访问的是它的IP地址,因为机器识别的是拥有固定格式和含义的IP地址,而域名可以千奇百怪,甚至是中文,不利于识别。还有比如公司内部的域验证,通过分配给员工的域账号登录内网就必须通过DNS来找到域名权限服务器,来认证身份,故有些书上说:DNS是因特网世界里不可缺少的东西。

比如,使用host命令进行DNS查询

host命令用来做DNS查询。如果命令参数是域名,命令会输出关联的IP;如果命令参数是IP,命令则输出关联的域名。

为什么叫域名系统,什么是域名?

人和人要互相识别和记忆,需要名字作为辅助,而对于网络世界,在因特网内也需要一种命名系统来做类似的事情,该系统使用了域来划分,任何一个网络里的主机(或者路由器)都有独一无二的域名(类似国家代码),域又能继续划分为子域(类似每个国家有不同的省份代码),子域还能继续划分(每个省都有自己的各个城市的代码)……在因特网内对应的就是顶级域名(com,net,cn,org等),二级域名……注意这仅仅是一种逻辑的划分。而这些域名系统在形式上组成了一种树结构。

名字(也叫标号)组成只能是英文或者数字,目前中文也支持了,长度不大于63个字符,总共完整域名长度不超过255个字符,英文域名不区分大小写,从右到左,域名级别依次降低。www是表示万维网,不属于域名。

域名空间树结构

域名的名字空间是一个树结构,根没有名字,各个树叶是单台计算机名,不能继续划分。

域名服务器

DNS服务器管理范围的单位是区,不是域,因为区才是DNS服务器管理的实际范围,区是域的子集,同一个区里的主机节点必须互通,它们都有一个统一的访问权限,该访问权限在通过一个权限域名服务器管理。比如,公司a,有两个部门x,y,部门x又有两个分部q和r,a会设立一个区叫a.com(区和域可以同名),这是一个大的权限范围,然后下属再设立一个区,叫 x.a.com,那么区 a.comx.a.com都属于域a.com

DNS服务器也是类似域名空间树一样的树结构,依次分为根域名服务器(知道所有的顶级域名服务器的域名和IP,最重要,它要是瘫痪,整个DNS就完蛋),然后是顶级域名服务器(管理二级域名),其次是权限域名服务器(负责区的域名服务器)。

最后是本地域名服务器(也叫默认域名服务器),本地域名服务器离主机很近(书上说不超过几个路由器),速度很快,其实本地域名服务器本质不属于域名服务器架构。

如图就是Linux的本地域名服务器配置

如图是Windows下本地DNS服务器配置

分布式域名系统

因为因特网规模很大,所以整个因特网只使用一个域名服务器是不行的。为了可靠,使用了分布式的域名系统,即使单个计算机除了故障,也不会妨碍整个DNS系统的正常运行。并采用c/s方式。DNS使大多数名字都在本地解析(resolve),仅有少量解析需要在因特网上通信,因此分布式DNS系统借助分布式的主机备份和缓存机制,非常强壮和有足够的性能。

DNS劫持及解决办法

DNS劫持又称域名劫持,说白了就是当用户请求DNS解析的时候,对正常的DNS请求报文进行拦截,偷到请求的域名,然后就可以做手脚,比如常常遇到访问某个健康的网址的时候,明明输入的网址是xxxx.com,结果却跳转到了不可描述的网站……即把审查范围,或者权限范围以外的请求放行,否则返回假的IP地址或者什么都不做使请求失去响应,效果就是让人误以为断网(360网络诊断里经常说的,打的开QQ,但是无法浏览网页的现象),或者得到了假网址,黑客们经常利用漏洞或者程序的缺陷对用户的DNS进行篡改,进行钓鱼网站的欺诈活动。

解决办法可以手动修改本地DNS域名服务器地址,首选DNS服务器:114.114.114.114,是国内第一个、全球第三个开放的DNS服务地址,又称114DNS,或8.8.8.8(google提供的DNS服务器)等,然后修改宽带密码,路由器密码,主机密码。

域名到IP地址的解析过程

当一个应用需要把主机名解析为IP地址时,该应用进程就调用地址解析程序,它自己就变为了DNS的一个客户,把待解析的域名放在DNS请求报文中,以UDP方式先发给本地域名服务器,本地域名服务器在查找域名后,把对应的IP地址放在回答报文中返回,应用程序获得目的主机的IP地址后即可进行通信。若本地域名服务器不能回答该请求,则此域名服务器就暂时称为DNS的另一个客户,并向其他域名服务器发出查询请求。这种过程直至找到能够回答该请求的域名服务器为止。

域名的解析过程

主机向本地域名服务器的查询一般都是采用递归查询

如果主机所询问的本地域名服务器不知道被查询的域名的IP地址,那么本地域名服务器就以DNS客户端的身份(递归思想),向根域名服务器继续发出查询报文(替主机查询),不让主机自己进行查询。递归查询返回的结果或者是IP,或者报错。这是从上到下的递归查询过程。

本地域名服务器向根域名服务器查询一般采用迭代查询

当根域名服务器收到本地域名服务器的查询请求,要么给出ip,要么通知本地域名服务器下一步应该去请求哪一个顶级域名服务器查询(并告知本地域名服务器自己知道的顶级域名的IP),让本地域名服务器继续查询,而不是替他查询。同理,顶级域名服务器无法返回IP的时候,也会通知本地域名服务器下一步向谁查询(查询哪一个权限域名服务器)……这是一个迭代过程。

到底采用哪种查询,取决于原始查询报文的设置,不绝对。

DNS缓存

DNS中使用了高速缓存,因为域名到地址的映射不常变,故为提高效率而设,主机在启动时从本地服务器下载名和地址的全部数据,并维护存放自己最近使用的域名的缓存,并且只在从缓存中找不到名字时才使用根域名服务器发起查询。实际中,当一个 DNS 服务器接收到一个 DNS 回答后,会将其信息缓存一段时间,当再有一个对相同域名的查询时,便可直接回复。通过 DNS 缓存,大部分查询都只需要本地 DNS 服务器便可完成解析。

DNS缓存污染

本地域名服务器在接收到DNS请求时,先查找DNS缓存,如果缓存命中直接返回结果,如果黑客攻入路由器,对部分域名的缓存进行了更改,比如将缓存的结果指向不可描述的页面,那么即导致用户的正常请求被转移……,此时可以清除各级缓存(浏览器,系统,路由器,DNS缓存)。貌似无法避免,只能是提高安全意识,即使使用了 HTTPS也不行,因为DNS解析过程发生在HTTPS请求交互前。

FQ方法之——hosts 文件

Hosts是一个没有扩展名的系统文件,作用是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”, 其实 hosts 文件可以看作是一个小型的本地 DNS 服务器。

实际上网时域名的解析过程

优先顺序是:当用户在地址栏输入一个URL之后,浏览器首先查询浏览器的缓存,找不到就去查询Hosts文件和本地DNS缓存,如果hosts和本地DNS缓存都没有找到域名对应的IP,则自动进入路由器的缓存中检查,以上均为客服端DNS缓存,若在客户端DNS缓存还是没找到,则进入ISP DNS缓存中查询,还是找不到,最终才向 根DNS 服务器发出 DNS 查询报文,再找不到就报错……

IP地址到域名的反向域名查询

先了解下DNS报文,稍后会分析

+---------------------+
| 报文头 |
+---------------------+
| 问题  | 向服务器提出的查询记录
+---------------------+
| 回答  | 服务器回复的资源记录
+---------------------+
| 授权 | 权威的资源记录
+---------------------+
| 格外的 | 格外的资源记录
+---------------------+

哎,这个报文格式和名字也是醉了,不过不碍事,当在浏览器内输入URL时,便开始了DNS解析过程,最后会把找到后的IP地址告知浏览器客户端,方便它继续发出 HTTP(s)请求,该过程中,浏览器提出的查询记录类型叫A记录(address)查询,其他查询记录类型常见的有A(地址)记录、CNAME(别名)记录、MX(邮件交换)记录等。

比如问:www.baidu.com的A记录是什么?

是 220.181.110.181

这个A记录意思是从域名解析得到IP地址。那么反过来,从IP地址得到域名的解析过程也需要一个记录,叫PTR记录(和A记录功能相反),可以使用nslookup命令查询,可以通过查询IP地址的PTR记录来得到该IP地址指向的域名,达到反查的目的。

反向域名查询和垃圾邮件过滤

IP反向解析主要应用到邮件服务器中来阻拦垃圾邮件,比如用 xxx@xxx.com 给邮箱 xxxxx@qq.com 发了一封信。qq邮件服务器会查看信头文件,信头文件显示信是由哪个IP地址发出的,然后根据IP地址反向解析,如反向解析到这个IP所对应的域名是xxx.com (不在黑名单)那么就接受,否则拒绝。

了解反向域名-arpa

域名系统中,一个IP地址可对应多个域名,在Internet上是不会去傻傻的遍历整个域名树的。故DNS的顶级域名提供了一个特别的顶级域——arpa 用来做反向域名解析,也称为反向域名。当一个主机加入网络,获得DNS授权,它的IP地址假设为192.168.1.1,它也顺便获得了对应IP地址的 in-addr.arpa (逆向解析域in-addr.arpa)空间的授权,注意DNS名由树底部向上组织,故它的DNS名字为192.168 .1.1.in-addr.arpa。IP地址的第一字节一定位于in-addr的下一级。这样欲解析的IP地址就会被表达成一种像域名一样的形式,后缀以反向解析域名"in-addr.arpa"结尾。

本质上:反向域名解析是将IP地址表达成了一个域名,这样反向解析的很大部分可以纳入正向解析中。

抓包分析具体解析过程

如上是通常情况下的DNS报文,基于UDP数据报封装(同时DNS也支持TCP),并且要知道DNS服务器的默认端口是53

ping一个主机,开始抓包

观察出现的数据包

如图,第一行是DNS查询报文,第二行是DNS回答报文。

先看整个数据包的结构

证实了DNS确实为应用层的协议,目的端口号确实是53,传输层一般情况下采用UDP也是ok的,网络层是IP协议,数据链路层有以太网帧。

查看DNS数据包

对应的抽象报文格式图

+---------------------+
| 报文头 |
+---------------------+
| 问题  | 向服务器提出的查询记录
+---------------------+
| 回答  | 服务器回复的资源记录
+---------------------+
| 授权 | 权威的资源记录
+---------------------+
| 格外的 | 格外的资源记录
+---------------------+

先看查询报文头

首部12字节

标识ID,两个字节,对应DNS查询和DNS响应报文的id,目的是可以辨别DNS应答报文是哪个请求报文的响应,如下是响应报文的ID,两个一样

标志flags(不同于标识)字段又单独划分了

从左到右为:QR,操作代码op,AA,TC,RD,RA,Z,响应代码

QR(query,response)1位,0代表查询,1代表响应

操作代码4位,0代表标准查询,1代表反向查询

AA(authoritative answer)1位,如果响应数据报设定,说明响应是由域内权限域名服务器发出

TC(truncation)1位,1代表报文被截断,如果DNS响应报文超过了512字节,只返回这512个字节,0代表没有截断

RD(recursion desired)1位,递归期望,请求报文设定,在响应报文返回,1代表名字服务器必须递归处理该查询。如

果该位为0,且被请求的名字服务器没有一个授权回答,它就返回一个能解答该查询的其他名字服务器列表,也就是迭代查询。

RA(recurision  available)1位,递归可用,响应报文设定,说明域名服务器支持递归查询

Z代表保留字,3位。必须为0

响应码是4位,类似HTTP响应码
- 无差错
- 格式错误
- 域名服务器出现错误
- 域参照问题
- 查询类型不支持
- 被禁止
~ 15 保留

然后是查询的问题数

Quetions(问题数) ,通常为1。Answer RRs(资源记录数),Authority RRs(授权资源记录数),Additional RRs(额外资源记录数)通常都为0。

以上是12字节的DNS包头

然后是DNS的报文身体部分(问题or回答部分)

+---------------------+
| 报文头 |
+---------------------+
| 问题  | 向服务器提出的查询记录
+---------------------+
| 回答  | 服务器回复的资源记录
+---------------------+
| 授权 | 权威的资源记录
+---------------------+
| 格外的 | 格外的资源记录
+---------------------+

Queries为查询或者响应的正文,如下是请求报文里的问题部分

每个问题对应一个查询类型,响应报文里的资源记录部分里每个响应(资源记录)也对应一个资源类型。PS:资源记录也叫响应,如下

分为 Name Type Class

Name(查询名称):域名 
Type(查询类型):2字节,这里是A记录.
Class类,2字节,IN表示Internet数据,一般为1

大约有20多种查询记录类型,最常用的查询类型是A记录类型,例子里DNS查询报文查询A记录,从域名www.baiodu.com解析到IP地址,PTR记录类型(反向查询IP地址的PTR记录,也叫指针记录),CNAME记录类型等。

其中cname就是别名,一般用在SEO中,可以使得多个域名指向同一个IP地址。

还有NS记录,也就是名字服务器name server

下面看DNS响应报文

大体和查询报文一致,响应包就是多出了一个Answers字段

响应报文的answer字段,第一个是请求的域名,然后cname记录表示出别名为www.a.shifen.com,这个别名的地址看下面具体的回答

Answers字段每项为一个资源记录
除了上面提到过的Name,Type,Class之外,还有Time to Live,Data length,addr

Time to Live(生存时间TTL):表示该资源记录的生命周期,从取出记录到抹掉DNS记录缓存的时间,以秒为单位 

Data length(资源数据长度):以字节为单位

Addr:返回的查询结果 ip地址

DNS使用的网络层协议

DNS同时支持UDP和TCP访问,当名字解析器发出一个查询请求,并且返回响应报文中的TC位设置为1时,名字解析器通常使用TCP重发原来的查询请求,TCP能将用户的数据流分为一些报文段,用多个报文段来传送任意长度的用户数据,即允许返回的响应超过512个字节。

此外,为了减轻单台DNS服务器的负载,有时要将同一DNS区域的内容保存在多个DNS服务器中(主从备份,分布式存储),这时,就要用到DNS的“区域传输”功能。在分布式的DNS数据库中,当一个域的辅助名字服务器在启动时,将从该域的主名字服务器执行区域传送。辅助服务器将定时(通常是3小时)向主服务器进行查询以便了解主服务器数据是否发生变动,如果有变动,为了数据一致性,将执行一次区域传送,区域传送将使用TCP,因为传送的数据远比一个查询或响应多。

故DNS主要使用UDP,TCP为辅,如果是UDP,那么无论是名字解析器还是名字服务器都必须自己处理超时和重传。此外,DNS不像其他的使用UDP的应用一样,大部分操作集中在局域网上,DNS查询和响应通常经过广域网。分组丢失率和往返时间的不确定性在广域网上比局域网上更大。这样对于DNS客户程序,一个好的重传和超时程序就显得更重要。

DNS熟知的端口号

DNS服务器使用的熟知端口号无论对UDP还是TCP都是53

本地私有 DNS 服务器搭建

BIND (Berkeley Internet Name Domain)是DNS协议的一个实现,提供了DNS主要功能的开放实现,包括

  • 域名服务器 (named)
  • DNS 解析库函数
  • DNS 服务器运行调试所用的工具

Bind 是一款开源的 DNS 服务器软件,由美国加州大学 Berkeley 分校开发和维护的,按照 ISC 的调查报告,BIND 是世界上使用最多最广泛的域名服务系统,通过搭建私有的 DNS 服务器,可以把国外的一些不可描述的 ip 地址放到自己的 DNS 服务器中畅快浏览。

安装环境本地ubuntu,客户端和服务器都是使用的一台机器

安装配置BIND

########安装BIND软件
sudo apt-get install bind9 bind9utils bind9-doc

########设置 BIND 为 IPv4 Mode,把 "-4" 添加到 OPTIONS 变量
dashuai@ubuntu:/etc$ sudo vim /etc/default/bind9

########如下
# run resolvconf?
RESOLVCONF=no

# startup options for the server
OPTIONS="-4 -u bind"

########解决只读问题
####1、确认文件属于自己
####2、权限为可读可写
####3、如果还是不行,就sudo vim ……打开即可

配置 DNS 主服务器(最好是设置主备)

########查看本机IP,保证ping通
192.168.124.8

########编辑BIND软件的配置文件 来配置环境
####配置ACL
##添加一个新的 ACL 块,把内网 ip 添加到信任名单,意思是只允许它查询 DNS 服务器 ,提高安全性。

dashuai@ubuntu:/etc/bind$ sudo vim named.conf.options

##如下
acl "trusted" {
    192.168.124.8;  # ns1 只有信任的主机才能查询 DNS 服务器,其他主机不能。
};
        recursion yes;
        allow-recursion {
            trusted;
        };
        listen-on {192.168.124.8};
        allow-transfer {none;};
        
        forwarders {
                114.114.114.114;
        };

##添加解析域
dashuai@ubuntu:/etc/bind$ sudo mkdir zones

####添加正向解析和反向解析文件的位置参数
dashuai@ubuntu:/etc/bind$ sudo vim named.conf.local 

##如下
zone "dashuaiBlog.com" {
    type master;
    file "/etc/bind/zones/db.dashuaiBlog.com";
};

zone "168.192.in-addr.arpa" {
    type master;
    file "/etc/bind/zones/db.192.168";  
};

####在解析域里编写正向解析域文件
dashuai@ubuntu:/etc/bind$ cd zones/
dashuai@ubuntu:/etc/bind/zones$ ls
dashuai@ubuntu:/etc/bind/zones$ touch db.dashuaiBlog.com
touch: cannot touch ‘db.dashuaiBlog.com’: Permission denied
dashuai@ubuntu:/etc/bind/zones$ sudo touch db.dashuaiBlog.com
dashuai@ubuntu:/etc/bind/zones$ ll
total 8
drwxr-sr-x 2 root bind 4096  1月 14 16:50 ./
drwxr-sr-x 3 root bind 4096  1月 14 16:41 ../
-rw-r--r-- 1 root bind    0  1月 14 16:50 db.dashuaiBlog.com
dashuai@ubuntu:/etc/bind/zones$ sudo vim db.dashuaiBlog.com 

##如下
;
; BIND data file for local loopback interface
$TTL    604800
@       IN      SOA     ns1.dashuaiBlog.com. admin.dashuaiBlog.com. (
      ; Serial
    ; Refresh
    ; Retry
    ; Expire
)   ; Negative Cache TTL
;
;
; name servers - NS records
     IN      NS      ns1.dashuaiBlog.com.
; name servers - A records
ns1.dashuaiBlog.com.          IN      A       192.168.124.8     

host1.dashuaiBlog.com.        IN      A      192.168.124.8

####编写反向解析域文件
dashuai@ubuntu:/etc/bind/zones$ sudo vim db.192.168  

##如下
$TTL    604800
@       IN      SOA     dashuaiBlog.com. admin.dashuaiBlog.com. (
        ; Serial
        ; Refresh
        ; Retry
        ; Expire
)       ; Negative Cache TTL
; name servers
      IN      NS      ns1.dashuaiBlog.com.

; PTR Records
2.42   IN      PTR     ns1.dashuaiBlog.com.    ; 192.168.124.8
1.42   IN      PTR     host1.dashuaiBlog.com.  ; 192.168.124.8

服务器环境测试

########检验 BIND  配置文件有没有语法错误
dashuai@ubuntu:/etc/bind/zones$ sudo named-checkconf
dashuai@ubuntu:/etc/bind/zones$ 

########查看正向解析和反向解析文件编写语法是否正确。
dashuai@ubuntu:/etc/bind/zones$ sudo named-checkzone dashuaiBlog.com db.dashuaiBlog.com
zone dashuaiBlog.com/IN: loaded serial 3
OK
dashuai@ubuntu:/etc/bind/zones$ sudo named-checkzone 168.192.in-addr.arpa db.192.168
zone 168.192.in-addr.arpa/IN: loaded serial 3
OK

重启 BIND

dashuai@ubuntu:/etc/bind/zones$ sudo service bind9 restart
 * Stopping domain name service... bind9
waiting for pid 4106 to die
   ...done.
 * Starting domain name service... bind9
   ...done.

配置 DNS 客户端

找一台机器作为DNS客户端,将客户端的 DNS 修改为刚刚搭建的DNS服务器的 ip 地址

########这是修改的本地DNS配置的真实文件
sudo vim /etc/resolvconf/resolv.conf.d/head
####如下
nameserver 192.168.124.8

########修改本地DNS配置文件的link
sudo vim /etc/resolv.conf
####如下
options timeout:1 attempts:1 rotate
nameserver  192.168.124.8

########运行 resolvconf 更新
sudo resolvconf -u

使用nslookup验证

使用nslookup来查询服务器(若使用其他的客户端, ip 地址 需要加入到 "trusted" ACL 里面)。

dashuai@ubuntu:~$ nslookup dashuaiBlog.com
Server:         192.168.124.8
Address:        192.168.124.8#53

Non-authoritative answer:
Name:   dashuaiBlog.com
Address: 192.168.124.8

dashuai@ubuntu:~$ nslookup 192.168.124.8
Server:         192.168.124.8
Address:        192.168.124.8#53

Non-authoritative answer:
8.124.168.192.in-addr.arpa      name = host1.dashuaiBlog.com
原文作者:dashuai
原文地址:Linux系统下搭建DNS服务器--DNS原理总结 - dashuai的博客 - 博客园
版权说明:本文由极乐科技合作博主原创,转载请注明作者与出处,谢谢!
一元抢购微信小程序>>> 链接地址