From 1053a95398e9b15c283c9ff6a962ece0be78a720 Mon Sep 17 00:00:00 2001 From: "ClanPartner (Alex)" Date: Wed, 8 Nov 2017 14:39:22 +0000 Subject: [PATCH 1/7] Added DB-Columns for storing DNS-Zonefiles and modified Bind-Plugin to store Zonefiles in DB. No DNSSEC-Support yet (Step 1) --- install/sql/incremental/upd_dev_collection.sql | 2 ++ server/plugins-available/bind_plugin.inc.php | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/install/sql/incremental/upd_dev_collection.sql b/install/sql/incremental/upd_dev_collection.sql index 71f702ebf8..cc1af4b485 100644 --- a/install/sql/incremental/upd_dev_collection.sql +++ b/install/sql/incremental/upd_dev_collection.sql @@ -108,3 +108,5 @@ ALTER TABLE `web_database` CHANGE `database_quota` `database_quota` INT(11) NULL ALTER TABLE `web_domain` ADD `log_retention` INT NOT NULL DEFAULT '30' ; ALTER TABLE spamfilter_policy CHANGE spam_tag_level spam_tag_level DECIMAL(5,2) NULL DEFAULT NULL, CHANGE spam_tag2_level spam_tag2_level DECIMAL(5,2) NULL DEFAULT NULL, CHANGE spam_kill_level spam_kill_level DECIMAL(5,2) NULL DEFAULT NULL, CHANGE spam_dsn_cutoff_level spam_dsn_cutoff_level DECIMAL(5,2) NULL DEFAULT NULL, CHANGE spam_quarantine_cutoff_level spam_quarantine_cutoff_level DECIMAL(5,2) NULL DEFAULT NULL; UPDATE `web_database` as d LEFT JOIN `web_domain` as w ON (w.domain_id = d.parent_domain_id) SET d.parent_domain_id = 0 WHERE w.domain_id IS NULL AND d.parent_domain_id != 0; + +ALTER TABLE `dns_soa` ADD COLUMN `zonefile_unsigned` LONGTEXT NULL AFTER `dnssec_info`, ADD COLUMN `zonefile_signed` LONGTEXT NULL AFTER `zonefile_unsigned`; diff --git a/server/plugins-available/bind_plugin.inc.php b/server/plugins-available/bind_plugin.inc.php index edf7b93d9f..8416e5f686 100644 --- a/server/plugins-available/bind_plugin.inc.php +++ b/server/plugins-available/bind_plugin.inc.php @@ -228,6 +228,10 @@ class bind_plugin { } function soa_update($event_name, $data) { + $this->soa_update_master($event_name, $data); + } + + function soa_update_master($event_name, $data) { global $app, $conf; //* Load libraries @@ -291,6 +295,7 @@ class bind_plugin { $old_zonefile = @file_get_contents($filename); file_put_contents($filename, $tpl->grab()); + $db_zone_unsigned = $tpl->grab(); chown($filename, escapeshellcmd($dns_config['bind_user'])); chgrp($filename, escapeshellcmd($dns_config['bind_group'])); @@ -309,12 +314,17 @@ class bind_plugin { if ($old_zonefile != '') { rename($filename, $filename.'.err'); file_put_contents($filename, $old_zonefile); + $db_zone_unsigned = $old_zonefile; chown($filename, escapeshellcmd($dns_config['bind_user'])); chgrp($filename, escapeshellcmd($dns_config['bind_group'])); } else { rename($filename, $filename.'.err'); } } + + //Update Zonefile in DB for slaves + $app->db->datalogUpdate('dns_soa', array("zonefile_unsigned" => $db_zone_unsigned), 'id', $data['new']['id']); + unset($tpl); unset($records); unset($records_out); @@ -335,7 +345,9 @@ class bind_plugin { else { $filename = $dns_config['bind_zonefiles_dir'].'/pri.'.str_replace("/", "_", substr($data['old']['origin'], 0, -1)); } - if(is_file($filename.'.signed')) unlink($filename.'.signed'); + if(is_file($filename.'.signed')) { + unlink($filename.'.signed'); + } } else if ($data['new']['dnssec_wanted'] == 'Y') $this->soa_dnssec_update($data); // END DNSSEC @@ -367,7 +379,7 @@ class bind_plugin { } } - + function soa_delete($event_name, $data) { global $app, $conf; -- GitLab From 5d3f4d2105a69a61026cd83b569177345274d578 Mon Sep 17 00:00:00 2001 From: "ClanPartner (Alex)" Date: Wed, 8 Nov 2017 15:11:28 +0000 Subject: [PATCH 2/7] Cleanup and slave-zone-generation (still experimental) - Step 2 --- server/plugins-available/bind_plugin.inc.php | 88 ++++++++++++-------- 1 file changed, 55 insertions(+), 33 deletions(-) diff --git a/server/plugins-available/bind_plugin.inc.php b/server/plugins-available/bind_plugin.inc.php index 8416e5f686..930e202904 100644 --- a/server/plugins-available/bind_plugin.inc.php +++ b/server/plugins-available/bind_plugin.inc.php @@ -228,12 +228,8 @@ class bind_plugin { } function soa_update($event_name, $data) { - $this->soa_update_master($event_name, $data); - } - - function soa_update_master($event_name, $data) { global $app, $conf; - + //* Load libraries $app->uses("getconf,tpl"); @@ -250,6 +246,60 @@ class bind_plugin { unset($tmp); } unset($bind); + + if ($conf['mirror_server_id'] > 0) { + //We are a mirroring DNS Server thus will take our zone from DB + $this->soa_update_mirror($event_name, $data, $dns_config); + } else { + //We are the master server and will create (as well as probably sign and store) the zone on our own + $this->soa_update_master($event_name, $data, $dns_config, $bind_caa); + } + + //* rebuild the named.conf file if the origin has changed or when the origin is inserted. + //if($this->action == 'insert' || $data['old']['origin'] != $data['new']['origin']) { + $this->write_named_conf($data, $dns_config); + //} + + //* Delete old domain file, if domain name has been changed + if($data['old']['origin'] != $data['new']['origin']) { + //TODO : change this when distribution information has been integrated into server record + if (file_exists('/etc/gentoo-release')) { + $filename = $dns_config['bind_zonefiles_dir'].'/pri/'.str_replace("/", "_", substr($data['old']['origin'], 0, -1)); + } + else { + $filename = $dns_config['bind_zonefiles_dir'].'/pri.'.str_replace("/", "_", substr($data['old']['origin'], 0, -1)); + } + + if(is_file($filename)) unlink($filename); + if(is_file($filename.'.err')) unlink($filename.'.err'); + if(is_file($filename.'.signed')) unlink($filename.'.signed'); + } + + //* Restart bind nameserver if update_acl is not empty, otherwise reload it + if($data['new']['update_acl'] != '') { + $app->services->restartServiceDelayed('bind', 'restart'); + } else { + $app->services->restartServiceDelayed('bind', 'reload'); + } + } + + function soa_update_mirror($event_name, $data, $dns_config) { + global $app, $conf; + + //* Write the domain files to file system (replicating from master via datalog/DB) + //TODO : change this when distribution information has been integrated into server record + if (file_exists('/etc/gentoo-release')) { + $filename = escapeshellcmd($dns_config['bind_zonefiles_dir'].'/pri/'.str_replace("/", "_", substr($zone['origin'], 0, -1))); + } + else { + $filename = escapeshellcmd($dns_config['bind_zonefiles_dir'].'/pri.'.str_replace("/", "_", substr($zone['origin'], 0, -1))); + } + if ($data['new']['zonefile_unsigned'] != null) file_put_contents($filename, $data['new']['zonefile_unsigned']); + if ($data['new']['zonefile_signed'] != null) file_put_contents($filename.'.signed', $data['new']['zonefile_signed']); + } + + function soa_update_master($event_name, $data, $dns_config, $bind_caa) { + global $app, $conf; //* Write the domain file if(!empty($data['new']['id'])) { @@ -350,34 +400,6 @@ class bind_plugin { } } else if ($data['new']['dnssec_wanted'] == 'Y') $this->soa_dnssec_update($data); // END DNSSEC - - //* rebuild the named.conf file if the origin has changed or when the origin is inserted. - //if($this->action == 'insert' || $data['old']['origin'] != $data['new']['origin']) { - $this->write_named_conf($data, $dns_config); - //} - - //* Delete old domain file, if domain name has been changed - if($data['old']['origin'] != $data['new']['origin']) { - //TODO : change this when distribution information has been integrated into server record - if (file_exists('/etc/gentoo-release')) { - $filename = $dns_config['bind_zonefiles_dir'].'/pri/'.str_replace("/", "_", substr($data['old']['origin'], 0, -1)); - } - else { - $filename = $dns_config['bind_zonefiles_dir'].'/pri.'.str_replace("/", "_", substr($data['old']['origin'], 0, -1)); - } - - if(is_file($filename)) unlink($filename); - if(is_file($filename.'.err')) unlink($filename.'.err'); - if(is_file($filename.'.signed')) unlink($filename.'.signed'); - } - - //* Restart bind nameserver if update_acl is not empty, otherwise reload it - if($data['new']['update_acl'] != '') { - $app->services->restartServiceDelayed('bind', 'restart'); - } else { - $app->services->restartServiceDelayed('bind', 'reload'); - } - } function soa_delete($event_name, $data) { -- GitLab From b65f8558b2de09623e9780883a623bce53f92c2f Mon Sep 17 00:00:00 2001 From: "ClanPartner (Alex)" Date: Wed, 8 Nov 2017 15:22:41 +0000 Subject: [PATCH 3/7] fixed wrong variable for filename generation on mirrors (still step 2) --- server/plugins-available/bind_plugin.inc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/plugins-available/bind_plugin.inc.php b/server/plugins-available/bind_plugin.inc.php index 930e202904..f477bbc87a 100644 --- a/server/plugins-available/bind_plugin.inc.php +++ b/server/plugins-available/bind_plugin.inc.php @@ -289,10 +289,10 @@ class bind_plugin { //* Write the domain files to file system (replicating from master via datalog/DB) //TODO : change this when distribution information has been integrated into server record if (file_exists('/etc/gentoo-release')) { - $filename = escapeshellcmd($dns_config['bind_zonefiles_dir'].'/pri/'.str_replace("/", "_", substr($zone['origin'], 0, -1))); + $filename = escapeshellcmd($dns_config['bind_zonefiles_dir'].'/pri/'.str_replace("/", "_", substr($data['new']['origin'], 0, -1))); } else { - $filename = escapeshellcmd($dns_config['bind_zonefiles_dir'].'/pri.'.str_replace("/", "_", substr($zone['origin'], 0, -1))); + $filename = escapeshellcmd($dns_config['bind_zonefiles_dir'].'/pri.'.str_replace("/", "_", substr($data['new']['origin'], 0, -1))); } if ($data['new']['zonefile_unsigned'] != null) file_put_contents($filename, $data['new']['zonefile_unsigned']); if ($data['new']['zonefile_signed'] != null) file_put_contents($filename.'.signed', $data['new']['zonefile_signed']); -- GitLab From 5f39b9075ec5f23a088a0db472dfe420c411cc12 Mon Sep 17 00:00:00 2001 From: "ClanPartner (Alex)" Date: Wed, 8 Nov 2017 15:32:07 +0000 Subject: [PATCH 4/7] Added DNSSEC-Zone to DB replication (Step 3) --- server/plugins-available/bind_plugin.inc.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/plugins-available/bind_plugin.inc.php b/server/plugins-available/bind_plugin.inc.php index f477bbc87a..8cc270f994 100644 --- a/server/plugins-available/bind_plugin.inc.php +++ b/server/plugins-available/bind_plugin.inc.php @@ -158,6 +158,9 @@ class bind_plugin { $dnssecdata .= file_get_contents($keyfile)."\n\n"; } + //Update signed Zonefile in DB for mirrors (it is intended to write unsigend data twice as signing might fail and then at least the unsigned data is in DB from soa_update) + $app->db->datalogUpdate('dns_soa', array("zonefile_signed" => file_get_contents($dns_config['bind_zonefiles_dir'].'/'.$filespre.$domain.'.signed'), "zonefile_unsigned" => $zonefile), 'id', $data['new']['id']); + if ($app->dbmaster !== $app->db) $app->dbmaster->query('UPDATE dns_soa SET dnssec_info=?, dnssec_initialized=\'Y\', dnssec_last_signed=? WHERE id=?', $dnssecdata, intval(time()), intval($data['new']['id'])); $app->db->query('UPDATE dns_soa SET dnssec_info=?, dnssec_initialized=\'Y\', dnssec_last_signed=? WHERE id=?', $dnssecdata, intval(time()), intval($data['new']['id'])); } @@ -372,7 +375,7 @@ class bind_plugin { } } - //Update Zonefile in DB for slaves + //Update Zonefile in DB for mirrors $app->db->datalogUpdate('dns_soa', array("zonefile_unsigned" => $db_zone_unsigned), 'id', $data['new']['id']); unset($tpl); -- GitLab From ee4243b618045d2e3398b156f7f36d1a852a1a27 Mon Sep 17 00:00:00 2001 From: "ClanPartner (Alex)" Date: Wed, 8 Nov 2017 16:03:27 +0000 Subject: [PATCH 5/7] working zone replication via DB instead of duplicate creation - including DNSSEC --- server/plugins-available/bind_plugin.inc.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/server/plugins-available/bind_plugin.inc.php b/server/plugins-available/bind_plugin.inc.php index 8cc270f994..8782cba2b5 100644 --- a/server/plugins-available/bind_plugin.inc.php +++ b/server/plugins-available/bind_plugin.inc.php @@ -159,7 +159,7 @@ class bind_plugin { } //Update signed Zonefile in DB for mirrors (it is intended to write unsigend data twice as signing might fail and then at least the unsigned data is in DB from soa_update) - $app->db->datalogUpdate('dns_soa', array("zonefile_signed" => file_get_contents($dns_config['bind_zonefiles_dir'].'/'.$filespre.$domain.'.signed'), "zonefile_unsigned" => $zonefile), 'id', $data['new']['id']); + $app->db->datalogUpdate('dns_soa', array("zonefile_signed" => file_get_contents($dns_config['bind_zonefiles_dir'].'/'.$filespre.$domain.'.signed'), "zonefile_unsigned" => $zonefile, "datalog_only_replication" => 1), 'id', $data['new']['id']); if ($app->dbmaster !== $app->db) $app->dbmaster->query('UPDATE dns_soa SET dnssec_info=?, dnssec_initialized=\'Y\', dnssec_last_signed=? WHERE id=?', $dnssecdata, intval(time()), intval($data['new']['id'])); $app->db->query('UPDATE dns_soa SET dnssec_info=?, dnssec_initialized=\'Y\', dnssec_last_signed=? WHERE id=?', $dnssecdata, intval(time()), intval($data['new']['id'])); @@ -253,11 +253,15 @@ class bind_plugin { if ($conf['mirror_server_id'] > 0) { //We are a mirroring DNS Server thus will take our zone from DB $this->soa_update_mirror($event_name, $data, $dns_config); - } else { + } else if ($data['new']['datalog_only_replication'] != 1) { //We are the master server and will create (as well as probably sign and store) the zone on our own $this->soa_update_master($event_name, $data, $dns_config, $bind_caa); } + //This shall ALWAYS BE 0 after these actions. This flag is made to stop datalog-recursion when replicating to mirrors. + $data['new']['datalog_only_replication'] = 0; + $app->db->query('UPDATE dns_soa SET datalog_only_replication=0 WHERE id=?', intval($data['new']['id'])); //Do not put this to datalog. + //* rebuild the named.conf file if the origin has changed or when the origin is inserted. //if($this->action == 'insert' || $data['old']['origin'] != $data['new']['origin']) { $this->write_named_conf($data, $dns_config); @@ -376,7 +380,7 @@ class bind_plugin { } //Update Zonefile in DB for mirrors - $app->db->datalogUpdate('dns_soa', array("zonefile_unsigned" => $db_zone_unsigned), 'id', $data['new']['id']); + $app->db->datalogUpdate('dns_soa', array("zonefile_unsigned" => $db_zone_unsigned, "datalog_only_replication" => 1), 'id', $data['new']['id']); unset($tpl); unset($records); -- GitLab From 87f6076ba60da7127c0cf1174e0f50e6105fae96 Mon Sep 17 00:00:00 2001 From: "ClanPartner (Alex)" Date: Wed, 8 Nov 2017 16:11:46 +0000 Subject: [PATCH 6/7] added last DB field --- install/sql/incremental/upd_dev_collection.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/sql/incremental/upd_dev_collection.sql b/install/sql/incremental/upd_dev_collection.sql index cc1af4b485..f0254216d5 100644 --- a/install/sql/incremental/upd_dev_collection.sql +++ b/install/sql/incremental/upd_dev_collection.sql @@ -109,4 +109,4 @@ ALTER TABLE `web_domain` ADD `log_retention` INT NOT NULL DEFAULT '30' ; ALTER TABLE spamfilter_policy CHANGE spam_tag_level spam_tag_level DECIMAL(5,2) NULL DEFAULT NULL, CHANGE spam_tag2_level spam_tag2_level DECIMAL(5,2) NULL DEFAULT NULL, CHANGE spam_kill_level spam_kill_level DECIMAL(5,2) NULL DEFAULT NULL, CHANGE spam_dsn_cutoff_level spam_dsn_cutoff_level DECIMAL(5,2) NULL DEFAULT NULL, CHANGE spam_quarantine_cutoff_level spam_quarantine_cutoff_level DECIMAL(5,2) NULL DEFAULT NULL; UPDATE `web_database` as d LEFT JOIN `web_domain` as w ON (w.domain_id = d.parent_domain_id) SET d.parent_domain_id = 0 WHERE w.domain_id IS NULL AND d.parent_domain_id != 0; -ALTER TABLE `dns_soa` ADD COLUMN `zonefile_unsigned` LONGTEXT NULL AFTER `dnssec_info`, ADD COLUMN `zonefile_signed` LONGTEXT NULL AFTER `zonefile_unsigned`; +ALTER TABLE `dns_soa` ADD COLUMN `zonefile_unsigned` LONGTEXT NULL AFTER `dnssec_info`, ADD COLUMN `zonefile_signed` LONGTEXT NULL AFTER `zonefile_unsigned`, ADD COLUMN `datalog_only_replication` TINYINT(1) NOT NULL DEFAULT '0' AFTER `zonefile_signed`; -- GitLab From 542ef5a1ae4b6197a98b2b7b6a9a62a8945dea2c Mon Sep 17 00:00:00 2001 From: "ClanPartner (Alex)" Date: Thu, 14 Dec 2017 13:02:23 +0000 Subject: [PATCH 7/7] replication via datalog and cronjob --- .../cron.d/400-bind_replication.inc.php | 85 +++++++++++++++++++ server/plugins-available/bind_plugin.inc.php | 4 +- 2 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 server/lib/classes/cron.d/400-bind_replication.inc.php diff --git a/server/lib/classes/cron.d/400-bind_replication.inc.php b/server/lib/classes/cron.d/400-bind_replication.inc.php new file mode 100644 index 0000000000..1014fab2cb --- /dev/null +++ b/server/lib/classes/cron.d/400-bind_replication.inc.php @@ -0,0 +1,85 @@ +db->dbHost != $app->dbmaster->dbHost) return; + + //* Load libraries + $app->uses("getconf,tpl"); + + $soas = $app->db->queryAllRecords("SELECT id,zonefile_signed,zonefile_unsigned FROM dns_soa WHERE active= 'Y' AND datalog_only_replication=0"); + + foreach ($soas as $data) { + $app->log('DNS-Replication: Adding DataLog-Entry for SOA ID '.$data['id'], LOGLEVEL_DEBUG); + $app->db->datalogUpdate('dns_soa', array("zonefile_signed" => $data['zonefile_signed'], "zonefile_unsigned" => $data['zonefile_unsigned'], "datalog_only_replication" => 1), 'id', $data['id']); + } + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/plugins-available/bind_plugin.inc.php b/server/plugins-available/bind_plugin.inc.php index 8782cba2b5..3e47e0f0f8 100644 --- a/server/plugins-available/bind_plugin.inc.php +++ b/server/plugins-available/bind_plugin.inc.php @@ -159,7 +159,7 @@ class bind_plugin { } //Update signed Zonefile in DB for mirrors (it is intended to write unsigend data twice as signing might fail and then at least the unsigned data is in DB from soa_update) - $app->db->datalogUpdate('dns_soa', array("zonefile_signed" => file_get_contents($dns_config['bind_zonefiles_dir'].'/'.$filespre.$domain.'.signed'), "zonefile_unsigned" => $zonefile, "datalog_only_replication" => 1), 'id', $data['new']['id']); + $app->dbmaster->query('UPDATE dns_soa SET zonefile_unsigned=?, zonefile_signed=?, datalog_only_replication=1 WHERE id=?', $zonefile_unsigned, file_get_contents($dns_config['bind_zonefiles_dir'].'/'.$filespre.$domain.'.signed'), $data['new']['id']); if ($app->dbmaster !== $app->db) $app->dbmaster->query('UPDATE dns_soa SET dnssec_info=?, dnssec_initialized=\'Y\', dnssec_last_signed=? WHERE id=?', $dnssecdata, intval(time()), intval($data['new']['id'])); $app->db->query('UPDATE dns_soa SET dnssec_info=?, dnssec_initialized=\'Y\', dnssec_last_signed=? WHERE id=?', $dnssecdata, intval(time()), intval($data['new']['id'])); @@ -380,7 +380,7 @@ class bind_plugin { } //Update Zonefile in DB for mirrors - $app->db->datalogUpdate('dns_soa', array("zonefile_unsigned" => $db_zone_unsigned, "datalog_only_replication" => 1), 'id', $data['new']['id']); + $app->dbmaster->query('UPDATE dns_soa SET zonefile_unsigned=?, datalog_only_replication=0 WHERE id=?', $zonefile_unsigned, $data['new']['id']); unset($tpl); unset($records); -- GitLab