测试服务器 :
BIND Server : 172.16.3.150
Client 1 IDC_A : 172.16.3.33
Client 2 IDC_B : 172.16.3.39
Client 3 IDC_C : 172.16.3.40
digoal.sky-mobi.com IN IDC_A : 172.16.3.2
digoal.sky-mobi.com IN IDC_B : 172.16.3.3
digoal.sky-mobi.com IN IDC_C : 172.16.3.4
测试目标 :
从Client 1查找digoal.sky-mobi.com返回的IP是172.16.3.2
从Client 2查找digoal.sky-mobi.com返回的IP是172.16.3.3
从Client 3查找digoal.sky-mobi.com返回的IP是172.16.3.4
版本 : bind-9.7.4-P1, (9.8.1-P1有DLZ BUG。)
安装PostgreSQL 9.1.1
编译BIND9的--with-dlz-postgres选项需要用到PostgreSQL的include和lib文件.所以需要先安装PostgreSQL.PG安装不在这里细数, 有兴趣的朋友可以参考我以前写过的BLOG或者参考PG手册.
BIND9 with dlz postgresql 简易安装 :
su - root
cd /opt/soft_bak/bind-9.7.4-P1
LDFLAGS="-L/opt/pgsql/lib" CFLAGS="-I/opt/pgsql/include" ./configure --prefix=/opt/bind --with-libtool --enable-largefile --enable-threads --enable-fixed-rrset --disable-openssl-version-check --with-dlz-postgres=/opt/soft_bak/bind-9.7.4-P1/contrib/dlz/drivers
make
make install
chown -R root:root /opt/bind
配置用户 :
# useradd bind
# su - bind
$ vi .bash_profile
增加如下,
# add by digoal.
export PS1="$USER@`/bin/hostname -s`-> "
export LANG=en_US.utf8
export PG_HOME=/opt/pgsql
export BIND_HOME=/opt/bind
export LD_LIBRARY_PATH=$PG_HOME/lib:$BIND_HOME/lib:/lib64:/usr/lib64:/usr/local/lib64:/lib:/usr/lib:/usr/local/lib
export DATE=`date +"%Y%m%d%H%M"`
export PATH=$BIND_HOME/sbin:$BIND_HOME/bin:$PATH:.
export MANPATH=$BIND_HOME/share/man:$MANPATH
alias rm='rm -i'
alias ll='ls -lh'
配置bind
cd /opt/bind/etc
rndc-confgen >rndc.conf
编辑rndc.conf,把注释的部分去除写入 /opt/bind/etc/named.conf
# Use with the following in named.conf, adjusting the allow list as needed:
controls {
inet 127.0.0.1 port 1953
allow { 127.0.0.1; } keys { "rndc-key"; };
};
# End of named.conf
rm -f rndc.conf (该文件与 rndc.key 文件一起出现会出现 rndc警告,删除为妙)
dig > /opt/bind/etc/named.root
查看是否存在 /opt/bind/etc/rndc.key 文件,如果没有就生成一个
rndc-confgen -a -c /opt/bind/etc/rndc.key
root@db-172-16-3-150-> cat /opt/bind/etc/rndc.key
key "rndc-key" {
algorithm hmac-md5;
secret "9D9cfokRSjU6KNm0mzG5sw==";
};
把KEY文件include到 named.conf
include "/opt/bind/etc/rndc.key";
调用KEY的时候用到的key需要和KEY文件里对应.
编写view配置文件:
/opt/bind/etc/idc_a.conf
#idc_a network view
view "idc_a" {
match-clients { IDC_A; }; #使用数据库时的配置,无需同步
allow-query { IDC_A; };
allow-recursion { LOCAL; }; #表示不递归解析不存在这个name server的地址.
#---dlz postgresql database configure----
dlz "postgres zone" {
database "postgres 8
{host=127.0.0.1 port=1921 dbname=dns user=dns}
{select zone from dns_records where zone = '$zone$' limit 1}
{select ttl, type, mx_priority, case when lower(type)='txt' then '\"' || data || '\"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = '$zone$' and lower(view)='idc_a' and host = '$record$'}";
};
#---dlz postgresql database configure----
};
/opt/bind/etc/idc_b.conf
#idc_a network view
view "idc_b" {
match-clients { IDC_B; }; #使用数据库时的配置,无需同步
allow-query { IDC_B; };
allow-recursion { LOCAL; }; #表示不递归解析不存在这个name server的地址.
#---dlz postgresql database configure----
dlz "postgres zone" {
database "postgres 8
{host=127.0.0.1 port=1921 dbname=dns user=dns}
{select zone from dns_records where zone = '$zone$' limit 1}
{select ttl, type, mx_priority, case when lower(type)='txt' then '\"' || data || '\"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = '$zone$' and lower(view)='idc_b' and host = '$record$'}";
};
#---dlz postgresql database configure----
};
/opt/bind/etc/idc_c.conf
#idc_a network view
view "idc_c" {
match-clients { IDC_C; }; #使用数据库时的配置,无需同步
allow-query { IDC_C; };
allow-recursion { LOCAL; }; #表示不递归解析不存在这个name server的地址.
#---dlz postgresql database configure----
dlz "postgres zone" {
database "postgres 8
{host=127.0.0.1 port=1921 dbname=dns user=dns}
{select zone from dns_records where zone = '$zone$' limit 1}
{select ttl, type, mx_priority, case when lower(type)='txt' then '\"' || data || '\"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = '$zone$' and lower(view)='idc_c' and host = '$record$'}";
};
#---dlz postgresql database configure----
};
最终的named.conf
# Use with the following in named.conf, adjusting the allow list as needed:
include "/opt/bind/etc/idc_a.conf";
include "/opt/bind/etc/idc_b.conf";
include "/opt/bind/etc/idc_c.conf";
include "/opt/bind/etc/rndc.key";
acl "LOCAL" {
localhost;
};
acl "ALL" {
172.16.0.0/16;
};
acl "IDC_A" {
172.16.3.33/32;
};
acl "IDC_B" {
172.16.3.39/32;
};
acl "IDC_C" {
172.16.3.40/32;
};
controls {
inet 127.0.0.1 port 1953
allow { 127.0.0.1; } keys { "rndc-key"; };
};
options
{
directory "/opt/bind/var/run/named";
dump-file "/opt/bind/var/cache_dump.db";
statistics-file "/opt/bind/var/named_stats.log";
memstatistics-file "/opt/bind/var/named_mem_stats.log";
listen-on port 53 { 0.0.0.0/0; };
allow-recursion { 127.0.0.1; };
edns-udp-size 512;
};
logging {
channel query_log {
file "/opt/bind/var/query.log" versions 3 size 20m;
severity info;
print-time yes;
print-category yes;
print-severity yes;
};
category default {
query_log;
};
};
# End of named.conf
配置PostgreSQL
最优配置应该是这样的,

本例仅仅为测试所以没有使用到复制,
初始化数据库与表:
create role dns .... ;
create tablespace .... ;
create database with owner dns .....;
\c dns dns
create schema dns authorization dsn;
create table dns_records(
zone text,
host text NOT NULL default '@',
ttl integer,
view text,
type text,
mx_priority integer,
data text,
resp_person text,
serial integer,
refresh integer,
retry integer,
expire integer,
minimum integer
);
create INDEX dns_records_host_index on dns_records (host);
create INDEX dns_records_zone_index on dns_records (zone);
配置pg_hba.conf . 让本地可以不需要密码访问数据库.
host dns dns 127.0.0.1/32 trust
插入zone数据
\c dns dns
insert into dns_records(zone, host, ttl, view, type, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum) values ('sky-mobi.com', 'digoal', 600, 'idc_a', 'A', NULL, '172.16.3.2', NULL, NULL, NULL, NULL, NULL, NULL);
insert into dns_records(zone, host, ttl, view, type, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum) values ('sky-mobi.com', 'digoal', 600, 'idc_b', 'A', NULL, '172.16.3.3', NULL, NULL, NULL, NULL, NULL, NULL);
insert into dns_records(zone, host, ttl, view, type, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum) values ('sky-mobi.com', 'digoal', 600, 'idc_c', 'A', NULL, '172.16.3.4', NULL, NULL, NULL, NULL, NULL, NULL);
不需要SOA,NS记录。这里只需要A记录。因为不配置SLAVE。
启动BIND(为了观察方便这里使用了-g -d 1, 测试正常后启动不需要加这个) :
su - root
. /home/bind/.bash_profile
named -c /opt/bind/etc/named.conf -g -d 1
测试 :
连接到172.16.3.33
nslookup
> digoal.sky-mobi.com
Server: 172.16.3.150
Address: 172.16.3.150#53
Name: digoal.sky-mobi.com
Address: 172.16.3.2
BIND日志:
24-Nov-2011 17:04:39.957
Query String: select zone from dns_records where zone = 'digoal.sky-mobi.com' limit 1
24-Nov-2011 17:04:39.957
Query String: select zone from dns_records where zone = 'sky-mobi.com' limit 1
24-Nov-2011 17:04:39.958
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_a' and host = '@'
24-Nov-2011 17:04:39.959
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_a' and host = '*'
24-Nov-2011 17:04:39.960
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_a' and host = 'digoal'
24-Nov-2011 17:04:39.961
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_a' and host = '@'
24-Nov-2011 17:04:39.962
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_a' and host = '*'
连接到172.16.3.39
nslookup
> digoal.sky-mobi.com
Server: 172.16.3.150
Address: 172.16.3.150#53
Name: digoal.sky-mobi.com
Address: 172.16.3.3
BIND日志 :
24-Nov-2011 17:06:48.641
Query String: select zone from dns_records where zone = 'digoal.sky-mobi.com' limit 1
24-Nov-2011 17:06:48.641
Query String: select zone from dns_records where zone = 'sky-mobi.com' limit 1
24-Nov-2011 17:06:48.642
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_b' and host = '@'
24-Nov-2011 17:06:48.642
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_b' and host = '*'
24-Nov-2011 17:06:48.643
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_b' and host = 'digoal'
24-Nov-2011 17:06:48.644
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_b' and host = '@'
24-Nov-2011 17:06:48.644
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_b' and host = '*'
连接到172.16.3.40
nslookup
> digoal.sky-mobi.com
Server: 172.16.3.150
Address: 172.16.3.150#53
Name: digoal.sky-mobi.com
Address: 172.16.3.4
BIND日志
24-Nov-2011 17:08:59.727
Query String: select zone from dns_records where zone = 'digoal.sky-mobi.com' limit 1
24-Nov-2011 17:08:59.728
Query String: select zone from dns_records where zone = 'sky-mobi.com' limit 1
24-Nov-2011 17:08:59.728
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_c' and host = '@'
24-Nov-2011 17:08:59.729
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_c' and host = '*'
24-Nov-2011 17:08:59.730
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_c' and host = 'digoal'
24-Nov-2011 17:08:59.731
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_c' and host = '@'
24-Nov-2011 17:08:59.731
Query String: select ttl, type, mx_priority, case when lower(type)='txt' then '"' || data || '"'
when lower(type)='soa' then data || ' ' || resp_person || ' ' || serial || ' ' || refresh || ' ' || retry || ' ' || expire || ' ' || minimum
else data end from dns_records where zone = 'sky-mobi.com' and lower(view)='idc_c' and host = '*'
【应用场景】
1. 根据来源IP解析不同的目标IP,可用于多机房部署的业务,数据库比如复制到了多个IDC,应用程序不需要关心数据库的IP,统统连到db.sky-mobi.com。BIND可以根据应用的IP来判断应该连接到最近的DB服务器。
2. 可以做FAILOVER,如与POSTGRESQL的流复制结合使用。例如 :

plproxy让你的数据库抛弃存储也可以跑得飞快。
PGCloud让你的数据库抛弃存储也可以达到高可用。
PGCloud让你的数据库抛弃虚拟机也可以跑在云端。
【参考】
BIND 9 Administrator Reference Manual
【附录】
可配置项 :
./configure --help
`configure' configures this package to adapt to many kinds of systems.
Usage: ./configure [OPTION]... [VAR=VALUE]...
To assign environment variables (e.g., CC, CFLAGS...), specify them as
VAR=VALUE. See below for descriptions of some of the useful variables.
Defaults for the options are specified in brackets.
Configuration:
-h, --help display this help and exit
--help=short display options specific to this package
--help=recursive display the short help of all the included packages
-V, --version display version information and exit
-q, --quiet, --silent do not print `checking ...' messages
--cache-file=FILE cache test results in FILE [disabled]
-C, --config-cache alias for `--cache-file=config.cache'
-n, --no-create do not create output files
--srcdir=DIR find the sources in DIR [configure dir or `..']
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
[/usr/local]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
[PREFIX]
By default, `make install' will install all the files in
`/usr/local/bin', `/usr/local/lib' etc. You can specify
an installation prefix other than `/usr/local' using `--prefix',
for instance `--prefix=$HOME'.
For better control, use the options below.
Fine tuning of the installation directories:
--bindir=DIR user executables [EPREFIX/bin]
--sbindir=DIR system admin executables [EPREFIX/sbin]
--libexecdir=DIR program executables [EPREFIX/libexec]
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
--datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
--datadir=DIR read-only architecture-independent data [DATAROOTDIR]
--infodir=DIR info documentation [DATAROOTDIR/info]
--localedir=DIR locale-dependent data [DATAROOTDIR/locale]
--mandir=DIR man documentation [DATAROOTDIR/man]
--docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
--htmldir=DIR html documentation [DOCDIR]
--dvidir=DIR dvi documentation [DOCDIR]
--pdfdir=DIR pdf documentation [DOCDIR]
--psdir=DIR ps documentation [DOCDIR]
System types:
--build=BUILD configure for building on BUILD [guessed]
--host=HOST cross-compile to build programs to run on HOST [BUILD]
Optional Features:
--disable-option-checking ignore unrecognized --enable/--with options
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--enable-shared[=PKGS] build shared libraries [default=yes]
--enable-static[=PKGS] build static libraries [default=yes]
--enable-fast-install[=PKGS]
optimize for fast installation [default=yes]
--disable-libtool-lock avoid locking (might break parallel builds)
--enable-libbind deprecated
--enable-kqueue use BSD kqueue when available [default=yes]
--enable-epoll use Linux epoll when available [default=auto]
--enable-devpoll use /dev/poll when available [default=yes]
--enable-openssl-version-check
Check OpenSSL Version [default=yes]
--enable-openssl-hash use OpenSSL for hash functions [default=no]
--enable-threads enable multithreading
--enable-largefile 64-bit file support
--enable-backtrace log stack backtrace on abort [default=yes]
--enable-symtable use internal symbol table for backtrace
[all|minimal(default)|none]
--enable-exportlib build exportable library (GNU make required)
[default=no]
--enable-ipv6 use IPv6 default=autodetect
--enable-getifaddrs Enable the use of getifaddrs() [yes|no].
--disable-isc-spnego use SPNEGO from GSSAPI library
--disable-chroot disable chroot
--disable-linux-caps disable linux capabilities
--enable-atomic enable machine specific atomic operations
[default=autodetect]
--enable-fixed-rrset enable fixed rrset ordering
[default=no]
--enable-rpz-nsip enable rpz-nsip rules [default=no]
--enable-rpz-nsdname enable rpz-nsdname rules [default=no]
--enable-filter-aaaa enable filtering of AAAA records over IPv4
[default=no]
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-gnu-ld assume the C compiler uses GNU ld [default=no]
--with-pic try to use only PIC/non-PIC objects [default=use
both]
--with-tags[=TAGS] include additional configurations [automatic]
--with-openssl=PATH Build with OpenSSL yes|no|path.
(Required for DNSSEC)
--with-pkcs11=PATH Build with PKCS11 support yes|no|path
(PATH is for the PKCS11 provider)
--with-gssapi=PATH Specify path for system-supplied GSSAPI [default=yes]
--with-randomdev=PATH Specify path for random device
--with-libxml2=PATH Build with libxml2 library yes|no|path
--with-purify=PATH use Rational purify
--with-libtool use GNU libtool
--with-export-libdir=PATH
installation directory for the export library
[EPREFIX/lib/bind9]
--with-export-includedir=PATH
installation directory for the header files of the
export library [PREFIX/include/bind9]
--with-kame=PATH use Kame IPv6 default path /usr/local/v6
--with-docbook-xsl=PATH Specify path for Docbook-XSL stylesheets
--with-idn=MPREFIX enable IDN support using idnkit default PREFIX
--with-libiconv=IPREFIX GNU libiconv are in IPREFIX default PREFIX
--with-iconv=LIBSPEC specify iconv library default -liconv
--with-idnlib=ARG specify libidnkit
--with-atf=ARG Automated Test Framework support
--with-dlopen=ARG Support dynamically loadable DLZ drivers
--with-dlz-postgres=PATH Build with Postgres DLZ driver yes|no|path.
(Required to use Postgres with DLZ)
--with-dlz-mysql=PATH Build with MySQL DLZ driver yes|no|path.
(Required to use MySQL with DLZ)
--with-dlz-bdb=PATH Build with Berkeley DB DLZ driver yes|no|path.
(Required to use Berkeley DB with DLZ)
--with-dlz-filesystem=PATH Build with filesystem DLZ driver yes|no.
(Required to use file system driver with DLZ)
--with-dlz-ldap=PATH Build with LDAP DLZ driver yes|no|path.
(Required to use LDAP with DLZ)
--with-dlz-odbc=PATH Build with ODBC DLZ driver yes|no|path.
(Required to use ODBC with DLZ)
--with-dlz-stub=PATH Build with stub DLZ driver yes|no.
(Required to use stub driver with DLZ)
--with-make-clean Run "make clean" at end of configure [yes|no].
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
you have headers in a nonstandard directory <include dir>
CPP C preprocessor
CXX C++ compiler command
CXXFLAGS C++ compiler flags
CXXCPP C++ preprocessor
F77 Fortran 77 compiler command
FFLAGS Fortran 77 compiler flags
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
Report bugs to the package provider.