From 8ede39948b4f6037012552bab20da2ff8376d715 Mon Sep 17 00:00:00 2001 From: elie Date: Sun, 20 Sep 2015 18:40:58 +0000 Subject: major revamp: * oneliner API moved to pysnmp.hlapi.asyncore location * all hlapi components now pulled from inner modules to into pysnmp.hlapi.asyncore. * LCD configuration moved from SNMP apps classes to be stand-alone * var-binds MIB<->protocol representation code moved from SNMP apps classes to be stand-alone --- pysnmp/hlapi/asyncore/__init__.py | 16 + pysnmp/hlapi/asyncore/_sync/cmdgen.py | 613 +++++++++++++++++++++++++++ pysnmp/hlapi/asyncore/_sync/compat/cmdgen.py | 266 ++++++++++++ pysnmp/hlapi/asyncore/_sync/compat/ntforg.py | 52 +++ pysnmp/hlapi/asyncore/_sync/ntforg.py | 124 ++++++ pysnmp/hlapi/asyncore/cmdgen.py | 529 +++++++++++++++++++++++ pysnmp/hlapi/asyncore/ntforg.py | 169 ++++++++ pysnmp/hlapi/asyncore/transport.py | 150 +++++++ pysnmp/hlapi/auth.py | 278 ++++++++++++ pysnmp/hlapi/context.py | 48 +++ pysnmp/hlapi/lcd.py | 259 +++++++++++ pysnmp/hlapi/varbinds.py | 62 +++ pysnmp/proto/rfc1155.py | 3 + pysnmp/proto/rfc1157.py | 3 + pysnmp/proto/rfc1902.py | 4 + pysnmp/proto/rfc1905.py | 6 + pysnmp/smi/rfc1902.py | 15 - 17 files changed, 2582 insertions(+), 15 deletions(-) create mode 100644 pysnmp/hlapi/asyncore/__init__.py create mode 100644 pysnmp/hlapi/asyncore/_sync/cmdgen.py create mode 100644 pysnmp/hlapi/asyncore/_sync/compat/cmdgen.py create mode 100644 pysnmp/hlapi/asyncore/_sync/compat/ntforg.py create mode 100644 pysnmp/hlapi/asyncore/_sync/ntforg.py create mode 100644 pysnmp/hlapi/asyncore/cmdgen.py create mode 100644 pysnmp/hlapi/asyncore/ntforg.py create mode 100644 pysnmp/hlapi/asyncore/transport.py create mode 100644 pysnmp/hlapi/auth.py create mode 100644 pysnmp/hlapi/context.py create mode 100644 pysnmp/hlapi/lcd.py create mode 100644 pysnmp/hlapi/varbinds.py diff --git a/pysnmp/hlapi/asyncore/__init__.py b/pysnmp/hlapi/asyncore/__init__.py new file mode 100644 index 0000000..2f815b6 --- /dev/null +++ b/pysnmp/hlapi/asyncore/__init__.py @@ -0,0 +1,16 @@ +# This file is necessary to make this directory a package. +from pysnmp.proto.rfc1902 import * +from pysnmp.smi.rfc1902 import * +from pysnmp.hlapi.auth import * +from pysnmp.hlapi.context import * +from pysnmp.hlapi.asyncore.transport import * +from pysnmp.hlapi.asyncore.cmdgen import * +from pysnmp.hlapi.asyncore.ntforg import * +from pysnmp.entity.engine import SnmpEngine + +try: + from pysnmp.hlapi.asyncore._sync.cmdgen import * + from pysnmp.hlapi.asyncore._sync.ntforg import * +except SyntaxError: + from pysnmp.hlapi.asyncore._sync.compat.cmdgen import * + from pysnmp.hlapi.asyncore._sync.compat.ntforg import * diff --git a/pysnmp/hlapi/asyncore/_sync/cmdgen.py b/pysnmp/hlapi/asyncore/_sync/cmdgen.py new file mode 100644 index 0000000..357cc52 --- /dev/null +++ b/pysnmp/hlapi/asyncore/_sync/cmdgen.py @@ -0,0 +1,613 @@ +from pysnmp.hlapi.asyncore.cmdgen import * +from pysnmp.hlapi.varbinds import * +from pysnmp.proto.rfc1905 import endOfMibView +from pysnmp.proto.errind import * +from pyasn1.type.univ import Null + +__all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd'] + +def getCmd(snmpEngine, authData, transportTarget, contextData, + *varBinds, **options): + """Creates a generator to perform one or more SNMP GET queries. + + On each iteration, new SNMP GET request is send (:RFC:`1905#section-4.2.1`). + The iterator blocks waiting for response to arrive or error to occur. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.entity.engine.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.CommunityData` or :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.entity.rfc3413.oneliner.target.UdpTransportTarget` or :py:class:`~pysnmp.entity.rfc3413.oneliner.target.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :py:class:`~pysnmp.entity.rfc3413.oneliner.ctx.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + \*varBinds : :py:class:`~pysnmp.smi.rfc1902.ObjectType` + One or more class instances representing MIB variables to place + into SNMP request. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Yields + ------ + errorIndication : str + True value indicates SNMP engine error. + errorStatus : str + True value indicates SNMP PDU error. + errorIndex : int + Non-zero value refers to `varBinds[errorIndex-1]` + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables returned in SNMP response. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Notes + ----- + The `getCmd` generator will be exhausted immidiately unless + a new sequence of `varBinds` are send back into running generator + (supported since Python 2.6). + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.cmdgen import * + >>> g = getCmd(SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0))) + >>> next(g) + (None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'))]) + >>> + + """ + def cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + cbCtx['errorIndication'] = errorIndication + cbCtx['errorStatus'] = errorStatus + cbCtx['errorIndex'] = errorIndex + cbCtx['varBinds'] = varBinds + + cbCtx = {} + + cmdGen = AsyncCommandGenerator() + + while True: + if varBinds: + cmdGen.getCmd( + snmpEngine, + authData, + transportTarget, + contextData, + varBinds, + (cbFun, cbCtx), + options.get('lookupMib', True) + ) + + snmpEngine.transportDispatcher.runDispatcher() + + errorIndication = cbCtx['errorIndication'] + errorStatus = cbCtx['errorStatus'] + errorIndex = cbCtx['errorIndex'] + varBinds = cbCtx['varBinds'] + else: + errorIndication = errorStatus = errorIndex = None + varBinds = [] + + varBinds = ( yield errorIndication, errorStatus, errorIndex, varBinds ) + + if not varBinds: + break + +def setCmd(snmpEngine, authData, transportTarget, contextData, + *varBinds, **options): + """Creates a generator to perform one or more SNMP SET queries. + + On each iteration, new SNMP SET request is send (:RFC:`1905#section-4.2.5`). + The iterator blocks waiting for response to arrive or error to occur. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.entity.engine.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.CommunityData` or :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.entity.rfc3413.oneliner.target.UdpTransportTarget` or :py:class:`~pysnmp.entity.rfc3413.oneliner.target.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :py:class:`~pysnmp.entity.rfc3413.oneliner.ctx.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + \*varBinds : :py:class:`~pysnmp.smi.rfc1902.ObjectType` + One or more class instances representing MIB variables to place + into SNMP request. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + Default is `True`. + + Yields + ------ + errorIndication : str + True value indicates SNMP engine error. + errorStatus : str + True value indicates SNMP PDU error. + errorIndex : int + Non-zero value refers to `varBinds[errorIndex-1]` + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables returned in SNMP response. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Notes + ----- + The `setCmd` generator will be exhausted immidiately unless + a new sequence of `varBinds` are send back into running generator + (supported since Python 2.6). + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.cmdgen import * + >>> g = setCmd(SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0), 'Linux i386')) + >>> next(g) + (None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('Linux i386'))]) + >>> + + """ + def cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + cbCtx['errorIndication'] = errorIndication + cbCtx['errorStatus'] = errorStatus + cbCtx['errorIndex'] = errorIndex + cbCtx['varBinds'] = varBinds + + cbCtx = {} + + cmdGen = AsyncCommandGenerator() + + while True: + if varBinds: + cmdGen.setCmd( + snmpEngine, + authData, + transportTarget, + contextData, + varBinds, + (cbFun, cbCtx), + options.get('lookupMib', True) + ) + + snmpEngine.transportDispatcher.runDispatcher() + + errorIndication = cbCtx['errorIndication'] + errorStatus = cbCtx['errorStatus'] + errorIndex = cbCtx['errorIndex'] + varBinds = cbCtx['varBinds'] + else: + errorIndication = errorStatus = errorIndex = None + varBinds = [] + + varBinds = ( yield errorIndication, errorStatus, errorIndex, varBinds ) + + if not varBinds: + break + +def nextCmd(snmpEngine, authData, transportTarget, contextData, + *varBinds, **options): + """Creates a generator to perform one or more SNMP GETNEXT queries. + + On each iteration, new SNMP GETNEXT request is send + (:RFC:`1905#section-4.2.2`). The iterator blocks waiting for response + to arrive or error to occur. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.entity.engine.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.CommunityData` or :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.entity.rfc3413.oneliner.target.UdpTransportTarget` or :py:class:`~pysnmp.entity.rfc3413.oneliner.target.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :py:class:`~pysnmp.entity.rfc3413.oneliner.ctx.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + \*varBinds : :py:class:`~pysnmp.smi.rfc1902.ObjectType` + One or more class instances representing MIB variables to place + into SNMP request. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + Default is `True`. + * `lexicographicMode` - stop iteration when all response MIB + variables leave the scope of initial MIB variables in + `varBinds`. Default is `True`. + * `ignoreNonIncreasingOid` - continue iteration even if response + MIB variables (OIDs) are not greater then request MIB variables. + Default is `False`. + * `maxRows` - stop iteration once this generator instance processed + `maxRows` of SNMP conceptual table. Default is `0` (no limit). + * `maxCalls` - stop iteration once this generator instance processed + `maxCalls` responses. Default is 0 (no limit). + + Yields + ------ + errorIndication : str + True value indicates SNMP engine error. + errorStatus : str + True value indicates SNMP PDU error. + errorIndex : int + Non-zero value refers to `varBinds[errorIndex-1]` + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables returned in SNMP response. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Notes + ----- + The `nextCmd` generator will be exhausted on any of the following + conditions: + + * SNMP engine error occurs thus `errorIndication` is `True` + * SNMP PDU `errorStatus` is reported as `True` + * SNMP :py:class:`~pysnmp.proto.rfc1905.EndOfMibView` values + (also known as *SNMP exception values*) are reported for all + MIB variables in `varBinds` + * *lexicographicMode* option is set to `False` and all + response MIB variables leave the scope of `varBinds` + + At any moment a new sequence of `varBinds` could be send back into + running generator (supported since Python 2.6). + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.cmdgen import * + >>> g = nextCmd(SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr'))) + >>> next(g) + (None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'))]) + >>> g.send( [ ObjectType(ObjectIdentity('IF-MIB', 'ifInOctets')) ] ) + (None, 0, 0, [(ObjectName('1.3.6.1.2.1.2.2.1.10.1'), Counter32(284817787))]) + """ + def cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBindTable, cbCtx): + cbCtx['errorIndication'] = errorIndication + cbCtx['errorStatus'] = errorStatus + cbCtx['errorIndex'] = errorIndex + cbCtx['varBindTable'] = varBindTable + + lookupMib = options.get('lookupMib', True) + lexicographicMode = options.get('lexicographicMode', True) + ignoreNonIncreasingOid = options.get('ignoreNonIncreasingOid', False) + maxRows = options.get('maxRows', 0) + maxCalls = options.get('maxCalls', 0) + + cbCtx = {} + + vbProcessor = CommandGeneratorVarBinds() + + cmdGen = AsyncCommandGenerator() + + initialVars = [ x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds) ] + + totalRows = totalCalls = 0 + + while True: + if varBinds: + cmdGen.nextCmd(snmpEngine, + authData, + transportTarget, + contextData, + [ (x[0], Null()) for x in varBinds ], + (cbFun, cbCtx), + lookupMib) + + snmpEngine.transportDispatcher.runDispatcher() + + errorIndication = cbCtx['errorIndication'] + errorStatus = cbCtx['errorStatus'] + errorIndex = cbCtx['errorIndex'] + + if ignoreNonIncreasingOid and errorIndication and \ + isinstance(errorIndication, errind.OidNotIncreasing): + errorIndication = None + + if errorIndication: + yield errorIndication, errorStatus, errorIndex, varBinds + return + elif errorStatus: + if errorStatus == 2: + # Hide SNMPv1 noSuchName error which leaks in here + # from SNMPv1 Agent through internal pysnmp proxy. + errorStatus = errorStatus.clone(0) + errorIndex = errorIndex.clone(0) + yield errorIndication, errorStatus, errorIndex, varBinds + return + else: + varBinds = cbCtx['varBindTable'] and cbCtx['varBindTable'][0] + for idx, varBind in enumerate(varBinds): + name, val = varBind + if not isinstance(val, Null): + if lexicographicMode or initialVars[idx].isPrefixOf(name): + break + else: + return + + totalRows += 1 + totalCalls += 1 + else: + errorIndication = errorStatus = errorIndex = None + varBinds = [] + + initialVarBinds = ( yield errorIndication, errorStatus, + errorIndex, varBinds ) + + if initialVarBinds: + varBinds = initialVarBinds + initialVars = [ x[0] for x in vbProcessor.makeVarBinds(snmpEngine, + varBinds) ] + + if maxRows and totalRows >= maxRows or \ + maxCalls and totalCalls >= maxCalls: + return + +def bulkCmd(snmpEngine, authData, transportTarget, contextData, + nonRepeaters, maxRepetitions, *varBinds, **options): + """Creates a generator to perform one or more SNMP GETBULK queries. + + On each iteration, new SNMP GETBULK request is send + (:RFC:`1905#section-4.2.3`). The iterator blocks waiting for response + to arrive or error to occur. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.entity.engine.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.CommunityData` or :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.entity.rfc3413.oneliner.target.UdpTransportTarget` or :py:class:`~pysnmp.entity.rfc3413.oneliner.target.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :py:class:`~pysnmp.entity.rfc3413.oneliner.ctx.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + nonRepeaters : int + One MIB variable is requested in response for the first + `nonRepeaters` MIB variables in request. + + maxRepetitions : int + `maxRepetitions` MIB variables are requested in response for each + of the remaining MIB variables in the request (e.g. excluding + `nonRepeaters`). Remote SNMP engine may choose lesser value than + requested. + + \*varBinds : :py:class:`~pysnmp.smi.rfc1902.ObjectType` + One or more class instances representing MIB variables to place + into SNMP request. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + Default is `True`. + * `lexicographicMode` - stop iteration when all response MIB + variables leave the scope of initial MIB variables in + `varBinds`. Default is `True`. + * `ignoreNonIncreasingOid` - continue iteration even if response + MIB variables (OIDs) are not greater then request MIB variables. + Default is `False`. + * `maxRows` - stop iteration once this generator instance processed + `maxRows` of SNMP conceptual table. Default is `0` (no limit). + * `maxCalls` - stop iteration once this generator instance processed + `maxCalls` responses. Default is 0 (no limit). + + Yields + ------ + errorIndication : str + True value indicates SNMP engine error. + errorStatus : str + True value indicates SNMP PDU error. + errorIndex : int + Non-zero value refers to *varBinds[errorIndex-1] + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables returned in SNMP response. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Notes + ----- + The `bulkCmd` generator will be exhausted on any of the following + conditions: + + * SNMP engine error occurs thus `errorIndication` is `True` + * SNMP PDU `errorStatus` is reported as `True` + * SNMP :py:class:`~pysnmp.proto.rfc1905.EndOfMibView` values + (also known as *SNMP exception values*) are reported for all + MIB variables in `varBinds` + * *lexicographicMode* option is set to `False` and all + response MIB variables leave the scope of `varBinds` + + At any moment a new sequence of `varBinds` could be send back into + running generator (supported since Python 2.6). + + Setting `maxRepetitions` value to 15..50 might significantly improve + system performance, as many MIB variables get packed into a single + response message at once. + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.cmdgen import * + >>> g = bulkCmd(SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... 0, 25, + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr'))) + >>> next(g) + (None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'))]) + >>> g.send( [ ObjectType(ObjectIdentity('IF-MIB', 'ifInOctets')) ] ) + (None, 0, 0, [(ObjectName('1.3.6.1.2.1.2.2.1.10.1'), Counter32(284817787))]) + """ + def cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBindTable, cbCtx): + cbCtx['errorIndication'] = errorIndication + cbCtx['errorStatus'] = errorStatus + cbCtx['errorIndex'] = errorIndex + cbCtx['varBindTable'] = varBindTable + + lookupMib = options.get('lookupMib', True) + lexicographicMode = options.get('lexicographicMode', True) + ignoreNonIncreasingOid = options.get('ignoreNonIncreasingOid', False) + maxRows = options.get('maxRows', 0) + maxCalls = options.get('maxCalls', 0) + + cbCtx = {} + + vbProcessor = CommandGeneratorVarBinds() + + cmdGen = AsyncCommandGenerator() + + initialVars = [ x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds) ] + nullVarBinds = [ False ] * len(initialVars) + + totalRows = totalCalls = 0 + stopFlag = False + + while not stopFlag: + if maxRows and totalRows < maxRows: + maxRepetitions = min(maxRepetitions, maxRows-totalRows) + + cmdGen.bulkCmd(snmpEngine, + authData, + transportTarget, + contextData, + nonRepeaters, maxRepetitions, + [ (x[0], Null()) for x in varBinds ], + (cbFun, cbCtx), + lookupMib) + + snmpEngine.transportDispatcher.runDispatcher() + + errorIndication = cbCtx['errorIndication'] + errorStatus = cbCtx['errorStatus'] + errorIndex = cbCtx['errorIndex'] + varBindTable = cbCtx['varBindTable'] + + if ignoreNonIncreasingOid and errorIndication and \ + isinstance(errorIndication, errind.OidNotIncreasing): + errorIndication = None + + if errorIndication: + yield errorIndication, errorStatus, errorIndex, \ + varBindTable and varBindTable[0] or [] + if errorIndication != errind.requestTimedOut: + return + elif errorStatus: + if errorStatus == 2: + # Hide SNMPv1 noSuchName error which leaks in here + # from SNMPv1 Agent through internal pysnmp proxy. + errorStatus = errorStatus.clone(0) + errorIndex = errorIndex.clone(0) + yield errorIndication, errorStatus, errorIndex, \ + varBindTable and varBindTable[0] or [] + return + else: + for i in range(len(varBindTable)): + stopFlag = True + if len(varBindTable[i]) != len(initialVars): + varBindTable = i and varBindTable[:i-1] or [] + break + for j in range(len(varBindTable[i])): + name, val = varBindTable[i][j] + if nullVarBinds[j]: + varBindTable[i][j] = name, endOfMibView + continue + stopFlag = False + if isinstance(val, Null): + nullVarBinds[j] = True + elif not lexicographicMode and \ + not initialVars[j].isPrefixOf(name): + varBindTable[i][j] = name, endOfMibView + nullVarBinds[j] = True + if stopFlag: + varBindTable = i and varBindTable[:i-1] or [] + break + + totalRows += len(varBindTable) + totalCalls += 1 + + if maxRows and totalRows >= maxRows: + if totalRows > maxRows: + varBindTable = varBindTable[:-(totalRows-maxRows)] + stopFlag = True + + if maxCalls and totalCalls >= maxCalls: + stopFlag = True + + for varBinds in varBindTable: + initialVarBinds = ( yield errorIndication, errorStatus, + errorIndex, varBinds ) + + if initialVarBinds: + varBinds = initialVarBinds + initialVars = [ x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds) ] diff --git a/pysnmp/hlapi/asyncore/_sync/compat/cmdgen.py b/pysnmp/hlapi/asyncore/_sync/compat/cmdgen.py new file mode 100644 index 0000000..530c376 --- /dev/null +++ b/pysnmp/hlapi/asyncore/_sync/compat/cmdgen.py @@ -0,0 +1,266 @@ +# +# This is a Python 2.6- version of the same file at level up +# +from pysnmp.hlapi.asyncore.cmdgen import * +from pysnmp.hlapi.varbinds import * +from pysnmp.proto.rfc1905 import endOfMibView +from pysnmp.proto.errind import * +from pyasn1.type.univ import Null + +__all__ = ['getCmd', 'nextCmd', 'setCmd', 'bulkCmd', 'next'] + +def next(iter): + return iter.next() + +def getCmd(snmpEngine, authData, transportTarget, contextData, + *varBinds, **options): + + def cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + cbCtx['errorIndication'] = errorIndication + cbCtx['errorStatus'] = errorStatus + cbCtx['errorIndex'] = errorIndex + cbCtx['varBinds'] = varBinds + + cbCtx = {} + + cmdGen = AsyncCommandGenerator() + + if varBinds: + cmdGen.getCmd( + snmpEngine, + authData, + transportTarget, + contextData, + varBinds, + (cbFun, cbCtx), + options.get('lookupMib', True) + ) + + snmpEngine.transportDispatcher.runDispatcher() + + errorIndication = cbCtx['errorIndication'] + errorStatus = cbCtx['errorStatus'] + errorIndex = cbCtx['errorIndex'] + varBinds = cbCtx['varBinds'] + else: + errorIndication = errorStatus = errorIndex = None + varBinds = [] + + yield errorIndication, errorStatus, errorIndex, varBinds + +def setCmd(snmpEngine, authData, transportTarget, contextData, + *varBinds, **options): + + def cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + cbCtx['errorIndication'] = errorIndication + cbCtx['errorStatus'] = errorStatus + cbCtx['errorIndex'] = errorIndex + cbCtx['varBinds'] = varBinds + + cbCtx = {} + + cmdGen = AsyncCommandGenerator() + + while True: + cmdGen.setCmd( + snmpEngine, + authData, + transportTarget, + contextData, + varBinds, + (cbFun, cbCtx), + options.get('lookupMib', True) + ) + + snmpEngine.transportDispatcher.runDispatcher() + + yield cbCtx['errorIndication'], \ + cbCtx['errorStatus'], cbCtx['errorIndex'], \ + cbCtx['varBinds'] + + if cbCtx['errorIndication'] != errind.requestTimedOut: + break + +def nextCmd(snmpEngine, authData, transportTarget, contextData, + *varBinds, **options): + + def cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBindTable, cbCtx): + cbCtx['errorIndication'] = errorIndication + cbCtx['errorStatus'] = errorStatus + cbCtx['errorIndex'] = errorIndex + cbCtx['varBindTable'] = varBindTable + + lookupMib = options.get('lookupMib', True) + lexicographicMode = options.get('lexicographicMode', True) + ignoreNonIncreasingOid = options.get('ignoreNonIncreasingOid', False) + maxRows = options.get('maxRows', 0) + maxCalls = options.get('maxCalls', 0) + + cbCtx = {} + + vbProcessor = CommandGeneratorVarBinds() + + cmdGen = AsyncCommandGenerator() + + initialVars = [ x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds) ] + + totalRows = totalCalls = 0 + + while True: + cmdGen.nextCmd(snmpEngine, + authData, + transportTarget, + contextData, + [ (x[0], Null()) for x in varBinds ], + (cbFun, cbCtx), + lookupMib) + + snmpEngine.transportDispatcher.runDispatcher() + + errorIndication = cbCtx['errorIndication'] + errorStatus = cbCtx['errorStatus'] + errorIndex = cbCtx['errorIndex'] + + if ignoreNonIncreasingOid and errorIndication and \ + isinstance(errorIndication, errind.OidNotIncreasing): + errorIndication = None + + if errorIndication: + yield errorIndication, errorStatus, errorIndex, varBinds + if errorIndication != errind.requestTimedOut: + return + elif errorStatus: + if errorStatus == 2: + # Hide SNMPv1 noSuchName error which leaks in here + # from SNMPv1 Agent through internal pysnmp proxy. + errorStatus = errorStatus.clone(0) + errorIndex = errorIndex.clone(0) + yield errorIndication, errorStatus, errorIndex, varBinds + return + else: + varBinds = cbCtx['varBindTable'] and cbCtx['varBindTable'][0] + for idx, varBind in enumerate(varBinds): + name, val = varBind + if not isinstance(val, Null): + if lexicographicMode or initialVars[idx].isPrefixOf(name): + break + else: + return + + totalRows += 1 + totalCalls += 1 + + yield errorIndication, errorStatus, errorIndex, varBinds + + if maxRows and totalRows >= maxRows or \ + maxCalls and totalCalls >= maxCalls: + return + +def bulkCmd(snmpEngine, authData, transportTarget, contextData, + nonRepeaters, maxRepetitions, *varBinds, **options): + + def cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBindTable, cbCtx): + cbCtx['errorIndication'] = errorIndication + cbCtx['errorStatus'] = errorStatus + cbCtx['errorIndex'] = errorIndex + cbCtx['varBindTable'] = varBindTable + + lookupMib = options.get('lookupMib', True) + lexicographicMode = options.get('lexicographicMode', True) + ignoreNonIncreasingOid = options.get('ignoreNonIncreasingOid', False) + maxRows = options.get('maxRows', 0) + maxCalls = options.get('maxCalls', 0) + + cbCtx = {} + + vbProcessor = CommandGeneratorVarBinds() + + cmdGen = AsyncCommandGenerator() + + initialVars = [ x[0] for x in vbProcessor.makeVarBinds(snmpEngine, varBinds) ] + nullVarBinds = [ False ] * len(initialVars) + + totalRows = totalCalls = 0 + stopFlag = False + + while not stopFlag: + if maxRows and totalRows < maxRows: + maxRepetitions = min(maxRepetitions, maxRows-totalRows) + + cmdGen.bulkCmd(snmpEngine, + authData, + transportTarget, + contextData, + nonRepeaters, maxRepetitions, + [ (x[0], Null()) for x in varBinds ], + (cbFun, cbCtx), + lookupMib) + + snmpEngine.transportDispatcher.runDispatcher() + + errorIndication = cbCtx['errorIndication'] + errorStatus = cbCtx['errorStatus'] + errorIndex = cbCtx['errorIndex'] + varBindTable = cbCtx['varBindTable'] + + if ignoreNonIncreasingOid and errorIndication and \ + isinstance(errorIndication, errind.OidNotIncreasing): + errorIndication = None + + if errorIndication: + yield errorIndication, errorStatus, errorIndex, \ + varBindTable and varBindTable[0] or [] + if errorIndication != errind.requestTimedOut: + return + elif errorStatus: + if errorStatus == 2: + # Hide SNMPv1 noSuchName error which leaks in here + # from SNMPv1 Agent through internal pysnmp proxy. + errorStatus = errorStatus.clone(0) + errorIndex = errorIndex.clone(0) + yield errorIndication, errorStatus, errorIndex, \ + varBindTable and varBindTable[0] or [] + return + else: + for i in range(len(varBindTable)): + stopFlag = True + if len(varBindTable[i]) != len(initialVars): + varBindTable = i and varBindTable[:i-1] or [] + break + for j in range(len(varBindTable[i])): + name, val = varBindTable[i][j] + if nullVarBinds[j]: + varBindTable[i][j] = name, endOfMibView + continue + stopFlag = False + if isinstance(val, Null): + nullVarBinds[j] = True + elif not lexicographicMode and \ + not initialVars[j].isPrefixOf(name): + varBindTable[i][j] = name, endOfMibView + nullVarBinds[j] = True + if stopFlag: + varBindTable = i and varBindTable[:i-1] or [] + break + + totalRows += len(varBindTable) + totalCalls += 1 + + if maxRows and totalRows >= maxRows: + if totalRows > maxRows: + varBindTable = varBindTable[:-(totalRows-maxRows)] + stopFlag = True + + if maxCalls and totalCalls >= maxCalls: + stopFlag = True + + for varBinds in varBindTable: + yield errorIndication, errorStatus, errorIndex, varBinds diff --git a/pysnmp/hlapi/asyncore/_sync/compat/ntforg.py b/pysnmp/hlapi/asyncore/_sync/compat/ntforg.py new file mode 100644 index 0000000..420b3b6 --- /dev/null +++ b/pysnmp/hlapi/asyncore/_sync/compat/ntforg.py @@ -0,0 +1,52 @@ +# +# This is a Python 2.6- version of the same file at level up +# +from pysnmp.hlapi.asyncore.ntforg import * + +__all__ = ['sendNotification', 'next'] + +def next(iter): + return iter.next() + +# +# Synchronous one-liner SNMP Notification Originator application +# + +def sendNotification(snmpEngine, authData, transportTarget, contextData, + notifyType, varBinds, **options): + + def cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + cbCtx['errorIndication'] = errorIndication + cbCtx['errorStatus'] = errorStatus + cbCtx['errorIndex'] = errorIndex + cbCtx['varBinds'] = varBinds + + cbCtx = {} + + ntfOrg = AsyncNotificationOriginator() + + if varBinds: + ntfOrg.sendNotification( + snmpEngine, + authData, + transportTarget, + contextData, + notifyType, + varBinds, + (cbFun, cbCtx), + options.get('lookupMib', True) + ) + + snmpEngine.transportDispatcher.runDispatcher() + + errorIndication = cbCtx.get('errorIndication') + errorStatus = cbCtx.get('errorStatus') + errorIndex = cbCtx.get('errorIndex') + varBinds = cbCtx.get('varBinds', []) + else: + errorIndication = errorStatus = errorIndex = None + varBinds = [] + + yield errorIndication, errorStatus, errorIndex, varBinds diff --git a/pysnmp/hlapi/asyncore/_sync/ntforg.py b/pysnmp/hlapi/asyncore/_sync/ntforg.py new file mode 100644 index 0000000..bec88cf --- /dev/null +++ b/pysnmp/hlapi/asyncore/_sync/ntforg.py @@ -0,0 +1,124 @@ +from pysnmp.hlapi.asyncore.ntforg import * + +__all__ = ['sendNotification'] + +def sendNotification(snmpEngine, authData, transportTarget, contextData, + notifyType, varBinds, **options): + """Creates a generator to send one or more SNMP notifications. + + On each iteration, new SNMP TRAP or INFORM notification is send + (:RFC:`1905#section-4,2,6`). The iterator blocks waiting for + INFORM acknowlegement to arrive or error to occur. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.entity.engine.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.CommunityData` or :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.entity.rfc3413.oneliner.target.UdpTransportTarget` or :py:class:`~pysnmp.entity.rfc3413.oneliner.target.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer address. + + contextData : :py:class:`~pysnmp.entity.rfc3413.oneliner.ctx.ContextData` + Class instance representing SNMP ContextEngineId and ContextName values. + + notifyType : str + Indicates type of notification to be sent. Recognized literal + values are *trap* or *inform*. + + varBinds: tuple + Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class instance + representing a minimum sequence of MIB variables required for + particular notification type. + Alternatively, a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` + objects could be passed instead. In the latter case it is up to + the user to ensure proper Notification PDU contents. + + Other Parameters + ---------------- + \*\*options : + Request options: + + * `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Yields + ------ + errorIndication : str + True value indicates SNMP engine error. + errorStatus : str + True value indicates SNMP PDU error. + errorIndex : int + Non-zero value refers to `varBinds[errorIndex-1]` + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables returned in SNMP response. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Notes + ----- + The `sendNotification` generator will be exhausted immidiately unless + an instance of :py:class:`~pysnmp.smi.rfc1902.NotificationType` class + or a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` `varBinds` + are send back into running generator (supported since Python 2.6). + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.ntforg import * + >>> g = sendNotification(SnmpEngine(), + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 162)), + ... ContextData(), + ... 'trap', + ... NotificationType(ObjectIdentity('IF-MIB', 'linkDown'))) + >>> next(g) + (None, 0, 0, []) + >>> + + """ + def cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + cbCtx['errorIndication'] = errorIndication + cbCtx['errorStatus'] = errorStatus + cbCtx['errorIndex'] = errorIndex + cbCtx['varBinds'] = varBinds + + cbCtx = {} + + ntfOrg = AsyncNotificationOriginator() + + while True: + if varBinds: + ntfOrg.sendNotification( + snmpEngine, + authData, + transportTarget, + contextData, + notifyType, + varBinds, + cbInfo=(cbFun, cbCtx), + lookupMib=options.get('lookupMib', True) + ) + + snmpEngine.transportDispatcher.runDispatcher() + + errorIndication = cbCtx.get('errorIndication') + errorStatus = cbCtx.get('errorStatus') + errorIndex = cbCtx.get('errorIndex') + varBinds = cbCtx.get('varBinds', []) + else: + errorIndication = errorStatus = errorIndex = None + varBinds = [] + + varBinds = ( yield errorIndication, errorStatus, errorIndex, varBinds ) + + if not varBinds: + break diff --git a/pysnmp/hlapi/asyncore/cmdgen.py b/pysnmp/hlapi/asyncore/cmdgen.py new file mode 100644 index 0000000..850dade --- /dev/null +++ b/pysnmp/hlapi/asyncore/cmdgen.py @@ -0,0 +1,529 @@ +from sys import version_info +from pysnmp.entity import config +from pysnmp.entity.rfc3413 import cmdgen +from pysnmp.smi.rfc1902 import * +from pysnmp.hlapi.auth import * +from pysnmp.hlapi.context import * +from pysnmp.hlapi.lcd import * +from pysnmp.hlapi.varbinds import * +from pysnmp.hlapi.asyncore.transport import * +from pysnmp.proto import rfc1905, errind +from pyasn1.type import univ, base + +__all__ = ['AsyncCommandGenerator'] + +class AsyncCommandGenerator: + """Creates asyncore-based SNMP Command Generator object. + + This is a high-level wrapper around pure Command Generator + impementation that aims at simplyfing + :py:class:`pysnmp.entity.engine.SnmpEngine`'s Local Configuration + Datastore (:RFC:`2271#section-3.4.2`) management. Typically, + users instantiate `AsyncCommandGenerator` and call its + commmand-specific methods passing them canned Security, + Transport and SNMP Context parameters along with + :py:class:`~pysnmp.smi.rfc1902.ObjectType` object carrying + MIB variables to include with SNMP request. `AsyncCommandGenerator` + will manage LCD by applying user-supplied configuratoin parameters + and running requested operation. + + See :RFC:`3413#section-3.1` for more information on SNMP + Command Generator purpose, design and supported operations. + + """ + vbProcessor = CommandGeneratorVarBinds() + lcd = CommandGeneratorLcdConfigurator() + + def getCmd(self, snmpEngine, authData, transportTarget, contextData, + varBinds, cbInfo, lookupMib=True): + """Performs SNMP GET query. + + Based on passed parameters, prepares SNMP GET packet + (:RFC:`1905#section-4.2.1`) and schedules its transmission by + I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.entity.engine.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.CommunityData` or :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.entity.rfc3413.oneliner.target.UdpTransportTarget` or :py:class:`~pysnmp.entity.rfc3413.oneliner.target.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer + address. + + contextData : :py:class:`~pysnmp.entity.rfc3413.oneliner.ctx.ContextData` + Class instance representing SNMP ContextEngineId and ContextName + values. + + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables to place into SNMP request. + + cbInfo : tuple + + * `cbFun` - user-supplied callable that is invoked to pass + SNMP response data or error to user at a later point of time. + * `cbCtx` - user-supplied object passing additional parameters + to/from `cbFun`. Default is `None`. + + Other Parameters + ---------------- + lookupMib : bool + `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Notes + ----- + User-supplied `cbFun` callable must have the following call + signature: + + * snmpEngine (:py:class:`~pysnmp.entity.engine.SnmpEngine`): + Class instance representing SNMP engine. + * sendRequestHandle (int): Unique request identifier. Can be used + for matching multiple ongoing requests with received responses. + * errorIndication (str): True value indicates SNMP engine error. + * errorStatus (str): True value indicates SNMP PDU error. + * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple): A sequence of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing MIB variables returned in SNMP response in exactly + the same order as `varBinds` in request. + * `cbCtx` : Original user-supplied object. + + Returns + ------- + sendRequestHandle : int + Unique request identifier. Can be used for matching received + responses with ongoing requests. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.cmdgen import * + >>> def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + ... print(errorIndication, errorStatus, errorIndex, varBinds) + >>> + >>> snmpEngine = SnmpEngine() + >>> g = AsyncCommandGenerator() + >>> g.getCmd(snmpEngine, + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0)), + ... (cbFun, None)) + >>> snmpEngine.transportDispatcher.runDispatcher() + (None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'))]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + return cbFun( + snmpEngine, + sendRequestHandle, + errorIndication, + errorStatus, + errorIndex, + self.vbProcessor.unmakeVarBinds( + snmpEngine, varBinds, lookupMib + ), + cbCtx + ) + + (cbFun, cbCtx) = cbInfo + addrName, paramsName = self.lcd.configure( + snmpEngine, authData, transportTarget + ) + + return cmdgen.GetCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + self.vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (lookupMib, cbFun, cbCtx) + ) + + def setCmd(self, snmpEngine, authData, transportTarget, contextData, + varBinds, cbInfo, lookupMib=True): + """Performs SNMP SET query. + + Based on passed parameters, prepares SNMP SET packet + (:RFC:`1905#section-4.2.5`) and schedules its transmission by + I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.entity.engine.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.CommunityData` or :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.entity.rfc3413.oneliner.target.UdpTransportTarget` or :py:class:`~pysnmp.entity.rfc3413.oneliner.target.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer + address. + + contextData : :py:class:`~pysnmp.entity.rfc3413.oneliner.ctx.ContextData` + Class instance representing SNMP ContextEngineId and ContextName + values. + + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables to place into SNMP request. + + cbInfo : tuple + + * `cbFun` - user-supplied callable that is invoked to pass + SNMP response data or error to user at a later point of time. + * `cbCtx` - user-supplied object passing additional parameters + to/from `cbFun`. Default is `None`. + + Other Parameters + ---------------- + lookupMib : bool + `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Notes + ----- + User-supplied `cbFun` callable must have the following call + signature: + + * snmpEngine (:py:class:`~pysnmp.entity.engine.SnmpEngine`): + Class instance representing SNMP engine. + * sendRequestHandle (int): Unique request identifier. Can be used + for matching multiple ongoing requests with received responses. + * errorIndication (str): True value indicates SNMP engine error. + * errorStatus (str): True value indicates SNMP PDU error. + * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple): A sequence of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing MIB variables returned in SNMP response in exactly + the same order as `varBinds` in request. + * `cbCtx` : Original user-supplied object. + + Returns + ------- + sendRequestHandle : int + Unique request identifier. Can be used for matching received + responses with ongoing requests. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.cmdgen import * + >>> def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + ... print(errorIndication, errorStatus, errorIndex, varBinds) + >>> + >>> snmpEngine = SnmpEngine() + >>> g = AsyncCommandGenerator() + >>> g.setCmd(snmpEngine, + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysContact', 0), 'info@snmplabs.com'), + ... (cbFun, None)) + >>> snmpEngine.transportDispatcher.runDispatcher() + (None, 0, 0, [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.4.0')), DisplayString('info@snmplabs.com'))]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBinds, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + return cbFun( + snmpEngine, + sendRequestHandle, + errorIndication, + errorStatus, + errorIndex, + self.vbProcessor.unmakeVarBinds( + snmpEngine, varBinds, lookupMib + ), + cbCtx + ) + + (cbFun, cbCtx) = cbInfo + addrName, paramsName = self.lcd.configure( + snmpEngine, authData, transportTarget + ) + + return cmdgen.SetCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + self.vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (lookupMib, cbFun, cbCtx) + ) + + def nextCmd(self, snmpEngine, authData, transportTarget, contextData, + varBinds, cbInfo, lookupMib=True): + """Performs SNMP GETNEXT query. + + Based on passed parameters, prepares SNMP GETNEXT packet + (:RFC:`1905#section-4.2.2`) and schedules its transmission by + I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.entity.engine.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.CommunityData` or :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.entity.rfc3413.oneliner.target.UdpTransportTarget` or :py:class:`~pysnmp.entity.rfc3413.oneliner.target.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer + address. + + contextData : :py:class:`~pysnmp.entity.rfc3413.oneliner.ctx.ContextData` + Class instance representing SNMP ContextEngineId and ContextName + values. + + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables to place into SNMP request. + + cbInfo : tuple + + * `cbFun` - user-supplied callable that is invoked to pass + SNMP response data or error to user at a later point of time. + * `cbCtx` - user-supplied object passing additional parameters + to/from `cbFun`. Default is `None`. + + Other Parameters + ---------------- + lookupMib : bool + `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Notes + ----- + User-supplied `cbFun` callable must have the following call + signature: + + * snmpEngine (:py:class:`~pysnmp.entity.engine.SnmpEngine`): + Class instance representing SNMP engine. + * sendRequestHandle (int): Unique request identifier. Can be used + for matching multiple ongoing requests with received responses. + * errorIndication (str): True value indicates SNMP engine error. + * errorStatus (str): True value indicates SNMP PDU error. + * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple): A sequence of sequences (e.g. 2-D array) of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing a table of MIB variables returned in SNMP response. + Inner sequences represent table rows and ordered exactly the same + as `varBinds` in request. Response to GETNEXT always contain a + single row. + * `cbCtx` : Original user-supplied object. + + Returns + ------- + sendRequestHandle : int + Unique request identifier. Can be used for matching received + responses with ongoing requests. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.cmdgen import * + >>> def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + ... print(errorIndication, errorStatus, errorIndex, varBinds) + >>> + >>> snmpEngine = SnmpEngine() + >>> g = AsyncCommandGenerator() + >>> g.nextCmd(snmpEngine, + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'system')), + ... (cbFun, None)) + >>> snmpEngine.transportDispatcher.runDispatcher() + (None, 0, 0, [ [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'))] ]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBindTable, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + return cbFun( + snmpEngine, + sendRequestHandle, + errorIndication, + errorStatus, + errorIndex, + [ self.vbProcessor.unmakeVarBinds(snmpEngine, varBindTableRow, lookupMib) for varBindTableRow in varBindTable ], + cbCtx + ) + + (cbFun, cbCtx) = cbInfo + addrName, paramsName = self.lcd.configure( + snmpEngine, authData, transportTarget + ) + return cmdgen.NextCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, contextData.contextName, + self.vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (lookupMib, cbFun, cbCtx) + ) + + def bulkCmd(self, snmpEngine, authData, transportTarget, contextData, + nonRepeaters, maxRepetitions, varBinds, cbInfo, + lookupMib=True): + """Performs SNMP GETBULK query. + + Based on passed parameters, prepares SNMP GETBULK packet + (:RFC:`1905#section-4.2.3`) and schedules its transmission by + I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.entity.engine.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.CommunityData` or :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.entity.rfc3413.oneliner.target.UdpTransportTarget` or :py:class:`~pysnmp.entity.rfc3413.oneliner.target.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer + address. + + contextData : :py:class:`~pysnmp.entity.rfc3413.oneliner.ctx.ContextData` + Class instance representing SNMP ContextEngineId and ContextName + values. + + nonRepeaters : int + One MIB variable is requested in response for the first + `nonRepeaters` MIB variables in request. + + maxRepetitions : int + `maxRepetitions` MIB variables are requested in response for each + of the remaining MIB variables in the request (e.g. excluding + `nonRepeaters`). Remote SNMP engine may choose lesser value than + requested. + + varBinds : tuple + A sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` class + instances representing MIB variables to place into SNMP request. + + cbInfo : tuple + + * `cbFun` - user-supplied callable that is invoked to pass + SNMP response data or error to user at a later point of time. + * `cbCtx` - user-supplied object passing additional parameters + to/from `cbFun`. Default is `None`. + + Other Parameters + ---------------- + lookupMib : bool + `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Notes + ----- + User-supplied `cbFun` callable must have the following call + signature: + + * snmpEngine (:py:class:`~pysnmp.entity.engine.SnmpEngine`): + Class instance representing SNMP engine. + * sendRequestHandle (int): Unique request identifier. Can be used + for matching multiple ongoing requests with received responses. + * errorIndication (str): True value indicates SNMP engine error. + * errorStatus (str): True value indicates SNMP PDU error. + * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple): A sequence of sequences (e.g. 2-D array) of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing a table of MIB variables returned in SNMP response. + Inner sequences represent table rows and ordered exactly the same + as `varBinds` in request. Number of rows might be less or equal + to `maxRepetitions` value in request. + * `cbCtx` : Original user-supplied object. + + Returns + ------- + sendRequestHandle : int + Unique request identifier. Can be used for matching received + responses with ongoing requests. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.cmdgen import * + >>> def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): + ... print(errorIndication, errorStatus, errorIndex, varBinds) + >>> + >>> snmpEngine = SnmpEngine() + >>> g = AsyncCommandGenerator() + >>> g.bulkCmd(snmpEngine, + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 161)), + ... ContextData(), + ... 0, 2, + ... ObjectType(ObjectIdentity('SNMPv2-MIB', 'system')), + ... (cbFun, None)) + >>> snmpEngine.transportDispatcher.runDispatcher() + (None, 0, 0, [ [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m')), ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.2.0')), ObjectIdentifier('1.3.6.1.4.1.424242.1.1')] ]) + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, + errorIndication, errorStatus, errorIndex, + varBindTable, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + return cbFun( + snmpEngine, + sendRequestHandle, + errorIndication, + errorStatus, + errorIndex, + [ self.vbProcessor.unmakeVarBinds(snmpEngine, varBindTableRow, lookupMib) for varBindTableRow in varBindTable ], + cbCtx + ) + + (cbFun, cbCtx) = cbInfo + addrName, paramsName = self.lcd.configure( + snmpEngine, authData, transportTarget + ) + return cmdgen.BulkCommandGenerator().sendVarBinds( + snmpEngine, + addrName, + contextData.contextEngineId, + contextData.contextName, + nonRepeaters, maxRepetitions, + self.vbProcessor.makeVarBinds(snmpEngine, varBinds), + __cbFun, + (lookupMib, cbFun, cbCtx) + ) diff --git a/pysnmp/hlapi/asyncore/ntforg.py b/pysnmp/hlapi/asyncore/ntforg.py new file mode 100644 index 0000000..6536b9c --- /dev/null +++ b/pysnmp/hlapi/asyncore/ntforg.py @@ -0,0 +1,169 @@ +from pysnmp.entity import engine, config +from pysnmp.smi.rfc1902 import * +from pysnmp.entity.rfc3413 import ntforg, context +from pysnmp.hlapi.auth import * +from pysnmp.hlapi.context import * +from pysnmp.hlapi.lcd import * +from pysnmp.hlapi.varbinds import * +from pysnmp.hlapi.asyncore.transport import * +from pysnmp.hlapi.asyncore import cmdgen +from pysnmp import error + +__all__ = ['AsyncNotificationOriginator'] + +class AsyncNotificationOriginator: + """Creates asyncore-based SNMP Notification Originator object. + + This is a high-level wrapper around pure Notification Originator + impementation that aims at simplyfing + :py:class:`pysnmp.entity.engine.SnmpEngine`'s Local Configuration + Datastore (:RFC:`2271#section-3.4.2`) management. Typically, + users instantiate `AsyncNotificationOriginator` and call its + commmand-specific methods passing them canned Security, + Transport and SNMP Context parameters along with + :py:class:`~pysnmp.smi.rfc1902.NotificationType` object carrying + MIB variables to include with Notification. `AsyncNotificationOriginator` + will manage LCD by applying user-supplied configuratoin parameters + and running requested operation. + + See :RFC:`3413#section-3.2` for more information on SNMP + Notification Originator purpose, design and supported operations. + + """ + vbProcessor = NotificationOriginatorVarBinds() + lcd = NotificationOriginatorLcdConfigurator() + + def sendNotification(self, snmpEngine, + authData, transportTarget, contextData, + notifyType, + varBinds, + cbInfo=(None, None), + lookupMib=False): + """Send SNMP notification. + + Based on passed parameters, prepares SNMP TRAP or INFORM + notification (:RFC:`1905#section-4.2.6`) and schedules its + transmission by I/O framework at a later point of time. + + Parameters + ---------- + snmpEngine : :py:class:`~pysnmp.entity.engine.SnmpEngine` + Class instance representing SNMP engine. + + authData : :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.CommunityData` or :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.UsmUserData` + Class instance representing SNMP credentials. + + transportTarget : :py:class:`~pysnmp.entity.rfc3413.oneliner.target.UdpTransportTarget` or :py:class:`~pysnmp.entity.rfc3413.oneliner.target.Udp6TransportTarget` + Class instance representing transport type along with SNMP peer + address. + + contextData : :py:class:`~pysnmp.entity.rfc3413.oneliner.ctx.ContextData` + Class instance representing SNMP ContextEngineId and ContextName + values. + + notifyType : str + Indicates type of notification to be sent. Recognized literal + values are *trap* or *inform*. + + varBinds: tuple + Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class + instance representing a minimum sequence of MIB variables + required for particular notification type. Alternatively, + a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` + objects could be passed instead. In the latter case it is up to + the user to ensure proper Notification PDU contents. + + cbInfo : tuple + + * `cbFun` - user-supplied callable that is invoked to pass + SNMP response to *INFORM* notification or error to user at + a later point of time. The `cbFun` callable is never invoked + for *TRAP* notifications. + * `cbCtx` - user-supplied object passing additional parameters + to/from `cbFun`. Default is `None`. + + Other Parameters + ---------------- + lookupMib : bool + `lookupMib` - load MIB and resolve response MIB variables at + the cost of slightly reduced performance. Default is `True`. + + Notes + ----- + User-supplied `cbFun` callable must have the following call + signature: + + * snmpEngine (:py:class:`~pysnmp.entity.engine.SnmpEngine`): + Class instance representing SNMP engine. + * sendRequestHandle (int): Unique request identifier. Can be used + for matching multiple ongoing *INFORM* notifications with received + responses. + * errorIndication (str): True value indicates SNMP engine error. + * errorStatus (str): True value indicates SNMP PDU error. + * errorIndex (int): Non-zero value refers to `varBinds[errorIndex-1]` + * varBinds (tuple): A sequence of + :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances + representing MIB variables returned in SNMP response in exactly + the same order as `varBinds` in request. + * `cbCtx` : Original user-supplied object. + + Returns + ------- + sendRequestHandle : int + Unique request identifier. Can be used for matching received + responses with ongoing *INFORM* requests. Returns `None` for + *TRAP* notifications. + + Raises + ------ + PySnmpError + Or its derivative indicating that an error occurred while + performing SNMP operation. + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.ntforg import * + >>> + >>> snmpEngine = SnmpEngine() + >>> n = AsyncNotificationOriginator() + >>> n.sendNotification( + ... snmpEngine, + ... CommunityData('public'), + ... UdpTransportTarget(('demo.snmplabs.com', 162)), + ... ContextData(), + ... 'trap', + ... NotificationType(ObjectIdentity('SNMPv2-MIB', 'coldStart')), + ... ) + >>> snmpEngine.transportDispatcher.runDispatcher() + >>> + + """ + def __cbFun(snmpEngine, sendRequestHandle, errorIndication, + errorStatus, errorIndex, varBinds, cbCtx): + lookupMib, cbFun, cbCtx = cbCtx + return cbFun and cbFun( + snmpEngine, + sendRequestHandle, + errorIndication, + errorStatus, errorIndex, + self.vbProcessor.unmakeVarBinds( + snmpEngine, varBinds, lookupMib + ), + cbCtx + ) + + cbFun, cbCtx = cbInfo + + # Create matching transport tags if not given by user + if not transportTarget.tagList: + transportTarget.tagList = str( + hash((authData.securityName, transportTarget.transportAddr)) + ) + if isinstance(authData, CommunityData) and not authData.tag: + authData.tag = transportTarget.tagList.split()[0] + + notifyName = self.lcd.configure( + snmpEngine, authData, transportTarget, notifyType + ) + + return ntforg.NotificationOriginator().sendVarBinds(snmpEngine, notifyName, contextData.contextEngineId, contextData.contextName, self.vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun, (lookupMib, cbFun, cbCtx)) diff --git a/pysnmp/hlapi/asyncore/transport.py b/pysnmp/hlapi/asyncore/transport.py new file mode 100644 index 0000000..f77f575 --- /dev/null +++ b/pysnmp/hlapi/asyncore/transport.py @@ -0,0 +1,150 @@ +import socket, sys +from pysnmp.carrier.asyncore.dgram import udp, udp6, unix +from pysnmp import error +from pyasn1.compat.octets import null + +__all__ = ['UnixTransportTarget', 'Udp6TransportTarget', 'UdpTransportTarget'] + +class _AbstractTransportTarget: + transportDomain = None + protoTransport = NotImplementedError + def __init__(self, transportAddr, timeout=1, retries=5, tagList=null): + self.transportAddr = self._resolveAddr(transportAddr) + self.timeout = timeout + self.retries = retries + self.tagList = tagList + self.iface = None + + def __repr__(self): + return '%s(%r, timeout=%r, retries=%r, tagList=%r)' % ( + self.__class__.__name__, self.transportAddr, + self.timeout, self.retries, self.tagList + ) + + def getTransportInfo(self): + return self.transportDomain, self.transportAddr + + def setLocalAddress(self, iface): + self.iface = iface + return self + + def openClientMode(self): + self.transport = self.protoTransport().openClientMode(self.iface) + return self.transport + + def verifyDispatcherCompatibility(self, snmpEngine): + if not self.protoTransport.isCompatibleWithDispatcher(snmpEngine.transportDispatcher): + raise error.PySnmpError('Transport %r is not compatible with dispatcher %r' % (self.protoTransport, snmpEngine.transportDispatcher)) + + def _resolveAddr(self, transportAddr): raise NotImplementedError() + +class UdpTransportTarget(_AbstractTransportTarget): + """Creates UDP/IPv4 configuration entry and initialize socket API if needed. + + This object can be used by + :py:class:`~pysnmp.entity.rfc3413.oneliner.cmdgen.AsyncCommandGenerator` or + :py:class:`~pysnmp.entity.rfc3413.oneliner.ntforg.AsyncNotificationOriginator` + and their derevatives for adding new entries to Local Configuration + Datastore (LCD) managed by :py:class:`~pysnmp.entity.engine.SnmpEngine` + class instance. + + See :RFC:`1906#section-3` for more information on the UDP transport mapping. + + Parameters + ---------- + transportAddr : tuple + Indicates remote address in Python :py:mod:`socket` module format + which is a tuple of FQDN, port where FQDN is a string representing + either hostname or IPv4 address in quad-dotted form, port is an + integer. + timeout : int + Response timeout in seconds. + retries : int + Maximum number of request retries, 0 retries means just a single + request. + tagList : str + Arbitrary string that contains a list of tag values which are used + to select target addresses for a particular operation + (:RFC:`3413#section-4.1.4`). + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.target import UdpTransportTarget + >>> UdpTransportTarget(('demo.snmplabs.com', 161)) + UdpTransportTarget(('195.218.195.228', 161), timeout=1, retries=5, tagList='') + >>> + + """ + transportDomain = udp.domainName + protoTransport = udp.UdpSocketTransport + def _resolveAddr(self, transportAddr): + try: + return socket.getaddrinfo(transportAddr[0], + transportAddr[1], + socket.AF_INET, + socket.SOCK_DGRAM, + socket.IPPROTO_UDP)[0][4][:2] + except socket.gaierror: + raise error.PySnmpError('Bad IPv4/UDP transport address %s: %s' % ('@'.join([ str(x) for x in transportAddr ]), sys.exc_info()[1])) + +class Udp6TransportTarget(_AbstractTransportTarget): + """Creates UDP/IPv6 configuration entry and initialize socket API if needed. + + This object can be used by + :py:class:`~pysnmp.entity.rfc3413.oneliner.cmdgen.AsyncCommandGenerator` or + :py:class:`~pysnmp.entity.rfc3413.oneliner.ntforg.AsyncNotificationOriginator` + and their derevatives for adding new entries to Local Configuration + Datastore (LCD) managed by :py:class:`~pysnmp.entity.engine.SnmpEngine` + class instance. + + See :RFC:`1906#section-3`, :RFC:`2851#section-4` for more information + on the UDP and IPv6 transport mapping. + + Parameters + ---------- + transportAddr : tuple + Indicates remote address in Python :py:mod:`socket` module format + which is a tuple of FQDN, port where FQDN is a string representing + either hostname or IPv6 address in one of three conventional forms + (:RFC:`1924#section-3`), port is an integer. + timeout : int + Response timeout in seconds. + retries : int + Maximum number of request retries, 0 retries means just a single + request. + tagList : str + Arbitrary string that contains a list of tag values which are used + to select target addresses for a particular operation + (:RFC:`3413#section-4.1.4`). + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.target import Udp6TransportTarget + >>> Udp6TransportTarget(('google.com', 161)) + Udp6TransportTarget(('2a00:1450:4014:80a::100e', 161), timeout=1, retries=5, tagList='') + >>> Udp6TransportTarget(('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', 161)) + Udp6TransportTarget(('fedc:ba98:7654:3210:fedc:ba98:7654:3210', 161), timeout=1, retries=5, tagList='') + >>> Udp6TransportTarget(('1080:0:0:0:8:800:200C:417A', 161)) + Udp6TransportTarget(('1080::8:800:200c:417a', 161), timeout=1, retries=5, tagList='') + >>> Udp6TransportTarget(('::0', 161)) + Udp6TransportTarget(('::', 161), timeout=1, retries=5, tagList='') + >>> Udp6TransportTarget(('::', 161)) + Udp6TransportTarget(('::', 161), timeout=1, retries=5, tagList='') + >>> + + """ + transportDomain = udp6.domainName + protoTransport = udp6.Udp6SocketTransport + def _resolveAddr(self, transportAddr): + try: + return socket.getaddrinfo(transportAddr[0], + transportAddr[1], + socket.AF_INET6, + socket.SOCK_DGRAM, + socket.IPPROTO_UDP)[0][4][:2] + except socket.gaierror: + raise error.PySnmpError('Bad IPv6/UDP transport address %s: %s' % ('@'.join([ str(x) for x in transportAddr ]), sys.exc_info()[1])) + +class UnixTransportTarget(_AbstractTransportTarget): + transportDomain = unix.domainName + protoTransport = unix.UnixSocketTransport diff --git a/pysnmp/hlapi/auth.py b/pysnmp/hlapi/auth.py new file mode 100644 index 0000000..5108a21 --- /dev/null +++ b/pysnmp/hlapi/auth.py @@ -0,0 +1,278 @@ +from pysnmp.entity import config +from pysnmp import error +from pyasn1.compat.octets import null + +__all__ = ['CommunityData', 'UsmUserData', + 'usm3DESEDEPrivProtocol', 'usmAesCfb128Protocol', + 'usmAesCfb192Protocol', 'usmAesCfb256Protocol', + 'usmDESPrivProtocol', 'usmHMACMD5AuthProtocol', + 'usmHMACSHAAuthProtocol', 'usmNoAuthProtocol', + 'usmNoPrivProtocol'] + +class CommunityData: + """Creates SNMP v1/v2c configuration entry. + + This object can be used by + :py:class:`~pysnmp.entity.rfc3413.oneliner.cmdgen.AsyncCommandGenerator` or + :py:class:`~pysnmp.entity.rfc3413.oneliner.ntforg.AsyncNotificationOriginator` + and their derivatives for adding new entries to Local Configuration + Datastore (LCD) managed by :py:class:`~pysnmp.entity.engine.SnmpEngine` + class instance. + + See :RFC:`2576#section-5.3` for more information on the + *SNMP-COMMUNITY-MIB::snmpCommunityTable*. + + Parameters + ---------- + communityIndex : str + Unique index value of a row in snmpCommunityTable. If it is the + only positional parameter, it is taken as *communityName*. + communityName : str + SNMP v1/v2c community string. + mpModel : int + SNMP version - 0 for SNMPv1 and 1 for SNMPv2c. + contextEngineId : str + Indicates the location of the context in which management + information is accessed when using the community string + specified by the above communityName. + contextName : str + The context in which management information is accessed when + using the above communityName. + tag : str + Arbitrary string that specifies a set of transport endpoints + to which a notification may be sent using communityName above + (see also :RFC:`3413#section-4.1.4`). + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.auth import CommunityData + >>> CommunityData('public') + CommunityData(communityIndex='s1410706889', communityName=, mpModel=1, contextEngineId=None, contextName='', tag='') + >>> CommunityData('public', 'public') + CommunityData(communityIndex='public', communityName=, mpModel=1, contextEngineId=None, contextName='', tag='') + >>> + + """ + mpModel = 1 # Default is SMIv2 + securityModel = mpModel + 1 + securityLevel = 'noAuthNoPriv' + contextName = null + tag = null + def __init__(self, communityIndex, communityName=None, mpModel=None, + contextEngineId=None, contextName=None, tag=None, + securityName=None): + if mpModel is not None: + self.mpModel = mpModel + self.securityModel = mpModel + 1 + self.contextEngineId = contextEngineId + if contextName is not None: + self.contextName = contextName + if tag is not None: + self.tag = tag + # a single arg is considered as a community name + if communityName is None: + communityName, communityIndex = communityIndex, None + self.communityName = communityName + # Autogenerate communityIndex if not specified + if communityIndex is None: + self.communityIndex = self.securityName = 's%s' % hash( + ( self.communityName, + self.mpModel, + self.contextEngineId, + self.contextName, + self.tag ) + ) + else: + self.communityIndex = communityIndex + self.securityName = securityName is not None and securityName or communityIndex + + def __hash__(self): + raise TypeError('%s is not hashable' % self.__class__.__name__) + + def __repr__(self): + return '%s(communityIndex=%r, communityName=, mpModel=%r, contextEngineId=%r, contextName=%r, tag=%r, securityName=%r)' % ( + self.__class__.__name__, + self.communityIndex, + self.mpModel, + self.contextEngineId, + self.contextName, + self.tag, + self.securityName + ) + + def clone(self, communityIndex=None, communityName=None, + mpModel=None, contextEngineId=None, + contextName=None, tag=None, securityName=None): + # a single arg is considered as a community name + if communityName is None: + communityName, communityIndex = communityIndex, None + return self.__class__( + communityIndex, + communityName is None and self.communityName or communityName, + mpModel is None and self.mpModel or mpModel, + contextEngineId is None and self.contextEngineId or contextEngineId, + contextName is None and self.contextName or contextName, + tag is None and self.tag or tag, + securityName is None and self.securityName or securityName + ) + +#: No Authentication Protocol. +usmNoAuthProtocol = config.usmNoAuthProtocol +#: The HMAC-MD5-96 Digest Authentication Protocol (:RFC:`3414#section-6`) +usmHMACMD5AuthProtocol = config.usmHMACMD5AuthProtocol +#: The HMAC-SHA-96 Digest Authentication Protocol (:RFC:`3414#section-7`) +usmHMACSHAAuthProtocol = config.usmHMACSHAAuthProtocol + +#: No Privacy Protocol. +usmNoPrivProtocol = config.usmNoPrivProtocol +#: The CBC-DES Symmetric Encryption Protocol (:RFC:`3414#section-8`) +usmDESPrivProtocol = config.usmDESPrivProtocol +#: The 3DES-EDE Symmetric Encryption Protocol (`draft-reeder-snmpv3-usm-3desede-00 `_) +usm3DESEDEPrivProtocol = config.usm3DESEDEPrivProtocol +#: The CFB128-AES-128 Symmetric Encryption Protocol (:RFC:`3826#section-3`) +usmAesCfb128Protocol = config.usmAesCfb128Protocol +#: The CFB128-AES-192 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 `_) +usmAesCfb192Protocol = config.usmAesCfb192Protocol +#: The CFB128-AES-256 Symmetric Encryption Protocol (`draft-blumenthal-aes-usm-04 `_) +usmAesCfb256Protocol = config.usmAesCfb256Protocol + +class UsmUserData: + """Creates SNMP v3 User Security Model (USM) configuration entry. + + This object can be used by + :py:class:`~pysnmp.entity.rfc3413.oneliner.cmdgen.AsyncCommandGenerator` or + :py:class:`~pysnmp.entity.rfc3413.oneliner.ntforg.AsyncNotificationOriginator` + and their derivatives for adding new entries to Local Configuration + Datastore (LCD) managed by :py:class:`~pysnmp.entity.engine.SnmpEngine` + class instance. + + See :RFC:`3414#section-5` for more information on the + *SNMP-USER-BASED-SM-MIB::usmUserTable*. + + Parameters + ---------- + userName : str + A human readable string representing the name of the SNMP USM user. + authKey : str + Initial value of the secret authentication key. If not set, + :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usmNoAuthProtocol` + is implied. If set and no *authProtocol* is specified, + :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usmHMACMD5AuthProtocol` + takes effect. + privKey : str + Initial value of the secret encryption key. If not set, + :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usmNoPrivProtocol` + is implied. If set and no *privProtocol* is specified, + :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usmDESPrivProtocol` + takes effect. + authProtocol : tuple + An indication of whether messages sent on behalf of this USM user + can be authenticated, and if so, the type of authentication protocol + which is used. + + Supported authentication protocol identifiers are: + + * :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usmNoAuthProtocol` (default is *authKey* not given) + * :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usmHMACMD5AuthProtocol` (default if *authKey* is given) + * :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usmHMACSHAAuthProtocol` + privProtocol : tuple + An indication of whether messages sent on behalf of this USM user + be encrypted, and if so, the type of encryption protocol which is used. + + Supported encryption protocol identifiers are: + + * :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usmNoPrivProtocol` (default is *authKey* not given) + * :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usmDESPrivProtocol` (default if *authKey* is given) + * :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usm3DESEDEPrivProtocol` + * :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usmAesCfb128Protocol` + * :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usmAesCfb192Protocol` + * :py:class:`~pysnmp.entity.rfc3413.oneliner.auth.usmAesCfb256Protocol` + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.auth import UsmUserData + >>> UsmUserData('testuser', authKey='authenticationkey') + UsmUserData(userName='testuser', authKey=, privKey=, authProtocol=(1,3,6,1,6,3,10,1,1,2), privProtocol=(1,3,6,1,6,3,10,1,2,1)) + >>> UsmUserData('testuser', authKey='authenticationkey', privKey='encryptionkey') + UsmUserData(userName='testuser', authKey=, privKey=, authProtocol=(1,3,6,1,6,3,10,1,1,2), privProtocol=(1,3,6,1,6,3,10,1,2,2)) + >>> + + """ + authKey = privKey = None + authProtocol = config.usmNoAuthProtocol + privProtocol = config.usmNoPrivProtocol + securityLevel = 'noAuthNoPriv' + securityModel = 3 + mpModel = 3 + contextName = null + # the contextEngineId/contextName values stored here should + # be used for USM configuration only, not for PDU contents + def __init__(self, userName, + authKey=None, privKey=None, + authProtocol=None, privProtocol=None, + securityEngineId=None, + # deprecated parameters begin + contextName=None, + contextEngineId=None, + # deprecated parameters end + securityName=None): + self.userName = userName + if securityName is None: + self.securityName = userName + else: + self.securityName = securityName + + if authKey is not None: + self.authKey = authKey + if authProtocol is None: + self.authProtocol = config.usmHMACMD5AuthProtocol + else: + self.authProtocol = authProtocol + if self.securityLevel != 'authPriv': + self.securityLevel = 'authNoPriv' + + if privKey is not None: + self.privKey = privKey + if self.authProtocol == config.usmNoAuthProtocol: + raise error.PySnmpError('Privacy implies authenticity') + self.securityLevel = 'authPriv' + if privProtocol is None: + self.privProtocol = config.usmDESPrivProtocol + else: + self.privProtocol = privProtocol + + # the contextEngineId parameter is actually a securityEngineId + if securityEngineId is None: + securityEngineId = contextEngineId + self.contextEngineId = self.securityEngineId = securityEngineId + + # the contextName parameter should never be used here + if contextName is not None: + self.contextName = contextName + + def __hash__(self): + raise TypeError('%s is not hashable' % self.__class__.__name__) + + def __repr__(self): + return '%s(userName=%r, authKey=, privKey=, authProtocol=%r, privProtocol=%r, securityEngineId=%r, securityName=%r)'%( + self.__class__.__name__, + self.userName, + self.authProtocol, + self.privProtocol, + self.securityEngineId is None and '' or self.securityEngineId, + self.securityName + ) + + def clone(self, userName=None, + authKey=None, privKey=None, + authProtocol=None, privProtocol=None, + securityEngineId=None, securityName=None): + return self.__class__( + userName is None and self.userName or userName, + authKey is None and self.authKey or authKey, + privKey is None and self.privKey or privKey, + authProtocol is None and self.authProtocol or authProtocol, + privProtocol is None and self.privProtocol or privProtocol, + securityEngineId is None and self.securityEngineId or securityEngineId, + securityName=securityName is None and self.securityName or securityName + ) diff --git a/pysnmp/hlapi/context.py b/pysnmp/hlapi/context.py new file mode 100644 index 0000000..0d86480 --- /dev/null +++ b/pysnmp/hlapi/context.py @@ -0,0 +1,48 @@ +from pyasn1.compat.octets import null + +__all__ = ['ContextData'] + +class ContextData: + """Creates UDP/IPv6 configuration entry and initialize socket API if needed. + + This object can be used by + :py:class:`~pysnmp.entity.rfc3413.oneliner.cmdgen.AsyncCommandGenerator` or + :py:class:`~pysnmp.entity.rfc3413.oneliner.ntforg.AsyncNotificationOriginator` + and their derevatives for forming SNMP PDU and also adding new entries to + Local Configuration Datastore (LCD) in order to support SNMPv1/v2c with + SNMPv3 interoperability. + + See :RFC:`3411#section-4.1` for SNMP Context details. + + Parameters + ---------- + contextEngineId : str + Uniquely identifies an SNMP entity that may realize an instance of + a MIB with a particular contextName (:RFC:`3411#section-3.3.2`). + More frequently than not, ContextEngineID is the same as + authoritative SnmpEngineID, however if SNMP Engine serves multiple + SNMP Entities, their ContextEngineIDs would be distinct. + Default is authoritative SNMP Engine ID. + contextName : str + Used to name an instance of MIB (:RFC:`3411#section-3.3.3`). + Default is empty string. + + Examples + -------- + >>> from pysnmp.entity.rfc3413.oneliner.ctx import ContextData + >>> ContextData() + ContextData(contextEngineId=None, contextName='') + >>> ContextData(OctetString(hexValue='01020ABBA0')) + ContextData(contextEngineId=OctetString(hexValue='01020abba0'), contextName='') + >>> ContextData(contextName='mycontext') + ContextData(contextEngineId=None, contextName='mycontext') + + """ + def __init__(self, contextEngineId=None, contextName=null): + self.contextEngineId = contextEngineId + self.contextName = contextName + + def __repr__(self): + return '%s(contextEngineId=%r, contextName=%r)' % ( + self.__class__.__name__, self.contextEngineId, self.contextName + ) diff --git a/pysnmp/hlapi/lcd.py b/pysnmp/hlapi/lcd.py new file mode 100644 index 0000000..e62eaf1 --- /dev/null +++ b/pysnmp/hlapi/lcd.py @@ -0,0 +1,259 @@ +from pysnmp.entity import config +from pysnmp import nextid, error +from pysnmp.hlapi.auth import * + +__all__ = ['CommandGeneratorLcdConfigurator', + 'NotificationOriginatorLcdConfigurator' ] + +class AbstractLcdConfigurator: + nextID = nextid.Integer(0xffffffff) + + def _getCache(self, snmpEngine): + cache = snmpEngine.getUserContext(self.__class__.__name__) + if cache is None: + cache = { + 'auth': {}, 'parm': {}, 'tran': {}, 'addr': {} + } + snmpEngine.setUserContext(cmdgen_cache=cache) + return cache + + def configure(self, snmpEngine, authData, transportTarget): pass + def unconfigure(self, snmpEngine, authData=None): pass + +class CommandGeneratorLcdConfigurator(AbstractLcdConfigurator): + def configure(self, snmpEngine, authData, transportTarget): + cache = self._getCache(snmpEngine) + if isinstance(authData, CommunityData): + if authData.communityIndex not in cache['auth']: + config.addV1System( + snmpEngine, + authData.communityIndex, + authData.communityName, + authData.contextEngineId, + authData.contextName, + authData.tag, + authData.securityName + ) + cache['auth'][authData.communityIndex] = authData + elif isinstance(authData, UsmUserData): + authDataKey = authData.userName, authData.securityEngineId + if authDataKey not in cache['auth']: + config.addV3User( + snmpEngine, + authData.userName, + authData.authProtocol, authData.authKey, + authData.privProtocol, authData.privKey, + authData.securityEngineId, + securityName=authData.securityName + ) + cache['auth'][authDataKey] = authData + else: + raise error.PySnmpError('Unsupported authentication object') + + paramsKey = authData.securityName, \ + authData.securityLevel, \ + authData.mpModel + if paramsKey in cache['parm']: + paramsName, useCount = cache['parm'][paramsKey] + cache['parm'][paramsKey] = paramsName, useCount + 1 + else: + paramsName = 'p%s' % self.nextID() + config.addTargetParams( + snmpEngine, paramsName, + authData.securityName, authData.securityLevel, authData.mpModel + ) + cache['parm'][paramsKey] = paramsName, 1 + + if transportTarget.transportDomain in cache['tran']: + transport, useCount = cache['tran'][transportTarget.transportDomain] + transportTarget.verifyDispatcherCompatibility(snmpEngine) + cache['tran'][transportTarget.transportDomain] = transport, useCount + 1 + elif config.getTransport(snmpEngine, transportTarget.transportDomain): + transportTarget.verifyDispatcherCompatibility(snmpEngine) + else: + transport = transportTarget.openClientMode() + config.addTransport( + snmpEngine, + transportTarget.transportDomain, + transport + ) + cache['tran'][transportTarget.transportDomain] = transport, 1 + + transportKey = ( paramsName, + transportTarget.transportDomain, + transportTarget.transportAddr, + transportTarget.tagList ) + + if transportKey in cache['addr']: + addrName, useCount = cache['addr'][transportKey] + cache['addr'][transportKey] = addrName, useCount + 1 + else: + addrName = 'a%s' % self.nextID() + config.addTargetAddr( + snmpEngine, addrName, + transportTarget.transportDomain, + transportTarget.transportAddr, + paramsName, + transportTarget.timeout * 100, + transportTarget.retries, + transportTarget.tagList + ) + cache['addr'][transportKey] = addrName, 1 + + return addrName, paramsName + + def unconfigure(self, snmpEngine, authData=None): + cache = _getCache(snmpEngine) + if authData: + if isinstance(authData, CommunityData): + authDataKey = authData.communityIndex + elif isinstance(authData, UsmUserData): + authDataKey = authData.userName, authData.securityEngineId + else: + raise error.PySnmpError('Unsupported authentication object') + if authDataKey in cache['auth']: + authDataKeys = ( authDataKey, ) + else: + raise error.PySnmpError('Unknown authData %s' % (authData,)) + else: + authDataKeys = list(cache['auth'].keys()) + + addrNames, paramsNames = set(), set() + + for authDataKey in authDataKeys: + authDataX = cache['auth'][authDataKey] + del cache['auth'][authDataKey] + if isinstance(authDataX, CommunityData): + config.delV1System( + snmpEngine, + authDataX.communityIndex + ) + elif isinstance(authDataX, UsmUserData): + config.delV3User( + snmpEngine, + authDataX.userName, + authDataX.securityEngineId + ) + else: + raise error.PySnmpError('Unsupported authentication object') + + paramsKey = authDataX.securityName, \ + authDataX.securityLevel, \ + authDataX.mpModel + if paramsKey in cache['parm']: + paramsName, useCount = cache['parm'][paramsKey] + useCount -= 1 + if useCount: + cache['parm'][paramsKey] = paramsName, useCount + else: + del cache['parm'][paramsKey] + config.delTargetParams( + snmpEngine, paramsName + ) + paramsNames.add(paramsName) + else: + raise error.PySnmpError('Unknown target %s' % (paramsKey,)) + + addrKeys = [ x for x in cache['addr'] if x[0] == paramsName ] + + for addrKey in addrKeys: + addrName, useCount = cache['addr'][addrKey] + useCount -= 1 + if useCount: + cache['addr'][addrKey] = addrName, useCount + else: + config.delTargetAddr(snmpEngine, addrName) + + addrNames.add(addrKey) + + if addrKey[1] in cache['tran']: + transport, useCount = cache['tran'][addrKey[1]] + if useCount > 1: + useCount -= 1 + cache['tran'][addrKey[1]] = transport, useCount + else: + config.delTransport(snmpEngine, addrKey[1]) + transport.closeTransport() + del cache['tran'][addrKey[1]] + + return addrNames, paramsNames + +class NotificationOriginatorLcdConfigurator(CommandGeneratorLcdConfigurator): + def configure(self, snmpEngine, authData, transportTarget, notifyType): + cache = self._getCache(snmpEngine) + addrName, paramsName = CommandGeneratorLcdConfigurator.configure(self, snmpEngine, authData, transportTarget) + tagList = transportTarget.tagList.split() + if not tagList: + tagList = [''] + for tag in tagList: + notifyNameKey = paramsName, tag, notifyType + if notifyNameKey in cache['name']: + notifyName, paramsName, useCount = cache['name'][notifyNameKey] + cache['name'][notifyNameKey] = notifyName, paramsName, useCount + 1 + else: + notifyName = 'n%s' % self.nextID() + config.addNotificationTarget( + snmpEngine, + notifyName, + paramsName, + tag, + notifyType + ) + cache['name'][notifyNameKey] = notifyName, paramsName, 1 + authDataKey = authData.securityName, authData.securityModel + if authDataKey in cache['auth']: + authDataX, subTree, useCount = cache['auth'][authDataKey] + cache['auth'][authDataKey] = authDataX, subTree, useCount + 1 + else: + subTree = (1,3,6) + config.addTrapUser( + snmpEngine, + authData.securityModel, + authData.securityName, + authData.securityLevel, + subTree + ) + cache['auth'][authDataKey] = authData, subTree, 1 + + return notifyName + + def unconfigure(self, snmpEngine, authData=None): + cache = _getCache(snmpEngine) + if authData: + authDataKey = authData.securityName, authData.securityModel + if authDataKey in cache['auth']: + authDataKeys = ( authDataKey, ) + else: + raise error.PySnmpError('Unknown authData %s' % (authData,)) + else: + authDataKeys = tuple(cache['auth'].keys()) + + addrNames, paramsNames = CommandGeneratorLcdConfigurator.unconfigure(self, snmpEngine, authData) + + notifyAndParamsNames = [ (cache['name'][x], x) for x in cache['name'].keys() if x[0] in paramsNames ] + + for (notifyName, paramsName, useCount), notifyNameKey in notifyAndParamsNames: + useCount -= 1 + if useCount: + cache['name'][notifyNameKey] = notifyName, paramsName, useCount + else: + config.delNotificationTarget( + snmpEngine, notifyName, paramsName + ) + del cache['name'][notifyNameKey] + + for authDataKey in authDataKeys: + authDataX, subTree, useCount = cache['auth'][authDataKey] + useCount -= 1 + if useCount: + cache['auth'][authDataKey] = authDataX, subTree, useCount + else: + config.delTrapUser( + snmpEngine, + authDataX.securityModel, + authDataX.securityName, + authDataX.securityLevel, + subTree + ) + del cache['auth'][authDataKey] + diff --git a/pysnmp/hlapi/varbinds.py b/pysnmp/hlapi/varbinds.py new file mode 100644 index 0000000..1f32847 --- /dev/null +++ b/pysnmp/hlapi/varbinds.py @@ -0,0 +1,62 @@ +from pysnmp.smi import view +from pysnmp.smi.rfc1902 import * + +__all__ = ['CommandGeneratorVarBinds', 'NotificationOriginatorVarBinds'] + +class AbstractVarBinds: + def getMibViewController(self, snmpEngine): + mibViewController = snmpEngine.getUserContext('mibViewController') + if not mibViewController: + mibViewController = view.MibViewController( + snmpEngine.getMibBuilder() + ) + snmpEngine.setUserContext(mibViewController=mibViewController) + return mibViewController + +class CommandGeneratorVarBinds(AbstractVarBinds): + def makeVarBinds(self, snmpEngine, varBinds): + mibViewController = self.getMibViewController(snmpEngine) + __varBinds = [] + for varBind in varBinds: + if isinstance(varBind, ObjectType): + pass + elif isinstance(varBind[0], ObjectIdentity): + varBind = ObjectType(*varBind) + elif isinstance(varBind[0][0], tuple): # legacy + varBind = ObjectType(ObjectIdentity(varBind[0][0][0], varBind[0][0][1], *varBind[0][1:]), varBind[1]) + else: + varBind = ObjectType(ObjectIdentity(varBind[0]), varBind[1]) + + __varBinds.append(varBind.resolveWithMib(mibViewController)) + + return __varBinds + + def unmakeVarBinds(self, snmpEngine, varBinds, lookupMib=True): + if lookupMib: + mibViewController = self.getMibViewController(snmpEngine) + varBinds = [ ObjectType(ObjectIdentity(x[0]), x[1]).resolveWithMib(mibViewController) for x in varBinds ] + + return varBinds + +class NotificationOriginatorVarBinds(AbstractVarBinds): + def makeVarBinds(self, snmpEngine, varBinds): + mibViewController = self.getMibViewController(snmpEngine) + if isinstance(varBinds, NotificationType): + varBinds.resolveWithMib(mibViewController) + __varBinds = [] + for varBind in varBinds: + if isinstance(varBind, ObjectType): + pass + elif isinstance(varBind[0], ObjectIdentity): + varBind = ObjectType(*varBind) + else: + varBind = ObjectType(ObjectIdentity(varBind[0]), varBind[1]) + __varBinds.append(varBind.resolveWithMib(mibViewController)) + return __varBinds + + def unmakeVarBinds(self, snmpEngine, varBinds, lookupMib=False): + if lookupMib: + mibViewController = self.getMibViewController(snmpEngine) + varBinds = [ ObjectType(ObjectIdentity(x[0]), x[1]).resolveWithMib(mibViewController) for x in varBinds ] + return varBinds + diff --git a/pysnmp/proto/rfc1155.py b/pysnmp/proto/rfc1155.py index 6f67f0a..4fb9aec 100644 --- a/pysnmp/proto/rfc1155.py +++ b/pysnmp/proto/rfc1155.py @@ -2,6 +2,9 @@ from pyasn1.type import univ, tag, constraint, namedtype from pyasn1.error import PyAsn1Error from pysnmp.proto import error +__all__ = ['Opaque', 'NetworkAddress', 'ObjectName', 'TimeTicks', + 'Counter', 'Gauge', 'IpAddress'] + class IpAddress(univ.OctetString): tagSet = univ.OctetString.tagSet.tagImplicitly( tag.Tag(tag.tagClassApplication, tag.tagFormatSimple, 0x00) diff --git a/pysnmp/proto/rfc1157.py b/pysnmp/proto/rfc1157.py index 4483cf1..6fd1643 100644 --- a/pysnmp/proto/rfc1157.py +++ b/pysnmp/proto/rfc1157.py @@ -1,6 +1,9 @@ from pyasn1.type import univ, tag, namedtype, namedval from pysnmp.proto import rfc1155 +__all__ = ['GetNextRequestPDU', 'GetResponsePDU', 'SetRequestPDU', + 'TrapPDU', 'GetRequestPDU'] + class VarBind(univ.Sequence): componentType = namedtype.NamedTypes( namedtype.NamedType('name', rfc1155.ObjectName()), diff --git a/pysnmp/proto/rfc1902.py b/pysnmp/proto/rfc1902.py index b284140..08e64ab 100644 --- a/pysnmp/proto/rfc1902.py +++ b/pysnmp/proto/rfc1902.py @@ -1,6 +1,10 @@ from pyasn1.type import univ, tag, constraint, namedtype, namedval from pysnmp.proto import rfc1155, error +__all__ = ['Opaque', 'TimeTicks', 'Bits', 'Integer', 'OctetString', + 'IpAddress', 'Counter64', 'Unsigned32', 'Gauge32', 'Integer32', + 'ObjectIdentifier', 'Counter32'] + class Integer32(univ.Integer): """Creates an instance of SNMP Integer32 class. diff --git a/pysnmp/proto/rfc1905.py b/pysnmp/proto/rfc1905.py index e77912f..945b32b 100644 --- a/pysnmp/proto/rfc1905.py +++ b/pysnmp/proto/rfc1905.py @@ -1,6 +1,12 @@ from pyasn1.type import univ, tag, constraint, namedtype, namedval from pysnmp.proto import rfc1902 +__all__ = ['unSpecified', 'EndOfMibView', 'ReportPDU', 'UnSpecified', + 'BulkPDU', 'SNMPv2TrapPDU', 'GetRequestPDU', 'NoSuchObject', + 'GetNextRequestPDU', 'GetBulkRequestPDU', 'NoSuchInstance', + 'ResponsePDU', 'noSuchObject', 'InformRequestPDU', 'endOfMibView', + 'SetRequestPDU', 'noSuchInstance'] + # Value reference -- max bindings in VarBindList max_bindings = rfc1902.Integer(2147483647) diff --git a/pysnmp/smi/rfc1902.py b/pysnmp/smi/rfc1902.py index b61f5a0..2ab5a8c 100644 --- a/pysnmp/smi/rfc1902.py +++ b/pysnmp/smi/rfc1902.py @@ -8,21 +8,6 @@ from pyasn1.type.base import AbstractSimpleAsn1Item from pyasn1.error import PyAsn1Error from pysnmp import debug -# expose SNMP types in this namespace for convenience -Integer = rfc1902.Integer -Integer32 = rfc1902.Integer32 -OctetString = rfc1902.OctetString -ObjectIdentifier = rfc1902.ObjectIdentifier -IpAddress = rfc1902.IpAddress -Counter32 = rfc1902.Counter32 -Gauge32 = rfc1902.Gauge32 -Unsigned32 = rfc1902.Unsigned32 -TimeTicks = rfc1902.TimeTicks -Opaque = rfc1902.Opaque -Counter64 = rfc1902.Counter64 -Bits = rfc1902.Bits -ObjectName = rfc1902.ObjectName - class ObjectIdentity: """Create an object representing MIB variable ID. -- cgit v1.2.1