Set mibs explicitly in SnmpQuery (#15199)

* Set mibs explicitly in SnmpQuery
Always override system mibs, so we have consistency
New method to control mibs

* Lint fixes
This commit is contained in:
Tony Murray 2023-08-05 07:45:15 -05:00 committed by GitHub
parent d66c09623f
commit 9382959c8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 102 additions and 98 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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();

View File

@ -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;

View File

@ -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)) {

View File

@ -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 [];
}
}

View File

@ -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);
}
}