PowerDNS scripts

The last few years I did create multiple scripts that could be used with PowerDNS auth. All scripts are tested with PowerDNS auth 3.2.

For help installing and using the scripts I strongly suggest mailing to info@sinnerg.nl and asking for a quote for the problems you have.

Cleaning “old” domains where you are the slave from PowerDNS:

<?php
// Script created by Mark Scholten (www.mscholten.eu) for SinnerG BV (www.sinnerg.nl)
// Distribution is allowed if you don't change this copyright notice
// Changing this code is allowed if you don't change this copyright notice (at least for the parts created by Mark Scholten)
// Asking money for this script is allowed, however if you didn't change it don't say you created it (if you want to donate money, please donate it to PowerDNS)
// Mark Scholten and SinnerG BV provide this script "as is" and without any warranties, it is possible that there are errors in this script
 
// This script requires that the column failed is added to the domains table in the powerdns database, without it it will not work. int(5) should really be enough for this column
 
mysql_connect(  'localhost', // host
'user', //username
'pass'); //pass
mysql_select_db('pdns');
$test = 0; // change to 0 to delete records/domains after $checks tests that failed, if set to something else it will not delete anything
$checks = 7; // define the number of checks before deleting records, this has to be a number. Setting it to 0 will clean it immediately after 1 failed check
$verbose = 0; // set to 1 to be verbose (output domainnames that are deleted/are to be deleted (depending on the $test setting)
 
function is_stil_active($domain,$server){
$axfr = shell_exec("dig AXFR ".$domain." @".$server."");
$explode = explode("XFR size:",$axfr);
if(isset($explode['1'])){
return TRUE;
}else{
sleep(1);
$axfr = shell_exec("dig AXFR ".$domain." @".$server."");
$explode = explode("XFR size:",$axfr);
if(isset($explode['1'])){
return TRUE;
}else{
return FALSE;
}
}
}
$timestamp = time()-(24*3600); // get the timestamp for 24 hours ago
 
mysql_query("UPDATE domains SET `failed`=0 WHERE `type`='SLAVE' AND `last_check` > ".$timestamp." AND `failed` NOT LIKE '0'");
 
$sql3 = "SELECT `id`,`name`,`master`,`failed`,`account` FROM domains WHERE `type`='SLAVE' AND `last_check` < ".$timestamp;
$query = mysql_query($sql3) or die(mysql_error());
$dump = '';
if(mysql_num_rows($query) == FALSE){
}else{
while($record = mysql_fetch_object($query)){
if(!is_stil_active($record->name,$record->master)){
if($test === 0){
mysql_query("UPDATE domains SET `failed`=failed+1 WHERE id='".$record->id."'") or die(mysql_error());
if($record->failed >= $checks){
mysql_query("DELETE FROM records WHERE domain_id='".$record->id."'");
mysql_query("DELETE FROM cryptokeys WHERE domain_id='".$record->id."'");
mysql_query("DELETE FROM domains WHERE id='".$record->id."'");
mysql_query("DELETE FROM domainmetadata WHERE domain_id='".$record->id."'");
//mysql_query("DELETE FROM dnssec WHERE domain_id='".$record->id."'"); // a table we use internally for the dnssec data (with some scripts it can be requested remote (read only) by our domain management UI)
}
}
if($verbose === 1){
echo $record->name."
";
}
$dump .= $record->name." - ".$record->master." - ".$record->account." - ".$record->failed."\r\n";
}elseif($record->failed != 0){
mysql_query("UPDATE domains SET `failed`=0 WHERE id='".$record->id."'") or die(mysql_error());
}
 
}
if($verbose === 1){
echo "Done
";
}
if($dump != ''){
//mail("mark@streamservice.nl","AXFR failed for the following domain names",$dump);
}
}
?>

Required for this to work is:

ALTER TABLE `domains` ADD `failed` INT( 5 ) NOT NULL

 

We also have a script to put all DNSSEC related information in a database, this will automatically sign domains:

<?php
// Start config
$mysqlhost = "127.0.0.1"; //mysql server
$mysqluser = "user"; // mysql user
$mysqlpass = "pass"; // mysql pass
$mysqldaba = "pdns"; //mysql database
$pdnssec = "/usr/bin/pdnssec"; // pdnssec
// End config
 
$mysqli = mysqli_init();
if(!$mysqli){
die('FATAL ERROR: mysqli_init failed');
}
if(!$mysqli->real_connect($mysqlhost, $mysqluser, $mysqlpass, $mysqldaba)){
die('FATAL ERROR: mysqli->real_connect failed');
}
$query = $mysqli->query('SELECT id,name,changed FROM `domains` WHERE `type` NOT LIKE "SLAVE"') or die($mysqli->error);
if($query->num_rows == "0"){
}else{
while($row = $query->fetch_array(MYSQLI_ASSOC)){
exec($pdnssec." show-zone ".$row['name']." 2>&1", &$output, $retval);
$dnssec = 0;
$ds = 1;
$dnskey = 1;
unset($ds);
unset($dnskey);
foreach($output as $line){
if($line == "Zone has NSEC semantics"){
$dnssec++;
}elseif($line == "Zone is not presigned"){
$dnssec++;
}elseif($line == "keys:"){
$dnssec++;
}else{
$expl = explode(' ',$line);
if($expl[0] === "DS"){
$expl2 = explode('DS',$line,3);
$ds[] = trim($expl2[2]);
unset($expl2);
}elseif($expl[0] === "KSK"){
$expl2 = explode('DNSKEY',$line,3);
$dnskey[] = trim($expl2[2]);
unset($expl2);
}
unset($expl);
}
}
unset($output);
if($dnssec !== 3){
exec($pdnssec." secure-zone ".$row['name']." 2>&1", &$output, $retval);
$secure = 0;
foreach($output as $line){
if($line == "Zone ".$row['name']." secured"){
$secure++;
}
}
unset($output);
if($secure !== 1){
exec($pdnssec." secure-zone ".$row['name']." 2>&1", &$output, $retval);
$secure = 0;
foreach($output as $line){
if($line == "Zone ".$row['name']." secured"){
$secure++;
}
}
unset($output);
if($secure !== 1){
exec($pdnssec." secure-zone ".$row['name']." 2>&1", &$output, $retval);
$secure = 0;
foreach($output as $line){
if($line == "Zone ".$row['name']." secured"){
$secure++;
}
}
unset($output);
if($secure !== 1){
exec($pdnssec." secure-zone ".$row['name']." 2>&1", &$output, $retval);
$secure = 0;
foreach($output as $line){
if($line == "Zone ".$row['name']." secured"){
$secure++;
}
}
unset($output);
}
}
}
exec($pdnssec." show-zone ".$row['name']." 2>&1", &$output, $retval);
$dnssec = 0;
foreach($output as $line){
if($line == "Zone has NSEC semantics"){
$dnssec++;
}elseif($line == "Zone is not presigned"){
$dnssec++;
}elseif($line == "keys:"){
$dnssec++;
}else{
$expl = explode(' ',$line);
if($expl[0] === "DS"){
$expl2 = explode('DS',$line,3);
$ds[] = trim($expl2[2]);
unset($expl2);
}elseif($expl[0] === "KSK"){
$expl2 = explode('DNSKEY',$line,3);
$dnskey[] = trim($expl2[2]);
unset($expl2);
}
unset($expl);
}
}
unset($output);
}
if(is_array($ds) && is_array($dnskey)){
$mysqli->query('DELETE FROM `dnssec` WHERE `domainid` LIKE '.$row['id'].'');
foreach($ds as $record){
$mysqli->query('INSERT INTO `dnssec` (`domainid`,`type`,`record`) VALUES ("'.$row['id'].'","DS","'.$record.'")');
}
foreach($dnskey as $record){
$mysqli->query('INSERT INTO `dnssec` (`domainid`,`type`,`record`) VALUES ("'.$row['id'].'","DNSKEY","'.$record.'")');
}
//echo $row['name']." secured and key stored.\r\n";
}
}
}
?>

This script requires an additional table, you can create this table with:

CREATE TABLE IF NOT EXISTS `dnssec` (
`id` bigint(255) NOT NULL auto_increment,
`domainid` int(255) NOT NULL,
`type` varchar(10) default NULL,
`record` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `domainid` (`domainid`,`type`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

To rectify all domains you can use the script below. For every change you do on the domains and records table you need to update the domains table and increase changed with 1. The script you can use is listed below:

<?php
// Script created by Mark Scholten (www.mscholten.eu) for SinnerG BV (www.sinnerg.nl)
// Distribution is allowed if you don't change this copyright notice
// Changing this code is allowed if you don't change this copyright notice (at least for the parts created by Mark Scholten)
// Asking money for this script is allowed, however if you didn't change it don't say you created it (if you want to donate money, please donate it to PowerDNS)
// Mark Scholten and SinnerG BV provide this script "as is" and without any warranties, it is possible that there are errors in this script
 
// This script assumes that there is an additional column in the domains table that contains the number of changes since the last time this script did run, we run this script every minute so the number is low (normally 0)
// If this isn't done there might be problems with domains not resolving, a default value for this column of 1 is probably the easiest option so you only need to update it (+1) when you update/remove/add a record
 
// Start config
$mysqlhost = "127.0.0.1"; //mysql server
$mysqluser = "user"; // mysql user
$mysqlpass = "pass"; // mysql pass
$mysqldaba = "database"; //mysql database
$pdnssec = "/usr/bin/pdnssec"; // pdnssec
// End config
 
$mysqli = mysqli_init();
if(!$mysqli){
die('FATAL ERROR: mysqli_init failed');
}
if(!$mysqli->real_connect($mysqlhost, $mysqluser, $mysqlpass, $mysqldaba)){
die('FATAL ERROR: mysqli->real_connect failed');
}
$query = $mysqli->query('SELECT id,name,changed FROM `domains` WHERE `changed` NOT LIKE "0"') or die($mysqli->error);
if($query->num_rows == "0"){
}else{
while($row = $query->fetch_array(MYSQLI_ASSOC)){
$output = passthru($pdnssec." rectify-zone ".$row['name'], $retval);
$mysqli->query("UPDATE `domains` SET `changed` = `changed`-".$row['changed']." WHERE `id` = ".$row['id']." LIMIT 1");
}
}
 
// To start ordering rectify-zone to all domain names without another system being the master: UPDATE `domains` SET `changed` = +1 WHERE `master` IS NULL;
// ALTER TABLE `domains` ADD `changed` INT( 5 ) NOT NULL;
?>

For this to work the following is required:

ALTER TABLE `domains` ADD `changed` INT( 5 ) NOT NULL