diff --git a/LibreNMS/Data/Source/NetSnmpQuery.php b/LibreNMS/Data/Source/NetSnmpQuery.php index fb8efe9236..bc1bdc480c 100644 --- a/LibreNMS/Data/Source/NetSnmpQuery.php +++ b/LibreNMS/Data/Source/NetSnmpQuery.php @@ -73,26 +73,17 @@ class NetSnmpQuery implements SnmpQueryInterface '*', ], ]; - /** - * @var string - */ - private $context = ''; + /** * @var string[] */ private array $mibDirs = []; - /** - * @var array|string - */ - private $options = [self::DEFAULT_FLAGS]; - /** - * @var \App\Models\Device - */ - private $device; - /** - * @var bool - */ - private $abort = false; + private string $context = ''; + private array|string $options = [self::DEFAULT_FLAGS]; + private Device $device; + private bool $abort = false; + // defaults for net-snmp https://net-snmp.sourceforge.io/docs/man/snmpcmd.html + private array $mibs = ['SNMPv2-TC', 'SNMPv2-MIB', 'IF-MIB', 'IP-MIB', 'TCP-MIB', 'UDP-MIB', 'SNMP-VACM-MIB']; public function __construct() { @@ -165,6 +156,17 @@ class NetSnmpQuery implements SnmpQueryInterface return $this; } + /** + * Set MIBs to use for this query. Base mibs are included by default. + * They will be appended to existing mibs unless $append is set to false. + */ + public function mibs(array $mibs, bool $append = true): SnmpQueryInterface + { + $this->mibs = $append ? array_merge($this->mibs, $mibs) : $mibs; + + return $this; + } + /** * When walking multiple OIDs, stop if one fails. Used when the first OID indicates if the rest are supported. * OIDs will be walked in order, so you may want to put your OIDs in a specific order. @@ -281,7 +283,7 @@ class NetSnmpQuery implements SnmpQueryInterface * Translate an OID. * call numeric() on the query to output numeric OID */ - public function translate(string $oid, ?string $mib = null): string + public function translate(string $oid): string { $this->options = array_diff($this->options, [self::DEFAULT_FLAGS]); // remove default options @@ -299,10 +301,6 @@ class NetSnmpQuery implements SnmpQueryInterface $this->options[] = '-IR'; // search for mib } - if ($mib) { - array_push($this->options, '-m', $mib); - } - return $this->exec('snmptranslate', [$oid])->value(); } @@ -311,6 +309,7 @@ class NetSnmpQuery implements SnmpQueryInterface $cmd = $this->initCommand($command, $oids); array_push($cmd, '-M', $this->mibDirectories()); + array_push($cmd, '-m', implode(':', $this->mibs)); if ($command === 'snmptranslate') { return array_merge($cmd, $this->options, $oids); diff --git a/LibreNMS/Data/Source/SnmpQueryInterface.php b/LibreNMS/Data/Source/SnmpQueryInterface.php index c04b38ad15..5b3bfc6a91 100644 --- a/LibreNMS/Data/Source/SnmpQueryInterface.php +++ b/LibreNMS/Data/Source/SnmpQueryInterface.php @@ -58,6 +58,12 @@ interface SnmpQueryInterface */ public function mibDir(?string $dir): SnmpQueryInterface; + /** + * Set MIBs to use for this query. Base mibs are included by default. + * They will be appended to existing mibs unless $append is set to false. + */ + public function mibs(array $mibs, bool $append = true): SnmpQueryInterface; + /** * When walking multiple OIDs, stop if one fails. Used when the first OID indicates if the rest are supported. * OIDs will be walked in order, so you may want to put your OIDs in a specific order. @@ -127,5 +133,5 @@ interface SnmpQueryInterface * Translate an OID. * Call numeric method prior output numeric OID. */ - public function translate(string $oid, ?string $mib = null): string; + public function translate(string $oid): string; } diff --git a/LibreNMS/OS/Junose.php b/LibreNMS/OS/Junose.php index 24ecec0d1c..841af9193e 100644 --- a/LibreNMS/OS/Junose.php +++ b/LibreNMS/OS/Junose.php @@ -37,7 +37,7 @@ class Junose extends \LibreNMS\OS return; } - $junose_hardware = \SnmpQuery::translate($device->sysObjectID, 'Juniper-Products-MIB'); + $junose_hardware = \SnmpQuery::mibs(['Juniper-Products-MIB'])->translate($device->sysObjectID); $device->hardware = $this->rewriteHardware($junose_hardware) ?: null; $junose_version = \SnmpQuery::get('Juniper-System-MIB::juniSystemSwVersion.0')->value(); diff --git a/LibreNMS/OS/Traits/YamlMempoolsDiscovery.php b/LibreNMS/OS/Traits/YamlMempoolsDiscovery.php index 7e78f290b7..41e0837c53 100644 --- a/LibreNMS/OS/Traits/YamlMempoolsDiscovery.php +++ b/LibreNMS/OS/Traits/YamlMempoolsDiscovery.php @@ -113,7 +113,7 @@ trait YamlMempoolsDiscovery } if (isset($this->mempoolsOids[$field])) { - return Oid::toNumeric("{$this->mempoolsOids[$field]}.$index", 'ALL'); + return Oid::toNumeric("{$this->mempoolsOids[$field]}.$index"); } return null; diff --git a/LibreNMS/Util/Oid.php b/LibreNMS/Util/Oid.php index 748b222061..d91ec10024 100644 --- a/LibreNMS/Util/Oid.php +++ b/LibreNMS/Util/Oid.php @@ -70,7 +70,13 @@ class Oid $key = 'Oid:toNumeric:' . $oid . '/' . $mib; $numeric_oid = Cache::remember($key, $cache, function () use ($oid, $mib) { - return \SnmpQuery::numeric()->translate($oid, $mib); + $snmpQuery = \SnmpQuery::numeric(); + + if ($mib) { + $snmpQuery->mibs([$mib], append: $mib !== 'ALL'); // append to base mibs unless using ALL + } + + return $snmpQuery->translate($oid); }); if (empty($numeric_oid)) { diff --git a/tests/Mocks/SnmpQueryMock.php b/tests/Mocks/SnmpQueryMock.php index 5e8bec992f..c470c38941 100644 --- a/tests/Mocks/SnmpQueryMock.php +++ b/tests/Mocks/SnmpQueryMock.php @@ -38,46 +38,24 @@ use Log; class SnmpQueryMock implements SnmpQueryInterface { - /** - * @var array - */ - private static $cache; + private static ?array $cache = null; + private Device $device; + private string $context = ''; + private ?string $mibDir = null; + private array $mibs = []; + private bool $numeric = false; + private bool $hideMib = false; + private array $options = []; + private bool $abort = false; - /** - * @var Device - */ - private $device; - /** - * @var string - */ - private $context; - /** - * @var string|null - */ - private $mibDir; - /** - * @var bool - */ - private $numeric = false; - /** - * @var bool - */ - private $hideMib = false; - /** - * @var array|mixed - */ - private $options = []; - /** - * @var bool - */ - private $abort = false; + public function __construct() + { + $this->device = DeviceCache::getPrimary(); + } public static function make(): SnmpQueryInterface { - $new = new static; - $new->device = DeviceCache::getPrimary(); - - return $new; + return new static; } public function device(Device $device): SnmpQueryInterface @@ -101,7 +79,7 @@ class SnmpQueryMock implements SnmpQueryInterface return $this; } - public function translate(string $oid, ?string $mib = null): string + public function translate(string $oid): string { // call real snmptranslate $options = $this->options; @@ -114,8 +92,9 @@ class SnmpQueryMock implements SnmpQueryInterface return NetSnmpQuery::make() ->mibDir($this->mibDir) + ->mibs($this->mibs) ->options($options) - ->translate($oid, $mib); + ->translate($oid); } public function abortOnFailure(): SnmpQueryInterface @@ -159,6 +138,17 @@ class SnmpQueryMock implements SnmpQueryInterface return $this; } + /** + * Set MIBs to use for this query. Base mibs are included by default. + * They will be appended to existing mibs unless $append is set to false. + */ + public function mibs(array $mibs, bool $append = true): SnmpQueryInterface + { + $this->mibs = $append ? array_merge($this->mibs, $mibs) : $mibs; + + return $this; + } + public function mibDir(?string $dir): SnmpQueryInterface { $this->mibDir = $dir; @@ -288,7 +278,7 @@ class SnmpQueryMock implements SnmpQueryInterface private function outputLine(string $oid, string $num_oid, string $type, string $data): string { if ($type == 6) { - $data = $this->numeric ? ".$data" : $this->translate($data, $this->extractMib($oid)); + $data = $this->numeric ? ".$data" : $this->mibs($this->extractMib($oid))->translate($data); } if ($this->numeric) { @@ -307,12 +297,11 @@ class SnmpQueryMock implements SnmpQueryInterface * The leading dot is ommited by default to be compatible with snmpsim * * @param string $oid the oid to tranlslate - * @param string $mib mib to use * @return string the oid in numeric format (1.3.4.5) * * @throws Exception Could not translate the oid */ - private function translateNumber($oid, $mib = null) + private function translateNumber($oid) { // optimizations (35s -> 1.6s on my laptop) switch ($oid) { @@ -337,11 +326,9 @@ class SnmpQueryMock implements SnmpQueryInterface } $options = ['-IR']; - if ($mib) { - $options[] = "-m $mib"; - } $number = NetSnmpQuery::make()->mibDir($this->mibDir) + ->mibs($this->mibs) ->options(array_merge($options, $this->options))->numeric()->translate($oid); if (empty($number)) { @@ -362,12 +349,12 @@ class SnmpQueryMock implements SnmpQueryInterface return $community; } - private function extractMib(string $oid): ?string + private function extractMib(string $oid): array { if (Str::contains($oid, '::')) { - return explode('::', $oid, 2)[0]; + return [explode('::', $oid, 2)[0]]; } - return null; + return []; } } diff --git a/tests/Unit/SnmpTranslateTest.php b/tests/Unit/SnmpTranslateTest.php index 3916ce2790..b1568d9da8 100644 --- a/tests/Unit/SnmpTranslateTest.php +++ b/tests/Unit/SnmpTranslateTest.php @@ -35,10 +35,10 @@ class SnmpTranslateTest extends TestCase $actual = \SnmpQuery::numeric()->translate('IF-MIB::ifTable'); $this->assertEquals('.1.3.6.1.2.1.2.2', $actual); - $actual = \SnmpQuery::numeric()->translate('ifTable', 'IF-MIB'); + $actual = \SnmpQuery::numeric()->mibs(['IF-MIB'], append: false)->translate('ifTable'); $this->assertEquals('.1.3.6.1.2.1.2.2', $actual); - $actual = \SnmpQuery::numeric()->translate('ifTable', 'ALL'); + $actual = \SnmpQuery::numeric()->mibs(['ALL'], append: false)->translate('ifTable'); $this->assertEquals('.1.3.6.1.2.1.2.2', $actual); $actual = \SnmpQuery::translate('IF-MIB::ifTable'); @@ -47,29 +47,29 @@ class SnmpTranslateTest extends TestCase $actual = \SnmpQuery::numeric()->translate('.1.3.6.1.2.1.2.2'); $this->assertEquals('.1.3.6.1.2.1.2.2', $actual); - $actual = \SnmpQuery::translate('.1.3.6.1.2.1.2.2', 'IF-MIB'); + $actual = \SnmpQuery::mibs(['IF-MIB'])->translate('.1.3.6.1.2.1.2.2'); $this->assertEquals('IF-MIB::ifTable', $actual); $actual = \SnmpQuery::numeric()->translate('1.3.6.1.2.1.2.2'); $this->assertEquals('.1.3.6.1.2.1.2.2', $actual); - $actual = \SnmpQuery::translate('.1.3.6.1.2.1.2.2', 'ALL'); + $actual = \SnmpQuery::mibs(['ALL'], append: false)->translate('.1.3.6.1.2.1.2.2'); $this->assertEquals('RFC1213-MIB::ifTable', $actual); - $actual = \SnmpQuery::numeric()->translate('ifTable', 'IP-MIB'); + $actual = \SnmpQuery::numeric()->mibs(['IP-MIB'])->translate('ifTable'); $this->assertEquals('.1.3.6.1.2.1.2.2', $actual); - $actual = \SnmpQuery::translate('ifTable', 'IP-MIB'); + $actual = \SnmpQuery::mibs(['IP-MIB'])->translate('ifTable'); $this->assertEquals('IF-MIB::ifTable', $actual); // with index $actual = \SnmpQuery::numeric()->translate('IF-MIB::ifTable.0'); $this->assertEquals('.1.3.6.1.2.1.2.2.0', $actual); - $actual = \SnmpQuery::numeric()->translate('ifTable.0', 'IF-MIB'); + $actual = \SnmpQuery::numeric()->mibs(['IF-MIB'])->translate('ifTable.0'); $this->assertEquals('.1.3.6.1.2.1.2.2.0', $actual); - $actual = \SnmpQuery::numeric()->translate('ifTable.0', 'ALL'); + $actual = \SnmpQuery::numeric()->mibs(['ALL'], append: false)->translate('ifTable.0'); $this->assertEquals('.1.3.6.1.2.1.2.2.0', $actual); $actual = \SnmpQuery::translate('IF-MIB::ifTable.0'); @@ -78,66 +78,72 @@ class SnmpTranslateTest extends TestCase $actual = \SnmpQuery::numeric()->translate('.1.3.6.1.2.1.2.2.0'); $this->assertEquals('.1.3.6.1.2.1.2.2.0', $actual); - $actual = \SnmpQuery::translate('.1.3.6.1.2.1.2.2.0', 'IF-MIB'); + $actual = \SnmpQuery::mibs(['IF-MIB'])->translate('.1.3.6.1.2.1.2.2.0'); $this->assertEquals('IF-MIB::ifTable.0', $actual); $actual = \SnmpQuery::numeric()->translate('1.3.6.1.2.1.2.2.0'); $this->assertEquals('.1.3.6.1.2.1.2.2.0', $actual); - $actual = \SnmpQuery::translate('.1.3.6.1.2.1.2.2.0', 'ALL'); + $actual = \SnmpQuery::mibs(['ALL'], append: false)->translate('.1.3.6.1.2.1.2.2.0'); $this->assertEquals('RFC1213-MIB::ifTable.0', $actual); - $actual = \SnmpQuery::translate('ifTable.0', 'IP-MIB'); + $actual = \SnmpQuery::mibs(['IP-MIB'])->translate('ifTable.0'); $this->assertEquals('IF-MIB::ifTable.0', $actual); - $actual = \SnmpQuery::translate('iso.3.6.1.2.1.1.1.0', 'SNMPv2-MIB'); + $actual = \SnmpQuery::mibs(['SNMPv2-MIB'])->translate('iso.3.6.1.2.1.1.1.0'); $this->assertEquals('SNMPv2-MIB::sysDescr.0', $actual); - $actual = \SnmpQuery::numeric()->translate('iso.3.6.1.2.1.1.1.0', 'SNMPv2-MIB'); + $actual = \SnmpQuery::numeric()->mibs(['SNMPv2-MIB'])->translate('iso.3.6.1.2.1.1.1.0'); $this->assertEquals('.1.3.6.1.2.1.1.1.0', $actual); } public function testFailedInput(): void { - $actual = \SnmpQuery::numeric()->translate('ifTable'); - $this->assertEquals('', $actual); - $actual = \SnmpQuery::translate('ifTable'); + $this->assertEquals('IF-MIB::ifTable', $actual); + + $actual = \SnmpQuery::numeric()->mibs([], append: false)->translate('ifTable'); $this->assertEquals('', $actual); - $actual = \SnmpQuery::numeric()->translate('ifTable', 'ASDF-MIB:SNMPv2-MIB'); + $actual = \SnmpQuery::mibs([], append: false)->translate('ifTable'); $this->assertEquals('', $actual); - $actual = \SnmpQuery::translate('ifTable'); + $actual = \SnmpQuery::numeric()->mibs(['ASDF-MIB', 'SNMPv2-MIB'], append: false)->translate('ifTable'); $this->assertEquals('', $actual); - $actual = \SnmpQuery::numeric()->translate('ifTable'); + $actual = \SnmpQuery::mibs([], append: false)->translate('ifTable'); $this->assertEquals('', $actual); - $actual = \SnmpQuery::translate('ifTable'); + $actual = \SnmpQuery::numeric()->mibs([], append: false)->translate('ifTable'); + $this->assertEquals('', $actual); + + $actual = \SnmpQuery::mibs([], append: false)->translate('ifTable'); $this->assertEquals('', $actual); } public function testComplexInput(): void { - $actual = \SnmpQuery::translate('.1.3.6.1.2.1.2.2', 'RFC1213-MIB:IF-MIB'); + $actual = \SnmpQuery::mibs(['RFC1213-MIB', 'IF-MIB'], append: false)->translate('.1.3.6.1.2.1.2.2'); $this->assertEquals('RFC1213-MIB::ifTable', $actual); - $actual = \SnmpQuery::translate('.1.3.6.1.2.1.2.2', 'IF-MIB:RFC1213-MIB'); + $actual = \SnmpQuery::mibs(['IF-MIB', 'RFC1213-MIB'], append: false)->translate('.1.3.6.1.2.1.2.2'); $this->assertEquals('IF-MIB::ifTable', $actual); - $actual = \SnmpQuery::translate('ifTable', 'RFC1213-MIB:IF-MIB'); + $actual = \SnmpQuery::translate('ifTable'); + $this->assertEquals('IF-MIB::ifTable', $actual); + + $actual = \SnmpQuery::mibs(['RFC1213-MIB', 'IF-MIB'], append: false)->translate('ifTable'); $this->assertEquals('RFC1213-MIB::ifTable', $actual); - $actual = \SnmpQuery::translate('ifTable', 'IF-MIB:RFC1213-MIB'); + $actual = \SnmpQuery::mibs(['IF-MIB', 'RFC1213-MIB'], append: false)->translate('ifTable'); $this->assertEquals('IF-MIB::ifTable', $actual); // partial numeric $device = Device::factory()->make(['os' => 'dlink']); - $actual = \SnmpQuery::device($device)->numeric()->translate('.1.3.6.1.4.1.171.14.5.1.4.1.4.1.dram', 'EQUIPMENT-MIB:DLINKSW-ENTITY-EXT-MIB'); + $actual = \SnmpQuery::device($device)->numeric()->mibs(['EQUIPMENT-MIB', 'DLINKSW-ENTITY-EXT-MIB'], append: false)->translate('.1.3.6.1.4.1.171.14.5.1.4.1.4.1.dram'); $this->assertEquals('.1.3.6.1.4.1.171.14.5.1.4.1.4.1.1', $actual); - $actual = \SnmpQuery::device($device)->numeric()->translate('iso.3.6.1.4.1.171.14.5.1.4.1.4.1.dram', 'EQUIPMENT-MIB:DLINKSW-ENTITY-EXT-MIB'); + $actual = \SnmpQuery::device($device)->numeric()->mibs(['EQUIPMENT-MIB', 'DLINKSW-ENTITY-EXT-MIB'], append: false)->translate('iso.3.6.1.4.1.171.14.5.1.4.1.4.1.dram'); $this->assertEquals('.1.3.6.1.4.1.171.14.5.1.4.1.4.1.1', $actual); } }