diff --git a/includes/discovery/os/linux.inc.php b/includes/discovery/os/linux.inc.php index 2fac2bdb5e..7322764cd6 100644 --- a/includes/discovery/os/linux.inc.php +++ b/includes/discovery/os/linux.inc.php @@ -7,73 +7,50 @@ if (!$os) { '.1.3.6.1.4.1.17713.21', '.1.3.6.1.4.1.2.3.51.3' ); - if (preg_match('/^Linux/', $sysDescr) && !in_array($sysObjectId, $skip_oids)) { + if (starts_with($sysDescr, 'Linux') && !in_array($sysObjectId, $skip_oids)) { $os = 'linux'; - } - // Specific Linux-derivatives - if ($os == 'linux') { - // Check for QNAP Systems TurboNAS - $entPhysicalMfgName = snmp_get($device, 'ENTITY-MIB::entPhysicalMfgName.1', '-Osqnv'); - - if (str_contains($sysObjectId, '.1.3.6.1.4.1.5528.100.20.10.2014') || str_contains($sysObjectId, '.1.3.6.1.4.1.5528.100.20.10.2016')) { + // Specific Linux-derivatives + if (starts_with($sysObjectId, array('.1.3.6.1.4.1.5528.100.20.10.2014', '.1.3.6.1.4.1.5528.100.20.10.2016'))) { $os = 'netbotz'; } elseif (str_contains($sysDescr, 'endian')) { $os = 'endian'; - } elseif (preg_match('/Cisco Small Business/', $sysDescr)) { + } elseif (str_contains($sysDescr, 'Cisco Small Business')) { $os = 'ciscosmblinux'; - } elseif (strpos($entPhysicalMfgName, 'QNAP') !== false) { + } elseif (str_contains(snmp_get($device, 'ENTITY-MIB::entPhysicalMfgName.1', '-Osqnv'), 'QNAP')) { $os = 'qnap'; - } elseif (stristr($sysObjectId, 'packetlogic') || str_contains($sysObjectId, '.1.3.6.1.4.1.15397.2')) { + } elseif (starts_with($sysObjectId, '.1.3.6.1.4.1.15397.2')) { $os = 'procera'; - } elseif (str_contains($sysObjectId, '.1.3.6.1.4.1.10002.1') || str_contains($sysObjectId, '.1.3.6.1.4.1.41112.1.4') || strpos(trim(snmp_get($device, 'dot11manufacturerName.5', '-Osqnv', 'IEEE802dot11-MIB')), 'Ubiquiti') !== false) { + } elseif (starts_with($sysObjectId, array('.1.3.6.1.4.1.10002.1', '.1.3.6.1.4.1.41112.1.4')) || str_contains(snmp_get($device, 'dot11manufacturerName.5', '-Osqnv', 'IEEE802dot11-MIB'), 'Ubiquiti')) { $os = 'airos'; - if (strpos(trim(snmp_get($device, 'dot11manufacturerProductName.5', '-Osqnv', 'IEEE802dot11-MIB')), 'UAP') !== false) { + if (str_contains(snmp_walk($device, 'dot11manufacturerProductName', '-Osqnv', 'IEEE802dot11-MIB'), 'UAP')) { $os = 'unifi'; - } elseif (strpos(trim(snmp_get($device, 'dot11manufacturerProductName.2', '-Osqnv', 'IEEE802dot11-MIB')), 'UAP') !== false) { - $os = 'unifi'; - } elseif (strpos(trim(snmp_get($device, 'dot11manufacturerProductName.3', '-Osqnv', 'IEEE802dot11-MIB')), 'UAP') !== false) { - $os = 'unifi'; - } elseif (strpos(trim(snmp_get($device, 'dot11manufacturerProductName.4', '-Osqnv', 'IEEE802dot11-MIB')), 'UAP') !== false) { - $os = 'unifi'; - } elseif (strpos(trim(snmp_get($device, 'dot11manufacturerProductName.6', '-Osqnv', 'IEEE802dot11-MIB')), 'UAP') !== false) { - $os = 'unifi'; - } elseif (trim(snmp_get($device, 'fwVersion.1', '-Osqnv', 'UBNT-AirFIBER-MIB')) != '') { + } elseif (snmp_get($device, 'fwVersion.1', '-Osqnv', 'UBNT-AirFIBER-MIB') !== false) { $os = 'airos-af'; } } elseif (snmp_get($device, 'GANDI-MIB::rxCounter.0', '-Osqnv', 'GANDI-MIB') !== false) { $os = 'pktj'; $pktj_mibs = array ( - "rxCounter" => "GANDI-MIB", // RX Packets - "txCounter" => "GANDI-MIB", // TX Packets - "dropCounter" => "GANDI-MIB", // Dropped counters - "acldropCounter" => "GANDI-MIB", // ACL Dropped counter - "ratedropCounter" => "GANDI-MIB", // Rate Dropped counter - "KNIrxCounter" => "GANDI-MIB", // KNI RX counter - "KNItxCounter" => "GANDI-MIB", // KNI TX counter - "KNIdropCounter" => "GANDI-MIB", // KNI DROP counter + "rxCounter" => "GANDI-MIB", // RX Packets + "txCounter" => "GANDI-MIB", // TX Packets + "dropCounter" => "GANDI-MIB", // Dropped counters + "acldropCounter" => "GANDI-MIB", // ACL Dropped counter + "ratedropCounter" => "GANDI-MIB", // Rate Dropped counter + "KNIrxCounter" => "GANDI-MIB", // KNI RX counter + "KNItxCounter" => "GANDI-MIB", // KNI TX counter + "KNIdropCounter" => "GANDI-MIB", // KNI DROP counter ); register_mibs($device, $pktj_mibs, "include/discovery/os/linux.inc.php"); - } elseif (stristr($sysObjectId, 'cumulusMib') || str_contains($sysObjectId, '.1.3.6.1.4.1.40310')) { + } elseif (starts_with($sysObjectId, '.1.3.6.1.4.1.40310')) { $os = 'cumulus'; } elseif (str_contains($sysDescr, array('g56fa85e', 'gc80f187', 'g829be90', 'g63c0044', 'gba768e5'))) { $os = 'sophos'; } elseif (snmp_get($device, 'SFA-INFO::systemName.0', '-Osqnv', 'SFA-INFO') !== false) { $os = 'ddnos'; - } else { - // Check for Synology DSM - $hrSystemInitialLoadParameters = trim(snmp_get($device, 'HOST-RESOURCES-MIB::hrSystemInitialLoadParameters.0', '-Osqnv')); - - if (strpos($hrSystemInitialLoadParameters, 'syno_hw_version') !== false) { - $os = 'dsm'; - } else { - // Check for Carel PCOweb - $roomTemp = trim(snmp_get($device, 'roomTemp.0', '-OqvU', 'CAREL-ug40cdz-MIB')); - - if (is_numeric($roomTemp)) { - $os = 'pcoweb'; - } - } + } elseif (str_contains(snmp_get($device, 'HOST-RESOURCES-MIB::hrSystemInitialLoadParameters.0', '-Osqnv'), 'syno_hw_version')) { + $os = 'dsm'; // Synology DSM + } elseif (is_numeric(trim(snmp_get($device, 'roomTemp.0', '-OqvU', 'CAREL-ug40cdz-MIB')))) { + $os = 'pcoweb'; // Carel PCOweb } } } diff --git a/includes/functions.php b/includes/functions.php index a5b9e6ad2c..68949f7527 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -106,20 +106,15 @@ function getHostOS($device) d_echo("| $sysDescr | $sysObjectId | "); - $path = $config['install_dir'] . "/includes/discovery/os"; - $dir_handle = @opendir($path) or die("Unable to open $path"); - while ($file = readdir($dir_handle)) { - if (preg_match("/.php$/", $file)) { - include($config['install_dir'] . "/includes/discovery/os/" . $file); + $pattern = $config['install_dir'] . '/includes/discovery/os/*.inc.php'; + foreach (glob($pattern) as $file) { + include $file; + if (isset($os)) { + return $os; } } - closedir($dir_handle); - if ($os) { - return $os; - } else { - return "generic"; - } + return "generic"; } function percent_colour($perc) diff --git a/tests/OSDiscoveryTest.php b/tests/OSDiscoveryTest.php new file mode 100644 index 0000000000..3a25450fd3 --- /dev/null +++ b/tests/OSDiscoveryTest.php @@ -0,0 +1,174 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2016 Tony Murray + * @author Tony Murray + */ + +namespace LibreNMS\Tests; + +include 'tests/mocks/mock.snmp.inc.php'; + +class DiscoveryTest extends \PHPUnit_Framework_TestCase +{ + public function testAiros() + { + $this->checkOS('airos', 'Linux', '.1.3.6.1.4.1.10002.1'); + $this->checkOS('airos', 'Linux', '.1.3.6.1.4.1.41112.1.4'); + + $mockSnmp = array( + 'dot11manufacturerName.5' => 'Ubiquiti', + ); + $this->checkOS('airos', 'Linux', '', $mockSnmp); + } + + /** + * Set up variables and include os discovery + * + * @param string $expectedOS the OS to test for + * @param string $sysDescr set the snmp sysDescr variable + * @param string $sysObjectId set the snmp sysObjectId variable + * @param array $snmpMock set arbitrary snmp variables with an associative array + * @param array $device device array to send + */ + private function checkOS($expectedOS, $sysDescr = '', $sysObjectId = '', $mockSnmp = array(), $device = array()) + { + global $config; + setSnmpMock($mockSnmp); + $os = null; + + // cannot use getHostOS() because of functions.php includes + $pattern = $config['install_dir'] . '/includes/discovery/os/*.inc.php'; + foreach (glob($pattern) as $file) { + include $file; + if (isset($os)) { + break; + } + } + + $this->assertEquals($expectedOS, $os); + } + + public function testAirosAf() + { + $mockSnmp = array( + 'fwVersion.1' => '1.0', + ); + $this->checkOS('airos-af', 'Linux', '.1.3.6.1.4.1.10002.1', $mockSnmp); + } + + public function testCiscosmblinux() + { + $this->checkOS('ciscosmblinux', 'Linux Cisco Small Business'); + } + + public function testCumulus() + { + $this->checkOS('cumulus', 'Linux', '.1.3.6.1.4.1.40310'); + } + + public function testDdnos() + { + $mockSnmp = array( + 'SFA-INFO::systemName.0' => 1, + ); + $this->checkOS('ddnos', 'Linux', '', $mockSnmp); + } + + public function testDsm() + { + $mockSnmp = array( + 'HOST-RESOURCES-MIB::hrSystemInitialLoadParameters.0' => 'syno_hw_version', + ); + $this->checkOS('dsm', 'Linux', '', $mockSnmp); + } + + public function testEndian() + { + $this->checkOS('endian', 'Linux endian'); + } + + public function testLinux() + { + $this->checkOS('linux', 'Linux'); + } + + public function testNetbotz() + { + $this->checkOS('netbotz', 'Linux', '.1.3.6.1.4.1.5528.100.20.10.2014'); + $this->checkOS('netbotz', 'Linux', '.1.3.6.1.4.1.5528.100.20.10.2016'); + } + + public function testPcoweb() + { + $mockSnmp = array( + 'roomTemp.0' => 1, + ); + $this->checkOS('pcoweb', 'Linux', '', $mockSnmp); + } + + public function testPktj() + { + $mockSnmp = array( + 'GANDI-MIB::rxCounter.0' => 1, + ); + $this->checkOS('pktj', 'Linux', '', $mockSnmp); + } + + public function testProcera() + { + $this->checkOS('procera', 'Linux', '.1.3.6.1.4.1.15397.2'); + } + + public function testQnap() + { + $mockSnmp = array( + 'ENTITY-MIB::entPhysicalMfgName.1' => 'QNAP', + ); + $this->checkOS('qnap', 'Linux', '', $mockSnmp); + } + + public function testSophos() + { + $this->checkOS('sophos', 'Linux g56fa85e'); + $this->checkOS('sophos', 'Linux gc80f187'); + $this->checkOS('sophos', 'Linux g829be90'); + $this->checkOS('sophos', 'Linux g63c0044'); + } + + public function testUnifi() + { + $mockSnmp = array( + 'dot11manufacturerProductName.6' => 'UAP', + ); + $this->checkOS('unifi', 'Linux', '.1.3.6.1.4.1.10002.1', $mockSnmp); + + $mockSnmp = array( + 'dot11manufacturerProductName.4' => 'UAP-PRO', + ); + $this->checkOS('unifi', 'Linux', '.1.3.6.1.4.1.10002.1', $mockSnmp); + + $mockSnmp = array( + 'dot11manufacturerProductName.0' => 'UAP-AC2', + ); + $this->checkOS('unifi', 'Linux', '.1.3.6.1.4.1.10002.1', $mockSnmp); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index baef847897..b63ba323d7 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -33,3 +33,6 @@ $classLoader->registerDir($install_dir . '/tests', 'LibreNMS\Tests'); require_once $install_dir . '/includes/common.php'; require_once $install_dir . '/includes/rrdtool.inc.php'; require_once $install_dir . '/includes/syslog.php'; + +ini_set('display_errors', 1); +ini_set('error_reporting', E_ALL); diff --git a/tests/mocks/mock.snmp.inc.php b/tests/mocks/mock.snmp.inc.php new file mode 100644 index 0000000000..c88d2abc3f --- /dev/null +++ b/tests/mocks/mock.snmp.inc.php @@ -0,0 +1,64 @@ +. + * + * @package LibreNMS + * @link http://librenms.org + * @copyright 2016 Tony Murray + * @author Tony Murray + */ + +function setSnmpMock($mockSnmpArray) +{ + global $mockSnmp; + $mockSnmp = $mockSnmpArray; +} + +function snmp_get($device, $oid) +{ + global $mockSnmp; + if (isset($mockSnmp) && !empty($mockSnmp)) { + if (isset($mockSnmp[$oid])) { + return $mockSnmp[$oid]; + } + } + return false; +} + +function snmp_walk($device, $oid) +{ + global $mockSnmp; + $output = ''; + foreach ($mockSnmp as $key => $value) { + if (starts_with($key, $oid)) { + $output .= $value . PHP_EOL; + } + } + + if (empty($output)) { + // does this match the behavior of the real snmp_walk()? + return false; + } else { + return $output; + } +} + +function register_mibs() +{ + // stub +}