Bind-9.10 DLZ MySQL

早期我这边的服务注册设计中针对域名:IP的映射关系是依靠/etc/hosts文件通过SSH 中间件统一管理的,但由于功能扩展需要需要用到DNS来解析,随即需要自建DNS来应对域名和IP的映射关系,既本文,使用Bind来提供DNS解析服务,通过MySQL(dynamically loaded zones)提供出来的接口关联注册服务,初步判断可行。

系统版本CentOS 6.8X64 Minimal
程序根目录/software/
Bind 版本9.10.4-P2

下载

1
https://www.isc.org/downloads/

创建用户

1
2
groupadd -r -g 1725 named
useradd -r -u 1725 -s /bin/nologin -d /software/bind -g named named

Bind 安装

1
2
3
4
5
6
CPPFLAGS="-I/software/mysql/include" LDFLAGS="-L/software/mysql/lib" ./configure --prefix=/software/bind --disable-openssl-version-check --with-dlz-mysql=/software/mysql --enable-threads=no
make
make install

#: 变更权限
chown named:named -R /software/bind/

配置和使用

获取根区域文件

1
wget --user=ftp --password=ftp ftp://ftp.rs.internic.net/domain/db.cache -O /software/bind/etc/db.root

named.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
options {
directory "/data/bind/cache";
allow-transfer {
none;
};
allow-query-cache {
any;
};
allow-query {
any;
};
allow-recursion {
any;
};

forward only;
forwarders {
10.255.1.252;
10.255.1.254;
};

max-cache-size 256m;
cleaning-interval 1;
max-cache-ttl 120;
max-ncache-ttl 120;
#dnssec-enable yes;
#dnssec-validation yes;
#dnssec-lookaside auto;

zone-statistics yes;
statistics-file "/data/bind/named-stats.out";
recursion yes;
};

key rndc {
algorithm hmac-md5 ;
secret "dG91emhpamlh";
};

controls {
inet 127.0.0.1 allow { localhost; } keys { rndc; };
};

zone "." {
type hint;
file "/software/bind/etc/db.root";
};

#: RFC 1912
zone "localhost.localdomain" IN {
type master;
file "/software/bind/etc/named.localhost";
allow-update { none; };
};

zone "localhost" IN {
type master;
file "/software/bind/etc/named.localhost";
allow-update { none; };
};

zone "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" IN {
type master;
file "/software/bind/etc/named.loopback";
allow-update { none; };
};

zone "1.0.0.127.in-addr.arpa" IN {
type master;
file "/software/bind/etc/named.loopback";
allow-update { none; };
};

zone "0.in-addr.arpa" IN {
type master;
file "/software/bind/etc/named.empty";
allow-update { none; };
};

include "/software/bind/etc/named.dlz.zones";

named.localhost

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$TTL 1D     ; 生存期, 默认单位为秒,另可设定为[W|D|H|M]

; [zone] IN SOA [主机名] [管理员email] ([五组更新时间参数])
; @=>zone IN SOA @=>主机名 rname.invalid.=>email
; @代表根域
; rname.invalid.解析为liusha@local,第一个"."为"@"的替代,尾部的"."为根域,表明其为绝对URL。
@ IN SOA @ liusha.local. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS @ ; 直接输入域名,访问@
A 127.0.0.1 ; 直接输入域名,解析到的IPV4的IP
AAAA ::1 ; 直接输入域名,解析到的IPV6的IP

named.loopback

1
2
3
4
5
6
7
8
9
10
11
$TTL 1D
@ IN SOA @ liusha.local. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS @
A 127.0.0.1
AAAA ::1
PTR localhost.

named.empty

1
2
3
4
5
6
7
8
9
10
$TTL 3H
@ IN SOA @ liusha.local. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS @
A 127.0.0.1
AAAA ::1

named.dlz.zones

1
2
3
4
5
6
7
8
9
10
11
12
dlz "mysql dlz" {
database "mysql
{
host=127.0.0.1 port=3306 socket=/tmp/mysql.sock
dbname=BindDB user=root pass=password threads=5
}
{SELECT zone FROM records WHERE zone = '$zone$'}
{SELECT ttl, type, mx_priority, IF(type = 'TXT', CONCAT('\"',data,'\"'), data) AS data FROM records WHERE zone = '$zone$' AND host = '$record$' AND type <> 'SOA' AND type <> 'NS'}
{SELECT ttl, type, data, primary_ns, resp_contact, serial, refresh, retry, expire, minimum FROM records WHERE zone = '$zone$' AND (type = 'SOA' OR type='NS')}
{SELECT ttl, type, host, mx_priority, IF(type = 'TXT', CONCAT('\"',data,'\"'), data) AS data, resp_contact, serial, refresh, retry, expire, minimum FROM records WHERE zone = '$zone$' AND type <> 'SOA' AND type <> 'NS'}
{SELECT zone FROM xfr where zone='$zone$' AND client = '$client$'}";
};

dlz sql script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#: Database
CREATE DATABASE `BindDB` DEFAULT CHARACTER SET utf8;

#: Table
CREATE TABLE IF NOT EXISTS `records` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`zone` varchar(255) NOT NULL,
`ttl` int(11) NOT NULL DEFAULT '86400',
`type` varchar(255) NOT NULL,
`host` varchar(255) NOT NULL DEFAULT '@',
`mx_priority` int(11) DEFAULT NULL,
`data` text,
`primary_ns` varchar(255) DEFAULT NULL,
`resp_contact` varchar(255) DEFAULT NULL,
`serial` bigint(20) DEFAULT NULL,
`refresh` int(11) DEFAULT NULL,
`retry` int(11) DEFAULT NULL,
`expire` int(11) DEFAULT NULL,
`minimum` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `type` (`type`),
KEY `host` (`host`),
KEY `zone` (`zone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `xfr` (
`zone` varchar(255) NOT NULL,
`client` varchar(255) NOT NULL,
KEY `zone` (`zone`),
KEY `client` (`client`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

#: 初始化示例数据
INSERT INTO `records` (`zone`, `ttl`, `type`, `host`, `mx_priority`, `data`, `primary_ns`, `resp_contact`, `serial`, `refresh`, `retry`, `expire`, `minimum`) VALUES
('example.com', 86400, 'SOA', '@', NULL, NULL, 'ns1.example.com.', 'info.example.com.', 2011043001, 10800, 7200, 604800, 86400),
('example.com', 86400, 'NS', '@', NULL, 'ns1.example.com.', NULL, NULL, NULL, NULL, NULL, NULL, NULL),
('example.com', 86400, 'NS', '@', NULL, 'ns2.example.com.', NULL, NULL, NULL, NULL, NULL, NULL, NULL),
('example.com', 86400, 'MX', '@', 10, 'mail.example.com.', NULL, NULL, NULL, NULL, NULL, NULL, NULL),
('example.com', 86400, 'A', '@', NULL, '192.168.0.2', NULL, NULL, NULL, NULL, NULL, NULL, NULL),
('example.com', 86400, 'CNAME', 'www', NULL, '@', NULL, NULL, NULL, NULL, NULL, NULL, NULL),
('example.com', 86400, 'A', 'ns1', NULL, '192.168.0.111', NULL, NULL, NULL, NULL, NULL, NULL, NULL),
('example.com', 86400, 'A', 'ns2', NULL, '192.168.0.222', NULL, NULL, NULL, NULL, NULL, NULL, NULL),
('example.com', 86400, 'A', 'mail', NULL, '192.168.0.3', NULL, NULL, NULL, NULL, NULL, NULL, NULL),
('example.com', 86400, 'TXT', '@', NULL, 'v=spf1 ip:192.168.0.3 ~all', NULL, NULL, NULL, NULL, NULL, NULL, NULL);

启动脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/bin/bash
# named a network name service.
# chkconfig: 345 35 75
# description: a name server

[ -r /etc/rc.d/init.d/functions ] && . /etc/rc.d/init.d/functions

Builddir=/software/bind
PidFile=/software/bind/named.pid
LockFile=/var/lock/subsys/named
Sbindir=${Builddir}/sbin
Configfile=${Builddir}/etc/named.conf
CheckConf=${Builddir}/sbin/named-checkconf
named=named

if [ ! -f ${Configfile} ]
then
echo "Can't find named.conf "
exit 1
fi

if [ ! -d /software/bind/ ]
then
echo "could not open directory '/software/named/': Permission denied "
exit 1
elif [ ! -w /software/bind/ ]
then
echo "could not open directory '/software/named/': Permission denied "
exit 1
fi


if [ ! -r ${Configfile} ]
then
echo "Error: ${Configfile} is not readfile!"
exit 1
else
$CheckConf
if [ $? != 0 ]
then
echo -e "Please check config file in \033[31m${Configfile} \033[0m!"
exit 2
fi
fi


start() {
[ -x ${Builddir}/sbin/$named ] || exit 4
if [ -f $LockFile ]; then
echo -n "$named is already running..."
echo_failure
echo
exit 5
fi

echo -n "Starting $named: "
daemon --pidfile "$PidFile" ${Sbindir}/$named -u named -4 -c ${Configfile}
RETVAL=$?
echo
if [ $RETVAL -eq 0 ]; then
touch $LockFile
return 0
else
rm -f $LockFile $PidFile
return 1
fi
}

stop() {
if [ ! -f $LockFile ];then
echo "$named is not started."
echo_failure
fi

echo -n "Stopping $named: "
killproc $named
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f $LockFile
return 0
}

restart() {
stop
sleep 1
start
}

reload() {
echo -n "Reloading $named: "
killproc $named -HUP
RETVAL=$?
echo
return $RETVAL
}

status() {
if pidof $named > /dev/null && [ -f $PidFile ]; then
echo "$named is running..."
else
echo "$named is stopped..."
fi
}

case $1 in
start)
start ;;
stop)
stop ;;
restart)
restart ;;
reload)
reload ;;
status)
status ;;
*)
echo "Usage:named {start|stop|status|reload|restart}"
exit 2;;
esac

启动

1
/software/bind/sbin/named -c /software/bind/etc/named.conf -f -g -u named -d 3