Ejemplo n.º 1
0
 def n_TrapV2cParams_exit(self, cbCtx, node):
     snmpEngine, ctx = cbCtx
     if 'informMode' in ctx:
         pdu = v2c.InformRequestPDU()
         v2c.apiPDU.setDefaults(pdu)
     else:
         pdu = v2c.TrapPDU()
         v2c.apiTrapPDU.setDefaults(pdu)
     v2c.apiPDU.setVarBinds(pdu,
                            [(v2c.ObjectIdentifier('1.3.6.1.2.1.1.3.0'),
                              v2c.TimeTicks(ctx['Uptime'])),
                             (v2c.ObjectIdentifier('1.3.6.1.6.3.1.1.4.1.0'),
                              v2c.ObjectIdentifier(ctx['TrapOid']))])
     ctx['pdu'] = pdu
Ejemplo n.º 2
0
    def sendVarBinds(self,
                     snmpEngine,
                     notificationTarget,
                     contextEngineId,
                     contextName,
                     varBinds=(),
                     cbFun=None,
                     cbCtx=None):
        debug.logger & debug.flagApp and debug.logger('sendVarBinds: notificationTarget %s, contextEngineId %s, contextName "%s", varBinds %s' % (notificationTarget, contextEngineId or '<default>', contextName, varBinds))

        if contextName:
            __SnmpAdminString, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('SNMP-FRAMEWORK-MIB', 'SnmpAdminString')
            contextName = __SnmpAdminString(contextName)
 
        # 3.3
        ( notifyTag,
          notifyType ) = config.getNotificationInfo(
                snmpEngine, notificationTarget
            )

        notificationHandle = getNextHandle()

        debug.logger & debug.flagApp and debug.logger('sendVarBinds: notificationHandle %s, notifyTag %s, notifyType %s' % (notificationHandle, notifyTag, notifyType))

        varBinds = [  (v2c.ObjectIdentifier(x),y) for x,y in varBinds ]

        # 3.3.2 & 3.3.3
        snmpTrapOID, sysUpTime = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpTrapOID', 'sysUpTime')

        for idx in range(len(varBinds)):
            if idx and varBinds[idx][0] == sysUpTime.getName():
                if varBinds[0][0] == sysUpTime.getName():
                    varBinds[0] = varBinds[idx]
                else:
                    varBinds.insert(0, varBinds[idx])
                    del varBinds[idx]

            if varBinds[0][0] != sysUpTime.getName():
                varBinds.insert(0, (v2c.ObjectIdentifier(sysUpTime.getName()),
                                    sysUpTime.getSyntax().clone()))

        if len(varBinds) < 2 or varBinds[1][0] != snmpTrapOID.getName():
            varBinds.insert(1, (v2c.ObjectIdentifier(snmpTrapOID.getName()),
                                snmpTrapOID.getSyntax()))

        debug.logger & debug.flagApp and debug.logger('sendVarBinds: final varBinds %s' % (varBinds,))

        for targetAddrName in config.getTargetNames(snmpEngine, notifyTag):
            ( transportDomain,
              transportAddress,
              timeout,
              retryCount,
              params ) = config.getTargetAddr(snmpEngine, targetAddrName)
            ( messageProcessingModel,
              securityModel,
              securityName,
              securityLevel ) = config.getTargetParams(snmpEngine, params)

            # 3.3.1 XXX
# XXX filtering's yet to be implemented
#             filterProfileName = config.getNotifyFilterProfile(params)

#             ( filterSubtree,
#               filterMask,
#               filterType ) = config.getNotifyFilter(filterProfileName)

            debug.logger & debug.flagApp and debug.logger('sendVarBinds: notificationHandle %s, notifyTag %s yields: transportDomain %s, transportAddress %r, securityModel %s, securityName %s, securityLevel %s' % (notificationHandle, notifyTag, transportDomain, transportAddress, securityModel, securityName, securityLevel))

            for varName, varVal in varBinds:
                if varName in (sysUpTime.name, snmpTrapOID.name):
                    continue
                try:
                    snmpEngine.accessControlModel[self.acmID].isAccessAllowed(
                        snmpEngine, securityModel, securityName,
                        securityLevel, 'notify', contextName, varName
                        )

                    debug.logger & debug.flagApp and debug.logger('sendVarBinds: ACL succeeded for OID %s securityName %s' % (varName, securityName))

                except error.StatusInformation:
                    debug.logger & debug.flagApp and debug.logger('sendVarBinds: ACL denied access for OID %s securityName %s, droppping notification' % (varName, securityName))
                    return

            # 3.3.4
            if notifyType == 1:
                pdu = v2c.SNMPv2TrapPDU()
            elif notifyType == 2:
                pdu = v2c.InformRequestPDU()
            else:
                raise error.ProtocolError('Unknown notify-type %r', notifyType)
            
            v2c.apiPDU.setDefaults(pdu)
            v2c.apiPDU.setVarBinds(pdu, varBinds)

            # 3.3.5
            try:
                sendRequestHandle = self.sendPdu(snmpEngine,
                                                 targetAddrName,
                                                 contextEngineId,
                                                 contextName,
                                                 pdu,
                                                 self.processResponseVarBinds,
                                                 (notificationHandle, 
                                                  cbFun, cbCtx))
                
            except error.StatusInformation:
                statusInformation = sys.exc_info()[1]
                debug.logger & debug.flagApp and debug.logger('sendVarBinds: sendRequestHandle %s: sendPdu() failed with %r' % (sendRequestHandle, statusInformation))
                if notificationHandle not in self.__pendingNotifications or \
                       not self.__pendingNotifications[notificationHandle]:
                    if notificationHandle in self.__pendingNotifications:
                        del self.__pendingNotifications[notificationHandle]
                    cbFun(snmpEngine,
                          notificationHandle,
                          statusInformation['errorIndication'],
                          0, 0, (), cbCtx)
                return notificationHandle

            debug.logger & debug.flagApp and debug.logger('sendVarBinds: notificationHandle %s, sendRequestHandle %s, timeout %d' % (notificationHandle, sendRequestHandle, timeout))

            if notifyType == 2:
                if notificationHandle not in self.__pendingNotifications:
                    self.__pendingNotifications[notificationHandle] = set()
                self.__pendingNotifications[notificationHandle].add(sendRequestHandle)

        debug.logger & debug.flagApp and debug.logger('sendVarBinds: notificationHandle %s, sendRequestHandle %s, notification(s) sent' % (notificationHandle, sendRequestHandle))

        return notificationHandle
Ejemplo n.º 3
0
    def sendVarBinds(self,
                     snmpEngine,
                     notificationTarget,
                     contextEngineId,
                     contextName,
                     varBinds=(),
                     cbFun=None,
                     cbCtx=None):
        debug.logger & debug.FLAG_APP and debug.logger(
            'sendVarBinds: notificationTarget %s, contextEngineId %s, '
            'contextName "%s", varBinds %s' %
            (notificationTarget, contextEngineId
             or '<default>', contextName, varBinds))

        mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder

        if contextName:
            __SnmpAdminString, = mibBuilder.importSymbols(
                'SNMP-FRAMEWORK-MIB', 'SnmpAdminString')
            contextName = __SnmpAdminString(contextName)

        # 3.3
        notifyTag, notifyType = config.getNotificationInfo(
            snmpEngine, notificationTarget)

        notificationHandle = getNextHandle()

        debug.logger & debug.FLAG_APP and debug.logger(
            'sendVarBinds: notificationHandle %s, notifyTag %s, '
            'notifyType %s' % (notificationHandle, notifyTag, notifyType))

        varBinds = [(v2c.ObjectIdentifier(x), y) for x, y in varBinds]

        # 3.3.2 & 3.3.3
        snmpTrapOID, sysUpTime = mibBuilder.importSymbols(
            '__SNMPv2-MIB', 'snmpTrapOID', 'sysUpTime')

        snmpTrapOID = snmpTrapOID.getName()
        sysUpTime, uptime = sysUpTime.getName(), sysUpTime.getSyntax()

        # Add sysUpTime if not present already
        if not varBinds or varBinds[0][0] != sysUpTime:
            varBinds.insert(0,
                            (v2c.ObjectIdentifier(sysUpTime), uptime.clone()))

        # Search for and reposition sysUpTime if it's elsewhere
        for idx, varBind in enumerate(varBinds[1:]):
            if varBind[0] == sysUpTime:
                varBinds[0] = varBind
                del varBinds[idx + 1]
                break

        if len(varBinds) < 2:
            raise error.PySnmpError('SNMP notification PDU requires '
                                    'SNMPv2-MIB::snmpTrapOID.0 to be present')

        # Search for and reposition snmpTrapOID if it's elsewhere
        for idx, varBind in enumerate(varBinds[2:]):
            if varBind[0] == snmpTrapOID:
                del varBinds[idx + 2]
                if varBinds[1][0] == snmpTrapOID:
                    varBinds[1] = varBind

                else:
                    varBinds.insert(1, varBind)
                break

        if varBinds[1][0] != snmpTrapOID:
            raise error.PySnmpError('SNMP notification PDU requires '
                                    'SNMPv2-MIB::snmpTrapOID.0 to be present')

        sendRequestHandle = -1

        debug.logger & debug.FLAG_APP and debug.logger(
            'sendVarBinds: final varBinds %s' % (varBinds, ))

        for targetAddrName in config.getTargetNames(snmpEngine, notifyTag):
            (transportDomain, transportAddress, timeout, retryCount,
             params) = config.getTargetAddr(snmpEngine, targetAddrName)

            (messageProcessingModel, securityModel, securityName,
             securityLevel) = config.getTargetParams(snmpEngine, params)

            # 3.3.1 XXX
            # XXX filtering's yet to be implemented
            #             filterProfileName = config.getNotifyFilterProfile(params)

            #             (filterSubtree, filterMask,
            #              filterType) = config.getNotifyFilter(filterProfileName)

            debug.logger & debug.FLAG_APP and debug.logger(
                'sendVarBinds: notificationHandle %s, notifyTag %s yields: '
                'transportDomain %s, transportAddress %r, securityModel %s, '
                'securityName %s, securityLevel %s' %
                (notificationHandle, notifyTag, transportDomain,
                 transportAddress, securityModel, securityName, securityLevel))

            for varName, varVal in varBinds:
                if varName in (sysUpTime, snmpTrapOID):
                    continue

                try:
                    snmpEngine.accessControlModel[self.ACM_ID].isAccessAllowed(
                        snmpEngine, securityModel, securityName, securityLevel,
                        'notify', contextName, varName)

                    debug.logger & debug.FLAG_APP and debug.logger(
                        'sendVarBinds: ACL succeeded for OID %s securityName %s'
                        % (varName, securityName))

                except error.StatusInformation:
                    debug.logger & debug.FLAG_APP and debug.logger(
                        'sendVarBinds: ACL denied access for OID %s securityName %s,'
                        'dropping notification' % (varName, securityName))
                    return

            # 3.3.4
            if notifyType == 1:
                pdu = v2c.SNMPv2TrapPDU()

            elif notifyType == 2:
                pdu = v2c.InformRequestPDU()

            else:
                raise error.ProtocolError('Unknown notify-type %r', notifyType)

            v2c.apiPDU.setDefaults(pdu)
            v2c.apiPDU.setVarBinds(pdu, varBinds)

            # 3.3.5
            try:
                sendRequestHandle = self.sendPdu(
                    snmpEngine, targetAddrName, contextEngineId, contextName,
                    pdu, self.processResponseVarBinds,
                    (notificationHandle, cbFun, cbCtx))

            except error.StatusInformation as exc:
                statusInformation = exc

                debug.logger & debug.FLAG_APP and debug.logger(
                    'sendVarBinds: sendRequestHandle %s: sendPdu() failed '
                    'with %r' % (sendRequestHandle, statusInformation))

                if (notificationHandle not in self.__pendingNotifications or
                        not self.__pendingNotifications[notificationHandle]):

                    if notificationHandle in self.__pendingNotifications:
                        del self.__pendingNotifications[notificationHandle]

                    if cbFun:
                        cbFun(snmpEngine, notificationHandle,
                              statusInformation['errorIndication'], 0, 0, (),
                              cbCtx)

                return notificationHandle

            debug.logger & debug.FLAG_APP and debug.logger(
                'sendVarBinds: notificationHandle %s, sendRequestHandle %s, '
                'timeout %d' %
                (notificationHandle, sendRequestHandle, timeout))

            if notifyType == 2:
                if notificationHandle not in self.__pendingNotifications:
                    self.__pendingNotifications[notificationHandle] = set()
                self.__pendingNotifications[notificationHandle].add(
                    sendRequestHandle)

        debug.logger & debug.FLAG_APP and debug.logger(
            'sendVarBinds: notificationHandle %s, sendRequestHandle %s, '
            'notification(s) sent' % (notificationHandle, sendRequestHandle))

        return notificationHandle
* with TRAP ID 'coldStart' specified as an OID

The following Net-SNMP command will produce similar SNMP notification:

| $ snmpinform -v2c -c public udp:demo.snmplabs.com 0 1.3.6.1.6.3.1.1.5.1
| $ snmpinform -v2c -c public udp6:[::1] 0 1.3.6.1.6.3.1.1.5.1

"""#
from time import time
from pysnmp.carrier.asynsock.dispatch import AsynsockDispatcher
from pysnmp.carrier.asynsock.dgram import udp, udp6
from pyasn1.codec.ber import encoder, decoder
from pysnmp.proto.api import v2c as pMod

# Build PDU
reqPDU = pMod.InformRequestPDU()
pMod.apiTrapPDU.setDefaults(reqPDU)

# Build message
trapMsg = pMod.Message()
pMod.apiMessage.setDefaults(trapMsg)
pMod.apiMessage.setCommunity(trapMsg, 'public')
pMod.apiMessage.setPDU(trapMsg, reqPDU)

startedAt = time()


def cbTimerFun(timeNow):
    if timeNow - startedAt > 3:
        raise Exception("Request timed out")
Ejemplo n.º 5
0
    def sendNotification(self,
                         snmpEngine,
                         notificationTarget,
                         notificationName,
                         additionalVarBinds=None,
                         cbFun=None,
                         cbCtx=None,
                         contextName=null):
        # 3.3
        (notifyTag,
         notifyType) = config.getNotificationInfo(snmpEngine,
                                                  notificationTarget)

        metaSendPduHandle = getNextHandle()

        debug.logger & debug.flagApp and debug.logger(
            'sendNotification: metaSendPduHandle %s, notifyTag %s, notifyType %s'
            % (metaSendPduHandle, notifyTag, notifyType))

        contextMibInstrumCtl = self.__context.getMibInstrum(contextName)

        for targetAddrName in config.getTargetNames(snmpEngine, notifyTag):
            (transportDomain, transportAddress, timeout, retryCount,
             params) = config.getTargetAddr(snmpEngine, targetAddrName)
            (messageProcessingModel, securityModel, securityName,
             securityLevel) = config.getTargetParams(snmpEngine, params)

            debug.logger & debug.flagApp and debug.logger(
                'sendNotification: metaSendPduHandle %s, notifyTag %s yields: transportDomain %s, transportAddress %r, securityModel %s, securityName %s, securityLevel %s'
                %
                (metaSendPduHandle, notifyTag, transportDomain,
                 transportAddress, securityModel, securityName, securityLevel))

            # 3.3.1 XXX
            # XXX filtering's yet to be implemented
            #             filterProfileName = config.getNotifyFilterProfile(params)

            #             ( filterSubtree,
            #               filterMask,
            #               filterType ) = config.getNotifyFilter(filterProfileName)

            varBinds = []

            # 3.3.2 & 3.3.3
            sysUpTime, = contextMibInstrumCtl.mibBuilder.importSymbols(
                '__SNMPv2-MIB', 'sysUpTime')

            if additionalVarBinds:
                for varName, varVal in additionalVarBinds:
                    if varName == sysUpTime.name:
                        varBinds.append((varName, varVal))
                        break
            if not varBinds:
                varBinds.append((sysUpTime.name,
                                 sysUpTime.syntax.clone()))  # for actual value

            snmpTrapOid, = contextMibInstrumCtl.mibBuilder.importSymbols(
                '__SNMPv2-MIB', 'snmpTrapOID')
            if notificationName:
                varBinds.append((snmpTrapOid.name,
                                 snmpTrapOid.syntax.clone(notificationName)))
            else:
                varBinds.append((snmpTrapOid.name, snmpTrapOid.syntax))

# XXX it's still not clear how to instantiate OBJECTS clause
#             # Get notification objects names
#             for notificationObject in snmpTrapVal.getObjects():
#                 mibNode, = contextMibInstrumCtl.mibBuilder.importSymbols(
#                     *notificationObject
#                     )
#                 try:
#                     objectInstance = mibNode.getNode(mibNode.name + (0,))
#                 except error.SmiError:
#                     return
#                 varBinds.append((objectInstance.name, objectInstance.syntax))

            for varName, varVal in additionalVarBinds:
                if varName in (sysUpTime.name, snmpTrapOid.name):
                    continue
                try:
                    snmpEngine.accessControlModel[self.acmID].isAccessAllowed(
                        snmpEngine, securityModel, securityName, securityLevel,
                        'notify', contextName, varName)
                except error.SmiError:
                    debug.logger & debug.flagApp and debug.logger(
                        'sendNotification: OID %s not allowed for %s, droppping notification'
                        % (varName, securityName))
                    return
                else:
                    varBinds.append((varName, varVal))

            # 3.3.4
            if notifyType == 1:
                pdu = v2c.SNMPv2TrapPDU()
            elif notifyType == 2:
                pdu = v2c.InformRequestPDU()
            else:
                raise RuntimeError()
            v2c.apiPDU.setDefaults(pdu)
            v2c.apiPDU.setVarBinds(pdu, varBinds)

            # User-side API assumes SMIv2
            if messageProcessingModel == 0:
                pdu = rfc2576.v2ToV1(pdu)
                pduVersion = 0
            else:
                pduVersion = 1

            # 3.3.5
            if notifyType == 1:
                snmpEngine.msgAndPduDsp.sendPdu(
                    snmpEngine, transportDomain, transportAddress,
                    messageProcessingModel, securityModel, securityName,
                    securityLevel, self.__context.contextEngineId, contextName,
                    pduVersion, pdu, None)
            else:
                # Convert timeout in seconds into timeout in timer ticks
                timeoutInTicks = float(
                    timeout
                ) / 100 / snmpEngine.transportDispatcher.getTimerResolution()

                # 3.3.6a
                sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
                    snmpEngine,
                    transportDomain,
                    transportAddress,
                    messageProcessingModel,
                    securityModel,
                    securityName,
                    securityLevel,
                    self.__context.contextEngineId,
                    contextName,
                    pduVersion,
                    pdu,
                    1,  # expectResponse
                    timeoutInTicks,
                    self.processResponsePdu,
                    (cbFun, cbCtx))

                debug.logger & debug.flagApp and debug.logger(
                    'sendNotification: metaSendPduHandle %s, sendPduHandle %s, timeout %d'
                    % (metaSendPduHandle, sendPduHandle, timeout))

                # 3.3.6b
                self.__pendingReqs[sendPduHandle] = (
                    transportDomain, transportAddress, messageProcessingModel,
                    securityModel, securityName, securityLevel,
                    self.__context.contextEngineId, contextName, pduVersion,
                    pdu, timeout, retryCount, 1, metaSendPduHandle)

                if metaSendPduHandle not in self.__pendingNotifications:
                    self.__pendingNotifications[metaSendPduHandle] = 0
                self.__pendingNotifications[metaSendPduHandle] += 1

                snmpEngine.transportDispatcher.jobStarted(id(self))

        debug.logger & debug.flagApp and debug.logger(
            'sendNotification: metaSendPduHandle %s, notification(s) sent' %
            metaSendPduHandle)

        return metaSendPduHandle
Ejemplo n.º 6
0
    def sendNotification(self,
                         snmpEngine,
                         notificationTarget,
                         notificationName,
                         additionalVarBinds=(),
                         cbFun=None,
                         cbCtx=None,
                         contextName=null,
                         instanceIndex=None):
        debug.logger & debug.flagApp and debug.logger(
            'sendNotification: notificationTarget %s, notificationName %s, additionalVarBinds %s, contextName "%s", instanceIndex %s'
            % (notificationTarget, notificationName, additionalVarBinds,
               contextName, instanceIndex))

        if contextName:
            __SnmpAdminString, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols(
                'SNMP-FRAMEWORK-MIB', 'SnmpAdminString')
            contextName = __SnmpAdminString(contextName)

        # 3.3
        (notifyTag,
         notifyType) = config.getNotificationInfo(snmpEngine,
                                                  notificationTarget)

        metaSendPduHandle = getNextHandle()

        debug.logger & debug.flagApp and debug.logger(
            'sendNotification: metaSendPduHandle %s, notifyTag %s, notifyType %s'
            % (metaSendPduHandle, notifyTag, notifyType))

        contextMibInstrumCtl = self.snmpContext.getMibInstrum(contextName)

        additionalVarBinds = [(v2c.ObjectIdentifier(x), y)
                              for x, y in additionalVarBinds]

        for targetAddrName in config.getTargetNames(snmpEngine, notifyTag):
            (transportDomain, transportAddress, timeout, retryCount,
             params) = config.getTargetAddr(snmpEngine, targetAddrName)
            (messageProcessingModel, securityModel, securityName,
             securityLevel) = config.getTargetParams(snmpEngine, params)

            debug.logger & debug.flagApp and debug.logger(
                'sendNotification: metaSendPduHandle %s, notifyTag %s yields: transportDomain %s, transportAddress %r, securityModel %s, securityName %s, securityLevel %s'
                %
                (metaSendPduHandle, notifyTag, transportDomain,
                 transportAddress, securityModel, securityName, securityLevel))

            # 3.3.1 XXX
            # XXX filtering's yet to be implemented
            #             filterProfileName = config.getNotifyFilterProfile(params)

            #             ( filterSubtree,
            #               filterMask,
            #               filterType ) = config.getNotifyFilter(filterProfileName)

            varBinds = []

            # 3.3.2 & 3.3.3
            sysUpTime, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols(
                '__SNMPv2-MIB', 'sysUpTime')

            for varName, varVal in additionalVarBinds:
                if varName == sysUpTime.name:
                    varBinds.append((varName, varVal))
                    break
            if not varBinds:
                varBinds.append((sysUpTime.name,
                                 sysUpTime.syntax.clone()))  # for actual value

            snmpTrapOid, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols(
                '__SNMPv2-MIB', 'snmpTrapOID')
            if len(notificationName) == 2:  # ('MIB', 'symbol')
                notificationTypeObject, = contextMibInstrumCtl.mibBuilder.importSymbols(
                    *notificationName)
                varBinds.append(
                    (snmpTrapOid.name,
                     v2c.ObjectIdentifier(notificationTypeObject.name)))
                debug.logger & debug.flagApp and debug.logger(
                    'sendNotification: notification type object is %s' %
                    notificationTypeObject)
                for notificationObject in notificationTypeObject.getObjects():
                    mibNode, = contextMibInstrumCtl.mibBuilder.importSymbols(
                        *notificationObject)
                    if instanceIndex:
                        mibNode = mibNode.getNode(mibNode.name + instanceIndex)
                    else:
                        mibNode = mibNode.getNextNode(mibNode.name)
                    varBinds.append((mibNode.name, mibNode.syntax))
                    debug.logger & debug.flagApp and debug.logger(
                        'sendNotification: processed notification object %s, instance index %s, var-bind %s'
                        % (notificationObject, instanceIndex is None
                           and "<first>" or instanceIndex, mibNode))
            elif notificationName:  # numeric OID
                varBinds.append((snmpTrapOid.name,
                                 snmpTrapOid.syntax.clone(notificationName)))
            else:
                varBinds.append((snmpTrapOid.name, snmpTrapOid.syntax))

            for varName, varVal in additionalVarBinds:
                if varName in (sysUpTime.name, snmpTrapOid.name):
                    continue
                try:
                    snmpEngine.accessControlModel[self.acmID].isAccessAllowed(
                        snmpEngine, securityModel, securityName, securityLevel,
                        'notify', contextName, varName)
                except error.StatusInformation:
                    debug.logger & debug.flagApp and debug.logger(
                        'sendNotification: OID %s not allowed for %s, droppping notification'
                        % (varName, securityName))
                    return
                else:
                    varBinds.append((varName, varVal))

            # 3.3.4
            if notifyType == 1:
                pdu = v2c.SNMPv2TrapPDU()
            elif notifyType == 2:
                pdu = v2c.InformRequestPDU()
            else:
                raise RuntimeError()
            v2c.apiPDU.setDefaults(pdu)
            v2c.apiPDU.setVarBinds(pdu, varBinds)

            # User-side API assumes SMIv2
            if messageProcessingModel == 0:
                reqPDU = rfc2576.v2ToV1(pdu)
                pduVersion = 0
            else:
                reqPDU = pdu
                pduVersion = 1

            # 3.3.5
            if notifyType == 1:
                try:
                    snmpEngine.msgAndPduDsp.sendPdu(
                        snmpEngine, transportDomain, transportAddress,
                        messageProcessingModel, securityModel, securityName,
                        securityLevel, self.snmpContext.contextEngineId,
                        contextName, pduVersion, reqPDU, None)
                except error.StatusInformation:
                    statusInformation = sys.exc_info()[1]
                    debug.logger & debug.flagApp and debug.logger(
                        'sendReq: metaSendPduHandle %s: sendPdu() failed with %r'
                        % (metaSendPduHandle, statusInformation))
                    if metaSendPduHandle not in self.__pendingNotifications or \
                            not self.__pendingNotifications[metaSendPduHandle]:
                        if metaSendPduHandle in self.__pendingNotifications:
                            del self.__pendingNotifications[metaSendPduHandle]
                        self._handleResponse(
                            metaSendPduHandle,
                            statusInformation['errorIndication'], 0, 0, (),
                            cbFun, cbCtx)
                    return metaSendPduHandle
            else:
                # Convert timeout in seconds into timeout in timer ticks
                timeoutInTicks = float(
                    timeout
                ) / 100 / snmpEngine.transportDispatcher.getTimerResolution()

                # 3.3.6a
                try:
                    sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
                        snmpEngine,
                        transportDomain,
                        transportAddress,
                        messageProcessingModel,
                        securityModel,
                        securityName,
                        securityLevel,
                        self.snmpContext.contextEngineId,
                        contextName,
                        pduVersion,
                        reqPDU,
                        1,  # expectResponse
                        timeoutInTicks,
                        self.processResponsePdu,
                        (cbFun, cbCtx))
                except error.StatusInformation:
                    statusInformation = sys.exc_info()[1]
                    debug.logger & debug.flagApp and debug.logger(
                        'sendReq: metaSendPduHandle %s: sendPdu() failed with %r'
                        % (metaSendPduHandle, statusInformation))
                    if metaSendPduHandle not in self.__pendingNotifications or \
                            not self.__pendingNotifications[metaSendPduHandle]:
                        if metaSendPduHandle in self.__pendingNotifications:
                            del self.__pendingNotifications[metaSendPduHandle]
                        self._handleResponse(
                            metaSendPduHandle,
                            statusInformation['errorIndication'], 0, 0, (),
                            cbFun, cbCtx)
                    return metaSendPduHandle

                debug.logger & debug.flagApp and debug.logger(
                    'sendNotification: metaSendPduHandle %s, sendPduHandle %s, timeout %d'
                    % (metaSendPduHandle, sendPduHandle, timeout))

                # 3.3.6b
                self.__pendingReqs[sendPduHandle] = (
                    transportDomain, transportAddress, messageProcessingModel,
                    securityModel, securityName, securityLevel,
                    self.snmpContext.contextEngineId, contextName, pdu,
                    timeout, retryCount, 1, metaSendPduHandle)

                if metaSendPduHandle not in self.__pendingNotifications:
                    self.__pendingNotifications[metaSendPduHandle] = 0
                self.__pendingNotifications[metaSendPduHandle] += 1

                snmpEngine.transportDispatcher.jobStarted(id(self))

        debug.logger & debug.flagApp and debug.logger(
            'sendNotification: metaSendPduHandle %s, notification(s) sent' %
            metaSendPduHandle)

        return metaSendPduHandle
Ejemplo n.º 7
0
def sendNotification(snmpDispatcher, authData, transportTarget, notifyType,
                     *varBinds, **options):
    """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
    ----------
    snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
        Class instance representing asyncore-based asynchronous event loop and
        associated state information.

    authData: :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData`
        Class instance representing SNMP credentials.

    transportTarget: :py:class:`~pysnmp.hlapi.asyncore.UdpTransportTarget` or
        :py:class:`~pysnmp.hlapi.asyncore.Udp6TransportTarget`
        Class instance representing transport type along with SNMP peer address.

    notifyType: str
        Indicates type of notification to be sent. Recognized literal
        values are *trap* or *inform*.

    \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType` or :py:class:`~pysnmp.smi.rfc1902.NotificationType`
        One or more objects representing MIB variables to place
        into SNMP notification. It could be tuples of OID-values
        or :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
        of :py:class:`~pysnmp.smi.rfc1902.NotificationType` objects.

        Besides user variable-bindings, SNMP Notification PDU requires at
        least two variable-bindings to be present:

        0. SNMPv2-MIB::sysUpTime.0 = <agent uptime>
        1. SNMPv2-SMI::snmpTrapOID.0 = <notification ID>

        When sending SNMPv1 TRAP, more variable-bindings could be present:

        2. SNMP-COMMUNITY-MIB::snmpTrapAddress.0 = <agent-IP>
        3. SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 = <snmp-community-name>
        4. SNMP-COMMUNITY-MIB::snmpTrapEnterprise.0 = <enterprise-OID>

        If user does not supply some or any of the above variable-bindings or
        if they are at the wrong positions, the system will add/reorder the
        missing ones automatically.

        On top of that, some notification types imply including some additional
        variable-bindings providing additional details on the event being
        reported. Therefore it is generally easier to use
        :py:class:`~pysnmp.smi.rfc1902.NotificationType` object which will
        help adding relevant variable-bindings.

    Other Parameters
    ----------------
    \*\*options :
        Request options:

        * `lookupMib` - load MIB and resolve response MIB variables at
          the cost of slightly reduced performance. Default is `False`.
        * `cbFun` (callable) - user-supplied callable that is invoked
          to pass SNMP response data or error to user at a later point
          of time. Default is `None`.
        * `cbCtx` (object) - user-supplied object passing additional
          parameters to/from `cbFun`. Default is `None`.

    Note
    ----
    The `SnmpDispatcher` object may be expensive to create, therefore it is
    advised to maintain it for the lifecycle of the application/thread for
    as long as possible.

    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.hlapi.v1arch.asyncore import *
    >>>
    >>> snmpDispatcher = SnmpDispatcher()
    >>>
    >>> sendNotification(
    >>>     snmpDispatcher,
    >>>     CommunityData('public'),
    >>>     UdpTransportTarget(('demo.snmplabs.com', 162)),
    >>>     'trap',
    >>>     NotificationType(ObjectIdentity('SNMPv2-MIB', 'coldStart')),
    >>>     lookupMib=True
    >>> )
    >>> snmpDispatcher.transportDispatcher.runDispatcher()
    """

    sysUpTime = v2c.apiTrapPDU.sysUpTime
    snmpTrapOID = v2c.apiTrapPDU.snmpTrapOID

    def _ensureVarBinds(varBinds):
        # Add sysUpTime if not present already
        if not varBinds or varBinds[0][0] != sysUpTime:
            varBinds.insert(
                0, (v2c.ObjectIdentifier(sysUpTime), v2c.TimeTicks(0)))

        # Search for and reposition sysUpTime if it's elsewhere
        for idx, varBind in enumerate(varBinds[1:]):
            if varBind[0] == sysUpTime:
                varBinds[0] = varBind
                del varBinds[idx + 1]
                break

        if len(varBinds) < 2:
            raise error.PySnmpError('SNMP notification PDU requires '
                                    'SNMPv2-MIB::snmpTrapOID.0 to be present')

        # Search for and reposition snmpTrapOID if it's elsewhere
        for idx, varBind in enumerate(varBinds[2:]):
            if varBind[0] == snmpTrapOID:
                del varBinds[idx + 2]
                if varBinds[1][0] == snmpTrapOID:
                    varBinds[1] = varBind
                else:
                    varBinds.insert(1, varBind)
                break

        # Fail on missing snmpTrapOID
        if varBinds[1][0] != snmpTrapOID:
            raise error.PySnmpError('SNMP notification PDU requires '
                                    'SNMPv2-MIB::snmpTrapOID.0 to be present')

        return varBinds

    def _cbFun(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
        if not cbFun:
            return

        if errorIndication:
            cbFun(errorIndication,
                  v2c.Integer(0),
                  v2c.Integer(0),
                  None,
                  cbCtx=cbCtx,
                  snmpDispatcher=snmpDispatcher,
                  stateHandle=stateHandle)
            return

        errorStatus = v2c.apiTrapPDU.getErrorStatus(rspPdu)
        errorIndex = v2c.apiTrapPDU.getErrorIndex(rspPdu)

        varBinds = v2c.apiTrapPDU.getVarBinds(rspPdu)

        if lookupMib:
            varBinds = VB_PROCESSOR.unmakeVarBinds(snmpDispatcher.cache,
                                                   varBinds)

        nextStateHandle = v2c.getNextRequestID()

        nextVarBinds = cbFun(errorIndication,
                             errorStatus,
                             errorIndex,
                             varBinds,
                             cbCtx=cbCtx,
                             snmpDispatcher=snmpDispatcher,
                             stateHandle=stateHandle,
                             nextStateHandle=nextStateHandle)

        if not nextVarBinds:
            return

        v2c.apiTrapPDU.setRequestID(reqPdu, nextStateHandle)
        v2c.apiTrapPDU.setVarBinds(reqPdu, _ensureVarBinds(nextVarBinds))

        return snmpDispatcher.sendPdu(authData,
                                      transportTarget,
                                      reqPdu,
                                      cbFun=_cbFun)

    lookupMib, cbFun, cbCtx = [
        options.get(x) for x in ('lookupMib', 'cbFun', 'cbCtx')
    ]

    if lookupMib:
        varBinds = VB_PROCESSOR.makeVarBinds(snmpDispatcher.cache, varBinds)

    if notifyType == 'trap':
        reqPdu = v2c.TrapPDU()
    else:
        reqPdu = v2c.InformRequestPDU()

    v2c.apiTrapPDU.setDefaults(reqPdu)
    v2c.apiTrapPDU.setVarBinds(reqPdu, varBinds)

    varBinds = v2c.apiTrapPDU.getVarBinds(reqPdu)

    v2c.apiTrapPDU.setVarBinds(reqPdu, _ensureVarBinds(varBinds))

    if authData.mpModel == 0:
        reqPdu = rfc2576.v2ToV1(reqPdu)

    return snmpDispatcher.sendPdu(authData,
                                  transportTarget,
                                  reqPdu,
                                  cbFun=_cbFun)
Ejemplo n.º 8
0
    def sendNotification(self,
                         snmpEngine,
                         notificationTarget,
                         notificationName,
                         additionalVarBinds=None,
                         cbFun=None,
                         cbCtx=None,
                         contextName=''):
        # 3.3
        (notifyTag,
         notifyType) = config.getNotificationInfo(snmpEngine,
                                                  notificationTarget)
        contextMibInstrumCtl = self.__context.getMibInstrum(contextName)
        for targetAddrName in config.getTargetNames(snmpEngine, notifyTag):
            (transportDomain, transportAddress, timeout, retryCount,
             params) = config.getTargetAddr(snmpEngine, targetAddrName)
            (messageProcessingModel, securityModel, securityName,
             securityLevel) = config.getTargetParams(snmpEngine, params)

            # 3.3.1 XXX
            # XXX filtering's yet to be implemented
            #             filterProfileName = config.getNotifyFilterProfile(params)

            #             ( filterSubtree,
            #               filterMask,
            #               filterType ) = config.getNotifyFilter(filterProfileName)

            varBinds = []

            # 3.3.2 & 3.3.3
            sysUpTime, = contextMibInstrumCtl.mibBuilder.importSymbols(
                '__SNMPv2-MIB', 'sysUpTime')
            varBinds.append(
                (sysUpTime.name, sysUpTime.syntax.clone())  # for actual value
            )

            snmpTrapOid, = contextMibInstrumCtl.mibBuilder.importSymbols(
                '__SNMPv2-MIB', 'snmpTrapOID')
            if notificationName:
                varBinds.append((snmpTrapOid.name,
                                 snmpTrapOid.syntax.clone(notificationName)))
            else:
                varBinds.append((snmpTrapOid.name, snmpTrapOid.syntax))

# XXX it's still not clear how to instantiate OBJECTS clause
#             # Get notification objects names
#             for notificationObject in snmpTrapVal.getObjects():
#                 mibNode, = apply(
#                     contextMibInstrumCtl.mibBuilder.importSymbols,
#                     notificationObject
#                     )
#                 try:
#                     objectInstance = mibNode.getNode(mibNode.name + (0,))
#                 except error.SmiError:
#                     return
#                 varBinds.append((objectInstance.name, objectInstance.syntax))

            if additionalVarBinds:
                if version_info < (1, 6):
                    additionalVarBinds = list(additionalVarBinds)
                varBinds.extend(additionalVarBinds)

            for varName, varVal in varBinds:
                try:
                    snmpEngine.accessControlModel[vacmID].isAccessAllowed(
                        snmpEngine, securityModel, securityName, securityLevel,
                        'notify', contextName, varName)
                except error.SmiError:
                    return

            # 3.3.4
            if notifyType == 1:
                pdu = v2c.SNMPv2TrapPDU()
            elif notifyType == 2:
                pdu = v2c.InformRequestPDU()
            else:
                raise RuntimeError()
            v2c.apiPDU.setDefaults(pdu)
            v2c.apiPDU.setVarBinds(pdu, varBinds)

            # User-side API assumes SMIv2
            if messageProcessingModel == 0:
                pdu = rfc2576.v2ToV1(pdu)
                pduVersion = 0
            else:
                pduVersion = 1

            # 3.3.5
            if notifyType == 1:
                snmpEngine.msgAndPduDsp.sendPdu(
                    snmpEngine, transportDomain, transportAddress,
                    messageProcessingModel, securityModel, securityName,
                    securityLevel, self.__context.contextEngineId, contextName,
                    pduVersion, pdu, None)
            else:
                # 3.3.6a
                sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
                    snmpEngine, transportDomain, transportAddress,
                    messageProcessingModel, securityModel, securityName,
                    securityLevel, self.__context.contextEngineId, contextName,
                    pduVersion, pdu,
                    (self.processResponsePdu,
                     float(timeout) / 100 + time.time(), (cbFun, cbCtx)))

                # 3.3.6b
                self.__pendingReqs[sendPduHandle] = (
                    transportDomain, transportAddress, messageProcessingModel,
                    securityModel, securityName, securityLevel,
                    self.__context.contextEngineId, contextName, pduVersion,
                    pdu, timeout, retryCount, 1, getNextHandle())

                snmpEngine.transportDispatcher.jobStarted(id(self))

                return sendPduHandle
Ejemplo n.º 9
0
def sendNotification(snmpDispatcher, authData, transportTarget, notifyType,
                     *varBinds, **options):
    """Creates a generator to send SNMP notification.

    When iterator gets advanced by :py:mod:`asyncio` main loop,
    SNMP TRAP or INFORM notification is send (:RFC:`1905#section-4.2.6`).
    The iterator yields :py:class:`asyncio.Future` which gets done whenever
    response arrives or error occurs.

    Parameters
    ----------
    snmpDispatcher: :py:class:`~pysnmp.hlapi.v1arch.asyncore.SnmpDispatcher`
        Class instance representing asynio-based asynchronous event loop and
        associated state information.

    authData: :py:class:`~pysnmp.hlapi.v1arch.CommunityData`
        Class instance representing SNMPv1/v2c credentials.

    transportTarget: :py:class:`~pysnmp.hlapi.v1arch.asyncio.UdpTransportTarget` or
        :py:class:`~pysnmp.hlapi.v1arch.asyncio.Udp6TransportTarget` Class instance representing
        transport type along with SNMP peer address.

    notifyType : str
        Indicates type of notification to be sent. Recognized literal
        values are *trap* or *inform*.

    \*varBinds: :class:`tuple` of OID-value pairs or :py:class:`~pysnmp.smi.rfc1902.ObjectType` or :py:class:`~pysnmp.smi.rfc1902.NotificationType`
        One or more objects representing MIB variables to place
        into SNMP notification. It could be tuples of OID-values
        or :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances
        of :py:class:`~pysnmp.smi.rfc1902.NotificationType` objects.

        Besides user variable-bindings, SNMP Notification PDU requires at
        least two variable-bindings to be present:

        0. SNMPv2-MIB::sysUpTime.0 = <agent uptime>
        1. SNMPv2-SMI::snmpTrapOID.0 = <notification ID>

        When sending SNMPv1 TRAP, more variable-bindings could be present:

        2. SNMP-COMMUNITY-MIB::snmpTrapAddress.0 = <agent-IP>
        3. SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 = <snmp-community-name>
        4. SNMP-COMMUNITY-MIB::snmpTrapEnterprise.0 = <enterprise-OID>

        If user does not supply some or any of the above variable-bindings or
        if they are at the wrong positions, the system will add/reorder the
        missing ones automatically.

        On top of that, some notification types imply including some additional
        variable-bindings providing additional details on the event being
        reported. Therefore it is generally easier to use
        :py:class:`~pysnmp.smi.rfc1902.NotificationType` object which will
        help adding relevant variable-bindings.

    Other Parameters
    ----------------
    \*\*options :
        Request options:

        * `lookupMib` - load MIB and resolve response MIB variables at
          the cost of slightly reduced performance. Default is `False`,
          unless :py:class:`~pysnmp.smi.rfc1902.ObjectType` or
          :py:class:`~pysnmp.smi.rfc1902.NotificationType` is present
          among `varBinds` in which case `lookupMib` gets automatically
          enabled.

    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 OID-value pairs in form of base SNMP types (if
        `lookupMib` is `False`) or :py:class:`~pysnmp.smi.rfc1902.ObjectType`
        class instances (if `lookupMib` is `True`) representing MIB variables
        returned in SNMP response.

    Raises
    ------
    PySnmpError
        Or its derivative indicating that an error occurred while
        performing SNMP operation.

    Examples
    --------
    >>> import asyncio
    >>> from pysnmp.hlapi.asyncio import *
    >>>
    >>> @asyncio.coroutine
    ... def run():
    ...     errorIndication, errorStatus, errorIndex, varBinds = yield from sendNotification(
    ...         SnmpDispatcher(),
    ...         CommunityData('public'),
    ...         UdpTransportTarget(('demo.snmplabs.com', 162)),
    ...         'trap',
    ...         NotificationType(ObjectIdentity('IF-MIB', 'linkDown')))
    ...     print(errorIndication, errorStatus, errorIndex, varBinds)
    ...
    >>> asyncio.get_event_loop().run_until_complete(run())
    (None, 0, 0, [])
    >>>
    """

    sysUpTime = v2c.apiTrapPDU.sysUpTime
    snmpTrapOID = v2c.apiTrapPDU.snmpTrapOID

    def _ensureVarBinds(varBinds):
        # Add sysUpTime if not present already
        if not varBinds or varBinds[0][0] != sysUpTime:
            varBinds.insert(
                0, (v2c.ObjectIdentifier(sysUpTime), v2c.TimeTicks(0)))

        # Search for and reposition sysUpTime if it's elsewhere
        for idx, varBind in enumerate(varBinds[1:]):
            if varBind[0] == sysUpTime:
                varBinds[0] = varBind
                del varBinds[idx + 1]
                break

        if len(varBinds) < 2:
            raise error.PySnmpError('SNMP notification PDU requires '
                                    'SNMPv2-MIB::snmpTrapOID.0 to be present')

        # Search for and reposition snmpTrapOID if it's elsewhere
        for idx, varBind in enumerate(varBinds[2:]):
            if varBind[0] == snmpTrapOID:
                del varBinds[idx + 2]
                if varBinds[1][0] == snmpTrapOID:
                    varBinds[1] = varBind
                else:
                    varBinds.insert(1, varBind)
                break

        # Fail on missing snmpTrapOID
        if varBinds[1][0] != snmpTrapOID:
            raise error.PySnmpError('SNMP notification PDU requires '
                                    'SNMPv2-MIB::snmpTrapOID.0 to be present')

        return varBinds

    def _cbFun(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
        if future.cancelled():
            return

        errorStatus = v2c.apiTrapPDU.getErrorStatus(rspPdu)
        errorIndex = v2c.apiTrapPDU.getErrorIndex(rspPdu)

        varBinds = v2c.apiTrapPDU.getVarBinds(rspPdu)

        try:
            varBindsUnmade = VB_PROCESSOR.unmakeVarBinds(
                snmpDispatcher.cache, varBinds, lookupMib)
        except Exception as e:
            future.set_exception(e)

        else:
            future.set_result(
                (errorIndication, errorStatus, errorIndex, varBindsUnmade))

    lookupMib = options.get('lookupMib')

    if not lookupMib and any(
            isinstance(x, (NotificationType, ObjectType)) for x in varBinds):
        lookupMib = True

    if lookupMib:
        varBinds = VB_PROCESSOR.makeVarBinds(snmpDispatcher.cache, varBinds)

    if notifyType == 'trap':
        reqPdu = v2c.TrapPDU()
    else:
        reqPdu = v2c.InformRequestPDU()

    v2c.apiTrapPDU.setDefaults(reqPdu)
    v2c.apiTrapPDU.setVarBinds(reqPdu, varBinds)

    varBinds = v2c.apiTrapPDU.getVarBinds(reqPdu)

    v2c.apiTrapPDU.setVarBinds(reqPdu, _ensureVarBinds(varBinds))

    if authData.mpModel == 0:
        reqPdu = rfc2576.v2ToV1(reqPdu)

    future = asyncio.Future()

    snmpDispatcher.sendPdu(authData, transportTarget, reqPdu, cbFun=_cbFun)

    if notifyType == 'trap':

        def __trapFun(future):
            if future.cancelled():
                return
            future.set_result((None, 0, 0, []))

        loop = asyncio.get_event_loop()
        loop.call_soon(__trapFun, future)

    return future