Beispiel #1
0
    def sendVarBinds(self,
                     snmpEngine,
                     notificationTarget,
                     contextEngineId,
                     contextName,
                     varBinds=(),
                     cbFun=None,
                     cbCtx=None):
        debug.logger & debug.FLAG_APP and debug.logger(
            'sendVarBinds: notificationTarget %s, contextEngineId %s, '
            'contextName "%s", varBinds %s' %
            (notificationTarget, contextEngineId
             or '<default>', contextName, varBinds))

        mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder

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

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

        notificationHandle = getNextHandle()

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

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

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

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

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

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

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

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

                else:
                    varBinds.insert(1, varBind)
                break

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

        sendRequestHandle = -1

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            except error.StatusInformation as exc:
                statusInformation = exc

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

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

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

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

                return notificationHandle

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

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

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

        return notificationHandle
Beispiel #2
0
    def sendPdu(self, snmpEngine, transportDomain, transportAddress,
                messageProcessingModel, securityModel, securityName,
                securityLevel, contextEngineId, contextName,
                pduVersion, PDU, expectResponse, timeout=0,
                cbFun=None, cbCtx=None):
        """PDU dispatcher -- prepare and serialize a request or notification"""
        # 4.1.1.2
        k = int(messageProcessingModel)
        if k in snmpEngine.messageProcessingSubsystems:
            mpHandler = snmpEngine.messageProcessingSubsystems[k]
        else:
            raise error.StatusInformation(
                errorIndication=errind.unsupportedMsgProcessingModel
            )

        debug.logger & debug.flagDsp and debug.logger(
            'sendPdu: securityName %s, PDU\n%s' % (securityName, PDU.prettyPrint()))

        # 4.1.1.3
        sendPduHandle = self.__sendPduHandle()
        if expectResponse:
            self.__cache.add(
                sendPduHandle,
                messageProcessingModel=messageProcessingModel,
                sendPduHandle=sendPduHandle,
                timeout=timeout + snmpEngine.transportDispatcher.getTimerTicks(),
                cbFun=cbFun,
                cbCtx=cbCtx
            )

            debug.logger & debug.flagDsp and debug.logger('sendPdu: current time %d ticks, one tick is %s seconds' % (
                snmpEngine.transportDispatcher.getTimerTicks(), snmpEngine.transportDispatcher.getTimerResolution()))

        debug.logger & debug.flagDsp and debug.logger(
            'sendPdu: new sendPduHandle %s, timeout %s ticks, cbFun %s' % (sendPduHandle, timeout, cbFun))

        origTransportDomain = transportDomain
        origTransportAddress = transportAddress

        # 4.1.1.4 & 4.1.1.5
        try:
            (transportDomain,
             transportAddress,
             outgoingMessage) = mpHandler.prepareOutgoingMessage(
                snmpEngine, origTransportDomain, origTransportAddress,
                messageProcessingModel, securityModel, securityName,
                securityLevel, contextEngineId, contextName,
                pduVersion, PDU, expectResponse, sendPduHandle
            )

            debug.logger & debug.flagDsp and debug.logger('sendPdu: MP succeeded')
        except PySnmpError:
            if expectResponse:
                self.__cache.pop(sendPduHandle)
                self.releaseStateInformation(snmpEngine, sendPduHandle, messageProcessingModel)
            raise

        # 4.1.1.6
        if snmpEngine.transportDispatcher is None:
            if expectResponse:
                self.__cache.pop(sendPduHandle)

            raise error.PySnmpError('Transport dispatcher not set')

        snmpEngine.observer.storeExecutionContext(
            snmpEngine, 'rfc3412.sendPdu',
            dict(transportDomain=transportDomain,
                 transportAddress=transportAddress,
                 outgoingMessage=outgoingMessage,
                 messageProcessingModel=messageProcessingModel,
                 securityModel=securityModel,
                 securityName=securityName,
                 securityLevel=securityLevel,
                 contextEngineId=contextEngineId,
                 contextName=contextName,
                 pdu=PDU)
        )

        try:
            snmpEngine.transportDispatcher.sendMessage(
                outgoingMessage, transportDomain, transportAddress
            )
        except PySnmpError:
            if expectResponse:
                self.__cache.pop(sendPduHandle)
            raise

        snmpEngine.observer.clearExecutionContext(snmpEngine, 'rfc3412.sendPdu')

        # Update cache with orignal req params (used for retrying)
        if expectResponse:
            self.__cache.update(sendPduHandle,
                                transportDomain=origTransportDomain,
                                transportAddress=origTransportAddress,
                                securityModel=securityModel,
                                securityName=securityName,
                                securityLevel=securityLevel,
                                contextEngineId=contextEngineId,
                                contextName=contextName,
                                pduVersion=pduVersion,
                                PDU=PDU)

        return sendPduHandle
Beispiel #3
0
    def sendPdu(self, snmpEngine, transportDomain, transportAddress,
                messageProcessingModel, securityModel, securityName,
                securityLevel, contextEngineId, contextName, pduVersion, PDU,
                expectResponse):
        """PDU dispatcher -- prepare and serialize a request or notification"""
        # 4.1.1.2
        mpHandler = snmpEngine.messageProcessingSubsystems.get(
            int(messageProcessingModel))
        if mpHandler is None:
            raise error.StatusInformation(
                errorIndication='unsupportedMsgProcessingModel')

        debug.logger & debug.flagDsp and debug.logger(
            'sendPdu: PDU %s' % PDU.prettyPrint())

        # 4.1.1.3
        sendPduHandle = self.__newSendPduHandle()
        if expectResponse:
            self.__cacheAdd(sendPduHandle,
                            messageProcessingModel=messageProcessingModel,
                            sendPduHandle=sendPduHandle,
                            expectResponse=expectResponse)

        debug.logger & debug.flagDsp and debug.logger(
            'sendPdu: new sendPduHandle %s' % sendPduHandle)

        # 4.1.1.4 & 4.1.1.5
        try:
            (destTransportDomain, destTransportAddress,
             outgoingMessage) = mpHandler.prepareOutgoingMessage(
                 snmpEngine, transportDomain, transportAddress,
                 messageProcessingModel, securityModel, securityName,
                 securityLevel, contextEngineId, contextName, pduVersion, PDU,
                 expectResponse, sendPduHandle)
            debug.logger & debug.flagDsp and debug.logger(
                'sendPdu: MP succeeded')
        except error.StatusInformation as statusInformation:
            # XXX is it still needed here?
            #            self.releaseStateInformation(snmpEngine, sendPduHandle, messageProcessingModel)
            raise

        # 4.1.1.6
        if snmpEngine.transportDispatcher is None:
            raise error.PySnmpError('Transport dispatcher not set')
        snmpEngine.transportDispatcher.sendMessage(outgoingMessage,
                                                   destTransportDomain,
                                                   destTransportAddress)

        # Update cache with orignal req params (used for retrying)
        if expectResponse:
            self.__cacheUpdate(sendPduHandle,
                               transportDomain=transportDomain,
                               transportAddress=transportAddress,
                               securityModel=securityModel,
                               securityName=securityName,
                               securityLevel=securityLevel,
                               contextEngineId=contextEngineId,
                               contextName=contextName,
                               pduVersion=pduVersion,
                               PDU=PDU)

        return sendPduHandle
Beispiel #4
0
class MsgAndPduDispatcher:
    """SNMP engine PDU & message dispatcher. Exchanges SNMP PDU's with
       applications and serialized messages with transport level.
    """
    def __init__(self, mibInstrumController=None):
        if mibInstrumController is None:
            self.mibInstrumController = instrum.MibInstrumController(
                builder.MibBuilder())
        else:
            self.mibInstrumController = mibInstrumController

        self.mibInstrumController.mibBuilder.loadModules(
            'SNMPv2-MIB', 'SNMP-MPD-MIB', 'SNMP-COMMUNITY-MIB',
            'SNMP-TARGET-MIB', 'SNMP-USER-BASED-SM-MIB')

        # Registered context engine IDs
        self.__appsRegistration = {}

        # Source of sendPduHandle and cache of requesting apps
        self.__sendPduHandle = 0L
        self.__cacheRepository = {}

        # To pass transport info to app
        self.__transportInfo = {}

    # These routines manage cache of management apps

    def __newSendPduHandle(self):
        sendPduHandle = self.__sendPduHandle = self.__sendPduHandle + 1
        return sendPduHandle

    def __cacheAdd(self, index, **kwargs):
        self.__cacheRepository[index] = kwargs
        return index

    def __cachePop(self, index):
        cachedParams = self.__cacheRepository.get(index)
        if cachedParams is None:
            return
        del self.__cacheRepository[index]
        return cachedParams

    def __cacheUpdate(self, index, **kwargs):
        if not self.__cacheRepository.has_key(index):
            raise error.ProtocolError('Cache miss on update for %s' % kwargs)
        self.__cacheRepository[index].update(kwargs)

    def __cacheExpire(self, snmpEngine, cbFun):
        for index, cachedParams in self.__cacheRepository.items():
            if cbFun:
                if cbFun(snmpEngine, cachedParams):
                    del self.__cacheRepository[index]

    def getTransportInfo(self, stateReference):
        if self.__transportInfo.has_key(stateReference):
            return self.__transportInfo[stateReference]
        else:
            raise error.ProtocolError('No data for stateReference %s' %
                                      stateReference)

    # Application registration with dispatcher

    # 4.3.1
    def registerContextEngineId(self, contextEngineId, pduTypes, processPdu):
        """Register application with dispatcher"""
        # 4.3.2 -> noop

        # 4.3.3
        for pduType in pduTypes:
            k = (str(contextEngineId), pduType)
            if self.__appsRegistration.has_key(k):
                raise error.ProtocolError('Duplicate registration %s/%s' %
                                          (contextEngineId, pduType))

            # 4.3.4
            self.__appsRegistration[k] = processPdu

        debug.logger & debug.flagDsp and debug.logger(
            'registerContextEngineId: contextEngineId %s pduTypes %s' %
            (contextEngineId, pduTypes))

    # 4.4.1
    def unregisterContextEngineId(self, contextEngineId, pduTypes):
        """Unregister application with dispatcher"""
        # 4.3.4
        if contextEngineId is None:
            # Default to local snmpEngineId
            contextEngineId, = self.mibInstrumController.mibBuilder.importSymbols(
                '__SNMP-FRAMEWORK-MIB', 'snmpEngineID')

        for pduType in pduTypes:
            k = (str(contextEngineId), pduType)
            if self.__appsRegistration.has_key(k):
                del self.__appsRegistration[k]

        debug.logger & debug.flagDsp and debug.logger(
            'unregisterContextEngineId: contextEngineId %s pduTypes %s' %
            (contextEngineId, pduTypes))

    def getRegisteredApp(self, contextEngineId, pduType):
        k = (str(contextEngineId), pduType)
        if self.__appsRegistration.has_key(k):
            return self.__appsRegistration[k]
        k = ('', pduType)
        if self.__appsRegistration.has_key(k):
            return self.__appsRegistration[k]  # wildcard

    # Dispatcher <-> application API

    # 4.1.1

    def sendPdu(self, snmpEngine, transportDomain, transportAddress,
                messageProcessingModel, securityModel, securityName,
                securityLevel, contextEngineId, contextName, pduVersion, PDU,
                expectResponse):
        """PDU dispatcher -- prepare and serialize a request or notification"""
        # 4.1.1.2
        mpHandler = snmpEngine.messageProcessingSubsystems.get(
            int(messageProcessingModel))
        if mpHandler is None:
            raise error.StatusInformation(
                errorIndication='unsupportedMsgProcessingModel')

        debug.logger & debug.flagDsp and debug.logger(
            'sendPdu: PDU %s' % PDU.prettyPrint())

        # 4.1.1.3
        sendPduHandle = self.__newSendPduHandle()
        if expectResponse:
            self.__cacheAdd(sendPduHandle,
                            messageProcessingModel=messageProcessingModel,
                            sendPduHandle=sendPduHandle,
                            expectResponse=expectResponse)

        debug.logger & debug.flagDsp and debug.logger(
            'sendPdu: new sendPduHandle %s' % sendPduHandle)

        # 4.1.1.4 & 4.1.1.5
        try:
            (destTransportDomain, destTransportAddress,
             outgoingMessage) = mpHandler.prepareOutgoingMessage(
                 snmpEngine, transportDomain, transportAddress,
                 messageProcessingModel, securityModel, securityName,
                 securityLevel, contextEngineId, contextName, pduVersion, PDU,
                 expectResponse, sendPduHandle)
            debug.logger & debug.flagDsp and debug.logger(
                'sendPdu: MP succeeded')
        except error.StatusInformation, statusInformation:
            # XXX is it still needed here?
            #            self.releaseStateInformation(snmpEngine, sendPduHandle, messageProcessingModel)
            raise

        # 4.1.1.6
        if snmpEngine.transportDispatcher is None:
            raise error.PySnmpError('Transport dispatcher not set')
        snmpEngine.transportDispatcher.sendMessage(outgoingMessage,
                                                   destTransportDomain,
                                                   destTransportAddress)

        # Update cache with orignal req params (used for retrying)
        if expectResponse:
            self.__cacheUpdate(sendPduHandle,
                               transportDomain=transportDomain,
                               transportAddress=transportAddress,
                               securityModel=securityModel,
                               securityName=securityName,
                               securityLevel=securityLevel,
                               contextEngineId=contextEngineId,
                               contextName=contextName,
                               pduVersion=pduVersion,
                               PDU=PDU)

        return sendPduHandle
Beispiel #5
0
    def sendPdu(
            self,
            snmpEngine,
            transportDomain,
            transportAddress,
            messageProcessingModel,
            securityModel,
            securityName,
            securityLevel,
            contextEngineId,
            contextName,
            pduVersion,
            PDU,
            expectResponse,
            timeout=0,  # timeout expressed in dispatcher ticks
            cbFun=None,
            cbCtx=None):
        """PDU dispatcher -- prepare and serialize a request or notification"""
        # 4.1.1.2
        k = int(messageProcessingModel)
        if k in snmpEngine.messageProcessingSubsystems:
            mpHandler = snmpEngine.messageProcessingSubsystems[k]
        else:
            raise error.StatusInformation(
                errorIndication=errind.unsupportedMsgProcessingModel)

        debug.logger & debug.flagDsp and debug.logger(
            'sendPdu: securityName %s, PDU\n%s' %
            (securityName, PDU.prettyPrint()))

        # 4.1.1.3
        sendPduHandle = self.__sendPduHandle()
        if expectResponse:
            self.__cache.add(sendPduHandle,
                             messageProcessingModel=messageProcessingModel,
                             sendPduHandle=sendPduHandle,
                             timeout=timeout +
                             snmpEngine.transportDispatcher.getTimerTicks(),
                             cbFun=cbFun,
                             cbCtx=cbCtx)
            debug.logger & debug.flagDsp and debug.logger(
                'sendPdu: current time in ticks %d' %
                (snmpEngine.transportDispatcher.getTimerTicks(), ))

        debug.logger & debug.flagDsp and debug.logger(
            'sendPdu: new sendPduHandle %s, timeout %s, cbFun %s' %
            (sendPduHandle, timeout, cbFun))

        # 4.1.1.4 & 4.1.1.5
        try:
            (destTransportDomain, destTransportAddress,
             outgoingMessage) = mpHandler.prepareOutgoingMessage(
                 snmpEngine, transportDomain, transportAddress,
                 messageProcessingModel, securityModel, securityName,
                 securityLevel, contextEngineId, contextName, pduVersion, PDU,
                 expectResponse, sendPduHandle)
            debug.logger & debug.flagDsp and debug.logger(
                'sendPdu: MP succeeded')
        except error.StatusInformation:
            # XXX is it still needed here?
            #            self.releaseStateInformation(snmpEngine, sendPduHandle, messageProcessingModel)
            raise

        # 4.1.1.6
        if snmpEngine.transportDispatcher is None:
            raise error.PySnmpError('Transport dispatcher not set')
        snmpEngine.transportDispatcher.sendMessage(outgoingMessage,
                                                   destTransportDomain,
                                                   destTransportAddress)

        # Update cache with orignal req params (used for retrying)
        if expectResponse:
            self.__cache.update(sendPduHandle,
                                transportDomain=transportDomain,
                                transportAddress=transportAddress,
                                securityModel=securityModel,
                                securityName=securityName,
                                securityLevel=securityLevel,
                                contextEngineId=contextEngineId,
                                contextName=contextName,
                                pduVersion=pduVersion,
                                PDU=PDU)

        return sendPduHandle