X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=include%2Ffunctions_dns.inc;h=e1cda20a0af871f8972d184bdf70ac72d122c6ce;hb=6c914a3f00e289e5ec1de619390ce21b9f87fa4d;hp=98c72eeeee7bea7483887c53768cd78b071bf08a;hpb=f1b2916637a2ac8ca28d68fa93531f429a310eba;p=gosa.git diff --git a/include/functions_dns.inc b/include/functions_dns.inc index 98c72eeee..e1cda20a0 100644 --- a/include/functions_dns.inc +++ b/include/functions_dns.inc @@ -29,17 +29,314 @@ $RecordTypes['rRSIGRecord'] = "rRSIGRecord"; $RecordTypes['nSECRecord'] = "nSECRecord"; -function getDnsRecordTypes() +/* Return all record types + */ +function getDnsRecordTypes($ForZones = false) +{ + global $RecordTypes; + if($ForZones){ + $tmp = $RecordTypes; + unset($tmp['cNAMERecord']); + unset($tmp['pTRRecord']); + unset($tmp['tXTRecord']); + return($tmp); + }else{ + return($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. + */ +function FlipIp($ip) +{ + $tmp = array_reverse(split("\.",$ip)); + $new = ""; + foreach($tmp as $section){ + $new .= $section."."; + } + return(preg_replace("/.$/","",$new)); +} + + +/* This function returns the zones specified for given host + */ +function getDNSZoneEntries($config,$HostDn,$silent = false) { global $RecordTypes; - return($RecordTypes); + + $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"); + + /* Get host entry */ + $ldap->cat($HostDn); + $host_attr = $ldap->fetch(); + + /* 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 = strtoupper($host_attr['cn'][0])."/".$attrs['zoneName'][0]; + $Zones[$zoneName] = $ZoneBase; + $Zones[$zoneName]['exists'] = true; + + /* Set basic attributes + */ + if(isset($attrs["dNSClass"][0])){ + $Zones[$zoneName]["dNSClass"] = $attrs["dNSClass"][0]; + } + + /* Set initial zone name, to be able to detect if this entry was renamed + */ + $Zones[$zoneName]['InitialzoneName'] = $zoneName; + $Zones[$zoneName]['zoneName'] = $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($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){ + print_red(sprintf(_("Can't find reverse zone for dns zone '%s'. Aborting parsing this zone."),$zoneName)); + } + unset($Zones[$zoneName]); + }elseif($ldap->count()>1){ + if(!$silent){ + print_red(sprintf(_("Found more than one reverse zone for dns zone '%s'. Aborting parsing this zone."),$zoneName)); + } + unset($Zones[$zoneName]); + }else{ + $tmp = $ldap->fetch(); + $Zones[$zoneName]['ReverseZone'] = strtoupper($host_attr['cn'][0])."/".FlipIp(str_replace(".in-addr.arpa","",$tmp['zoneName'][0])); + $Zones[$zoneName]['InitialReverseZone'] = strtoupper($host_attr['cn'][0])."/".FlipIp(str_replace(".in-addr.arpa","",$tmp['zoneName'][0])); + } + } + return($Zones); +} + + +/* This 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 + */ +function getDNSZoneEntriesDiff($config,$newZones,$HostDn) +{ + $oldZones = 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=".getNameFromMix($zone['InitialzoneName']).",".$HostDn; + $newDn = "zoneName=".getNameFromMix($zone['zoneName']).",".$HostDn; + $PrePareZoneEntries[$zone['InitialzoneName']] = getNameFromMix($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=".getNameFromMix($zone['zoneName']).",".$HostDn; + $obj = $zoneBase; + $obj['zoneName'] = getNameFromMix($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=".getNameFromMix($zone['zoneName']).",".$HostDn; + $oldRDn = "zoneName=". FlipIp(getNameFromMix($zone['InitialReverseZone'])).".in-addr.arpa,".$base; + $newRDn = "zoneName=". FlipIp(getNameFromMix($zone['ReverseZone'])).".in-addr.arpa,".$base; + $PrePareZoneEntries[FlipIp($zone['InitialReverseZone']).".in-addr.arpa"] = 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'] = FlipIp(getNameFromMix($zone['ReverseZone'])).".in-addr.arpa"; + $base = "zoneName=".getNameFromMix($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=".getNameFromMix($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=".getNameFromMix($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 function returns (if exists) the dns-host eintries for given +/* This function returns the dns-host eintries for given * name. */ -function getDNSHostEntries($config,$name) +function getDNSHostEntries($config,$name,$silent = false) { global $RecordTypes; @@ -59,18 +356,27 @@ function getDNSHostEntries($config,$name) */ $foundIn = array(); $zones = getAvailableZones($config); - foreach($zones as $zone){ - $zoneDn = getDNSZoneDN($config,$zone); - $ldap->ls("(&(objectClass=dNSZone)(zoneName=*)(relativeDomainName=".$name.")(!(relativeDomainName=@)))", $zoneDn,$attrs = array("*")); - while($attrs = $ldap->fetch()){ - $foundIn [] = $attrs['dn']; + + $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]); } - - /* Alert if there is more than one zone with an entry named like $name - */ - if(count($foundIn) > 1) { - print_red(sprintf(_("Found more than one dns zone which contains an entry named '%s'. Aborting getting dns informations for this device."),$name)); + + foreach($zonesArr as $nameServer => $nameServerArr){ + $foundInTmp = array(); + foreach($nameServerArr as $zoneArr => $zone){ + $zoneMix = $nameServer."/".$zone; + $zoneDn = getDNSZoneDN($config,$zoneMix); + $ldap->ls("(&(objectClass=dNSZone)(zoneName=*)(relativeDomainName=".$name.")(!(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 @@ -81,7 +387,8 @@ function getDNSHostEntries($config,$name) /* Get host informations from zone */ - $ldap->cd($foundIn[0]); + $id_tmp = key($foundIn); + $ldap->cd($foundIn[$id_tmp]); $ldap->search("(&(objectClass=dNSZone)(zoneName=*)(!(relativeDomainName=@)))",array("*")); while($attrs = $ldap->fetch()){ @@ -90,7 +397,8 @@ function getDNSHostEntries($config,$name) */ if($attrs['relativeDomainName'][0] == $name){ $ret['exists'] = true; - foreach(array("dNSClass","zoneName","dNSTTL") as $atr){ + $ret['zoneName'] = $id_tmp; + foreach(array("dNSClass","dNSTTL") as $atr){ if(isset($attrs[$atr][0])){ $ret[$atr] = $attrs[$atr][0]; } @@ -116,10 +424,11 @@ function getDNSHostEntries($config,$name) } + /* This 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 zoneName has changed + * - rename, if a dn must be renamed, for example, the relativeDomainName has changed * - add, if there is a new dns account created */ function getDNSHostEntriesDiff($config,$oldName,$newEntry,$newName) @@ -133,24 +442,38 @@ function getDNSHostEntriesDiff($config,$oldName,$newEntry,$newName) $move = array(); $zones = getAvailableZones($config); - $specialAttributes = array("cNAMERecord","pTRRecord"); - $newRecords = array(); // Used to remember which records are removed + $zoneNameMix = $newEntry['zoneName']; + $zoneDn = getDNSZoneDN($config,$zoneNameMix); + $tmp = array_flip($zones); + $zoneName = getNameFromMix($zoneNameMix); + + /* 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 = getDNSZoneDN($config,$reverseNameMix); + if(empty($reverseDn)){ + $newEntry['exists'] = false; + } + }else{ + $newEntry['exists'] = false; + } - $zoneName = $newEntry['zoneName']; - $tmp = array_flip($zones); - $reverseName = $tmp[$zoneName]; - - $zoneDn = getDNSZoneDN($config,$zoneName); - $reverseDn = getDNSZoneDN($config,$reverseName); - - + /* 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)); + } + /* If account was edited prepare some * attributes & arrays ... if required add some * dns to $move */ - if(($oldEntry['exists'])){ + if($oldEntry['exists']){ /* Check if the account was removed */ @@ -162,26 +485,30 @@ function getDNSHostEntriesDiff($config,$oldName,$newEntry,$newName) /* Check if zoneName has changed */ - if($oldEntry['zoneName'] != $newEntry['zoneName']){ - $oldzoneDn = getDNSZoneDN($config,$oldEntry['zoneName']); - $dn = "relativeDomainName=".$oldName.",".$oldzoneDn; - $dn2= "relativeDomainName=".$oldName.",".$zoneDn; - $move[$dn]=$dn2; - } + if(count($newEntry['RECORDS'])){ + if($oldEntry['zoneName'] != $newEntry['zoneName']){ + $oldzoneDn = 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; + /* 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 - */ + + /* 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(); } @@ -189,10 +516,11 @@ function getDNSHostEntriesDiff($config,$oldName,$newEntry,$newName) /* There must be at least one record in our entry */ - if(!count($newEntry['RECORDS'])){ - $dn = "relativeDomainName=".$oldName.",".getDNSZoneDN($config,$oldEntry['zoneName']); + if((!count($newEntry['RECORDS'])) || (!$newEntry['exists'])){ + $dn = "relativeDomainName=".$newName.",".getDNSZoneDN($config,$oldEntry['zoneName']); $del[$dn] =""; - return(array("move"=>$move,"add"=>$add,"del"=>$del)); + $ret = array("move"=>$move,"add"=>$add,"del"=>$del); + return($ret); } /* Prepare temp obj @@ -242,19 +570,24 @@ function getDNSHostEntriesDiff($config,$oldName,$newEntry,$newName) * like pTRRecord or CNAMERecord */ if($rec['type'] == "pTRRecord"){ - $PTRdn= "relativeDomainName=".$rec['value'].",".$baseDn; + $PTRdn= "relativeDomainName=".FlipIP($rec['value']).",".$baseDn; $ptrObj = $baseObj; + $reverseName = getNameFromMix($reverseNameMix); $ptrObj['zoneName'] = $reverseName; - $ptrObj['pTRRecord'] = $newName.".".$zoneName; - $ptrObj['relativeDomainName'] = $rec['value']; - + if(!preg_match("/\.$/",$newName)){ + $ptrObj['pTRRecord'] = preg_replace("/\.\.$/",".",$newName.".".$zoneName."."); + }else{ + $ptrObj['pTRRecord'] = preg_replace("/\.\.$/",".",$newName."."); + } + $ptrObj['relativeDomainName'] = FlipIP($rec['value']); + $add[$PTRdn] = $ptrObj; }else if($rec['type'] == "cNAMERecord"){ $PTRdn= "relativeDomainName=".$rec['value'].",".$baseDn; $ptrObj = $baseObj; - $ptrObj['zoneName'] = $reverseName; - $ptrObj['cNAMERecord'] = $newName.".".$zoneName; + $ptrObj['zoneName'] = $zoneName; + $ptrObj['cNAMERecord'] = $newName; $ptrObj['relativeDomainName'] = $rec['value']; $add[$PTRdn] = $ptrObj; @@ -265,21 +598,48 @@ function getDNSHostEntriesDiff($config,$oldName,$newEntry,$newName) } } // foreach record - return(array("move"=>$move,"add"=>$add,"del"=>$del)); + $ret = array("move"=>$move,"add"=>$add,"del"=>$del); + return($ret); } +function getNameFromMix($zoneMix){ + $ret = ""; + if(!strstr($zoneMix, '/')) return($ret); + $zoneIndex = split("/",$zoneMix); + return($zoneIndex[1]); +} /* returns the dn for a specified zone */ -function getDNSZoneDN($config,$zoneName){ +function getDNSZoneDN($config,$zoneNameMix) +{ $ret = ""; - $ldap = $config->get_ldap_link(); + if(!strstr($zoneNameMix, '/')) { + print_red(sprintf(_("Undefined zone name '%s'. Zone name must look like this 'server/zone.com'."),$zoneNameMix)); + 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); } @@ -295,25 +655,32 @@ function getAvailableZones($config) /* Search for zones ... */ - $ldap->search("(&(objectClass=dNSZone)(sOARecord=*))",array("zoneName","tXTRecord")); + $ldap->search("(&(objectClass=dNSZone)(sOARecord=*))",array("zoneName")); + + $ForwardZones = array(); + $ReverseZones = array(); + $zones = array(); while($at = $ldap->fetch()){ if(preg_match("/\.in\-addr\.arpa/",$at['zoneName'][0])){ - $name = preg_replace("/^zoneName=/","",$at['tXTRecord'][0]); - $ret[$name]['addr']= $at['zoneName'][0]; + $ReverseZones[$at['dn']] = $at; }else{ - $name = $at['zoneName'][0]; - $ret[$name]['name']= $at['zoneName'][0]; + $ForwardZones[$at['dn']] = $at; } } - $tmp =array(); - foreach($ret as $name => $entry){ - if((isset($entry['addr']))&&(isset($entry['name']))){ - $tmp[$entry['addr']]=$entry['name']; - } + 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]; + } + } } - return($tmp); + return($zones); } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: