function dns_record_modify($options = "") { global $conf, $self, $onadb; // Version - UPDATE on every edit! $version = '1.13'; printmsg("DEBUG => dns_record_modify({$options}) called", 3); // Parse incoming options string to an array $options = parse_options($options); // Return the usage summary if we need to if ($options['help'] or !$options['set_name'] and !$options['set_ip'] and !$options['set_ttl'] and !$options['set_pointsto'] and !$options['set_srv_pri'] and !$options['set_srv_weight'] and !$options['set_srv_port'] and !$options['set_mx_preference'] and !$options['set_notes'] and !$options['set_view']) { // NOTE: Help message lines should not exceed 80 characters for proper display on a console $self['error'] = 'ERROR => Insufficient parameters'; return array(1, <<<EOM dns_record_modify-v{$version} Modify a DNS record Synopsis: dns_record_modify [KEY=VALUE] ... Where: name=NAME[.DOMAIN] or ID select dns record by name or ID Update: set_name=NAME[.DOMAIN] change name and/or domain set_ip=ADDRESS change IP the record points to set_ttl=NUMBER change the TTL value, 0 = use domains TTL value set_pointsto=NAME[.DOMAIN] change where a CNAME points set_notes=NOTES change the textual notes set_mx_preference=NUMBER change the MX record preference value set_txt=STRING change the value of the TXT record set_srv_pri=NUMBER change SRV Priority set_srv_weight=NUMBER change SRV Weight set_srv_port=NUMBER change SRV Port set_ebegin change the begin date for record, 0 disables set_domain=DOMAIN use if you need to explicitly set domain set_view=STRING change DNS view identifier. AKA Split horizon. Note: * You are not allowed to change the type of the DNS record, to do that you must delete and re-add the record with the new type. * DOMAIN will default to {$conf['dns_defaultdomain']} if not specified EOM ); } /* Modify logic 1. find the dns record we are editing 2. If it is an A, check that the name we are changing to does not already match an existing A/ip or CNAME 3. if its a CNAME, check that it is not the same as any other records. */ // Check permissions if (!auth('host_modify')) { $self['error'] = "Permission denied!"; printmsg($self['error'], 0); return array(10, $self['error'] . "\n"); } // Sanitize addptr.. set it to Y if it is not set $options['set_addptr'] = sanitize_YN($options['set_addptr'], 'Y'); // clean up what is passed in $options['set_ip'] = trim($options['set_ip']); $options['set_pointsto'] = trim($options['set_pointsto']); $options['set_name'] = trim($options['set_name']); $options['set_domain'] = trim($options['set_domain']); $options['set_txt'] = trim($options['set_txt']); //$options['set_view'] = trim($options['set_view']); // // Find the dns record we're modifying // // If the name we were passed has a leading . in it then remove the dot. $options['set_name'] = preg_replace("/^\\./", '', $options['set_name']); // Find the DNS record from $options['name'] list($status, $rows, $dns) = ona_find_dns_record($options['name']); printmsg("DEBUG => dns_record_modify() DNS record: {$dns['fqdn']}", 3); if ($rows > 1) { printmsg("DEBUG => Found more than one DNS record for: {$options['name']}", 3); $self['error'] = "ERROR => Found more than one DNS record for: {$options['name']}"; return array(2, $self['error'] . "\n"); } // If we didn't get a record then exit if (!$dns['id']) { printmsg("DEBUG => DNS record not found ({$options['name']})!", 3); $self['error'] = "ERROR => DNS record not found ({$options['name']})!"; return array(4, $self['error'] . "\n"); } // Set the current_name variable with the records current name // Used by the add pointer function below since it runs before any names are updated $current_name = $dns['fqdn']; $current_int_id = $dns['interface_id']; $check_dns_view_id = $dns['dns_view_id']; $current_dns_view_id = $dns['dns_view_id']; // Set status on if we are chaning IP addresses $changingint = 0; $changingview = 0; // Set a message to display when using dns views if ($conf['dns_views']) { $viewmsg = ' Ensure you are selecting the proper DNS view for this record.'; } // // Define the records we're updating // // This variable will contain the updated info we'll insert into the DB $SET = array(); // Gather DNS view information if (array_key_exists('set_view', $options)) { if (is_numeric($options['set_view'])) { $viewsearch = array('id' => $options['set_view']); } else { $viewsearch = array('name' => strtoupper($options['set_view'])); } // find the IP interface record, list($status, $rows, $dnsview) = ona_get_dns_view_record($viewsearch); if (!$rows) { printmsg("ERROR => dns_record_modify() Unable to find DNS view: {$options['set_view']}", 3); $self['error'] = "ERROR => dns_record_modify() Unable to find DNS view: {$options['set_view']}."; return array(4, $self['error'] . "\n"); } // If we have a new dns view, add it to the SET array and update the check view variable used in all the checks. if ($dns['dns_view_id'] != $dnsview['id']) { // You can only change the view on parent records.. if this record has a dns_id, you must change the parent if ($dns['dns_id']) { printmsg("ERROR => You must change the parent DNS A record to the new view. This record will follow.", 3); $self['error'] = "ERROR => You must change the parent DNS A record to the new view. This record will follow."; return array(5, $self['error'] . "\n"); } $SET['dns_view_id'] = $dnsview['id']; $check_dns_view_id = $dnsview['id']; $changingview = 1; } } // Checking the IP setting first to estabilish if we are changing the IP so I can check the new combo of A/ip later if ($options['set_ip'] and $options['set_ip'] != '0.0.0.0') { // find the IP interface record, to ensure it is valid list($status, $rows, $interface) = ona_find_interface($options['set_ip']); if (!$rows) { printmsg("ERROR => dns_record_modify() Unable to find IP interface: {$options['set_ip']}", 3); $self['error'] = "ERROR => dns_record_modify() Unable to find IP interface: {$options['set_ip']}\n"; return array(4, $self['error']); } // If they actually changed the ip address if ($interface['id'] != $dns['interface_id']) { // check for child records that would match our new values // I think they will always be just PTR records so I am only selecting that type for now? list($status, $rows, $dnschild) = ona_get_dns_record(array('dns_id' => $dns['id'], 'interface_id' => $interface['id'], 'type' => 'PTR')); if ($rows) { printmsg("ERROR => dns_record_modify() This change results in a duplicate child DNS record: PTR {$options['set_ip']}. Delete existing PTR record first.", 3); $self['error'] = "<br>ERROR => dns_record_modify() This change results in a duplicate child DNS record: PTR {$options['set_ip']}.<br> Delete existing PTR record first.\n"; return array(4, $self['error']); } $changingint = 1; $SET['interface_id'] = $interface['id']; // get the info on the original interface list($status, $rows, $origint) = ona_get_interface_record(array('id' => $dns['interface_id'])); } } // Set options['set_name']? // Validate that the DNS name has only valid characters in it if ($options['set_name']) { // If we are specifically passing in a domain, use its value. If we dont have a domain // then try to find it in the name that we are setting. if ($options['set_domain']) { // Find the domain name piece of $search list($status, $rows, $domain) = ona_find_domain($options['set_domain'], 0); } else { list($status, $rows, $domain) = ona_find_domain($options['set_name'], 0); } // Find the domain name piece of $search if (!isset($domain['id'])) { printmsg("ERROR => Unable to determine domain name portion of ({$options['set_name']})!", 3); $self['error'] = "ERROR => Unable to determine domain name portion of ({$options['set_name']})!"; return array(3, $self['error'] . "\n"); } printmsg("DEBUG => ona_find_domain({$options['set_name']}) returned: {$domain['fqdn']} for new name.", 3); // Now find what the host part of $search is $hostname = str_replace(".{$domain['fqdn']}", '', $options['set_name']); // Validate that the DNS name has only valid characters in it $hostname = sanitize_hostname($hostname); if (!$hostname) { printmsg("DEBUG => Invalid host name ({$options['set_name']})!", 3); $self['error'] = "ERROR => Invalid host name ({$options['set_name']})!"; return array(4, $self['error'] . "\n"); } // If the hostname we came up with and the domain name are the same, then assume this is // meant to be a domain specific record, like A, MX, NS type records. if ($hostname == $domain['fqdn']) { $hostname = ''; } // Debugging printmsg("DEBUG => Using hostname: {$hostname}.{$domain['fqdn']}, Domain ID: {$domain['id']}", 3); // if it is an a record and we are changing the name.. make sure there is not already an A with that name/ip combo if ($dns['type'] == 'A') { // If we are changing the interface id as determined above, check using that value if ($changingint) { $dns['interface_id'] = $SET['interface_id']; } list($status, $rows, $tmp) = ona_get_dns_record(array('name' => $hostname, 'domain_id' => $domain['id'], 'interface_id' => $dns['interface_id'], 'type' => 'A', 'dns_view_id' => $check_dns_view_id)); if ($rows) { if ($tmp['id'] != $dns['id'] or $rows > 1) { printmsg("ERROR => There is already an A record with that name and IP address!{$viewmsg}", 3); $self['error'] = "ERROR => There is already an A record with that name and IP address!{$viewmsg}"; return array(5, $self['error'] . "\n"); } } } // make sure that name/pointsto combo doesnt already exist if ($dns['type'] == 'CNAME' or $dns['type'] == 'MX' or $dns['type'] == 'NS' or $dns['type'] == 'SRV') { list($status, $rows, $tmp) = ona_get_dns_record(array('name' => $hostname, 'domain_id' => $domain['id'], 'dns_id' => $dns['dns_id'], 'type' => $dns['type'], 'dns_view_id' => $check_dns_view_id)); if ($rows) { if ($tmp['id'] != $dns['id'] or $rows > 1) { printmsg("ERROR => There is already a {$dns['type']} with that name pointing to that A record!{$viewmsg}", 3); $self['error'] = "ERROR => There is already a {$dns['type']} with that name pointing to that A record!{$viewmsg}"; return array(6, $self['error'] . "\n"); } } } if ($dns['type'] == 'CNAME') { // if it is a CNAME, make sure the new name is not an A record name already list($status, $rows, $tmp) = ona_get_dns_record(array('name' => $hostname, 'domain_id' => $domain['id'], 'type' => 'A', 'dns_view_id' => $check_dns_view_id)); if ($status or $rows) { printmsg("ERROR => There is already an A record with that name!{$viewmsg}", 3); $self['error'] = "ERROR => There is already an A record with that name!{$viewmsg}"; return array(7, $self['error'] . "\n"); } } // lets try and determine the interface record using the name passed in. Only works if we get one record back // this is all to help associate if it can so that when the A record is removed, so is this TXT record. if ($dns['type'] == 'TXT') { // if we are dealing with a change to a domain only.. then blank the interface id and dns_id if ($hostname == '') { $SET['interface_id'] = ''; $SET['dns_id'] = ''; } else { list($status, $rows, $hostint) = ona_get_dns_record(array('name' => $hostname, 'domain_id' => $domain['id'], 'type' => 'A', 'dns_view_id' => $check_dns_view_id)); if ($rows == 1) { $SET['interface_id'] = $hostint['interface_id']; $SET['dns_id'] = $hostint['id']; $SET['name'] = $hostname; } } } // If you have actually changed the name from what it was, set the new variable $SET if ($dns['name'] != $hostname) { $SET['name'] = $hostname; } if ($dns['domain_id'] != $domain['id']) { $SET['domain_id'] = $domain['id']; } } // If we are modifying a pointsto option if (array_key_exists('set_pointsto', $options) and ($options['set_type'] == 'CNAME' or $options['set_type'] == 'MX' or $options['set_type'] == 'NS' or $options['set_type'] == 'SRV')) { // Determine the host and domain name portions of the pointsto option // Find the domain name piece of $search list($status, $rows, $pdomain) = ona_find_domain($options['set_pointsto']); printmsg("DEBUG => ona_find_domain({$options['set_pointsto']}) returned: {$domain['fqdn']} for pointsto.", 3); // Now find what the host part of $search is $phostname = str_replace(".{$pdomain['fqdn']}", '', $options['set_pointsto']); // Validate that the DNS name has only valid characters in it $phostname = sanitize_hostname($phostname); if (!$phostname) { printmsg("DEBUG => Invalid pointsto host name ({$options['set_pointsto']})!", 3); $self['error'] = "ERROR => Invalid pointsto host name ({$options['set_pointsto']})!"; return array(4, $self['error'] . "\n"); } // Debugging printmsg("DEBUG => Using 'pointsto' hostname: {$phostname}.{$pdomain['fqdn']}, Domain ID: {$pdomain['id']}", 3); // Find the dns record that it will point to list($status, $rows, $pointsto_record) = ona_get_dns_record(array('name' => $phostname, 'domain_id' => $pdomain['id'], 'type' => 'A', 'dns_view_id' => $check_dns_view_id)); if ($status or !$rows) { printmsg("ERROR => Unable to find DNS A record to point {$options['set_type']} entry to!{$viewmsg}", 3); $self['error'] = "ERROR => Unable to find DNS A record to point {$options['set_type']} entry to!{$viewmsg}"; return array(5, $self['error'] . "\n"); } // Validate that there are no entries already pointed to the new A record list($c_status, $c_rows, $c_record) = ona_get_dns_record(array('name' => $dns['name'], 'domain_id' => $dns['domain_id'], 'dns_id' => $pointsto_record['id'], 'type' => $options['set_type'], 'dns_view_id' => $check_dns_view_id)); if ($c_record['id'] != $dns['id'] and $c_rows) { printmsg("ERROR => Another DNS {$options['set_type']} record exists with the values you've selected!{$viewmsg}", 3); $self['error'] = "ERROR => Another DNS {$options['set_type']} record exists with the values you've selected!{$viewmsg}"; return array(5, $self['error'] . "\n"); } $SET['dns_id'] = $pointsto_record['id']; $SET['interface_id'] = $pointsto_record['interface_id']; } // Set options['set_notes'] (it can be a null string!) if (array_key_exists('set_notes', $options)) { // There is an issue with escaping '=' and '&'. We need to avoid adding escape characters $options['set_notes'] = str_replace('\\=', '=', $options['set_notes']); $options['set_notes'] = str_replace('\\&', '&', $options['set_notes']); // If it changed... if ($dns['notes'] != $options['set_notes']) { $SET['notes'] = $options['set_notes']; } } // Check the date formatting etc if (isset($options['set_ebegin']) and $options['set_ebegin'] != $dns['ebegin']) { // format the time that was passed in for the database, leave it as 0 if they pass it as 0 $options['set_ebegin'] = $options['set_ebegin'] == '0' ? 0 : date('Y-m-j G:i:s', strtotime($options['set_ebegin'])); // Force the SET variable if its ont 0 and the current record is not 0000:00:00 00:00 if (!($options['set_ebegin'] == '0' and $dns['ebegin'] == '0000-00-00 00:00:00')) { $SET['ebegin'] = $options['set_ebegin']; } } else { // If I got no date, use right now as the date/time $options['set_ebegin'] = date('Y-m-j G:i:s'); } // Add the remaining items to the $SET variable // if there is a ttl setting and it is not the same as the existing record if (array_key_exists('set_ttl', $options) and $options['set_ttl'] != $dns['ttl']) { $SET['ttl'] = $options['set_ttl']; } if (array_key_exists('set_mx_preference', $options) and $options['set_mx_preference'] != $dns['mx_preference']) { $SET['mx_preference'] = $options['set_mx_preference']; } if (array_key_exists('set_srv_pri', $options) and $options['set_srv_pri'] != $dns['srv_pri']) { $SET['srv_pri'] = $options['set_srv_pri']; } if (array_key_exists('set_srv_weight', $options) and $options['set_srv_weight'] != $dns['srv_weight']) { $SET['srv_weight'] = $options['set_srv_weight']; } if (array_key_exists('set_srv_port', $options) and $options['set_srv_port'] != $dns['srv_port']) { $SET['srv_port'] = $options['set_srv_port']; } if (array_key_exists('set_txt', $options)) { // There is an issue with escaping '=' and '&'. We need to avoid adding escape characters $options['set_txt'] = str_replace('\\=', '=', $options['set_txt']); $options['set_txt'] = str_replace('\\&', '&', $options['set_txt']); // If it changed... if ($dns['txt'] != $options['set_txt']) { $SET['txt'] = $options['set_txt']; } } // If it is an A record and they have specified to auto add the PTR record for it. if ($options['set_addptr'] == 'Y' and $options['set_type'] == 'A') { printmsg("DEBUG => Auto adding a PTR record for {$options['set_name']}.", 0); // Run dns_record_add as a PTR type // Always use the $current_name variable as the name might change during the update list($status, $output) = run_module('dns_record_add', array('name' => $current_name, 'domain' => $domain['fqdn'], 'ip' => $options['set_ip'], 'ebegin' => $options['set_ebegin'], 'type' => 'PTR', 'view' => $check_dns_view_id)); if ($status) { return array($status, $output); } printmsg($text); } // Get the dns record before updating (logging) $original_record = $dns; // Update the host record if necessary //if(count($SET) > 0 and $options['set_ebegin'] != $dns['ebegin']) { if (count($SET) > 0) { // Use the ebegin value set above $SET['ebegin'] = $options['set_ebegin']; // If we are changing the interface id as determined above, check using that value if ($changingint) { // If the interface id has changed, make sure any child records are updated first if ($SET['interface_id'] != $current_int_id) { printmsg("DEBUG = > dns_record_modify() Updating child interfaces to new interface.", 2); list($status, $rows) = db_update_record($onadb, 'dns', array('dns_id' => $dns['id'], 'interface_id' => $current_int_id), array('interface_id' => $SET['interface_id'])); if ($status) { $self['error'] = "ERROR => dns_record_modify() SQL Query failed for dns record: " . $self['error']; printmsg($self['error'], 0); return array(11, $self['error'] . "\n"); } // TODO: may need set rebuild flag on each of the domains related to these child records that just changed } // Check the PTR record has the proper domain still $ipflip = ip_mangle($interface['ip_addr_text'], 'flip'); $octets = explode(".", $ipflip); if (count($octets) > 4) { $arpa = '.ip6.arpa'; $octcount = 31; } else { $arpa = '.in-addr.arpa'; $octcount = 3; } // Find a pointer zone for this record to associate with. list($status, $prows, $ptrdomain) = ona_find_domain($ipflip . $arpa); list($status, $drrows, $dnsrec) = ona_get_dns_record(array('type' => 'PTR', 'interface_id' => $SET['interface_id'], 'dns_view_id' => $check_dns_view_id)); // TRIGGER: we made a change and need to update the CURRENT PTR record as well, only sets it if the ptrdomain changes list($status, $rows) = db_update_record($onadb, 'dns_server_domains', array('domain_id' => $dnsrec['domain_id']), array('rebuild_flag' => 1)); if ($status) { $self['error'] = "ERROR => dns_record_add() Unable to update rebuild flags for domain.: {$self['error']}"; printmsg($self['error'], 0); return array(7, $self['error'] . "\n"); } // if we find any PTR records and the domain has chaned, make sure the child PTR records have the updated PTR domain info. if (isset($ptrdomain['id']) and $drrows > 0 and $dnsrec['domain_id'] != $ptrdomain['id']) { list($status, $rows) = db_update_record($onadb, 'dns', array('id' => $dnsrec['id']), array('domain_id' => $ptrdomain['id'], 'ebegin' => $SET['ebegin'])); if ($status or !$rows) { $self['error'] = "ERROR => dns_record_modify() Child PTR record domain update failed: " . $self['error']; printmsg($self['error'], 0); return array(14, $self['error'] . "\n"); } // TRIGGER: we made a change and need to update the NEW PTR record as well, only sets it if the ptrdomain changes list($status, $rows) = db_update_record($onadb, 'dns_server_domains', array('domain_id' => $ptrdomain['id']), array('rebuild_flag' => 1)); if ($status) { $self['error'] = "ERROR => dns_record_add() Unable to update rebuild flags for domain.: {$self['error']}"; printmsg($self['error'], 0); return array(7, $self['error'] . "\n"); } } } // If we are changing the view, we must change all other DNS records that point to this one to the same view. if ($changingview) { if ($SET['dns_view_id'] != $current_dns_view_id) { printmsg("DEBUG = > dns_record_modify() Updating child DNS records to new dns view.", 2); list($status, $rows) = db_update_record($onadb, 'dns', array('dns_id' => $dns['id']), array('dns_view_id' => $SET['dns_view_id'])); if ($status) { $self['error'] = "ERROR => dns_record_modify() SQL Query failed for dns record child view updates: " . $self['error']; printmsg($self['error'], 0); return array(11, $self['error'] . "\n"); } } // TRIGGER: yep I probably need one here FIXME } // Make sure we us A type for both A and AAAA if ($SET['type'] == 'AAAA') { $SET['type'] = 'A'; } // Change the actual DNS record list($status, $rows) = db_update_record($onadb, 'dns', array('id' => $dns['id']), $SET); if ($status or !$rows) { $self['error'] = "ERROR => dns_record_modify() SQL Query failed for dns record: " . $self['error']; printmsg($self['error'], 0); return array(12, $self['error'] . "\n"); } // TRIGGER: we made a change, lets mark the domain for rebuild on its servers list($status, $rows) = db_update_record($onadb, 'dns_server_domains', array('domain_id' => $dns['domain_id']), array('rebuild_flag' => 1)); if ($status) { $self['error'] = "ERROR => dns_record_add() Unable to update rebuild flags for domain.: {$self['error']}"; printmsg($self['error'], 0); return array(7, $self['error'] . "\n"); } // TRIGGER: If we are changing domains, lets flag the new domain as well, lets mark the domain for rebuild on its servers if ($SET['domain_id']) { list($status, $rows) = db_update_record($onadb, 'dns_server_domains', array('domain_id' => $SET['domain_id']), array('rebuild_flag' => 1)); if ($status) { $self['error'] = "ERROR => dns_record_add() Unable to update rebuild flags for domain.: {$self['error']}"; printmsg($self['error'], 0); return array(7, $self['error'] . "\n"); } } } // Get the host record after updating (logging) list($status, $rows, $new_record) = ona_get_dns_record(array('id' => $dns['id'])); // Return the success notice $self['error'] = "INFO => DNS record UPDATED:{$dns['id']}: {$new_record['fqdn']}"; $log_msg = "INFO => DNS record UPDATED:{$dns['id']}: "; $more = ''; foreach (array_keys($original_record) as $key) { if ($original_record[$key] != $new_record[$key]) { $log_msg .= $more . $key . "[" . $original_record[$key] . "=>" . $new_record[$key] . "]"; $more = "; "; } } // only print to logfile if a change has been made to the record if ($more != '') { printmsg($log_msg, 0); } return array(0, $self['error'] . "\n"); }
function ws_save($window_name, $form = '') { global $include, $conf, $self, $onadb; // Check permissions if (!(auth('host_modify') or auth('host_add'))) { $response = new xajaxResponse(); $response->addScript("alert('Permission denied!');"); return $response->getXML(); } // Instantiate the xajaxResponse object $response = new xajaxResponse(); $js = ''; // Validate input if ($form['set_type'] == '' or $form['host'] == '.' and $form['set_ip'] == '') { $response->addScript("alert('Please complete all fields to continue!');"); return $response->getXML(); } // Since we're adding two records (host and an interface) // we need to do a little validation here to make sure things // have a good chance of working! // Validate the "set_host" name is valid $form['set_host'] = sanitize_hostname(trim($form['set_host'])); if (!$form['set_host']) { $response->addScript("alert('Invalid hostname!');"); return $response->getXML(); } // Validate domain is valid // list($status, $rows, $domain) = ona_find_domain($form['set_domain'],0); // if ($status or !$rows) { // $response->addScript("alert('Invalid domain!');"); // return($response->getXML()); // } // Make sure the IP address specified is valid if ($form['host'] != '.' and $form['set_ip']) { $form['set_ip'] = ip_mangle($form['set_ip'], 'dotted'); if ($form['set_ip'] == -1) { $response->addScript("alert('{$self['error']}');"); return $response->getXML(); } } if ($form['set_addptr'] == '') { $form['set_addptr'] = 'N'; } // FIXME: If we're editing, validate the $form['host'] is valid // FIXME: If we're editing, validate the $form['interface'] is valid // FIXME: Verify that the device "type" ID is valid (not a big risk since they select from a drop-down) // If no location is passed, make sure the value is 0 // if (array_key_exists('set_location', $form)) $form['set_location'] = 0; // Decide if we're editing or adding $module = 'modify'; // If we're adding, re-map some the array names to match what the "add" module wants if ($form['host'] == '.') { $module = 'add'; if (!auth('host_add')) { $response = new xajaxResponse(); $response->addScript("alert('Permission denied!');"); return $response->getXML(); } // Device options $form['type'] = $form['set_type']; unset($form['set_type']); $form['location'] = $form['set_location']; unset($form['set_location']); // Host options $form['domain'] = $form['set_domain']; $form['host'] = $form['set_host'] . '.' . $form['set_domain']; unset($form['set_host']); unset($form['set_domain']); $form['notes'] = $form['set_notes']; unset($form['set_notes']); $form['description'] = $form['set_description']; unset($form['set_description']); $form['view'] = $form['set_view']; unset($form['set_view']); // Interface options $form['ip'] = $form['set_ip']; unset($form['set_ip']); $form['mac'] = $form['set_mac']; unset($form['set_mac']); $form['name'] = $form['set_name']; unset($form['set_name']); $form['addptr'] = $form['set_addptr']; unset($form['set_addptr']); // If there's no "refresh" javascript, add a command to view the new host if (!preg_match('/\\w/', $form['js'])) { $form['js'] = "xajax_window_submit('work_space', 'xajax_window_submit(\\'display_host\\', \\'host=>{$form['host']}\\', \\'display\\')');"; } } else { $form['set_host'] .= '.' . $form['set_domain']; } // Do a pre check of the ptr domain so we can prompt the user properly if ($module == 'add') { $ipflip = ip_mangle($form['ip'], 'flip'); $octets = explode(".", $ipflip); if (count($octets) > 4) { $arpa = '.ip6.arpa'; $octcount = 31; } else { $arpa = '.in-addr.arpa'; $octcount = 3; } list($status, $rows, $ptrdomain) = ona_find_domain($ipflip . $arpa); if (!$ptrdomain['id']) { printmsg("ERROR => This operation tried to create a PTR record that is the first in this IP address space. You must first create at least the following DNS domain: {$octets[$octcount]}.in-addr.arpa", 3); $self['error'] = "ERROR => This operation tried to create a PTR record that is the first in this IP address space.<br>You must first create at least the following DNS domain: <b>{$octets[$octcount]}.in-addr.arpa</b>.<br>You could also create domains at deeper level reverse zones if desired.<br>We have opened the add domain dialog for you."; $response->addScript("alert('{$self['error']}');xajax_window_submit('edit_domain', 'newptrdomainname=>{$octets[$octcount]}{$arpa}', 'editor');"); return $response->getXML(); } } // Run the module to ADD the HOST AND INTERFACE, or MODIFY THE HOST. list($status, $output) = run_module('host_' . $module, $form); // If the module returned an error code display a popup warning if ($status) { $js .= "alert('Save failed.\\n" . preg_replace('/[\\s\']+/', ' ', $self['error']) . "');"; } else { // Run the module to MODIFY THE INTERFACE if we need to if ($module == 'modify' and $form['set_ip']) { list($status, $output) = run_module('interface_' . $module, $form); } // If the module returned an error code display a popup warning if ($status and $module == 'modify' and $form['set_ip']) { $js .= "alert('Interface update failed.\\n" . preg_replace('/[\\s\']+/', ' ', $self['error']) . "');"; } else { // if they have checked the keep adding hosts box then dont remove the window if (!$form['keepadding']) { $js .= "removeElement('{$window_name}');"; } else { $js .= "el('statusinfo_{$window_name}').innerHTML = 'Previously added:<br>{$form['host']} => {$form['ip']}';"; } if ($form['js']) { $js .= $form['js']; } } } // Insert the new table into the window $response->addScript($js); return $response->getXML(); }
function ws_save($window_name, $form = '') { global $include, $conf, $self, $onadb; // Check permissions if (!(auth('dns_record_modify') and auth('dns_record_add'))) { $response = new xajaxResponse(); $response->addScript("alert('Permission denied!');"); return $response->getXML(); } // Instantiate the xajaxResponse object $response = new xajaxResponse(); $js = ''; // Validate input // if ($form['set_domain'] == '' or // $form['set_type'] == '' // ) { // $response->addScript("alert('Please complete all fields to continue!');"); // return($response->getXML()); // } // we need to do a little validation here to make sure things // have a good chance of working! // If the name we were passed has a leading . in it then remove the dot. $form['set_name'] = preg_replace("/^\\./", '', trim($form['set_name'])); $form['set_ip'] = trim($form['set_ip']); // Validate the "set_name" name is valid if ($form['set_name'] and $form['set_type'] != 'NS') { $form['set_name'] = sanitize_hostname($form['set_name']); if (!$form['set_name']) { $response->addScript("alert('Invalid hostname!');"); return $response->getXML(); } } // Make sure the IP address specified is valid if ($form['set_name'] != '.' and $form['set_ip']) { $form['set_ip'] = ip_mangle($form['set_ip'], 'dotted'); if ($form['set_ip'] == -1) { $response->addScript("alert('{$self['error']}');"); return $response->getXML(); } } $form['set_addptr'] = sanitize_YN($form['set_addptr'], 'N'); // Set the effective date to 0 to disable if ($form['disable']) { $form['set_ebegin'] = 0; } // Decide if we're editing or adding $module = 'modify'; // If we're adding, re-map some the array names to match what the "add" module wants if (!$form['dns_id']) { $module = 'add'; // options $form['domain'] = $form['set_domain']; $form['name'] = $form['set_name'] . '.' . $form['set_domain']; unset($form['set_name']); unset($form['set_domain']); $form['type'] = $form['set_type']; unset($form['set_type']); $form['ebegin'] = $form['set_ebegin']; unset($form['set_ebegin']); $form['notes'] = $form['set_notes']; unset($form['set_notes']); $form['ip'] = $form['set_ip']; unset($form['set_ip']); $form['ttl'] = $form['set_ttl']; unset($form['set_ttl']); $form['addptr'] = $form['set_addptr']; unset($form['set_addptr']); $form['view'] = $form['set_view']; unset($form['set_view']); // if this is a cname. then set the pointsto option if ($form['type'] == 'CNAME' or $form['type'] == 'MX' or $form['type'] == 'NS' or $form['type'] == 'SRV') { $form['pointsto'] = $form['set_pointsto']; } if ($form['type'] == 'MX') { $form['mx_preference'] = $form['set_mx_preference']; } if ($form['type'] == 'TXT') { $form['txt'] = $form['set_txt']; } if ($form['type'] == 'SRV') { $form['srv_pri'] = $form['set_srv_pri']; } if ($form['type'] == 'SRV') { $form['srv_weight'] = $form['set_srv_weight']; } if ($form['type'] == 'SRV') { $form['srv_port'] = $form['set_srv_port']; } // If it is an NS record, blank the name out //if ($form['type'] == 'NS') $form['name'] = $form['set_domain']; // If we are adding a PTR.. switch existing a record to name if ($form['type'] == 'PTR') { $form['name'] = $form['set_pointsto']; } // If there's no "refresh" javascript, add a command to view the new dns record if (!preg_match('/\\w/', $form['js'])) { $form['js'] = "xajax_window_submit('work_space', 'xajax_window_submit(\\'display_host\\', \\'host=>{$form['name']}\\', \\'display\\')');"; } } else { $form['set_name'] .= '.' . $form['set_domain']; //FIXME: MP temporary kludge to get around not having a proper find_dns_record module.. ID is the only way to find a record now and it is done via the name field $form['name'] = $form['dns_id']; // if this is a cname. then set the pointsto option if ($form['set_type'] != 'CNAME') { $form['set_pointsto'] == ''; } } // Run the module to ADD the DNS record, or MODIFY THE DNS record. list($status, $output) = run_module('dns_record_' . $module, $form); // If the module returned an error code display a popup warning if ($status) { $js .= "alert('Save failed.\\n" . preg_replace('/[\\s\']+/', ' ', $self['error']) . "');"; } else { // if they have checked the keep adding records box then dont remove the window if (!$form['keepadding']) { $js .= "removeElement('{$window_name}');"; } else { $js .= "el('statusinfo_{$window_name}').innerHTML = 'Previously added:<br>{$form['name']} Type: {$form['type']}';"; } if ($form['js']) { $js .= $form['js']; } } // Insert the new table into the window $response->addScript($js); return $response->getXML(); }
function host_add($options = "") { global $conf, $self, $onadb; // Version - UPDATE on every edit! $version = '1.11'; printmsg("DEBUG => host_add({$options}) called", 3); // Parse incoming options string to an array $options = parse_options($options); // Return the usage summary if we need to if ($options['help'] or !($options['host'] and $options['type'] and $options['ip'])) { // NOTE: Help message lines should not exceed 80 characters for proper display on a console $self['error'] = 'ERROR => Insufficient parameters'; return array(1, <<<EOM host_add-v{$version} Add a new host Synopsis: host_add [KEY=VALUE] ... Required: host=NAME[.DOMAIN] Hostname for new DNS record type=TYPE or ID Device/model type or ID ip=ADDRESS IP address (numeric or dotted) Optional: notes=NOTES Textual notes location=REF Reference of location device=NAME|ID The device this host is associated with Optional, add an interface too: mac=ADDRESS Mac address (most formats are ok) name=NAME Interface name (i.e. "FastEthernet0/1.100") description=TEXT Brief description of the interface addptr=Y|N Auto add a PTR record for new host/IP (default: Y) EOM ); } // Sanitize addptr.. set it to Y if it is not set $options['addptr'] = sanitize_YN($options['addptr'], 'Y'); // clean up what is passed in $options['ip'] = trim($options['ip']); $options['mac'] = trim($options['mac']); $options['name'] = trim($options['name']); $options['host'] = trim($options['host']); // Validate that there isn't already another interface with the same IP address list($status, $rows, $interface) = ona_get_interface_record(array('ip_addr' => $options['ip'])); if ($rows) { printmsg("DEBUG => host_add() IP conflict: That IP address (" . ip_mangle($orig_ip, 'dotted') . ") is already in use!", 3); $self['error'] = "ERROR => host_add() IP conflict: That IP address (" . ip_mangle($orig_ip, 'dotted') . ") is already in use!"; return array(4, $self['error'] . "\n" . "INFO => Conflicting interface record ID: {$interface['id']}\n"); } // Find the Location ID to use if ($options['location']) { list($status, $rows, $loc) = ona_find_location($options['location']); if ($status or !$rows) { printmsg("DEBUG => The location specified, {$options['location']}, does not exist!", 3); $self['error'] = "ERROR => The location specified, {$options['location']}, does not exist!"; return array(2, "{$self['error']}\n"); } printmsg("DEBUG => Location selected: {$loc['reference']}, location name: {$loc['name']}", 3); } else { $loc['id'] = 0; } // Find the Device Type ID (i.e. Type) to use list($status, $rows, $device_type) = ona_find_device_type($options['type']); if ($status or $rows != 1 or !$device_type['id']) { printmsg("DEBUG => The device type specified, {$options['type']}, does not exist!", 3); return array(3, "ERROR => The device type specified, {$options['type']}, does not exist!\n"); } printmsg("DEBUG => Device type selected: {$device_type['model_description']} Device ID: {$device_type['id']}", 3); // Sanitize "security_level" option $options['security_level'] = sanitize_security_level($options['security_level']); if ($options['security_level'] == -1) { printmsg("DEBUG => Sanitize security level failed either ({$options['security_level']}) is invalid or is higher than user's level!", 3); return array(3, $self['error'] . "\n"); } // Determine the real hostname to be used -- // i.e. add .something.com, or find the part of the name provided // that will be used as the "domain". This means testing many // domain names against the DB to see what's valid. // // Find the domain name piece of $search. // If we are specifically passing in a domain, use its value. If we dont have a domain // then try to find it in the name that we are setting. if ($options['domain']) { // Find the domain name piece of $search list($status, $rows, $domain) = ona_find_domain($options['domain'], 0); } else { list($status, $rows, $domain) = ona_find_domain($options['host'], 0); } if (!isset($domain['id'])) { printmsg("ERROR => Unable to determine domain name portion of ({$options['host']})!", 3); $self['error'] = "ERROR => Unable to determine domain name portion of ({$options['host']})!"; return array(3, $self['error'] . "\n"); } printmsg("DEBUG => ona_find_domain({$options['host']}) returned: {$domain['fqdn']}", 3); // Now find what the host part of $search is $hostname = str_replace(".{$domain['fqdn']}", '', $options['host']); // Validate that the DNS name has only valid characters in it $hostname = sanitize_hostname($hostname); if (!$hostname) { printmsg("ERROR => Invalid host name ({$options['host']})!", 3); $self['error'] = "ERROR => Invalid host name ({$options['host']})!"; return array(4, $self['error'] . "\n"); } // Debugging printmsg("DEBUG => Using hostname: {$hostname} Domainname: {$domain['fqdn']}, Domain ID: {$domain['id']}", 3); // Validate that there isn't already any dns record named $host['name'] in the domain $host_domain_id. $h_status = $h_rows = 0; // does the domain $host_domain_id even exist? list($d_status, $d_rows, $d_record) = ona_get_dns_record(array('name' => $hostname, 'domain_id' => $domain['id'])); if ($d_status or $d_rows) { printmsg("DEBUG => The name {$hostname}.{$domain['fqdn']} is already in use, the primary name for a host should be unique!", 3); $self['error'] = "ERROR => Another DNS record named {$hostname}.{$domain['fqdn']} is already in use, the primary name for a host should be unique!"; return array(5, $self['error'] . "\n"); } // Check permissions if (!auth('host_add')) { $self['error'] = "Permission denied!"; printmsg($self['error'], 0); return array(10, $self['error'] . "\n"); } // Get the next ID for the new host record $id = ona_get_next_id('hosts'); if (!$id) { $self['error'] = "ERROR => The ona_get_next_id('hosts') call failed!"; printmsg($self['error'], 0); return array(7, $self['error'] . "\n"); } printmsg("DEBUG => ID for new host record: {$id}", 3); // Get the next ID for the new device record or use the one passed in the CLI if (!$options['device']) { $host['device_id'] = ona_get_next_id('devices'); if (!$id) { $self['error'] = "ERROR => The ona_get_next_id('device') call failed!"; printmsg($self['error'], 0); return array(7, $self['error'] . "\n"); } printmsg("DEBUG => ID for new device record: {$id}", 3); } else { list($status, $rows, $devid) = ona_find_device($options['device']); if (!$rows) { printmsg("DEBUG => The device specified, {$options['device']}, does not exist!", 3); $self['error'] = "ERROR => The device specified, {$options['device']}, does not exist!"; return array(7, $self['error'] . "\n"); } $host['device_id'] = $devid['id']; } // There is an issue with escaping '=' and '&'. We need to avoid adding escape characters $options['notes'] = str_replace('\\=', '=', $options['notes']); $options['notes'] = str_replace('\\&', '&', $options['notes']); // Add the device record // FIXME: (MP) quick add of device record. more detail should be looked at here to ensure it is done right // FIXME: MP this should use the run_module('device_add')!!! when it is ready list($status, $rows) = db_insert_record($onadb, 'devices', array('id' => $host['device_id'], 'device_type_id' => $device_type['id'], 'location_id' => $loc['id'], 'primary_host_id' => $id)); if ($status or !$rows) { $self['error'] = "ERROR => host_add() SQL Query failed adding device: " . $self['error']; printmsg($self['error'], 0); return array(6, $self['error'] . "\n"); } // Add the host record // FIXME: (PK) Needs to insert to multiple tables for e.g. name and domain_id. list($status, $rows) = db_insert_record($onadb, 'hosts', array('id' => $id, 'primary_dns_id' => '', 'device_id' => $host['device_id'], 'notes' => $options['notes'])); if ($status or !$rows) { $self['error'] = "ERROR => host_add() SQL Query failed adding host: " . $self['error']; printmsg($self['error'], 0); return array(6, $self['error'] . "\n"); } // Else start an output message $text = "INFO => Host ADDED: {$hostname}.{$domain['fqdn']}"; printmsg($text, 0); $text .= "\n"; // We must always have an IP now to add an interface, call that module now: // since we have no name yet, we need to use the ID of the new host as the host option for the following module calls $options['host'] = $id; // for annoying reasons we need to keep track of what was set first $options['addptrsave'] = $options['addptr']; // Interface adds can add PTR records, lets let the A record add that happens next add it instead. $options['addptr'] = '0'; printmsg("DEBUG => host_add() ({$hostname}.{$domain['fqdn']}) calling interface_add() ({$options['ip']})", 3); list($status, $output) = run_module('interface_add', $options); if ($status) { return array($status, $output); } $text .= $output; // Find the interface_id for the interface we just added list($status, $rows, $int) = ona_find_interface($options['ip']); // make the dns record type A $options['type'] = 'A'; // FIXME: MP I had to force the name value here. name is comming in as the interface name. this is nasty! $options['name'] = "{$hostname}.{$domain['fqdn']}"; $options['domain'] = $domain['fqdn']; // And we will go ahead and auto add the ptr. the user can remove it later if they dont want it. FIXME: maybe create a checkbox on the host edit $options['addptr'] = $options['addptrsave']; // Add the DNS entry with the IP address etc printmsg("DEBUG => host_add() ({$hostname}.{$domain['fqdn']}) calling dns_record_add() ({$options['ip']})", 3); list($status, $output) = run_module('dns_record_add', $options); if ($status) { return array($status, $output); } $text .= $output; // find the dns record we just added so we can use its ID as the primary_dns_id for the host. list($status, $rows, $dnsrecord) = ona_get_dns_record(array('name' => $hostname, 'domain_id' => $domain['id'], 'interface_id' => $int['id'], 'type' => 'A')); // Set the primary_dns_id to the dns record that was just added list($status, $rows) = db_update_record($onadb, 'hosts', array('id' => $id), array('primary_dns_id' => $dnsrecord['id'])); if ($status or !$rows) { $self['error'] = "ERROR => host_add() SQL Query failed to update primary_dns_id for host: " . $self['error']; printmsg($self['error'], 0); return array(8, $self['error'] . "\n"); } return array(0, $text); }
function domain_add($options = "") { global $conf, $self, $onadb; printmsg("DEBUG => domain_add({$options}) called", 3); // Version - UPDATE on every edit! $version = '1.07'; // Parse incoming options string to an array $options = parse_options($options); // Return the usage summary if we need to if ($options['help'] or !($options['name'] or ($options['admin'] or $options['ptr'] or $options['primary_master']))) { // NOTE: Help message lines should not exceed 80 characters for proper display on a console $self['error'] = 'ERROR => Insufficient parameters'; return array(1, <<<EOM domain_add-v{$version} Adds a DNS domain into the database Synopsis: domain_add [KEY=VALUE] ... Required: name=STRING full name of new domain (i.e. name.something.com) Optional: admin=STRING Default ({$conf['dns_admin_email']}) primary_master=STRING Default ({$conf['dns_primary_master']}) refresh=NUMBER Default ({$conf['dns_refresh']}) retry=NUMBER Default ({$conf['dns_retry']}) expiry=NUMBER Default ({$conf['dns_expiry']}) minimum=NUMBER Default ({$conf['dns_minimum']}) parent=DOMAIN_NAME Default ({$conf['dns_parent']}) ttl=NUMBER Default ({$conf['dns_default_ttl']}) EOM ); } // Use default if something was not passed on command line if ($options['admin']) { $admin = $options['admin']; } else { $admin = $conf['dns_admin_email']; } if ($options['primary_master']) { $primary = $options['primary_master']; } else { $primary = $conf['dns_primary_master']; } if ($options['refresh']) { $refresh = $options['refresh']; } else { $refresh = $conf['dns_refresh']; } if ($options['retry']) { $retry = $options['retry']; } else { $retry = $conf['dns_retry']; } if ($options['expiry']) { $expiry = $options['expiry']; } else { $expiry = $conf['dns_expiry']; } if ($options['minimum']) { $minimum = $options['minimum']; } else { $minimum = $conf['dns_minimum']; } if ($options['ttl']) { $ttl = $options['ttl']; } else { $ttl = $conf['dns_default_ttl']; } $options['name'] = trim($options['name']); $options['parent'] = trim($options['parent']); $options['primary_master'] = trim($options['primary_master']); $options['admin'] = trim($options['admin']); // Setup array for searching existing domains $exist_domain = array('name' => $options['name']); // get parent domain info if ($options['parent']) { list($status, $rows, $parent_domain) = ona_find_domain($options['parent'], 0); if (!isset($parent_domain['id'])) { printmsg("DEBUG => The parent domain specified ({$options['parent']}) does not exist!", 3); $self['error'] = "ERROR => The parent domain specified, {$options['parent']}, does not exist!"; return array(5, $self['error'] . "\n"); } // Set up the parent part of the search if there was one $exist_domain['parent_id'] = $parent_domain['id']; } else { $parent_domain['id'] = 0; } // Validate that this domain doesnt already exist list($status, $rows, $record) = ona_get_domain_record($exist_domain); if ($record['id']) { printmsg("DEBUG => The domain specified ({$record['name']}) already exists!", 3); $self['error'] = "ERROR => The domain specified, {$options['name']}, already exists!"; return array(11, $self['error'] . "\n"); } if (is_string($options['name'])) { // FIXME: not sure if its needed but this was calling sanitize_domainname, which did not exist $domain_name = sanitize_hostname($options['name']); if (!is_string($domain_name)) { printmsg("DEBUG => The domain name ({$options['name']}) is invalid!", 3); $self['error'] = "ERROR => The domain name ({$options['name']}) is invalid!"; return array(4, $self['error'] . "\n"); } } // FIXME: MP for now this is removed. it is a chicken/egg issue on setting this name // Also it cant use find_host as the name is not always primary dns name. // if ($primary) { // // Determine the primary master is a valid host // list($status, $rows, $ohost) = ona_find_host($primary); // // if (!$ohost['id']) { // printmsg("DEBUG => The primary master host specified ({$primary}) does not exist!", 3); // $self['error'] = "ERROR => The primary master host specified ({$primary}) does not exist!"; // return(array(2, $self['error'] . "\n")); // } // // } // Check permissions if (!auth('advanced')) { $self['error'] = "Permission denied!"; printmsg($self['error'], 0); return array(10, $self['error'] . "\n"); } // Get the next ID $first_id = $id = ona_get_next_id('domains'); if (!$id) { $self['error'] = "ERROR => The ona_get_next_id('domains') call failed!"; printmsg($self['error'], 0); return array(6, $self['error'] . "\n"); } printmsg("DEBUG => domain_add(): New domain ID: {$id} name: {$domain_name}.{$parent_domain['fqdn']}", 3); // come up with a serial_number // Calculate a serial based on time // concatinate year,month,day,percentage of day // FIXME: MP this needs more work to be more accurate. maybe not use date.. pretty limiting at 10 characters as suggested here: http://www.zytrax.com/books/dns/ch8/soa.html // for now I'm going with non zero padded(zp) month,zp day, zp hour, zp minute, zp second. The only issue I can see at this point with this is when it rolls to january.. // will that be too much of an increment for it to properly zone xfer? i.e. 1209230515 = 12/09 23:05:15 in time format // MP: FOR NOW SERIAL WONT EVER GET USED... LEFT IT IN HERE FOR AWHILE THOUGH $serial_number = date('njHis'); // Add the record list($status, $rows) = db_insert_record($onadb, 'domains', array('id' => $id, 'name' => $domain_name, 'primary_master' => $primary, 'admin_email' => $admin, 'refresh' => $refresh, 'retry' => $retry, 'expiry' => $expiry, 'minimum' => $minimum, 'default_ttl' => $ttl, 'parent_id' => $parent_domain['id'], 'serial' => $serial_number)); if ($status or !$rows) { $self['error'] = "ERROR => domain_add() SQL Query failed: " . $self['error']; printmsg($self['error'], 0); return array(7, $self['error'] . "\n"); } // Return the success notice $self['error'] = "INFO => Domain ADDED: {$domain_name}"; printmsg($self['error'], 0); return array(0, $self['error'] . "\n"); }