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