From 3f9c6a3a929694715d756e023de4447de554e4c4 Mon Sep 17 00:00:00 2001 From: Webslice Date: Thu, 17 Jan 2019 20:16:53 +0100 Subject: [PATCH] Add support for powerdns 4.x, fixes #5223 --- .../plugins-available/powerdns_plugin.inc.php | 108 +++++++++++------- 1 file changed, 67 insertions(+), 41 deletions(-) diff --git a/server/plugins-available/powerdns_plugin.inc.php b/server/plugins-available/powerdns_plugin.inc.php index f5f5158c4..1ecdfaf50 100644 --- a/server/plugins-available/powerdns_plugin.inc.php +++ b/server/plugins-available/powerdns_plugin.inc.php @@ -7,14 +7,14 @@ All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of ISPConfig nor the names of its contributors - may be used to endorse or promote products derived from this software without - specific prior written permission. + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of ISPConfig nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -97,7 +97,7 @@ class powerdns_plugin { /* - This function is called when the plugin is loaded + This function is called when the plugin is loaded */ function onLoad() { @@ -421,15 +421,23 @@ class powerdns_plugin { } } - function find_pdns_pdnssec() { + function find_pdns_pdnssec_or_pdnsutil() { $output = array(); $retval = ''; + + // The command is named pdnssec in PowerDNS 3 exec("type -p pdnssec", $output, $retval); if ($retval == 0 && is_file($output[0])){ return $output[0]; - } else { - return false; } + + // But in PowerNDS 4 they renamed it to pdnsutil + exec("type -p pdnsutil", $output, $retval); + if ($retval == 0 && is_file($output[0])){ + return $output[0]; + } + + return false; } function zoneRediscover() { @@ -466,6 +474,14 @@ class powerdns_plugin { } } + function is_pdns_version_supported() { + if (preg_match('/^[34]/',$this->get_pdns_version())) { + return true; + } + + return false; + } + function handle_dnssec($data) { // If origin changed, delete keys first if ($data['old']['origin'] != $data['new']['origin']) { @@ -475,14 +491,14 @@ class powerdns_plugin { } // If DNSSEC is disabled, but was enabled before, just disable DNSSEC but leave the keys in dns_info - if ($data['new']['dnssec_wanted'] === 'N' && $data['old']['dnssec_initialized'] === 'Y') { + if ($data['new']['dnssec_wanted'] === 'N' && $data['old']['dnssec_wanted'] === 'Y') { $this->soa_dnssec_disable($data); return; } // If DNSSEC is wanted, enable it - if ($data['new']['dnssec_wanted'] === 'Y') { + if ($data['new']['dnssec_wanted'] === 'Y' && $data['old']['dnssec_wanted'] === 'N') { $this->soa_dnssec_create($data); } } @@ -490,11 +506,11 @@ class powerdns_plugin { function soa_dnssec_create($data) { global $app; - if (!preg_match('/^3/',$this->get_pdns_version()) ) { + if (false === $this->is_pdns_version_supported()) { return; } - $pdns_pdnssec = $this->find_pdns_pdnssec(); + $pdns_pdnssec = $this->find_pdns_pdnssec_or_pdnsutil(); if ($pdns_pdnssec === false) { return; } @@ -504,9 +520,13 @@ class powerdns_plugin { // We don't log the actual commands here, because having commands in the dnssec_info field will trigger // the IDS if you try to save the record using the interface afterwards. - $cmd_secure_zone = sprintf('%s secure-zone %s 2>&1', $pdns_pdnssec, $zone); - $log[] = sprintf("\r\n%s %s", date('c'), 'Running secure-zone command...'); - exec($cmd_secure_zone, $log); + $cmd_add_zone_key_ksk = sprintf('%s add-zone-key %s ksk active 2048 rsasha256', $pdns_pdnssec, $zone); + $log[] = sprintf("\r\n%s %s", date('c'), 'Running add-zone-key ksk command...'); + exec($cmd_add_zone_key_ksk, $log); + + $cmd_add_zone_key_zsk = sprintf('%s add-zone-key %s zsk active 1024 rsasha256', $pdns_pdnssec, $zone); + $log[] = sprintf("\r\n%s %s", date('c'), 'Running add-zone-key zsk command...'); + exec($cmd_add_zone_key_zsk, $log); $cmd_set_nsec3 = sprintf('%s set-nsec3 %s "1 0 10 deadbeef" 2>&1', $pdns_pdnssec, $zone); $log[] = sprintf("\r\n%s %s", date('c'), 'Running set-nsec3 command...'); @@ -539,17 +559,19 @@ class powerdns_plugin { switch ($part = substr($line, 0, 3)) { case 'ID ': // Only process active keys - if (!strpos($line, 'Active: 1')) { - continue; + // 'Active: 1' is pdnssec (PowerDNS 3.x) output + // 'Active (' is pdnsutil (PowerDNS 4.x) output + if (!strpos($line, 'Active: 1') && !strpos($line, 'Active ( ')) { + break; } - // Determine key type (KSK or ZSK) - preg_match('/(KSK|ZSK)/', $line, $matches_key_type); + // Determine key type (KSK, ZSK or CSK) + preg_match('/(KSK|ZSK|CSK)/', $line, $matches_key_type); $key_type = $matches_key_type[1]; - // We only care about the KSK - if ('ZSK' === $key_type) { - continue; + // We only care about the KSK or CSK + if (!in_array($key_type, ['KSK', 'CSK'], true)) { + break; } // Determine key tag @@ -568,6 +590,7 @@ class powerdns_plugin { break; case 'KSK': + case 'CSK': // Determine DNSKEY preg_match('/ IN DNSKEY \d+ \d+ \d+ (.*) ;/', $line, $matches_dnskey); $formatted[] = sprintf('DNSKEY: %s', $matches_dnskey[1]); @@ -604,11 +627,11 @@ class powerdns_plugin { function soa_dnssec_disable($data) { global $app; - if (!preg_match('/^3/',$this->get_pdns_version()) ) { + if (false === $this->is_pdns_version_supported()) { return; } - $pdns_pdnssec = $this->find_pdns_pdnssec(); + $pdns_pdnssec = $this->find_pdns_pdnssec_or_pdnsutil(); if ($pdns_pdnssec === false) { return; } @@ -631,11 +654,11 @@ class powerdns_plugin { function soa_dnssec_delete($data) { global $app; - if (!preg_match('/^3/',$this->get_pdns_version()) ) { + if (false === $this->is_pdns_version_supported()) { return; } - $pdns_pdnssec = $this->find_pdns_pdnssec(); + $pdns_pdnssec = $this->find_pdns_pdnssec_or_pdnsutil(); if ($pdns_pdnssec === false) { return; } @@ -661,17 +684,20 @@ class powerdns_plugin { function rectifyZone($data) { global $app, $conf; - if ( preg_match('/^3/',$this->get_pdns_version()) ) { - $pdns_pdnssec = $this->find_pdns_pdnssec(); - if ( $pdns_pdnssec != false ) { - if (isset($data["new"]["origin"])) { - //* data has origin field only for SOA recordtypes - exec($pdns_pdnssec . ' rectify-zone ' . rtrim($data["new"]["origin"],".")); - } else { - // get origin from DB for all other recordtypes - $zn = $app->db->queryOneRecord("SELECT d.name AS name FROM powerdns.domains d, powerdns.records r WHERE r.ispconfig_id=? AND r.domain_id = d.id", $data["new"]["id"]); - exec($pdns_pdnssec . ' rectify-zone ' . trim($zn["name"])); - } + + if (false === $this->is_pdns_version_supported()) { + return; + } + + $pdns_pdnssec = $this->find_pdns_pdnssec_or_pdnsutil(); + if ( $pdns_pdnssec != false ) { + if (isset($data["new"]["origin"])) { + //* data has origin field only for SOA recordtypes + exec($pdns_pdnssec . ' rectify-zone ' . rtrim($data["new"]["origin"],".")); + } else { + // get origin from DB for all other recordtypes + $zn = $app->db->queryOneRecord("SELECT d.name AS name FROM powerdns.domains d, powerdns.records r WHERE r.ispconfig_id=? AND r.domain_id = d.id", $data["new"]["id"]); + exec($pdns_pdnssec . ' rectify-zone ' . trim($zn["name"])); } } } -- GitLab