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的解析,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 | }; |