From b6f99958fda6b2492e8fdeabed45dc8ab6435265 Mon Sep 17 00:00:00 2001 From: Daniel Reichelt Date: Fri, 17 Jun 2016 14:32:06 +0200 Subject: [PATCH 1/7] dns: fix generation of alias records for subdomains The checks whether or not to create wildcard/www records for subdomains wrongly depended on the setting of the parent domain instead of the subdomain in question. --- lib/functions/dns/function.createDomainZone.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/functions/dns/function.createDomainZone.php b/lib/functions/dns/function.createDomainZone.php index 424c6ceb..3fadb2ec 100644 --- a/lib/functions/dns/function.createDomainZone.php +++ b/lib/functions/dns/function.createDomainZone.php @@ -67,7 +67,7 @@ function createDomainZone($domain_id, $froxlorhostname = false) { // additional required records for subdomains $subdomains_stmt = Database::prepare(" - SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "` + SELECT `domain`, `iswildcarddomain`, `wwwserveralias` FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `parentdomainid` = :domainid "); Database::pexecute($subdomains_stmt, array( @@ -81,10 +81,10 @@ function createDomainZone($domain_id, $froxlorhostname = false) addRequiredEntry(str_replace('.' . $domain['domain'], '', $subdomain['domain']), 'AAAA', $required_entries); // Check whether to add a www.-prefix - if ($domain['iswildcarddomain'] == '1') { + if ($subdomain['iswildcarddomain'] == '1') { addRequiredEntry('*.' . str_replace('.' . $domain['domain'], '', $subdomain['domain']), 'A', $required_entries); addRequiredEntry('*.' . str_replace('.' . $domain['domain'], '', $subdomain['domain']), 'AAAA', $required_entries); - } elseif ($domain['wwwserveralias'] == '1') { + } elseif ($subdomain['wwwserveralias'] == '1') { addRequiredEntry('www.' . str_replace('.' . $domain['domain'], '', $subdomain['domain']), 'A', $required_entries); addRequiredEntry('www.' . str_replace('.' . $domain['domain'], '', $subdomain['domain']), 'AAAA', $required_entries); } From d6dc71436abcfb94d97bffecfa381ce521b1eaef Mon Sep 17 00:00:00 2001 From: Daniel Reichelt Date: Fri, 17 Jun 2016 15:32:58 +0200 Subject: [PATCH 2/7] dns: fix generation of imap/pop3/mail/smtp A/AAAA-records The dns-editor introduced a regression where imap/pop3/mail/smtp A-records would not get created, even tough the setting system.dns_createmailentry was enabled. fix A fix --- lib/functions/dns/function.createDomainZone.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/functions/dns/function.createDomainZone.php b/lib/functions/dns/function.createDomainZone.php index 3fadb2ec..7eb878a8 100644 --- a/lib/functions/dns/function.createDomainZone.php +++ b/lib/functions/dns/function.createDomainZone.php @@ -52,6 +52,13 @@ function createDomainZone($domain_id, $froxlorhostname = false) addRequiredEntry('@', 'NS', $required_entries); if ($domain['isemaildomain'] === '1') { addRequiredEntry('@', 'MX', $required_entries); + if (Settings::Get('system.dns_createmailentry')) { + foreach(['imap', 'pop3', 'mail', 'smtp'] as $record) { + foreach(['AAAA', 'A'] as $type) { + addRequiredEntry($record, $type, $required_entries); + } + } + } } // additional required records by setting From 5f9962b6ba401ca386eb9b1e76269cc8a3c5b45e Mon Sep 17 00:00:00 2001 From: Daniel Reichelt Date: Fri, 17 Jun 2016 19:55:00 +0200 Subject: [PATCH 3/7] dns: fix generation of zone serials --- lib/functions/dns/function.createDomainZone.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/functions/dns/function.createDomainZone.php b/lib/functions/dns/function.createDomainZone.php index 7eb878a8..29076004 100644 --- a/lib/functions/dns/function.createDomainZone.php +++ b/lib/functions/dns/function.createDomainZone.php @@ -272,9 +272,22 @@ function createDomainZone($domain_id, $froxlorhostname = false) $primary_ns = Settings::Get('system.hostname'); } - // TODO for now, dummy time-periods + $date = date('Ymd'); + $domain['bindserial'] = (preg_match('/^' . $date . '/', $domain['bindserial']) ? + $domain['bindserial'] + 1 : + $date . '00'); + if (!$froxlorhostname) { + $upd_stmt = Database::prepare(" + UPDATE `" . TABLE_PANEL_DOMAINS . "` SET + `bindserial` = :serial + WHERE `id` = :id + "); + Database::pexecute($upd_stmt, array('serial' => $domain['bindserial'], 'id' => $domain['id'])); + } + $soa_content = $primary_ns . " " . escapeSoaAdminMail(Settings::Get('panel.adminmail')) . " (" . PHP_EOL; $soa_content .= $domain['bindserial'] . "\t; serial" . PHP_EOL; + // TODO for now, dummy time-periods $soa_content .= "1800\t; refresh (30 mins)" . PHP_EOL; $soa_content .= "900\t; retry (15 mins)" . PHP_EOL; $soa_content .= "604800\t; expire (7 days)" . PHP_EOL; From a400fc9c659e48cff0a893e48a3dc7718a40d246 Mon Sep 17 00:00:00 2001 From: Daniel Reichelt Date: Fri, 17 Jun 2016 19:22:45 +0200 Subject: [PATCH 4/7] dns: no separate zonefiles for ismainbutsubto domains 1/3 move log message --- scripts/classes/class.DnsBase.php | 1 - scripts/jobs/cron_tasks.inc.dns.10.bind.php | 69 +++++++++++---------- scripts/jobs/cron_tasks.inc.dns.20.pdns.php | 51 ++++++++------- 3 files changed, 63 insertions(+), 58 deletions(-) diff --git a/scripts/classes/class.DnsBase.php b/scripts/classes/class.DnsBase.php index ba7a8506..ea63b3c4 100644 --- a/scripts/classes/class.DnsBase.php +++ b/scripts/classes/class.DnsBase.php @@ -98,7 +98,6 @@ abstract class DnsBase } if (empty($domains)) { - $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'No domains found for nameserver-config, skipping...'); return null; } diff --git a/scripts/jobs/cron_tasks.inc.dns.10.bind.php b/scripts/jobs/cron_tasks.inc.dns.10.bind.php index 89120e98..330676df 100644 --- a/scripts/jobs/cron_tasks.inc.dns.10.bind.php +++ b/scripts/jobs/cron_tasks.inc.dns.10.bind.php @@ -35,40 +35,43 @@ class bind extends DnsBase $domains = $this->getDomainList(); - if (! empty($domains)) { - $bindconf_file = '# ' . Settings::Get('system.bindconf_directory') . 'froxlor_bind.conf' . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n\n"; - - foreach ($domains as $domain) { - // check for system-hostname - $isFroxlorHostname = false; - if (isset($domain['froxlorhost']) && $domain['froxlorhost'] == 1) { - $isFroxlorHostname = true; - } - // create zone-file - $this->_logger->logAction(CRON_ACTION, LOG_DEBUG, 'Generating dns zone for ' . $domain['domain']); - $zone = createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname); - $zonefile = (string)$zone; - $domain['zonefile'] = 'domains/' . $domain['domain'] . '.zone'; - $zonefile_name = makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . $domain['zonefile']); - $zonefile_handler = fopen($zonefile_name, 'w'); - fwrite($zonefile_handler, $zonefile); - fclose($zonefile_handler); - $this->_logger->logAction(CRON_ACTION, LOG_INFO, '`' . $zonefile_name . '` zone written'); - - // generate config - $bindconf_file .= $this->_generateDomainConfig($domain); - } - - // write config - $bindconf_file_handler = fopen(makeCorrectFile(Settings::Get('system.bindconf_directory') . '/froxlor_bind.conf'), 'w'); - fwrite($bindconf_file_handler, $bindconf_file); - fclose($bindconf_file_handler); - $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'froxlor_bind.conf written'); - - // reload Bind - safe_exec(escapeshellcmd(Settings::Get('system.bindreload_command'))); - $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Bind9 reloaded'); + if (empty($domains)) { + $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'No domains found for nameserver-config, skipping...'); + return; } + + $bindconf_file = '# ' . Settings::Get('system.bindconf_directory') . 'froxlor_bind.conf' . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n\n"; + + foreach ($domains as $domain) { + // check for system-hostname + $isFroxlorHostname = false; + if (isset($domain['froxlorhost']) && $domain['froxlorhost'] == 1) { + $isFroxlorHostname = true; + } + // create zone-file + $this->_logger->logAction(CRON_ACTION, LOG_DEBUG, 'Generating dns zone for ' . $domain['domain']); + $zone = createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname); + $zonefile = (string)$zone; + $domain['zonefile'] = 'domains/' . $domain['domain'] . '.zone'; + $zonefile_name = makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . $domain['zonefile']); + $zonefile_handler = fopen($zonefile_name, 'w'); + fwrite($zonefile_handler, $zonefile); + fclose($zonefile_handler); + $this->_logger->logAction(CRON_ACTION, LOG_INFO, '`' . $zonefile_name . '` zone written'); + + // generate config + $bindconf_file .= $this->_generateDomainConfig($domain); + } + + // write config + $bindconf_file_handler = fopen(makeCorrectFile(Settings::Get('system.bindconf_directory') . '/froxlor_bind.conf'), 'w'); + fwrite($bindconf_file_handler, $bindconf_file); + fclose($bindconf_file_handler); + $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'froxlor_bind.conf written'); + + // reload Bind + safe_exec(escapeshellcmd(Settings::Get('system.bindreload_command'))); + $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Bind9 reloaded'); } private function _generateDomainConfig($domain = array()) diff --git a/scripts/jobs/cron_tasks.inc.dns.20.pdns.php b/scripts/jobs/cron_tasks.inc.dns.20.pdns.php index 3847657d..efc50b31 100644 --- a/scripts/jobs/cron_tasks.inc.dns.20.pdns.php +++ b/scripts/jobs/cron_tasks.inc.dns.20.pdns.php @@ -34,31 +34,34 @@ class pdns extends DnsBase $domains = $this->getDomainList(); - if (! empty($domains)) { - - foreach ($domains as $domain) { - // check for system-hostname - $isFroxlorHostname = false; - if (isset($domain['froxlorhost']) && $domain['froxlorhost'] == 1) { - $isFroxlorHostname = true; - } - // create zone-file - $this->_logger->logAction(CRON_ACTION, LOG_DEBUG, 'Generating dns zone for ' . $domain['domain']); - $zone = createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname); - - $dom_id = $this->_insertZone($zone->origin, $zone->serial); - $this->_insertRecords($dom_id, $zone->records, $zone->origin); - $this->_insertAllowedTransfers($dom_id); - - $this->_logger->logAction(CRON_ACTION, LOG_INFO, '`' . $domain['domain'] . '` zone written'); - } - - $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Database updated'); - - // reload Bind - safe_exec(escapeshellcmd(Settings::Get('system.bindreload_command'))); - $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'pdns reloaded'); + if (empty($domains)) { + $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'No domains found for nameserver-config, skipping...'); + return; } + + + foreach ($domains as $domain) { + // check for system-hostname + $isFroxlorHostname = false; + if (isset($domain['froxlorhost']) && $domain['froxlorhost'] == 1) { + $isFroxlorHostname = true; + } + // create zone-file + $this->_logger->logAction(CRON_ACTION, LOG_DEBUG, 'Generating dns zone for ' . $domain['domain']); + $zone = createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname); + + $dom_id = $this->_insertZone($zone->origin, $zone->serial); + $this->_insertRecords($dom_id, $zone->records, $zone->origin); + $this->_insertAllowedTransfers($dom_id); + + $this->_logger->logAction(CRON_ACTION, LOG_INFO, '`' . $domain['domain'] . '` zone written'); + } + + $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Database updated'); + + // reload Bind + safe_exec(escapeshellcmd(Settings::Get('system.bindreload_command'))); + $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'pdns reloaded'); } private function _cleanZonefiles() From 631e36f4d5bb28e18691f7642f8c782609188627 Mon Sep 17 00:00:00 2001 From: Daniel Reichelt Date: Fri, 17 Jun 2016 19:21:10 +0200 Subject: [PATCH 5/7] dns: no separate zonefiles for ismainbutsubto domains 2/3 rewrite getDomainList() to contain parent-relations --- scripts/classes/class.DnsBase.php | 72 ++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 7 deletions(-) diff --git a/scripts/classes/class.DnsBase.php b/scripts/classes/class.DnsBase.php index ea63b3c4..5103ee0d 100644 --- a/scripts/classes/class.DnsBase.php +++ b/scripts/classes/class.DnsBase.php @@ -69,14 +69,38 @@ abstract class DnsBase protected function getDomainList() { - // get all Domains - $result_domains_stmt = Database::query(" - SELECT `d`.`id`, `d`.`domain`, `d`.`customerid`, `d`.`zonefile`, `c`.`loginname`, `c`.`guid` - FROM `" . TABLE_PANEL_DOMAINS . "` `d` LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`) - WHERE `d`.`isbinddomain` = '1' ORDER BY `d`.`domain` ASC + $result_domains_stmt = Database::query( + " + SELECT + `d`.`id`, + `d`.`domain`, + `d`.`isemaildomain`, + `d`.`iswildcarddomain`, + `d`.`wwwserveralias`, + `d`.`customerid`, + `d`.`zonefile`, + `d`.`bindserial`, + `d`.`dkim`, + `d`.`dkim_id`, + `d`.`dkim_pubkey`, + `d`.`ismainbutsubto`, + `c`.`loginname`, + `c`.`guid` + FROM + `" . TABLE_PANEL_DOMAINS . "` `d` + LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`) + WHERE + `d`.`isbinddomain` = '1' + ORDER BY + `d`.`domain` ASC "); - $domains = $result_domains_stmt->fetchAll(PDO::FETCH_ASSOC); + $domains = array(); + // don't use fetchall() to be able to set the first column to the domain id and use it later on to set the rows' + // array of direct children without having to search the outer array + while ($domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) { + $domains[$domain["id"]] = $domain; + } // frolxor-hostname (#1090) if (Settings::get('system.dns_createhostnameentry') == 1) { @@ -101,7 +125,41 @@ abstract class DnsBase return null; } - return $domains; + // collect domain IDs of direct child domains as arrays in ['children'] column + foreach (array_keys($domains) as $key) { + if (! isset($domains[$key]['children'])) { + $domains[$key]['children'] = array(); + } + if ($domains[$key]['ismainbutsubto'] > 0) { + if (isset($domains[ $domains[$key]['ismainbutsubto'] ])) { + $domains[ $domains[$key]['ismainbutsubto'] ]['children'][] = $domains[$key]['id']; + } else { + $this->_logger->logAction(CRON_ACTION, LOG_ERR, + 'Database inconsistency: domain ' . $domain['domain'] . ' (ID #' . $key . + ') is set to to be subdomain to non-existent domain ID #' . + $domains[$key]['ismainbutsubto'] . + '. No DNS record(s) will be created for this domain.'); + } + } + } + + $this->_logger->logAction(CRON_ACTION, LOG_DEBUG, + str_pad('domId', 9, ' ') . str_pad('domain', 40, ' ') . + 'ismainbutsubto ' . str_pad('parent domain', 40, ' ') . + "list of child domain ids"); + foreach ($domains as $domain) { + $logLine = + str_pad($domain['id'], 9, ' ') . + str_pad($domain['domain'], 40, ' ') . + str_pad($domain['ismainbutsubto'], 15, ' ') . + str_pad(((isset($domains[ $domain['ismainbutsubto'] ])) ? + $domains[ $domain['ismainbutsubto'] ]['domain'] : + '-'), 40, ' ') . + join(', ', $domain['children']); + $this->_logger->logAction(CRON_ACTION, LOG_DEBUG, $logLine); + } + + return $domains; } public function writeDKIMconfigs() From 50317da18597d873129a196d3f097ed12851a479 Mon Sep 17 00:00:00 2001 From: Daniel Reichelt Date: Fri, 17 Jun 2016 20:15:44 +0200 Subject: [PATCH 6/7] dns: no separate zonefiles for ismainbutsubto domains 3/3 replace iteration over $domains array by recursive walkDomainList() --- .../dns/function.createDomainZone.php | 66 +++++++--------- scripts/jobs/cron_tasks.inc.dns.10.bind.php | 78 +++++++++++++------ scripts/jobs/cron_tasks.inc.dns.20.pdns.php | 70 +++++++++++++---- 3 files changed, 138 insertions(+), 76 deletions(-) diff --git a/lib/functions/dns/function.createDomainZone.php b/lib/functions/dns/function.createDomainZone.php index 29076004..b99f193a 100644 --- a/lib/functions/dns/function.createDomainZone.php +++ b/lib/functions/dns/function.createDomainZone.php @@ -14,7 +14,7 @@ * @package Functions * */ -function createDomainZone($domain_id, $froxlorhostname = false) +function createDomainZone($domain_id, $froxlorhostname = false, $isMainButSubTo = false) { if (!$froxlorhostname) { @@ -49,7 +49,9 @@ function createDomainZone($domain_id, $froxlorhostname = false) addRequiredEntry('@', 'A', $required_entries); addRequiredEntry('@', 'AAAA', $required_entries); - addRequiredEntry('@', 'NS', $required_entries); + if (! $isMainButSubTo) { + addRequiredEntry('@', 'NS', $required_entries); + } if ($domain['isemaildomain'] === '1') { addRequiredEntry('@', 'MX', $required_entries); if (Settings::Get('system.dns_createmailentry')) { @@ -96,20 +98,6 @@ function createDomainZone($domain_id, $froxlorhostname = false) addRequiredEntry('www.' . str_replace('.' . $domain['domain'], '', $subdomain['domain']), 'AAAA', $required_entries); } } - - // additional required records for main-but-subdomain-to - $mainbutsub_stmt = Database::prepare(" - SELECT `domain` FROM `" . TABLE_PANEL_DOMAINS . "` - WHERE `ismainbutsubto` = :domainid - "); - Database::pexecute($mainbutsub_stmt, array( - 'domainid' => $domain_id - )); - - while ($mainbutsubtodomain = $mainbutsub_stmt->fetch(PDO::FETCH_ASSOC)) { - // Add NS entry for subdomain-records of "main-but-subdomain-to"-domains, they get their own Zone - addRequiredEntry(str_replace('.' . $domain['domain'], '', $mainbutsubtodomain['domain']), 'NS', $required_entries); - } } // additional required records for SPF and DKIM if activated @@ -272,30 +260,32 @@ function createDomainZone($domain_id, $froxlorhostname = false) $primary_ns = Settings::Get('system.hostname'); } - $date = date('Ymd'); - $domain['bindserial'] = (preg_match('/^' . $date . '/', $domain['bindserial']) ? - $domain['bindserial'] + 1 : - $date . '00'); - if (!$froxlorhostname) { - $upd_stmt = Database::prepare(" - UPDATE `" . TABLE_PANEL_DOMAINS . "` SET - `bindserial` = :serial - WHERE `id` = :id - "); - Database::pexecute($upd_stmt, array('serial' => $domain['bindserial'], 'id' => $domain['id'])); + if (! $isMainButSubTo) { + $date = date('Ymd'); + $domain['bindserial'] = (preg_match('/^' . $date . '/', $domain['bindserial']) ? + $domain['bindserial'] + 1 : + $date . '00'); + if (!$froxlorhostname) { + $upd_stmt = Database::prepare(" + UPDATE `" . TABLE_PANEL_DOMAINS . "` SET + `bindserial` = :serial + WHERE `id` = :id + "); + Database::pexecute($upd_stmt, array('serial' => $domain['bindserial'], 'id' => $domain['id'])); + } + + $soa_content = $primary_ns . " " . escapeSoaAdminMail(Settings::Get('panel.adminmail')) . " (" . PHP_EOL; + $soa_content .= $domain['bindserial'] . "\t; serial" . PHP_EOL; + // TODO for now, dummy time-periods + $soa_content .= "1800\t; refresh (30 mins)" . PHP_EOL; + $soa_content .= "900\t; retry (15 mins)" . PHP_EOL; + $soa_content .= "604800\t; expire (7 days)" . PHP_EOL; + $soa_content .= "1200\t)\t; minimum (20 mins)"; + + $soa_record = new DnsEntry('@', 'SOA', $soa_content); + array_unshift($zonerecords, $soa_record); } - $soa_content = $primary_ns . " " . escapeSoaAdminMail(Settings::Get('panel.adminmail')) . " (" . PHP_EOL; - $soa_content .= $domain['bindserial'] . "\t; serial" . PHP_EOL; - // TODO for now, dummy time-periods - $soa_content .= "1800\t; refresh (30 mins)" . PHP_EOL; - $soa_content .= "900\t; retry (15 mins)" . PHP_EOL; - $soa_content .= "604800\t; expire (7 days)" . PHP_EOL; - $soa_content .= "1200\t)\t; minimum (20 mins)"; - - $soa_record = new DnsEntry('@', 'SOA', $soa_content); - array_unshift($zonerecords, $soa_record); - $zone = new DnsZone((int) Settings::Get('system.defaultttl'), $domain['domain'], $domain['bindserial'], $zonerecords); return $zone; diff --git a/scripts/jobs/cron_tasks.inc.dns.10.bind.php b/scripts/jobs/cron_tasks.inc.dns.10.bind.php index 330676df..091cc6ce 100644 --- a/scripts/jobs/cron_tasks.inc.dns.10.bind.php +++ b/scripts/jobs/cron_tasks.inc.dns.10.bind.php @@ -19,6 +19,8 @@ if (! defined('MASTER_CRONJOB')) class bind extends DnsBase { + private $_bindconf_file = ""; + public function writeConfigs() { // tell the world what we are doing @@ -43,35 +45,67 @@ class bind extends DnsBase $bindconf_file = '# ' . Settings::Get('system.bindconf_directory') . 'froxlor_bind.conf' . "\n" . '# Created ' . date('d.m.Y H:i') . "\n" . '# Do NOT manually edit this file, all changes will be deleted after the next domain change at the panel.' . "\n\n"; foreach ($domains as $domain) { + if ($domain['ismainbutsubto'] > 0) { + // domains with ismainbutsubto>0 are handled by recursion within walkDomainList() + continue; + } + $this->walkDomainList($domain, $domains); + } + + $bindconf_file_handler = fopen(makeCorrectFile(Settings::Get('system.bindconf_directory') . '/froxlor_bind.conf'), 'w'); + fwrite($bindconf_file_handler, $this->_bindconf_file); + fclose($bindconf_file_handler); + $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'froxlor_bind.conf written'); + safe_exec(escapeshellcmd(Settings::Get('system.bindreload_command'))); + $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Bind9 reloaded'); + $domains_dir = makeCorrectDir(Settings::Get('system.bindconf_directory') . '/domains/'); + + $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Task4 finished'); + } + + + private function walkDomainList($domain, $domains) + { + $zoneContent = ''; + $subzones = ''; + + foreach ($domain['children'] as $child_domain_id) { + $subzones .= $this->walkDomainList($domains[$child_domain_id], $domains); + } + + if ($domain['zonefile'] == '') { // check for system-hostname $isFroxlorHostname = false; if (isset($domain['froxlorhost']) && $domain['froxlorhost'] == 1) { $isFroxlorHostname = true; } - // create zone-file - $this->_logger->logAction(CRON_ACTION, LOG_DEBUG, 'Generating dns zone for ' . $domain['domain']); - $zone = createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname); - $zonefile = (string)$zone; - $domain['zonefile'] = 'domains/' . $domain['domain'] . '.zone'; - $zonefile_name = makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . $domain['zonefile']); - $zonefile_handler = fopen($zonefile_name, 'w'); - fwrite($zonefile_handler, $zonefile); - fclose($zonefile_handler); - $this->_logger->logAction(CRON_ACTION, LOG_INFO, '`' . $zonefile_name . '` zone written'); - // generate config - $bindconf_file .= $this->_generateDomainConfig($domain); + if ($domain['ismainbutsubto'] == 0) { + $zoneContent = (string) createDomainZone(($domain['id'] == 'none') ? + $domain : + $domain['id'], + $isFroxlorHostname); + $domain['zonefile'] = 'domains/' . $domain['domain'] . '.zone'; + $zonefile_name = makeCorrectFile(Settings::Get('system.bindconf_directory') . '/' . + $domain['zonefile']); + $zonefile_handler = fopen($zonefile_name, 'w'); + fwrite($zonefile_handler, $zoneContent . $subzones); + fclose($zonefile_handler); + $this->_logger->logAction(CRON_ACTION, LOG_INFO, '`' . $zonefile_name . '` written'); + $this->_bindconf_file .= $this->_generateDomainConfig($domain); + } else { + return (string) createDomainZone(($domain['id'] == 'none') ? + $domain : + $domain['id'], + $isFroxlorHostname, + true); + } + } else { + $this->_logger->logAction(CRON_ACTION, LOG_INFO, + 'Added zonefile ' . $domain['zonefile'] . ' for domain ' . $domain['domain'] . + ' - Note that you will also have to handle ALL records for ALL subdomains.'); + $this->_bindconf_file .= $this->_generateDomainConfig($domain); } - - // write config - $bindconf_file_handler = fopen(makeCorrectFile(Settings::Get('system.bindconf_directory') . '/froxlor_bind.conf'), 'w'); - fwrite($bindconf_file_handler, $bindconf_file); - fclose($bindconf_file_handler); - $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'froxlor_bind.conf written'); - - // reload Bind - safe_exec(escapeshellcmd(Settings::Get('system.bindreload_command'))); - $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Bind9 reloaded'); } private function _generateDomainConfig($domain = array()) diff --git a/scripts/jobs/cron_tasks.inc.dns.20.pdns.php b/scripts/jobs/cron_tasks.inc.dns.20.pdns.php index efc50b31..d0d59ee0 100644 --- a/scripts/jobs/cron_tasks.inc.dns.20.pdns.php +++ b/scripts/jobs/cron_tasks.inc.dns.20.pdns.php @@ -30,7 +30,7 @@ class pdns extends DnsBase $this->_connectToPdnsDb(); // clean up - $this->_cleanZonefiles(); + $this->_clearZoneTables(); $domains = $this->getDomainList(); @@ -39,22 +39,12 @@ class pdns extends DnsBase return; } - foreach ($domains as $domain) { - // check for system-hostname - $isFroxlorHostname = false; - if (isset($domain['froxlorhost']) && $domain['froxlorhost'] == 1) { - $isFroxlorHostname = true; + if ($domain['ismainbutsubto'] > 0) { + // domains with ismainbutsubto>0 are handled by recursion within walkDomainList() + continue; } - // create zone-file - $this->_logger->logAction(CRON_ACTION, LOG_DEBUG, 'Generating dns zone for ' . $domain['domain']); - $zone = createDomainZone(($domain['id'] == 'none') ? $domain : $domain['id'], $isFroxlorHostname); - - $dom_id = $this->_insertZone($zone->origin, $zone->serial); - $this->_insertRecords($dom_id, $zone->records, $zone->origin); - $this->_insertAllowedTransfers($dom_id); - - $this->_logger->logAction(CRON_ACTION, LOG_INFO, '`' . $domain['domain'] . '` zone written'); + $this->walkDomainList($domain, $domains); } $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Database updated'); @@ -64,7 +54,50 @@ class pdns extends DnsBase $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'pdns reloaded'); } - private function _cleanZonefiles() + private function walkDomainList($domain, $domains) + { + $zoneContent = ''; + $subzones = array(); + + foreach ($domain['children'] as $child_domain_id) { + $subzones[] = $this->walkDomainList($domains[$child_domain_id], $domains); + } + + if ($domain['zonefile'] == '') { + // check for system-hostname + $isFroxlorHostname = false; + if (isset($domain['froxlorhost']) && $domain['froxlorhost'] == 1) { + $isFroxlorHostname = true; + } + + if ($domain['ismainbutsubto'] == 0) { + $zoneContent = createDomainZone(($domain['id'] == 'none') ? + $domain : + $domain['id'], + $isFroxlorHostname); + if (count($subzones)) { + array_push($zoneContent->records, ...$subzones); + } + $pdnsDomId = $this->_insertZone($zoneContent->origin, $zoneContent->serial); + $this->_insertRecords($pdnsDomId, $zoneContent->records, $zoneContent->origin); + $this->_insertAllowedTransfers($pdnsDomId); + $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'DB entries stored for zone `' . $domain['domain'] . '`'); + } else { + return createDomainZone(($domain['id'] == 'none') ? + $domain : + $domain['id'], + $isFroxlorHostname, + true); + } + } else { + $this->_logger->logAction(CRON_ACTION, LOG_ERROR, + 'Zonefiles are NOT supported when PowerDNS is selected as DNS daemon (triggered by: ' . + $domain['domain'] . ')'); + $this->_bindconf_file .= $this->_generateDomainConfig($domain); + } + } + + private function _clearZoneTables() { $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Cleaning dns zone entries from database'); @@ -99,6 +132,11 @@ class pdns extends DnsBase foreach ($records as $record) { + if ($record instanceof DnsZone) { + $this->_insertRecords($domainid, $record->records, $record->origin); + continue; + } + if ($record->record == '@') { $_record = $origin; } From b4f90730cc32d008e5d2ad61e69ca042ba02f084 Mon Sep 17 00:00:00 2001 From: Daniel Reichelt Date: Fri, 17 Jun 2016 23:01:37 +0200 Subject: [PATCH 7/7] unify "reloading" the dns daemon --- scripts/classes/class.DnsBase.php | 14 ++++++++++++++ scripts/jobs/cron_tasks.inc.dns.10.bind.php | 5 +---- scripts/jobs/cron_tasks.inc.dns.20.pdns.php | 8 +++----- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/scripts/classes/class.DnsBase.php b/scripts/classes/class.DnsBase.php index 5103ee0d..65753b59 100644 --- a/scripts/classes/class.DnsBase.php +++ b/scripts/classes/class.DnsBase.php @@ -162,6 +162,20 @@ abstract class DnsBase return $domains; } + public function reloadDaemon() + { + // reload DNS daemon + $cmd = Settings::Get('system.bindreload_command'); + $cmdStatus = 1; + safe_exec(escapeshellcmd($cmd), $cmdStatus); + if ($cmdStatus === 0) { + $this->_logger->logAction(CRON_ACTION, LOG_INFO, Settings::Get('system.dns_server') . ' daemon reloaded'); + } else { + $this->_logger->logAction(CRON_ACTION, LOG_ERR, 'Error while running `' . $cmd . + '`: exit code (' . $cmdStatus . ') - please check your system logs'); + } + } + public function writeDKIMconfigs() { if (Settings::Get('dkim.use_dkim') == '1') { diff --git a/scripts/jobs/cron_tasks.inc.dns.10.bind.php b/scripts/jobs/cron_tasks.inc.dns.10.bind.php index 091cc6ce..06fbc9c8 100644 --- a/scripts/jobs/cron_tasks.inc.dns.10.bind.php +++ b/scripts/jobs/cron_tasks.inc.dns.10.bind.php @@ -56,10 +56,7 @@ class bind extends DnsBase fwrite($bindconf_file_handler, $this->_bindconf_file); fclose($bindconf_file_handler); $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'froxlor_bind.conf written'); - safe_exec(escapeshellcmd(Settings::Get('system.bindreload_command'))); - $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Bind9 reloaded'); - $domains_dir = makeCorrectDir(Settings::Get('system.bindconf_directory') . '/domains/'); - + $this->reloadDaemon(); $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Task4 finished'); } diff --git a/scripts/jobs/cron_tasks.inc.dns.20.pdns.php b/scripts/jobs/cron_tasks.inc.dns.20.pdns.php index d0d59ee0..15844c71 100644 --- a/scripts/jobs/cron_tasks.inc.dns.20.pdns.php +++ b/scripts/jobs/cron_tasks.inc.dns.20.pdns.php @@ -47,11 +47,9 @@ class pdns extends DnsBase $this->walkDomainList($domain, $domains); } - $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Database updated'); - - // reload Bind - safe_exec(escapeshellcmd(Settings::Get('system.bindreload_command'))); - $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'pdns reloaded'); + $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'PowerDNS database updated'); + $this->reloadDaemon(); + $this->_logger->logAction(CRON_ACTION, LOG_INFO, 'Task4 finished'); } private function walkDomainList($domain, $domains)