场景假设:
我们要为内部网络 192.168.1.0/24
搭建一个权威 DNS 服务器。
- 域名:
mylab.local
- DNS 服务器 IP:
192.168.1.10
- 我们将配置正向解析 (hostname -> IP) 和反向解析 (IP -> hostname)。
一、安装 BIND9
- 更新系统并安装 BIND 及工具:
sudo yum update -y sudo yum install -y bind bind-utils
bind
: BIND9 服务器软件包。bind-utils
: 包含dig
,nslookup
,named-checkconf
,named-checkzone
等实用工具。
二、配置 BIND9 (named.conf
)
BIND 的主配置文件是 /etc/named.conf
。CentOS 上的 named.conf
通常会包含其他配置文件,如 named.rfc1912.zones
,我们将在这里定义我们的区域。
-
编辑主配置文件
/etc/named.conf
:sudo vi /etc/named.conf
修改
options
部分:options { listen-on port 53 { 127.0.0.1; 192.168.1.10; }; // 监听本地和服务器的内网IP listen-on-v6 port 53 { ::1; }; // 如果不需要IPv6,可以设为 none directory "/var/named"; // 区域文件和其他数据的工作目录 dump-file "/var/named/data/cache_dump.db"; statistics-file "/var/named/data/named_stats.txt"; memstatistics-file "/var/named/data/named_mem_stats.txt"; recursing-file "/var/named/data/named.recursing"; secroots-file "/var/named/data/named.secroots"; allow-query { localhost; 192.168.1.0/24; }; // 允许哪些IP查询 (这里是本地和内网) /* * 如果你正在构建一个权威的DNS服务器,你不希望它也为其他人执行递归查询。 * 如果你有一个内部网络,并且希望你的DNS服务器也为你的内部客户端解析外部名称, * 那么你需要设置 allow-recursion 并可能配置 forwarders。 * 对于纯权威服务器,recursion应为no。 */ recursion no; // 作为权威服务器,通常不提供递归查询给外部 dnssec-enable yes; dnssec-validation yes; /* Path to ISC DLV key */ bindkeys-file "/etc/named.iscdlv.key"; managed-keys-directory "/var/named/dynamic"; pid-file "/run/named/named.pid"; session-keyfile "/run/named/session.key"; /* https://fedoraproject.org/wiki/Changes/CryptoPolicy */ include "/etc/crypto-policies/back-ends/bind.config"; }; logging { channel default_debug { file "data/named.run"; severity dynamic; }; }; // 默认会包含这个文件,我们将在其中定义我们的区域 include "/etc/named.rfc1912.zones"; include "/etc/named.root.key";
关键修改点:
listen-on port 53 { 127.0.0.1; 192.168.1.10; };
: 让 BIND 监听服务器的内网 IP 地址192.168.1.10
上的 DNS 请求。allow-query { localhost; 192.168.1.0/24; };
: 允许来自本地和192.168.1.0/24
网段的查询。recursion no;
: 非常重要! 作为权威服务器,我们不希望它为公共网络提供递归查询服务,这会使其成为 DDoS 放大攻击的目标。如果你的服务器也需要为内部客户端提供递归,那么这里可以设为yes
,并且allow-recursion
需要精确配置。
-
定义区域 (编辑
/etc/named.rfc1912.zones
):
这个文件默认包含了一些模板,我们可以在文件末尾添加我们的区域定义。sudo vi /etc/named.rfc1912.zones
在文件末尾添加以下内容:
// 正向解析区域 mylab.local zone "mylab.local" IN { type master; // 主服务器 file "forward.mylab.local"; // 区域数据文件名 (相对于 /var/named/) allow-update { none; }; // 禁止动态更新 (除非你需要) allow-transfer { none; }; // 禁止区域传送 (除非你有从服务器) }; // 反向解析区域 1.168.192.in-addr.arpa (对应 192.168.1.0/24) zone "1.168.192.in-addr.arpa" IN { type master; file "reverse.mylab.local"; allow-update { none; }; allow-transfer { none; }; };
forward.mylab.local
和reverse.mylab.local
是我们将要创建的区域数据文件的名称。
三、创建区域文件
区域文件存放在 /var/named/
目录下。
-
创建正向区域文件
/var/named/forward.mylab.local
:sudo vi /var/named/forward.mylab.local
添加以下内容:
$TTL 86400 ; 1 day @ IN SOA ns1.mylab.local. admin.mylab.local. ( 2023072001 ; Serial (YYYYMMDDNN format, 每次修改必须增加) 3600 ; Refresh (1 hour) 1800 ; Retry (30 minutes) 604800 ; Expire (1 week) 86400 ; Minimum TTL (1 day) ) ; Name Servers @ IN NS ns1.mylab.local. ; A Records for Name Servers ns1 IN A 192.168.1.10 ; Other A Records server1 IN A 192.168.1.100 client1 IN A 192.168.1.101 www IN CNAME server1.mylab.local.
注意:
ns1.mylab.local.
和admin.mylab.local.
末尾的.
非常重要,表示这是一个完全限定域名 (FQDN)。admin.mylab.local.
中的第一个.
代表@
符号,所以实际邮箱是admin@mylab.local
。- 序列号 (Serial) 每次修改区域文件时必须增加,否则从服务器(如果有的话)不会同步更新。
-
创建反向区域文件
/var/named/reverse.mylab.local
:sudo vi /var/named/reverse.mylab.local
添加以下内容:
$TTL 86400 @ IN SOA ns1.mylab.local. admin.mylab.local. ( 2023072001 ; Serial 3600 ; Refresh 1800 ; Retry 604800 ; Expire 86400 ; Minimum TTL ) ; Name Server @ IN NS ns1.mylab.local. ; PTR Records (IP的最后一位) 10 IN PTR ns1.mylab.local. ; 192.168.1.10 100 IN PTR server1.mylab.local. ; 192.168.1.100 101 IN PTR client1.mylab.local. ; 192.168.1.101
-
设置区域文件权限:
BIND 进程 (通常以named
用户运行) 需要能够读取这些文件。sudo chown root:named /var/named/forward.mylab.local sudo chown root:named /var/named/reverse.mylab.local sudo chmod 640 /var/named/forward.mylab.local sudo chmod 640 /var/named/reverse.mylab.local
四、检查配置和启动服务
-
检查主配置文件语法:
sudo named-checkconf /etc/named.conf
如果没有任何输出,表示语法正确。
-
检查区域文件语法:
sudo named-checkzone mylab.local /var/named/forward.mylab.local sudo named-checkzone 1.168.192.in-addr.arpa /var/named/reverse.mylab.local
输出应类似:
zone mylab.local/IN: loaded serial 2023072001
OK
-
启动并设置 BIND 开机自启:
sudo systemctl start named sudo systemctl enable named sudo systemctl status named
确保服务状态是
active (running)
。 -
配置防火墙:
允许 DNS 查询 (UDP 和 TCP 端口 53)。sudo firewall-cmd --permanent --add-service=dns sudo firewall-cmd --reload
如果你没有使用
firewalld
,而是iptables
,命令会是:sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 53 -j ACCEPT sudo service iptables save # 或等效命令保存规则
五、测试 DNS 解析
-
在 DNS 服务器本机测试:
dig @localhost server1.mylab.local dig @localhost www.mylab.local dig @localhost -x 192.168.1.100
你应该能看到正确的 A 记录、CNAME 记录和 PTR 记录。
-
在内部网络中的其他客户端测试:
- 修改客户端的 DNS 服务器设置为
192.168.1.10
。- 在 Linux 客户端,可以修改
/etc/resolv.conf
(临时) 或网络管理器的配置。 - 在 Windows 客户端,修改网络适配器的 DNS 设置。
- 在 Linux 客户端,可以修改
- 然后使用
nslookup
或dig
测试:nslookup server1.mylab.local nslookup 192.168.1.100
- 修改客户端的 DNS 服务器设置为
六、经典案例:权威主服务器 + 缓存递归
上面的案例是一个纯粹的权威服务器。一个更常见的内部网络案例是,DNS 服务器既作为内部域名的权威服务器,也为内部客户端提供对外部域名的递归查询服务。
修改配置:
/etc/named.conf
中的options
:options { listen-on port 53 { 127.0.0.1; 192.168.1.10; }; // ... 其他选项 ... allow-query { localhost; 192.168.1.0/24; }; recursion yes; // 启用递归 allow-recursion { localhost; 192.168.1.0/24; }; // 允许内网递归 // 可选:配置转发器,如果不想让BIND直接查询根服务器 // forwarders { // 8.8.8.8; // Google DNS // 1.1.1.1; // Cloudflare DNS // }; // forward only; // 如果设置了forwarders,是只转发还是先转发再自己递归 // ... 其他选项 ... };
- 区域定义 (
/etc/named.rfc1912.zones
) 和区域文件保持不变。 - 重启
named
服务。
现在,你的 BIND 服务器不仅能解析 mylab.local
,还能为 192.168.1.0/24
网段的客户端解析如 www.google.com
这样的外部域名。
七、常见问题及解决方法
-
问题:
named
服务启动失败。- 原因: 配置文件语法错误、区域文件错误、权限问题、端口被占用。
- 解决:
sudo named-checkconf /etc/named.conf
检查主配置。sudo named-checkzone <zone_name> <zone_file_path>
检查区域文件。- 查看日志:
sudo journalctl -u named -f
或/var/log/messages
(取决于系统日志配置)。 - 检查文件权限:
named
用户(通常是named
)需要读取配置文件和区域文件,以及写入/var/named/data
和/run/named/
目录。 sudo netstat -tulnp | grep :53
检查端口 53 是否被其他程序占用。
-
问题:客户端无法解析域名,或解析到错误 IP。
- 原因: 防火墙阻止、
allow-query
配置错误、客户端 DNS 设置错误、区域文件记录错误、缓存问题。 - 解决:
- 检查服务器防火墙是否允许 UDP/TCP 53 端口。
- 确认
named.conf
中的listen-on
和allow-query
设置正确。 - 确认客户端的 DNS 服务器指向了正确的 BIND 服务器 IP。
- 仔细检查区域文件中的记录,特别是 IP 地址和主机名。
- 清除客户端 DNS 缓存 (Windows:
ipconfig /flushdns
, Linux: 可能需要重启nscd
或systemd-resolved
)。 - 在服务器上使用
dig @localhost <domain>
测试。
- 原因: 防火墙阻止、
-
问题:修改区域文件后,解析结果没有更新。
- 原因: 未增加 SOA 记录中的序列号、未重载 BIND 配置/区域。
- 解决:
- 每次修改区域文件后,务必增加 SOA 记录中的序列号!
- 重载 BIND:
sudo rndc reload
或sudo systemctl reload named
。 - 如果只想重载特定区域:
sudo rndc reload mylab.local
。
-
问题:
rndc: connect failed: 127.0.0.1#953: connection refused
- 原因:
rndc
控制通道未正确配置或named
未监听控制端口。 - 解决:
- 确保
/etc/named.conf
中有controls
块,并且引用了正确的rndc.key
文件。通常 CentOS 默认配置是好的。include "/etc/rndc.key"; // 或 /etc/named.conf 中直接定义 key controls { inet 127.0.0.1 port 953 allow { 127.0.0.1; } keys { "rndc-key"; }; // "rndc-key" 是在 rndc.key 中定义的名称 };
- 确保
/etc/rndc.key
文件存在且权限正确 (通常named
用户可读)。 - 如果
rndc.key
不存在或有问题,可以尝试重新生成:sudo rndc-confgen -a -c /etc/rndc.key
(注意备份旧文件)。
- 确保
- 原因:
-
问题:SELinux 阻止 BIND 操作。
- 原因: SELinux 策略可能阻止
named
写入某些文件(如区域文件,如果配置了动态更新或主文件在非标准位置)或绑定到某些端口。 - 解决:
- 查看审计日志:
sudo ausearch -m avc -ts recent
。 - 如果
named
需要写主区域文件(不常见,除非是动态更新或特殊配置):
sudo setsebool -P named_write_master_zones on
- 如果区域文件或日志文件上下文不正确,可以使用
restorecon
:
sudo restorecon -Rv /var/named/
sudo restorecon -Rv /etc/named.conf
- 或者,临时将 SELinux 设置为 permissive 模式进行调试:
sudo setenforce 0
(不推荐在生产环境长期使用)。
- 查看审计日志:
- 原因: SELinux 策略可能阻止
-
问题:区域传送 (Zone Transfer) 失败。
- 原因: 主服务器
allow-transfer
未配置或配置错误;从服务器masters
配置错误;防火墙阻止;主服务器未正确加载区域。 - 解决:
- 在主服务器的
zone
定义中,allow-transfer { <slave_ip>; };
。 - 在从服务器的
zone
定义中,masters { <master_ip>; };
。 - 确保主从服务器之间 TCP 端口 53 可达。
- 检查主服务器日志,确认区域已成功加载且序列号正确。
- 在主服务器的
- 原因: 主服务器
八、改进和进阶
-
从服务器 (Slave/Secondary DNS):
- 为提高可用性和冗余,应至少配置一个从 DNS 服务器。
- 从服务器从主服务器复制区域数据。
- 主服务器配置
allow-transfer { <slave_ip>; };
和also-notify { <slave_ip>; };
。 - 从服务器配置
type slave;
和masters { <master_ip>; };
。
-
DNSSEC (Domain Name System Security Extensions):
- 通过数字签名来验证 DNS 数据的真实性和完整性,防止 DNS 欺骗和缓存投毒。
- 配置 DNSSEC 相对复杂,涉及密钥生成、区域签名、信任锚配置等。
-
视图 (Views):
- 实现 Split DNS (或 Split Horizon DNS),根据客户端的源 IP 地址提供不同的 DNS 应答。
- 例如,内部客户端解析
server.mylab.local
得到私有 IP,外部客户端解析得到公共 IP。
-
更精细的日志记录:
- 在
named.conf
的logging
部分配置不同的通道 (channel) 和类别 (category),将不同类型的日志(如查询日志、安全日志、区域加载日志)输出到不同文件或 syslog,并设置不同级别。 - 注意: 查询日志 (
category queries
) 会产生大量数据,通常仅用于调试。
- 在
-
安全加固:
- 隐藏版本号: 在
options
中添加version "not available";
。 - 响应速率限制 (RRL - Response Rate Limiting): 帮助缓解某些类型的 DNS 放大攻击。需要在
options
中配置rate-limit { ... };
。 - 定期更新 BIND: 及时修补已知的安全漏洞。
- 最小权限原则: 确保
named
进程以非 root 用户运行。
- 隐藏版本号: 在
-
监控:
- 使用监控工具 (如 Nagios, Zabbix, Prometheus) 监控 BIND 服务的可用性、响应时间、区域序列号等。
- BIND 自身也提供统计信息,可以通过
rndc stats
查看,或配置statistics-channel
。
-
使用
rndc
管理:- 熟悉
rndc
命令,如rndc reload
,rndc reconfig
,rndc flush
,rndc status
,rndc querylog on/off
等,避免不必要的服务重启。
- 熟悉
这个实战案例和相关信息应该能帮助你成功部署和管理 CentOS 7 上的 BIND9 服务器。记住,DNS 是一个关键的基础服务,仔细规划和测试非常重要。