见字如面,我是小斐,今天文章展开说明BIND 9中named.conf配置文件的结构和语法以及相关参数,主要目的是既能搭建bind 9运行起来,又明白内在配置的意义,努力做到知其然,知其所以然。
上篇主要介绍bind 9安装和运行,要顺利把bind9运行起来,首先需要把相关配置文件配置好,并且根据你需要的不同角色和功能,配置不同的配置文件,以顺利达到你的需求。
named.conf 结构文件包含三种类型实体:
- 注释
- 块
- 语句
bind 9 配置由块、语句和注释组成。
注释/* C语言风格注释 */
# C语言风格注释不能嵌套 如下面的注释就是无效的,以第一个*/结尾 可多行注释
/* This is the start of a comment.
This is still part of the comment.
/* This is an incorrect attempt at nesting a comment. */
This is no longer in any comment. */
// C 语言风格注释,只能行注释
# 这是Shell 风格(或 Perl 风格)注释,只能行注释
# and Perl
说明:zone区域配置文件可以使用分号 ( ; ) 字符注释,但是在主配置文件中不可用 ( ; ) 注释,而是配置文件的行末尾结束符。
块主要说明经常使用的模块做基础介绍
模块 | 功能说明 |
acl | 定义访问控制列表 |
controls | 定义rndc命令使用的控制通道,若省略,则只允许经过rndc.key认证的127.0.0.1的rndc控制 |
include | include filename; 引入外部局部配置文件 |
dnssec-policy | dnssec 安全策略,一般默认不启用dnssec功能 |
key | 使用 TSIG 指定用于身份验证和授权的密钥信息,一般rndc的授权密钥信息 |
logging | 日志记录 |
options | 定义全局选项 |
statistics-channels | 声明通信的通道,用于访问bind的统计信息数据 |
TLS | 指定 TLS 连接的配置信息 |
http | 指定 HTTP 连接的配置信息 |
trust-anchors | 定义 DNSSEC 密钥信息 |
zone | 定义一个区域声明 |
view | 定义域名空间的一个视图 |
server | 可以出现在配置文件的顶级,可以在一个view中,定义对特定的服务器设置参数 |
primaries | 定义一个命名的主服务器列表,一般包含在存根区或者辅区的primaries或者also-notify列表中。 |
parental-agents | 定义要由主要和次要区域使用的委派代理列表 |
重点说明下:acl、view、logging、options、zone等模块
模块说明controls模块位置:最顶级 不可嵌入
tips:就是controls块必须在 named.conf 配置文件的顶层,如下所示 named.conf
// rndc通道
controls {
inet 127.0.0.1 port 953 allow { 127.0.0.1; } keys { "rndc-key"; };
};
// 全局选项
options {
......
};
// 日志记录
logging {
......
};
// 视图层
view telecom {
......
};
key:可以出现在配置文件的顶层和view语句内部
view telecom {
key "rndc-key" {
algorithm hmac-sha256;
secret "Ocpnouni6h/ob6Bw9aWAYBoCSYNJQVK/fG3XsYVm56k=";
};
};
主要是启用rndc(Remote Name Daemon Control)是远程名称守护程序控件,rndc 可以在本地或者远程了解当前服务器的运行状况,也可以对服务器进行关闭、重载、刷新缓存、增加删除zone等操作。
rndc工具简单介绍
使用rndc可以在不停止DNS服务器工作的情况进行数据的更新,使修改后的配置文件生效。在实际情况下,DNS服务器是非常繁忙的,任何短时间的停顿都会给用户的使用带来影响。因此,使用rndc工具可以使DNS服务器更好地为用户提供服务。在使用rndc管理bind前需要使用rndc生成一对密钥文件,一半保存于rndc的配置文件中,另一半保存于bind主配置文件中。rndc的配置文件为/etc/rndc.conf,在CentOS或者RHEL中,rndc的密钥保存在/etc/rndc.key文件中。rndc默认监听在953号端口(TCP),其实在bind9中rndc默认就是可以使用,不需要配置密钥文件。
rndc与DNS服务器实行连接时,需要通过数字证书进行认证,而不是传统的用户名/密码方式,在通信两端使用预共享密钥,在连接的两端使用共享密钥。它为命令请求和名字服务器的响应提供 TSIG类型的认证。所有经由通道发送的命令都必须被一个服务器所知道的 key_id 签名。为了生成双方都认可的密钥,可以使用 rndc-confgen 命令产生密钥和相应的配置,再把这些配置分别放入named.conf和rndc的配置文件rndc.conf中。
rndc 详细语法:
BIND 9 9.19.8-dev documentationbind9.readthedocs.io/en/latest/manpages.html#rndc-name-server-control-utility
常用命令介绍:
# 显示bind服务器的工作状态
rndc status
# 重新加载配置文件和区域文件
rndc reload
# 重新加载指定区域配置文件
rndc reload zone_name
# 重读配置文件并加载新增的区域
rndc reconfig
# 关闭或开启查询日志
rndc querylog
# 将高速缓存转储到转储文件 (named_dump.db)
rndc dumpdb
# 暂停更新所有动态zone
rndc freeze
# 暂停更新一个动态zone
rndc freeze [zone [class [view]]]
# 刷新服务器的所有高速缓存
rndc flush [view]
# 为某一视图刷新服务器的高速缓存
rndc flushname name [view]
# 将服务器统计信息写入统计文件中
rndc stats
# 将暂挂更新保存到主文件并停止服务器 -p
rndc stop
# 将暂挂更新保存到主文件并停止服务器,返回进程ID
rndc stop -p
# 停止服务器,但不保存暂挂更新
rndc halt
# 打开debug, debug有级别的概念,每执行一次提升一次级别
rndc trace
# 指定 debug 的级别, trace 0 表示关闭debug
rndc trace [level]
# 将调试级别设置为 0
rndc notrace
# 重新启动服务器(尚未实现)
rndc restart
# 增加一个zone
rndc addzone zone [class [view]] { zone-options }
# 删除一个zone
rndc delzone zone [class [view]]
# 删除一个TSIG key
rndc tsig-delete keyname [view]
# 查询当前有效的TSIG列表
rndc tsig-list
# 开启/关闭dnssec 默认检测状态
rndc validation (on | off | status) [view ...]
acl模块
ACL是Access Control List的缩写,即访问控制列表,就是一个被命名的地址匹配列表。使用访问控制列表可以使配置简单而清晰,一次定义之后可以在多处使用,不会使配置文件因为大量的 IP 地址而变得混乱。
ACL语句是named.conf的顶级语句,不可以将其嵌入其他语句,要使用用户自己定义的访问控制列表,必须在使用之前定义。因为可以在 options 语句里使用访问控制列表,所以定义访问控制列表的 acl 语句应该位于 options 语句之前。
语法:
acl acl_name {
address_match_list;
};
bind 9 中预设了4 个名称的地址匹配列表,他们可以直接使用,分别为:
- any : 所有主机
- localhost : 本机
- localnets : 本地网络上的所有主机
- none : 不匹配任何主机
为了便于维护管理员定义的访问控制列表,可以将所有定义 acl 的语句存放在单独的文件 /usr/local/bind/etc/named.conf.acls 中,然后在主配置文件 /usr/local/bind/etc/named.conf 中引入如下语句:
include "/usr/local/bind/etc/named.conf.acls";
使用ACL
定义了 ACL 之后,可以在任何可以使用ACL匹配的子句中使用,下面简单介绍常用的子句:
子句 | 模块 | 说明 |
allow-query | options,zone | 指定哪些主机或网络可以查询本服务器或区域,默认的是允许所有主机进行查询。 |
allow-transfer | options,zone | 指定哪些主机允许和本地服务器进行域传输,默认值是允许和所有主机进行域传输。 |
allow-recursion | options | 指定哪些主机可以进行递归查询。如果没有设定,缺省是允许所有主机进行递归查询的。注意禁止一台主机的递归查询,并不能阻止这台主机查询已经存在于服务器缓存中的数据。 |
allow-update | zone | 指定哪些主机允许为主域名服务器提交动态 DNS 更新。默认为拒绝任何主机进行更新。 |
blackhole | options | 指定不接收来自哪些主机的查询请求和地址解析。默认值是 none 。 |
Tips :上面列出的一些配置子句既可以出现在全局配置 options 语句里,又可以出现在 zone 声明语句里,当在两处同时出现时,zone 声明语句中的配置将会覆盖全局配置 options 语句中的配置。
举例:
限制查询
假如要限制只有 172.16.0.0/16 和 172.17.0.0/16 查询本地服务器的所有区信息,可以在 options 语句里使用如下的 allow-query 子句:
options {
......
allow-query { 172.16.0.0/16; 172.17.0.0/16; };
......
};
上面的配置没有使用 ACL,若使用 acl,需要以下的配置步骤:
在 /usr/local/bind/etc/named.conf.acls 中添加如下的 acl 语句,对允许查询的主机列表命名
acl allow-query-list {
172.16.0.0/16;
172.17.0.0/16;
};
在 /usr/local/named/etc/named.conf.options 中使用定义的 acl_name 限制允许查询的主机列表。(我们也会把options模块独立出一个文件)
options {
......
allow-query { allow-query-list; };
......
};
限制区传输
假如要限制只有 192.168.10.200 和 192.168.10.201 可以从本地服务器传输 “Example Domain” 的区信息,可以在 zone 语句里使用如下的 allow-transfer 子句
zone "example.com" {
type primary;
file "example.com.hosts"; // 区域文件定义 RR资源
allow-transfer { 192.168.10.200; 192.168.10.201; };
};
上面的配置没有使用 ACL,若使用 acl,需要以下的配置步骤:
在 /usr/local/bind/etc/named.conf.acls 中添加如下的 acl 语句,对允许查询的主机列表命名
acl allow-transfer-list {
192.168.10.200;
192.168.10.201;
};
在 /usr/local/named/etc/named.conf 中使用定义的 acl_name 限制允许进行域传输的主机列表
zone "example.com" {
type primary;
file "example.com.hosts"; // 区域文件定义 RR资源
allow-transfer { allow-transfer-list; };
};
防止欺骗和拒绝服务攻击
为了防止欺骗和拒绝服务攻击,对于 Internet 上的每个 DNS 服务器至少应该有一个假地址的 ACL 和一个本地地址的 ACL。为此,需要执行如下的步骤
在 /usr/local/bind/etc/named.conf.acls 中添加如下的 acl 语句,创建一个名称为 “bogusnets” 的 ACL 来阻止经常用于欺骗性攻击的(RFC1918)地址空间
acl bogus-nets {
0.0.0.0/8;
1.0.0.0/8;
2.0.0.0/8;
169.254.0.0/16;
192.0.2.0/24;
224.0.0.0/3;
10.0.0.0/8;
172.16.0.0/12;
192.168.0.0/16;
};
创建一个名称为 “our-nets” 的 ACL,并将其配置为实际本网的 IP 地址段
acl our-nets { //用您的网络地址替换下面的地址列表
x.x.x.x/24;
x.x.x.x/21;
};
在 /usr/local/bind/etc/bind/named.conf.options 中使用定义的 acl_name 限制查询和响应
options {
......
allow-query { our-nets; };
allow-recursion { our-nets; };
blackhole { bogus-nets; };
......
};
logging模块
官方文档:
在默认情况下,bind 9把日志消息写到/var/log/messages文件中,而这些日志消息是非常少的,主要就是启动,关闭的日志记录和一些严重错误的消息,所以要详细记录服务器的运行状况,需要自己配置服务器的日志行为,也就是要在配置文件named.conf中使用logging语句来定制自己所需要的日志记录。
语法格式
logging {
category <string> { <string>; ... }; // may occur multiple times
channel <string> {
buffered <boolean>;
file <quoted_string> [ versions ( unlimited | <integer> ) ] [ size <size> ] [ suffix ( increment | timestamp ) ];
null;
print-category <boolean>;
print-severity <boolean>;
print-time ( iso8601 | iso8601-utc | local | <boolean> );
severity <log_severity>;
stderr;
syslog [ <syslog_facility> ];
}; // may occur multiple times
};
- 日志通道:定义日志通过什么方式记录保存并设置日志格式
- 日志类别:定义特定通道的日志数据类型
通道(channel)和类别(category)。通道指定了应该向哪里发送日志数据:是发送给syslog,还是写在一个文件里,或是发送给named的标准错误输出,还是被丢弃。类别则规定了哪些数据需要记录。
举例:
把日志输出到文件中:
logging {
channel an_example_channel {
file "example.log" versions 3 size 20m suffix increment;
print-time yes;
print-category yes;
};
};
severity是指定记录消息的级别:按照严重性递减的顺序
- critical
- error
- warning
- notice
- info
- debug [ level ]
- dynamic
定义了某个级别后,系统会记录包括该级别以及比该级别更严重的级别的所有消息。比如定义级别为error,则会记录critical和error 两个级别的信息。一般情况下,我们记录到info级别就可以了。
- print-time是设定在日志中是否需要写入时间
- print-severity是设定在日志中是否需要写入消息级别
- print-category是设定在日志中是否需要写入日志类别
category语句是指定哪一种类别的数据使用哪个或者哪几个已经定义了的通道:
类别 | 说明 |
default | 匹配所有未明确指定通道的类别,但是不匹配不属于任何类别的消息。这些不属于任何类别的消息属于下面列出的这些类别。 |
general | 包括所有未明确分类的bind消息 |
client | 处理客户端请求 |
database | 同bind内部数据库相关的消息,用来存储区数据和缓存记录 |
dnssec | 处理DNSSEC签名的响应 |
lame-servers | 发现错误授权 |
network | 网络操作 |
notify | 异步区域变动通知 |
queries | 查询日志 |
resolver | 名字解析,包括对来自解析器的递归查询的处理 |
security | 认可/非认可的请求 |
update | 动态更新事件 |
xfer-in | 从远程名称服务器到本地名称服务器的区传送 |
xfer-out | 从本地名称服务器到远程名称服务器的区传送 |
例如要记录queries消息,就可以如下配置(把以下语句添加到named.conf中就可以了):
logging {
channel access_log {
file "/var/log/named/access.log" versions 100 size 100M;
severity dynamic;
print-category yes;
print-severity yes;
print-time yes;
buffered yes;
};
category default {
access_log;
};
};
这样服务器会在工作目录(directory语句所指定的目录,通常为:/var/named)下创建query.log这个文件,并把运行过程产生的queries消息写入到query.log文件中,如下:
Nov 28 16:04:55.516 queries: client 192.168.0.113#32770: query: dns.andy.com IN A
另外解释一下file “query.log” versions 3 size 20m;语句中 “version”和“size”的意义:
是指定允许同时存在多少个版本的该文件,比如指定5个版本(version 5),当access.log达到size的大小,则会保存为query.log.0,以此类推一直保存到access.log.4
#ll
-rw-r--r--. 1 root root 4971 2月 22 08:57 access.log
-rw-r--r--. 1 root root 14240 2月 22 08:57 access.log.0
-rw-r--r--. 1 root root 13204 2月 22 08:57 access.log.1
-rw-r--r--. 1 root root 14240 2月 22 08:57 access.log.2
-rw-r--r--. 1 root root 13204 2月 22 08:57 access.log.3
-rw-r--r--. 1 root root 14240 2月 22 08:57 access.log.4
此时,如果access.log又达到了size的大小,同时version也达到了限制,此时会删除最早的access.log.0,并把access.log.1更改成 access.log.0,把access.log.2更改成access.log.1,以此类推。
view模块官方文档:
语句语法:
view view_name [ class ] {
match-clients { address_match_list } ;
match-destinations { address_match_list } ;
match-recursive-only <boolean> ;
[ view_option ; ... ]
[ zone_statement ; ... ]
} ;
视图是bind 9强大的新功能,允许名称服务器根据询问者的不同有区别的回答DNS查询。特别是当运行拆分DNS设置而不需要运行多个服务器时特别有用。每个视图定义了一个将会在用户的子集中见到的DNS名称空间。
根据用户的源地址("address_match_list")匹配视图定义的"match_clients"和用户的目的地址("address_match_list")匹配视图定义的"matach-destinations"。
如果没有被指定,match-clients和match-destinations默认匹配所有地址。一个视图也可以做为match-recursive-only来指定,意思是来自匹配用户的递归请求将会匹配该视图。视图语句的顺序是很重要的,一位用户的请求将会在它所匹配的第一个视图中被解答。在视图语句中定义的域只对匹配视图的用户是可用的。通过在多个视图中用相同名称定义一个域,不同域数据可以传给不同的用户。例如:在拆分DNS设置中的”内部”和”外部”用户。
许多在named.conf 的options里的语句中给出的选项也能在视图语句中使用,仅仅用于使用哪个视图解答请求的时候。当view-specific值没有给出,options里的语句值就使用默认值。域选项也可以在视图语句中指定默认值;这些view-specific默认值的优先级高于那些在options里面配置的语句。
视图精确到类。如果没有给定任何类,就假设为IN类。注意到所有非IN视图必须包含一个暗示域,因为只有IN类具有compiled-in默认暗示。
如果在配置文件中没有view语句,在IN类中就会自动产生一个默认视图匹配于任何用户,任何指定在配置文件的最高级的zone语句被看作是此默认视图的一部分。如果存在外部view语句,所有的域视图必须会在view语句内部产生。
示例:视图语句运行的拆分DNS设置
view "internal" {
match-clients { 10.0.0.0/8; };
// 应该与内部网络匹配.
// 只对内部用户提供递归服务.
// 提供example.com zone 的完全视图
//包括内部主机地址.
recursion yes;
zone "example.com" {
type master;
file "example-internal.db";
};
};
view "external" {
match-clients { any; };
// 拒绝对外部用户提供递归服务
// 提供一个example.com zone 的受限视图
// 只包括公共可接入主机
recursion no;
zone "example.com" {
type master;
file "example-external.db";
};
};
zone模块
官方文档:
语句语法:
zone <string> [ <class> ] {
in-view <string>;
};
zone <string> [ <class> ] {
type delegation-only;
};
zone <string> [ <class> ] {
type forward;
delegation-only <boolean>;
forward ( first | only );
forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ dscp <integer> ]; ... };
};
zone <string> [ <class> ] {
type hint;
check-names ( fail | warn | ignore );
delegation-only <boolean>;
file <quoted_string>;
};
zone <string> [ <class> ] {
type mirror;
allow-notify { <address_match_element>; ... };
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update-forwarding { <address_match_element>; ... };
also-notify [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
alt-transfer-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
alt-transfer-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
check-names ( fail | warn | ignore );
database <string>;
file <quoted_string>;
ixfr-from-differences <boolean>;
journal <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
multi-master <boolean>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;
notify-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
notify-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
primaries [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
request-expire <boolean>;
request-ixfr <boolean>;
transfer-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
transfer-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
try-tcp-refresh <boolean>;
use-alt-transfer-source <boolean>;
zero-no-soa-ttl <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};
zone <string> [ <class> ] {
type primary;
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update { <address_match_element>; ... };
also-notify [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
alt-transfer-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
alt-transfer-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
auto-dnssec ( allow | maintain | off );
check-dup-records ( fail | warn | ignore );
check-integrity <boolean>;
check-mx ( fail | warn | ignore );
check-mx-cname ( fail | warn | ignore );
check-names ( fail | warn | ignore );
check-sibling <boolean>;
check-spf ( warn | ignore );
check-srv-cname ( fail | warn | ignore );
check-wildcard <boolean>;
database <string>;
dialup ( notify | notify-passive | passive | refresh | <boolean> );
dlz <string>;
dnskey-sig-validity <integer>;
dnssec-dnskey-kskonly <boolean>;
dnssec-loadkeys-interval <integer>;
dnssec-policy <string>;
dnssec-secure-to-insecure <boolean>;
dnssec-update-mode ( maintain | no-resign );
file <quoted_string>;
forward ( first | only );
forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ dscp <integer> ]; ... };
inline-signing <boolean>;
ixfr-from-differences <boolean>;
journal <quoted_string>;
key-directory <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-out <integer>;
max-zone-ttl ( unlimited | <duration> );
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;
notify-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
notify-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
notify-to-soa <boolean>;
nsec3-test-zone <boolean>; // test only
parental-agents [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
parental-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
parental-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
serial-update-method ( date | increment | unixtime );
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ];
update-check-ksk <boolean>;
update-policy ( local | { ( deny | grant ) <string> ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ <string> ] <rrtypelist>; ... } );
zero-no-soa-ttl <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};
zone <string> [ <class> ] {
type redirect;
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
dlz <string>;
file <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-records <integer>;
max-zone-ttl ( unlimited | <duration> );
primaries [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
zone-statistics ( full | terse | none | <boolean> );
};
zone <string> [ <class> ] {
type secondary;
allow-notify { <address_match_element>; ... };
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
allow-transfer [ port <integer> ] [ transport <string> ] { <address_match_element>; ... };
allow-update-forwarding { <address_match_element>; ... };
also-notify [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
alt-transfer-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
alt-transfer-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
auto-dnssec ( allow | maintain | off );
check-names ( fail | warn | ignore );
database <string>;
dialup ( notify | notify-passive | passive | refresh | <boolean> );
dlz <string>;
dnskey-sig-validity <integer>;
dnssec-dnskey-kskonly <boolean>;
dnssec-loadkeys-interval <integer>;
dnssec-policy <string>;
dnssec-update-mode ( maintain | no-resign );
file <quoted_string>;
forward ( first | only );
forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ dscp <integer> ]; ... };
inline-signing <boolean>;
ixfr-from-differences <boolean>;
journal <quoted_string>;
key-directory <quoted_string>;
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-ixfr-ratio ( unlimited | <percentage> );
max-journal-size ( default | unlimited | <sizeval> );
max-records <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-idle-out <integer>;
max-transfer-time-in <integer>;
max-transfer-time-out <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
multi-master <boolean>;
notify ( explicit | master-only | primary-only | <boolean> );
notify-delay <integer>;
notify-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
notify-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
notify-to-soa <boolean>;
nsec3-test-zone <boolean>; // test only
parental-agents [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
parental-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
parental-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
primaries [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
request-expire <boolean>;
request-ixfr <boolean>;
sig-signing-nodes <integer>;
sig-signing-signatures <integer>;
sig-signing-type <integer>;
sig-validity-interval <integer> [ <integer> ];
transfer-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
transfer-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
try-tcp-refresh <boolean>;
update-check-ksk <boolean>;
use-alt-transfer-source <boolean>;
zero-no-soa-ttl <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};
zone <string> [ <class> ] {
type static-stub;
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
forward ( first | only );
forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ dscp <integer> ]; ... };
max-records <integer>;
server-addresses { ( <ipv4_address> | <ipv6_address> ); ... };
server-names { <string>; ... };
zone-statistics ( full | terse | none | <boolean> );
};
zone <string> [ <class> ] {
type stub;
allow-query { <address_match_element>; ... };
allow-query-on { <address_match_element>; ... };
check-names ( fail | warn | ignore );
database <string>;
delegation-only <boolean>;
dialup ( notify | notify-passive | passive | refresh | <boolean> );
file <quoted_string>;
forward ( first | only );
forwarders [ port <integer> ] [ dscp <integer> ] { ( <ipv4_address> | <ipv6_address> ) [ port <integer> ] [ dscp <integer> ]; ... };
masterfile-format ( raw | text );
masterfile-style ( full | relative );
max-records <integer>;
max-refresh-time <integer>;
max-retry-time <integer>;
max-transfer-idle-in <integer>;
max-transfer-time-in <integer>;
min-refresh-time <integer>;
min-retry-time <integer>;
multi-master <boolean>;
primaries [ port <integer> ] [ dscp <integer> ] { ( <remote-servers> | <ipv4_address> [ port <integer> ] | <ipv6_address> [ port <integer> ] ) [ key <string> ] [ tls <string> ]; ... };
transfer-source ( <ipv4_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
transfer-source-v6 ( <ipv6_address> | * ) [ port ( <integer> | * ) ] [ dscp <integer> ];
use-alt-transfer-source <boolean>;
zone-statistics ( full | terse | none | <boolean> );
};
区域类型说明:
type (delegation-only, forward, hint, mirror, primary, redirect, secondary, static-stub, stub)
上面[class] 一般默认指IN类型。
针对区域说明:
type hint:根提示
根NS的设置,也就是根域的服务器设置。因为我们知道,客户端从指定的NS上找不到记录后,将会出现两种情况,一种向根域服务器请求查询。一种将请求转发到上一级NS服务器。这里的设置是指第一种。
// 根提示常规配置
zone "." IN {
type hint;
file "/usr/local/bind/etc/named.root"; // named.root文件可从上篇文章提供的地方下载根域名服务器RR
};
Tips:hint只针对.域进行设置
type primary:主要服务器
这是一个主从结构,也是最常用的,和我们平时所说的主从是一个意思,一般情况下,一个域名解析会使用2个NS,其实这里就是主从,防止单点故障,当然也可以一主多从。举例说明:
zone "abc.com" IN {
type primary;
file "/usr/local/bind/etc/named.abc.com"; // RR记录文件名称可以自定义 最好取有意义名称
};
named.abc.com中的内容到底是什么样的?看下面的注解:
FQDN的写法:
$TTL 600
@ IN SOA primary.abc.com. admin.abc.com. ( 2022120802 3H 15M 1W 1D )
@ IN NS primary.abc.com.
primary.abc.com. IN A 192.168.10.200
@ IN MX 10 www.abc.com.
www.abc.com. IN A 192.168.10.121
bbs.abc.com. IN CNAME www.abc.com.
ftp.abc.com. IN CNAME www.abc.com.
linux.abc.com. IN CNAME www.abc.com.
secondary.abc.com. IN A 192.168.10.201
122.abc.com. IN A 192.168.10.122
# 其中2022120802 3H 15M 1W 1D,分别是serial,refresh,retry,expire,Minimum
serial 格式一般默认按照年-月-日期-序号表示,序号代表更改的版本
简写:
$TTL 600
@ IN SOA primary.abc.com. admin.abc.com.( 2022120802 3H 15M 1W 1D )
@ IN NS primary
primary IN A 192.168.10.200
@ IN MX 10 www
www IN A 192.168.10.121
bbs IN CNAME www
ftp IN CNAME www
linux IN CNAME www
secondary IN A 192.168.10.201
122 IN A 192.168.10.122
简写不太容易看明白,而FQDN的写法,又太啰嗦,而且要注意.(点号),所以我个人偏好喜欢这样的写法。
$TTL 600
@ IN SOA primary.abc.com. admin.abc.com.( 2022120802 3H 15M 1W 1D )
@ IN NS primary.abc.com.
master IN A 192.168.10.200
@ IN MX 10 www.abc.com.
www IN A 192.168.10.121
bbs IN CNAME www.abc.com.
ftp IN CNAME www.abc.com.
linux IN CNAME www.abc.com.
secondary IN A 192.168.10.201
122 IN A 192.168.10.122
RR记录更新策略:
;Refresh >= Retry *2
;Refresh Retry < Expire
;Expire >= Rrtry * 10
;Expire >= 7Days ;
RR参数介绍:
- primary.abc.com. admin.abc.com. :这里是SOA的固定格式,这里有两部分内容,中间用空格隔开,前半部分:zone的主 DNS 服务器的主机名,后半部分:管理zone的负责人的电子邮件地址。在该电子邮件名称中使用英文句点 (.) 代替“at”符号 (@);
- $TTL 指令:该zone的缓存时间;
- Serial:数值Serial代表这个zone的序列号,序号越大表明资料越新,主要用在 primary / secondary 同步使用,每次zone文件更新,都需要修改Serial数值。RFC1912 2.2建议的格式为YYYYMMDDnn 其中nn为修订号,,但修订号的最大值不能大于2的32次方,即4294967296;
- Refresh:数值Refresh设置secondary DNS多长时间与primary Server进行Serial核对。目前bind的notify参数可设置每次primary DNS更新都会主动通知secondary DNS更新,Refresh参数主要用于notify参数关闭时;
- Retry:数值Retry设置当Slave DNS试图获取Master DNS Serial时,如果Master DNS未响应,多长时间重新进行检查;
- Expire:如果primary / secondary在1周内都链接失败,secondary将不再尝试链接primary,但注意,此时secondary还会继续提供解析服务,只是数据不在更新。
- Minimum:在 8.2版本之前,由于没有独立的 $TTL 指令,所以通过 SOA 最后一个字段来实现。但由于 BIND 8.2 后出现了 $TTL 指令,该部分功能就不再由 SOA 的最后一个字段来负责,由 $TTL 全权负责,SOA 的最后一个字段专门负责 Negative Answer TTL(Negative Caching)
反向解析配置:
zone "10.168.192.in-addr.arpa" IN {
type primary;
file "/usr/local/bind/etc/named.192.168.10";
allow-update { none; };
};
cat /usr/local/bind/etc/named.192.168.10
$TTL 600
@ IN SOA primary.abc.com. admin.abc.com.( 2022120802 3H 15M 1W 1D )
@ IN NS primary.abc.com.
200 IN PTR primary.abc.com.
201 IN PTR secondary.abc.com.
121 IN PTR www.abc.com.
122 IN PTR 122.abc.com.
# 这里不再重复介绍,将正解的A换成PTR即可
如果反向解析配置文件变成这样:
zone "168.192.in-addr.arpa" IN {
type primary;
file "/usr/local/bind/etc/named.192.168.10";
allow-update { none; };
};
那相应的 /usr/local/bind/etc/named.192.168.10 的文件也相应的调整:
$TTL 600
@ IN SOA primary.abc.com. admin.abc.com.( 2022120802 3H 15M 1W 1D )
@ IN NS primary.abc.com.
200.10 IN PTR primary.abc.com. //注意是110.10,而不是10.110
201.10 IN PTR secondary.abc.com.
121.10 IN PTR www.abc.com.
122.10 IN PTR 122.abc.com.
type secondary:次要服务器
和primary很相似,有几个不同点,secondary不需要配置 named.192.168.20 和 named.abc.com 文件,因为secondary启动成功后,会自动同步primary里面的RR记录。在named.conf中的配置也不一样,注意比较:
zone "abc.com" IN {
type secondary;
file "/usr/local/bind/etc/named.abc.com";
primarys {192.168.10.200;};
};
zone "10.168.192.in-addr.arpa" IN {
type secondary;
file "/usr/local/bind/etc/named.192.168.10";
allow-update { none; };
primarys {192.168.10.200;};
};
type forward:区域转发
zone "itkmi.org" IN {
type forward;
forward first; // only和first
forwarders {10.0.2.3;};
};
此时访问 itkmi.org 这个 zone 将转发给10.0.2.3来处理。
forward
- 此选项只有当forwarders 列表中有内容的时候才有意义。当值是 first,默认情况下,使服务器先查询设置的forwarders,如果它没有得到回答,服务器就会查询全局options转发器寻找答案。如果设定的是 only,服务器就只会把请求转发到指定的服务器上去。
forwarders
- 设定转发使用的 ip 地址。默认的列表是空的( 不转发)。转发也可以设置在每个域上,这样全局选项options中的转发设置就不会起作用了。用户可以将不同的域转发到服务器上,或者对不同的域可以实现 forward only 或 first 的不同方式,也可以根本就不转发。
options 语句设立可以被整个 bind 使用的全局选项。这个语句在每个配置文件中只有一处。如果出现多个 options 语句,则第一个 options 的配置有效,并且会产生一个警告信息。如果没有 options 语句,每个选项择使用缺省值。
options模块一般情况下,我会创建一个文件 named.conf.options 利用include引入,如下文件所示:
/usr/local/bind/etc/bind/named.conf.options
options {
version "not currently available";
directory "/usr/local/bind";
pid-file "/usr/local/bind/var/run/named.pid";
recursion no;
allow-query { any; };
allow-query-cache { none; };
listen-on port 53 { 192.168.10.201; };
forwarders {
223.5.5.5;
114.114.114.114
};
forward only;
dnssec-validation no;
listen-on-v6 { none; };
auth-nxdomain no;
};
options 子句语法说明:
# 内存统计信息保存文件路径名 默认 named.memstats
memstatistics-file "/usr/local/bind/var/run/named.memstats";
# 进程ID文件的路径名
pid-file "/usr/local/bind/var/run/named.pid";
# 递归查询转储的文件路径名 默认 named.recursing
recursing-file "/usr/local/bind/var/run/named.recursing";
# 统计信息文件路径名
statistics-file "/usr/local/bind/var/run/named.stats";
# DNSSEC启用管理密钥路径名 默认 /etc/bind.keys
bindkeys-file "/usr/local/bind/etc/bind.keys";
# 接收和发送 DNS-over-TLS 协议流量的 TCP 端口号。默认值为 853
tls-port 853
# 接收和发送 DNS 协议流量的 UDP/TCP 端口号。默认为53
port 53
# 接收和发送 DNS-over-HTTPS 协议流量的 TCP 端口号。默认值为 443
https-port
# 通过 HTTP 接收和发送未加密的 DNS 流量的 TCP 端口号
http-port
# 设定哪个主机可以允许递归
allow-recursion { <address_match_element>; ... };
# 设定哪个主机可以允许递归 用于多主配置
allow-recursion-on { <address_match_element>; ... };
# 设定哪个主机可以进行普通的查询 默认 any
allow-query { <address_match_element>; ... };
# 设定哪个主机可以进行普通的查询 用于多主配置 默认 any
allow-query-on { <address_match_element>; ... };
# 设定哪个主机可以进行普通的缓存查询 默认 any
allow-query-cache { <address_match_element>; ... };
# 是设定哪个主机可以进行普通的缓存查询 用于多主配置 默认 any
allow-query-cache-on { <address_match_element>; ... };
# 这指定允许哪些主机向该区域提交动态 DNS 更新 默认是拒绝来自所有主机的更新
allow-update { <address_match_element>; ... };
# 这指定允许哪些主机提交动态 DNS 更新并将它们转发到主要区域。默认为,表示不执行更新转发
allow-update-forwarding { <address_match_element>; ... };
# DNS黑洞 指定了服务器不接受查询或用于解析查询的地址列表 默认 none
blackhole { <address_match_element>; ... };
# 设定哪台主机允许和本地服务器进行域传输,默认 any
allow-transfer { <address_match_element>; ... };
# 是否允许递归
recursion yes | no;
# IPv4监听端口
listen-on port 53
listen-on port 53 { 192.168.10.201; }; // 监听该地址端口
# IPv6监听端口
listen-on-v6 port 53
# 是否显示版本信息 建议关闭
version "not currently available";
# 服务器运行工作目录
directory "/usr/local/bind";
# 关闭DNSSEC
dnssec-validation no;
# 定义全局转发器 forward ( first | only ); only代表只转发 first代表转发服务器查询不到 允许回退递归
forwarders {
223.5.5.5;
114.114.114.114
};
官方文档查询:
关于DNS介绍到此,DNS服务实现有很多可选方案,除了bind 9,还有如下DNS方案:
CoreDNS:Go语言编写,适合K8s环境,对云原生支持较好,简单灵活。
Dnsmasq:C语言编写,开源轻量级,适合针对家庭局域网等小型局域网设计,资源占用低,易于配置。
PowerDNS:C 语言编写,开源全面,数据库代替域文件,Web管理方便。
Microsoft DNS:C语言编写,不开源,内部企业使用域环境比较适合,比较全面。
bind 9就是最重量级的嘉宾,互联网基石,由C语言编写,支持的系统全面,部署广泛,稳定性好,配置复杂功能全面。
bind 9还可以利用Web页面进行域名记录的增删改查管理,结合webmin管理bind 9,具体请查看:
后面介绍下PowerDNS和其配套应用,敬请期待,更多精彩可关注公众号:网络小斐。