How to get BIND 9.8.1 working with DLZ working with FreeBSD

Normally I’m a huge fan or FreeBSD, but I’ve been having problems with Dynamic Loadable Zones (DLZ) plugin for Bind for the longest time. It turns out that there is a miriad of bugs that are not fleshed out, and requires a lot of massaging to make it work. I finally caved in and fixed all the problems.

My environment is FreeBSD 8.2 (fresh install) with MySQL 5.1 and Bind 9.8.1.

Some things to note about Bind with DLZ, is that MySQL is not thread safe with DLZ, so do not enabled threads.

Bind 9.8.1 will not compile with DLZ-mysql

The first problem is that bind 9.8 will not compile with DLZ-mysql. You will get the folowing error:

dlz_mysql_driver.o(.text+0x457): In function `mysql_get_resultset':
: undefined reference to `sdlzh_build_querystring’
dlz_mysql_driver.o(.text+0x511): In function `mysql_get_resultset':
: undefined reference to `sdlzh_build_querystring’
dlz_mysql_driver.o(.text+0x52b): In function `mysql_get_resultset':
: undefined reference to `sdlzh_build_querystring’
dlz_mysql_driver.o(.text+0x545): In function `mysql_get_resultset':
: undefined reference to `sdlzh_build_querystring’
dlz_mysql_driver.o(.text+0x55f): In function `mysql_get_resultset':
: undefined reference to `sdlzh_build_querystring’
dlz_mysql_driver.o(.text+0x579): more undefined references to `sdlzh_build_query string’ follow
dlz_mysql_driver.o(.text+0x1015): In function `mysql_create':
: undefined reference to `sdlzh_get_parameter_value’
dlz_mysql_driver.o(.text+0x103c): In function `mysql_create':
: undefined reference to `sdlzh_get_parameter_value’
dlz_mysql_driver.o(.text+0x10dd): In function `mysql_create':
: undefined reference to `sdlzh_destroy_sqldbinstance’
dlz_mysql_driver.o(.text+0x11f3): In function `mysql_create':
: undefined reference to `sdlzh_build_sqldbinstance’
dlz_mysql_driver.o(.text+0x127a): In function `mysql_create':
: undefined reference to `sdlzh_build_sqldbinstance’
dlz_mysql_driver.o(.text+0x12ad): In function `mysql_create':
: undefined reference to `sdlzh_build_sqldbinstance’
dlz_mysql_driver.o(.text+0x12e4): In function `mysql_create':
: undefined reference to `sdlzh_build_sqldbinstance’
dlz_mysql_driver.o(.text+0x1340): In function `mysql_create':
: undefined reference to `sdlzh_get_parameter_value’
dlz_mysql_driver.o(.text+0x138c): In function `mysql_create':
: undefined reference to `sdlzh_get_parameter_value’
dlz_mysql_driver.o(.text+0x13da): In function `mysql_create':
: undefined reference to `sdlzh_get_parameter_value’
dlz_mysql_driver.o(.text+0x1428): In function `mysql_create':
: undefined reference to `sdlzh_get_parameter_value’
dlz_mysql_driver.o(.text+0x1441): In function `mysql_create':
: undefined reference to `sdlzh_get_parameter_value’
dlz_mysql_driver.o(.text+0x145a): more undefined references to `sdlzh_get_parame ter_value’ follow
dlz_mysql_driver.o(.text+0xf56): In function `mysql_destroy':
: undefined reference to `sdlzh_destroy_sqldbinstance’
*** Error code 1
Stop in /usr/ports/dns/bind98/work/bind-9.8.1-P1/bin/named.
*** Error code 1
Stop in /usr/ports/dns/bind98/work/bind-9.8.1-P1/bin.
*** Error code 1
Stop in /usr/ports/dns/bind98/work/bind-9.8.1-P1.
*** Error code 1
Stop in /usr/ports/dns/bind98.
*** Error code 1
Stop in /usr/ports/dns/bind98

What I had to do is edit /usr/ports/dns/bind98/work/bind-9.8.1-P1/contrib/dlz/drivers/sdlz_helper.c, and remove “#ifdef DLZ” on line 53, and remove “#endif” at the end of the file.  Then do a cd /usr/ports/dns/bind98 && make install clean.

BIND (any version) with DLZ-mysql will fail at startup

After that is installed, the next problem that I found is that BIND will not start on bootup.  This is due to a bug with BIND-DLZ where is does not re-order the start order, so BIND will always start before MySQL, thus BIND will fail.  To see what order everything will start in, you can execute the following command:

rcorder /etc/rc.d/* /usr/local/etc/rc.d/* | more

To fix this, you need to edit /usr/local/etc/rc.d/mysql-server, and delete the following line:

# REQUIRE: LOGIN

and then replace it with:

# REQUIRE: SERVERS cleanvar
# BEFORE: named

Now when you check rcorder, you’ll see what mysql-server will start before Bind.

Lingering Managed-Key Errors

I thought I was in the clear, until I noticed that the startup log still had errors:

Dec 15 20:11:41 goDNS01 named[25265]: starting BIND 9.8.1-P1 -t /var/named -u bind
Dec 15 20:11:41 goDNS01 named[25265]: built with '--localstatedir=/var' '--disable-linux-caps' '--disable-symtable' blahblahlbah
Dec 15 20:11:41 goDNS01 named[25265]: command channel listening on 127.0.0.1#953
Dec 15 20:11:41 goDNS01 named[25265]: command channel listening on ::1#953
Dec 15 20:11:41 goDNS01 named[25265]: managed-keys-zone ./IN: loading from master file managed-keys.bind failed:
file not found
Dec 15 20:11:41 goDNS01 named[25265]: running

In looking around, I couldn’t find a good answer as to why this is, as the default config doesn’t specify any keys to use. Even when I added keys for IPSEC, I still got this error. I was able to quell it by running the following:

touch /etc/namedb/working/managed-keys.bind

How to configure BIND with DLZ-MySQL

Now that we’re past my complaints with FreeBSD’s DLZ-MySQL flaws (and lack of documentation), we can move onto the configuration stuff. There’s a lot of ways you can implement this, but this is how I chose to do it.

Let’s add the structure and guts for the database. I’ve also included some example data as well. You should be able to put it all together for yourself. If you want to add another DNS zone, simply add additional entries with a different zone name (so like example.com for some entries, and example.org for other entries).

CREATE DATABASE `BindDB` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
USE `BindDB`;

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=latin1;

INSERT INTO `records` (`id`, `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),

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=latin1;

Now lets create a MySQL user for Bind (please modify the username and password to something more secure):

CREATE USER 'Bind_User'@'%' IDENTIFIED BY 'Your_Password';
GRANT SELECT ON `BindDB` . * TO 'Bind_User'@'%';
FLUSH PRIVILEGES;

Now let’s get Bind to talk to our new database. Edit /etc/namedb/named.conf and edit it to reflect the mentioned lines:

listen-on       { 127.0.0.1; }; # If you want it accessible from outside of your own system, change this to your ip address

# skip down to the end of the config file, and add this:
// and now for the new Dynamic Loading Zone (DLZ) MySQL connection...

dlz "Mysql zone" {
   database "mysql
   {host=127.0.0.1 port=3306 socket=/tmp/mysql.sock dbname=BindDB user=Bind_User pass=Your_Password}
   {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$'}";
};

We should be able to manually start Bind by executing:

/etc/rc.d/named start

To ensure that Bind will start upon a system restart, add the following into /etc/rc.conf

named_enable="YES" #Start BIND

Verifying That BIND Is Working

To make sure that Bind is working, first make sure there’s no errors upon starting, and then check /var/log/messages. One major hangup for people is that they try to reference localhost for the DLZ config. You MUST change it to 127.0.0.1, or the IP of an external mysql server. The short story for this is that MySQL changed how it treats localhost (MySQL treats it differently than 127.0.0.1).

Next, we need to see if BIND responds to DNS queries. Run the following DIG commands:

 dig @127.0.0.1 soa example.com
dig @127.0.0.1 ns example.com
dig @127.0.0.1 a example.com
dig @127.0.0.1 mx example.com

Congratulations, you now have a working BIND 9.8 DLZ-MySQL Server!

This entry was posted in DNS. Bookmark the permalink.

Comments are closed.