220 lines
11 KiB
PHP
220 lines
11 KiB
PHP
<?php
|
|
/**
|
|
* Observium
|
|
*
|
|
* This file is part of Observium.
|
|
*
|
|
* @package observium
|
|
* @subpackage discovery
|
|
* @copyright (C) Adam Armstrong
|
|
*
|
|
*/
|
|
|
|
/*
|
|
CISCO-CDP-MIB::cdpCacheAddressType.1.0 = INTEGER: ip(1)
|
|
CISCO-CDP-MIB::cdpCacheAddress.1.0 = Hex-STRING: CD EB 52 C2
|
|
CISCO-CDP-MIB::cdpCacheVersion.1.0 = STRING: 2007656304
|
|
CISCO-CDP-MIB::cdpCacheDeviceId.1.0 = STRING: ASW10.SPN.WPA1.imdc.com
|
|
CISCO-CDP-MIB::cdpCacheDevicePort.1.0 = STRING: GigabitEthernet1/27
|
|
CISCO-CDP-MIB::cdpCachePlatform.1.0 = STRING: cisco WS-C4948-10GE
|
|
CISCO-CDP-MIB::cdpCacheCapabilities.1.0 = Hex-STRING: 00 00 00 29
|
|
CISCO-CDP-MIB::cdpCacheVTPMgmtDomain.1.0 = STRING: IMDC-1
|
|
CISCO-CDP-MIB::cdpCacheNativeVLAN.1.0 = INTEGER: 0
|
|
CISCO-CDP-MIB::cdpCacheDuplex.1.0 = INTEGER: unknown(1)
|
|
CISCO-CDP-MIB::cdpCacheApplianceID.1.0 = Gauge32: 0
|
|
CISCO-CDP-MIB::cdpCacheVlanID.1.0 = Gauge32: 0
|
|
CISCO-CDP-MIB::cdpCachePowerConsumption.1.0 = Gauge32: 0 milliwatts
|
|
CISCO-CDP-MIB::cdpCacheMTU.1.0 = Gauge32: 0
|
|
CISCO-CDP-MIB::cdpCacheSysName.1.0 = STRING: ASW10.SPN.WPA1.imdc.com
|
|
CISCO-CDP-MIB::cdpCacheSysObjectID.1.0 = OID: SNMPv2-SMI::zeroDotZero.0
|
|
CISCO-CDP-MIB::cdpCachePrimaryMgmtAddrType.1.0 = INTEGER: ip(1)
|
|
CISCO-CDP-MIB::cdpCachePrimaryMgmtAddr.1.0 = STRING: "205.235.82.194"
|
|
CISCO-CDP-MIB::cdpCacheSecondaryMgmtAddrType.1.0 = INTEGER: 0
|
|
CISCO-CDP-MIB::cdpCacheSecondaryMgmtAddr.1.0 = ""
|
|
CISCO-CDP-MIB::cdpCachePhysLocation.1.0 = STRING:
|
|
CISCO-CDP-MIB::cdpCacheLastChange.1.0 = Timeticks: (120) 0:00:01.20
|
|
CISCO-CDP-MIB::cdpGlobalLastChange.0 = Timeticks: (600708689) 69 days, 12:38:06.89
|
|
*/
|
|
|
|
$cdp_flags = OBS_SNMP_ALL_MULTILINE | OBS_SNMP_DISPLAY_HINT; // disable hints
|
|
//$cdp_flags = OBS_SNMP_ALL_NUMERIC_INDEX | OBS_SNMP_DISPLAY_HINT | OBS_SNMP_CONCAT;
|
|
$cdp_array = snmpwalk_cache_twopart_oid($device, "cdpCache", [], "CISCO-CDP-MIB", NULL, $cdp_flags);
|
|
|
|
// If we get timeout error and device has 'CISCO-FLASH-MIB', sleep and try re-walk
|
|
if (snmp_status() === FALSE && is_device_mib($device, 'CISCO-FLASH-MIB') &&
|
|
(snmp_error_code() === OBS_SNMP_ERROR_REQUEST_TIMEOUT || snmp_error_code() === OBS_SNMP_ERROR_BULK_REQUEST_TIMEOUT)) {
|
|
print_debug('Try to re-walk "CISCO-CDP-MIB"..');
|
|
sleep(5); // Additional sleep, see comments in includes/discovery/storage/cisco-flash-mib-inc.php
|
|
$cdp_array = snmpwalk_cache_twopart_oid($device, "cdpCache", $cdp_array, "CISCO-CDP-MIB", NULL, $cdp_flags);
|
|
}
|
|
print_debug_vars($cdp_array);
|
|
|
|
if (safe_empty($cdp_array)) {
|
|
return;
|
|
}
|
|
|
|
// fetch sysUptime for correct last change
|
|
// $device_sysUptime = timeticks_to_sec(snmp_get_oid($device, "sysUpTime.0", "SNMPv2-MIB"));
|
|
|
|
// Force fetch cdpCacheAddress as HEX strings!
|
|
$cdp_array = snmpwalk_cache_twopart_oid($device, "cdpCacheAddress", $cdp_array, "CISCO-CDP-MIB", NULL, OBS_SNMP_ALL_HEX);
|
|
foreach ($cdp_array as $ifIndex => $port_neighbours) {
|
|
$port = get_port_by_index_cache($device, $ifIndex);
|
|
//$port = dbFetchRow("SELECT * FROM `ports` WHERE `device_id` = ? AND `ifIndex` = ?", array($device['device_id'], $ifIndex));
|
|
|
|
foreach ($port_neighbours as $cdpCacheDeviceIndex => $cdp_entry) {
|
|
// Init
|
|
$remote_mac = NULL;
|
|
$remote_hostname = '';
|
|
|
|
// Remote hostname
|
|
// NOTE. cdpCacheDeviceId have undocumented limit by 40 chars!
|
|
if (preg_match('/^([A-F\d]{2}\s?){6}$/i', $cdp_entry['cdpCacheDeviceId'])) {
|
|
// HEX mac address
|
|
// cdpCacheDeviceId.3.1 = "98 90 96 D1 59 5A "
|
|
// cdpCacheDeviceId.3.1 = "549fc6fd89c7"
|
|
$remote_hostname = $cdp_entry['cdpCacheDeviceId'];
|
|
$remote_mac = str_replace(' ', '', $cdp_entry['cdpCacheDeviceId']);
|
|
} elseif (preg_match('/^01 (?<ip>([A-F\d]{2}\s?){4})$/', $cdp_entry['cdpCacheDeviceId'], $matches)) {
|
|
// HEX ip address
|
|
// cdpCacheDeviceId.5.2 = "01 90 7F 93 3E "
|
|
$remote_hostname = hex2ip($matches['ip']);
|
|
} else {
|
|
$remote_hostname = snmp_hexstring($cdp_entry['cdpCacheDeviceId']);
|
|
if (preg_match('/^(?:SEP|SIP|\w+\-)?([a-f\d]{12})$/i', $remote_hostname, $matches)) {
|
|
// Meraki report mac instead hostname
|
|
// Axis: axis-<mac>
|
|
// Cisco IP Phone: SEP<mac>
|
|
// SIP-<platform><mac>,
|
|
$remote_hostname = $cdp_entry['cdpCacheDeviceId'];
|
|
$remote_mac = $matches[1];
|
|
} elseif (preg_match(OBS_PATTERN_NOPRINT, $remote_hostname)) {
|
|
// Non-printable chars, seems as ID is not hostname, keep as is
|
|
$tmp = preg_replace(OBS_PATTERN_NOPRINT, '', $remote_hostname);
|
|
if (is_valid_hostname($tmp)) {
|
|
print_debug("Probably valid hostname with broken chars? '" . $cdp_entry['cdpCacheDeviceId'] . "' => '$tmp'");
|
|
}
|
|
$remote_hostname = $cdp_entry['cdpCacheDeviceId'];
|
|
} else {
|
|
$remote_hostname = explode('(', $remote_hostname)[0]; // Fix for Nexus CDP neighbors: <hostname>(serial number)
|
|
}
|
|
}
|
|
$hostname_len = strlen($remote_hostname);
|
|
|
|
// cdpCacheSysName
|
|
if (isset($cdp_entry['cdpCacheSysName'])) {
|
|
$cdp_entry['cdpCacheSysName'] = snmp_hexstring($cdp_entry['cdpCacheSysName']);
|
|
$sysname_len = strlen($cdp_entry['cdpCacheSysName']);
|
|
if (is_valid_hostname($cdp_entry['cdpCacheSysName']) && $sysname_len > $hostname_len) {
|
|
$remote_hostname = $cdp_entry['cdpCacheSysName'];
|
|
} elseif ($sysname_len && preg_match('/^[a-f\d]{12}$/i', $cdp_entry['cdpCacheDeviceId'])) {
|
|
// DeviceId is mac, prefer sysName
|
|
$remote_hostname = $cdp_entry['cdpCacheSysName'];
|
|
}
|
|
}
|
|
|
|
// Remote address
|
|
$remote_address = hex2ip($cdp_entry['cdpCacheAddress']);
|
|
// MGMT address, select best
|
|
$mgmt_address = hex2ip($cdp_entry['cdpCachePrimaryMgmtAddr']);
|
|
if ($mgmt_address && $remote_address !== $mgmt_address) {
|
|
$remote_type = get_ip_type($remote_address);
|
|
$mgmt_type = get_ip_type($mgmt_address);
|
|
// cdpCacheAddressType.436207616.16318465 = ip
|
|
// cdpCacheAddress.436207616.16318465 = "64 69 00 31 " -> 100.105.0.49 (cgnat)
|
|
// cdpCachePrimaryMgmtAddrType.436207616.16318465 = ip
|
|
// cdpCachePrimaryMgmtAddr.436207616.16318465 = "0A AF 0C 3C " -> 10.175.12.60
|
|
// cdpCacheSecondaryMgmtAddrType.436207616.16318465 = ip
|
|
// cdpCacheSecondaryMgmtAddr.436207616.16318465 = ""
|
|
if (in_array($remote_type, [ 'cgnat', 'link-local' ]) &&
|
|
!in_array($mgmt_type, [ 'cgnat', 'link-local' ])) {
|
|
print_debug("Select best address:\n cdpCacheAddress - $remote_address ($remote_type),\n* cdpCachePrimaryMgmtAddr - $mgmt_address ($mgmt_type)");
|
|
$remote_address = $mgmt_address;
|
|
} else {
|
|
print_debug("Select best address:\n* cdpCacheAddress - $remote_address ($remote_type),\n cdpCachePrimaryMgmtAddr - $mgmt_address ($mgmt_type)");
|
|
}
|
|
}
|
|
|
|
// Last change
|
|
/* Derp. Do not use Last change from neighbour, it's not correct for us
|
|
* (seems as changed uptime by remote host, not possible correct calculate unixtime)
|
|
$last_change = timeticks_to_sec($cdp_entry['cdpCacheLastChange']);
|
|
if ($last_change > 0)
|
|
{
|
|
$last_change = get_time() - $device_sysUptime + $last_change;
|
|
}
|
|
*/
|
|
|
|
// Remote MAC on some devices
|
|
$if = NULL;
|
|
if (preg_match('/^([A-F\d]{2}\s?){6}$/', $cdp_entry['cdpCacheDevicePort'])) {
|
|
$remote_mac = $cdp_entry['cdpCacheDevicePort'];
|
|
} else {
|
|
$cdp_entry['cdpCacheDevicePort'] = snmp_hexstring($cdp_entry['cdpCacheDevicePort']);
|
|
if (preg_match('/^[a-f\d]{12}$/i', $cdp_entry['cdpCacheDevicePort'])) {
|
|
$remote_mac = $cdp_entry['cdpCacheDevicePort'];
|
|
} else {
|
|
$if = $cdp_entry['cdpCacheDevicePort'];
|
|
}
|
|
}
|
|
|
|
// Try to find a remote device and check if already cached
|
|
$remote_device_id = get_autodiscovery_device_id($device, $remote_hostname, $remote_address, $remote_mac);
|
|
if (is_null($remote_device_id) && // NULL - never cached in other rounds
|
|
check_autodiscovery($remote_hostname, $remote_address)) { // Check all previous autodiscovery rounds
|
|
// Neighbour never checked, try autodiscovery
|
|
$remote_device_id = autodiscovery_device($remote_hostname, $remote_address, 'CDP', $cdp_entry['cdpCachePlatform'], $device, $port);
|
|
}
|
|
|
|
$remote_port_id = NULL;
|
|
if ($remote_device_id) {
|
|
//$if = $cdp_entry['cdpCacheDevicePort'];
|
|
|
|
if (!is_null($if)) {
|
|
$query = 'SELECT `port_id` FROM `ports` WHERE (`ifName` = ? OR `ifDescr` = ? OR `port_label_short` = ?) AND `device_id` = ? AND `deleted` = ?';
|
|
$remote_port_id = dbFetchCell($query, [$if, $if, $if, $remote_device_id, 0]);
|
|
|
|
// Aruba devices can report ifAlias instead ifDescr
|
|
if (!$remote_port_id && !is_hex_string($if)) {
|
|
$query = 'SELECT `port_id` FROM `ports` WHERE `ifAlias` = ? AND `device_id` = ? AND `deleted` = ?';
|
|
$remote_port_id = dbFetchCell($query, [$if, $remote_device_id, 0]);
|
|
}
|
|
}
|
|
if (!$remote_port_id) {
|
|
if (!is_null($remote_mac)) {
|
|
// By MAC
|
|
$remote_port_id = get_port_id_by_mac($remote_device_id, $remote_mac);
|
|
} elseif (!is_null($if)) {
|
|
// Try by ifAlias
|
|
$query = 'SELECT `port_id` FROM `ports` WHERE `ifAlias` = ? AND `device_id` = ? AND `deleted` = ?';
|
|
$remote_port_id = dbFetchCell($query, [$if, $remote_device_id, 0]);
|
|
}
|
|
|
|
if (!$remote_port_id) {
|
|
// Try by IP
|
|
$peer_where = generate_query_values_and($remote_device_id, 'device_id'); // Additional filter for include self IPs
|
|
// Fetch all ports with peer IP and filter by UP
|
|
if ($ids = get_entity_ids_ip_by_network('port', $remote_address, $peer_where)) {
|
|
$remote_port_id = $ids[0];
|
|
//$port = get_port_by_id_cache($ids[0]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$neighbour = [
|
|
'remote_device_id' => $remote_device_id,
|
|
'remote_port_id' => $remote_port_id,
|
|
'remote_hostname' => $remote_hostname,
|
|
'remote_port' => $cdp_entry['cdpCacheDevicePort'],
|
|
'remote_platform' => $cdp_entry['cdpCachePlatform'],
|
|
'remote_version' => $cdp_entry['cdpCacheVersion'],
|
|
'remote_address' => $remote_address,
|
|
//'last_change' => $last_change
|
|
];
|
|
discover_neighbour($port, 'cdp', $neighbour);
|
|
}
|
|
}
|
|
|
|
// EOF
|