240 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			240 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')
 | 
						|
          AND sb.web_action NOT IN ('DELETE')
 | 
						|
        ORDER BY ENTRY ;");
 | 
						|
        $t="";
 | 
						|
        while ($db->next_record()) {
 | 
						|
            $t.= $db->f('ENTRY')."\n";
 | 
						|
        }
 | 
						|
        return $t;
 | 
						|
    }
 | 
						|
 | 
						|
    
 | 
						|
} // m_bind
 | 
						|
 |