Commit version 24.12.13800

This commit is contained in:
2025-01-06 17:35:06 -05:00
parent b7f6a79c2c
commit 55d9218816
6133 changed files with 4239740 additions and 1374287 deletions

View File

@ -4,9 +4,9 @@
*
* This file is part of Observium.
*
* @package observium
* @subpackage discovery
* @copyright (C) 2006-2013 Adam Armstrong, (C) 2013-2022 Observium Limited
* @package observium
* @subpackage discovery
* @copyright (C) Adam Armstrong
*
*/
@ -18,171 +18,152 @@
// CISCO-IETF-IP-MIB -- based on an early draft of the revised IP-MIB
// cInetNetToMediaTable
unset($mac_table);
$mac_table = [];
// Caching ifIndex
$query = 'SELECT `port_id`, `ifIndex` FROM `ports` WHERE `device_id` = ? GROUP BY `port_id`';
foreach (dbFetchRows($query, array($device['device_id'])) as $entry) {
$entry_if = $entry['ifIndex'];
$interface[$entry_if] = $entry['port_id'];
}
$include_dir = 'includes/discovery/arp';
$include_order = 'default'; // Use MIBs from default os definitions by first!
/// FIXME. Here necessary to use snmpwalk_cache_oid, but snmpwalk_cache_oid() not support custom options like (-OXqs) for parser. -- mike
/// Duplicate the function to use -OX. The SNMP specific stuff is all elsewhere, so shouldn't be too much duplicated -- adama
$vrf_name = '';
include($config['install_dir'] . "/includes/include-dir-mib.inc.php");
// FIXME check is_device_mib first!
// First check IP-MIB::ipNetToPhysicalPhysAddress (IPv4 & IPv6)
//ipNetToPhysicalPhysAddress[5][ipv4]["80.93.52.129"] 0:23:ab:64:d:42
//ipNetToPhysicalPhysAddress[34][ipv6]["2a:01:00:d8:00:00:00:01:00:00:00:00:00:00:00:03"] 0:15:63:e8:fb:31:0:0
$ipNetToPhysicalPhysAddress_oid = snmp_walk($device, 'ipNetToPhysicalPhysAddress', '-OXqs', 'IP-MIB');
if ($ipNetToPhysicalPhysAddress_oid)
{
$oid_data = $ipNetToPhysicalPhysAddress_oid;
print_debug("Used IP-MIB::ipNetToPhysicalPhysAddress");
} else {
$oid_data = '';
if ($device['os_group'] === 'cisco')
{
// Last check CISCO-IETF-IP-MIB::cInetNetToMediaPhysAddress (IPv6 only, Cisco only)
//cInetNetToMediaPhysAddress[167][ipv6]["20:01:0b:08:0b:08:0b:08:00:00:00:00:00:00:00:b1"] 0:24:c4:db:9b:40:0:0
$cInetNetToMediaPhysAddress_oid = snmp_walk($device, 'cInetNetToMediaPhysAddress', '-OXqs', 'CISCO-IETF-IP-MIB');
if ($cInetNetToMediaPhysAddress_oid)
{
$oid_data .= $cInetNetToMediaPhysAddress_oid;
print_debug("Used CISCO-IETF-IP-MIB::cInetNetToMediaPhysAddress");
// Try discovery ARP addresses in VRF SNMP contexts
if ($vrf_contexts = get_device_vrf_contexts($device)) { // SNMP VRF context discovered for device
// Keep original device array
$device_original = $device;
foreach ($vrf_contexts as $vrf_name => $snmp_virtual) {
print_message("ARP 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/arp';
$include_order = 'default'; // Use MIBs from default os definitions by first!
include($config['install_dir'] . "/includes/include-dir-mib.inc.php");
}
} else {
// Or check IPV6-MIB::ipv6NetToMediaPhysAddress (IPv6 only, deprecated, junos)
//ipv6NetToMediaPhysAddress[18][fe80:0:0:0:200:ff:fe00:4] 2:0:0:0:0:4
$ipv6NetToMediaPhysAddress_oid = snmp_walk($device, 'ipv6NetToMediaPhysAddress', '-OXqs', 'IPV6-MIB');
if ($ipv6NetToMediaPhysAddress_oid)
{
$oid_data .= $ipv6NetToMediaPhysAddress_oid;
print_debug("Used IPV6-MIB::ipv6NetToMediaPhysAddress");
}
}
// Clean
$device = $device_original;
unset($device_original);
}
if (!str_contains($oid_data, 'ipv4'))
{
// Check IP-MIB::ipNetToMediaPhysAddress (IPv4 only)
//ipNetToMediaPhysAddress[213][10.0.0.162] 70:81:5:ec:f9:bf
$ipNetToMediaPhysAddress_oid = snmp_walk($device, 'ipNetToMediaPhysAddress', '-OXqs', 'IP-MIB');
if ($ipNetToMediaPhysAddress_oid)
{
$oid_data .= $ipNetToMediaPhysAddress_oid;
print_debug("Used IP-MIB::ipNetToMediaPhysAddress");
}
}
$oid_data = trim($oid_data);
print_debug_vars($mac_table);
// Caching old ARP/NDP table
$query = 'SELECT mac_id, mac_address, ip_address, ip_version, ifIndex FROM ip_mac AS M
LEFT JOIN ports AS I ON M.port_id = I.port_id
WHERE I.device_id = ?';
$cache_arp = dbFetchRows($query, array($device['device_id']));
foreach ($cache_arp as $entry)
{
$old_if = $entry['ifIndex'];
$old_mac = $entry['mac_address'];
$old_address = $entry['ip_address'];
$old_version = $entry['ip_version'];
$old_table[$old_if][$old_version][$old_address] = $old_mac;
if (get_db_version() < 482) {
print_error("Need update DB schema: ./discovery.php -u");
}
$ipv4_pattern = '/\[(\d+)\](?:\[ipv4\])?\["?([\d\.]+)"?\]\s+([a-f\d]+):([a-f\d]+):([a-f\d]+):([a-f\d]+):([a-f\d]+):([a-f\d]{1,2})/i';
$ipv6_pattern = '/\[(\d+)\](?:\[ipv6\])?\["?([a-f\d:]+)"?\]\s+(?:([a-f\d]+):([a-f\d]+):)?([a-f\d]+):([a-f\d]+):([a-f\d]+):([a-f\d]{1,2})/i';
$query = 'SELECT * FROM `ip_mac` WHERE `device_id` = ?';
$old_table = [];
foreach (dbFetchRows($query, [$device['device_id']]) as $entry) {
$old_if = $entry['mac_ifIndex'];
$old_mac = $entry['mac_address'];
$old_address = $entry['ip_address'];
$old_version = 'ipv' . $entry['ip_version'];
$old_vrf = !safe_empty($entry['virtual_name']) ? $entry['virtual_name'] : '';
foreach (explode("\n", $oid_data) as $data)
{
if (preg_match($ipv4_pattern, $data, $matches))
{
$ip = $matches[2];
$ip_version = 4;
}
elseif (preg_match($ipv6_pattern, $data, $matches))
{
if (count(explode(':', $matches[2])) === 8)
{
$ip = Net_IPv6::uncompress($matches[2], TRUE);
$old_table[$old_vrf][$old_version][$old_if][$old_address] = ['mac' => $old_mac, 'mac_id' => $entry['mac_id']];
}
print_debug_vars($old_table);
$table_rows = [];
foreach ($mac_table as $vrf_name => $entry1) {
foreach ($entry1 as $ip_version => $entry2) {
foreach ($entry2 as $ifIndex => $entry3) {
$port_vrf_name = $vrf_name;
if ($port = get_port_by_index_cache($device, $ifIndex)) {
$port_id = $port['port_id'];
if ($port['ifVrf']) {
// Set VRF name by port associated vrf
$port_vrf_name = dbFetchCell('SELECT `vrf_name` FROM `vrfs` WHERE `device_id` = ? AND `vrf_id` = ?', [$device['device_id'], $port['ifVrf']]);
}
} else {
// That possible with VRF discovery
print_debug("Not found port for ifIndex: $ifIndex");
$port_id = ['NULL'];
}
foreach ($entry3 as $ip => $clean_mac) {
if (isset($old_table[$port_vrf_name][$ip_version][$ifIndex][$ip])) {
// Already exist
$entry = $old_table[$port_vrf_name][$ip_version][$ifIndex][$ip];
$old_mac = $entry['mac'];
if ($clean_mac !== $old_mac && $clean_mac !== '000000000000' && $old_mac !== '000000000000') {
print_debug("Changed MAC address for $ip from " . format_mac($old_mac) . " to " . format_mac($clean_mac));
log_event("MAC changed: $ip : " . format_mac($old_mac) . " -> " . format_mac($clean_mac), $device, "port", $port_id);
dbUpdate(['mac_address' => $clean_mac], 'ip_mac', 'mac_id = ?', [$entry['mac_id']]);
//echo("U");
$GLOBALS['module_stats'][$module]['updated']++;
} else {
//echo(".");
$GLOBALS['module_stats'][$module]['unchanged']++;
}
// remove entry for deletion
unset($old_table[$port_vrf_name][$ip_version][$ifIndex][$ip]);
} else {
// new entry
$insert = [
'device_id' => $device['device_id'],
'port_id' => $port_id,
'mac_ifIndex' => $ifIndex,
'mac_address' => $clean_mac,
'ip_address' => $ip,
'ip_version' => str_replace('ipv', '', $ip_version),
'virtual_name' => safe_empty($port_vrf_name) ? ['NULL'] : $port_vrf_name
];
dbInsert($insert, 'ip_mac');
print_debug("Added MAC address " . format_mac($clean_mac) . " for $ip");
//log_event("MAC added: $ip : " . format_mac($clean_mac), $device, "port", $port_id);
//echo("+");
$GLOBALS['module_stats'][$module]['added']++;
}
}
$table_rows[] = [$ifIndex, truncate($port['ifDescr'], 30), $port_vrf_name, nicecase($ip_version), count($entry3)];
// clean entry for deletion
if (empty($old_table[$port_vrf_name][$ip_version][$ifIndex])) {
unset($old_table[$port_vrf_name][$ip_version][$ifIndex]);
}
// clean entry for deletion
if (empty($old_table[$port_vrf_name][$ip_version])) {
unset($old_table[$port_vrf_name][$ip_version]);
}
// clean entry for deletion
if (empty($old_table[$port_vrf_name])) {
unset($old_table[$port_vrf_name]);
}
}
}
else
{
$ip = hex2ip($matches[2]);
}
$ip_version = 6;
} else {
// In principle the such shouldn't be.
continue;
}
$if = $matches[1];
$port_id = $interface[$if];
if ($ip && $port_id)
{
if ($matches[3] === '' && $matches[4] === '')
{
// Convert IPv4 to fake MAC for 6to4 tunnels
//ipNetToPhysicalPhysAddress[27][ipv6]["20:02:c0:58:63:01:00:00:00:00:00:00:00:00:00:00"] 0:0:c0:58
$matches[3] = 'ff';
$matches[4] = 'fe';
}
$mac = zeropad($matches[3]);
for ($i = 4; $i <= 8; $i++) { $mac .= ':' . zeropad($matches[$i]); }
$clean_mac = str_replace(':', '', $mac);
$mac_table[$if][$ip_version][$ip] = $clean_mac;
if (isset($old_table[$if][$ip_version][$ip]))
{
$old_mac = $old_table[$if][$ip_version][$ip];
if ($clean_mac != $old_mac && $clean_mac != '00:00:00:00:00:00' && $old_mac != '00:00:00:00:00:00')
{
print_debug("Changed MAC address for $ip from ".format_mac($old_mac)." to ".format_mac($clean_mac));
log_event("MAC changed: $ip : " . format_mac($old_mac) . " -> " . format_mac($clean_mac), $device, "port", $port_id);
dbUpdate(array('mac_address' => $clean_mac) , 'ip_mac', 'port_id = ? AND ip_address = ?', array($port_id, $ip));
echo("U");
} else {
echo(".");
}
} else {
$params = array(
'port_id' => $port_id,
'mac_address' => $clean_mac,
'ip_address' => $ip,
'ip_version' => $ip_version);
dbInsert($params, 'ip_mac');
print_debug("Added MAC address ".format_mac($clean_mac)." for $ip");
//log_event("MAC added: $ip : " . format_mac($clean_mac), $device, "port", $port_id);
echo("+");
}
}
}
// Remove expired ARP/NDP entries
$remove_mac_ids = array();
foreach ($cache_arp as $entry)
{
$entry_mac_id = $entry['mac_id'];
$entry_mac = $entry['mac_address'];
$entry_ip = $entry['ip_address'];
$entry_version = $entry['ip_version'];
$entry_if = $entry['ifIndex'];
$entry_port_id = $interface[$entry_if];
if (!isset($mac_table[$entry_if][$entry_version][$entry_ip]))
{
$remove_mac_ids[] = $entry_mac_id;
//dbDelete('ip_mac', 'mac_id = ?', array($entry_mac_id));
print_debug("Removed MAC address ".format_mac($entry_mac)." for $entry_ip");
//log_event("MAC removed: $entry_ip : " . format_mac($entry_mac), $device, "port", $entry['port_id']);
echo("-");
}
$remove_mac_ids = [];
print_debug_vars($old_table);
foreach ($old_table as $vrf_name => $entry1) {
foreach ($entry1 as $ip_version => $entry2) {
foreach ($entry2 as $ifIndex => $entry3) {
foreach ($entry3 as $ip => $entry) {
$remove_mac_ids[] = $entry['mac_id'];
print_debug("Removed MAC address " . format_mac($entry['mac']) . " for $ip");
//log_event("MAC removed: $entry_ip : " . format_mac($entry_mac), $device, "port", $entry['port_id']);
//echo("-");
$GLOBALS['module_stats'][$module]['deleted']++;
}
}
}
}
if (count($remove_mac_ids))
{
dbDelete('ip_mac', generate_query_values_ng($remove_mac_ids, 'mac_id'));
if (!safe_empty($remove_mac_ids)) {
dbDelete('ip_mac', generate_query_values($remove_mac_ids, 'mac_id'));
}
echo(PHP_EOL);
unset($interface, $remove_mac_ids);
$table_headers = ['%WifIndex%n', '%WifDescr%n', '%WVRF%n', '%WIP: Version%n', '%WAddresses Count%n'];
print_cli_table($table_rows, $table_headers);
unset($mac_table, $old_table, $remove_mac_ids, $table_rows, $table_headers);
// EOF