DNS与BIND.
DNS服务
大家都知道啦, 我们的DNS就是Domain Name Service, DNS作为一个(C/S架构的)协议, 也是一个规范. 对DNS协议的实现, 最标准的就是BIND了. 原先是Bekerley Internet Name Domain, 后来移交给了ISC来维护.
既然是C/S架构, 那么不可避免会使用到套接字, 那么也就需要端口和双方地址. 作为一个基础服务, 端口必须是众所周知的. DNS使用UDP/TCP的53端口, 在我们正常使用的一般是UDP协议的53端口, 原因也很简单了: 快啊~ 事实上, DNS服务不是在网络开始的时候出现的, 只是因为时间的推移, 主机越来越多, 人记忆IP地址实在是太难了所以才催生了DNS的诞生.
所以在互联网上使用名字也就不能随便想叫什么就叫啥了. 管理这些的组织是IANA, 一旦一个地址被分配出去了决不能在分配给另外一个主机了. 因此, 出现了一种应用机制: 比如/etc/hosts这个文件 , 而Windows是%WINDOWS%/system32/drivers/etc/hosts
他的格式就像是: X.X.X.X www.test.com 其实就类似的数据库的查找匹配
但是, 这种实现方式在后来接入网络主机越来越多, 越来越快, 本机维护hosts文件就越来越困难了. 于是IANA就维护一个单独的公共的服务器, 当有人申请的时候就会想办法把映射存进去. 后来条目又越来越多, 使得检索变得困难.所以这个服务器的数据进行了Hash化, 并且是Hash桶的形式, 存入内存 这样就会更快了.
但是, 随着主机记录更多了的时候, 这样一个服务器先不说需要多大的内存来存储, 还需要应付同时几十万的查询请求, 甚至还出现了Hash碰撞. 而每次加入数据库, 都需要重新更新, 载入内存. 这样对于一个服务器来说, 压力太多了!
所以, 我们就采取分布式的办法, 进行功能划分. 采用层级管理的方法, 每一级只需要知道自己一级的和自己下一级的地址就好.
这样最上级来管理的服务器, 我们就称为根名称服务器(root nameserver): 根服务器一共有13个IP, 但是服务器本身并不是就这么13个设备, 有很多镜像, 他们的安全等级非常高.
接下来说说解析的类型, 我们的名称解析是可以进行反向解析的, 在DNS诞生之前, 反向解析是十分简单的, 因为他就是两个键而已.但是DNS之后再想进行反向解析就不是这么简单了, 为什么? 请问: IP地址怎么做分布式? 很困难, 即使是现在(可以通过线索提示的方式进行检索), 反向解析也是一件尚未解决的问题. 而反向解析其实也是很重要的, 比如在我们的垃圾邮件判断上, 反向解析就是一种有效的手段, 通过判断名称和IP双向对应才会认为不是垃圾邮件. 需要注意的是: 正向解析和反向解析是两个不同的命名空间, 是两颗不同的树.
我们的DNS服务器的类型也是有很多的:
- 主DNS服务器: 维护所负责的解析域内的解析库DNS服务器. 这个解析域是管理员维护的.
- 从DNS服务器: 从主DNS服务器或者其他的DNS服务器那里”复制” ( 区域同步 )
- 由于 ,这个复制是自动的, 没有人工. 所以要考虑到主服务器内记录发生变化,而从服务器却没有得到同步的情况. 这个就是通过解析记录来完成的, 首先, 从服务器定期进行检查. 早期是通过版本号(序列号)来实现的, 每次主服务器解析库发生变化, 他的序列号就会发生变化. 一旦发生出现变化, 从服务器就会请求同步. 同步的方式有两种, 一种叫做全量传送: 传递整个解析库, 一种叫做增量传送: 传递解析库变化的那部分内容. 那好, 定期检查, 这个定期到底改定成多少呢? 我们把这个时间间隔叫做刷新时间, 一旦刷新失败了, 进行重试. 这里就又会有一个重试时间, 也就是再次尝试的时间间隔. 很显然, 重试时间一定小于刷新时间. 另外, 还有一个时间叫做过期时长. 当主服务器始终不上线, 连不上的话, 从服务器就会!放弃自己的一切职务!停止提供服务! 所以如果出现故障的话就要立即修复. 为了避免从服务器落后于主服务器, 主服务区还可以有一种通知机制来告知从服务器内容有更新快来更新.
- 缓存DNS服务器: 为了加速每一个用户的互联网访问, 才会需要进行缓存.所谓缓存就是一段内存空间, 向上面一样使用Hash存储, O(1)的速度. 在缓存失效之前, 所有的查询都会使用缓存. 缓存时间长, 可以减少耗时,性能优秀, 但是过时内容可能积攒太多. 缓存时间短, 内容可得到及时的更新, 但是带宽和性能消耗大. 所有这个时间的折中很重要. 其实每一个条目都有他自己的缓存.
- 转发器
我们刚才一直在说区域 (区域传送) 而没有说 域 这两者是有区别的. 对于DNS服务器来说, 他有正向的和反向的两棵树, 对于任意一个域(Domain)来说:
正向: FQDN –> IP, 反向: IP –> FQDN. 他们的解析库也不是一个解析库, 来分别负责本地域名的正反向解析. 对于正向解析库来讲, 它属于正向解析区域. 所有我们说域的时候, 可能是说正向和反向 而说区域的时候, 只能是单向的, 有可能是正向有可能是反向的.
FQDN就是指 完全合格域名 比如: www.baidu.com. 而 www 就不是.
DNS查询
Client –> hosts (如果没有结果) –> DNS Service
而在查询DNS Server的时候, 先检查Local DNS Cache –> 如果没有结果 –> DNS server(recursion) –> Server DNS Cache –> iteration(迭代)
解析答案有两种: 一种是肯定答案, 一种是否定答案(请求的条目不存在). 除此之外, 我们还有权威答案和非权威答案(缓存)
而我们每一个解析条目在解析库中, 叫做一个资源记录, 简称为RR. 记录有类型:
A记录, Address之意, 标记FQDN–>ipv4. 反过来的是PTR记录, CNAME(Canonical Name), 别名记录. SOA(Start Of Authority起始授权记录)定义域的负责, 一个区域解析库只能有一个SOA记录而且必须出现在第一条, NS就是Name Server的记录, 专门用于表明当前区域的DNS服务器, MX(mail exchange), 邮件交换器,AAAA定义ipv6的地址, 也就是FQDN–>ipv6 这些就是最常用的几个.
一条资源记录是有着格式的:
1 | 语法: name [TTL] IN rr_type value |
BIND
我们搭建DNS服务器的程序包叫做BIND. BIND这个程序包包含多个程序子包, 有趣的是, 虽然程序包叫做BIND, 但提供的工具却叫做named.
1 | [root@WWW ~]# yum list bind* |
其中有一个util包很重要, 提供基础DNS查询还有测试工具, 我们的dig工具就是这个包提供的. 在bind开头的程序包中有一个叫做chroot的包, 他可以使得我们的DNS圈进在/var/named/chroot/, 把这个当做根来使用.
bind的主配置文件在named.conf, 但是惯例了, 为了不使配置文件过于庞大, 所以进行切片到一个叫做named.rfc1912.zones的文件中. 另外还有一个文件叫做: /etc/rndc.key 这个rndc是什么玩意?
rndc == remote name domain controller, 远程名称域控制器. 能够实现清理缓存, 重新装载区域配置文件, 查看状态. 但是默认只适用于本地主机, 通过127.0.0.1本地回环地址来进行管理, 它提供了很多辅助性的管理功能.
rndc也是一个服务, 监听在953/tcp端口. 所有的认证就依靠那个key文件.
OK, 现在回到BIND上, 最重要的部分就是我们的解析库文件了对不. 但是现在很肯定是空的嘛. 默认我们把解析解析库放在/var/named这个目录下. 每一个区域由一个解析库文件, 一个DNS服务区可以同时解析多个区域, 而且都可以进行正向和反向的解析. 一般约定俗成的都叫做ZONE_NAME.ZONE文件, 负责保存本地的区域数据. 这里面应该还有一个最重要的区域文件, 叫做根区域文件 这个文件叫做named.ca 另外还会解析localhost, 对于这两个特殊的区域(甚至更多, 如果包括ipv6的话)来实现本地回环地址和localhost的解析库.
我们来到/var/named, 来看看这个目录下的文件
1 | [root@WWW named]# pwd |
看, 这个就是我们的根区域的记录. 其实这个文件是使用dig工具生成的. 剩下两个localhost和loopback就是我们的本机:
1 | [root@WWW named]# cat named.localhost |
那么这个区域名称@是什么呢, 在哪里定义的? 我们转向主配置文件:
1 | [root@WWW named]# vim /etc/named.conf |
由于这个rpm包已经是来源做过的了的, 所以其实直接启动的话他已经可以作为一个缓存DNS服务器了, 虽然只能解析自己和根, 而且只能给localhost用. 所有我们需要让它监听在一个可以和外部连接的IP上. 那么我们现在来修改一下他的配置文件.
1 | [root@WWW named]# cp -av /etc/named.conf{,.bak} |
接着重启服务就可以了.
考虑到现在DNS服务的安全性, 这些年流行了一种新的机制, 叫做dnssec, 也就是每一个DNS都加上数字签名来进行校验. 但是由于其配置很复杂, 而且如果大家都没开就你一个人开了, 意义不大. 所以建议测试的时候把他关掉:
1 | dnssec-enable yes; |
把上面这一段都注释掉吧, 注意注释的嵌套.
还有一个关键的一项, 就是allow-query
这个选项 可以选择把他注释掉, 或者把里面的localhost改成any, 这个是named内置的访问控制列表, 允许任何主机进行查询.
好, 接下来我们来看看怎么配一个主DNS服务器.
首先第一步, 我们在rfc1912.zones文件中加上
1 | zone "yaoxuannn.com" IN { |
接下来我们进行文件的创建 (定义区域解析库文件), 这个时候就要好好看看上面的记录格式了:
1 | $TTL 86400 # 定义宏 |
这样写有没有觉得的很麻烦啊, 其实我们可以把区域名省略, 这样文件就变成了这样:
1 | $TTL 86400 |
注意啦, 如果采取省略写法,那么一定不要在后面加上.了哦.
这么麻烦, 那人工检查是不是太麻烦了啊, 所以named提供了两条命令帮助你进行检查:
1 | [root@WWW named]# named-checkconf |
现在就可以进行尝试解析了.我们来看看:
1 | [root@WWW named]# dig www.yaoxuannn.com |
哇!出现了! 解析成功了! 经测试同一个子网的另外一台机器也能够成功解析!
OK, 那么现在回过头来看看/var/named这个目录:
1 | [root@WWW named]# cd /var/named/ |
发现我们创建的文件是属于root组的, 而且权限是644, 这样并不好, 所以我们要把它改成和其他一样的:
1 | [root@WWW named]# chmod 640 yaoxuannn.com.zone |
好了. 至此我们的DNS服务器就初步搭建完成了.
DNS服务器的测试
dig
测试命令dig的使用:
dig [-t type] name [@SERVER] [query-options]
这个命令是不会进行dns系统hosts文件查询的
查询选项:
+[no]trace: 跟踪解析过程
+[no]recurse: 使用递归解析
host
测试命令host的使用:
host [-t type] name [SERVER]
十分简单, 就不说了
nslookup
更多的使用在交互式模式下,
nslookup>
server IP: 指明DNS服务器
set q=RR_TYPE: 指明查询的资源类型.
NAME: 接着输入需要查询的内容就可以了.