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
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
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
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
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