"aRecord", 'mDRecord' => "mDRecord", 'mXRecord' => "mXRecord", 'nSRecord' => "nSRecord", 'pTRRecord' => "relativeDomainName", 'hInfoRecord' => "hInfoRecord", 'mInfoRecord' => "mInfoRecord", 'cNAMERecord' => "relativeDomainName", 'tXTRecord' => "tXTRecord", 'aFSDBRecord' => "aFSDBRecord", 'SigRecord' => "SigRecord", 'KeyRecord' => "KeyRecord", 'aAAARecord' => "aAAARecord", 'LocRecord' => "LocRecord", 'nXTRecord' => "nXTRecord", 'sRVRecord' => "sRVRecord", 'nAPTRRecord' => "nAPTRRecord", 'kXRecord' => "kXRecord", 'certRecord' => "certRecord", 'a6Record' => "a6Record", 'dSRecord' => "dSRecord", 'sSHFPRecord' => "sSHFPRecord", 'rRSIGRecord' => "rRSIGRecord", 'nSECRecord' => "nSECRecord"); /* All available record types */ /* Return all record types */ static function getDnsRecordTypes($ForZones = false) { if($ForZones){ $tmp = DNS::$RecordTypes; unset($tmp['cNAMERecord']); unset($tmp['pTRRecord']); unset($tmp['tXTRecord']); return($tmp); }else{ return(DNS::$RecordTypes); } } /* This fucntion is used to flip the ip address, for example 12.3.45 -> 45.3.12 Because some entries (like zones) are store like that 45.3.12.in-addr.arpa but we want to display 12.3.45. */ static function FlipIp($ip) { $tmp = array_reverse(split("\.",$ip)); $new = ""; foreach($tmp as $section){ $new .= $section."."; } return(preg_replace("/.$/","",$new)); } /* This static function returns the zones specified for given host */ static function getDNSZoneEntries($config,$HostDn,$silent = false) { $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); /* Not all records are allowed within a zone entry */ $SkipRecords = array("tXTRecord","cNAMERecord","pTRRecord"); /* Special sOArecords */ $sOAREcords = array("0"=>"sOAprimary","1"=>"sOAmail","2"=>"sOAserial","3"=>"sOArefresh","4"=>"sOAretry","5"=>"sOAexpire","6"=>"sOAttl"); /* Create tempalte for all fetched zone Data */ $ZoneBase = array(); $ZoneBase['exists'] = false; $ZoneBase['RECORDS'] = array(); $ZoneBase['zoneName'] = array(); $ZoneBase['dNSClass'] = array(); foreach($sOAREcords as $attr){ $ZoneBase[$attr] = ""; } $Zones = array(); /* Get & Parse all zone entries */ $ldap->ls("(&(objectClass=dNSZone)(zoneName=*)(relativeDomainName=@))",$HostDn,array("*")); $tmp_res = array(); while($attrs = $ldap->fetch()) { $tmp_res[] = $attrs; } /* Parse fetched zones */ foreach($tmp_res as $attrs){ $zoneName = $attrs['zoneName'][0]; $Zones[$zoneName] = $ZoneBase; $Zones[$zoneName]['exists'] = true; /* Set basic attributes */ foreach(array("zoneName","dNSClass") as $attr){ if(isset($attrs[$attr][0])){ $Zones[$zoneName][$attr] = $attrs[$attr][0]; } } /* Set initial zone name, to be able to detect if this entry was renamed */ $Zones[$zoneName]['InitialzoneName'] = $zoneName; /* Generate SOA entry */ if(isset($attrs['sOARecord'][0])){ $tmp = split("\ ",$attrs['sOARecord'][0]) ; $tmp2 = array(); /* Assign soa vars */ foreach($sOAREcords as $key => $name){ if(isset($tmp[$key])){ $Zones[$zoneName][$name] = $tmp[$key]; }else{ $Zones[$zoneName][$name] = ""; } } } // ENDE SOA Record /* Get record attributes */ foreach(DNS::$RecordTypes as $name => $value){ /* Skip some attributes */ if(in_array($name,$SkipRecords)) continue; /* If there is a record attribute */ if(isset($attrs[$name])){ /* get all entries */ for($i = 0 ; $i < $attrs[$value]['count']; $i ++){ $Zones[$zoneName]['RECORDS'][] = array("type"=>$name,"value"=>$attrs[$value][$i]); } } } /* Get reverse record .. */ $ldap->ls("(&(objectClass=dNSZone)(relativeDomainName=@)(zoneName=*))",$attrs['dn'],array("zoneName")); if($ldap->count() == 0){ if(!$silent){ msg_dialog::display(_("Error"), sprintf(_("Cannot find reverse zone for DNS zone '%s'. Parsing zone aborted."),$zoneName), ERROR_DIALOG); } unset($Zones[$zoneName]); }elseif($ldap->count()>1){ if(!$silent){ msg_dialog::display(_("Error"), sprintf(_("Found more than one reverse zone for '%s'. Parsing zone aborted."),$zoneName), ERROR_DIALOG); } unset($Zones[$zoneName]); }else{ $tmp = $ldap->fetch(); $Zones[$zoneName]['ReverseZone'] = DNS::FlipIp(str_replace(".in-addr.arpa","",$tmp['zoneName'][0])); $Zones[$zoneName]['InitialReverseZone'] = DNS::FlipIp(str_replace(".in-addr.arpa","",$tmp['zoneName'][0])); } } return($Zones); } /* This static function compares two dns zone objects and returns an * array with following indexes * - delete, for dns which must be deleted (only if dns zone is removed) * - rename, if a dn must be renamed, for example, the zoneName has changed * - add, if there is a new dns account created */ static function getDNSZoneEntriesDiff($config,$newZones,$HostDn) { $oldZones = DNS::getDNSZoneEntries($config,$HostDn,true); $sOAattributes = array("sOAprimary","sOAmail","sOAserial","sOArefresh","sOAretry","sOAexpire","sOAttl"); $move = array(); $add = array(); $del = array(); /* Generate a template for zones with default values */ $zoneBase = array(); $zoneBase['objectClass'] = array("top","dNSZone"); $zoneBase['zoneName'] = ""; $zoneBase['relativeDomainName'] = "@"; $zoneBase['dNSClass'] = "IN"; $zoneBase['sOARecord'] = ""; /* Contains all renamed zoneNames * For zone entry udpdates */ $PrePareZoneEntries = array(); /* Walk through all zones and detect renamed/added/deleted zones ... */ foreach($newZones as $name => $zone){ /* This zone was renamed */ if((!empty($zone['InitialzoneName'])) && ($zone['InitialzoneName'] != $zone['zoneName'])){ /* Move old zone to new position */ $oldDn = "zoneName=".$zone['InitialzoneName'].",".$HostDn; $newDn = "zoneName=".$zone['zoneName'].",".$HostDn; $PrePareZoneEntries[$zone['InitialzoneName']] = $zone['zoneName']; $move [$oldDn] = $newDn; } /* Get old zone if available */ $oldZone=array(); if(!empty($oldZones[$zone['InitialzoneName']])){ $oldZone = $oldZones[$zone['InitialzoneName']]; } /* Create forward zone entry and put it in our add queue */ $newDn = "zoneName=".$zone['zoneName'].",".$HostDn; $obj = $zoneBase; $obj['zoneName'] = $zone['zoneName']; /* Create sOARecord & add it to the obj */ $soa = ""; foreach($sOAattributes as $attr){ $soa.=" ".$zone[$attr]; } $obj['sOARecord'] = trim($soa); $obj['nSRecord'] = $zone['sOAprimary']; /* If reverse zone was renamed, move entry */ if(!empty($zone['InitialReverseZone'])){ if($zone['InitialReverseZone'] != $zone['ReverseZone']){ $base = "zoneName=".$zone['zoneName'].",".$HostDn; $oldRDn = "zoneName=". DNS::FlipIp($zone['InitialReverseZone']).".in-addr.arpa,".$base; $newRDn = "zoneName=". DNS::FlipIp($zone['ReverseZone']).".in-addr.arpa,".$base; $PrePareZoneEntries[DNS::FlipIp($zone['InitialReverseZone']).".in-addr.arpa"] = DNS::FlipIp($zone['ReverseZone']).".in-addr.arpa"; $move [$oldRDn] = $newRDn; } } /* Append record entries * Set old value to array, to ensure that * they will be deleted if necessary */ if(isset($oldZone['RECORDS'])){ foreach($oldZone['RECORDS'] as $rec){ $obj[$rec['type']] = array(); } } /* Add new Records */ foreach($zone['RECORDS'] as $rec){ if(!isset($obj[$rec['type']])||!is_array($obj[$rec['type']])){ $obj[$rec['type']] = array(); } $obj[$rec['type']][] = $rec['value']; } /* Append udpated Zone Forward Entry to our add queue */ $add[$newDn] = $obj; /* Create Reverse Entry * And append it to our add queue */ $zone['ReverseZone'] = DNS::FlipIp($zone['ReverseZone']).".in-addr.arpa"; $base = "zoneName=".$zone['zoneName'].",".$HostDn; $newRDn = "zoneName=".$zone['ReverseZone'].",".$base; $rObj = $obj; $rObj['zoneName']= $zone['ReverseZone']; $add[$newRDn] = $rObj; /* Remove currently managed zone from oldZones. * this gives us the ability to detect removed zones */ if(isset($oldZones[$zone['InitialzoneName']])){ unset($oldZones[$zone['InitialzoneName']]); } } /* The rest of our oldZones must be deleted * because they are no longer available in newZones anymore. */ foreach($oldZones as $zone) { $oldDn = "zoneName=".$zone['InitialzoneName'].",".$HostDn; $del[$oldDn] = $zone; } /* Check for entries which must be updated */ $zoneUpdates = array(); $udpate = array(); if(count($PrePareZoneEntries)){ $ldap = $config->get_ldap_link(); foreach($PrePareZoneEntries as $FromZoneName => $ToZoneName){ $ldap->cd($HostDn); $ldap->search("(&(objectClass=dNSZone)(zoneName=".$FromZoneName.")(!(relativeDomainName=@)))",array("zoneName")); while($attrs = $ldap->fetch()){ $zoneUpdates[$attrs['dn']] = array("zoneName"=>$ToZoneName); } } } $ret = array("del" => $del , "move" => $move , "add" => $add,"zoneUpdates"=>$zoneUpdates); return($ret); } /* This static function returns the dns-host eintries for given * name. */ static function getDNSHostEntries($config,$name,$silent = false) { $types = array(); $ret = array(); $ret['RECORDS'] = array(); $ret['dNSClass'] = "IN"; $ret['zoneName'] = ""; $ret['dNSTTL'] = "7440"; $ret['exists'] = false; $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); /* First check all zones for an entry with the given name. * If the name occurs in more than one entry alert the user ... */ $foundIn = array(); $zones = DNS::getAvailableZones($config); $zonesArr = array(); foreach($zones as $zoneMix){ $zoneIndex = split("/",$zoneMix); if(!array_key_exists($zoneIndex[0],$zonesArr)) { $zonesArr[$zoneIndex[0]] = array(); } array_push($zonesArr[$zoneIndex[0]],$zoneIndex[1]); } foreach($zonesArr as $nameServer => $nameServerArr){ $foundInTmp = array(); foreach($nameServerArr as $zoneArr => $zone){ /* Strip eventually domain part from hostname */ $zN = trim($zone,"."); $nN = trim($name,"."); if(preg_match("/".normalizePreg($zN)."$/",$nN)){ $nN = preg_replace("/[\.]*".normalizePreg($zN)."[\.]*$/","",$nN); }else{ $nN = $name; } $zoneMix = $nameServer."/".$zone; $zoneDn = DNS::getDNSZoneDN($config,$zoneMix); $ldap->ls("(&(objectClass=dNSZone)(zoneName=*)(relativeDomainName=".$nN.")(!(relativeDomainName=@)))", $zoneDn,$attrs = array("*")); while($attrs = $ldap->fetch()){ $foundInTmp [$zoneMix] = $attrs['dn']; $foundIn [$zoneMix] = $attrs['dn']; } } } /* No zone found which contains an entry for us */ if(count($foundIn) == 0){ return($ret); } /* Get host informations from zone */ $id_tmp = key($foundIn); $ldap->cd($foundIn[$id_tmp]); $ldap->search("(&(objectClass=dNSZone)(zoneName=*)(!(relativeDomainName=@)))",array("*")); while($attrs = $ldap->fetch()){ /* Strip eventually domain part from hostname */ $zN = trim($attrs['zoneName'][0],"."); $nN = trim($name,"."); $testname = $attrs['relativeDomainName'][0].".".$zN; /* Check given host name with zone settings */ if(preg_match("/".normalizePreg($testname)."[\.]*$/",$nN)){ $ret['exists'] = true; $ret['zoneName'] = $id_tmp; foreach(array("dNSClass","dNSTTL") as $atr){ if(isset($attrs[$atr][0])){ $ret[$atr] = $attrs[$atr][0]; } } } /* Create list with all used records */ foreach(DNS::$RecordTypes as $name => $value){ /* If there is a record attribute */ if(isset($attrs[$name])){ /* get all entries */ for($i = 0 ; $i < $attrs[$value]['count']; $i ++){ $types[] = array( "type" => $name, "value" => $attrs[$value][$i]); } } } $ret['RECORDS'] = $types; } return($ret); } /* This static function compares two dns settings and returns an * array with following indexes * - delete, for dns which must be deleted (only if dns account is removed) * - rename, if a dn must be renamed, for example, the relativeDomainName has changed * - add, if there is a new dns account created */ static function getDNSHostEntriesDiff($config,$oldName,$newEntry,$newName) { $oldEntry = DNS::getDNSHostEntries($config,$oldName); $add = array(); $del = array(); $move = array(); /* Don't go further if there is nothing to do * Is no account / was no account */ if(($newEntry['exists'] == false )&& ($oldEntry['exists'] == false)){ return(array("move"=>$move,"add"=>$add,"del"=>$del)); } $zones = DNS::getAvailableZones($config); $specialAttributes = array("cNAMERecord","pTRRecord"); $newRecords = array(); // Used to remember which records are removed $zoneNameMix = $newEntry['zoneName']; $zoneDn = DNS::getDNSZoneDN($config,$zoneNameMix); $tmp = array_flip($zones); $zoneName = DNS::getNameFromMix($zoneNameMix); /* Strip domain part out of dns host entry */ $zN = trim($zoneName,"."); $nN = trim($newName,"."); $oN = trim($oldName,"."); $newName = preg_replace("/[\.]*".normalizePreg($zN)."$/i","",$nN); $oldName = preg_replace("/[\.]*".normalizePreg($zN)."$/i","",$oN); /* If reverseZone can't be resolved ... this * can't be a valid entry, so remove this account */ if(isset($tmp[$zoneNameMix])){ $reverseNameMix = $tmp[$zoneNameMix]; $reverseDn = DNS::getDNSZoneDN($config,$reverseNameMix); if(empty($reverseDn)){ $newEntry['exists'] = false; } }else{ $newEntry['exists'] = false; } /* If account was edited prepare some * attributes & arrays ... if required add some * dns to $move */ if($oldEntry['exists']){ /* Check if the account was removed */ if($newEntry['exists'] == false){ $dn = "relativeDomainName=".$oldName.",".DNS::getDNSZoneDN($config,$oldEntry['zoneName']); $del[$dn] =""; return(array("move"=>$move,"add"=>$add,"del"=>$del)); } /* Check if zoneName has changed */ if(count($newEntry['RECORDS'])){ if($oldEntry['zoneName'] != $newEntry['zoneName']){ $oldzoneDn = DNS::getDNSZoneDN($config,$oldEntry['zoneName']); $dn = "relativeDomainName=".$oldName.",".$oldzoneDn; $dn2= "relativeDomainName=".$oldName.",".$zoneDn; $move[$dn]=$dn2; } /* Check if host name has changed */ if($oldName != $newName){ $dn = "relativeDomainName=".$oldName.",".$zoneDn; $dn2= "relativeDomainName=".$newName.",".$zoneDn; $move[$dn]=$dn2; $dn = "relativeDomainName=".$oldName.",".$dn2; $dn2= "relativeDomainName=".$newName.",".$dn2; $move[$dn]=$dn2; } } /* Prepare record entries * Fill old records with array(); * To ensure that they will be deleted if they stay unused */ foreach($oldEntry['RECORDS'] as $id => $rec){ $newRecords[$rec['type']] = array(); } } /* There must be at least one record in our entry */ if((!count($newEntry['RECORDS'])) || (!$newEntry['exists'])){ $dn = "relativeDomainName=".$newName.",".DNS::getDNSZoneDN($config,$oldEntry['zoneName']); $del[$dn] =""; $ret = array("move"=>$move,"add"=>$add,"del"=>$del); return($ret); } /* Prepare temp obj */ $baseObj = array(); $baseObj['objectClass'] = array("top","dNSZone"); $baseObj['dNSTTL'] = $newEntry['dNSTTL']; $baseObj['dNSClass'] = $newEntry['dNSClass']; $baseObj['zoneName'] = $zoneName; $baseObj['relativeDomainName']= $newName; /* Add Container Object to zone * (this possibly already exists, check this before writing to ldap) */ $baseDn = "relativeDomainName=".$newName.",".$zoneDn; $add[$baseDn] = $baseObj; /* Add base obejct which contains all std records */ $stdDn = "relativeDomainName=".$newName.",".$baseDn; $add[$stdDn] = $baseObj; /* Set defaults. Normaly only contains old record names. * The old names will be set to array, to ensure that they will be deleted. * Or overwritten and filled with new values. */ foreach($newRecords as $name => $def){ if(!in_array($name,$specialAttributes)){ $add[$stdDn][$name] = $def; } } /* Delete all OLD special attributes. */ foreach($oldEntry['RECORDS'] as $id => $rec){ if(in_array($rec['type'],$specialAttributes)){ $deldn= "relativeDomainName=".$rec['value'].",".$baseDn; $del[$deldn] = ""; } } /* Create new record entries */ foreach($newEntry['RECORDS'] as $id => $rec){ /* Create object which contains special records * like pTRRecord or CNAMERecord */ if($rec['type'] == "pTRRecord"){ $PTRdn= "relativeDomainName=".DNS::FlipIP($rec['value']).",".$baseDn; $ptrObj = $baseObj; $reverseName = DNS::getNameFromMix($reverseNameMix); $ptrObj['zoneName'] = $reverseName; if(!preg_match("/\.$/",$newName)){ $ptrObj['pTRRecord'] = preg_replace("/\.\.$/",".",$newName.".".$zoneName."."); }else{ $ptrObj['pTRRecord'] = preg_replace("/\.\.$/",".",$newName."."); } $ptrObj['relativeDomainName'] = DNS::FlipIP($rec['value']); $add[$PTRdn] = $ptrObj; }else if($rec['type'] == "cNAMERecord"){ $PTRdn= "relativeDomainName=".$rec['value'].",".$baseDn; $ptrObj = $baseObj; $ptrObj['zoneName'] = $zoneName; $ptrObj['cNAMERecord'] = $newName; $ptrObj['relativeDomainName'] = $rec['value']; $add[$PTRdn] = $ptrObj; }else{ /* Append basic attributes */ $add[$stdDn][$rec['type']][] = $rec['value']; } } // foreach record $ret = array("move"=>$move,"add"=>$add,"del"=>$del); return($ret); } static function getNameFromMix($zoneMix){ $ret = ""; if(!strstr($zoneMix, '/')) return($ret); $zoneIndex = split("/",$zoneMix); return($zoneIndex[1]); } /* returns the dn for a specified zone */ static function getDNSZoneDN($config,$zoneNameMix) { $ret = ""; if(!strstr($zoneNameMix, '/')) { msg_dialog::display(_("Error"), sprintf(_("Undefined zone name '%s'!"),$zoneNameMix), ERROR_DIALOG); return($ret); } $zoneNameIndex = split("/",$zoneNameMix); $zoneName = $zoneNameIndex[1]; $nameServer = strtolower($zoneNameIndex[0]); $ldap = $config->get_ldap_link(); /* search for the nameserver */ $ldap-> cd($config->current['BASE']); $ldap->search("(&(objectClass=goServer)(cn=".$nameServer."))",array("cn")); if($ldap->count()){ $attr = $ldap->fetch(); } else { return($ret); } $ldap-> cd($attr['dn']); $ldap->search("(&(objectClass=dNSZone)(sOARecord=*)(zoneName=".$zoneName."))",array("zoneName")); if($ldap->count()){ $attr = $ldap->fetch(); return($attr['dn']); } return($ret); } /* returns all available zones * array[reverseName] = zoneName; */ static function getAvailableZones($config) { $ReverseZones = $ForwardZones = $zones = array(); $runtime_cache = session::get("runtime_cache"); if(!isset($runtime_cache['DNS']['getAvailableZones'])){ $ret = array(); $ldap = $config->get_ldap_link(); $tmp = get_sub_list("(&(objectClass=dNSZone)(sOARecord=*))","",get_ou("serverou"), $config->current['BASE'],array("zoneName"),GL_NO_ACL_CHECK | GL_SUBSEARCH); foreach($tmp as $at){ if(preg_match("/\.in\-addr\.arpa/",$at['zoneName'][0])){ $ReverseZones[$at['dn']] = $at; }else{ $ForwardZones[$at['dn']] = $at; } } foreach($ForwardZones as $dn => $obj){ /* try to find reverse */ foreach($ReverseZones as $Rdn => $Robj ){ if(preg_match("/".$dn."/",$Rdn)){ $zones[strtoupper($ldap->getCn($dn))."/".$Robj['zoneName'][0]] = strtoupper($ldap->getCn($dn))."/".$obj['zoneName'][0]; } } } $runtime_cache['DNS']['getAvailableZones'] = $zones; session::set("runtime_cache",$runtime_cache); } return($runtime_cache['DNS']['getAvailableZones']); } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?>