在做一些实验时,经常需要一个内网的DNS服务器。本文详细描述了构建整个DNS服务器的过程。
强烈推荐在安装任何服务之前先把SELinux和iptables(也就是防火墙)暂时禁止掉,这样的话我们可以专注于安装服务本身,而不会被各种SELinux上下文和防火墙规则所干扰。
在全部服务都安装好之后,你可以根据需要,开启SELinux和iptables。注意,本文不包含SELinux和iptables的配置。
# vim /etc/sysconfig/selinux
SELINUX=disabled # 由enforcing 改成 disabled
# iptables -F
# iptables -L
# service iptables save
也可以彻底关闭iptables服务:
# service iptables stop
# chkconfig iptables off
之所以打开这个功能,是因为我想把Linux当做一个路由器来用。
# vim /etc/sysctl.conf
net.ipv4.ip_forward = 1 #修改:由0改成1
# sysctl -p
为了让SELinux的禁用的设置生效,必须重启机器。
如下图所示:
这里不使用图形界面,使用命令行的方式来配置。
首先配置一下IP(192.168.0.2)以及相关的参数(因为我的虚拟机有多个网卡,这里用第二个网卡 eth1 来进行配置)。
# vim /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
TYPE=Ethernet
UUID=06dbc3e2-4d24-4cb5-9b24-89c166a71e5a
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=none
HWADDR=08:00:27:6D:CA:57
IPADDR=192.168.0.2
NETMASK=255.255.255.0
PREFIX=24
DEFROUTE=no
IPV4_FAILURE_FATAL=yes
IPV6INIT=no
NAME="System eth1"
HWADDR=08:00:27:C6:79:2B
MTU=1500
UUID=9c92fad9-6ecb-3e6c-eb4d-8a47c6f50c04
LAST_CONNECT=1409908255
重启网络服务,并查看eth1的配置信息:
# service network restart
# ip addr show eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 08:00:27:c6:79:2b brd ff:ff:ff:ff:ff:ff
inet 192.168.0.2/24 brd 192.168.0.255 scope global eth1
inet6 fe80::a00:27ff:fec6:792b/64 scope link
valid_lft forever preferred_lft forever
```language
修改主机名(server.example.com),先:
# vim /etc/sysconfig/network
NETWORKING=yes
HOSTNAME=server.example.com
再:
# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.0.2 server.example.com
重启,使 hostname 生效:
# reboot
使用yum进行安装:
# yum -y install bind bind-chroot
编写一个 chroot(/root/bind-chroot-admin)脚本,内容如下:
#!/bin/sh
#bind-chroot install check
rpm -q bind-chroot > /dev/null 2>&1
[ $? -ne 0 ] && echo bind-chroot not install && exit 1
# bind-chroot enabled
sed -i '/^ROOTDIR=/d' /etc/sysconfig/named
echo ROOTDIR=/var/named/chroot >> /etc/sysconfig/named
# file copy
filelist=`mktemp`
rpm -ql bind|grep ^/etc >> ${filelist}
rpm -ql bind|grep ^/var >> ${filelist}
for file in `cat ${filelist}`
do
# directory make
if [ -d ${file} ]; then
DIRNAME=/var/named/chroot${file}
[ ! -d ${DIRNAME} ] && mkdir -p ${DIRNAME}
fi
# file copy
if [ -f ${file} ]; then
DIRNAME=/var/named/chroot`dirname ${file}`
[ ! -d ${DIRNAME} ] && mkdir -p ${DIRNAME}
/bin/cp -a ${file} ${DIRNAME}
fi
done
rm -f ${filelist}
chown named:named /var/named/chroot/var/named/data
chmod 770 /var/named/chroot/var/named/data
chown named:named /var/named/chroot/var/named/dynamic
exit
执行此脚本:
# sh bind-chroot-admin
//
// named.conf
//
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS
// server as a caching only nameserver (as a localhost DNS resolver only).
//
// See /usr/share/doc/bind*/sample/ for example named configuration files.
//
options {
#listen-on port 53 { 127.0.0.1; }; #注释掉
#listen-on-v6 port 53 { ::1; }; #注释掉
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";
allow-query { localhost; localnets; }; # 修改: 添加 localnets
recursion yes;
empty-zones-enable no; #追加: 启动时对于空的zone的错误日志不输出
dnssec-enable no; #修改: yes -> no, 不使用DNSSEC
dnssec-validation no; #修改: yes -> no, 不使用DNSSEC
#dnssec-lookaside auto; #注释掉
/* Path to ISC DLV key */
bindkeys-file "/etc/named.iscdlv.key";
forwarders{ #追加
192.168.0.2; #追加: 路由器的IP,我把本机当路由了
}; #追加
managed-keys-directory "/var/named/dynamic";
};
logging {
channel default_debug {
file "data/named.run";
severity dynamic;
};
category lame-servers { null; }; #追加
};
view "internal" { #追加
match-clients { localnets; }; #追加
match-destinations { localnets; }; #追加
zone "." IN {
type hint;
file "named.ca";
};
include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";
include "/etc/named.example.com.zone"; #追加
}; #追加
view "external" { #追加,可选,如果你的DNS服务器不准备连接外网的话,这里不用写
match-clients { any; };#追加,可选,如果你的DNS服务器不准备连接外网的话,这里不用写
match-destinations { any; };#追加,可选,如果你的DNS服务器不准备连接外网的话,这里不用写
recursion no; #追加,可选,如果你的DNS服务器不准备连接外网的话,这里不用写
include "/etc/named.example.com.zone.wan"; #追加:注意这里和你的域名做相应的调整,,可选,如果你的DNS服务器不准备连接外网的话,这里不用写
}; #追加,可选,如果你的DNS服务器不准备连接外网的话,这里不用写
文件名:/var/named/chroot/etc/named.example.com.zone
zone "example.com" {
type master;
file "example.com.db";
};
zone "0.168.192.in-addr.arpa" {
type master;
file "0.168.192.in-addr.arpa.db";
};
文件名:/var/named/chroot/etc/named.example.com.zone.wan
如果你的DNS服务器不打算接入Internet的话,这个文件不需要。
zone "example.com" {
type master;
file "example.com.db.wan";
allow-query { any; };
};
zone "1.168.192.in-addr.arpa" {
type master;
file "1.168.192.in-addr.arpa.db";
allow-query { any; };
};
文件名:/etc/sysconfig/named
OPTIONS="-4" # 在文件的最后加入这行
再次提醒,如果你只是内网使用DNS的话,这一小节的内容请无视。
# dig . ns @198.41.0.4 +bufsize=1024 > /var/named/chroot/var/named/named.ca
为了方便起见,可以使用一个自动脚(named.root_update)本来跟新根DNS域名服务器的列表:
#!/bin/bash
new=`mktemp`
errors=`mktemp`
dig . ns @198.41.0.4 +bufsize=1024 > $new 2> $errors
if [ $? -eq 0 ]; then
sort_new=`mktemp`
sort_old=`mktemp`
diff_out=`mktemp`
sort $new > $sort_new
sort /var/named/chroot/var/named/named.ca > $sort_old
diff --ignore-matching-lines=^\; $sort_new $sort_old > $diff_out
if [ $? -ne 0 ]; then
(
echo '-------------------- old named.root --------------------'
cat /var/named/chroot/var/named/named.ca
echo
echo '-------------------- new named.root --------------------'
cat $new
echo '---------------------- difference ----------------------'
cat $diff_out
) | mail -s 'named.root updated' root
cp -f $new /var/named/chroot/var/named/named.ca
chown named. /var/named/chroot/var/named/named.ca
chmod 644 /var/named/chroot/var/named/named.ca
/etc/rc.d/init.d/named restart > /dev/null
fi
rm -f $sort_new $sort_old $diff_out
else
cat $errors | mail -s 'named.root update check error' root
fi
rm -f $new $errors
然后让这个脚本可执行;
# chmod 700 named.root_update
最后让这个脚本每个月自动执行(前提是你的crond已经打开):
# mv named.root_update /etc/cron.monthly/
也就是从域名到IP地址的解析关系。
文件名:/var/named/chroot/var/named/example.com.db
$TTL 86400
@ IN SOA example.com. root.example.com.(
2013120801; Serial
28800 ; Refresh
14400 ; Retry
3600000 ; Expire
86400 ) ; Minimum
IN NS example.com.
IN MX 10 example.com.
@ IN A 192.168.0.2
* IN A 192.168.0.2
dns IN A 192.168.0.2
server IN A 192.168.0.2
ldap IN A 192.168.0.2
www IN A 192.168.0.2
mail IN A 192.168.0.2
ftp IN A 192.168.0.2
sgd-server IN A 192.168.0.3
win IN A 192.168.0.4
lin IN A 192.168.0.5
sol IN A 192.168.0.6
wins IN A 192.168.0.7
也就是从IP到域名的关系。
文件名:/var/named/chroot/var/named/0.168.192.in-addr.arpa.db
$TTL 86400
@ IN SOA example.com. root.example.com.(
2013120801 ; Serial
28800 ; Refresh
14400 ; Retry
3600000 ; Expire
86400 ) ; Minimum
IN NS example.com.
2 IN PTR example.com.
2 IN PTR dns.example.com.
2 IN PTR server.example.com.
2 IN PTR ldap.example.com.
2 IN PTR www.example.com.
2 IN PTR mail.example.com.
2 IN PTR ftp.example.com.
3 IN PTR sgd-server.example.com.
4 IN PTR win.example.com.
5 IN PTR lin.example.com.
6 IN PTR sol.example.com.
7 IN PTR wins.example.com.
也就是从外部访问时,从域名到IP地址的解析关系。
文件名:/var/named/chroot/var/named/example.com.db.wan
$TTL 86400
@ IN SOA ns1.example.com. root.example.com.(
2013120801 ; Serial
7200 ; Refresh
7200 ; Retry
2419200 ; Expire
86400 ) ; Minimum
IN NS ns1.example.com.
IN MX 10 example.com.
ns1 IN A 192.168.1.2
@ IN A 192.168.1.2
www IN A 192.168.1.2
ftp IN A 192.168.1.2
mail IN A 192.168.1.2
server IN A 192.168.1.2
ldap IN A 192.168.1.2
dns IN A 192.168.1.2
example.com. IN TXT "v=spf1 ip4:192.168.1.2 ~all"
文件名:/var/named/chroot/var/named/1.168.192.in-addr.arpa.db
$TTL 86400
@ IN SOA example.com. root.example.com.(
2013120801 ; serial
3600 ; refresh (1 hour)
900 ; retry (15 minutes)
604800 ; expire (1 week)
86400 ; negative (1 day)
)
IN NS example.com.
2 IN PTR example.com.
```languag
启动服务:
# service named start
开机自动运行DNS服务:
# chkconfig named on
配置网卡eth1的DNS,使用本机做为DNS服务器:
# vim /etc/sysconfig/network-scripts/ifcfg-eth1
DNS1=127.0.0.1
先测试正向解析:
# dig example.com
; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.17.rc1.0.2.el6_4.6 <<>> example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5153
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 86400 IN A 192.168.0.2
;; AUTHORITY SECTION:
example.com. 86400 IN NS example.com.
;; Query time: 4 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Tue Sep 9 15:08:27 2014
;; MSG SIZE rcvd: 59
观察上面的ANSWER SECTION,可以看出解析成功了。
接下来试试反向解析:
# dig -x 192.168.0.2
; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.17.rc1.0.2.el6_4.6 <<>> -x 192.168.0.2
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31947
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 7, AUTHORITY: 1, ADDITIONAL: 1
;; QUESTION SECTION:
;2.0.168.192.in-addr.arpa. IN PTR
;; ANSWER SECTION:
2.0.168.192.in-addr.arpa. 86400 IN PTR mail.example.com.
2.0.168.192.in-addr.arpa. 86400 IN PTR ftp.example.com.
2.0.168.192.in-addr.arpa. 86400 IN PTR example.com.
2.0.168.192.in-addr.arpa. 86400 IN PTR dns.example.com.
2.0.168.192.in-addr.arpa. 86400 IN PTR server.example.com.
2.0.168.192.in-addr.arpa. 86400 IN PTR ldap.example.com.
2.0.168.192.in-addr.arpa. 86400 IN PTR www.example.com.
;; AUTHORITY SECTION:
0.168.192.in-addr.arpa. 86400 IN NS example.com.
;; ADDITIONAL SECTION:
example.com. 86400 IN A 192.168.0.2
;; Query time: 4 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Tue Sep 9 15:09:31 2014
;; MSG SIZE rcvd: 210
```language
观察上面的ANSWER SECTION,可以看出解析也成功了。
至于外部解析,因为和上面的步骤相同,这里就不在赘述。
至此为止,所有的配置都完成了。