Bind DLZ

mattpascoe edited this page Jan 6, 2013 · 1 revision

The following will help you setup BIND-DLZ extension to perform dynamic lookups via your existing ONA database.

Configure BIND to use the DLZ extension

This is slightly outside the scope of this tutorial but can be found via a simple Google search. You can view related information at the sourceforge page: BIND DLZ -- please note it is no longer necessary to manually download and patch bind as the DLZ extension has been integrated into the main source repository for all recent versions of BIND9. The code examples used below take advantage of all features of OpenNetAdmin DNS administration including record disabling and future activation. It also respects designating master/slave name-servers per domain to set AXFR permission and DNS Views. The example below assumes you have two views defined 'PUBLIC' and 'PRIVATE' that contain your internal IPs/hosts and external IPs/hosts respectively.

Create a MySQL View

Using your MySQL command line tool, connect to your ONA database and issue the following statement to create a view that we will reference later from within BIND.

## Create a MySQL view that presents all of the required elements for
## BIND-DLZ lookups through the OpenNetAdmin database.
## This view should be created in your 'ona_default' database.
##
## NOTE:  Currently this view DOES NOT support IPv6
##
use ona_default;
drop view if exists dns_records;
create view dns_records as select
    case when ttl > 0 then ttl else default_ttl end as ttl, type,
    cast(case
        when type = 'ptr' then trim(trailing concat('.',domains.name) from concat_ws('.', ip_addr % 256, (ip_addr >> 8) % 256, (ip_addr >> 16) % 256, (ip_addr >> 24) % 256, 'in-addr.arpa'))
        when dns.name = '' then '@' else dns.name
    end as char) as host,
    case when type = 'mx' then mx_preference else '' end as mx_priority,
    cast(case
        when type = 'txt' then concat('"', txt,'"')
        when type = 'srv' then concat_ws(' ', srv_pri, srv_weight, srv_port,
            (select concat(dns2.name, '.', domains.name, '.') from
            dns as dns2 inner join domains on domains.id = dns2.domain_id where dns.dns_id = dns2.id))
        when type in ('ptr', 'cname', 'mx', 'ns') then (select concat(dns2.name,'.',domains.name,'.') from
        dns as dns2 inner join domains on domains.id = dns2.domain_id where dns.dns_id = dns2.id)
        when type = 'a' then inet_ntoa(interfaces.ip_addr)
    end as char) as data,'' as resp_person, '' as serial, '' as refresh, '' as retry, '' as expire, '' as minimum, domains.name as zone, dns_views.name as view from
    dns inner join domains on dns.domain_id = domains.id inner join dns_views on dns.dns_view_id = dns_views.id left join interfaces on interfaces.id = dns.interface_id
    where (dns.ebegin > 0 and now() >= dns.ebegin)
    union select default_ttl as ttl, 'SOA' as type, '@' as host, '' as mx_priority, concat(trim(trailing '.' from domains.primary_master), '.') as data,
    concat(trim(trailing '.' from domains.admin_email), '.') as resp_person, serial, refresh, retry, expiry as expire, minimum, domains.name as zone, 'ALL' as view from
    domains join dns_server_domains on domains.id = dns_server_domains.domain_id and role in ('master','slave');
drop view if exists xfr_table;
create view xfr_table as select
    domains.name as zone, inet_ntoa(interfaces.ip_addr) as client from domains
    inner join dns_server_domains on dns_server_domains.domain_id = domains.id
    inner join interfaces on dns_server_domains.host_id = interfaces.host_id;

Configure BIND

Place the following in a named configuration file such as named.conf or named.conf.local depending on your distribution. Please note the configuration below uses $zone$ and $record$ as the BIND DLZ reference tokens instead of the default %zone% and %record% values. This is due to the currently implemented patch to the default Ubuntu Linux (10.04) BIND source packages. If you are using another distro, please adjust. The blank {} query is not accidental, I found it was necessary to force a blank query for the DLZ 'authority' query and return authority info via the 'lookup' query where you can restrict by zone and host. When I specified a valid 'authority' query I had instances where BIND DLZ would return delegated zone NS records for the main zone.

acl "private_hosts" {
	127.0.0.0/8;
	10.0.0.0/8;
	172.16.0.0/12;
	192.168.0.0/16;
};

view "private" {
	match-clients { private_hosts; };
	recursion yes;

	dlz "ONA Private Zone" {
		database "mysql
		{host=localhost dbname=ona_default user=ona_sys pass=ona_sys_pass}
		{select zone from dns_records where zone = '$zone$' and type = 'SOA' limit 1}
		{select ttl, type, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum
			from dns_records where zone = '$zone$' and host = '$record$' and view in ('PRIVATE', 'ALL')}
		{}
		{select ttl, type, host, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum
			from dns_records where zone = '$zone$' and view in ('PRIVATE', 'ALL')}
		{select zone from xfr_table where zone = '$zone$' and client = '$client$'}";
	};

	// rndc key
	include "/etc/bind/rndc.key";
};

view "public" {
	match-clients { !private_hosts; any; };
	recursion no;

	dlz "ONA Public Zone" {
		database "mysql
		{host=localhost dbname=ona_default user=ona_sys pass=ona_sys_pass}
		{select zone from dns_records where zone = '$zone$' and type = 'SOA' limit 1}
		{select ttl, type, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum
			from dns_records where zone = '$zone$' and host = '$record$' and view in ('PUBLIC', 'ALL')}
		{}
		{select ttl, type, host, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum
			from dns_records where zone = '$zone$' and view in ('PUBLIC', 'ALL')}
		{select zone from xfr_table where zone = '$zone$' and client = '$client$'}";
	};

	// rfc1918 zones
	include "/etc/bind/zones.rfc1918";
};

That's it, you should now be able to query your name-server attached to your ONA database and have results reflected in real time. You should also be able to configure slaves on any hosts defined as name-servers in your ONA configuration. The ACL definition above is just an example, please adjust to reflect your actual internal private networks.

Try this if you are not using DNS views in your environment:

recursion yes;

dlz "ONA Default" {
	database "mysql
	{host=localhost dbname=ona_default user=ona_sys pass=ona_sys_pass}
	{select zone from dns_records where zone = '$zone$' and type = 'SOA' limit 1}
	{select ttl, type, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum
		from dns_records where zone = '$zone$' and host = '$record$' and view in ('DEFAULT', 'ALL')}
	{}
	{select ttl, type, host, mx_priority, data, resp_person, serial, refresh, retry, expire, minimum
		from dns_records where zone = '$zone$' and view in ('DEFAULT', 'ALL')}
	{select zone from xfr_table where zone = '$zone$' and client = '$client$'}";
};

// rndc key
include "/etc/bind/rndc.key";