Knowledge Base ISC Main Website Ask a Question/Contact ISC
A short introduction to Catalog Zones
Author: Witold Krecicki Reference Number: AA-01401 Views: 3653 Created: 2016-07-20 19:04 Last Updated: 2016-10-04 20:50 0 Rating/ Voters

Catalog Zones is a new BIND feature allowing easy provisioning of zones to  slave servers. A "catalog zone" is a special DNS zone that contains a list of other zones to be served, along with their configuration parameters.  The zones listed in a catalog zone are called "member zones".  When a catalog zone is loaded or transferred to a slave server that supports this functionality, the slave server will create the member zones automatically.  When the catalog zone is updated (for example, to add or delete member zones, or change their configuration parameters) those changes are immediately put into effect. Because the catalog zone is a normal DNS zone, these configuration changes can be propagated using the standard AXFR/IXFR zone transfer mechanism. 

This guide shows the basic usage of catalog zones - how to add set up a master and slave provisioned using catalog zone, how to add a new zone to the catalog zone and how to possibly automate it. In this guide we'll be using three servers - master running on 10.53.0.1 and two slaves running on 10.53.0.2 and 10.53.0.3. To make it easier to try out this example on your own system, we are using unprivileged ports 5300 and 9953, for DNS and RNDC respectively.


First we create an empty catalog zone named "catalog.example" that we'll be using. It has to have NS and SOA records (just like a regular zone) and an IN TXT record which tells the server what version of the catalog zone syntax this zone uses - the current version is "1":

; catalog.example.db
catalog.example. IN SOA . . 1 86400 3600 86400 3600
catalog.example. IN NS invalid.
version IN TXT "1"

For the master server we have to enable "allow-new-zones" and RNDC access, and we also have to serve the catalog zone for slaves:

; named-ns1.conf
key rndc_key { secret "1234abcd8765"; algorithm hmac-sha256; };

controls { inet 10.53.0.1 port 9953 allow { any; } keys { rndc_key; }; };

options {
        query-source address 10.53.0.1;
        notify-source 10.53.0.1;
        transfer-source 10.53.0.1;
        port 5300;
        allow-new-zones yes;
        pid-file "named.pid";
        listen-on { 10.53.0.1; };
        listen-on-v6 { none; };
        notify no;
        recursion no;   
        allow-transfer { any; };
};

zone "catalog.example" {
        type master;
        file "catalog.example.db";
        allow-transfer { any; };
        allow-update { any; };
        also-notify { 10.53.0.2; 10.53.0.3; };
        notify explicit;
};

For both slave servers we need to slave the catalog.example zone from master and enable it as a catalog zone.  The configuration for ns3 is identical to ns2 except all 10.53.0.2 addresses are replaced with 10.53.0.3:

; named-ns2.conf
options {
        query-source address 10.53.0.2;
        notify-source 10.53.0.2;
        transfer-source 10.53.0.2;
        port 5300;
        pid-file "named.pid";
        listen-on { 10.53.0.2; };
        listen-on-v6 { none; };
        notify no;
        recursion no;
        catalog-zones {
                zone "catalog.example" default-masters { 10.53.0.1; };
        };
};

zone "catalog.example" {
        type slave;
        file "catalog.example.db";
        masters { 10.53.0.1; };
};
; named-ns3.conf
options {
        query-source address 10.53.0.3;
        notify-source 10.53.0.3;
        transfer-source 10.53.0.3;
        port 5300;
        pid-file "named.pid";
        listen-on { 10.53.0.3; };
        listen-on-v6 { none; };
        notify no;
        recursion no;
        catalog-zones {
                zone "catalog.example" default-masters { 10.53.0.1; };
        };
};

zone "catalog.example" {
        type slave;
        file "catalog.example.db";
        masters { 10.53.0.1; };
};

We also need to setup "rndc.conf" with our key:

; rndc.conf
key rndc_key { secret "1234abcd8765"; algorithm hmac-sha256; };

Please remember that this is just an example configuration - in the real world you should never allow updates to everyone.  Zone transfers should be protected with TSIG and catalog zones should not be open for queries.

 We then launch ns1 and ns2 (in separate directories) - we'll leave ns3 for later. ns2 should download the now empty "catalog.example" zone and we should be able to query it:

$ dig +short @10.53.0.2 -p 5300 soa catalog.example
. . 1 86400 3600 86400 3600

Although leaving the catalog zone open for queries is not recommended in our case it'll be useful for debugging.

To add a zone we first need to create a stub master file:

; example.com.db
example.com. 3600 IN SOA . . 1 3600 3600 3600 3600
example.com. IN NS ns1.isc.org.
example.com. IN NS ns2.isc.org.

and then add the zone to master using rndc:

rndc -k rndc.conf -y rndc_key -s 10.53.0.1 -p 9953 addzone example.com '{type master; file "example.com.db";};'

The zone is now served by ns1:

$ dig +short @10.53.0.1 -p 5300 soa example.com
. . 1 3600 3600 3600 3600

To provision the zone on slave we have to add it to catalog zone, for now we'll do it using nsupdate. The long label (c5e4...) is the hex digest of the SHA1 hash of the zone name ("example.com") in wire format.  The method of calculating it is shown below in catz-add.py script:

$ cat << __EOF | nsupdate
server 10.53.0.1 5300
update add c5e4b4da1e5a620ddaa3635e55c3732a5b49c7f4.zones.catalog.example 3600 IN PTR example.com
send
__EOF

The new version of catalog.example zone is transferred to ns2 and a moment later ns2 should transfer and serve example.com:

$ dig +short @10.53.0.2 -p 5300 soa example.com
. . 1 3600 3600 3600 3600

Obviously in a real life scenario this should be automated. Using dnspython and the isc.rndc module we can write a simple Python script that does everything we did automatically:

#!/usr/bin/python
# catz-add.py
import sys
import os
import isc
import dns.query
import dns.update
import dns.name
import hashlib

ZONEPATH='/tmp/'
MASTER='10.53.0.1'
DNSPORT=5300
RNDCPORT=9953
RNDCALGO='sha256'
RNDCKEY='1234abcd8765'
CATZONE='catalog.example'

def add_zone(name):
  # Create a stub master file
  with file('%s%s.db' % (ZONEPATH, name), 'w') as f:
    f.write('@ 3600 IN SOA . . 1 3600 3600 3600 3600\n')
    f.write('@ IN NS ns1.isc.org.\n')
    f.write('@ IN NS ns2.isc.org.\n')

   # Add zone to master using RNDC
  r = isc.rndc((MASTER, RNDCPORT), RNDCALGO, RNDCKEY)
  response = r.call('addzone %s {type master; file "%s%s.db";};' % (name, ZONEPATH, name))
  if response['result'] != '0':
    raise Exception("Error adding zone to master: %s" % response['err'])

   # Update catalog zone
  update = dns.update.Update(CATZONE)
  hash = hashlib.sha1(dns.name.from_text(name).to_wire()).hexdigest()
  update.add('%s.zones' % hash, 3600, 'ptr', '%s.' % name)
  response = dns.query.tcp(update, MASTER, port=DNSPORT)
  if response.rcode() != 0:
    raise Exception("Error updating catalog zone: %d" % response.rcode())

add_zone(sys.argv[1])

We can use this script to add a new zone:

python ./catz-add.py example2.com

Which will be immediately served by both master and slave:

$ dig +short @10.53.0.1 -p 5300 soa example2.com
. . 1 3600 3600 3600 3600
$ dig +short @10.53.0.2 -p 5300 soa example2.com
. . 1 3600 3600 3600 3600

We can obviously also delete zones, an example script for this purpose:

#!/usr/bin/python
# catz-del.py
import sys
import os
import isc
import dns.query
import dns.update
import dns.name
import hashlib
 
ZONEPATH='/tmp/'
MASTER='10.53.0.1'
DNSPORT=5300
RNDCPORT=9953
RNDCALGO='sha256'
RNDCKEY='1234abcd8765'
CATZONE='catalog.example'
 
def del_zone(name):
  # Update catalog zone
  update = dns.update.Update(CATZONE)  
  hash = hashlib.sha1(dns.name.from_text(name).to_wire()).hexdigest()
  update.delete('%s.zones' % hash)
  response = dns.query.tcp(update, MASTER, port=DNSPORT)  
  if response.rcode() != 0:
    raise Exception("Error updating catalog zone: %d" % response.rcode())
 
  # Delete zone from master using RNDC
  r = isc.rndc((MASTER, DNSPORT), RNDCALGO, RNDCKEY)
  response = r.call('delzone %s' % name)
  if response['result'] != '0':
    raise Exception("Error deleting zone from master: %s" % response['err'])
 
   # Delete zone file
  os.unlink('%s%s.db' % (ZONEPATH, name))
 
del_zone(sys.argv[1])

What was shown above isn't anything amazing and could be easily achieved by simply adding the zones to the slave using rndc addzone. The advantage of the Catalog Zones is that no matter how many slaves you have the zones catalog is kept in one central place - in a catalog zone, on the master server. If we now launch ns3 it will download this configured catalog zone and immediately add the previously configured example.com and example2.com zones and start serving them:

$ dig +short @10.53.0.3 -p 5300 soa example.com
. . 1 3600 3600 3600 3600
$ dig +short @10.53.0.3 -p 5300 soa example2.com
. . 1 3600 3600 3600 3600


© 2001-2016 Internet Systems Consortium

Please help us to improve the content of our knowledge base by letting us know below how we can improve this article.

If you have a technical question or problem on which you'd like help, please don't submit it here as article feedback.

For assistance with problems and questions for which you have not been able to find an answer in our Knowledge Base, we recommend searching our community mailing list archives and/or posting your question there (you will need to register there first for your posts to be accepted). The bind-users and the dhcp-users lists particularly have a long-standing and active membership.

ISC relies on the financial support of the community to fund the development of its open source software products. If you would like to support future product evolution and maintenance as well having peace of mind knowing that our team of experts are poised to provide you with individual technical assistance whenever you call upon them, then please consider our Professional Subscription Support services - details can be found on our main website.

Feedback
  • There is no feedback for this article
Info Submit Feedback on this Article
Nickname: Your Email: Subject: Comment:
Enter the code below:
Quick Jump Menu