aboutsummaryrefslogtreecommitdiffstats
path: root/config/bind/bind.inc
diff options
context:
space:
mode:
Diffstat (limited to 'config/bind/bind.inc')
-rw-r--r--config/bind/bind.inc883
1 files changed, 883 insertions, 0 deletions
diff --git a/config/bind/bind.inc b/config/bind/bind.inc
new file mode 100644
index 00000000..146632c9
--- /dev/null
+++ b/config/bind/bind.inc
@@ -0,0 +1,883 @@
+<?PHP
+/* $Id$ */
+/*
+ bind.inc
+ part of the Bind package for pfSense
+ Copyright (C) 2013 Juliano Oliveira/Adriano Brancher
+ Copyright (C) 2013 Marcello Coutinho
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. 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.
+
+ THIS SOFTWARE IS PROVIDED ``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
+ AUTHOR 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.
+
+*/
+$shortcut_section = "bind";
+require_once('globals.inc');
+require_once('config.inc');
+require_once('util.inc');
+require_once('pfsense-utils.inc');
+require_once('pkg-utils.inc');
+require_once('service-utils.inc');
+if(!function_exists("filter_configure"))
+ require_once("filter.inc");
+
+$pf_version=substr(trim(file_get_contents("/etc/version")),0,3);
+if ($pf_version > 2.0)
+ define('BIND_LOCALBASE', '/usr/pbi/bind-' . php_uname("m"));
+else
+ define('BIND_LOCALBASE','/usr/local');
+
+define('CHROOT_LOCALBASE','/cf/named');
+
+function bind_zone_validate($post, $input_errors){
+ if (key_exists("mail",$_POST))
+ $_POST['mail']=preg_replace("/@/",".",$post['mail']);
+
+ switch ($_POST['type']){
+ case 'slave':
+ if( $_POST['slaveip'] == "")
+ $input_errors[] = 'The field \'Master Zone IP\' is required for slave zones.';
+ break;
+ case 'forward':
+ if( $_POST['forwarders'] == "")
+ $input_errors[] = 'The field \'Forwarders\' is required for forward zones.';
+ break;
+ case 'redirect':
+ $_POST['tll']=300;
+ $_POST['refresh']=0;
+ $_POST['serial']=0;
+ $_POST['retry']=0;
+ $_POST['expire']=0;
+ $_POST['minimum']=0;
+ if($_POST['mail']=='')
+ $input_errors[] = "The field 'Mail Admin Zone' is required for {$_POST['type']} zones.";
+
+ default:
+ if($_POST['nameserver']=='')
+ $input_errors[] = "The field 'Name server' is required for {$_POST['type']} zones.";
+ for ($i=0;$i < count($_POST);$i++){
+ if (key_exists("hostname$i",$_POST)){
+ if ($_POST['reverso']=="on"){
+ $_POST["hostvalue$i"]="";
+ if (!preg_match("/(PTR|NS)/",$_POST["hosttype$i"]))
+ $input_errors[] = 'On reverse zones, valid record types are NS or PTR';
+ }
+ if (preg_match("/(MX|NS)/",$_POST["hosttype$i"]))
+ $_POST["hostname$i"]="";
+ if (!preg_match("/(MX|NS)/",$_POST["hosttype$i"]) && $_POST["hostname$i"]=="")
+ $input_errors[] = 'Record cannot be empty for '.$_POST["hosttype$i"].' type ';
+ if ($_POST["hosttype$i"]=="MX" && $_POST["hostvalue$i"]=="")
+ $_POST["hostvalue$i"]="10";
+ if ($_POST["hosttype$i"]!="MX" && $_POST["hostvalue$i"]!="")
+ $_POST["hostvalue$i"]="";
+ if ($_POST["hostdst$i"]=="")
+ $input_errors[] = 'Alias or IP address cannot be empty.';
+ }
+ }
+ }
+}
+
+ function bind_sync(){
+
+ global $config;
+ conf_mount_rw();
+ //create rndc
+ $rndc_confgen="/usr/local/sbin/rndc-confgen";
+ if (!file_exists(BIND_LOCALBASE."/etc/rndc-confgen.pfsense") && file_exists($rndc_confgen)){
+ exec("$rndc_confgen ",$rndc_conf);
+ foreach($rndc_conf as $line)
+ $confgen_file.="$line\n";
+ file_put_contents(BIND_LOCALBASE."/etc/rndc-confgen.pfsese",$confgen_file);
+ }
+ if (file_exists(BIND_LOCALBASE."/etc/rndc-confgen.pfsese")){
+ $rndc_conf=file(BIND_LOCALBASE."/etc/rndc-confgen.pfsese");
+ $confgen="rndc.conf";
+ $rndc_bindconf="";
+ foreach ($rndc_conf as $line){
+ if ($confgen =="rndc.conf"){
+ if (!preg_match ("/^#/",$line))
+ $rndc_file.=$line;
+ }
+ else{
+ if (!preg_match ("/named.conf/",$line))
+ $rndc_bindconf.=preg_replace('/#/',"",$line);
+ }
+ if (preg_match("/named.conf/",$line)){
+ $confgen="named.conf";
+ file_put_contents(BIND_LOCALBASE."/etc/rndc.conf",$rndc_file);
+ }
+ }
+ }
+
+ $bind = $config["installedpackages"]["bind"]["config"][0];
+ $bind_enable = $bind['enable_bind'];
+ $bind_forwarder = $bind['bind_forwarder'];
+ $forwarder_ips = $bind['bind_forwarder_ips'];
+ $ram_limit = ($bind['bind_ram_limit']?$bind['bind_ram_limit']:"256M");
+ $hide_version = $bind['bind_hide_version'];
+ $bind_notify = $bind['bind_notify'];
+ $custom_options = base64_decode($bind['bind_custom_options']);
+ $bind_logging = $bind['bind_logging'];
+ $bind_conf ="#Bind pfsense configuration\n";
+ $bind_conf .="#Do not edit this file!!!\n\n";
+ $bind_conf .= "$rndc_bindconf\n";
+ $bind_conf .= <<<EOD
+
+options {
+ directory "/etc/namedb";
+ pid-file "/var/run/named/pid";
+ statistics-file "/var/log/named.stats";
+ max-cache-size {$ram_limit};
+
+EOD;
+ // check response rate limit option
+ //https://kb.isc.org/article/AA-01000/0/A-Quick-Introduction-to-Response-Rate-Limiting.html
+ //http://ss.vix.su/~vjs/rl-arm.html
+ if ($bind['rate_enabled']=="on"){
+ $rate_limit=($bind['rate_limit']?$bind['rate_limit']:"15");
+ $log_only=($bind['log_only']=="no"?"no":"yes");
+ $bind_conf .= <<<EOD
+ rate-limit {
+ responses-per-second {$rate_limit};
+ log-only {$log_only};
+ };
+
+EOD;
+ }
+ //check ips to listen on
+ if (preg_match("/All/",$bind['listenon'])){
+ $bind_listenonv6="Any;";
+ $bind_listenon="Any;";
+ }
+ else{
+ $bind_listenonv6="";
+ $bind_listenon ="";
+ foreach (explode(',',$bind['listenon']) as $listenon){
+ if (is_ipaddrv6($listenon))
+ $bind_listenonv6 .= $listenon."; ";
+ elseif (is_ipaddr($listenon))
+ $bind_listenon .= $listenon."; ";
+ else{
+ $listenon=(pfSense_get_interface_addresses(convert_friendly_interface_to_real_interface_name($listenon)));
+ if (is_ipaddr($listenon['ipaddr']))
+ $bind_listenon .= $listenon['ipaddr']."; ";
+ if(is_ipaddrv6($listenon['ipaddr6']))
+ $bind_listenonv6 .= $listenon['ipaddr6']."; ";
+ }
+ }
+ }
+ $bind_listenonv6=($bind_listenonv6==""?"none;":$bind_listenonv6);
+ $bind_listenon=($bind_listenon==""?"none;":$bind_listenon);
+ //print "<PRE>$bind_listenonv6 $bind_listenon";
+ if (key_exists("ipv6allow",$config['system'])){
+ $bind_conf .="\t\tlisten-on-v6 { $bind_listenonv6 };\n";
+ }
+ $bind_conf .="\t\tlisten-on { $bind_listenon };\n";
+
+ #forwarder config
+ if ($bind_forwarder == on)
+ $bind_conf .="\t\tforwarders { $forwarder_ips };\n";
+ if ($bind_notify == on)
+ $bind_conf .="\t\tnotify yes;\n";
+ if ($hide_version == on)
+ $bind_conf .="\t\tversion \"N/A\";\n";
+
+ $bind_conf .="\t\t$custom_options\n";
+ $bind_conf .= "\t};\n\n";
+
+ if ($bind_logging == on){
+ //check if bind is included on syslog
+ $syslog_files=array("/etc/inc/system.inc","/var/etc/syslog.conf");
+ $restart_syslog=0;
+ foreach ($syslog_files as $syslog_file){
+ $syslog_file_data=file_get_contents($syslog_file);
+ if (!preg_match("/dnsmasq,named,filterdns/",$syslog_file_data)){
+ $syslog_file_data=preg_replace("/dnsmasq,filterdns/","dnsmasq,named,filterdns",$syslog_file_data);
+ file_put_contents($syslog_file,$syslog_file_data);
+ $restart_syslog++;
+ }
+ }
+ if ($restart_syslog > 0){
+ system("/usr/bin/killall -HUP syslogd");
+ }
+ $log_categories=explode(",",$bind['log_options']);
+ $log_severity=($bind['log_severity']?$bind['log_severity']:'default');
+ if (sizeof($log_categories) > 0 && $log_categories[0]!=""){
+ $bind_conf .= <<<EOD
+
+ logging {
+ channel custom {
+ syslog daemon;
+ print-time no;
+ print-severity yes;
+ print-category yes;
+ severity {$log_severity};
+ };
+
+EOD;
+ foreach ($log_categories as $category)
+ $bind_conf .="\t\t\tcategory $category\t{custom;};\n";
+ $bind_conf .="\t\t};\n\n";
+ }
+ }
+ else {
+ $bind_conf .="\t\tlogging { category default { null; }; };\n\n";
+ }
+
+ #Config Zone domain
+ if(!is_array($config["installedpackages"]["bindacls"]) || !is_array($config["installedpackages"]["bindacls"]["config"])){
+ $config["installedpackages"]["bindacls"]["config"][] =array("name"=>"any","description"=>"Default Access list","row" => array("value"=> "","description"=>""));
+ write_config("Create Default bind acl 'Any'");
+ }
+ $bindacls = $config["installedpackages"]["bindacls"]["config"];
+ for ($i=0; $i<sizeof($bindacls); $i++)
+ {
+ $aclname = $bindacls[$i]['name'];
+ $aclhost = $bindacls[$i]['row'];
+ if($aclname != "any"){
+ $bind_conf .= "acl \"$aclname\" {\n";
+ for ($u=0; $u<sizeof($aclhost); $u++)
+ {
+ $aclhostvalue = $aclhost[$u]['value'];
+ $bind_conf .= "\t$aclhostvalue;\n";
+ }
+ $bind_conf .= "};\n\n";
+ }
+ }
+
+ if(is_array($config["installedpackages"]["bindviews"]))
+ $bindview = $config["installedpackages"]["bindviews"]["config"];
+ else
+ $bindview =array();
+
+ for ($i=0; $i<sizeof($bindview); $i++)
+ {
+ $views = $config["installedpackages"]["bindviews"]["config"][$i];
+ $viewname = $views['name'];
+ $viewrecursion = $views['recursion'];
+ if($views['match-clients'] == '')
+ $viewmatchclients = "none";
+ else
+ $viewmatchclients = str_replace(',','; ',$views['match-clients']);
+ if($views['allow-recursion'] == '')
+ $viewallowrecursion = "none";
+ else
+ $viewallowrecursion = str_replace(',','; ',$views['allow-recursion']);
+ $viewcustomoptions = base64_decode($views['bind_custom_options']);
+
+ $bind_conf .= "view \"$viewname\" { \n\n";
+ $bind_conf .= "\trecursion $viewrecursion;\n";
+ $bind_conf .= "\tmatch-clients { $viewmatchclients;};\n";
+ $bind_conf .= "\tallow-recursion { $viewallowrecursion;};\n";
+ $bind_conf .= "\t$viewcustomoptions\n\n";
+
+ if(is_array($config["installedpackages"]["bindzone"]))
+ $bindzone = $config["installedpackages"]["bindzone"]["config"];
+ else
+ $bindzone =array();
+
+ $write_config=0;
+ for ($x=0; $x<sizeof($bindzone); $x++)
+ {
+ $zone = $bindzone[$x];
+ if ($zone['disabled']=="on"){
+ continue;
+ }
+ $zonename = $zone['name'];
+ if ($zonename=="."){
+ $custom_root_zone[$i]=true;
+ }
+ $zonetype = $zone['type'];
+ $zoneview = $zone['view'];
+ $zonecustom = base64_decode($zone['custom']);
+ $zoneipslave = $zone['slaveip'];
+ $zoneforwarders=$zone['forwarders'];
+ $zonereverso = $zone['reverso'];
+
+ if (!(is_dir(CHROOT_LOCALBASE."/etc/namedb/$zonetype/$zoneview")))
+ mkdir(CHROOT_LOCALBASE."/etc/namedb/$zonetype/$zoneview",0755,true);
+
+ if($zone['allowupdate'] == '')
+ $zoneallowupdate = "none";
+ else
+ $zoneallowupdate = str_replace(',','; ',$zone['allowupdate']);
+ if($zone['allowquery'] == '')
+ $zoneallowquery = "none";
+ else
+ $zoneallowquery = str_replace(',','; ',$zone['allowquery']);
+ if($zone['allowtransfer'] == '')
+ $zoneallowtransfer = "none";
+ else
+ $zoneallowtransfer = str_replace(',','; ',$zone['allowtransfer']);
+
+ if ($zoneview == $viewname){
+ if($zonereverso == "on")
+ $bind_conf .= "\tzone \"$zonename.in-addr.arpa\" {\n";
+ else
+ $bind_conf .= "\tzone \"$zonename\" {\n";
+
+ $bind_conf .= "\t\ttype $zonetype;\n";
+ if ($zonetype != "forward")
+ $bind_conf .= "\t\tfile \"/etc/namedb/$zonetype/$zoneview/$zonename.DB\";\n";
+ switch ($zonetype){
+ case "slave":
+ $bind_conf .= "\t\tmasters { $zoneipslave; };\n";
+ $bind_conf .= "\t\tallow-transfer {none;};\n";
+ $bind_conf .= "\t\tnotify no;\n";
+ break;
+ case "forward":
+ $bind_conf .= "\t\tforward only;\n";
+ $bind_conf .= "\t\tforwarders { $zoneforwarders; };\n";
+ break;
+ case "redirect":
+ $bind_conf .= "\t\t# While using redirect zones,NXDOMAIN Redirection will not override DNSSEC\n";
+ $bind_conf .= "\t\t# If the client has requested DNSSEC records (DO=1) and the NXDOMAIN response is signed then no substitution will occur\n";
+ $bind_conf .= "\t\t# https://kb.isc.org/article/AA-00376/192/BIND-9.9-redirect-zones-for-NXDOMAIN-redirection.html\n";
+ break;
+ default:
+ $bind_conf .= "\t\tallow-update { $zoneallowupdate;};\n";
+ $bind_conf .= "\t\tallow-query { $zoneallowquery;};\n";
+ $bind_conf .= "\t\tallow-transfer { $zoneallowtransfer;};\n";
+ if ($zone['dnssec']=="on"){
+ //https://kb.isc.org/article/AA-00626/
+ $bind_conf .="\n\t\t# look for dnssec keys here:\n";
+ $bind_conf .="\t\tkey-directory \"/etc/namedb/keys\";\n\n";
+ $bind_conf .="\t\t# publish and activate dnssec keys:\n";
+ $bind_conf .="\t\tauto-dnssec maintain;\n\n";
+ $bind_conf .="\t\t# use inline signing:\n";
+ $bind_conf .="\t\tinline-signing yes;\n\n";
+ }
+ }
+ if ($zonecustom != '')
+ $bind_conf .= "\t\t$zonecustom\n";
+
+ $bind_conf .= "\t};\n\n";
+
+ switch($zonetype){
+ case "redirect":
+ case "master":
+ //check/update slave dir permission
+ chown(CHROOT_LOCALBASE."/etc/namedb/$zonetype","bind");
+ chown(CHROOT_LOCALBASE."/etc/namedb/$zonetype/$zoneview","bind");
+ $zonetll = ($zone['tll']?$zone['tll']:"43200");
+ $zonemail = ($zone['mail']?$zone['mail']:"zonemaster.{$zonename}");
+ $zonemail = preg_replace("/@/",".",$zonemail);
+ $zoneserial = $zone['serial'];
+ $zonerefresh = ($zone['refresh']?$zone['refresh']:"3600");
+ $zoneretry = ($zone['retry']?$zone['retry']:"600");
+ $zoneexpire = ($zone['expire']?$zone['expire']:"86400");
+ $zoneminimum = ($zone['minimum']?$zone['minimum']:"3600");
+ $zonenameserver = $zone['nameserver'];
+ $zoneipns = $zone['ipns'];
+ $zonereverso = $zone['reverso'];
+ if($zone['allowupdate'] == '')
+ $zoneallowupdate = "none";
+ else
+ $zoneallowupdate = str_replace(',','; ',$zone['allowupdate']);
+ if($zone['allowquery'] == '')
+ $zoneallowquery = "none";
+ else
+ $zoneallowquery = str_replace(',','; ',$zone['allowquery']);
+ if($zone['allowtransfer'] == '')
+ $zoneallowtransfer = "none";
+ else
+ $zoneallowtransfer = str_replace(',','; ',$zone['allowtransfer']);
+ $zone_conf = "\$TTL {$zonetll}\n;\n";
+ if($zonereverso == "on")
+ $zone_conf .= "\$ORIGIN {$zonename}.in-addr.arpa.\n\n";
+ else
+ $zone_conf .= "\$ORIGIN {$zonename}.\n\n";
+ $zone_conf .= ";\tDatabase file {$zonename}.DB for {$zonename} zone.\n";
+ $zone_conf .= ";\tDo not edit this file!!!\n";
+ $zone_conf .= ";\tZone version {$zoneserial}\n;\n";
+ if($zonereverso == "on" || $zonetype =="redirect")
+ $zone_conf .= "@\t IN SOA $zonenameserver. \t $zonemail. (\n";
+ else
+ $zone_conf .= "$zonename.\t IN SOA $zonenameserver. \t $zonemail. (\n";
+
+ $zone_conf .= "\t\t$zoneserial ; serial\n";
+ $zone_conf .= "\t\t$zonerefresh ; refresh\n";
+ $zone_conf .= "\t\t$zoneretry ; retry\n";
+ $zone_conf .= "\t\t$zoneexpire ; expire\n";
+ $zone_conf .= "\t\t$zoneminimum ; default_ttl\n\t\t)\n\n";
+ $zone_conf .= ";\n; Zone Records\n;\n";
+
+ if($zonereverso == "on")
+ $zone_conf .= "\t IN NS \t$zonenameserver.\n";
+ else{
+ $zone_conf .= "@ \t IN NS \t$zonenameserver.\n";
+ if ($zoneipns !="")
+ $zone_conf .= "@ \t IN A \t$zoneipns\n";
+ }
+ for ($y=0; $y<sizeof($zone['row']); $y++)
+ {
+ $hostname = (preg_match("/(MX|NS)/",$zone['row'][$y]['hosttype'])?"@":$zone['row'][$y]['hostname']);
+ $hosttype = $zone['row'][$y]['hosttype'];
+ $hostdst = $zone['row'][$y]['hostdst'];
+ if (preg_match("/[a-zA-Z]/",$hostdst) && !preg_match("/(TXT|SPF)/",$hosttype))
+ $hostdst .= ".";
+ $hostvalue = $zone['row'][$y]['hostvalue'];
+
+ $zone_conf .= "$hostname \t IN $hosttype $hostvalue \t$hostdst\n";
+ }
+ if (($zone[regdhcpstatic] == 'on') && is_array($config['dhcpd'])) {
+ foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf)
+ if(is_array($dhcpifconf['staticmap']) && isset($dhcpifconf['enable']))
+ foreach ($dhcpifconf['staticmap'] as $host)
+ if ($host['ipaddr'] && $host['hostname']) {
+ $zone_conf .= "{$host['hostname']}\tIN A\t{$host['ipaddr']}\n";
+ }
+ }
+ if ($zone['customzonerecords']!=""){
+ $zone_conf .= "\n\n;\n;custom zone records\n;\n".base64_decode($zone['customzonerecords'])."\n";
+ }
+ file_put_contents(CHROOT_LOCALBASE."/etc/namedb/$zonetype/$zoneview/$zonename.DB", $zone_conf);
+ $config["installedpackages"]["bindzone"]["config"][$x][resultconfig]=base64_encode($zone_conf);
+ $write_config++;
+ //check dnssec keys creation for master zones
+ if($zone['dnssec']=="on"){
+ $zone_found=0;
+ foreach (glob(CHROOT_LOCALBASE."/etc/namedb/keys/*{$zonename}*key",GLOB_NOSORT) as $filename){
+ $zone_found++;
+ }
+ if ($zone_found==0){
+ $key_restored=0;
+ if(is_array($config['installedpackages']['dnsseckeys']) && is_array($config['installedpackages']['dnsseckeys']['config'])){
+ foreach ($config['installedpackages']['dnsseckeys']['config']as $filer)
+ if (preg_match ("/K$zonename\.+/",$filer['fullfile'])){
+ file_put_contents($filer['fullfile'],base64_decode($filer['filedata']),LOCK_EX);
+ chmod($filer['fullfile'],0700);
+ chown($filer['fullfile'],"bind");
+ $key_restored++;
+ }
+ }
+ if ($key_restored > 0){
+ log_error("[bind] {$key_restored} DNSSEC keys restored from XML backup for {$zonename} zone.");
+ }
+ $dnssec_bin="/usr/local/sbin/dnssec-keygen";
+ if (file_exists($dnssec_bin) && $key_restored==0){
+ exec("{$dnssec_bin} -K ".CHROOT_LOCALBASE."/etc/namedb/keys {$zonename}",$kout);
+ exec("{$dnssec_bin} -K ".CHROOT_LOCALBASE."/etc/namedb/keys -fk {$zonename}",$kout);
+ foreach($kout as $filename){
+ chown(CHROOT_LOCALBASE."/etc/namedb/keys/{$filename}.key","bind");
+ chown(CHROOT_LOCALBASE."/etc/namedb/keys/{$filename}.private","bind");
+ }
+ log_error("[bind] DNSSEC keys for {$zonename} created.");
+ }
+ }
+ //get ds keys
+ $dsfromkey="/usr/local/sbin/dnssec-dsfromkey";
+ foreach (glob(CHROOT_LOCALBASE."/etc/namedb/keys/*{$zonename}*key",GLOB_NOSORT) as $filename) {
+ $zone_key=file_get_contents($filename);
+ if (preg_match("/IN DNSKEY 257 /",$zone_key) && file_exists($dsfromkey)){
+ exec("$dsfromkey $filename",$dsset);
+ $config["installedpackages"]["bindzone"]["config"][$x]['dsset']=base64_encode(array_pop($dsset)."\n".array_pop($dsset));
+ $write_config++;
+ }
+ }
+ //save dnssec keys to xml
+
+ if($zone['backupkeys']=="on"){
+ $dnssec_keys=0;
+ foreach (glob(CHROOT_LOCALBASE."/etc/namedb/keys/*{$zonename}*",GLOB_NOSORT) as $filename){
+ $file_found=0;
+ if(is_array($config['installedpackages']['dnsseckeys']) && is_array($config['installedpackages']['dnsseckeys']['config'])){
+ foreach ($config['installedpackages']['dnsseckeys']['config']as $filer){
+ if ($filer['fullfile']==$filename)
+ $file_found++;
+ }
+ }
+ if ($file_found==0){
+ $config['installedpackages']['dnsseckeys']['config'][]=array('fullfile'=> $filename,
+ 'description'=> "bind {$zonename} DNSSEC backup file",
+ 'filedata'=> base64_encode(file_get_contents($filename)));
+ $write_config++;
+ $dnssec_keys++;
+ }
+ }
+ if($dnssec_keys>0){
+ log_error("[bind] {$dnssec_keys} DNSSEC keys for {$zonename} zone saved on XML config.");
+ }
+ }
+ }
+ break;
+ case "slave":
+ //check/update slave dir permission
+ chown(CHROOT_LOCALBASE."/etc/namedb/$zonetype","bind");
+ chown(CHROOT_LOCALBASE."/etc/namedb/$zonetype/$zoneview","bind");
+ //check if exists slave zone file
+ $rsconfig="";
+ if ($zone['dnssec']=="on"){
+ if (file_exists(CHROOT_LOCALBASE."/etc/namedb/$zonetype/$zoneview/$zonename.DB.signed"))
+ exec("/usr/local/sbin/named-checkzone -D -f raw -o - {$zonename} ".CHROOT_LOCALBASE."/etc/namedb/$zonetype/$zoneview/$zonename.DB.signed",$slave_file);
+ }
+ else{
+ if (file_exists(CHROOT_LOCALBASE."/etc/namedb/$zonetype/$zoneview/$zonename.DB"))
+ $slave_file=file(CHROOT_LOCALBASE."/etc/namedb/$zonetype/$zoneview/$zonename.DB");
+ }
+ if (is_array($slave_file)){
+ foreach ($slave_file as $zfile)
+ $rsconfig.= $zfile;
+ $config["installedpackages"]["bindzone"]["config"][$x][resultconfig]=base64_encode($rsconfig);
+ $write_config++;
+ }
+ break;
+ }
+ }
+ }
+ if (!$custom_root_zone[$i]){
+ $bind_conf .="\tzone \".\" {\n";
+ $bind_conf .="\t\ttype hint;\n";
+ $bind_conf .="\t\tfile \"/etc/namedb/named.root\";\n";
+ $bind_conf .= "\t};\n\n";
+ }
+ if($write_config > 0){
+ write_config("save result config file for zone on xml");
+ }
+ $bind_conf .= "};\n";
+ }
+ $dirs=array("/etc/namedb/keys","/var/run/named","/var/dump","/var/log","/var/stats","/dev");
+ foreach ($dirs as $dir){
+ if (!is_dir(CHROOT_LOCALBASE .$dir))
+ mkdir(CHROOT_LOCALBASE .$dir,0755,true);
+ }
+ //dev dirs for chroot
+ $bind_dev_dir=CHROOT_LOCALBASE."/dev";
+ if (!file_exists("$bind_dev_dir/random")){
+ $dev_dirs=array("null","zero","random","urandom");
+ exec("/sbin/mount -t devfs devfs {$bind_dev_dir}",$dout);
+ exec("/sbin/devfs -m {$bind_dev_dir} ruleset 1",$dout);
+ exec("/sbin/devfs -m {$bind_dev_dir} rule add hide",$dout);
+ foreach ($dev_dirs as $dev_dir)
+ exec("/sbin/devfs -m {$bind_dev_dir} rule add path $dev_dir unhide",$dout);
+ exec("/sbin/devfs -m {$bind_dev_dir} rule applyset",$dout);
+ }
+ //http://www.unixwiz.net/techtips/bind9-chroot.html
+ file_put_contents(CHROOT_LOCALBASE.'/etc/namedb/named.conf', $bind_conf);
+ file_put_contents(CHROOT_LOCALBASE.'/etc/namedb/rndc.conf', $rndc_file);
+
+ if (!file_exists(CHROOT_LOCALBASE."/etc/namedb/named.root")){
+ //dig +tcp @a.root-servers.net > CHROOT_LOCALBASE."/etc/namedb/named.root"
+ $named_root=file_get_contents("http://www.internic.net/domain/named.root");
+ file_put_contents(CHROOT_LOCALBASE."/etc/namedb/named.root",$named_root,LOCK_EX);
+ }
+ if (!file_exists(CHROOT_LOCALBASE."/etc/localtime")){
+ copy("/etc/localtime", CHROOT_LOCALBASE."/etc/localtime");
+ }
+
+ bind_write_rcfile();
+ chown(CHROOT_LOCALBASE."/etc/namedb/keys","bind");
+ chown(CHROOT_LOCALBASE."/etc/namedb","bind");
+ chown(CHROOT_LOCALBASE."/var/log","bind");
+ chown(CHROOT_LOCALBASE."/var/run/named","bind");
+ chgrp(CHROOT_LOCALBASE."/var/log","bind");
+ $bind_sh="/usr/local/etc/rc.d/named.sh";
+ if($bind_enable == "on"){
+ chmod ($bind_sh,0755);
+ mwexec("{$bind_sh} restart");
+ }
+ elseif (is_service_running('named')){
+ mwexec("{$bind_sh} stop");
+ chmod ($bind_sh,0644);
+ }
+ //sync to backup servers
+ bind_sync_on_changes();
+ conf_mount_ro();
+}
+
+function bind_print_javascript_type_zone(){
+?>
+ <script language="JavaScript">
+ <!--
+ function on_type_zone_changed() {
+
+ var field = document.iform.type;
+ var tipo = field.options[field.selectedIndex].value;
+ switch (tipo){
+ case 'master':
+ document.iform.slaveip.disabled = 1;
+ document.iform.tll.disabled = 0;
+ document.iform.nameserver.disabled = 0;
+ document.iform.reverso.disabled = 0;
+ document.iform.forwarders.disabled = 1;
+ document.iform.dnssec.disabled = 0;
+ document.iform.backupkeys.disabled = 0;
+ document.iform.regdhcpstatic.disabled = 0;
+ document.iform.ipns.disabled = 0;
+ document.iform.mail.disabled = 0;
+ document.iform.serial.disabled = 0;
+ document.iform.refresh.disabled = 0;
+ document.iform.retry.disabled = 0;
+ document.iform.expire.disabled = 0;
+ document.iform.minimum.disabled = 0;
+ break;
+ case 'slave':
+ document.iform.slaveip.disabled = 0;
+ document.iform.tll.disabled = 1;
+ document.iform.nameserver.disabled = 1;
+ document.iform.reverso.disabled = 0;
+ document.iform.forwarders.disabled = 1;
+ document.iform.dnssec.disabled = 0;
+ document.iform.backupkeys.disabled = 0;
+ document.iform.regdhcpstatic.disabled = 0;
+ document.iform.ipns.disabled = 1;
+ document.iform.mail.disabled = 1;
+ document.iform.serial.disabled = 1;
+ document.iform.refresh.disabled = 1;
+ document.iform.retry.disabled = 1;
+ document.iform.expire.disabled = 1;
+ document.iform.minimum.disabled = 1;
+ break;
+ case 'forward':
+ document.iform.slaveip.disabled = 1;
+ document.iform.tll.disabled = 1;
+ document.iform.nameserver.disabled = 1;
+ document.iform.reverso.disabled = 1;
+ document.iform.forwarders.disabled = 0;
+ document.iform.dnssec.disabled = 1;
+ document.iform.backupkeys.disabled = 1;
+ document.iform.regdhcpstatic.disabled = 1;
+ document.iform.ipns.disabled = 1;
+ document.iform.mail.disabled = 1;
+ document.iform.serial.disabled = 1;
+ document.iform.refresh.disabled = 1;
+ document.iform.retry.disabled = 1;
+ document.iform.expire.disabled = 1;
+ document.iform.minimum.disabled = 1;
+ break;
+ case 'redirect':
+ document.iform.slaveip.disabled = 1;
+ document.iform.tll.disabled = 1;
+ document.iform.nameserver.disabled = 0;
+ document.iform.reverso.disabled = 1;
+ document.iform.forwarders.disabled = 1;
+ document.iform.dnssec.disabled = 1;
+ document.iform.backupkeys.disabled = 1;
+ document.iform.regdhcpstatic.disabled = 1;
+ document.iform.ipns.disabled = 1;
+ document.iform.mail.disabled = 0;
+ document.iform.serial.disabled = 0;
+ document.iform.refresh.disabled = 0;
+ document.iform.retry.disabled = 0;
+ document.iform.expire.disabled = 0;
+ document.iform.minimum.disabled = 0;
+ break;
+ }
+ }
+ -->
+ </script>
+<?php
+}
+
+function bind_print_javascript_type_zone2(){
+ print("<script language=\"JavaScript\">on_type_zone_changed();document.iform.resultconfig.disabled = 1;document.iform.dsset.disabled = 1;</script>\n");
+}
+
+function bind_write_rcfile() {
+ $rc = array();
+ $BIND_LOCALBASE = "/usr/local";
+ $rc['file'] = 'named.sh';
+ $rc['start'] = <<<EOD
+if [ -z "`ps auxw | grep "[n]amed -c /etc/namedb/named.conf"|awk '{print $2}'`" ];then
+ {$BIND_LOCALBASE}/sbin/named -c /etc/namedb/named.conf -u bind -t /cf/named/
+fi
+
+EOD;
+ $rc['stop'] = <<<EOD
+killall -9 named 2>/dev/null
+sleep 2
+EOD;
+ $rc['restart'] = <<<EOD
+if [ -z "`ps auxw | grep "[n]amed -c /etc/namedb/named.conf"|awk '{print $2}'`" ];then
+ {$BIND_LOCALBASE}/sbin/named -c /etc/namedb/named.conf -u bind -t /cf/named/
+ else
+ killall -9 named 2>/dev/null
+ sleep 3
+ {$BIND_LOCALBASE}/sbin/named -c /etc/namedb/named.conf -u bind -t /cf/named/
+ fi
+
+EOD;
+ conf_mount_rw();
+ write_rcfile($rc);
+ conf_mount_ro();
+}
+
+/* Uses XMLRPC to synchronize the changes to a remote node */
+function bind_sync_on_changes() {
+ global $config, $g;
+ if (is_array($config['installedpackages']['bindsync']['config'])){
+ $bind_sync=$config['installedpackages']['bindsync']['config'][0];
+ $synconchanges = $bind_sync['synconchanges'];
+ $synctimeout = $bind_sync['synctimeout'];
+ $master_zone_ip=$bind_sync['masterip'];
+ switch ($synconchanges){
+ case "manual":
+ if (is_array($bind_sync[row])){
+ $rs=$bind_sync[row];
+ }
+ else{
+ log_error("[bind] xmlrpc sync is enabled but there is no hosts to push on bind config.");
+ return;
+ }
+ break;
+ case "auto":
+ if (is_array($config['hasync'])){
+ $hasync=$config['hasync'][0];
+ $rs[0]['ipaddress']=$hasync['synchronizetoip'];
+ $rs[0]['username']=$hasync['username'];
+ $rs[0]['password']=$hasync['password'];
+ }
+ else{
+ log_error("[bind] xmlrpc sync is enabled but there is no system backup hosts to push bind config.");
+ return;
+ }
+ break;
+ default:
+ return;
+ break;
+ }
+ if (is_array($rs)){
+ log_error("[bind] xmlrpc sync is starting.");
+ foreach($rs as $sh){
+ $sync_to_ip = $sh['ipaddress'];
+ $password = $sh['password'];
+ if($sh['username'])
+ $username = $sh['username'];
+ else
+ $username = 'admin';
+ if($password && $sync_to_ip)
+ bind_do_xmlrpc_sync($sync_to_ip, $username, $password,$synctimeout,$master_zone_ip);
+ }
+ log_error("[bind] xmlrpc sync is ending.");
+ }
+ }
+}
+/* Do the actual XMLRPC sync */
+function bind_do_xmlrpc_sync($sync_to_ip, $username, $password, $synctimeout,$master_zone_ip) {
+ global $config, $g;
+
+ if(!$username)
+ return;
+
+ if(!$password)
+ return;
+
+ if(!$sync_to_ip)
+ return;
+
+ if(!$synctimeout)
+ $synctimeout=25;
+
+
+ $xmlrpc_sync_neighbor = $sync_to_ip;
+ if($config['system']['webgui']['protocol'] != "") {
+ $synchronizetoip = $config['system']['webgui']['protocol'];
+ $synchronizetoip .= "://";
+ }
+ $port = $config['system']['webgui']['port'];
+ /* if port is empty lets rely on the protocol selection */
+ if($port == "") {
+ if($config['system']['webgui']['protocol'] == "http")
+ $port = "80";
+ else
+ $port = "443";
+ }
+ $synchronizetoip .= $sync_to_ip;
+
+ /* xml will hold the sections to sync */
+ $xml = array();
+ $xml['bind'] = $config['installedpackages']['bind'];
+ $xml['bindacls'] = $config['installedpackages']['bindacls'];
+ $xml['bindviews'] = $config['installedpackages']['bindviews'];
+ $xml['bindzone'] = $config['installedpackages']['bindzone'];
+ if (is_array($config['installedpackages']['dnsseckeys']))
+ $xml['dnsseckeys']=$config['installedpackages']['dnsseckeys'];
+ //change master zone to slave on backup servers
+ if(is_array($xml['bindzone']["config"]))
+ for ($x=0; $x<sizeof($xml['bindzone']["config"]); $x++){
+ if ($xml['bindzone']["config"][$x]['type']=="master"){
+ $xml['bindzone']["config"][$x]['type']="slave";
+ $xml['bindzone']["config"][$x]['slaveip']=$master_zone_ip;
+ }
+
+ }
+ /* assemble xmlrpc payload */
+ $params = array(
+ XML_RPC_encode($password),
+ XML_RPC_encode($xml)
+ );
+
+ /* set a few variables needed for sync code borrowed from filter.inc */
+ $url = $synchronizetoip;
+ log_error("[bind] Beginning bind XMLRPC sync to {$url}:{$port}.");
+ $method = 'pfsense.merge_installedpackages_section_xmlrpc';
+ $msg = new XML_RPC_Message($method, $params);
+ $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
+ $cli->setCredentials($username, $password);
+ if($g['debug'])
+ $cli->setDebug(1);
+ /* send our XMLRPC message and timeout after defined sync timeout value*/
+ $resp = $cli->send($msg, $synctimeout);
+ if(!$resp) {
+ $error = "A communications error occurred while attempting bind XMLRPC sync with {$url}:{$port}.";
+ log_error($error);
+ file_notice("sync_settings", $error, "bind Settings Sync", "");
+ } elseif($resp->faultCode()) {
+ $cli->setDebug(1);
+ $resp = $cli->send($msg, $synctimeout);
+ $error = "An error code was received while attempting bind XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
+ log_error($error);
+ file_notice("sync_settings", $error, "bind Settings Sync", "");
+ } else {
+ log_error("[bind] XMLRPC sync successfully completed with {$url}:{$port}.");
+ }
+
+ /* tell bind to reload our settings on the destination sync host. */
+ $method = 'pfsense.exec_php';
+ $execcmd = "require_once('/usr/local/pkg/bind.inc');\n";
+ $execcmd .= "bind_sync('yes');";
+ /* assemble xmlrpc payload */
+ $params = array(
+ XML_RPC_encode($password),
+ XML_RPC_encode($execcmd)
+ );
+
+ log_error("[bind] XMLRPC reload data {$url}:{$port}.");
+ $msg = new XML_RPC_Message($method, $params);
+ $cli = new XML_RPC_Client('/xmlrpc.php', $url, $port);
+ $cli->setCredentials($username, $password);
+ $resp = $cli->send($msg, $synctimeout);
+ if(!$resp) {
+ $error = "A communications error occurred while attempting bind XMLRPC sync with {$url}:{$port} (pfsense.exec_php).";
+ log_error($error);
+ file_notice("sync_settings", $error, "Bind Settings Sync", "");
+ } elseif($resp->faultCode()) {
+ $cli->setDebug(1);
+ $resp = $cli->send($msg, $synctimeout);
+ $error = "[Bind] An error code was received while attempting bind XMLRPC sync with {$url}:{$port} - Code " . $resp->faultCode() . ": " . $resp->faultString();
+ log_error($error);
+ file_notice("sync_settings", $error, "bind Settings Sync", "");
+ } else {
+ log_error("Bind XMLRPC reload data success with {$url}:{$port} (pfsense.exec_php).");
+ }
+
+}
+?>