Exporting PowerDNS Zones to Bind Files
Can you easily export PowerDNS zones using a MySQL DB? The answer may not be as easy as it seems.
I have been working on a Migration from PowerDNS using a MySQL DB. We have a custom solution which gets updated and gets pushed to Akamai. The problem is, this custom solution requires all the zones to be in bind format. Doing some research I found out there is no easy way to get these zones into a bind zone file. You could setup a secondary server and do zone transfers, but that wouldnt meet my requirements.
Luckily I stumbled across this post by James Linden in which he created a PHP script that scrapes the entire database and then generates a bind file for each zone with the records.
It is actually a pretty easy script to run, you need to fill in about 5 variables and then you are good to execute it. Here is a copy of the script in case it is no longer available. (It was created in 2013, but still works flawlessly!)
All you need to do is update the 3 lines, to put in the MySQL DB IP, the username, password and database name. You will then enter in the nameservers and hostmaster to be used for the bind files.
1#!/bin/env php
2<?php
3
4/**
5 * @copyright 2013 James Linden <[email protected]>
6 * @author James Linden <[email protected]>
7 * @url http://jameslinden.com/code/powerdns-to-bind-zone
8 * @license BSD (2 clause) <http://www.opensource.org/licenses/BSD-2-Clause>
9 */
10
11$pdns_db = [ 'host' => 'localhost', 'user' => 'root', 'pass' => 'powerdns', 'name' => 'powerdns' ];
12$zone_ns = [ 'ns1.lab.local', 'ns2.lab.local' ];
13$zone_adm = 'support.lab.local';
14
15$zones = [];
16$db = new mysqli( $pdns_db['host'], $pdns_db['user'], $pdns_db['pass'], $pdns_db['name'] );
17if( $q = $db->query( 'SELECT * FROM domains' ) ) {
18 while( $r = $q->fetch_assoc() ) {
19 $d = strtolower( $r['name'] );
20 if( $q1 = $db->query( 'SELECT * FROM records WHERE domain_id=' . $r['id'] ) ) {
21 $x = [ 'A' => [], 'CNAME' => [], 'NS' => [], 'MX' => [], 'TXT' => [] ];
22 while( $r1 = $q1->fetch_assoc() ) {
23 $r1['name'] = strtolower( $r1['name'] );
24 switch( $r1['type'] ) {
25 case 'A':
26 $x[ $r1['type'] ][] = [ $r1['name'], $r1['content'] ];
27 break;
28 case 'CNAME':
29 $x[ $r1['type'] ][] = [ trim( str_replace( $d, null, $r1['name'] ), '.' ), strtolower( $r1['content'] ) ];
30 break;
31 case 'NS':
32 $x[ $r1['type'] ][] = strtolower( $r1['content'] );
33 break;
34 case 'MX':
35 $x[ $r1['type'] ][] = [ (int)$r1['prio'], strtolower( $r1['content'] ) ];
36 break;
37 case 'TXT':
38 $x[ $r1['type'] ][] = [ trim( str_replace( $d, null, $r1['name'] ), '.' ), $r1['content'] ];
39 break;
40 }
41 }
42 $q1->free();
43 }
44 $zones[ $d ] = $x;
45 }
46 $q->free();
47}
48$db->close();
49
50if( is_array( $zones ) && count( $zones ) > 0 ) {
51 $p = './tmp/';
52 if( !is_dir( $p ) ) {
53 if( !mkdir( $p ) ) {
54 die( 'Unable to make tmp directory' . PHP_EOL );
55 }
56 }
57 if( count( $zones ) > 0 ) {
58 foreach( $zones as $d => $r ) {
59 $x = ' ';
60 $t = [ '$TTL 43200', null, '@ IN SOA ' . $zone_ns[0] . '. ' . $zone_adm . '. (', $x . time(), $x . '7200', $x . '3600', $x . '604800', $x . '43200 )', null ];
61 foreach( $zone_ns as $x ) {
62 $t[] = ' IN NS ' . $x . '.';
63 }
64 $t[] = null;
65 foreach( $r['MX'] as $x ) {
66 $t[] = ' IN MX ' . str_pad( $x[0], 5, ' ', STR_PAD_RIGHT ) . $x[1] . ( is_numeric( substr( $x[1], -1, 1 ) ) ? null : '.' );
67 }
68 $t[] = null;
69 foreach( $r['A'] as $x ) {
70 $t[] = str_pad( $x[0] . '.', 32, ' ', STR_PAD_RIGHT ) . ' IN A ' . $x[1];
71 }
72 $t[] = null;
73 foreach( $r['CNAME'] as $x ) {
74 $t[] = str_pad( $x[0], 32, ' ', STR_PAD_RIGHT ) . ' IN CNAME ' . $x[1] . '.';
75 }
76 $t[] = null;
77 foreach( $r['TXT'] as $x ) {
78 $t[] = str_pad( $x[0], 32, ' ', STR_PAD_RIGHT ) . ' IN TXT ' . $x[1];
79 }
80 file_put_contents( $p . $d . '.zone', implode( PHP_EOL, $t ) . PHP_EOL );
81 }
82 }
83}
84
85?>
Once you have populated the script, you can run it by going to a commandline that has MySQL tools and PHP installed and run
1php scriptname.php
This will create a /tmp folder in the same directory with an export of all your zones.
Thats it! I just wanted to blog about this in case other people were looking for a way to accomplish this, its actually quite simple!
Thanks for stopping by.
comments powered by Disqus