Commit version 24.12.13800
This commit is contained in:
@ -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
|
||||
|
Reference in New Issue
Block a user