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; }