Search code examples
pythonsnmppysnmpmib

How to add variable in the MIB tree?


This is the sample code I got from the https://pysnmp.readthedocs.io/en/latest/examples/v3arch/asyncore/agent/cmdrsp/agent-side-mib-implementations.html here they gave sample program for "Multiple MIB trees under distinct context names".


from pysnmp.entity import engine, config
from pysnmp.entity.rfc3413 import cmdrsp, context
from pysnmp.carrier.asyncore.dgram import udp
from pysnmp.smi import instrum, builder
from pysnmp.proto.api import v2c

# Create SNMP engine
snmpEngine = engine.SnmpEngine()

# Transport setup

# UDP over IPv4
config.addTransport(
    snmpEngine,
    udp.domainName,
    udp.UdpTransport().openServerMode(('127.0.0.1', 161))
)

# SNMPv3/USM setup

# user: usr-md5-none, auth: MD5, priv NONE
config.addV3User(
    snmpEngine, 'usr-md5-none',
    config.usmHMACMD5AuthProtocol, 'authkey1'
)

# Allow full MIB access for each user at VACM
config.addVacmUser(snmpEngine, 3, 'usr-md5-none', 'authNoPriv', (1, 3, 6, 1, 2, 1), (1, 3, 6, 1, 2, 1))

# Create an SNMP context with default ContextEngineId (same as SNMP engine ID)
snmpContext = context.SnmpContext(snmpEngine)

# Create multiple independent trees of MIB managed objects (empty so far)
mibTreeA = instrum.MibInstrumController(builder.MibBuilder())
mibTreeB = instrum.MibInstrumController(builder.MibBuilder())

# Register MIB trees at distinct SNMP Context names
snmpContext.registerContextName(v2c.OctetString('context-a'), mibTreeA)
snmpContext.registerContextName(v2c.OctetString('context-b'), mibTreeB)

# Register SNMP Applications at the SNMP engine for particular SNMP context
cmdrsp.GetCommandResponder(snmpEngine, snmpContext)
cmdrsp.SetCommandResponder(snmpEngine, snmpContext)
cmdrsp.NextCommandResponder(snmpEngine, snmpContext)
cmdrsp.BulkCommandResponder(snmpEngine, snmpContext)

# Register an imaginary never-ending job to keep I/O dispatcher running forever
snmpEngine.transportDispatcher.jobStarted(1)

# Run I/O dispatcher which would receive queries and send responses
try:
    snmpEngine.transportDispatcher.runDispatcher()

except:
    snmpEngine.transportDispatcher.closeDispatcher()
    raise

I tried it with following snmp walk

snmpwalk -v3 -u usr-md5-none -l authNoPriv -A authkey1 -n context-a 127.0.0.1 .1.3.6

and I am getting

SNMPv2-SMI::dod = No more variables left in this MIB View (It is past the end of the MIB tree)

I understood this is happening because the MIB trees are empty. But how to add my data to it?


Solution

  • To generically add or override a functioning MIB tree's OID, you can add the code below to the code example you provided:

    ...
    mibBuilder = snmpContext.getMibInstrum().getMibBuilder()
    
    MibScalar, MibScalarInstance = mibBuilder.importSymbols(
        'SNMPv2-SMI', 'MibScalar', 'MibScalarInstance'
    )
    
    class MyStaticMibScalarInstance(MibScalarInstance):
        def getValue(self, name, idx):
            currentDT = datetime.datetime.now()
            return self.getSyntax().clone(
                'Hello World! It\'s currently: ' + str(currentDT)
            )
    
    mibBuilder.exportSymbols(
        '__MY_MIB', MibScalar((1, 3, 6, 1, 2, 1, 1, 1), v2c.OctetString()),
        MyStaticMibScalarInstance((1, 3, 6, 1, 2, 1, 1, 1), (0,), v2c.OctetString())
    )
    
    # Register SNMP Applications at the SNMP engine for particular SNMP context
    cmdrsp.GetCommandResponder(snmpEngine, snmpContext)
    ...
    
    # snmpwalk -v3 -u usr-md5-none -l authNoPriv -A authkey1 127.0.0.1 .1.3.6
    iso.3.6.1.2.1.1.1.0 = STRING: "Hello World! It's currently: 2019-11-18 16:02:43.796005"
    iso.3.6.1.2.1.1.2.0 = OID: iso.3.6.1.4.1.20408
    iso.3.6.1.2.1.1.3.0 = Timeticks: (494) 0:00:04.94
    iso.3.6.1.2.1.1.4.0 = ""
    iso.3.6.1.2.1.1.5.0 = ""
    iso.3.6.1.2.1.1.6.0 = ""
    iso.3.6.1.2.1.1.7.0 = INTEGER: 0
    iso.3.6.1.2.1.1.8.0 = Timeticks: (0) 0:00:00.00
    iso.3.6.1.2.1.11.1.0 = Counter32: 13
    iso.3.6.1.2.1.11.2.0 = Counter32: 0
    iso.3.6.1.2.1.11.3.0 = Counter32: 0
    iso.3.6.1.2.1.11.4.0 = Counter32: 0
    iso.3.6.1.2.1.11.5.0 = Counter32: 0
    iso.3.6.1.2.1.11.6.0 = Counter32: 0
    iso.3.6.1.2.1.11.8.0 = Counter32: 0
    iso.3.6.1.2.1.11.9.0 = Counter32: 0
    

    If you really need that second context and independent tree you can create a generic controller to examine and send back whatever you want.

    # Create an SNMP context with default ContextEngineId (same as SNMP engine ID)
    snmpContext = context.SnmpContext(snmpEngine)
    
    # Very basic Management Instrumentation Controller without
    # any Managed Objects attached. It supports only GET's and
    # modded to react to a target OID, otherwise
    # always echos request var-binds in response.
    class EchoMibInstrumController(instrum.AbstractMibInstrumController):
        def readVars(self, varBinds, acInfo=(None, None)):
            retItem = []
            for ov in varBinds:
                if str(ov[0]) == '1.3.6.1.2.1.1.1.0':
                    currentDT = datetime.datetime.now()
                    retItem.extend([(ov[0], v2c.OctetString('Hello World! It\'s currently: %s' % str(currentDT)))])
                else:
                    retItem.extend([(ov[0], v2c.OctetString('You queried OID %s' % ov[0]))])
            return retItem
    
    
    # Create multiple independent trees of MIB managed objects (empty so far)
    mibTreeA = EchoMibInstrumController()
    mibTreeB = instrum.MibInstrumController(builder.MibBuilder())
    
    # Register MIB trees at distinct SNMP Context names
    snmpContext.registerContextName(v2c.OctetString('context-a'), mibTreeA)
    snmpContext.registerContextName(v2c.OctetString('context-b'), mibTreeB)
    
    

    snmpget -v3 -u usr-md5-none -l authNoPriv -A authkey1 -n context-a 127.0.0.1 .1.3.6.1.2.1.1.1.0

    # snmpget -v3 -u usr-md5-none -l authNoPriv -A authkey1 127.0.0.1 .1.3.6.1.2.1.1.1.0
    iso.3.6.1.2.1.1.1.0 = STRING: "PySNMP engine version 4.4.12, Python 3.5.2 (default, Jul  5 2016, 12:43:10)  [GCC 5.4.0 20160609]"
    
    # snmpget -v3 -u usr-md5-none -l authNoPriv -A authkey1 -n context-a 127.0.0.1 .1.3.6.1.2.1.1.1.0
    iso.3.6.1.2.1.1.1.0 = STRING: "Hello World! It's currently: 2019-11-18 15:56:26.598242"
    
    # snmpget -v3 -u usr-md5-none -l authNoPriv -A authkey1 -n context-a 127.0.0.1 .1.3.6.1.2.1.1.2.0
    iso.3.6.1.2.1.1.2.0 = STRING: "You queried OID 1.3.6.1.2.1.1.2.0"