Пример #1
0
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");
}
Пример #2
0
function ws_display_list($window_name, $form = '')
{
    global $conf, $self, $onadb;
    global $images, $color, $style;
    $html = '';
    $js = '';
    // If the user supplied an array in a string, transform it into an array
    $form = parse_options_string($form);
    // Find the "tab" we're on
    $tab = $_SESSION['ona'][$form['form_id']]['tab'];
    // Build js to refresh this list
    $refresh = "xajax_window_submit('{$window_name}', xajax.getFormValues('{$form['form_id']}'), 'display_list');";
    // If it's not a new query, load the previous query from the session
    // into $form and save the current page and filter in the session.
    // Also find/set the "page" we're viewing
    $page = 1;
    if ($form['page'] and is_numeric($form['page'])) {
        $form = array_merge($form, (array) $_SESSION['ona'][$form['form_id']][$tab]['q']);
        $_SESSION['ona'][$form['form_id']][$tab]['page'] = $page = $form['page'];
        $_SESSION['ona'][$form['form_id']][$tab]['filter'] = $form['filter'];
    }
    printmsg("DEBUG => Displaying records list page: {$page}", 1);
    // Calculate the SQL query offset (based on the page being displayed)
    $offset = $conf['search_results_per_page'] * ($page - 1);
    if ($offset == 0) {
        $offset = -1;
    }
    // Search results go in here
    $results = array();
    $count = 0;
    //
    // *** ADVANCED RECORD SEARCH ***
    //       FIND RESULT SET
    //
    // Start building the "where" clause for the sql query to find the records to display
    $where = "";
    $and = "";
    $orderby = "";
    // enable or disable wildcards
    $wildcard = '%';
    if ($form['nowildcard']) {
        $wildcard = '';
    }
    // RECORD ID
    if ($form['record_id']) {
        $where .= $and . "id = " . $onadb->qstr($form['record_id']);
        $and = " AND ";
    }
    // DNS VIEW ID
    if ($form['dns_view']) {
        if (is_string($form['dns_view'])) {
            list($status, $rows, $dnsview) = ona_get_dns_view_record(array('name' => $form['dns_view']));
        }
        if (is_numeric($form['dns_view'])) {
            list($status, $rows, $dnsview) = ona_get_dns_view_record(array('id' => $form['dns_view']));
        }
        $where .= $and . "dns_view_id = " . $onadb->qstr($dnsview['id']);
        $and = " AND ";
    }
    // INTERFACE ID
    if ($form['interface_id']) {
        $where .= $and . "interface_id = " . $onadb->qstr($form['interface_id']);
        $and = " AND ";
    }
    // DNS RECORD note
    if ($form['notes']) {
        $where .= $and . "notes LIKE " . $onadb->qstr($wildcard . $form['notes'] . $wildcard);
        $and = " AND ";
    }
    // DNS RECORD TYPE
    if ($form['dnstype']) {
        $where .= $and . "type = " . $onadb->qstr($form['dnstype']);
        $and = " AND ";
    }
    // HOSTNAME
    if ($form['hostname']) {
        $where .= $and . "id IN (SELECT id " . "  FROM dns " . "  WHERE name LIKE " . $onadb->qstr($wildcard . $form['hostname'] . $wildcard) . " )";
        $and = " AND ";
    }
    // DOMAIN
    if ($form['domain']) {
        // FIXME: MP test if this clause works correctly?  Not sure that anything even uses this?
        list($status, $rows, $tmpdomain) = ona_find_domain($form['domain']);
        $where .= $and . "domain_id = " . $onadb->qstr($tmpdomain['id']);
        $orderby .= "name, domain_id";
        $and = " AND ";
    }
    // DOMAIN ID
    if ($form['domain_id']) {
        //$where .= $and . "primary_dns_id IN ( SELECT id " .
        //                                    "  FROM dns " .
        //                                    "  WHERE domain_id = " . $onadb->qstr($form['domain_id']) . " )  ";
        $where .= $and . "domain_id = " . $onadb->qstr($form['domain_id']);
        $orderby .= "name, domain_id";
        $and = " AND ";
    }
    // IP ADDRESS
    $ip = $ip_end = '';
    if ($form['ip']) {
        // Build $ip and $ip_end from $form['ip'] and $form['ip_thru']
        $ip = ip_complete($form['ip'], '0');
        if ($form['ip_thru']) {
            $ip_end = ip_complete($form['ip_thru'], '255');
        } else {
            $ip_end = ip_complete($form['ip'], '255');
        }
        // Find out if $ip and $ip_end are valid
        $ip = ip_mangle($ip, 'numeric');
        $ip_end = ip_mangle($ip_end, 'numeric');
        if ($ip != -1 and $ip_end != -1) {
            // We do a sub-select to find interface id's between the specified ranges
            $where .= $and . "interface_id IN ( SELECT id " . "        FROM interfaces " . "        WHERE ip_addr >= " . $onadb->qstr($ip) . " AND ip_addr <= " . $onadb->qstr($ip_end) . " )";
            $and = " AND ";
        }
    }
    // display a nice message when we dont find all the records
    if ($where == '' and $form['content_id'] == 'search_results_list') {
        $js .= "el('search_results_msg').innerHTML = 'Unable to find DNS records matching your query, showing all records';";
    }
    // Wild card .. if $while is still empty, add a 'ID > 0' to it so you see everything.
    if ($where == '') {
        $where = 'id > 0';
    }
    // If we dont have DNS views turned on, limit data to just the default view.
    // Even if there is data associated with other views, ignore it
    if (!$conf['dns_views']) {
        $where .= ' AND dns_view_id = 0';
    }
    // Do the SQL Query
    $filter = '';
    if ($form['filter']) {
        // Host names should always be lower case
        $form['filter'] = strtolower($form['filter']);
        $filter = ' AND name LIKE ' . $onadb->qstr('%' . $form['filter'] . '%');
    }
    // If we get a specific host to look for we must do the following
    // 1. get (A) records that match any interface_id associated with the host
    // 2. get CNAMES that point to dns records that are using an interface_id associated with the host
    if ($form['host_id']) {
        // If we dont have DNS views turned on, limit data to just the default view.
        // Even if there is data associated with other views, ignore it
        // MP: something strange with this, it should only limit to default view.. sometimes it does not???
        if (!$conf['dns_views']) {
            $hwhere .= 'dns_view_id = 0 AND ';
        }
        // Get the host record so we know what the primary interface is
        list($status, $rows, $host) = ona_get_host_record(array('id' => $form['host_id']), '');
        list($status, $rows, $results) = db_get_records($onadb, 'dns', $hwhere . 'interface_id in (select id from interfaces where host_id = ' . $onadb->qstr($form['host_id']) . ') OR interface_id in (select interface_id from interface_clusters where host_id = ' . $onadb->qstr($form['host_id']) . ')', "type", $conf['search_results_per_page'], $offset);
        // If we got less than search_results_per_page, add the current offset to it
        // so that if we're on the last page $rows still has the right number in it.
        if ($rows > 0 and $rows < $conf['search_results_per_page']) {
            $rows += $conf['search_results_per_page'] * ($page - 1);
        } else {
            if ($rows >= $conf['search_results_per_page']) {
                list($status, $rows, $records) = db_get_records($onadb, 'dns', $hwhere . 'interface_id in (select id from interfaces where host_id = ' . $onadb->qstr($form['host_id']) . ') OR interface_id in (select interface_id from interface_clusters where host_id = ' . $onadb->qstr($form['host_id']) . ')' . $filter, "", 0);
            }
        }
    } else {
        list($status, $rows, $results) = db_get_records($onadb, 'dns', $where . $filter, $orderby, $conf['search_results_per_page'], $offset);
        // If we got less than search_results_per_page, add the current offset to it
        // so that if we're on the last page $rows still has the right number in it.
        if ($rows > 0 and $rows < $conf['search_results_per_page']) {
            $rows += $conf['search_results_per_page'] * ($page - 1);
        } else {
            if ($rows >= $conf['search_results_per_page']) {
                list($status, $rows, $records) = db_get_records($onadb, 'dns', $where . $filter, "", 0);
            }
        }
    }
    $count = $rows;
    //
    // *** BUILD HTML LIST ***
    //
    $html .= <<<EOL
        <!-- dns record Results -->
        <table id="{$form['form_id']}_dns_record_list" class="list-box" cellspacing="0" border="0" cellpadding="0">

            <!-- Table Header -->
            <tr>

                <td colspan="2" class="list-header" align="center" style="{$style['borderR']};">Name</td>
                <td class="list-header" align="center" style="{$style['borderR']};">Time to Live</td>
                <td class="list-header" align="center" style="{$style['borderR']};">Type</td>
                <td class="list-header" align="center" style="{$style['borderR']};">Data</td>
                <td class="list-header" align="center" style="{$style['borderR']};">Effective</td>
EOL;
    if ($conf['dns_views']) {
        $html .= "<td class=\"list-header\" align=\"center\" style=\"{$style['borderR']};\">DNS View</td>";
    }
    $html .= <<<EOL
                <td class="list-header" align="center" style="{$style['borderR']};">Notes</td>
                <td class="list-header" align="center">&nbsp;</td>
            </tr>
EOL;
    // Loop and display each record
    //  $last_record = array('name' => $results[0]['name'], 'domain_id' => $results[0]['domain_id']);
    //  $last_record_count = 0;
    for ($i = 1; $i <= count($results); $i++) {
        $record = $results[$i];
        // Get additional info about each host record
        $record = $results[$i - 1];
        // if the interface is the primary_dns_id for the host then mark it
        $primary_record = '&nbsp;';
        if ($host['primary_dns_id'] == $record['id']) {
            $primary_record = '<img title="Primary DNS record" src="' . $images . '/silk/font_go.png" border="0">';
        }
        // Check for interface records (and find out how many there are)
        list($status, $interfaces, $interface) = ona_get_interface_record(array('id' => $record['interface_id']), '');
        if ($interfaces) {
            // Get the host record so we know what the primary interface is
            //list($status, $rows, $inthost) = ona_get_host_record(array('id' => $interface['host_id']), '');
            // Make the type correct based on the IP passed in
            if (strlen($interface['ip_addr']) > 11 and $record['type'] == 'A') {
                $record['type'] = 'AAAA';
            }
            $record['ip_addr'] = ip_mangle($interface['ip_addr'], 'dotted');
            // Subnet description
            list($status, $rows, $subnet) = ona_get_subnet_record(array('id' => $interface['subnet_id']));
            $record['subnet'] = $subnet['name'];
            $record['ip_mask'] = ip_mangle($subnet['ip_mask'], 'dotted');
            $record['ip_mask_cidr'] = ip_mangle($subnet['ip_mask'], 'cidr');
            // Create string to be embedded in HTML for display
            $data = <<<EOL
                        {$record['ip_addr']}&nbsp;

EOL;
        } else {
            // Get other DNS records which name this record as parent
            list($status, $rows, $dns_other) = ona_get_host_record(array('id' => $record['dns_id']));
            // Create string to be embedded in HTML for display
            if ($rows) {
                $data = <<<EOL
                <a title="View host. ID: {$dns_other['id']}"
                    class="nav"
                    onClick="xajax_window_submit('work_space', 'xajax_window_submit(\\'display_host\\', \\'host_id=>{$dns_other['id']}\\', \\'display\\')');"
                >{$dns_other['name']}</a
                >.<a title="View domain. ID: {$dns_other['domain_id']}"
                        class="domain"
                        onClick="xajax_window_submit('work_space', 'xajax_window_submit(\\'display_domain\\', \\'domain_id=>{$dns_other['domain_id']}\\', \\'display\\')');"
                >{$dns_other['domain_fqdn']}</a>&nbsp;
EOL;
            }
        }
        $record['notes_short'] = truncate($record['notes'], 30);
        // Add a dot to the end of record name for display purposes
        $record['name'] = $record['name'] . '.';
        // Process PTR record
        if ($record['type'] == 'PTR') {
            list($status, $rows, $pointsto) = ona_get_dns_record(array('id' => $record['dns_id']), '');
            list($status, $rows, $pdomain) = ona_get_domain_record(array('id' => $record['domain_id']), '');
            // Flip the IP address
            $record['name'] = ip_mangle($record['ip_addr'], 'flip');
            $record['domain'] = $pdomain['name'];
            if ($pdomain['parent_id']) {
                list($status, $rows, $parent) = ona_get_domain_record(array('id' => $pdomain['parent_id']));
                $parent['name'] = ona_build_domain_name($parent['id']);
                $record['domain'] = $pdomain['name'] . '.' . $parent['name'];
                unset($parent['name']);
            }
            // strip down the IP to just the "host" part as it relates to the domain its in
            if (strstr($record['domain'], 'in-addr.arpa')) {
                $domain_part = preg_replace("/.in-addr.arpa\$/", '', $record['domain']);
            } else {
                $domain_part = preg_replace("/.ip6.arpa\$/", '', $record['domain']);
            }
            $record['name'] = preg_replace("/{$domain_part}\$/", '', $record['name']);
            $data = <<<EOL
                    <a title="Edit DNS A record"
                       class="act"
                       onClick="xajax_window_submit('edit_record', 'dns_record_id=>{$record['dns_id']}', 'editor');"
                    >{$pointsto['name']}</a>.<a title="View domain. ID: {$pointsto['domain_id']}"
                         class="domain"
                         onClick="xajax_window_submit('work_space', 'xajax_window_submit(\\'display_domain\\', \\'domain_id=>{$pointsto['domain_id']}\\', \\'display\\')');"
                    >{$pointsto['domain_fqdn']}</a>.&nbsp;
EOL;
        }
        // Process CNAME record
        if ($record['type'] == 'CNAME') {
            list($status, $rows, $cname) = ona_get_dns_record(array('id' => $record['dns_id']), '');
            $data = <<<EOL
                    <a title="Edit DNS A record"
                       class="act"
                       onClick="xajax_window_submit('edit_record', 'dns_record_id=>{$record['dns_id']}', 'editor');"
                    >{$cname['name']}</a>.<a title="View domain. ID: {$cname['domain_id']}"
                         class="domain"
                         onClick="xajax_window_submit('work_space', 'xajax_window_submit(\\'display_domain\\', \\'domain_id=>{$cname['domain_id']}\\', \\'display\\')');"
                    >{$cname['domain_fqdn']}</a>.&nbsp;
EOL;
        }
        // Process NS record
        if ($record['type'] == 'NS') {
            // clear out the $record['domain'] value so it shows properly in the list
            $record['name'] = '';
            list($status, $rows, $ns) = ona_get_dns_record(array('id' => $record['dns_id']), '');
            $data = <<<EOL
                    <a title="Edit DNS A record"
                       class="act"
                       onClick="xajax_window_submit('edit_record', 'dns_record_id=>{$record['dns_id']}', 'editor');"
                    >{$ns['name']}</a>.<a title="View domain. ID: {$ns['domain_id']}"
                         class="domain"
                         onClick="xajax_window_submit('work_space', 'xajax_window_submit(\\'display_domain\\', \\'domain_id=>{$ns['domain_id']}\\', \\'display\\')');"
                    >{$ns['domain_fqdn']}</a>.&nbsp;
EOL;
        }
        // Process MX record
        if ($record['type'] == 'MX') {
            // show the preference value next to the type
            $record['type'] = "{$record['type']} ({$record['mx_preference']})";
            list($status, $rows, $mx) = ona_get_dns_record(array('id' => $record['dns_id']), '');
            $data = <<<EOL
                    <a title="Edit DNS A record"
                       class="act"
                       onClick="xajax_window_submit('edit_record', 'dns_record_id=>{$record['dns_id']}', 'editor');"
                    >{$mx['name']}</a>.<a title="View domain. ID: {$mx['domain_id']}"
                         class="domain"
                         onClick="xajax_window_submit('work_space', 'xajax_window_submit(\\'display_domain\\', \\'domain_id=>{$mx['domain_id']}\\', \\'display\\')');"
                    >{$mx['domain_fqdn']}</a>.&nbsp;
EOL;
        }
        // Process SRV record
        if ($record['type'] == 'SRV') {
            // show the preference value next to the type
            $record['type'] = "{$record['type']} ({$record['srv_port']})";
            list($status, $rows, $srv) = ona_get_dns_record(array('id' => $record['dns_id']), '');
            $data = <<<EOL
                    <a title="Edit DNS A record"
                       class="act"
                       onClick="xajax_window_submit('edit_record', 'dns_record_id=>{$record['dns_id']}', 'editor');"
                    >{$srv['name']}</a>.<a title="View domain. ID: {$srv['domain_id']}"
                         class="domain"
                         onClick="xajax_window_submit('work_space', 'xajax_window_submit(\\'display_domain\\', \\'domain_id=>{$srv['domain_id']}\\', \\'display\\')');"
                    >{$srv['domain_fqdn']}</a>.&nbsp;
EOL;
        }
        // Process TXT record
        if ($record['type'] == 'TXT') {
            // some records will have an interfaceid and dnsid when associated to another dns name
            // some will just be un associated txt records or domain only records.  Determine that here and
            // display appropriately.  This is to ensure associated DNS records match up if the name changes
            if ($record['interface_id'] and $record['dns_id']) {
                list($status, $rows, $txtmain) = ona_get_dns_record(array('id' => $record['dns_id']), '');
                $record['name'] = $txtmain['name'] . '.';
            }
            $data = truncate($record['txt'], 70);
        }
        // Get the domain name and domain ttl
        $ttl_style = 'title="Time-to-Live"';
        list($status, $rows, $domain) = ona_get_domain_record(array('id' => $record['domain_id']));
        // Make record['domain'] have the right name in it
        if ($record['type'] != 'PTR') {
            $record['domain'] = $domain['fqdn'];
        }
        // clear out the $record['domain'] value so it shows properly in the list for NS records
        if ($record['type'] == 'NS') {
            $record['domain'] = $domain['fqdn'];
        }
        // if the ttl is blank, use the one in the domain (minimum)
        if ($record['ttl'] == 0) {
            $record['ttl'] = $domain['default_ttl'];
            $ttl_style = 'style="font-style: italic;" title="Using TTL from domain"';
        }
        // format the ebegin using the configured date format
        $ebegin = '';
        // If it is in the future, print the time
        if (strtotime($record['ebegin']) > time()) {
            $ebegin = '<span title="Active in DNS on: ' . $record['ebegin'] . '">' . date($conf['date_format'], strtotime($record['ebegin'])) . '</span>';
        }
        // If it is 0 then show as disabled
        if (strtotime($record['ebegin']) < 0) {
            $ebegin = <<<EOL
                <span
                    style="background-color:#FFFF99;"
                    title="Disabled: Won't build in DNS"
                    onClick="var doit=confirm('Are you sure you want to enable this DNS record?');
                                if (doit == true)
                                    xajax_window_submit('edit_record', xajax.getFormValues('{$form['form_id']}_list_record_{$record['id']}'), 'enablerecord');"
                >Disabled</span>
EOL;
        }
        // If we get this far and the name we have built has a leading . in it then remove the dot.
        $record['name'] = preg_replace("/^\\./", '', $record['name']);
        // Get the name of the view and the description
        if ($conf['dns_views']) {
            list($status, $rows, $dnsview) = ona_get_dns_view_record(array('id' => $record['dns_view_id']));
            $record['view_name'] = $dnsview['name'];
            $record['view_desc'] = $dnsview['description'];
        }
        // Escape data for display in html
        foreach (array_keys($record) as $key) {
            $record[$key] = htmlentities($record[$key], ENT_QUOTES, $conf['php_charset']);
        }
        //$primary_object_js = "xajax_window_submit('work_space', 'xajax_window_submit(\'display_host\', \'host_id=>{$record['id']}\', \'display\')');";
        $html .= <<<EOL
            <tr onMouseOver="this.className='row-highlight';" onMouseOut="this.className='row-normal';">
                <td class="list-row" style="padding-right: 2px; padding-left: 4px;" width="16px">
                {$primary_record}
                </td>

                <td class="list-row">
                    <span title="Record. ID: {$record['id']}"
                       onClick=""
                    >{$record['name']}</span
                    ><a title="View domain. ID: {$domain['id']}"
                         class="domain"
                         onClick="xajax_window_submit('work_space', 'xajax_window_submit(\\'display_domain\\', \\'domain_id=>{$domain['id']}\\', \\'display\\')');"
                    >{$record['domain']}.</a>
                </td>

                <td class="list-row">
                    <span
                       onClick=""
                       {$ttl_style}
                    >{$record['ttl']} seconds</span>&nbsp;
                </td>

                <td class="list-row">
                    <span title="Record Type"
                       onClick=""
                    >{$record['type']}</span>&nbsp;
                </td>

                <td class="list-row" align="left">
EOL;
        // Put the data in!
        $html .= $data;
        $html .= <<<EOL
                </td>

                <td class="list-row" align="center">
                    {$ebegin}&nbsp;
                </td>
EOL;
        // Display the view we are part of
        if ($conf['dns_views']) {
            $html .= <<<EOL
                <td class="list-row" align="center" title="{$record['view_desc']}">
                    {$record['view_name']}&nbsp;
                </td>
EOL;
        }
        $html .= <<<EOL
                <td class="list-row">
                    <span title="{$record['notes']}">{$record['notes_short']}</span>&nbsp;
                </td>

                <!-- ACTION ICONS -->
                <td class="list-row" align="right">
                    <form id="{$form['form_id']}_list_record_{$record['id']}"
                        ><input type="hidden" name="dns_record_id" value="{$record['id']}"
                        ><input type="hidden" name="host_id" value="{$host['id']}"
                        ><input type="hidden" name="js" value="{$refresh}"
                    ></form>&nbsp;
EOL;
        if (auth('dns_record_modify')) {
            // If it is an A record but not the primary, display an option to make it primary. and only if we are dealing with a specific host
            if (($record['type'] == 'A' or $record['type'] == 'AAAA') and $host['primary_dns_id'] != $record['id'] and $form['host_id']) {
                $html .= <<<EOL

                    <a title="Make this the primary DNS record"
                       class="act"
                       onClick="var doit=confirm('Are you sure you want to make this the primary DNS record for this host?');
                                if (doit == true)
                                    xajax_window_submit('edit_record', xajax.getFormValues('{$form['form_id']}_list_record_{$record['id']}'), 'makeprimary');"
                    ><img src="{$images}/silk/font_go.png" border="0"></a>
EOL;
            }
        }
        // display a view host button on the dns record search form list
        if ($form['search_form_id'] == 'dns_record_search_form') {
            $html .= <<<EOL

                    <a title="View associated host record: {$interface['host_id']}"
                       class="act"
                       onClick="xajax_window_submit('display_host', 'host_id=>{$interface['host_id']}', 'display');"
                    ><img src="{$images}/silk/computer_go.png" border="0"></a>&nbsp;
EOL;
        }
        if (auth('dns_record_modify')) {
            $html .= <<<EOL

                    <a title="Edit DNS record"
                       class="act"
                       onClick="xajax_window_submit('edit_record', xajax.getFormValues('{$form['form_id']}_list_record_{$record['id']}'), 'editor');"
                    ><img src="{$images}/silk/page_edit.png" border="0"></a>&nbsp;
EOL;
        }
        if (auth('dns_record_del')) {
            $html .= <<<EOL

                    <a title="Delete DNS record"
                       class="act"
                       onClick="xajax_window_submit('edit_record', xajax.getFormValues('{$form['form_id']}_list_record_{$record['id']}'), 'delete');"
                    ><img src="{$images}/silk/delete.png" border="0"></a>
EOL;
        }
        $html .= <<<EOL
                    &nbsp;
                </td>

            </tr>
EOL;
        // reset the record counter before we go back for the next iteration
        $last_record = array('name' => $record['name'], 'domain_id' => $record['domain_id']);
        $last_record_count = 1;
    }
    $html .= <<<EOL
    </table>
EOL;
    // Build page links if there are any
    $html .= get_page_links($page, $conf['search_results_per_page'], $count, $window_name, $form['form_id']);
    // Insert the new html into the content div specified
    // Instantiate the xajaxResponse object
    $response = new xajaxResponse();
    $response->addAssign("{$form['form_id']}_{$tab}_count", "innerHTML", "({$count})");
    $response->addAssign($form['content_id'], "innerHTML", $html);
    if ($js) {
        $response->addScript($js);
    }
    return $response->getXML();
}