Esempio n. 1
0
    def _sendPdu(self, snmpEngine, transportDomain, transportAddress,
                 messageProcessingModel, securityModel, securityName,
                 securityLevel, contextEngineId, contextName, reqPDU, timeout,
                 retryCount, retries, sendRequestHandle, cbInfo):
        (processResponsePdu, cbCtx) = cbInfo

        # Convert timeout in seconds into timeout in timer ticks
        timeoutInTicks = float(
            timeout) / 100 / snmpEngine.transportDispatcher.getTimerResolution(
            )

        if not self.__SnmpEngineID or not self.__SnmpAdminString:
            self.__SnmpEngineID, self.__SnmpAdminString = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols(
                'SNMP-FRAMEWORK-MIB', 'SnmpEngineID', 'SnmpAdminString')

        # Cast possible strings into bytes
        if contextEngineId:
            contextEngineId = self.__SnmpEngineID(contextEngineId)
        contextName = self.__SnmpAdminString(contextName)

        origPDU = reqPDU

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

        # 3.1
        sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
            snmpEngine,
            transportDomain,
            transportAddress,
            messageProcessingModel,
            securityModel,
            securityName,
            securityLevel,
            contextEngineId,
            contextName,
            pduVersion,
            reqPDU,
            1,  # expectResponse
            timeoutInTicks,
            processResponsePdu,
            cbCtx)

        snmpEngine.transportDispatcher.jobStarted(id(self))

        self.__pendingReqs[sendPduHandle] = (transportDomain, transportAddress,
                                             messageProcessingModel,
                                             securityModel, securityName,
                                             securityLevel, contextEngineId,
                                             contextName, pduVersion, origPDU,
                                             timeout, retryCount, retries,
                                             sendRequestHandle)

        debug.logger & debug.flagApp and debug.logger(
            '_sendPdu: sendPduHandle %s, timeout %d*10 ms/%d ticks, retry %d of %d'
            % (sendPduHandle, timeout, timeoutInTicks, retries, retryCount))
Esempio n. 2
0
    def sendPdu(self, snmpEngine, stateReference, PDU):
        (messageProcessingModel, securityModel, securityName,
         securityLevel, contextEngineId, contextName,
         pduVersion, _, origPdu, maxSizeResponseScopedPDU,
         statusInformation) = self.__pendingReqs[stateReference]

        # Agent-side API complies with SMIv2
        if messageProcessingModel == 0:
            PDU = rfc2576.v2ToV1(PDU, origPdu)

        # 3.2.6
        try:
            snmpEngine.msgAndPduDsp.returnResponsePdu(
                snmpEngine,
                messageProcessingModel,
                securityModel,
                securityName,
                securityLevel,
                contextEngineId,
                contextName,
                pduVersion,
                PDU,
                maxSizeResponseScopedPDU,
                stateReference,
                statusInformation
            )

        except error.StatusInformation:
            debug.logger & debug.flagApp and debug.logger(
                'sendPdu: stateReference %s, statusInformation %s' % (stateReference, sys.exc_info()[1]))
            snmpSilentDrops, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB',
                                                                                                     'snmpSilentDrops')
            snmpSilentDrops.syntax += 1
Esempio n. 3
0
    def sendPdu(self, snmpEngine, stateReference, PDU):
        (messageProcessingModel, securityModel, securityName, securityLevel,
         contextEngineId, contextName, pduVersion, _, origPdu,
         maxSizeResponseScopedPDU,
         statusInformation) = self.__pendingReqs[stateReference]

        # Agent-side API complies with SMIv2
        if messageProcessingModel == 0:
            PDU = rfc2576.v2ToV1(PDU, origPdu)

        # 3.2.6
        try:
            snmpEngine.msgAndPduDsp.returnResponsePdu(
                snmpEngine, messageProcessingModel, securityModel,
                securityName, securityLevel, contextEngineId, contextName,
                pduVersion, PDU, maxSizeResponseScopedPDU, stateReference,
                statusInformation)

        except error.StatusInformation as exc:
            debug.logger & debug.FLAG_APP and debug.logger(
                'sendPdu: stateReference %s, statusInformation '
                '%s' % (stateReference, exc))

            snmpSilentDrops, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols(
                '__SNMPv2-MIB', 'snmpSilentDrops')

            snmpSilentDrops.syntax += 1
Esempio n. 4
0
    def sendRsp(self, snmpEngine, stateReference, errorStatus, errorIndex,
                varBinds):
        (messageProcessingModel, securityModel, securityName, securityLevel,
         contextEngineId, contextName, pduVersion, PDU, origPdu,
         maxSizeResponseScopedPDU,
         statusInformation) = self.__pendingReqs[stateReference]

        debug.logger & debug.flagApp and debug.logger(
            'sendRsp: stateReference %s, errorStatus %s, errorIndex %s, varBinds %s'
            % (stateReference, errorStatus, errorIndex, varBinds))

        v2c.apiPDU.setErrorStatus(PDU, errorStatus)
        v2c.apiPDU.setErrorIndex(PDU, errorIndex)
        v2c.apiPDU.setVarBinds(PDU, varBinds)

        # Agent-side API complies with SMIv2
        if messageProcessingModel == 0:
            PDU = rfc2576.v2ToV1(PDU, origPdu)

        # 3.2.6
        try:
            snmpEngine.msgAndPduDsp.returnResponsePdu(
                snmpEngine, messageProcessingModel, securityModel,
                securityName, securityLevel, contextEngineId, contextName,
                pduVersion, PDU, maxSizeResponseScopedPDU, stateReference,
                statusInformation)
        except error.StatusInformation:
            debug.logger & debug.flagApp and debug.logger(
                'sendRsp: stateReference %s, statusInformation %s' %
                (stateReference, sys.exc_info()[1]))
            snmpSilentDrops, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols(
                '__SNMPv2-MIB', 'snmpSilentDrops')
            snmpSilentDrops.syntax = snmpSilentDrops.syntax + 1
Esempio n. 5
0
    def sendReq(self,
                snmpEngine,
                addrName,
                varBinds,
                cbFun,
                cbCtx=None,
                contextEngineId=None,
                contextName=''):
        (transportDomain, transportAddress, timeout, retryCount,
         messageProcessingModel, securityModel, securityName,
         securityLevel) = config.getTargetInfo(snmpEngine, addrName)

        pduVersion, pMod = getVersionSpecifics(messageProcessingModel)

        reqPDU = pMod.SetRequestPDU()
        pMod.apiPDU.setDefaults(reqPDU)

        pMod.apiPDU.setVarBinds(reqPDU, varBinds)

        # User-side API assumes SMIv2
        if messageProcessingModel == 0:
            reqPDU = rfc2576.v2ToV1(reqPDU)
            pMod = api.protoModules[api.protoVersion1]

        requestHandle = getNextHandle()

        self._sendPdu(snmpEngine, transportDomain, transportAddress,
                      messageProcessingModel, securityModel, securityName,
                      securityLevel, contextEngineId, contextName, pduVersion,
                      reqPDU, timeout, retryCount, 0, requestHandle,
                      (self.processResponsePdu, (cbFun, cbCtx)))

        return requestHandle
Esempio n. 6
0
    def sendPdu(self, snmpEngine, targetName, contextEngineId,
                contextName, pdu, cbFun=None, cbCtx=None):
        (transportDomain, transportAddress, timeout,
         retryCount, params) = config.getTargetAddr(snmpEngine, targetName)

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

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

        else:
            reqPDU = pdu
            pduVersion = 1

        # 3.3.5
        if reqPDU.tagSet in rfc3411.CONFIRMED_CLASS_PDUS:
            # Convert timeout in seconds into timeout in timer ticks
            timeoutInTicks = (float(timeout) / 100 /
                              snmpEngine.transportDispatcher.getTimerResolution())

            sendRequestHandle = getNextHandle()

            # 3.3.6a
            sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
                snmpEngine, transportDomain, transportAddress,
                messageProcessingModel, securityModel, securityName,
                securityLevel, contextEngineId, contextName,
                pduVersion, reqPDU, True, timeoutInTicks,
                self.processResponsePdu, (sendRequestHandle, cbFun, cbCtx)
            )

            debug.logger & debug.FLAG_APP and debug.logger(
                'sendPdu: sendPduHandle %s, timeout %d' % (sendPduHandle, timeout))

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

            snmpEngine.transportDispatcher.jobStarted(id(self))

        else:
            snmpEngine.msgAndPduDsp.sendPdu(
                snmpEngine, transportDomain, transportAddress,
                messageProcessingModel, securityModel,
                securityName, securityLevel, contextEngineId,
                contextName, pduVersion, reqPDU, False
            )

            sendRequestHandle = None

            debug.logger & debug.FLAG_APP and debug.logger('sendPdu: message sent')

        return sendRequestHandle
Esempio n. 7
0
    def sendPdu(self, snmpEngine, targetName, contextEngineId,
                contextName, PDU, cbFun, cbCtx):
        (transportDomain, transportAddress, timeout,
         retryCount, messageProcessingModel, securityModel,
         securityName,
         securityLevel) = config.getTargetInfo(snmpEngine, targetName)

        # Convert timeout in seconds into timeout in timer ticks
        timeoutInTicks = (float(timeout) / 100 /
                          snmpEngine.transportDispatcher.getTimerResolution())

        mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder

        SnmpEngineID, SnmpAdminString = mibBuilder.importSymbols(
            'SNMP-FRAMEWORK-MIB', 'SnmpEngineID', 'SnmpAdminString')

        # Cast possible strings into bytes
        if contextEngineId:
            contextEngineId = SnmpEngineID(contextEngineId)

        contextName = SnmpAdminString(contextName)

        origPDU = PDU

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

        else:
            pduVersion = 1

        sendRequestHandle = getNextHandle()

        # 3.1
        sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
            snmpEngine, transportDomain, transportAddress,
            messageProcessingModel, securityModel, securityName,
            securityLevel, contextEngineId, contextName,
            pduVersion, PDU, True, timeoutInTicks, self.processResponsePdu,
            (sendRequestHandle, cbFun, cbCtx)
        )

        snmpEngine.transportDispatcher.jobStarted(id(self))

        self.__pendingReqs[sendPduHandle] = (
            transportDomain, transportAddress, messageProcessingModel,
            securityModel, securityName, securityLevel, contextEngineId,
            contextName, pduVersion, origPDU, timeoutInTicks,
            retryCount, 0, 0
        )

        debug.logger & debug.FLAG_APP and debug.logger(
            'sendPdu: sendPduHandle %s, timeout %d*10 ms/%d ticks, retry '
            '0 of %d' % (sendPduHandle, timeout, timeoutInTicks, retryCount))

        return sendRequestHandle
Esempio n. 8
0
    def sendPdu(self, snmpEngine, targetName, contextEngineId, contextName,
                PDU, cbFun, cbCtx):
        (transportDomain, transportAddress, timeout, retryCount,
         messageProcessingModel, securityModel, securityName,
         securityLevel) = config.getTargetInfo(snmpEngine, targetName)

        # Convert timeout in seconds into timeout in timer ticks
        timeoutInTicks = (float(timeout) / 100 /
                          snmpEngine.transportDispatcher.getTimerResolution())

        mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder

        SnmpEngineID, SnmpAdminString = mibBuilder.importSymbols(
            'SNMP-FRAMEWORK-MIB', 'SnmpEngineID', 'SnmpAdminString')

        # Cast possible strings into bytes
        if contextEngineId:
            contextEngineId = SnmpEngineID(contextEngineId)

        contextName = SnmpAdminString(contextName)

        origPDU = PDU

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

        else:
            pduVersion = 1

        sendRequestHandle = getNextHandle()

        # 3.1
        sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
            snmpEngine, transportDomain, transportAddress,
            messageProcessingModel, securityModel, securityName, securityLevel,
            contextEngineId, contextName, pduVersion, PDU, True,
            timeoutInTicks, self.processResponsePdu,
            (sendRequestHandle, cbFun, cbCtx))

        snmpEngine.transportDispatcher.jobStarted(id(self))

        self.__pendingReqs[sendPduHandle] = (transportDomain, transportAddress,
                                             messageProcessingModel,
                                             securityModel, securityName,
                                             securityLevel, contextEngineId,
                                             contextName, pduVersion, origPDU,
                                             timeoutInTicks, retryCount, 0, 0)

        debug.logger & debug.FLAG_APP and debug.logger(
            'sendPdu: sendPduHandle %s, timeout %d*10 ms/%d ticks, retry '
            '0 of %d' % (sendPduHandle, timeout, timeoutInTicks, retryCount))

        return sendRequestHandle
Esempio n. 9
0
    def sendPdu(self, snmpEngine, targetName, contextEngineId,
                contextName, pdu, cbFun=None, cbCtx=None):
        (transportDomain, transportAddress, timeout,
         retryCount, params) = config.getTargetAddr(snmpEngine, targetName)

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

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

        # 3.3.5
        if reqPDU.tagSet in rfc3411.confirmedClassPDUs:
            # Convert timeout in seconds into timeout in timer ticks
            timeoutInTicks = float(timeout) / 100 / snmpEngine.transportDispatcher.getTimerResolution()

            sendRequestHandle = getNextHandle()

            # 3.3.6a
            sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
                snmpEngine, transportDomain, transportAddress,
                messageProcessingModel, securityModel, securityName,
                securityLevel, contextEngineId, contextName,
                pduVersion, reqPDU, True, timeoutInTicks,
                self.processResponsePdu, (sendRequestHandle, cbFun, cbCtx)
            )

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

            # 3.3.6b
            self.__pendingReqs[sendPduHandle] = (
                transportDomain, transportAddress, messageProcessingModel,
                securityModel, securityName, securityLevel, contextEngineId,
                contextName, pdu, timeout, retryCount, True
            )
            snmpEngine.transportDispatcher.jobStarted(id(self))
        else:
            snmpEngine.msgAndPduDsp.sendPdu(
                snmpEngine, transportDomain, transportAddress,
                messageProcessingModel, securityModel,
                securityName, securityLevel, contextEngineId,
                contextName, pduVersion, reqPDU, False
            )

            sendRequestHandle = None

            debug.logger & debug.flagApp and debug.logger('sendPdu: message sent')

        return sendRequestHandle
Esempio n. 10
0
    def sendReq(
        self,
        snmpEngine,
        addrName,
        varBinds,
        cbFun,
        cbCtx=None,
        contextEngineId=None,
        contextName=''
        ):
        ( transportDomain,
          transportAddress,
          timeout,
          retryCount,
          messageProcessingModel,
          securityModel,
          securityName,
          securityLevel ) = config.getTargetInfo(snmpEngine, addrName)

        pduVersion, pMod = getVersionSpecifics(messageProcessingModel)
        
        reqPDU = pMod.SetRequestPDU()
        pMod.apiPDU.setDefaults(reqPDU)

        pMod.apiPDU.setVarBinds(reqPDU, varBinds)

        # User-side API assumes SMIv2
        if messageProcessingModel == 0:
            reqPDU = rfc2576.v2ToV1(reqPDU)
            pMod = api.protoModules[api.protoVersion1]

        requestHandle = getNextHandle()        
        
        self._sendPdu(
            snmpEngine,
            transportDomain,
            transportAddress,
            messageProcessingModel,
            securityModel,
            securityName,
            securityLevel,
            contextEngineId,
            contextName,
            pduVersion,
            reqPDU,
            timeout,
            retryCount,
            0,
            requestHandle,
            (self.processResponsePdu, (cbFun, cbCtx))            
            )

        return requestHandle
Esempio n. 11
0
    def __sendResponse(self, snmpEngine, errorStatus, errorIndex,
                       varBinds, stateReference):
        ( messageProcessingModel,
          securityModel,
          securityName,
          securityLevel,
          contextEngineId,
          contextName,
          pduVersion,
          PDU,
          maxSizeResponseScopedPDU,
          statusInformation ) = self.__pendingReqs[stateReference]

        del self.__pendingReqs[stateReference]

        v2c.apiPDU.setErrorStatus(PDU, errorStatus)
        v2c.apiPDU.setErrorIndex(PDU, errorIndex)
        v2c.apiPDU.setVarBinds(PDU, varBinds)

        # Agent-side API complies with SMIv2
        if messageProcessingModel == 0:
            PDU = rfc2576.v2ToV1(PDU)
        
        # 3.2.6
        try:
            snmpEngine.msgAndPduDsp.returnResponsePdu(
                snmpEngine,
                messageProcessingModel,
                securityModel,
                securityName,
                securityLevel,
                contextEngineId,
                contextName,
                pduVersion,
                PDU,
                maxSizeResponseScopedPDU,
                stateReference,
                statusInformation
                )
        except error.StatusInformation:
            snmpSilentDrops, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpSilentDrops')
            snmpSilentDrops.syntax = snmpSilentDrops.syntax + 1
Esempio n. 12
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
Esempio n. 13
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)
Esempio n. 14
0
    def processPdu(self, snmpEngine, messageProcessingModel,
                   securityModel, securityName, securityLevel,
                   contextEngineId, contextName, pduVersion, PDU,
                   maxSizeResponseScopedPDU, stateReference):

        # Agent-side API complies with SMIv2
        if messageProcessingModel == 0:
            origPdu = PDU
            PDU = rfc2576.v1ToV2(PDU)
        else:
            origPdu = None

        errorStatus = 'noError'
        errorIndex = 0
        varBinds = v2c.apiPDU.getVarBinds(PDU)

        debug.logger & debug.flagApp and debug.logger(
            'processPdu: stateReference %s, varBinds %s' % (stateReference, varBinds))

        # 3.4
        if PDU.tagSet in rfc3411.confirmedClassPDUs:
            # 3.4.1 --> no-op

            rspPDU = v2c.apiPDU.getResponse(PDU)

            # 3.4.2
            v2c.apiPDU.setErrorStatus(rspPDU, errorStatus)
            v2c.apiPDU.setErrorIndex(rspPDU, errorIndex)
            v2c.apiPDU.setVarBinds(rspPDU, varBinds)

            debug.logger & debug.flagApp and debug.logger(
                'processPdu: stateReference %s, confirm PDU %s' % (stateReference, rspPDU.prettyPrint()))

            # Agent-side API complies with SMIv2
            if messageProcessingModel == 0:
                rspPDU = rfc2576.v2ToV1(rspPDU, origPdu)

            statusInformation = {}

            # 3.4.3
            try:
                snmpEngine.msgAndPduDsp.returnResponsePdu(
                    snmpEngine, messageProcessingModel, securityModel,
                    securityName, securityLevel, contextEngineId,
                    contextName, pduVersion, rspPDU, maxSizeResponseScopedPDU,
                    stateReference, statusInformation)

            except error.StatusInformation:
                debug.logger & debug.flagApp and debug.logger(
                    'processPdu: stateReference %s, statusInformation %s' % (stateReference, sys.exc_info()[1]))
                snmpSilentDrops, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB',
                                                                                                         'snmpSilentDrops')
                snmpSilentDrops.syntax += 1

        elif PDU.tagSet in rfc3411.unconfirmedClassPDUs:
            pass
        else:
            raise error.ProtocolError('Unexpected PDU class %s' % PDU.tagSet)

        debug.logger & debug.flagApp and debug.logger(
            'processPdu: stateReference %s, user cbFun %s, cbCtx %s, varBinds %s' % (
                stateReference, self.__cbFun, self.__cbCtx, varBinds))

        if self.__cbFunVer:
            self.__cbFun(snmpEngine, stateReference, contextEngineId,
                         contextName, varBinds, self.__cbCtx)
        else:
            # Compatibility stub (handle legacy cbFun interface)
            try:
                self.__cbFun(snmpEngine, contextEngineId, contextName,
                             varBinds, self.__cbCtx)
            except TypeError:
                self.__cbFunVer = 1
                self.__cbFun(snmpEngine, stateReference, contextEngineId,
                             contextName, varBinds, self.__cbCtx)
Esempio n. 15
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
Esempio n. 16
0
    def processResponsePdu(self, snmpEngine, messageProcessingModel,
                           securityModel, securityName, securityLevel,
                           contextEngineId, contextName, pduVersion, PDU,
                           statusInformation, sendPduHandle, cbInfo):

        sendRequestHandle, cbFun, cbCtx = cbInfo

        # 3.3.6d
        if sendPduHandle not in self.__pendingReqs:
            raise error.ProtocolError('Missing sendPduHandle %s' %
                                      sendPduHandle)

        (origTransportDomain, origTransportAddress, origMessageProcessingModel,
         origSecurityModel, origSecurityName, origSecurityLevel,
         origContextEngineId, origContextName, origPdu, origTimeout,
         origRetryCount, origRetries,
         origDiscoveryRetries) = self.__pendingReqs.pop(sendPduHandle)

        snmpEngine.transportDispatcher.jobFinished(id(self))

        if statusInformation:
            debug.logger & debug.FLAG_APP and debug.logger(
                'processResponsePdu: sendRequestHandle %s, sendPduHandle %s '
                'statusInformation %s' %
                (sendRequestHandle, sendPduHandle, statusInformation))

            errorIndication = statusInformation['errorIndication']

            if errorIndication in (errind.notInTimeWindow,
                                   errind.unknownEngineID):
                origDiscoveryRetries += 1
                origRetries = 0

            else:
                origDiscoveryRetries = 0
                origRetries += 1

            if (origRetries > origRetryCount
                    or origDiscoveryRetries > self.__options.get(
                        'discoveryRetries', 4)):

                debug.logger & debug.FLAG_APP and debug.logger(
                    'processResponsePdu: sendRequestHandle %s, sendPduHandle %s '
                    'retry count %d exceeded' %
                    (sendRequestHandle, sendPduHandle, origRetries))

                cbFun(snmpEngine, sendRequestHandle, errorIndication, None,
                      cbCtx)

                return

            # Convert timeout in seconds into timeout in timer ticks
            timeoutInTicks = (
                float(origTimeout) / 100 /
                snmpEngine.transportDispatcher.getTimerResolution())

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

            else:
                reqPDU = origPdu
                pduVersion = 1

            # 3.3.6a
            try:
                sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
                    snmpEngine, origTransportDomain, origTransportAddress,
                    origMessageProcessingModel, origSecurityModel,
                    origSecurityName, origSecurityLevel, origContextEngineId,
                    origContextName, pduVersion, reqPDU, True, timeoutInTicks,
                    self.processResponsePdu, (sendRequestHandle, cbFun, cbCtx))

            except error.StatusInformation as exc:
                statusInformation = exc

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

                cbFun(snmpEngine, sendRequestHandle,
                      statusInformation['errorIndication'], None, cbCtx)

                return

            snmpEngine.transportDispatcher.jobStarted(id(self))

            debug.logger & debug.FLAG_APP and debug.logger(
                'processResponsePdu: sendRequestHandle %s, sendPduHandle %s, '
                'timeout %d, retry %d of %d' %
                (sendRequestHandle, sendPduHandle, origTimeout, origRetries,
                 origRetryCount))

            # 3.3.6b
            self.__pendingReqs[sendPduHandle] = (
                origTransportDomain, origTransportAddress,
                origMessageProcessingModel, origSecurityModel,
                origSecurityName, origSecurityLevel, origContextEngineId,
                origContextName, origPdu, origTimeout, origRetryCount,
                origRetries, origDiscoveryRetries)

            return

        # 3.3.6c
        # User-side API assumes SMIv2
        if messageProcessingModel == 0:
            PDU = rfc2576.v1ToV2(PDU, origPdu)

        cbFun(snmpEngine, sendRequestHandle, None, PDU, cbCtx)
Esempio n. 17
0
    def processPdu(self, snmpEngine, messageProcessingModel,
                   securityModel, securityName, securityLevel,
                   contextEngineId, contextName, pduVersion, PDU,
                   maxSizeResponseScopedPDU, stateReference):

        # Agent-side API complies with SMIv2
        if messageProcessingModel == 0:
            origPdu = PDU
            PDU = rfc2576.v1ToV2(PDU, snmpTrapCommunity=self.__snmpTrapCommunity)
        else:
            origPdu = None

        errorStatus = 'noError'
        errorIndex = 0
        varBinds = v2c.apiPDU.getVarBinds(PDU)

        debug.logger & debug.flagApp and debug.logger(
            'processPdu: stateReference %s, varBinds %s' % (stateReference, varBinds))

        # 3.4
        if PDU.tagSet in rfc3411.confirmedClassPDUs:
            # 3.4.1 --> no-op

            rspPDU = v2c.apiPDU.getResponse(PDU)

            # 3.4.2
            v2c.apiPDU.setErrorStatus(rspPDU, errorStatus)
            v2c.apiPDU.setErrorIndex(rspPDU, errorIndex)
            v2c.apiPDU.setVarBinds(rspPDU, varBinds)

            debug.logger & debug.flagApp and debug.logger(
                'processPdu: stateReference %s, confirm PDU %s' % (stateReference, rspPDU.prettyPrint()))

            # Agent-side API complies with SMIv2
            if messageProcessingModel == 0:
                rspPDU = rfc2576.v2ToV1(rspPDU, origPdu)

            statusInformation = {}

            # 3.4.3
            try:
                snmpEngine.msgAndPduDsp.returnResponsePdu(
                    snmpEngine, messageProcessingModel, securityModel,
                    securityName, securityLevel, contextEngineId,
                    contextName, pduVersion, rspPDU, maxSizeResponseScopedPDU,
                    stateReference, statusInformation)

            except error.StatusInformation:
                debug.logger & debug.flagApp and debug.logger(
                    'processPdu: stateReference %s, statusInformation %s' % (stateReference, sys.exc_info()[1]))
                snmpSilentDrops, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB',
                                                                                                         'snmpSilentDrops')
                snmpSilentDrops.syntax += 1

        elif PDU.tagSet in rfc3411.unconfirmedClassPDUs:
            pass
        else:
            raise error.ProtocolError('Unexpected PDU class %s' % PDU.tagSet)

        debug.logger & debug.flagApp and debug.logger(
            'processPdu: stateReference %s, user cbFun %s, cbCtx %s, varBinds %s' % (
                stateReference, self.__cbFun, self.__cbCtx, varBinds))

        self.__cbFun(snmpEngine, stateReference, contextEngineId,
                     contextName, varBinds, self.__cbCtx)
Esempio n. 18
0
    def processResponsePdu(self, snmpEngine, messageProcessingModel,
                           securityModel, securityName, securityLevel,
                           contextEngineId, contextName, pduVersion,
                           PDU, statusInformation, sendPduHandle, cbCtx):
        origSendRequestHandle, cbFun, cbCtx = cbCtx

        # 3.1.1
        if sendPduHandle not in self.__pendingReqs:
            raise error.PySnmpError('Missing sendPduHandle %s' % sendPduHandle)

        (origTransportDomain, origTransportAddress,
         origMessageProcessingModel, origSecurityModel,
         origSecurityName, origSecurityLevel, origContextEngineId,
         origContextName, origPduVersion, origPdu,
         origTimeout, origRetryCount,
         origRetries, origDiscoveryRetries) = self.__pendingReqs.pop(sendPduHandle)

        snmpEngine.transportDispatcher.jobFinished(id(self))

        # 3.1.3
        if statusInformation:
            debug.logger & debug.FLAG_APP and debug.logger(
                'processResponsePdu: sendPduHandle %s, statusInformation '
                '%s' % (sendPduHandle, statusInformation))

            errorIndication = statusInformation['errorIndication']

            if errorIndication in (errind.notInTimeWindow, errind.unknownEngineID):
                origDiscoveryRetries += 1
                origRetries = 0
            else:
                origDiscoveryRetries = 0
                origRetries += 1

            if (origRetries > origRetryCount or
                    origDiscoveryRetries > self.__options.get('discoveryRetries', 4)):

                debug.logger & debug.FLAG_APP and debug.logger(
                    'processResponsePdu: sendPduHandle %s, retry count %d '
                    'exceeded' % (sendPduHandle, origRetries))

                cbFun(snmpEngine, origSendRequestHandle,
                      errorIndication, None, cbCtx)
                return

            # User-side API assumes SMIv2
            if origMessageProcessingModel == 0:
                reqPDU = rfc2576.v2ToV1(origPdu)
                pduVersion = 0

            else:
                reqPDU = origPdu
                pduVersion = 1

            try:
                sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
                    snmpEngine, origTransportDomain, origTransportAddress,
                    origMessageProcessingModel, origSecurityModel,
                    origSecurityName, origSecurityLevel, origContextEngineId,
                    origContextName, pduVersion, reqPDU,
                    True, origTimeout, self.processResponsePdu,
                    (origSendRequestHandle, cbFun, cbCtx))

                snmpEngine.transportDispatcher.jobStarted(id(self))

                self.__pendingReqs[sendPduHandle] = (
                    origTransportDomain, origTransportAddress,
                    origMessageProcessingModel, origSecurityModel,
                    origSecurityName, origSecurityLevel, origContextEngineId,
                    origContextName, origPduVersion, origPdu, origTimeout,
                    origRetryCount, origRetries, origDiscoveryRetries
                )

                return

            except StatusInformation as exc:
                statusInformation = exc

                debug.logger & debug.FLAG_APP and debug.logger(
                    'processResponsePdu: origSendRequestHandle %s, _sendPdu() '
                    'failed with %r' % (sendPduHandle, statusInformation))

                cbFun(snmpEngine, origSendRequestHandle,
                      statusInformation['errorIndication'],
                      None, cbCtx)

                return

        if (origMessageProcessingModel != messageProcessingModel or
                origSecurityModel != securityModel or
                origSecurityName != origSecurityName or
                origContextEngineId and origContextEngineId != contextEngineId or
                origContextName and origContextName != contextName or
                origPduVersion != pduVersion):

            debug.logger & debug.FLAG_APP and debug.logger(
                'processResponsePdu: sendPduHandle %s, request/response '
                'data mismatch' % sendPduHandle)

            cbFun(snmpEngine, origSendRequestHandle,
                  'badResponse', None, cbCtx)

            return

        # User-side API assumes SMIv2
        if messageProcessingModel == 0:
            PDU = rfc2576.v1ToV2(PDU, origPdu)

        # 3.1.2
        if v2c.apiPDU.getRequestID(PDU) != v2c.apiPDU.getRequestID(origPdu):
            debug.logger & debug.FLAG_APP and debug.logger(
                'processResponsePdu: sendPduHandle %s, request-id/response-id '
                'mismatch' % sendPduHandle)

            cbFun(snmpEngine, origSendRequestHandle,
                  'badResponse', None, cbCtx)

            return

        cbFun(snmpEngine, origSendRequestHandle, None, PDU, cbCtx)
Esempio n. 19
0
    def processResponsePdu(self, snmpEngine, messageProcessingModel,
                           securityModel, securityName, securityLevel,
                           contextEngineId, contextName, pduVersion,
                           PDU, statusInformation, sendPduHandle, cbInfo):

        sendRequestHandle, cbFun, cbCtx = cbInfo

        # 3.3.6d
        if sendPduHandle not in self.__pendingReqs:
            raise error.ProtocolError('Missing sendPduHandle %s' % sendPduHandle)

        (origTransportDomain, origTransportAddress,
         origMessageProcessingModel, origSecurityModel,
         origSecurityName, origSecurityLevel, origContextEngineId,
         origContextName, origPdu, origTimeout,
         origRetryCount, origRetries,
         origDiscoveryRetries) = self.__pendingReqs.pop(sendPduHandle)

        snmpEngine.transportDispatcher.jobFinished(id(self))

        if statusInformation:
            debug.logger & debug.FLAG_APP and debug.logger(
                'processResponsePdu: sendRequestHandle %s, sendPduHandle %s '
                'statusInformation %s' % (sendRequestHandle, sendPduHandle,
                                          statusInformation))

            errorIndication = statusInformation['errorIndication']

            if errorIndication in (errind.notInTimeWindow, errind.unknownEngineID):
                origDiscoveryRetries += 1
                origRetries = 0

            else:
                origDiscoveryRetries = 0
                origRetries += 1

            if (origRetries > origRetryCount or
                    origDiscoveryRetries > self.__options.get('discoveryRetries', 4)):

                debug.logger & debug.FLAG_APP and debug.logger(
                    'processResponsePdu: sendRequestHandle %s, sendPduHandle %s '
                    'retry count %d exceeded' % (
                        sendRequestHandle, sendPduHandle, origRetries))

                cbFun(snmpEngine, sendRequestHandle, errorIndication, None, cbCtx)

                return

            # Convert timeout in seconds into timeout in timer ticks
            timeoutInTicks = (float(origTimeout) / 100 /
                              snmpEngine.transportDispatcher.getTimerResolution())

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

            else:
                reqPDU = origPdu
                pduVersion = 1

            # 3.3.6a
            try:
                sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
                    snmpEngine, origTransportDomain, origTransportAddress,
                    origMessageProcessingModel, origSecurityModel,
                    origSecurityName, origSecurityLevel,
                    origContextEngineId, origContextName, pduVersion,
                    reqPDU, True, timeoutInTicks, self.processResponsePdu,
                    (sendRequestHandle, cbFun, cbCtx)
                )

            except error.StatusInformation as exc:
                statusInformation = exc

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

                cbFun(snmpEngine, sendRequestHandle,
                      statusInformation['errorIndication'], None, cbCtx)

                return

            snmpEngine.transportDispatcher.jobStarted(id(self))

            debug.logger & debug.FLAG_APP and debug.logger(
                'processResponsePdu: sendRequestHandle %s, sendPduHandle %s, '
                'timeout %d, retry %d of %d' % (
                    sendRequestHandle, sendPduHandle, origTimeout, origRetries,
                    origRetryCount))

            # 3.3.6b
            self.__pendingReqs[sendPduHandle] = (
                origTransportDomain, origTransportAddress,
                origMessageProcessingModel, origSecurityModel,
                origSecurityName, origSecurityLevel,
                origContextEngineId, origContextName, origPdu,
                origTimeout, origRetryCount, origRetries, origDiscoveryRetries
            )

            return

        # 3.3.6c
        # User-side API assumes SMIv2
        if messageProcessingModel == 0:
            PDU = rfc2576.v1ToV2(PDU, origPdu)

        cbFun(snmpEngine, sendRequestHandle, None, PDU, cbCtx)
Esempio n. 20
0
    def processPdu(
        self,
        snmpEngine,
        messageProcessingModel,
        securityModel,
        securityName,
        securityLevel,
        contextEngineId,
        contextName,
        pduVersion,
        PDU,
        maxSizeResponseScopedPDU,
        stateReference
        ):

        # Agent-side API complies with SMIv2
        if messageProcessingModel == 0:
            PDU = rfc2576.v1ToV2(PDU)

        errorStatus = 'noError'; errorIndex = 0
        varBinds = v2c.apiPDU.getVarBinds(PDU)
        
        # 3.4
        if rfc3411.confirmedClassPDUs.has_key(PDU.tagSet):
            # 3.4.1 --> no-op
            
            rspPDU = v2c.apiPDU.getResponse(PDU)
            
            # 3.4.2
            v2c.apiPDU.setErrorStatus(rspPDU, errorStatus)
            v2c.apiPDU.setErrorIndex(rspPDU, errorIndex)
            v2c.apiPDU.setVarBinds(rspPDU, varBinds)

            # Agent-side API complies with SMIv2
            if messageProcessingModel == 0:
                rspPDU = rfc2576.v2ToV1(rspPDU)

            statusInformation = {}
            
            # 3.4.3
            try:
                snmpEngine.msgAndPduDsp.returnResponsePdu(
                    snmpEngine,
                    messageProcessingModel,
                    securityModel,
                    securityName,
                    securityLevel,
                    contextEngineId,
                    contextName,
                    pduVersion,
                    rspPDU,
                    maxSizeResponseScopedPDU,
                    stateReference,
                    statusInformation
                    )
            except error.StatusInformation:
                snmpSilentDrops, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpSilentDrops')
                snmpSilentDrops.syntax = snmpSilentDrops.syntax + 1

        elif rfc3411.unconfirmedClassPDUs.has_key(PDU.tagSet):
            pass
        else:
            raise error.ProtocolError('Unexpected PDU class %s' % PDU.tagSet)

        if self.__cbFunVer:
            self.__cbFun(
                snmpEngine, stateReference, contextEngineId, contextName,
                varBinds, self.__cbCtx
                )
        else:
            # Compatibility stub (handle legacy cbFun interface)
            try:
                self.__cbFun(
                    snmpEngine, contextEngineId, contextName,
                    varBinds, self.__cbCtx
                    )
            except TypeError:
                self.__cbFunVer = 1
                self.__cbFun(
                    snmpEngine, stateReference, contextEngineId, contextName,
                    varBinds, self.__cbCtx
                    )
Esempio n. 21
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
    def _sendPdu(
        self,
        snmpEngine,
        transportDomain,
        transportAddress,
        messageProcessingModel,
        securityModel,
        securityName,
        securityLevel,
        contextEngineId,
        contextName,
        reqPDU,
        timeout,
        retryCount,
        retries,
        sendRequestHandle,
        cbInfo
        ):
        (processResponsePdu, cbCtx) = cbInfo

        # Convert timeout in seconds into timeout in timer ticks
        timeoutInTicks = float(timeout)/100/snmpEngine.transportDispatcher.getTimerResolution()

        if not self.__SnmpEngineID or not self.__SnmpAdminString:
            self.__SnmpEngineID, self.__SnmpAdminString = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('SNMP-FRAMEWORK-MIB', 'SnmpEngineID', 'SnmpAdminString')

        # Cast possible strings into bytes
        if contextEngineId:
            contextEngineId = self.__SnmpEngineID(contextEngineId)
        contextName = self.__SnmpAdminString(contextName)

        origPDU = reqPDU

        # User-side API assumes SMIv2
        if messageProcessingModel == 0:
            reqPDU = rfc2576.v2ToV1(reqPDU)
            pduVersion = 0
        else:
            pduVersion = 1
 
        # 3.1
        sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
            snmpEngine,
            transportDomain,
            transportAddress,
            messageProcessingModel,
            securityModel,
            securityName,
            securityLevel,
            contextEngineId,
            contextName,
            pduVersion,
            reqPDU,
            1, # expectResponse
            timeoutInTicks,
            processResponsePdu,
            cbCtx
        )

        snmpEngine.transportDispatcher.jobStarted(id(self))

        self.__pendingReqs[sendPduHandle] = (
            transportDomain,
            transportAddress,
            messageProcessingModel,
            securityModel,
            securityName,
            securityLevel,
            contextEngineId,
            contextName,
            pduVersion,
            origPDU,
            timeout,
            retryCount,
            retries,
            sendRequestHandle
        )
 
        debug.logger & debug.flagApp and debug.logger('_sendPdu: sendPduHandle %s, timeout %d*10 ms/%d ticks, retry %d of %d' % (sendPduHandle, timeout, timeoutInTicks, retries, retryCount))
Esempio n. 23
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
Esempio n. 24
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.

        SNMP Notification PDU places rigid requirement on the ordering of
        the variable-bindings.

        Mandatory variable-bindings:

        0. SNMPv2-MIB::sysUpTime.0 = <agent uptime>
        1. SNMPv2-SMI::snmpTrapOID.0 = {SNMPv2-MIB::coldStart, ...}

        Optional variable-bindings (applicable to SNMP v1 TRAP):

        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>

        Informational variable-bindings:

        * SNMPv2-SMI::NOTIFICATION-TYPE
        * SNMPv2-SMI::OBJECT-TYPE

    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()
    """
    def _cbFun(snmpDispatcher, stateHandle, errorIndication, rspPdu, _cbCtx):
        if not cbFun:
            return

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

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

        varBinds = pMod.apiTrapPDU.getVarBinds(rspPdu)

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

        nextStateHandle = pMod.getNextRequestID()

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

        if not nextVarBinds:
            return

        pMod.apiTrapPDU.setRequestID(reqPdu, nextStateHandle)
        pMod.apiTrapPDU.setVarBinds(reqPdu, nextVarBinds)

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

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

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

    # # make sure required PDU payload is in place
    # completeVarBinds = []
    #
    # # ensure sysUpTime
    # if len(varBinds) < 1 or varBinds[0][0] != pMod.apiTrapPDU.sysUpTime:
    #     varBinds.insert(0, (ObjectIdentifier(pMod.apiTrapPDU.sysUpTime), pMod.Integer(0)))
    #
    # # ensure sysUpTime
    # if len(varBinds) < 1 or varBinds[0][0] != pMod.apiTrapPDU.sysUpTime:
    #     varBinds.insert(0, (ObjectIdentifier(pMod.apiTrapPDU.sysUpTime), pMod.Integer(0)))
    #
    # # ensure snmpTrapOID
    # if len(varBinds) < 2 or varBinds[1][0] != pMod.apiTrapPDU.snmpTrapOID:
    #     varBinds.insert(0, (ObjectIdentifier(pMod.apiTrapPDU.sysUpTime), pMod.Integer(0)))

    # input PDU is always v2c
    pMod = api.protoModules[api.protoVersion2c]

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

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

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

    return snmpDispatcher.sendPdu(authData,
                                  transportTarget,
                                  reqPdu,
                                  cbFun=_cbFun)
    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 not self.__pendingNotifications[metaSendPduHandle]:
                        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 not self.__pendingNotifications[metaSendPduHandle]:
                        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
Esempio n. 26
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))
Esempio n. 27
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
Esempio n. 28
0
    def processResponsePdu(self, snmpEngine, messageProcessingModel,
                           securityModel, securityName, securityLevel,
                           contextEngineId, contextName, pduVersion, PDU,
                           statusInformation, sendPduHandle, cbCtx):
        origSendRequestHandle, cbFun, cbCtx = cbCtx

        # 3.1.1
        if sendPduHandle not in self.__pendingReqs:
            raise error.PySnmpError('Missing sendPduHandle %s' % sendPduHandle)

        (origTransportDomain, origTransportAddress, origMessageProcessingModel,
         origSecurityModel, origSecurityName, origSecurityLevel,
         origContextEngineId, origContextName, origPduVersion, origPdu,
         origTimeout, origRetryCount, origRetries,
         origDiscoveryRetries) = self.__pendingReqs.pop(sendPduHandle)

        snmpEngine.transportDispatcher.jobFinished(id(self))

        # 3.1.3
        if statusInformation:
            debug.logger & debug.flagApp and debug.logger(
                'processResponsePdu: sendPduHandle %s, statusInformation %s' %
                (sendPduHandle, statusInformation))

            errorIndication = statusInformation['errorIndication']

            if errorIndication in (errind.notInTimeWindow,
                                   errind.unknownEngineID):
                origDiscoveryRetries += 1
                origRetries = 0
            else:
                origDiscoveryRetries = 0
                origRetries += 1

            if origRetries > origRetryCount or origDiscoveryRetries > self.__options.get(
                    'discoveryRetries', 4):
                debug.logger & debug.flagApp and debug.logger(
                    'processResponsePdu: sendPduHandle %s, retry count %d exceeded'
                    % (sendPduHandle, origRetries))
                cbFun(snmpEngine, origSendRequestHandle, errorIndication, None,
                      cbCtx)
                return

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

            try:
                sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
                    snmpEngine, origTransportDomain, origTransportAddress,
                    origMessageProcessingModel, origSecurityModel,
                    origSecurityName, origSecurityLevel, origContextEngineId,
                    origContextName, pduVersion, reqPDU, True, origTimeout,
                    self.processResponsePdu,
                    (origSendRequestHandle, cbFun, cbCtx))

                snmpEngine.transportDispatcher.jobStarted(id(self))

                self.__pendingReqs[sendPduHandle] = (
                    origTransportDomain, origTransportAddress,
                    origMessageProcessingModel, origSecurityModel,
                    origSecurityName, origSecurityLevel, origContextEngineId,
                    origContextName, origPduVersion, origPdu, origTimeout,
                    origRetryCount, origRetries, origDiscoveryRetries)
                return

            except StatusInformation:
                statusInformation = sys.exc_info()[1]
                debug.logger & debug.flagApp and debug.logger(
                    'processResponsePdu: origSendRequestHandle %s, _sendPdu() failed with %r'
                    % (sendPduHandle, statusInformation))
                cbFun(snmpEngine, origSendRequestHandle,
                      statusInformation['errorIndication'], None, cbCtx)
                return

        if (origMessageProcessingModel != messageProcessingModel
                or origSecurityModel != securityModel
                or origSecurityName != origSecurityName or origContextEngineId
                and origContextEngineId != contextEngineId
                or origContextName and origContextName != contextName
                or origPduVersion != pduVersion):
            debug.logger & debug.flagApp and debug.logger(
                'processResponsePdu: sendPduHandle %s, request/response data mismatch'
                % sendPduHandle)

            cbFun(snmpEngine, origSendRequestHandle, 'badResponse', None,
                  cbCtx)
            return

        # User-side API assumes SMIv2
        if messageProcessingModel == 0:
            PDU = rfc2576.v1ToV2(PDU, origPdu)

        # 3.1.2
        if v2c.apiPDU.getRequestID(PDU) != v2c.apiPDU.getRequestID(origPdu):
            debug.logger & debug.flagApp and debug.logger(
                'processResponsePdu: sendPduHandle %s, request-id/response-id mismatch'
                % sendPduHandle)
            cbFun(snmpEngine, origSendRequestHandle, 'badResponse', None,
                  cbCtx)
            return

        cbFun(snmpEngine, origSendRequestHandle, None, PDU, cbCtx)
Esempio n. 29
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
Esempio n. 30
0
    def processResponsePdu(self,
                           snmpEngine,
                           messageProcessingModel,
                           securityModel,
                           securityName,
                           securityLevel,
                           contextEngineId,
                           contextName,
                           pduVersion,
                           PDU,
                           statusInformation,
                           sendPduHandle,
                           cbInfo):
        sendRequestHandle, cbFun, cbCtx = cbInfo

        # 3.3.6d
        if sendPduHandle not in self.__pendingReqs:
            raise error.ProtocolError('Missing sendPduHandle %s' % sendPduHandle)

        ( origTransportDomain,
          origTransportAddress,
          origMessageProcessingModel,
          origSecurityModel,
          origSecurityName,
          origSecurityLevel,
          origContextEngineId,
          origContextName,
          origPdu,
          origTimeout,
          origRetryCount,
          origRetries ) = self.__pendingReqs.pop(sendPduHandle)

        snmpEngine.transportDispatcher.jobFinished(id(self))

        if statusInformation:
            debug.logger & debug.flagApp and debug.logger('processResponsePdu: sendRequestHandle %s, sendPduHandle %s statusInformation %s' % (sendRequestHandle, sendPduHandle, statusInformation))
            if origRetries == origRetryCount:
                debug.logger & debug.flagApp and debug.logger('processResponsePdu: sendRequestHandle %s, sendPduHandle %s retry count %d exceeded' % (sendRequestHandle, sendPduHandle, origRetries))
                cbFun(snmpEngine,
                      sendRequestHandle,
                      statusInformation['errorIndication'],
                      None,
                      cbCtx)
                return

            # Convert timeout in seconds into timeout in timer ticks
            timeoutInTicks = float(origTimeout)/100/snmpEngine.transportDispatcher.getTimerResolution()

            # User-side API assumes SMIv2
            if messageProcessingModel == 0:
                reqPDU = rfc2576.v2ToV1(origPdu)
                pduVersion = 0
            else:
                reqPDU = origPdu
                pduVersion = 1
 
            # 3.3.6a
            try:
                sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu(
                    snmpEngine,
                    origTransportDomain,
                    origTransportAddress,
                    origMessageProcessingModel,
                    origSecurityModel,
                    origSecurityName,
                    origSecurityLevel,
                    origContextEngineId,
                    origContextName,
                    pduVersion,
                    reqPDU,
                    1,                              # expectResponse
                    timeoutInTicks,
                    self.processResponsePdu,
                    (sendRequestHandle, cbFun, cbCtx)
                )
            except error.StatusInformation:
                statusInformation = sys.exc_info()[1]
                debug.logger & debug.flagApp and debug.logger('processResponsePdu: sendRequestHandle %s: sendPdu() failed with %r ' % (sendRequestHandle, statusInformation))
                cbFun(snmpEngine,
                      sendRequestHandle,
                      statusInformation['errorIndication'],
                      None,
                      cbCtx)
                return

            snmpEngine.transportDispatcher.jobStarted(id(self))

            debug.logger & debug.flagApp and debug.logger('processResponsePdu: sendRequestHandle %s, sendPduHandle %s, timeout %d, retry %d of %d' % (sendRequestHandle, sendPduHandle, origTimeout, origRetries, origRetryCount))
        
            # 3.3.6b
            self.__pendingReqs[sendPduHandle] = (
                origTransportDomain,
                origTransportAddress,
                origMessageProcessingModel,
                origSecurityModel,
                origSecurityName,
                origSecurityLevel,
                origContextEngineId,
                origContextName,
                origPdu,
                origTimeout,
                origRetryCount,
                origRetries + 1
            )
            return

        # 3.3.6c
        # User-side API assumes SMIv2
        if messageProcessingModel == 0:
            PDU = rfc2576.v1ToV2(PDU, origPdu)

        cbFun(snmpEngine, sendRequestHandle, None, PDU, cbCtx)
Esempio n. 31
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)