DNS服务器


到现在为止我们通过DHCP给客户端配置的DNS服务器仍然是直接用电信公司给的DNS,一般来说这已经可以了。但有如下两种情况可以让我们有足够的理由设置一个自己的DNS服务器:

 l         想给内部网的服务器做本地的名称解析,方便访问内部服务器;
 l         和我一样不幸在使用电信公司提供给的几个不太稳定的DNS 服务器,并且维护着一个比较大的网络终端遍布在N区N县),总不能在某个DNS宕掉后通知各用户挨个修改吧?不要试图在Windows里设置多个 DNS来解决这个问题,你试试就知道了)所以有必要设置一个可以转发DNS查询请求的本地DNS,这样对内部用户来说,只要设置好DNS指向内部DNS地址就可以了,剩下的事情由管理员根据情况修改这个本地DNS把解析请求转发到最佳的公网DNS上。

在众多 Internet 服务器当中DNS服务是所有服务的基础,它最主要的职责之一是完成从主机域名到IP地址的映射关系的查询。DNS系统管理域名采用一个树状结构,DNS树的最上面是一个无名的root域,用“.”来表示。这个域只用来定位,并不包含任何信息,它由NIC来管理控制。Root下是分层的domain组成树状结构,一个DNS域domain)是DNS树状结构中的一个分枝,domain中包含很多被授权管理的区域zone),它是每个授权单位所管理的主机和IP地址的集合,我们平时说的域,实际上就是zone。比如,把www.silly.com这个URL地址拆解开:

.com            domain

.silly.com      zone

www             则是.silly.com区域内的一台具体的主机

Linux上最常用的DNS服务器软件是BINDBerkeley Internet Name Domain),BIND在不断的更新和完善,在http://www.isc.org/products/BIND/上可以获得它的最新源代码和文档。Red Hat Linux 7.3自带的是bind9.2。

§§ 安装bind软件包

首先来安装bind软件包

[root@rh73 /mnt/cdrom/RedHat/RPMS]# rpm -ivh bind-9.2.0-8.i386.rpm

Preparing...                ########################################### [100%]

   1:bind                   ########################################### [100%]

§§ 了解bind的配置文件/etc/named.conf

为了将来维护的方便,我打算把内部的某些主机做本地的名称解析,假定本地域为silly.com,我要把ns和firewall两个主机名都指向接入服务器的地址192.168.100.254:

ns.silly.com    192.168.100.254

firewall.silly.com  192.168.100.254

Linux上的DNS软件包是bind,但服务进程的名字为named,首先来看一下/etc/named.conf,该文件是bind最主要的配置文件,这里定义了域名服务器的类型,以及相应的数据库文件所在目录等内容。

该文件开始是options设定部分:

options {

        directory "/var/named";

        /*

         * If there is a firewall between you and nameservers you want

         * to talk to, you might need to uncomment the query-source

         * directive below.  Previous versions of BIND always asked

         * questions using port 53, but BIND 8.1 uses an unprivileged

         * port by default.

         */

        // query-source address * port 53;

};

其中directory设定指出了named的数据资源文件存放在/var/named目录下面。也就是说,named进程会在这个目录里查找相关文件获得DNS数据,然后在后面设置数据文件时,可以直接放在这个目录里,不需要再使用绝对路径。

接下来的一段文字是说如果你的DNS服务器是bind 8.1之前的版本,并且和客户端之间如果隔着防火墙的话,要将// query-source address * port 53;前面的//拿掉去掉注释)。我们使用的是9.2版的软件,所以不需要更改这个设置。

//

// a caching only nameserver config

//

controls {

        inet 127.0.0.1 allow { localhost; } keys { rndckey; };

};

controls和文件最后的include "/etc/rndc.key";是bind 9.x版本的新功能,是有关DNS更新以及更新时加密处理的,暂时我们用不到,先不管它。

zone "." IN {

        type hint;

        file "named.ca";

};

这部分设置定义了DNS系统中的root区域“.”root zone),其类型为hint。本地DNS无法解析到的非本地区域的内容,都会根据named.ca的里设定到root区域负责查询。

zone "localhost" IN {

        type master;

        file "localhost.zone";

        allow-update { none; };

};

zone "0.0.127.in-addr.arpa" IN {

        type master;

        file "named.local";

        allow-update { none; };

};

这两段定义了本机名称的DNS解析,第一个zone是localhost的解析,其类型为master,数据文件是/var/named/localhost.zone。第二个zone是本机区域的反向解析,即根据IP地址反查域名的数据。

include "/etc/rndc.key";

下面看看localhost.zone的内容:

[root@rh73 /var/named]# cat localhost.zone

$TTL    86400

$ORIGIN localhost.

@               1D IN SOA       @ root (

                                42              ; serial (d. adams)

                                3H              ; refresh

                                15M             ; retry

                                1W              ; expiry

                                1D )            ; minimum

 

                1D IN NS        @

                1D IN A         127.0.0.1

第一行是TTL Time To Live)设定,以秒为单位,这里定义为86400秒,也就是一天。每一个DNS服务器都有缓存非本地域名信息的功能,TTL指出了解析结果在缓存中保留的时间。平时你可能注意到了,第一次访问某个站点可能需要较长的时间才能打开,接下来再访问时就快一点,这就是DNS缓存功能的作用,它减少了第二次解析域名到IP地址的时间。

第二行是ORIGIN,指出下面的主机记录属于哪个域。在下面的@是它的替代符号。

第三行开始的@ 是ORIGIN的替代符,这里是指localhost。接下来的1D1day,一天,也可以写成秒为单位的数字,如86400)是TTL值,可以不指定,如果没有指定,则参考前面设定的TTL值,如果前面也没定义,则参考后面要介绍的minium tll的值。你可以单独为每一个记录设定TTL,只要将要设定的值放在“IN”之前就可以了。

IN后面的SOAStart Of Authority)是指这一行记录的类型,表示当前区域的授权记录开始。每一个数据文件只能有一个SOA,不能重复,并且必须是所负责zone中的第一个记录。

SOA后面指定了这个区域的授权主机和管理者信箱,这里分别是@localhost.)和root@localhost。root如果写全了应该是root.localhost,这里用“.”代替“@”。SOA的授权主机名称必须在DNS系统中有一个A记录。

接下来的 SOA 设定是被括在"( )"之间的 5 组数字,主要作为和 slave 服务器同步 DNS 数据所使用的数据而设定的:

Serial:其格式通常是“年月日+修改次数”。当 slave 要进行数据同步的时候,会比较这个数值。如果发现在这里的数值比它那边的数值“大”,就进行更新,否则忽略。serial不能超过 10 位数字。

Refresh:这里是是告诉 slave 隔多久进行一次数据同步是否同步要看 Serial 的比较结果)。

Retry:slave 在进行更新失败后,要隔多久再进行重试。

Expire:这是记录逾期时间;当 slave 一直未能成功与 master 取得联络,那到这里就放弃retry,同时这里的数据也将标识为过期expired)。

Minimum:这是最小预设 TTL 值,如果在前面没有用“$TTL”来定义,就会以此值为准。

以上的数字都是以秒为单位,也可以用 H小时)、D天)﹑W星期)来做单位,如:3H 和 259200 是一样的。无论用什么单位来设定,都要遵守下面的规则:

expire >= refresh + retry

expire >= 10 * retry

请注意:SOA 记录中这对“)”符号中的左括号“”一定要和 SOA 写在同一行!

最后两行表示负责localhost.这个记录的Name ServerNS)是localhost这台主机,localhost的IP地址Address)是127.0.0.1。

named.local在/etc/named.conf里定为“0.0.0.127.in-addr.arpa”zone的反向解析数据文件,其内容如下:

[root@rh73 /var/named]# cat named.local

$TTL    86400

@       IN      SOA     localhost. root.localhost.  (

                                      1997022700 ; Serial

                                      28800      ; Refresh

                                      14400      ; Retry

                                      3600000    ; Expire

                                      86400 )    ; Minimum

        IN      NS      localhost.

 

        IN      PTR     localhost.

来看最后一行“1       IN      PTR     localhost.”,这个记录类型是PTRPointer),通常用在反向解析时,将IP指向主机名称和A记录正好相反)。前面的设置中,我们知道127.0.0.1对应的主机名称是localhost,反向查询时,IP地址应该倒过来写1.0.0.127.in-addr.arpa,由于这里的 ORIGIN@)是“0.0.127-in-addr.arpa.”,所以在写PTR记录时,只需要写1,后面会自动补上0.0.127-in- addr.arpa.

§§ 实现本地域主机的解析

了解了上面的内容,我们来看看如何做本地的域名解析。我们要做的工作是:

/etc/named.conf里添加两个zone设置:

zone "silly.com" IN {

        type master;

        file "silly.zone";

        allow-update { none; };

};

zone "100.168.192.in-addr.arpa" IN {

        type master;

        file "named.silly";

        allow-update { none; };

};

设置/var/named/下的数据文件:

[root@rh73 /var/named]# cat silly.zone

$TTL    86400

$ORIGIN silly.com.

@       IN      SOA     ns.silly.com. root.silly.com.  (

                                      1997022700 ; Serial

                                      28800      ; Refresh

                                      14400      ; Retry

                                      3600000    ; Expire

                                      86400 )    ; Minimum

                IN      NS      ns.silly.com.

 

ns              IN      A       192.168.100.254

firewall        IN      CNAME   ns

CNAME记录用来定义一个主机域名的别名。当多个主机名指向同一个地址的时候,这个记录类型可以方便设置。

设置反向解析zone:

[root@rh73 /var/named]# cat named.silly

$TTL    86400

@       IN      SOA     ns.silly.com. root.silly.com.  (

                                      1997022700 ; Serial

                                      28800      ; Refresh

                                      14400      ; Retry

                                      3600000    ; Expire

                                      86400 )    ; Minimum

        IN      NS      ns.silly.com.

 

254     IN      PTR     ns.silly.com.

§§ 转发解析请求

为了提高我们这个DNS服务器的查询效率,我们会采取这样的措施:把非本地域的解析请求转发到我们的ISP提供的DNS。

这个功能是由forwarder 选项来完成的。所谓的 forwarder,就是当某一台 NS 主机遇到非本机负责的 zone ( slave zone 也属于本机负责的范围) 查询请求的时候,将不直接向 root zone 查询而把请求转交给指定的 forwarder (一台或多台) 主机代为查询。如果你不了解 DNS 的查询模式,那么很难理解这个 forwarder 的意义和好处。

我们知道,当DNS 服务器接到客户端主机的查询请求时,首先会检查这个查询是否属于本机管辖,否则将转向 root zone 再逐级的查询下去,最后再把查询结果告诉客户端。在这个过程之中,DNS服务器还会将查询到的结果存放到缓存中。只要缓存中的 TTL 没过期,在下次遇到同样查询的时候,就可以直接将结果响应给客户端,而无需再重复上次的查询流程。如果DNS服务器上指定了forwarder,那这个 DNS发现缓存中没有记录时,将不向 root 查询,而是向 forwarder 送出同样的请求转发),然后等待查询结果,即把逐级往下查询这个耗费精力的动作,交给 forwarder 负责。但无论这个结果是自己直接查询得来的,还是 forwarder 送回来的,DNS服务器都会保存一份数据在缓存中。这样,以后的相同查询就快多了,这对于DNS所服务的 客户端而言查询效率会提高很多。

forwarder 机制的好处并非仅是上面所提到的效率提升,对于整个网络流量(尤其是对外的流量)也是有帮助的。比方说,你的内部网络需要 10 台 DNS 来提供服务,你只需在某一台能直接与外界沟通的计算机上架设 DNS 服务,然后将其它内部DNS的 forwarder 指向该服务器就行了。这样可能本来需要 10 次的 root 查询,在 forwarders 的机制下,就只需 1 次而已。连同下层的往返查询来计算的话,总体上所省下的对外查询就更多了,再加上缓存带来的好处,forwarder 所降低的 DNS 流量是非常显著的。

事实上,在本章开始我们就提到如何集中管理内部局域网用户域名解析问题,解决的方法就是:在本地DNS的 forwarder 设定为 ISP 的 DNS,局域网用户把DNS都设置成本地DNS地址,在进行外部域名解析时,我们的DNS把解析请求转发给ISP的DNS;又因为 ISP 上的 DNS 也有缓存的关系,所以这样设置查询还可以提高速度。

罗嗦了半天,现在看看如何配置。具体的设置很简单:在named.conf的options部分添加这样一行:

forwarders { 211.136.17.107; 202.102.152.3; };

如此设置完毕,那么所有非本区域的查询都会直接转发到forwarders指定的DNS服务器上去。

§§ 测试DNS

全部设置完后,把named进程重起一下,使设置生效:

[root@rh73 /var/named]# /etc/rc.d/init.d/named restart

现在测试一下刚才的设置是否正确:

设置Linux主机的DNS客户端

[root@rh73 ~]# vi /etc/resolv.conf

其实在系统安装设置网卡参数时我们已经设置了这个文件,其内容可能是:

nameserver 202.102.152.3

nameserver 202.102.134.68

现在把这两行内容去掉或注释掉,在行首加“#”),然后写上:

nameserver 192.168.100.254

即使用我们刚才设定的192.168.100.254这个DNS服务器。

Linux上我们可以用ping、nslookup、dig、host等命令来测试DNS是否工作正常,这些小工具都很简单,以host为例:

[root@rh73 ~]# host ns.silly.com

ns.silly.com has address 192.168.100.254

[root@rh73 ~]# host firewall.silly.com

firewall.silly.com is an alias for ns.silly.com.

ns.silly.com has address 192.168.100.254

[root@rh73 ~]# host china.com

china.com has address 61.151.243.8

可以正常解析出本地区域和Internet上域名的IP地址,符合我们的设计要求。当然配置一个完善的DNS服务器这些知识是远远不够的,如果想了解更多,请参考其它资料。

§§ 如何成为公众网上的DNS

我们在这里配置的域名服务器解析的silly.com 相关的内容,只有在我们内部有效,如果你想让silly.com成为Internet上的域名,并且别人能够通过你的DNS服务器的数据来解析到它,挨个通知把DNS设置成你的服务器地址是不太现实的。根据DNS的工作原理,应该需要在silly.com的上级域名服务器com中注册,这样域名空间的其它域名服务器就可以访问到该域名服务器的数据。谁做过这个工作? 

[tips]

在设置named.conf的options部分时,我们可以利用下面几个有用的options,来增强系统的安全特性:

version "Hello World";

当别人要探测我们DNS服务器的版本时,对方得到的将是Hello World :)

Listen-on{192.168.100.254;};

如果DNS服务运行在有多个网卡的服务器上,那么默认的它会在所有网卡接口上监听服务,这个选项告诉它只在指定的借口上进行服务监听。

如果不想让某些主机或网络使用我们的DNS服务,那么可以通过配置acl,并在options部分设置Blackhole完成:

acl denied {

192.168.100.50;

192.168.100.51;

192.168.1.0/24.

};

Blackhole {denied;};

这样设置之后,192.168.100.50,192.168.100.51和192.168.1.0/24的主机都不能使用这个DNS服务器了。


相关内容