239 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
| <?php
 | |
| 
 | |
| /*
 | |
|   ----------------------------------------------------------------------
 | |
|   LICENSE
 | |
| 
 | |
|   This program is free software; you can redistribute it and/or
 | |
|   modify it under the terms of the GNU General Public License (GPL)
 | |
|   as published by the Free Software Foundation; either version 2
 | |
|   of the License, or (at your option) any later version.
 | |
| 
 | |
|   This program is distributed in the hope that it will be useful,
 | |
|   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|   GNU General Public License for more details.
 | |
| 
 | |
|   To read the license please visit http://www.gnu.org/copyleft/gpl.html
 | |
|   ----------------------------------------------------------------------
 | |
| */
 | |
| 
 | |
| /**
 | |
|  * Manages BIND 9+ zone management templates in AlternC 3.5+
 | |
|  * 
 | |
|  * @copyright AlternC-Team 2000-2018 https://alternc.com/
 | |
|  */
 | |
| class m_bind {
 | |
| 
 | |
|     var $shouldreload;
 | |
|     var $shouldreconfig;
 | |
|     
 | |
|     var $ZONE_TEMPLATE ="/etc/alternc/templates/bind/templates/zone.template";
 | |
|     var $NAMED_TEMPLATE ="/etc/alternc/templates/bind/templates/named.template";
 | |
|     var $NAMED_CONF ="/var/lib/alternc/bind/automatic.conf";
 | |
|     var $RNDC ="/usr/sbin/rndc";
 | |
| 
 | |
|     var $zone_file_directory = '/var/lib/alternc/bind/zones';
 | |
| 
 | |
|     // ------------------------------------------------------------
 | |
|     /** Hook launched before any action by updatedomains 
 | |
|      * initialize the reload/reconfig flags used by POST
 | |
|      * @NOTE launched as ROOT 
 | |
|      */
 | |
|     function hook_updatedomains_dns_pre() {
 | |
|         $this->shouldreload=false;
 | |
|         $this->shouldreconfig=false;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     // ------------------------------------------------------------
 | |
|     /**
 | |
|      * Hook launched for each ZONE for which we want a zone update (or create)
 | |
|      * update the zone, create it if necessary, 
 | |
|      * and ask for reload or reconfig of bind9 depending on what happened
 | |
|      * @NOTE launched as ROOT 
 | |
|      */
 | |
|     function hook_updatedomains_dns_add($dominfo) {
 | |
|         global $L_FQDN,$L_NS1_HOSTNAME,$L_NS2_HOSTNAME,$L_DEFAULT_MX,$L_DEFAULT_SECONDARY_MX,$L_PUBLIC_IP,$L_PUBLIC_IPV6;
 | |
| 
 | |
|         $domain = $dominfo["domaine"];
 | |
|         $ttl = $dominfo["zonettl"];
 | |
| 
 | |
|         // does it already exist?
 | |
|         if (file_exists($this->zone_file_directory."/".$domain)) {
 | |
|             list($islocked,$serial,$more)=$this->read_zone($domain);
 | |
|             $serial++; // only increment serial for new zones
 | |
|         } else {
 | |
|             $more="";
 | |
|             $serial=date("Ymd")."00";
 | |
|             $islocked=false;
 | |
|         }
 | |
|         if ($islocked) return;
 | |
| 
 | |
|         // Prepare a new zonefile from a template
 | |
|         $zone = file_get_contents($this->ZONE_TEMPLATE);
 | |
| 
 | |
|         // add the SUBDOMAIN entries
 | |
|         $zone .= $this->conf_from_db($domain);
 | |
| 
 | |
|         // substitute ALTERNC & domain variables
 | |
|         $zone = strtr($zone, array(
 | |
|             "%%fqdn%%" => "$L_FQDN",
 | |
|             "%%ns1%%" => "$L_NS1_HOSTNAME",
 | |
|             "%%ns2%%" => "$L_NS2_HOSTNAME",
 | |
|             "%%DEFAULT_MX%%" => "$L_DEFAULT_MX",
 | |
|             "%%DEFAULT_SECONDARY_MX%%" => "$L_DEFAULT_SECONDARY_MX",
 | |
|             "@@fqdn@@" => "$L_FQDN",
 | |
|             "@@ns1@@" => "$L_NS1_HOSTNAME",
 | |
|             "@@ns2@@" => "$L_NS2_HOSTNAME",
 | |
|             "@@DEFAULT_MX@@" => "$L_DEFAULT_MX",
 | |
|             "@@DEFAULT_SECONDARY_MX@@" => "$L_DEFAULT_SECONDARY_MX",
 | |
|             "@@DOMAINE@@" => $domain,
 | |
|             "@@SERIAL@@" => $serial,
 | |
|             "@@PUBLIC_IP@@" => "$L_PUBLIC_IP",
 | |
|             "@@PUBLIC_IPV6@@" => "$L_PUBLIC_IPV6",
 | |
|             "@@ZONETTL@@" => $ttl,
 | |
|         ));
 | |
| 
 | |
|         // add the "END ALTERNC CONF line";
 | |
|         $zone .= ";;; END ALTERNC AUTOGENERATE CONFIGURATION\n";
 | |
| 
 | |
|         // add the manually entered info:
 | |
|         $zone .= $more;
 | |
|         file_put_contents($this->zone_file_directory."/".$domain,$zone);
 | |
| 
 | |
|         // add the line into bind9 conf:
 | |
|         if (add_line_to_file(
 | |
|             $this->NAMED_CONF,
 | |
|             trim(strtr(
 | |
|                 file_get_contents($this->NAMED_TEMPLATE),
 | |
|                 array(
 | |
|                     "@@DOMAIN@@" => $domain,
 | |
|                     "@@ZONE_FILE@@" => $this->zone_file_directory."/".$domain
 | |
|                 )
 | |
|             )))
 | |
|         ) {
 | |
|             $this->shouldreconfig=true;
 | |
|         } else {
 | |
|             $this->shouldreload=true;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     // ------------------------------------------------------------
 | |
|     /** 
 | |
|      * Hook launched for each ZONE for which we want a zone DELETE
 | |
|      * remove the zone and its file,
 | |
|      * and if any action happened, ask for bind RECONFIG at posttime
 | |
|      * @NOTE launched as ROOT 
 | |
|      */
 | |
|     function hook_updatedomains_dns_del($dominfo) {
 | |
|         $domain = $dominfo["domaine"];
 | |
|         if (del_line_from_file(
 | |
|             $this->NAMED_CONF,
 | |
|             trim(strtr(
 | |
|                 file_get_contents($this->NAMED_TEMPLATE),
 | |
|                 array(
 | |
|                     "@@DOMAIN@@" => $domain,
 | |
|                     "@@ZONE_FILE@@" => $this->zone_file_directory."/".$domain
 | |
|                 )
 | |
|             )))
 | |
|         ) {
 | |
|             $this->shouldreconfig=true;
 | |
|         } else {
 | |
|             return;
 | |
|         }
 | |
|         @unlink($this->zone_file_directory."/".$domain);
 | |
|     }
 | |
| 
 | |
|     
 | |
|     // ------------------------------------------------------------
 | |
|     /** 
 | |
|      * Hook function launched at the very end of updatedomains 
 | |
|      * here, we just reload OR reconfig (or both) bind9 depending 
 | |
|      * on what happened before.
 | |
|      * @NOTE launched as ROOT 
 | |
|      */ 
 | |
|     function hook_updatedomains_dns_post() {
 | |
|         global $msg;
 | |
|         if ($this->shouldreload) {
 | |
|             $ret=0;
 | |
|             exec($this->RNDC." reload 2>&1",$out,$ret);
 | |
|             if ($ret!=0) {
 | |
|                 $msg->raise("ERROR","bind","Error while reloading bind, error code is $ret\n".implode("\n",$out));
 | |
|             } else {
 | |
|                 $msg->raise("INFO","bind","Bind reloaded");
 | |
|             }
 | |
|         }
 | |
|         if ($this->shouldreconfig) {
 | |
|             $ret=0;
 | |
|             exec($this->RNDC." reconfig 2>&1",$out,$ret);
 | |
|             if ($ret!=0) {
 | |
|                 $msg->raise("ERROR","bind","Error while reconfiguring bind, error code is $ret\n".implode("\n",$out));
 | |
|             } else {
 | |
|                 $msg->raise("INFO","bind","Bind reconfigured");
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     
 | |
|     // ------------------------------------------------------------
 | |
|     /** 
 | |
|      * read a zone file for $domain, 
 | |
|      * @param $domain string the domain name 
 | |
|      * @return array with 3 informations: 
 | |
|      * is the domain locked? (boolean), what's the current serial (integer), the data after alternc conf (string of lines)
 | |
|      */
 | |
|     function read_zone($domain) {
 | |
|         $f=fopen($this->zone_file_directory."/".$domain,"rb");
 | |
|         $islocked=false;
 | |
|         $more="";
 | |
|         $serial=date("Ymd")."00";
 | |
|         while ($s=fgets($f,4096)) {
 | |
|             if (preg_match("#\;\s*LOCKED:YES#i",$s)) {
 | |
|                 $islocked=true;
 | |
|             }
 | |
|             if (preg_match("/\s*(\d{10})\s+\;\sserial\s?/", $s,$mat)) {
 | |
|                 $serial=$mat[1];
 | |
|             }
 | |
|             if (preg_match('/\;\s*END\sALTERNC\sAUTOGENERATE\sCONFIGURATION(.*)/s', $s)) {
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         while ($s=fgets($f,4096)) {
 | |
|             $more.=$s;
 | |
|         }
 | |
|         return array($islocked,$serial,$more);
 | |
|     }
 | |
| 
 | |
| 
 | |
|     // ------------------------------------------------------------
 | |
|     /**
 | |
|      * Return the part of the conf we got from the sub_domaines table
 | |
|      * @global m_mysql $db
 | |
|      * @param string $domain
 | |
|      * @return string a zonefile excerpt
 | |
|      */
 | |
|     function conf_from_db($domain) {
 | |
|         global $db;
 | |
|         $db->query("
 | |
|         SELECT 
 | |
|           REPLACE(REPLACE(dt.entry,'%TARGET%',sd.valeur), '%SUB%', if(length(sd.sub)>0,sd.sub,'@')) AS ENTRY 
 | |
|         FROM 
 | |
|           sub_domaines sd,
 | |
|           domaines_type dt 
 | |
|         WHERE 
 | |
|           sd.type=dt.name
 | |
|           AND sd.enable IN ('ENABLE', 'ENABLED') 
 | |
|         ORDER BY ENTRY ;");
 | |
|         $t="";
 | |
|         while ($db->next_record()) {
 | |
|             $t.= $db->f('ENTRY')."\n";
 | |
|         }
 | |
|         return $t;
 | |
|     }
 | |
| 
 | |
|     
 | |
| } // m_bind
 | |
| 
 |