array(), 'ipv6' => array()); //$valid['ip-addresses'] = array(); $include_dir = 'includes/discovery/ip-addresses'; $include_order = 'default'; // Use MIBs from default os definitions by first! include($config['install_dir'] . "/includes/include-dir-mib.inc.php"); foreach (get_device_mibs_permitted($device) as $mib) { // Detect addresses by definitions if (is_array($config['mibs'][$mib]['ip-address'])) { print_cli_data_field($mib); foreach ($config['mibs'][$mib]['ip-address'] as $oid_data) { discover_ip_address_definition($device, $mib, $oid_data); } print_cli(PHP_EOL); } } // Try discovery IP addresses in VRF SNMP contexts (currently actual only on Cisco Nexus) if (safe_empty($device['snmp_context']) && // Device not already with context isset($config['os'][$device['os']]['snmp']['virtual']) && $config['os'][$device['os']]['snmp']['virtual'] && // Context permitted for os $vrf_contexts = safe_json_decode(get_entity_attrib('device', $device, 'vrf_contexts'))) { // SNMP VRF context discovered for device // Keep original device array $device_original = $device; foreach ($vrf_contexts as $vrf_name => $snmp_virtual) { print_message("Addresses in Virtual Routing: $vrf_name..."); $device = snmp_virtual_device($device_original, $snmp_virtual); //$device['snmp_context'] = $snmp_context; if (!$device['snmp_retries']) { // force less retries on vrf requests.. if not set in db $device['snmp_retries'] = 1; } $include_dir = 'includes/discovery/ip-addresses'; $include_order = 'default'; // Use MIBs from default os definitions by first! include($config['install_dir']."/includes/include-dir-mib.inc.php"); } // Clean $device = $device_original; unset($device_original); } // Process IP Addresses $table_rows = array(); $check_networks = array(); foreach (array('ipv4', 'ipv6') as $ip_version) { print_debug_vars($ip_data[$ip_version]); // Caching old IP addresses table $query = 'SELECT * FROM `'.$ip_version.'_addresses` WHERE `device_id` = ?'; foreach (dbFetchRows($query, array($device['device_id'])) as $entry) { if (!strlen($entry['ifIndex'])) { // Compatibility $ifIndex = dbFetchCell('SELECT `ifIndex` FROM `ports` WHERE `port_id` = ? AND `deleted` = ?', array($entry['port_id'], 0)); } else { $ifIndex = $entry['ifIndex']; } $old_table[$ip_version][$ifIndex][$entry[$ip_version.'_address']] = $entry; } if (!safe_count($ip_data[$ip_version]) && !safe_count($old_table[$ip_version])) { // Skip if walk and DB empty continue; } // Process founded IP addresses foreach ($ip_data[$ip_version] as $ifIndex => $addresses) { $port = get_port_by_index_cache($device, $ifIndex); if (is_array($port) && !$port['deleted']) { $port_id = $port['port_id']; } else { // Allow to store IP addresses without associated port, but ifIndex available // ie, Nortel/Avaya devices have hidden vlan ifIndexes $port_id = '0'; } print_debug_vars($port); print_debug_vars($addresses); foreach ($addresses as $ip_address => $entry) { if ($ip_version === 'ipv4') { // IPv4 $ip_prefix = $entry['prefix']; $ip_origin = $entry['origin']; $ip_compressed = $ip_address; // just for compat with IPv6 $ip_type = $entry['type']; $addr = Net_IPv4::parseAddress($ip_address.'/'.$ip_prefix); $ip_cidr = $addr->bitmask; $ip_network = $addr->network . '/' . $ip_cidr; $full_address = $ip_address . '/' . $ip_cidr; $new_address = [ 'port_id' => $port_id, 'ifIndex' => $ifIndex, 'device_id' => $device['device_id'], 'ipv4_address' => $ip_address, 'ipv4_binary' => inet_pton($ip_address), 'ipv4_prefixlen' => $ip_cidr, 'ipv4_type' => $ip_type ]; } else { // IPv6 $ip_prefix = $entry['prefix']; $ip_origin = $entry['origin']; $ip_compressed = Net_IPv6::compress($ip_address, TRUE); $full_address = $ip_compressed.'/'.$ip_prefix; $ip_type = $entry['type']; $ip_network = Net_IPv6::getNetmask($full_address) . '/' . $ip_prefix; //$full_compressed = $ip_compressed.'/'.$ipv6_prefixlen; $new_address = [ 'port_id' => $port_id, 'ifIndex' => $ifIndex, 'device_id' => $device['device_id'], 'ipv6_address' => $ip_address, 'ipv6_binary' => inet_pton($ip_address), 'ipv6_compressed' => $ip_compressed, 'ipv6_prefixlen' => $ip_prefix, 'ipv6_type' => $ip_type, 'ipv6_origin' => $ip_origin ]; } // VRFs $sql = "SELECT `vrf_id` FROM `vrfs` WHERE `device_id` = ? AND `vrf_name` = ?"; if (strlen($entry['vrf']) && $vrf_id = dbFetchCell($sql, [ $device['device_id'], $entry['vrf'] ])) { $new_address['vrf_id'] = $vrf_id; } // Check network $ip_network_id = dbFetchCell('SELECT `'.$ip_version.'_network_id` FROM `'.$ip_version.'_networks` WHERE `'.$ip_version.'_network` = ?', array($ip_network)); if (empty($ip_network_id)) { // Add new network $ip_network_id = dbInsert(array($ip_version.'_network' => $ip_network), $ip_version.'_networks'); //echo('N'); } $new_address[$ip_version.'_network_id'] = $ip_network_id; // Add to display table $table_rows[] = array($ifIndex, truncate($port['ifDescr'], 30), nicecase($ip_version), $full_address, $ip_network, $entry['type'], $ip_origin); // Check IP in DB $update_array = array(); if (isset($old_table[$ip_version][$ifIndex][$ip_address])) { $old_address = &$old_table[$ip_version][$ifIndex][$ip_address]; $ip_address_id = $old_address[$ip_version.'_address_id']; $params = array_diff(array_keys($old_address), [ 'device_id', $ip_version.'_address_id' ]); foreach ($params as $param) { if ($param === 'ipv6_binary') { // Compare decoded binary IPv6 address if (inet_ntop($old_address[$param]) != $new_address['ipv6_compressed']) { $update_array[$param] = $new_address[$param]; } } elseif ($param === 'ipv4_binary') { // Compare decoded binary IPv4 address if (inet_ntop($old_address[$param]) != $new_address['ipv4_address']) { $update_array[$param] = $new_address[$param]; } } else { // All other params as string if ($old_address[$param] != $new_address[$param]) { if (in_array($param, [ 'vrf_id', 'ifIndex', $ip_version.'_type' ]) && !strlen($new_address[$param])) { $update_array[$param] = [ 'NULL' ]; } else { $update_array[$param] = $new_address[$param]; } } } } $update_count = count($update_array); if ($update_count === 1 && (isset($update_array['ipv4_binary']) || isset($update_array['ipv6_binary']))) { // Silent update binary address after upgrade dbUpdate($update_array, $ip_version.'_addresses', '`'.$ip_version.'_address_id` = ?', array($old_address[$ip_version.'_address_id'])); $GLOBALS['module_stats'][$module]['unchanged']++; } elseif ($update_count) { // Updated dbUpdate($update_array, $ip_version.'_addresses', '`'.$ip_version.'_address_id` = ?', array($old_address[$ip_version.'_address_id'])); if (!$port_id) { log_event("IP address changed: $ip_compressed/".$old_address[$ip_version.'_prefixlen']." -> $full_address", $device, 'device', $device['device_id']); } else if (isset($update_array['port_id'])) { // Address moved to another port log_event("IP address removed: $ip_compressed/".$old_address[$ip_version.'_prefixlen'], $device, 'port', $old_address['port_id']); log_event("IP address added: $full_address", $device, 'port', $port_id); } else { // Changed prefix/cidr log_event("IP address changed: $ip_compressed/".$old_address[$ip_version.'_prefixlen']." -> $full_address", $device, 'port', $port_id); } $GLOBALS['module_stats'][$module]['updated']++; //echo "U"; $check_networks[$ip_version][$ip_network_id] = 1; } else { // Not changed $GLOBALS['module_stats'][$module]['unchanged']++; //echo "."; } } else { // New IP $update_array = $new_address; $ip_address_id = dbInsert($update_array, $ip_version.'_addresses'); if ($port_id) { log_event("IP address added: $full_address", $device, 'port', $port_id); } else { log_event("IP address added: $full_address", $device, 'device', $device['device_id']); } $GLOBALS['module_stats'][$module]['added']++; //echo "+"; } $valid[$ip_version][$ip_address_id] = $full_address . ':' . $port_id; } } // Refetch and clean IP addresses from DB foreach (dbFetchRows($query, array($device['device_id'])) as $entry) { $ip_address_id = $entry[$ip_version.'_address_id']; if (!isset($valid[$ip_version][$ip_address_id])) { $full_address = ($ip_version === 'ipv4' ? $entry['ipv4_address'] : $entry['ipv6_compressed']); $full_address .= '/' . $entry[$ip_version.'_prefixlen']; // Delete IP dbDelete($ip_version.'_addresses', '`'.$ip_version.'_address_id` = ?', array($ip_address_id)); if ($port_id) { log_event("IP address removed: $full_address", $device, 'port', $entry['port_id']); } else { log_event("IP address removed: $full_address", $device, 'device', $entry['device_id']); } $GLOBALS['module_stats'][$module]['deleted']++; //echo "-"; $check_networks[$ip_version][$entry[$ip_version.'_network_id']] = 1; } } // Clean networks foreach ($check_networks[$ip_version] as $ip_network_id => $n) { //$count = dbFetchCell('SELECT COUNT(*) FROM `'.$ip_version.'_addresses` WHERE `'.$ip_version.'_network_id` = ?', array($ip_network_id)); //if (empty($count)) if (!dbExist($ip_version.'_addresses', '`'.$ip_version.'_network_id` = ?', array($ip_network_id))) { dbDelete($ip_version.'_networks', '`'.$ip_version.'_network_id` = ?', array($ip_network_id)); //echo('n'); } } } $table_headers = array('%WifIndex%n', '%WifDescr%n', '%WIP: Version%n', '%WAddress%n', '%WNetwork%n', '%WType%n', '%WOrigin%n'); print_cli_table($table_rows, $table_headers); // Clean unset($ip_data, $check_networks, $check_ipv6_mib, $update_array, $old_table, $table_rows, $table_headers); // EOF