Jusene's Blog

DNS服务详解

字数统计: 3.4k阅读时长: 15 min
2017/03/19 Share

DNS

DNS作为互联网最基础服务,在整个互联网通信过程中扮演着举足轻重的地位,全世界13台根DNS服务器,及其衍生出的众多子域服务器,构建如今互联网的基础架构。所以今天我们就来聊聊DNS服务器及自己来构建一组可用的DNS服务器。

BIND

在Linux上DNS通过bind程序来实现,其主要程序包包括:

  • bind-libs:被bind和bind-utils包中的共同用到的库文件
  • bind-utils:bind客户端程序集,例如dig,host,nslookup等
  • bind:提供的dns server程序,以及几个常用的测试程序
  • bind-chroot:选装,让named运行于jail模式下,如果我们要提供公网解析,最好设置,但一般自建dns都是用来内网使用的。

配置文件

主配置文件:/etc/named.conf
或包含进来的其他文件:
/etc/named.iscdlv.key
/etc/named.rfc1912.zones
/etc/named.root.key
解析库文件:
/var/named/目录下
一般名字为:ZONE_NAME.zone

注意:

  • (1)一台dns服务器可同时为多个区域提供解析
  • (2)必须要有根区域解析库文件:named.ca
  • (3)还应该有两个区域解析库文件:localhost和127.0.0.1的正反向解析库
    • 正向:named.localhost
    • 反向:named.loopback

rndc:remote name domain contoller
953/tcp,但默认监听127.0.0.1地址,因此默认只能本地使用,当然我们也可以配置成远程控制,可以远程控制dns服务器,但是在公网配置建议不开启。

bind程序安装完成之后,默认即可做缓存名称服务器使用;如果没有专门负责解析的区域,直接即可启动服务;
centos 6:service named start
centos 7:systemctl start named

主配置文件 named.conf

1
#全区配置段
2
options {
3
        listen-on port 53 { 127.0.0.1; };                          #这里需要需要改成any,默认监听127.0.0.1,无法完成接受外部的访问
4
        directory       "/var/named";
5
        dump-file       "/var/named/data/cache_dump.db";
6
        statistics-file "/var/named/data/named_stats.txt";
7
        memstatistics-file "/var/named/data/named_mem_stats.txt";
8
        allow-query     { localhost; };                            #这里也需要修改成any,默认只接受本地查询,无法完成外部访问
9
10
        /* 
11
         - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.
12
         - If you are building a RECURSIVE (caching) DNS server, you need to enable 
13
           recursion. 
14
         - If your recursive DNS server has a public IP address, you MUST enable access 
15
           control to limit queries to your legitimate users. Failing to do so will
16
           cause your server to become part of large scale DNS amplification 
17
           attacks. Implementing BCP38 within your network would greatly
18
           reduce such attack surface 
19
        */
20
        recursion yes;                                            #应该定义递归ip,后面会有讲到
21
22
        dnssec-enable yes;                                        #因为自建的dns一般都是内网使用,所以可以关闭bind的安全功能
23
        dnssec-validation yes;                                    #一样关闭复杂的安全功能
24
25
        /* Path to ISC DLV key */
26
        bindkeys-file "/etc/named.iscdlv.key";
27
28
        managed-keys-directory "/var/named/dynamic";
29
30
        pid-file "/run/named/named.pid";
31
        session-keyfile "/run/named/session.key";
32
};
33
#日志配置段
34
logging {
35
        channel default_debug {
36
                file "data/named.run";
37
                severity dynamic;
38
        };
39
};
40
#区域配置段
41
zone "." IN {
42
        type hint;
43
        file "named.ca";
44
};
45
46
include "/etc/named.rfc1912.zones";
47
include "/etc/named.root.key";

启动 bind 服务,默认安全的dns就可以当作缓存服务器使用,我们可以将dns指向这台dns服务器,就可以实现递归和迭代查询dns域名,并且缓存解析域名。

dns

这个解析过程可以参照上图。

测试工具

为了测试dns的解析,bind-utils为我们提供了三种工具:

dig,host,nslookup
dig命令:
dig [-t RR_TYPE] name [@SERVER] [query opotion]
用与测试dns系统,因此不会查询hosts文件
查询选项:
+[no]trace:跟踪解析过程
+[no]recurse:进行递归解析
模拟完全区域传送:
dig -t axfr DOMAIN [@SERVER]

host命令:
host [-t RR_TYPE] name SERVER_IP

nslookup命令:
nslookup [-options] [name] [server]
交互式模式:
nsloopup>
server IP:以指定的ip为dns服务器进行查询
set q=RR_TYPE:要查询的资源记录类型
name:要查询的名称

配置解析一个正向区域

(1)定义区域
在主配置文件中或主配置文件辅助配置文件中实现
一般在/etc/named.rfc1912.zones中定义区域
zone “ZONE_NAME” IN {
type {master | slave | hint |forward};
file “ZONE_NAME.zone”;
};
(2)建立区域数据文件
在/var/named目录下建立区域数据文件

1
$TTL 3600
2
@     IN SOA jusene.me. admin.jusene.me. (
3
        2017031901
4
        1H
5
        10M
6
        3D
7
        1D
8
)
9
10
                    IN NS ns1
11
                    IN MX 10 mx1
12
    ns1             IN A 10.211.55.24
13
    mx1             IN A 10.211.55.23
14
    www             IN A 192.168.31.26

(3)让服务器重载配置文件和区域数据文件
检查语法错误
named-checkconf
named-checkzone zone zone-file

示例:

1
~]#vim /etc/named.rfc1912.zones
2
zone "jusene.me" IN {
3
        type master;
4
        file "jusene.me.zone";
5
};
6
~]#vim /var/named/jusene.me.zone
7
$TTL 3600
8
@     IN SOA jusene.me. admin.jusene.me. (
9
                2017031901    ;serial
10
                1H            ;refresh
11
                10M           ;retry
12
                3D            ;expire
13
                1D            ;negative answer ttl
14
        )
15
16
                IN NS ns1
17
                IN MX 10 mx1
18
ns1             IN A 10.211.55.24
19
mx1             IN A 10.211.55.23
20
www             IN A 192.168.31.26

重启named服务,我们就可以测试正向解析

配置解析一个反向区域

(1)定义区域
在主配置文件中或主配置文件辅助配置文件中实现
一般在/etc/named.rfc1912.zones中定义区域
zone “ZONE_NAME” IN {
type {master | slave | hint |forward};
file “ZONE_NAME.zone”;
};
注意:反向区域的名字 反向的网段地址in-addr.arpa
(2)建立区域数据文件
在/var/named目录下建立区域数据文件

1
$TTL 3600
2
@     IN   SOA  jusene.me admin.jusene.me (
3
          2017031901
4
          1H
5
          10M
6
          3D
7
          1D
8
      )
9
        		  IN  NS ns1.jusene.me.
10
24        IN PTR  ns1.jusene.me.
11
23        IN PTR  mx1.jusene.me.
12
26        IN PTR www.jusene.me.

(3)让服务器重载配置文件和区域数据文件
检查语法错误
named-checkconf
named-checkzone zone zone-file

示例:

1
~]#vim /etc/named.rfc1912.zones
2
zone "55.211.10.in-addr.arpa" IN {
3
        type master;
4
        file "55.211.10.zone";
5
};
6
~]#vim /var/named/55.211.10.zone
7
$TTL 3600
8
@     IN   SOA  jusene.me admin.jusene.me (
9
            2017031901
10
            1H
11
            10M
12
            3D
13
            1D
14
        )
15
          IN  NS ns1.jusene.me.
16
24        IN PTR  ns1.jusene.me.
17
23        IN PTR  mx1.jusene.me.
18
26        IN PTR  www.jusene.me.

重启named服务,我们就可以测试反向解析

配置主从服务器

注意:从服务器是区域级别的概念
on slave
配置一个从区域:
(1)定义区域
定义一个从区域;
zone “ZONE_NAME” IN {
type slave;
file ‘slaves/ZONE_NAME.zone’;
masters {MASTER_IP;};
};
配置文件语法检查:named-checkconf
(2)重载配置
rndc reload
systemctl reload named

on master
(1)确保区域数据文件中为每个从服务器配置NS记录,并且在正向区域文件需要每个从服务器的NS记录的主机名配置一个A记录,且此A后面的地址为真正的从服务器的ip地址。

手动测试区域传输:dig -t axfr jusene.me @master server

注意:时间要同步

示例:

1
on slave
2
~]#vim /etc/named.rfc1912.zones
3
zone "jusene.me" IN {
4
	type slave;
5
	file ''slaves/jusene.me.zone;
6
	masters {10.211.55.24;};	
7
};
8
on master
9
~]#vim /var/named/jusene.me.zone
10
$TTL 3600
11
@     IN SOA jusene.me. admin.jusene.me. (
12
                2017031901    ;serial
13
                1H            ;refresh
14
                10M           ;retry
15
                3D            ;expire
16
                1D            ;negative answer ttl
17
        )
18
19
                IN NS ns1
20
                IN NS ns2
21
                IN MX 10 mx1
22
ns1             IN A 10.211.55.24
23
ns2             IN A 10.211.55.35
24
mx1             IN A 10.211.55.23
25
www             IN A 192.168.31.26

注意:这里的主从复制是通过serial的值来区别主是否被修改过,所以每次修改过主的记录,记得修改serial

这里可以使用通过dig来测试区域传送,但是这是不安全,如果可以任意区域传送,可以很容易推测出内部拓扑结构,所以要限定只能从服务器来区域传送,最重要的是从服务器无法写,所以当主服务器宕机,在expire的时间到了的时候,从服务器也会宕机,所以请维护好主服务器,备服务器只能临时支撑起解析业务。

子域授权

正向解析的子域授权实现起来很容易,但是反向解析的实现就很困难,但是互联网对于域名反解的需求很小。

示例:

1
~]#vim /var/named/jusene.me.zone
2
$TTL 3600
3
@     IN SOA jusene.me. admin.jusene.me. (
4
                2017031901    ;serial
5
                1H            ;refresh
6
                10M           ;retry
7
                3D            ;expire
8
                1D            ;negative answer ttl
9
        )
10
11
                IN NS ns1
12
                IN NS ns2
13
                IN MX 10 mx1
14
ns1             IN A 10.211.55.24
15
ns2             IN A 10.211.55.35
16
mx1             IN A 10.211.55.23
17
www             IN A 192.168.31.26
18
19
ops             IN NS ns1.ops
20
ns1.ops         IN A 10.211.55.36
21
22
再另一台机器上起同样的服务
23
~]#vim /etc/named.rfc1912.zones
24
zone "ops.jusene.me" IN {
25
        type master;
26
        file "ops.jusene.me.zone";
27
};
28
~]#vim /var/named/ops.jusene.me.zone
29
$TTL 3600
30
@     IN SOA ops.jusene.me. admin.jusene.me. (
31
                2017031901    ;serial
32
                1H            ;refresh
33
                10M           ;retry
34
                3D            ;expire
35
                1D            ;negative answer ttl
36
        )
37
38
                IN NS ns1
39
                IN MX 10 mx1
40
ns1             IN A 10.211.55.36
41
mx1             IN A 10.211.55.25
42
www             IN A 192.168.31.31

我们可以通过父域的解析道子域的记录,但是想要从子域通过追踪可以发现去递归查询了,也就是说子域无法直接用父域的解析。

定义转发

上面说到子域无法使用父域的解析记录,那我们可以通过定义转发器来实现服务。
注意:被转发的服务器必须允许为当前服务器做递归

1
(1)区域转发:仅转发对特定区域的解析请求
2
zone “ZONE_NAME” IN {
3
     type forward;
4
     forward {first | only};	
5
     forwarders {SERVER_IP}; 
6
};
7
8
first:首先转发,转发不通过,自己做迭代
9
only:只转发
10
11
(2)全局转发:针对凡本地没通过zone定义的区域查询请求,通通转发给某转发器
12
opotions {
13
	forward only;
14
	forwarders {SERVER_IP};
15
}

BIND 中的安全定义

acl:访问控制列表;把一个或多个地址归并一个命名的集合,随后通过此名称即可对此集合内的所有主机实现统一调用;

acl acl_name{
ip;
net/prelen;
};

示例:

1
acl mynet {
2
    172.16.0.0/16;
3
    127.0.0.0/8
4
}

bind有四个内置acl
none:没有一个主机
any:任意主机
localhost:本机
localnet:本机所在的网络

访问控制指令:
allow-query {};允许查询的主机;白名单;
allow-transfer {};允许向哪些主机做区域传送;默认为向所以主机;应该配置仅允许从服务器
allow-recursion {};允许哪些主机向当前dns服务器发起递归查询请求,不应该允许全部的递归请求
allow-update{};DDNS,允许动态更新区域数据库文件中内容

BIND 智能dns的实现

bind view

视图:
view VIEW_NAME {
ZONE
ZONE
ZONE
};

示例:

1
view internal {
2
  match-clients{10.211.55.0/24;};
3
  zone "jusene.com" IN {
4
    type master;
5
    file "jusene.com/internal";
6
  };
7
};
8
9
view external{
10
  match-clients{any;};
11
  zone "jusene.me" IN {
12
    type master;
13
    file "jusene.me/external";
14
  };
15
};

可以根据特定的ip的acl来规定请求的zone区域。

测试解析性能

queryperf进行dns拨测

1
wget http://ftp.isc.org/isc/bind9/9.7.3/bind-9.7.3.tar.gz
2
tar zxvf bind-9.7.3.tar.gz
3
cd bind-9.7.3/contrib/queryperf/
4
./configure
5
make
6
7
使用方法:
8
queryperf -d input_file -s server
9
10
input_file 压力测试读取文件的格式
11
12
www.baidu.com A
13
www.sina.com A
14
www.qq.com A

BIND 日志文件

我们在主配置中也看见了logging,我们看下logging需要怎么配置

1
logging语句的语法为:
2
logging {
3
            channel <string>; {
4
                file <logfile>;;
5
                    syslog <optional_facility>;;
6
                null;
7
                stderr;
8
                    severity <logseverity>;;
9
                    print-time <boolean>;;
10
                    print-severity <boolean>;;
11
                    print-category <boolean>;;
12
        };
13
        category <string>; { <string>;; ... };
14
};

在日志中主要有两个概念:通道(channel)和类别(category)。通道指定了应该向哪里发送日志数据,severity是指定记录消息的级别。

1
critical
2
error
3
warning
4
notice
5
info
6
debug [ level ]
7
dynamic

print-time是设定在日志中是否需要写入时间,print-severity是设定在日志中是否需要写入消息级别,print-category是设定在日志中是否需要写入日志类别。

1
category语句是指定哪一种类别的数据使用哪个或者哪几个已经定义了的通道。在bind9中类别有:
2
default
3
default类别匹配所有未明确指定通道的类别,但是不匹配不属于任何类别的消息。这些不属于任何类别的消息属于下面列出的这些类别。
4
general        包括所有未明确分类的BIND消息。
5
client        处理客户端请求。
6
config        配置文件分析和处理。
7
database    同BIND内部数据库相关的消息,用来存储区数据和缓存记录。
8
dnssec        处理DNSSEC签名的响应。
9
lame-servers    发现错误授权。
10
network        网络操作
11
notify        异步区变动通知。
12
queries        查询日志
13
resolver        名字解析,包括对来自解析器的递归查询的处理。
14
security        认可/非认可的请求。
15
update        动态更新事件。
16
xfer-in        从远程名字服务器到本地名字服务器的区传送。
17
xfer-out        从本地名字服务器到远程名字服务器的区传送。

示例:

1
logging {
2
             channel query_log {
3
                     file "query.log"    versions 3 size 20m;
4
                     severity    info;
5
                     print-time    yes;
6
                     print-category  yes;
7
             };
8
             category queries {
9
                     query_log;
10
             };
11
     };
CATALOG
  1. 1. DNS
    1. 1.1. BIND
      1. 1.1.1. 配置文件
      2. 1.1.2. 测试工具
      3. 1.1.3. 配置解析一个正向区域
      4. 1.1.4. 配置解析一个反向区域
      5. 1.1.5. 配置主从服务器
      6. 1.1.6. 子域授权
      7. 1.1.7. 定义转发
      8. 1.1.8. BIND 中的安全定义
      9. 1.1.9. BIND 智能dns的实现
      10. 1.1.10. 测试解析性能
      11. 1.1.11. BIND 日志文件