Till Brehm
2014-11-06 d907c0ce889a71b1ac5fb49e8dd5229b9459bd0e
commit | author | age
7dbea0 1 <?php
T 2
3 /*
4 Copyright (c) 2009, Till Brehm, projektfarm Gmbh
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without modification,
8 are permitted provided that the following conditions are met:
9
10     * Redistributions of source code must retain the above copyright notice,
11       this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright notice,
13       this list of conditions and the following disclaimer in the documentation
14       and/or other materials provided with the distribution.
15     * Neither the name of ISPConfig nor the names of its contributors
16       may be used to endorse or promote products derived from this software without
17       specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 class bind_plugin {
7fe908 32
7dbea0 33     var $plugin_name = 'bind_plugin';
T 34     var $class_name  = 'bind_plugin';
35     var $action = 'update';
7fe908 36
7dbea0 37     //* This function is called during ispconfig installation to determine
T 38     //  if a symlink shall be created for this plugin.
39     function onInstall() {
40         global $conf;
7fe908 41
4bd960 42         if(isset($conf['bind']['installed']) && $conf['bind']['installed'] == true && @is_link('/usr/local/ispconfig/server/mods-enabled/dns_module.inc.php')) {
7dbea0 43             return true;
T 44         } else {
45             return false;
46         }
7fe908 47
7dbea0 48     }
7fe908 49
MC 50
7dbea0 51     /*
T 52          This function is called when the plugin is loaded
53     */
7fe908 54
7dbea0 55     function onLoad() {
T 56         global $app;
7fe908 57
7dbea0 58         /*
T 59         Register for the events
60         */
a59731 61
7fe908 62         //* SOA
MC 63         $app->plugins->registerEvent('dns_soa_insert', $this->plugin_name, 'soa_insert');
64         $app->plugins->registerEvent('dns_soa_update', $this->plugin_name, 'soa_update');
65         $app->plugins->registerEvent('dns_soa_delete', $this->plugin_name, 'soa_delete');
66
67         //* SLAVE
68         $app->plugins->registerEvent('dns_slave_insert', $this->plugin_name, 'slave_insert');
69         $app->plugins->registerEvent('dns_slave_update', $this->plugin_name, 'slave_update');
70         $app->plugins->registerEvent('dns_slave_delete', $this->plugin_name, 'slave_delete');
71
7dbea0 72         //* RR
7fe908 73         $app->plugins->registerEvent('dns_rr_insert', $this->plugin_name, 'rr_insert');
MC 74         $app->plugins->registerEvent('dns_rr_update', $this->plugin_name, 'rr_update');
75         $app->plugins->registerEvent('dns_rr_delete', $this->plugin_name, 'rr_delete');
76
7dbea0 77     }
7fe908 78
MC 79
80     function soa_insert($event_name, $data) {
7dbea0 81         global $app, $conf;
7fe908 82
7dbea0 83         $this->action = 'insert';
7fe908 84         $this->soa_update($event_name, $data);
MC 85
7dbea0 86     }
7fe908 87
MC 88     function soa_update($event_name, $data) {
7dbea0 89         global $app, $conf;
7fe908 90
fc70a2 91         //* Load libraries
T 92         $app->uses("getconf,tpl");
7fe908 93
7dbea0 94         //* load the server configuration options
T 95         $dns_config = $app->getconf->get_server_config($conf["server_id"], 'dns');
7fe908 96
7dbea0 97         //* Write the domain file
fdb514 98         if(!empty($data['new']['id'])) {
8ee180 99             $tpl = new tpl();
T 100             $tpl->newTemplate("bind_pri.domain.master");
7fe908 101
8ee180 102             $zone = $data['new'];
T 103             $tpl->setVar($zone);
7fe908 104
8ee180 105             $records = $app->db->queryAllRecords("SELECT * FROM dns_rr WHERE zone = ".$zone['id']." AND active = 'Y'");
615a0a 106             if(is_array($records) && !empty($records)){
T 107                 for($i=0;$i<sizeof($records);$i++){
108                     if($records[$i]['ttl'] == 0) $records[$i]['ttl'] = '';
42f822 109                     if($records[$i]['name'] == '') $records[$i]['name'] = '@';
793c77 110                     //* Split TXT records, if nescessary
TB 111                     if($records[$i]['type'] == 'TXT' && strlen($records[$i]['data']) > 255) {
112                         $records[$i]['data'] = implode('" "',str_split( $records[$i]['data'], 255));
113                     }
615a0a 114                 }
T 115             }
7fe908 116             $tpl->setLoop('zones', $records);
MC 117
4b88c2 118             //TODO : change this when distribution information has been integrated into server record
7fe908 119             if (file_exists('/etc/gentoo-release')) {
d907c0 120                 $filename = escapeshellcmd($dns_config['bind_zonefiles_dir'].'/pri/'.str_replace("/", "_", substr($zone['origin'], 0, -1)));
7fe908 121             }
MC 122             else {
123                 $filename = escapeshellcmd($dns_config['bind_zonefiles_dir'].'/pri.'.str_replace("/", "_", substr($zone['origin'], 0, -1)));
124             }
125
126             file_put_contents($filename, $tpl->grab());
8e725d 127             chown($filename, escapeshellcmd($dns_config['bind_user']));
J 128             chgrp($filename, escapeshellcmd($dns_config['bind_group']));
7fe908 129
f038c0 130             //* Check the zonefile
T 131             if(is_file($filename.'.err')) unlink($filename.'.err');
7fe908 132             exec('named-checkzone '.escapeshellarg($zone['origin']).' '.escapeshellarg($filename), $out, $return_status);
f038c0 133             if($return_status === 0) {
7fe908 134                 $app->log("Writing BIND domain file: ".$filename, LOGLEVEL_DEBUG);
f038c0 135             } else {
7fe908 136                 $app->log("Writing BIND domain file failed: ".$filename." ".implode(' ', $out), LOGLEVEL_WARN);
MC 137                 rename($filename, $filename.'.err');
f038c0 138             }
8ee180 139             unset($tpl);
T 140             unset($records);
a59ad3 141             unset($records_out);
8ee180 142             unset($zone);
T 143         }
7fe908 144
7dbea0 145         //* rebuild the named.conf file if the origin has changed or when the origin is inserted.
fc70a2 146         //if($this->action == 'insert' || $data['old']['origin'] != $data['new']['origin']) {
7fe908 147         $this->write_named_conf($data, $dns_config);
fc70a2 148         //}
7fe908 149
7dbea0 150         //* Delete old domain file, if domain name has been changed
T 151         if($data['old']['origin'] != $data['new']['origin']) {
4b88c2 152             //TODO : change this when distribution information has been integrated into server record
7fe908 153             if (file_exists('/etc/gentoo-release')) {
d907c0 154                 $filename = $dns_config['bind_zonefiles_dir'].'/pri/'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
7fe908 155             }
MC 156             else {
157                 $filename = $dns_config['bind_zonefiles_dir'].'/pri.'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
158             }
159
f038c0 160             if(is_file($filename)) unlink($filename);
T 161             if(is_file($filename.'.err')) unlink($filename.'.err');
7dbea0 162         }
7fe908 163
eb64c3 164         //* Restart bind nameserver if update_acl is not empty, otherwise reload it
TB 165         if($data['new']['update_acl'] != '') {
166             $app->services->restartServiceDelayed('bind', 'restart');
167         } else {
168             $app->services->restartServiceDelayed('bind', 'reload');
169         }
7fe908 170
7dbea0 171     }
a59731 172
7fe908 173     function soa_delete($event_name, $data) {
a59731 174         global $app, $conf;
7fe908 175
MC 176         //* load the server configuration options
177         $app->uses("getconf,tpl");
178         $dns_config = $app->getconf->get_server_config($conf["server_id"], 'dns');
179
180         //* rebuild the named.conf file
181         $this->write_named_conf($data, $dns_config);
182
183         //* Delete the domain file
184         //TODO : change this when distribution information has been integrated into server record
185         if (file_exists('/etc/gentoo-release')) {
186             $zone_file_name = $dns_config['bind_zonefiles_dir'].'/pri/'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
187         }
188         else {
189             $zone_file_name = $dns_config['bind_zonefiles_dir'].'/pri.'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
190         }
191
192         if(is_file($zone_file_name)) unlink($zone_file_name);
193         if(is_file($zone_file_name.'.err')) unlink($zone_file_name.'.err');
194         $app->log("Deleting BIND domain file: ".$zone_file_name, LOGLEVEL_DEBUG);
195
196         //* Reload bind nameserver
197         $app->services->restartServiceDelayed('bind', 'reload');
198
a59731 199     }
7fe908 200
MC 201     function slave_insert($event_name, $data) {
a59731 202         global $app, $conf;
7fe908 203
MC 204         $this->action = 'insert';
205         $this->slave_update($event_name, $data);
206
207     }
208
209     function slave_update($event_name, $data) {
210         global $app, $conf;
211
a59731 212         //* Load libraries
D 213         $app->uses("getconf,tpl");
7fe908 214
a59731 215         //* load the server configuration options
D 216         $dns_config = $app->getconf->get_server_config($conf["server_id"], 'dns');
7fe908 217
a59731 218         //* rebuild the named.conf file if the origin has changed or when the origin is inserted.
D 219         //if($this->action == 'insert' || $data['old']['origin'] != $data['new']['origin']) {
7fe908 220         $this->write_named_conf($data, $dns_config);
a59731 221         //}
7fe908 222
a59731 223         //* Delete old domain file, if domain name has been changed
D 224         if($data['old']['origin'] != $data['new']['origin']) {
4b88c2 225             //TODO : change this when distribution information has been integrated into server record
7fe908 226             if (file_exists('/etc/gentoo-release')) {
MC 227                 $filename = $dns_config['bind_zonefiles_dir'].'/sec/'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
228             }
229             else {
230                 $filename = $dns_config['bind_zonefiles_dir'].'/slave/sec.'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
231             }
232
a59731 233             if(is_file($filename)) unset($filename);
D 234         }
7fe908 235
355efb 236         //* Ensure that the named slave directory is writable by the named user
T 237         if (file_exists('/etc/gentoo-release')) {
238             $slave_record_dir = $dns_config['bind_zonefiles_dir'].'/sec';
239         } else {
240             $slave_record_dir = $dns_config['bind_zonefiles_dir'].'/slave';
241         }
7fe908 242         if(!@is_dir($slave_record_dir)) mkdir($slave_record_dir, 0770);
MC 243         chown($slave_record_dir, $dns_config['bind_user']);
244         chgrp($slave_record_dir, $dns_config['bind_group']);
245
a59731 246         //* Reload bind nameserver
7fe908 247         $app->services->restartServiceDelayed('bind', 'reload');
MC 248
a59731 249     }
7fe908 250
MC 251     function slave_delete($event_name, $data) {
a59731 252         global $app, $conf;
7fe908 253
MC 254
a59731 255         //* load the server configuration options
D 256         $app->uses("getconf,tpl");
257         $dns_config = $app->getconf->get_server_config($conf["server_id"], 'dns');
7fe908 258
a59731 259         //* rebuild the named.conf file
7fe908 260         $this->write_named_conf($data, $dns_config);
MC 261
a59731 262         //* Delete the domain file
4b88c2 263         //TODO : change this when distribution information has been integrated into server record
7fe908 264         if (file_exists('/etc/gentoo-release')) {
MC 265             $zone_file_name = $dns_config['bind_zonefiles_dir'].'/sec/'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
266         }
267         else {
268             $zone_file_name = $dns_config['bind_zonefiles_dir'].'/slave/sec.'.str_replace("/", "_", substr($data['old']['origin'], 0, -1));
269         }
270
a59731 271         if(is_file($zone_file_name)) unlink($zone_file_name);
7fe908 272         $app->log("Deleting BIND domain file for secondary zone: ".$zone_file_name, LOGLEVEL_DEBUG);
MC 273
a59731 274         //* Reload bind nameserver
7fe908 275         $app->services->restartServiceDelayed('bind', 'reload');
MC 276
7dbea0 277
T 278     }
7fe908 279
MC 280     function rr_insert($event_name, $data) {
7dbea0 281         global $app, $conf;
7fe908 282
7dbea0 283         //* Get the data of the soa and call soa_update
T 284         $tmp = $app->db->queryOneRecord("SELECT * FROM dns_soa WHERE id = ".$data['new']['zone']);
285         $data["new"] = $tmp;
286         $data["old"] = $tmp;
287         $this->action = 'update';
7fe908 288         $this->soa_update($event_name, $data);
MC 289
7dbea0 290     }
7fe908 291
MC 292     function rr_update($event_name, $data) {
7dbea0 293         global $app, $conf;
7fe908 294
MC 295         //* Get the data of the soa and call soa_update
296         $tmp = $app->db->queryOneRecord("SELECT * FROM dns_soa WHERE id = ".$data['new']['zone']);
297         $data["new"] = $tmp;
298         $data["old"] = $tmp;
299         $this->action = 'update';
300         $this->soa_update($event_name, $data);
301
302     }
303
304     function rr_delete($event_name, $data) {
305         global $app, $conf;
306
7dbea0 307         //* Get the data of the soa and call soa_update
531afa 308         $tmp = $app->db->queryOneRecord("SELECT * FROM dns_soa WHERE id = ".intval($data['old']['zone']));
7dbea0 309         $data["new"] = $tmp;
T 310         $data["old"] = $tmp;
311         $this->action = 'update';
7fe908 312         $this->soa_update($event_name, $data);
MC 313
7dbea0 314     }
7fe908 315
MC 316     //##################################################################
317
7dbea0 318     function write_named_conf($data, $dns_config) {
T 319         global $app, $conf;
7fe908 320
MC 321         //* Only write the master file for the current server
c36fe4 322         $tmps = $app->db->queryAllRecords("SELECT origin, xfer, also_notify, update_acl FROM dns_soa WHERE active = 'Y' AND server_id=".$conf["server_id"]);
fc70a2 323         $zones = array();
7fe908 324
957aaf 325         //* Check if the current zone that triggered this function has at least one NS record
f038c0 326         /* Has been replaced by a better zone check
531afa 327         $rec_num = $app->db->queryOneRecord("SELECT count(id) as ns FROM dns_rr WHERE type = 'NS' AND zone = ".intval($data['new']['id'])." AND active = 'Y'");
957aaf 328         if($rec_num['ns'] == 0) {
T 329             $exclude_zone = $data['new']['origin'];
330         } else {
331             $exclude_zone = '';
332         }
f038c0 333         */
7fe908 334
4b88c2 335         //TODO : change this when distribution information has been integrated into server record
7fe908 336         if (file_exists('/etc/gentoo-release')) {
MC 337             $pri_zonefiles_path = $dns_config['bind_zonefiles_dir'].'/pri/';
338             $sec_zonefiles_path = $dns_config['bind_zonefiles_dir'].'/sec/';
339
340         }
341         else {
342             $pri_zonefiles_path = $dns_config['bind_zonefiles_dir'].'/pri.';
343             $sec_zonefiles_path = $dns_config['bind_zonefiles_dir'].'/slave/sec.';
344         }
a59ad3 345
957aaf 346         //* Loop trough zones
fc70a2 347         foreach($tmps as $tmp) {
7fe908 348
MC 349             $zone_file = $pri_zonefiles_path.str_replace("/", "_", substr($tmp['origin'], 0, -1));
350
a59ad3 351             $options = '';
a59731 352             if(trim($tmp['xfer']) != '') {
7fe908 353                 $options .= "        allow-transfer {".str_replace(',', ';', $tmp['xfer']).";};\n";
a59731 354             } else {
D 355                 $options .= "        allow-transfer {none;};\n";
356             }
7fe908 357             if(trim($tmp['also_notify']) != '') $options .= '        also-notify {'.str_replace(',', ';', $tmp['also_notify']).";};\n";
MC 358             if(trim($tmp['update_acl']) != '') $options .= "        allow-update {".str_replace(',', ';', $tmp['update_acl']).";};\n";
359
f038c0 360             if(file_exists($zone_file)) {
7fe908 361                 $zones[] = array( 'zone' => substr($tmp['origin'], 0, -1),
MC 362                     'zonefile_path' => $zone_file,
363                     'options' => $options
364                 );
957aaf 365             }
fc70a2 366         }
a59731 367
7dbea0 368         $tpl = new tpl();
T 369         $tpl->newTemplate("bind_named.conf.local.master");
7fe908 370         $tpl->setLoop('zones', $zones);
MC 371
a59731 372         //* And loop through the secondary zones, but only for the current server
D 373         $tmps_sec = $app->db->queryAllRecords("SELECT origin, xfer, ns FROM dns_slave WHERE active = 'Y' AND server_id=".$conf["server_id"]);
374         $zones_sec = array();
375
376         foreach($tmps_sec as $tmp) {
7fe908 377
a59731 378             $options = "        masters {".$tmp['ns'].";};\n";
7fe908 379             if(trim($tmp['xfer']) != '') {
MC 380                 $options .= "        allow-transfer {".str_replace(',', ';', $tmp['xfer']).";};\n";
381             } else {
382                 $options .= "        allow-transfer {none;};\n";
383             }
a59731 384
D 385
7fe908 386             $zones_sec[] = array( 'zone' => substr($tmp['origin'], 0, -1),
MC 387                 'zonefile_path' => $sec_zonefiles_path.str_replace("/", "_", substr($tmp['origin'], 0, -1)),
388                 'options' => $options
389             );
a59731 390
7fe908 391             //   $filename = escapeshellcmd($dns_config['bind_zonefiles_dir'].'/slave/sec.'.substr($tmp['origin'],0,-1));
MC 392             //   $app->log("Writing BIND domain file: ".$filename,LOGLEVEL_DEBUG);
393
394
a59731 395         }
7fe908 396
a59731 397         $tpl_sec = new tpl();
D 398         $tpl_sec->newTemplate("bind_named.conf.local.slave");
7fe908 399         $tpl_sec->setLoop('zones', $zones_sec);
a59731 400
7fe908 401         file_put_contents($dns_config['named_conf_local_path'], $tpl->grab()."\n".$tpl_sec->grab());
MC 402         $app->log("Writing BIND named.conf.local file: ".$dns_config['named_conf_local_path'], LOGLEVEL_DEBUG);
403
404         unset($tpl_sec);
405         unset($zones_sec);
406         unset($tmps_sec);
7dbea0 407         unset($tpl);
fc70a2 408         unset($zones);
T 409         unset($tmps);
7fe908 410
7dbea0 411     }
7fe908 412
MC 413
414
7dbea0 415
T 416 } // end class
417
a59731 418 ?>