bind_plugin.inc.php 23.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
<?php

/*
Copyright (c) 2009, Till Brehm, projektfarm Gmbh
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.

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
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

class bind_plugin {
32

33 34 35
	var $plugin_name = 'bind_plugin';
	var $class_name  = 'bind_plugin';
	var $action = 'update';
36

37 38 39 40
	//* This function is called during ispconfig installation to determine
	//  if a symlink shall be created for this plugin.
	function onInstall() {
		global $conf;
41

42
		if(isset($conf['bind']['installed']) && $conf['bind']['installed'] == true && @is_link('/usr/local/ispconfig/server/mods-enabled/dns_module.inc.php')) {
43 44 45 46
			return true;
		} else {
			return false;
		}
47

48
	}
49 50


51 52 53
	/*
	 	This function is called when the plugin is loaded
	*/
54

55 56
	function onLoad() {
		global $app;
57

58 59 60
		/*
		Register for the events
		*/
61

62
		//* SOA
63 64 65 66 67 68 69 70 71
		$app->plugins->registerEvent('dns_soa_insert', $this->plugin_name, 'soa_insert');
		$app->plugins->registerEvent('dns_soa_update', $this->plugin_name, 'soa_update');
		$app->plugins->registerEvent('dns_soa_delete', $this->plugin_name, 'soa_delete');

		//* SLAVE
		$app->plugins->registerEvent('dns_slave_insert', $this->plugin_name, 'slave_insert');
		$app->plugins->registerEvent('dns_slave_update', $this->plugin_name, 'slave_update');
		$app->plugins->registerEvent('dns_slave_delete', $this->plugin_name, 'slave_delete');

72
		//* RR
73 74 75 76
		$app->plugins->registerEvent('dns_rr_insert', $this->plugin_name, 'rr_insert');
		$app->plugins->registerEvent('dns_rr_update', $this->plugin_name, 'rr_update');
		$app->plugins->registerEvent('dns_rr_delete', $this->plugin_name, 'rr_delete');

77
	}
78

79
	//* This creates DNSSEC-Keys and calls soa_dnssec_update.
80
	function soa_dnssec_create(&$data) {
81 82 83 84 85 86 87 88
		global $app, $conf;

		//* Load libraries
		$app->uses("getconf,tpl");

		//* load the server configuration options
		$dns_config = $app->getconf->get_server_config($conf["server_id"], 'dns');
		
89 90 91
		//TODO : change this when distribution information has been integrated into server record
		$filespre = (file_exists('/etc/gentoo-release')) ? 'pri/' : 'pri.';
		
92
		$domain = substr($data['new']['origin'], 0, strlen($data['new']['origin'])-1);
93
		if (!file_exists($dns_config['bind_zonefiles_dir'].'/'.$filespre.$domain)) return false;
94
		
95 96
		//* Check Entropy
		if (file_get_contents('/proc/sys/kernel/random/entropy_avail') < 400) {
A. Täffner's avatar
A. Täffner committed
97 98
			$app->log('DNSSEC ERROR: We are low on entropy. Not generating new Keys for '.$domain.'. Please consider installing package haveged.', LOGLEVEL_WARN);
			echo "DNSSEC ERROR: We are low on entropy. Not generating new Keys for $domain. Please consider installing package haveged.\n";
99 100 101 102
			return false;
		}
		
		//* Verify that we do not already have keys (overwriting-protection)
103
		if (file_exists($dns_config['bind_zonefiles_dir'].'/dsset-'.$domain.'.')) {
A. Täffner's avatar
A. Täffner committed
104
			return $this->soa_dnssec_update($data);
105 106 107 108 109 110 111 112 113
		} else if ($data['new']['dnssec_initialized'] == 'Y') { //In case that we generated keys but the dsset-file was not generated
			$keycount=0;
			foreach (glob($dns_config['bind_zonefiles_dir'].'/K'.$domain.'*.key') as $keyfile) {
				$keycount++;
			}
			if ($keycount > 0) {
				$this->soa_dnssec_sign($data);
				return true;
			}
114 115 116
		}
		
		//Do some magic...
117
		exec('cd '.escapeshellcmd($dns_config['bind_zonefiles_dir']).';'.
A. Täffner's avatar
A. Täffner committed
118 119
		'dnssec-keygen -a NSEC3RSASHA1 -b 2048 -n ZONE '.escapeshellcmd($domain).';'.
		'dnssec-keygen -f KSK -a NSEC3RSASHA1 -b 4096 -n ZONE '.escapeshellcmd($domain));
120

121 122 123 124 125 126 127 128 129 130 131 132
		$this->soa_dnssec_sign($data); //Now sign the zone for the first time
		$data['new']['dnssec_initialized']='Y';
	}
	
	function soa_dnssec_sign(&$data) {
		global $app, $conf;
		
		//* Load libraries
		$app->uses("getconf,tpl");

		//* load the server configuration options
		$dns_config = $app->getconf->get_server_config($conf["server_id"], 'dns');
133
		
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
		//TODO : change this when distribution information has been integrated into server record
		$filespre = (file_exists('/etc/gentoo-release')) ? 'pri/' : 'pri.';
		
		$domain = substr($data['new']['origin'], 0, strlen($data['new']['origin'])-1);
		if (!file_exists($dns_config['bind_zonefiles_dir'].'/'.$filespre.$domain)) return false;
		
		$zonefile = file_get_contents($dns_config['bind_zonefiles_dir'].'/'.$filespre.$domain);
		$keycount=0;
		foreach (glob($dns_config['bind_zonefiles_dir'].'/K'.$domain.'*.key') as $keyfile) {
			$includeline = '$INCLUDE '.basename($keyfile);
			if (!preg_match('@'.preg_quote($includeline).'@', $zonefile)) $zonefile .= "\n".$includeline."\n";
			$keycount++;
		}
		if ($keycount != 2) $app->log('DNSSEC Warning: There are more or less than 2 keyfiles for zone '.$domain, LOGLEVEL_WARN);
		file_put_contents($dns_config['bind_zonefiles_dir'].'/'.$filespre.$domain, $zonefile);
		
		//Sign the zone and set it valid for max. 16 days
		exec('cd '.escapeshellcmd($dns_config['bind_zonefiles_dir']).';'.
A. Täffner's avatar
A. Täffner committed
152
			 'dnssec-signzone -A -e +1382400 -3 $(head -c 1000 /dev/random | sha1sum | cut -b 1-16) -N increment -o '.escapeshellcmd($domain).' -t '.$filespre.escapeshellcmd($domain));
153 154
			 
		//Write Data back ino DB
155 156
		$dnssecdata = "DS-Records:\n".file_get_contents($dns_config['bind_zonefiles_dir'].'/dsset-'.$domain.'.');
		$dnssecdata .= "\n------------------------------------\n\nDNSKEY-Records:\n";
157
		foreach (glob($dns_config['bind_zonefiles_dir'].'/K'.$domain.'*.key') as $keyfile) {
158 159 160
			$dnssecdata .= file_get_contents($keyfile)."\n\n";
		}
		
A. Täffner's avatar
A. Täffner committed
161 162
		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']));
163 164
	}
	
165
	function soa_dnssec_update(&$data, $new=false) {
166 167 168 169 170 171 172 173
		global $app, $conf;

		//* Load libraries
		$app->uses("getconf,tpl");

		//* load the server configuration options
		$dns_config = $app->getconf->get_server_config($conf["server_id"], 'dns');
		
174 175 176 177 178 179 180
		//TODO : change this when distribution information has been integrated into server record
		$filespre = (file_exists('/etc/gentoo-release')) ? 'pri/' : 'pri.';
		
		$domain = substr($data['new']['origin'], 0, strlen($data['new']['origin'])-1);
		if (!file_exists($dns_config['bind_zonefiles_dir'].'/'.$filespre.$domain)) return false;
		
		//* Check for available entropy
181 182
		if (file_get_contents('/proc/sys/kernel/random/entropy_avail') < 200) {
			$app->log('DNSSEC ERROR: We are low on entropy. This could cause server script to fail. Please consider installing package haveged.', LOGLEVEL_ERR);
183
			echo "DNSSEC ERROR: We are low on entropy. This could cause server script to fail. Please consider installing package haveged.\n";
184 185 186
			return false;
		}
		
187
		if (!$new && !file_exists($dns_config['bind_zonefiles_dir'].'/dsset-'.$domain.'.')) $this->soa_dnssec_create($data);
188
		
A. Täffner's avatar
A. Täffner committed
189
		$dbdata = $app->db->queryOneRecord('SELECT id,serial FROM dns_soa WHERE id=?', intval($data['new']['id']));
190
		exec('cd '.escapeshellcmd($dns_config['bind_zonefiles_dir']).';'.
A. Täffner's avatar
A. Täffner committed
191
			 'named-checkzone '.escapeshellcmd($domain).' '.escapeshellcmd($dns_config['bind_zonefiles_dir']).'/'.$filespre.escapeshellcmd($domain).' | egrep -ho \'[0-9]{10}\'', $serial, $retState);
192 193 194 195
		if ($retState != 0) {
			$app->log('DNSSEC Error: Error in Zonefile for '.$domain, LOGLEVEL_ERR);
			return false;
		}
196
		
197 198 199 200 201 202 203 204 205 206 207
		$this->soa_dnssec_sign($data);
	}
	
	function soa_dnssec_delete(&$data) {
		global $app, $conf;

		//* Load libraries
		$app->uses("getconf,tpl");

		//* load the server configuration options
		$dns_config = $app->getconf->get_server_config($conf["server_id"], 'dns');
208
		
209 210 211 212 213 214 215 216 217
		//TODO : change this when distribution information has been integrated into server record
		$filespre = (file_exists('/etc/gentoo-release')) ? 'pri/' : 'pri.';
		
		$domain = substr($data['new']['origin'], 0, strlen($data['new']['origin'])-1);
		
		unlink($dns_config['bind_zonefiles_dir'].'/K'.$domain.'.+*');
		unlink($dns_config['bind_zonefiles_dir'].'/'.$filespre.$domain.'.signed');
		unlink($dns_config['bind_zonefiles_dir'].'/dsset-'.$domain.'.');
		
A. Täffner's avatar
A. Täffner committed
218 219
		if ($app->dbmaster !== $app->db) $app->dbmaster->query('UPDATE dns_soa SET dnssec_info=\'\', dnssec_initialized=\'N\' WHERE id=?', intval($data['new']['id']));
		$app->db->query('UPDATE dns_soa SET dnssec_info=\'\', dnssec_initialized=\'N\' WHERE id=?', intval($data['new']['id']));
220
	}
221 222

	function soa_insert($event_name, $data) {
223
		global $app, $conf;
224

225
		$this->action = 'insert';
226 227
		$this->soa_update($event_name, $data);

228
	}
229 230

	function soa_update($event_name, $data) {
231
		global $app, $conf;
232

233 234
		//* Load libraries
		$app->uses("getconf,tpl");
235

236 237
		//* load the server configuration options
		$dns_config = $app->getconf->get_server_config($conf["server_id"], 'dns');
238

239
		//* Write the domain file
240
		if(!empty($data['new']['id'])) {
tbrehm's avatar
tbrehm committed
241 242
			$tpl = new tpl();
			$tpl->newTemplate("bind_pri.domain.master");
243

tbrehm's avatar
tbrehm committed
244 245
			$zone = $data['new'];
			$tpl->setVar($zone);
246

A. Täffner's avatar
A. Täffner committed
247
			$records = $app->db->queryAllRecords("SELECT * FROM dns_rr WHERE zone = ? AND active = 'Y'", $zone['id']);
248 249 250
			if(is_array($records) && !empty($records)){
				for($i=0;$i<sizeof($records);$i++){
					if($records[$i]['ttl'] == 0) $records[$i]['ttl'] = '';
251
					if($records[$i]['name'] == '') $records[$i]['name'] = '@';
252 253 254 255
					//* Split TXT records, if nescessary
					if($records[$i]['type'] == 'TXT' && strlen($records[$i]['data']) > 255) {
						$records[$i]['data'] = implode('" "',str_split( $records[$i]['data'], 255));
					}
256 257
				}
			}
258 259
			$tpl->setLoop('zones', $records);

wyrie's avatar
wyrie committed
260
			//TODO : change this when distribution information has been integrated into server record
261
			if (file_exists('/etc/gentoo-release')) {
262
				$filename = escapeshellcmd($dns_config['bind_zonefiles_dir'].'/pri/'.str_replace("/", "_", substr($zone['origin'], 0, -1)));
263 264 265 266 267
			}
			else {
				$filename = escapeshellcmd($dns_config['bind_zonefiles_dir'].'/pri.'.str_replace("/", "_", substr($zone['origin'], 0, -1)));
			}

268
			$old_zonefile = @file_get_contents($filename);
269
			file_put_contents($filename, $tpl->grab());
270 271
			chown($filename, escapeshellcmd($dns_config['bind_user']));
			chgrp($filename, escapeshellcmd($dns_config['bind_group']));
272

273 274
			//* Check the zonefile
			if(is_file($filename.'.err')) unlink($filename.'.err');
A. Täffner's avatar
A. Täffner committed
275
			$out=array();
A. Täffner's avatar
A. Täffner committed
276
			exec('named-checkzone '.escapeshellarg($zone['origin']).' '.escapeshellarg($filename).' 2>&1', $out, $return_status);
A. Täffner's avatar
A. Täffner committed
277 278
			$statustext='';
			foreach ($out as $line) $statustext .= $line."\n";
279
			if($return_status === 0) {
280
				$app->log("Writing BIND domain file: ".$filename, LOGLEVEL_DEBUG);
A. Täffner's avatar
A. Täffner committed
281
				$app->db->query('UPDATE dns_soa SET status=\'OK\', status_txt=\'\' WHERE id='.$data['new']['id']);
282
				$app->dbmaster->query('UPDATE dns_soa SET status=\'OK\', status_txt=\'\' WHERE id='.$data['new']['id']);
283
			} else {
284
				$loglevel = @($dns_config['disable_bind_log'] === 'y')?'LOGLEVEL_DEBUG':'LOGLEVEL_WARN';
285 286 287 288 289 290 291 292 293 294
				$app->log("Writing BIND domain file failed: ".$filename." ".implode(' ', $out), $loglevel);
				if(is_array($out) && !empty($out)){
					$app->log('Reason for Bind restart failure: '.implode("\n", $out), $loglevel);
					$app->dbmaster->datalogError(implode("\n", $out));
				}
				if ($old_zonefile != '') {
					rename($filename, $filename.'.err');
					file_put_contents($filename, $old_zonefile);
					chown($filename, escapeshellcmd($dns_config['bind_user']));
					chgrp($filename, escapeshellcmd($dns_config['bind_group']));
295
				} else {
296
					rename($filename, $filename.'.err');
297
				}
A. Täffner's avatar
A. Täffner committed
298
				$app->db->query('UPDATE dns_soa SET status=\'ERROR\', status_txt=\''.str_replace(array('"', '\''), '', $statustext).'\' WHERE id='.$data['new']['id']);
299
				$app->dbmaster->query('UPDATE dns_soa SET status=\'ERROR\', status_txt=\''.str_replace(array('"', '\''), '', $statustext).'\' WHERE id='.$data['new']['id']);
300
			}
tbrehm's avatar
tbrehm committed
301 302
			unset($tpl);
			unset($records);
303
			unset($records_out);
tbrehm's avatar
tbrehm committed
304 305
			unset($zone);
		}
306 307 308
		
		//* DNSSEC-Implementation
		if($data['old']['origin'] != $data['new']['origin']) {			
309
			if (@$data['old']['dnssec_initialized'] == 'Y' && strlen(@$data['old']['origin']) > 3) $this->soa_dnssec_delete($data); //delete old keys
310
			if ($data['new']['dnssec_wanted'] == 'Y') $this->soa_dnssec_create($data);
311
		}
312
		else if ($data['new']['dnssec_wanted'] == 'Y' && $data['old']['dnssec_initialized'] == 'N') $this->soa_dnssec_create($data);
313
		else if ($data['new']['dnssec_wanted'] == 'N' && $data['old']['dnssec_initialized'] == 'Y') {	//delete old signed file if dnssec is no longer wanted
314 315 316 317 318 319 320 321
			//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.'.signed')) unlink($filename.'.signed');
322
 		} else if ($data['new']['dnssec_wanted'] == 'Y') $this->soa_dnssec_update($data);
323
		// END DNSSEC
324
		
325
		//* rebuild the named.conf file if the origin has changed or when the origin is inserted.
326
		//if($this->action == 'insert' || $data['old']['origin'] != $data['new']['origin']) {
327
		$this->write_named_conf($data, $dns_config);
328
		//}
329

330 331
		//* Delete old domain file, if domain name has been changed
		if($data['old']['origin'] != $data['new']['origin']) {
wyrie's avatar
wyrie committed
332
			//TODO : change this when distribution information has been integrated into server record
333
			if (file_exists('/etc/gentoo-release')) {
334
				$filename = $dns_config['bind_zonefiles_dir'].'/pri/'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
335 336 337 338 339
			}
			else {
				$filename = $dns_config['bind_zonefiles_dir'].'/pri.'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
			}

340 341
			if(is_file($filename)) unlink($filename);
			if(is_file($filename.'.err')) unlink($filename.'.err');
A. Täffner's avatar
A. Täffner committed
342
			if(is_file($filename.'.signed')) unlink($filename.'.signed');
A. Täffner's avatar
A. Täffner committed
343 344
		}

345 346 347 348 349 350
		//* 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');
		}
351

352
	}
353 354

	function soa_delete($event_name, $data) {
355
		global $app, $conf;
356

357
		//* load the server configuration options
358
		$app->uses("getconf,tpl");
359
		$dns_config = $app->getconf->get_server_config($conf["server_id"], 'dns');
360

361
		//* rebuild the named.conf file
362 363
		$this->write_named_conf($data, $dns_config);

364
		//* Delete the domain file
wyrie's avatar
wyrie committed
365
		//TODO : change this when distribution information has been integrated into server record
366 367 368 369 370 371 372
		if (file_exists('/etc/gentoo-release')) {
			$zone_file_name = $dns_config['bind_zonefiles_dir'].'/pri/'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
		}
		else {
			$zone_file_name = $dns_config['bind_zonefiles_dir'].'/pri.'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
		}

373
		if(is_file($zone_file_name)) unlink($zone_file_name);
374
		if(is_file($zone_file_name.'.err')) unlink($zone_file_name.'.err');
375 376
		$app->log("Deleting BIND domain file: ".$zone_file_name, LOGLEVEL_DEBUG);

377
 		//* DNSSEC-Implementation
378
 		if ($data['old']['dnssec_initialized'] == 'Y') exec('/usr/local/ispconfig/server/scripts/dnssec-delete.sh '.$data['old']['origin']); //delete keys
379
 		
380
		//* Reload bind nameserver
381 382
		$app->services->restartServiceDelayed('bind', 'reload');

383 384
	}

385
	function slave_insert($event_name, $data) {
386
		global $app, $conf;
387

388
		$this->action = 'insert';
389 390
		$this->slave_update($event_name, $data);

391
	}
392 393

	function slave_update($event_name, $data) {
394
		global $app, $conf;
395

396 397
		//* Load libraries
		$app->uses("getconf,tpl");
398

399 400
		//* load the server configuration options
		$dns_config = $app->getconf->get_server_config($conf["server_id"], 'dns');
401

402 403
		//* 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']) {
404
		$this->write_named_conf($data, $dns_config);
405
		//}
406

407 408
		//* Delete old domain file, if domain name has been changed
		if($data['old']['origin'] != $data['new']['origin']) {
wyrie's avatar
wyrie committed
409
			//TODO : change this when distribution information has been integrated into server record
410 411 412 413 414 415 416
			if (file_exists('/etc/gentoo-release')) {
				$filename = $dns_config['bind_zonefiles_dir'].'/sec/'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
			}
			else {
				$filename = $dns_config['bind_zonefiles_dir'].'/slave/sec.'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
			}

417 418
			if(is_file($filename)) unset($filename);
		}
419

420 421 422 423 424 425
		//* Ensure that the named slave directory is writable by the named user
		if (file_exists('/etc/gentoo-release')) {
			$slave_record_dir = $dns_config['bind_zonefiles_dir'].'/sec';
		} else {
			$slave_record_dir = $dns_config['bind_zonefiles_dir'].'/slave';
		}
426 427 428 429
		if(!@is_dir($slave_record_dir)) mkdir($slave_record_dir, 0770);
		chown($slave_record_dir, $dns_config['bind_user']);
		chgrp($slave_record_dir, $dns_config['bind_group']);

430
		//* Reload bind nameserver
431 432
		$app->services->restartServiceDelayed('bind', 'reload');

433
	}
434 435

	function slave_delete($event_name, $data) {
436
		global $app, $conf;
437 438


439 440 441
		//* load the server configuration options
		$app->uses("getconf,tpl");
		$dns_config = $app->getconf->get_server_config($conf["server_id"], 'dns');
442

443
		//* rebuild the named.conf file
444 445
		$this->write_named_conf($data, $dns_config);

446
		//* Delete the domain file
wyrie's avatar
wyrie committed
447
		//TODO : change this when distribution information has been integrated into server record
448 449 450 451 452 453 454
		if (file_exists('/etc/gentoo-release')) {
			$zone_file_name = $dns_config['bind_zonefiles_dir'].'/sec/'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
		}
		else {
			$zone_file_name = $dns_config['bind_zonefiles_dir'].'/slave/sec.'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
		}

455
		if(is_file($zone_file_name)) unlink($zone_file_name);
456 457
		$app->log("Deleting BIND domain file for secondary zone: ".$zone_file_name, LOGLEVEL_DEBUG);

458
		//* Reload bind nameserver
459 460 461
		$app->services->restartServiceDelayed('bind', 'reload');


462
	}
463 464

	function rr_insert($event_name, $data) {
465
		global $app, $conf;
466

467
		//* Get the data of the soa and call soa_update
468
		$tmp = $app->db->queryOneRecord("SELECT * FROM dns_soa WHERE id = ?", $data['new']['zone']);
469 470 471
		$data["new"] = $tmp;
		$data["old"] = $tmp;
		$this->action = 'update';
472
		$this->soa_update($event_name, $data);
473 474

	}
475 476

	function rr_update($event_name, $data) {
477
		global $app, $conf;
478

479
		//* Get the data of the soa and call soa_update
480
		$tmp = $app->db->queryOneRecord("SELECT * FROM dns_soa WHERE id = ?", $data['new']['zone']);
481 482 483
		$data["new"] = $tmp;
		$data["old"] = $tmp;
		$this->action = 'update';
484 485
		$this->soa_update($event_name, $data);

486
	}
487 488

	function rr_delete($event_name, $data) {
489
		global $app, $conf;
490

491
		//* Get the data of the soa and call soa_update
492
		$tmp = $app->db->queryOneRecord("SELECT * FROM dns_soa WHERE id = ?", $data['old']['zone']);
493 494 495
		$data["new"] = $tmp;
		$data["old"] = $tmp;
		$this->action = 'update';
496 497
		$this->soa_update($event_name, $data);

498
	}
499 500 501

	//##################################################################

502 503
	function write_named_conf($data, $dns_config) {
		global $app, $conf;
504 505

		//* Only write the master file for the current server
506
		$tmps = $app->db->queryAllRecords("SELECT origin, xfer, also_notify, update_acl, dnssec_wanted FROM dns_soa WHERE active = 'Y' AND server_id=?", $conf["server_id"]);
507
		$zones = array();
508

509
		//* Check if the current zone that triggered this function has at least one NS record
510

wyrie's avatar
wyrie committed
511
		//TODO : change this when distribution information has been integrated into server record
512 513 514 515 516 517 518 519 520
		if (file_exists('/etc/gentoo-release')) {
			$pri_zonefiles_path = $dns_config['bind_zonefiles_dir'].'/pri/';
			$sec_zonefiles_path = $dns_config['bind_zonefiles_dir'].'/sec/';

		}
		else {
			$pri_zonefiles_path = $dns_config['bind_zonefiles_dir'].'/pri.';
			$sec_zonefiles_path = $dns_config['bind_zonefiles_dir'].'/slave/sec.';
		}
521

522
		//* Loop trough zones
523
		foreach($tmps as $tmp) {
524
			$zone_file = $pri_zonefiles_path.str_replace("/", "_", substr($tmp['origin'], 0, -1));
525
			if ($tmp['dnssec_wanted'] == 'Y') $zone_file .= '.signed'; //.signed is for DNSSEC-Implementation
526

527
			$options = '';
528
			if(trim($tmp['xfer']) != '') {
529
				$options .= "        allow-transfer {".str_replace(',', ';', $tmp['xfer']).";};\n";
530 531 532
			} else {
				$options .= "        allow-transfer {none;};\n";
			}
533 534 535
			if(trim($tmp['also_notify']) != '') $options .= '        also-notify {'.str_replace(',', ';', $tmp['also_notify']).";};\n";
			if(trim($tmp['update_acl']) != '') $options .= "        allow-update {".str_replace(',', ';', $tmp['update_acl']).";};\n";

536
			if(file_exists($zone_file)) {
537 538 539 540
				$zones[] = array( 'zone' => substr($tmp['origin'], 0, -1),
					'zonefile_path' => $zone_file,
					'options' => $options
				);
541
			}
542
		}
543

544 545
		$tpl = new tpl();
		$tpl->newTemplate("bind_named.conf.local.master");
546 547
		$tpl->setLoop('zones', $zones);

548
		//* And loop through the secondary zones, but only for the current server
549
		$tmps_sec = $app->db->queryAllRecords("SELECT origin, xfer, ns FROM dns_slave WHERE active = 'Y' AND server_id=?", $conf["server_id"]);
550 551 552
		$zones_sec = array();

		foreach($tmps_sec as $tmp) {
553

554
			$options = "        masters {".$tmp['ns'].";};\n";
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
			if(trim($tmp['xfer']) != '') {
				$options .= "        allow-transfer {".str_replace(',', ';', $tmp['xfer']).";};\n";
			} else {
				$options .= "        allow-transfer {none;};\n";
			}


			$zones_sec[] = array( 'zone' => substr($tmp['origin'], 0, -1),
				'zonefile_path' => $sec_zonefiles_path.str_replace("/", "_", substr($tmp['origin'], 0, -1)),
				'options' => $options
			);

			//   $filename = escapeshellcmd($dns_config['bind_zonefiles_dir'].'/slave/sec.'.substr($tmp['origin'],0,-1));
			//   $app->log("Writing BIND domain file: ".$filename,LOGLEVEL_DEBUG);


571
		}
572

573 574
		$tpl_sec = new tpl();
		$tpl_sec->newTemplate("bind_named.conf.local.slave");
575 576 577 578 579 580 581 582
		$tpl_sec->setLoop('zones', $zones_sec);

		file_put_contents($dns_config['named_conf_local_path'], $tpl->grab()."\n".$tpl_sec->grab());
		$app->log("Writing BIND named.conf.local file: ".$dns_config['named_conf_local_path'], LOGLEVEL_DEBUG);

		unset($tpl_sec);
		unset($zones_sec);
		unset($tmps_sec);
583
		unset($tpl);
584 585
		unset($zones);
		unset($tmps);
586

587
	}
588 589 590



591 592 593

} // end class

594

595
?>