def sendTrap(self, notification, trap_name, var_binds): ntfOrg = ntforg.NotificationOriginator(self._snmpContext) errorIndication = ntfOrg.sendNotification( self._snmpEngine, 'test-notification', ( 'QUMULO-MIB', trap_name ), var_binds)
def sendTrap(self): print("Sending trap") ntfOrg = ntforg.NotificationOriginator(self._snmpContext) errorIndication = ntfOrg.sendNotification(self._snmpEngine, 'test-notification', ('SABIH-MIB', 'testTrap'), ())
def sendNotification(self, authData, transportTarget, notifyType, notificationType, varBinds=(), cbInfo=(None, None), lookupNames=False, lookupValues=False, contextName=null): def __cbFun(sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): lookupNames, lookupValues, cbFun, cbCtx = cbCtx if cbFun is None: # user callback not supplied return try: # we need to pass response PDU information to user for INFORMs return cbFun( sendRequestHandle, errorIndication, errorStatus, errorIndex, self.unmakeVarBinds(varBinds, lookupNames, lookupValues), cbCtx) except TypeError: # a backward compatible way of calling user function return cbFun(sendRequestHandle, errorIndication, cbCtx) # for backward compatibility if contextName is null and authData.contextName: contextName = authData.contextName (cbFun, cbCtx) = cbInfo # Create matching transport tags if not given by user if not transportTarget.tagList: transportTarget.tagList = str( hash((authData.securityName, transportTarget.transportAddr))) if isinstance(authData, CommunityData) and not authData.tag: authData.tag = transportTarget.tagList.split()[0] notifyName = self.cfgNtfOrg(authData, transportTarget, notifyType) if isinstance(notificationType, MibVariable): notificationType = notificationType.resolveWithMib( self.mibViewController, oidOnly=True) elif isinstance(notificationType[0], tuple): # legacy notificationType = MibVariable( notificationType[0][0], notificationType[0][1], *notificationType[1:]).resolveWithMib(self.mibViewController) return ntforg.NotificationOriginator( self.snmpContext).sendNotification( self.snmpEngine, notifyName, notificationType, self.makeVarBinds(varBinds), __cbFun, (lookupNames, lookupValues, cbFun, cbCtx), contextName)
def sendNotification(self, authData, transportTarget, notifyType, notificationType=None, varBinds=None, cbInfo=(None, None)): (cbFun, cbCtx) = cbInfo notifyName = self.cfgNtfOrg(authData, transportTarget, notifyType) if notificationType is not None: if isinstance(notificationType, MibVariable): notificationType = notificationType.resolveWithMib( self.mibViewController, oidOnly=True) elif isinstance(notificationType[0], tuple): # legacy notificationType = MibVariable( notificationType[0][0], notificationType[0][1], *notificationType[1:]).resolveWithMib( self.mibViewController) if varBinds: __varBinds = [] for varName, varVal in varBinds: if isinstance(varName, MibVariable): varName.resolveWithMib(self.mibViewController) if not isinstance(varVal, base.AbstractSimpleAsn1Item): varVal = varName.getMibNode().getSyntax().clone(varVal) elif isinstance(varName[0], tuple): # legacy varName = MibVariable(varName[0][0], varName[0][1], *varName[1:]).resolveWithMib( self.mibViewController) if not isinstance(varVal, base.AbstractSimpleAsn1Item): varVal = varName.getMibNode().getSyntax().clone(varVal) else: if isinstance(varVal, base.AbstractSimpleAsn1Item): varName = MibVariable(varName).resolveWithMib( self.mibViewController, oidOnly=True) else: varName = MibVariable(varName).resolveWithMib( self.mibViewController) varVal = varName.getMibNode().getSyntax().clone(varVal) __varBinds.append((varName, varVal)) else: __varBinds = None return ntforg.NotificationOriginator( self.snmpContext).sendNotification(self.snmpEngine, notifyName, notificationType, __varBinds, cbFun, cbCtx)
def sendNotification(self, snmpEngine, snmpContext, authData, transportTarget, notifyType, notificationType, varBinds=(), cbInfo=(None, None), lookupNames=False, lookupValues=False, contextName=null): def __cbFun(sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): lookupNames, lookupValues, cbFun, cbCtx = cbCtx return cbFun and cbFun( sendRequestHandle, errorIndication, errorStatus, errorIndex, self.unmakeVarBinds(snmpEngine, varBinds, lookupNames, lookupValues), cbCtx) cache = self._getCmdCache(snmpEngine) (cbFun, cbCtx) = cbInfo # Create matching transport tags if not given by user if not transportTarget.tagList: transportTarget.tagList = str( hash((authData.securityName, transportTarget.transportAddr))) if isinstance(authData, CommunityData) and not authData.tag: authData.tag = transportTarget.tagList.split()[0] notifyName = self.cfgNtfOrg(snmpEngine, authData, transportTarget, notifyType) if isinstance(notificationType, MibVariable): notificationType = notificationType.resolveWithMib( cache['mibViewController'], oidOnly=True) return ntforg.NotificationOriginator(snmpContext).sendNotification( snmpEngine, notifyName, notificationType, self.makeVarBinds(snmpEngine, varBinds), __cbFun, (lookupNames, lookupValues, cbFun, cbCtx), contextName)
def sendNotification(snmpEngine, authData, transportTarget, contextData, notifyType, varBinds, cbFun=None, cbCtx=None, lookupMib=False): """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 ---------- snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` Class instance representing SNMP engine. 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. contextData : :py:class:`~pysnmp.hlapi.ContextData` Class instance representing SNMP ContextEngineId and ContextName values. notifyType : str Indicates type of notification to be sent. Recognized literal values are *trap* or *inform*. varBinds : tuple Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class instance representing a minimum sequence of MIB variables required for particular notification type. Alternatively, a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` objects could be passed instead. In the latter case it is up to the user to ensure proper Notification PDU contents. Other Parameters ---------------- cbFun : callable user-supplied callable that is invoked to pass SNMP response to *INFORM* notification or error to user at a later point of time. The `cbFun` callable is never invoked for *TRAP* notifications. cbCtx : object user-supplied object passing additional parameters to/from `cbFun`. lookupMib : bool `lookupMib` - load MIB and resolve response MIB variables at the cost of slightly reduced performance. Default is `True`. Notes ----- User-supplied `cbFun` callable must have the following call signature: * snmpEngine (:py:class:`~pysnmp.hlapi.SnmpEngine`): Class instance representing SNMP engine. * sendRequestHandle (int): Unique request identifier. Can be used for matching multiple ongoing *INFORM* notifications with received responses. * 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 :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances representing MIB variables returned in SNMP response in exactly the same order as `varBinds` in request. * `cbCtx` : Original user-supplied object. 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.asyncore import * >>> >>> snmpEngine = SnmpEngine() >>> sendNotification( ... snmpEngine, ... CommunityData('public'), ... UdpTransportTarget(('demo.snmplabs.com', 162)), ... ContextData(), ... 'trap', ... NotificationType(ObjectIdentity('SNMPv2-MIB', 'coldStart')), ... ) >>> snmpEngine.transportDispatcher.runDispatcher() >>> """ # noinspection PyShadowingNames def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): lookupMib, cbFun, cbCtx = cbCtx return cbFun and cbFun( snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, vbProcessor.unmakeVarBinds(snmpEngine, varBinds, lookupMib), cbCtx) notifyName = lcd.configure(snmpEngine, authData, transportTarget, notifyType) return ntforg.NotificationOriginator().sendVarBinds( snmpEngine, notifyName, contextData.contextEngineId, contextData.contextName, vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun, (lookupMib, cbFun, cbCtx))
def sendNotification(snmpEngine, authData, transportTarget, contextData, 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 ---------- snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` Class instance representing SNMP engine. 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. contextData : :py:class:`~pysnmp.hlapi.ContextData` Class instance representing SNMP ContextEngineId and ContextName values. 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 includes some housekeeping items that are required for SNMP to function. Agent information: * SNMPv2-MIB::sysUpTime.0 = <agent uptime> * SNMPv2-SMI::snmpTrapOID.0 = {SNMPv2-MIB::coldStart, ...} Applicable to SNMP v1 TRAP: * SNMP-COMMUNITY-MIB::snmpTrapAddress.0 = <agent-IP> * SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 = <snmp-community-name> * SNMP-COMMUNITY-MIB::snmpTrapEnterprise.0 = <enterprise-OID> .. note:: Unless user passes some of these variable-bindings, `.sendNotification()` call will fill in the missing items. User variable-bindings: * SNMPv2-SMI::NOTIFICATION-TYPE * SNMPv2-SMI::OBJECT-TYPE .. note:: The :py:class:`~pysnmp.smi.rfc1902.NotificationType` object ensures properly formed SNMP notification (to comply MIB definition). If you build notification PDU out of :py:class:`~pysnmp.smi.rfc1902.ObjectType` objects or simple tuples of OID-value objects, it is your responsibility to provide well-formed notificaton payload. Other Parameters ---------------- \*\*options: * lookupMib: bool `lookupMib` - load MIB and resolve response MIB variables at the cost of slightly reduced performance. Default is `True`. * cbFun: callable user-supplied callable that is invoked to pass SNMP response to *INFORM* notification or error to user at a later point of time. The `cbFun` callable is never invoked for *TRAP* notifications. * cbCtx: object user-supplied object passing additional parameters to/from `cbFun` Notes ----- User-supplied `cbFun` callable must have the following call signature: * snmpEngine (:py:class:`~pysnmp.hlapi.SnmpEngine`): Class instance representing SNMP engine. * sendRequestHandle (int): Unique request identifier. Can be used for matching multiple ongoing *INFORM* notifications with received responses. * 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 :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances representing MIB variables returned in SNMP response in exactly the same order as `varBinds` in request. * `cbCtx` : Original user-supplied object. 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.asyncore import * >>> >>> snmpEngine = SnmpEngine() >>> sendNotification( ... snmpEngine, ... CommunityData('public'), ... UdpTransportTarget(('demo.snmplabs.com', 162)), ... ContextData(), ... 'trap', ... NotificationType(ObjectIdentity('SNMPv2-MIB', 'coldStart')), ... ) >>> snmpEngine.transportDispatcher.runDispatcher() >>> """ # noinspection PyShadowingNames def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): lookupMib, cbFun, cbCtx = cbCtx return cbFun and cbFun( snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, vbProcessor.unmakeVarBinds(snmpEngine.cache, varBinds, lookupMib), cbCtx) notifyName = lcd.configure(snmpEngine, authData, transportTarget, notifyType, contextData.contextName) return ntforg.NotificationOriginator().sendVarBinds( snmpEngine, notifyName, contextData.contextEngineId, contextData.contextName, vbProcessor.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, (options.get('lookupMib', True), options.get('cbFun'), options.get('cbCtx')))
config.addContext(snmpEngine, '') config.addVacmUser(snmpEngine, 1, 'test-agent', 'noAuthNoPriv', (), (), (1,3,6)) # v1 config.addVacmUser(snmpEngine, 2, 'test-agent', 'noAuthNoPriv', (), (), (1,3,6)) # v2c config.addVacmUser(snmpEngine, 3, 'test-user', 'authPriv', (), (), (1,3,6)) # v3 # SNMP context snmpContext = context.SnmpContext(snmpEngine) def cbFun(snmpEngine, errorIndication, cbCtx): if errorIndication: print errorIndication errorIndication = ntforg.NotificationOriginator(snmpContext).sendNotification( snmpEngine, # Notification targets 'myNotifyName', # Trap OID (SNMPv2-MIB::coldStart) (1,3,6,1,6,3,1,1,5,1), # ((oid, value), ... ) (((1,3,6,1,2,1,1,5), v2c.OctetString('Example Notificator')),), cbFun ) if errorIndication: print errorIndication else: snmpEngine.transportDispatcher.runDispatcher()
# Specify what kind of notification should be sent (TRAP or INFORM), # to what targets (chosen by tag) and what filter should apply to # the set of targets (selected by tag) config.addNotificationTarget(snmpEngine, 'my-notification', 'my-filter', 'all-my-managers', 'inform') # Allow NOTIFY access to Agent's MIB by this SNMP model (2), securityLevel # and SecurityName config.addContext(snmpEngine, '') config.addVacmUser(snmpEngine, 2, 'my-area', 'noAuthNoPriv', (), (), (1, 3, 6)) # *** SNMP engine configuration is complete by this line *** # Create Notification Originator App instance. ntfOrg = ntforg.NotificationOriginator() # Error/confirmation receiver # noinspection PyUnusedLocal,PyUnusedLocal,PyUnusedLocal,PyUnusedLocal,PyUnusedLocal def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): print('Notification %s, status - %s' % (sendRequestHandle, errorIndication and errorIndication or 'delivered')) # Build and submit notification message to dispatcher sendRequestHandle = ntfOrg.sendVarBinds( snmpEngine, 'my-notification', # notification targets
def sendTheTrap(): uptime = getUptime() # Create SNMP engine instance with specific (and locally unique) # SnmpEngineId -- it must also be known to the receiving party # and configured at its VACM users table. snmpEngine = engine.SnmpEngine(snmpEngineID=v2c.OctetString( hexValue='0102030405060708')) # Add USM user config.addV3User(snmpEngine, userConfig['DEFAULT']['SNMPUSER'], config.usmHMAC128SHA224AuthProtocol, userConfig['DEFAULT']['SNMPAUTH'], config.usmAesCfb192Protocol, userConfig['DEFAULT']['SNMPPRIV']) config.addTargetParams(snmpEngine, userConfig['DEFAULT']['SNMPAUTH'], userConfig['DEFAULT']['SNMPUSER'], 'authPriv') # Setup transport endpoint and bind it with security settings yielding # a target name config.addTransport(snmpEngine, udp.domainName, udp.UdpSocketTransport().openClientMode()) config.addTargetAddr(snmpEngine, 'my-nms', udp.domainName, (userConfig['DEFAULT']['SNMPMANAGERIP'], int(userConfig['DEFAULT']['SNMPMANAGERPORT'])), userConfig['DEFAULT']['SNMPAUTH'], tagList='all-my-managers') # Specify what kind of notification should be sent (TRAP or INFORM), # to what targets (chosen by tag) and what filter should apply to # the set of targets (selected by tag) config.addNotificationTarget(snmpEngine, 'my-notification', 'my-filter', 'all-my-managers', 'trap') # Allow NOTIFY access to Agent's MIB by this SNMP model (3), securityLevel # and SecurityName config.addContext(snmpEngine, '') config.addVacmUser(snmpEngine, 3, userConfig['DEFAULT']['SNMPUSER'], 'authPriv', (), (), (1, 3, 6), 'aContextName') # *** SNMP engine configuration is complete by this line *** # Create Notification Originator App instance. ntfOrg = ntforg.NotificationOriginator() # Build and submit notification message to dispatcher ntfOrg.sendVarBinds( snmpEngine, # Notification targets 'my-notification', # notification targets None, 'aContextName', # contextEngineId, contextName # var-binds [((1, 3, 6, 1, 2, 1, 1, 3, 0), v2c.OctetString(uptime)), ((1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0), v2c.ObjectIdentifier((1, 3, 6, 1, 6, 3, 1, 1, 5, 1))), ((1, 3, 6, 1, 2, 1, 1, 5, 0), v2c.OctetString(socket.getfqdn())), ((1, 3, 6, 1, 4, 1, 6876, 4, 50, 1, 2, 10, 0), v2c.OctetString('Application')), ((1, 3, 6, 1, 4, 1, 6876, 4, 50, 1, 2, 11, 0), v2c.OctetString('Performance')), ((1, 3, 6, 1, 4, 1, 6876, 4, 50, 1, 2, 12, 0), v2c.OctetString('critical')), ((1, 3, 6, 1, 4, 1, 6876, 4, 50, 1, 2, 19, 0), v2c.OctetString('health')), ((1, 3, 6, 1, 4, 1, 6876, 4, 50, 1, 2, 20, 0), v2c.OctetString('vROpsExternalMonitorService.py')), ((1, 3, 6, 1, 4, 1, 6876, 4, 50, 1, 2, 50, 0), v2c.OctetString( 'vROps services are having issues, please check nodes'))]) print('Notification is scheduled to be sent') # Run I/O dispatcher which would send pending message and process response snmpEngine.transportDispatcher.runDispatcher()
((symName, modName), suffix) = mibvar.oidToMibName( self.mibViewController, name + oid ) syntax = mibvar.cloneFromMibValue( self.mibViewController, modName, symName, varVal ) if syntax is None: raise error.PySnmpError( 'Value type MIB lookup failed for %s' % repr(varName) ) varVal = syntax.clone(varVal) __varBinds.append((name + oid, varVal)) else: __varBinds = None return ntforg.NotificationOriginator(self.snmpContext).sendNotification(self.snmpEngine, notifyName, notificationType, __varBinds, cbFun, cbCtx) class NotificationOriginator(AsynNotificationOriginator): def sendNotification( self, authData, transportTarget, notifyType, notificationType, *varBinds ): def __cbFun(sendRequestHandle, errorIndication, appReturn): appReturn['errorIndication'] = errorIndication appReturn = {} errorIndication = self.asyncSendNotification( authData, transportTarget, notifyType, notificationType, varBinds, (__cbFun, appReturn) ) if errorIndication:
def sendTrap(self): print "Sending Trap" ntfOrg = ntforg.NotificationOriginator(self._snmpContext) errorIndication = ntfOrg.sendNotification(self._snmpEngine, 'test-notification', ("MY-MIB", 'testTrap'), ())
inTableFlag = 1 if not inTableFlag: return # stop on end-of-table return 1 # continue walking snmpContext = context.SnmpContext(snmpEngine) # Agent-side VACM setup config.addContext(snmpEngine, '') config.addTrapUser(snmpEngine, 1, ctx['securityName'], 'noAuthNoPriv', (1, 3, 6)) # v1 config.addTrapUser(snmpEngine, 2, ctx['securityName'], 'noAuthNoPriv', (1, 3, 6)) # v2c config.addTrapUser(snmpEngine, 3, ctx['securityName'], 'authPriv', (1, 3, 6)) # v3 ctx['notificationName'] = 'myNotifyName' config.addNotificationTarget(snmpEngine, ctx['notificationName'], ctx['paramsName'], ctx['transportTag'], 'trap') ntforg.NotificationOriginator(snmpContext).sendNotification( snmpEngine, ctx['notificationName'], ('SNMPv2-MIB', ctx['GenericTrap']), ctx['varBinds'], cbFun, ctx) try: snmpEngine.transportDispatcher.runDispatcher() except error.PySnmpError, why: sys.stderr.write('Error: %s\n' % why) sys.exit(-1)
def trigger_trap(temp): # Create SNMP engine instance snmpEngine = engine.SnmpEngine() # SecurityName <-> CommunityName mapping config.addV1System(snmpEngine, 'my-area', 'federated') # Specify security settings per SecurityName (SNMPv2c -> 1) config.addTargetParams(snmpEngine, 'my-creds', 'my-area', 'noAuthNoPriv', 1) # Setup transport endpoint and bind it with security settings yielding # a target name config.addSocketTransport( snmpEngine, udp.domainName, udp.UdpSocketTransport().openClientMode() ) config.addTargetAddr( snmpEngine, 'my-nms', udp.domainName, ('34.215.95.184', 162), 'my-creds', tagList='all-my-managers' ) # Specify what kind of notification should be sent (TRAP or INFORM), # to what targets (chosen by tag) and what filter should apply to # the set of targets (selected by tag) config.addNotificationTarget( snmpEngine, 'my-notification', 'my-filter', 'all-my-managers', 'trap' ) # Allow NOTIFY access to Agent's MIB by this SNMP model (2), securityLevel # and SecurityName config.addContext(snmpEngine, '') config.addVacmUser(snmpEngine, 2, 'my-area', 'noAuthNoPriv', (), (), (1,3,6)) # *** SNMP engine configuration is complete by this line *** # Create default SNMP context where contextEngineId == SnmpEngineId snmpContext = context.SnmpContext(snmpEngine) # Create Notification Originator App instance. ntfOrg = ntforg.NotificationOriginator(snmpContext) # Build and submit notification message to dispatcher ntfOrg.sendNotification( snmpEngine, # Notification targets 'my-notification', # Trap OID (SNMPv2-MIB::coldStart) #(1,3,6,1,6,3,1,1,5,1), (1,3,6,1,4,1,8072,2,7,1,1,1,1,3,1), # ( (oid, value), ... ) ( ((1,3,6,1,4,1,8072,2,7,1,1,1,1,3,1), v2c.OctetString(temp)), ((1,3,6,1,2,1,1,5,0), v2c.OctetString('Reason: Admin brought down')) ) ) print('Notification is scheduled to be sent') # Run I/O dispatcher which would send pending message and process response snmpEngine.transportDispatcher.runDispatcher()
def __init__(self, args, queue): configDict = loadConfig(args.config) self.moduleLogger = set_logging(configDict, __class__.__name__) self.moduleLogger.info(f'original configDict: {configDict}') self._queue = queue # temp lines for graylog client end # # configDict['usmUserDataMatrix'] = [ usmUserTuple.strip().split(',') # for usmUserTuple in configDict['usmUserTuples'].split(';') if len(usmUserTuple) > 0 ] # self.moduleLogger.debug('configDict['usmUserDataMatrix']: {}'.format(configDict['usmUserDataMatrix'])) # configDict['usmUsers'] = [] self.moduleLogger.info(f'modified configDict: {configDict}') self._snmpEngine = snmp_config.getSnmpEngine( engineId=configDict['snmp'].get('engineId')) engineBoots = snmp_config.setSnmpEngineBoots( self._snmpEngine, configDict.get('stateDir', '.')) self._targets = snmp_config.setTrapTypeForTag(self._snmpEngine, self.TARGETS_TAG) authEntries = {} for snmpVersion, snmpConfigEntries in configDict['snmp'].get( 'versions', {}).items(): snmpVersion = str(snmpVersion) if snmpVersion in ('1', '2c'): for security, snmpConfig in snmpConfigEntries.items(): community = snmpConfig['community'] authLevel = snmp_config.setCommunity( self._snmpEngine, security, community, version=snmpVersion, tag=self.TARGETS_TAG) self.moduleLogger.info( f'Configuring SNMPv{snmpVersion} security name ' f'{security}, community name {community}') authEntries[security] = snmpVersion, authLevel elif snmpVersion == '3': for security, usmCreds in snmpConfigEntries.get('usmUsers', {}).items(): authLevel = snmp_config.setUsmUser( self._snmpEngine, security, usmCreds.get('user'), usmCreds.get('authKey'), usmCreds.get('authProtocol'), usmCreds.get('privKey'), usmCreds.get('privProtocol')) self.moduleLogger.info( f'Configuring SNMPv3 USM security {security}, user ' f'{usmCreds.get("user")}, ' f'auth {usmCreds.get("authKey")}/{usmCreds.get("authProtocol")}, ' f'priv {usmCreds.get("privKey")}/{usmCreds.get("privProtocol")}') authEntries[security] = snmpVersion, authLevel else: raise error.BdsError(f'Unknown SNMP version {snmpVersion}') self._birthday = time.time() snmpTrapTargets = configDict['notificator'].get('snmpTrapTargets', {}).items() for targetId, (targetName, targetConfig) in enumerate(snmpTrapTargets): bind_address = targetConfig.get('bind-address', '0.0.0.0'), 0 security = targetConfig['security-name'] transportDomain = snmp_config.setSnmpTransport( self._snmpEngine, iface=bind_address, iface_num=targetId) transportAddress = (targetConfig['address'], int(targetConfig.get('port', 162))) snmp_config.setTrapTargetAddress( self._snmpEngine, security, transportDomain, transportAddress, tag=self.TARGETS_TAG) snmpVersion, authLevel = authEntries[security] snmp_config.setTrapVersion( self._snmpEngine, security, authLevel, snmpVersion) self.moduleLogger.info( f'Configuring target #{targetId}, transport domain ' f'{transportDomain}, destination {transportAddress}, ' f'bind address {bind_address} using security name {security}') self._configureMibObjects(configDict) self._ntfOrg = ntforg.NotificationOriginator() self._trapCounter = 0 self.moduleLogger.info( f'Running SNMP engine ID {self._snmpEngine}, boots {engineBoots}')
def sendTrap(self, version, enterprise, varList, community=False, destPort=False): if destPort: trapPort = destPort else: trapPort = TRAP_PORT if community: comm = community else: comm = DEFAULT_COMM snmpEngine = engine.SnmpEngine() # v1/2 setup config.addV1System(snmpEngine, TEST_AGENT, comm) # v3 setup config.addV3User(snmpEngine, TEST_USER, config.usmHMACMD5AuthProtocol, 'authKey1', config.usmDESPrivProtocol, 'privKey1') # Transport params config.addTargetParams(snmpEngine, PARAM, TEST_USER, AUTHPRIV) #config.addTargetParams(snmpEngine, 'myParams', 'test-agent', 'noAuthNoPriv', 0) # Transport addresses config.addTargetAddr(snmpEngine, NMS, config.snmpUDPDomain, (self.dataCollector, trapPort), PARAM, tagList='myManagementStations') # Notification targets config.addNotificationTarget( # snmpEngine, 'myNotifyName', 'myParams', 'myManagementStations', 'trap' snmpEngine, 'myNotifyName', PARAM, 'myManagementStations', 'inform') # Setup transport endpoint config.addSocketTransport(snmpEngine, udp.domainName, udp.UdpSocketTransport().openClientMode()) # Agent-side VACM setup config.addContext(snmpEngine, '') config.addTrapUser(snmpEngine, 1, 'test-agent', 'noAuthNoPriv', (1, 3, 6)) # v1 config.addTrapUser(snmpEngine, 2, 'test-agent', 'noAuthNoPriv', (1, 3, 6)) # v2c config.addTrapUser(snmpEngine, 3, 'test-user', 'authPriv', (1, 3, 6)) # v3 # SNMP context snmpContext = context.SnmpContext(snmpEngine) def cbFun(sendRequestHandle, errorIndication, cbCtx): if errorIndication: print errorIndication ntforg.NotificationOriginator(snmpContext).sendNotification( snmpEngine, 'myNotifyName', ('SNMPv2-MIB', 'coldStart'), (((1, 3, 6, 1, 2, 1, 1, 5), v2c.OctetString('Example Notificator')), ), cbFun) snmpEngine.transportDispatcher.runDispatcher()
'all-my-managers', 'inform') # Allow NOTIFY access to Agent's MIB by this SNMP model (2&3), securityLevel # and SecurityName config.addContext(snmpEngine, '') config.addVacmUser(snmpEngine, 2, 'my-area', 'noAuthNoPriv', (), (), (1, 3, 6)) config.addVacmUser(snmpEngine, 3, 'usr-md5-none', 'authNoPriv', (), (), (1, 3, 6)) # *** SNMP engine configuration is complete by this line *** # Create default SNMP context where contextEngineId == SnmpEngineId snmpContext = context.SnmpContext(snmpEngine) # Create Notification Originator App instance. ntfOrg = ntforg.NotificationOriginator(snmpContext) # Error/confirmation receiver def cbFun(sendRequestHandle, errorIndication, cbCtx): print('Notification %s, status - %s' % (sendRequestHandle, errorIndication and errorIndication or 'delivered')) # Build and submit notification message to dispatcher ntfOrg.sendNotification( snmpEngine, # Notification targets 'my-notification', # Trap OID (SNMPv2-MIB::coldStart)
def sendNotification(snmpEngine, authData, transportTarget, contextData, notifyType, *varBinds, **options): """Sends SNMP notification. Based on passed parameters, prepares SNMP TRAP or INFORM message (:RFC:`1905#section-4.2.6`) and schedules its transmission by :mod:`twisted` I/O framework at a later point of time. Parameters ---------- snmpEngine: :py:class:`~pysnmp.hlapi.SnmpEngine` Class instance representing SNMP engine. authData: :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` Class instance representing SNMP credentials. transportTarget : :py:class:`~pysnmp.hlapi.twisted.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.twisted.Udp6TransportTarget` Class instance representing transport type along with SNMP peer address. contextData: :py:class:`~pysnmp.hlapi.ContextData` Class instance representing SNMP ContextEngineId and ContextName values. 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 includes some housekeeping items that are required for SNMP to function. Agent information: * SNMPv2-MIB::sysUpTime.0 = <agent uptime> * SNMPv2-SMI::snmpTrapOID.0 = {SNMPv2-MIB::coldStart, ...} Applicable to SNMP v1 TRAP: * SNMP-COMMUNITY-MIB::snmpTrapAddress.0 = <agent-IP> * SNMP-COMMUNITY-MIB::snmpTrapCommunity.0 = <snmp-community-name> * SNMP-COMMUNITY-MIB::snmpTrapEnterprise.0 = <enterprise-OID> .. note:: Unless user passes some of these variable-bindings, `.sendNotification()` call will fill in the missing items. User variable-bindings: * SNMPv2-SMI::NOTIFICATION-TYPE * SNMPv2-SMI::OBJECT-TYPE .. note:: The :py:class:`~pysnmp.smi.rfc1902.NotificationType` object ensures properly formed SNMP notification (to comply MIB definition). If you build notification PDU out of :py:class:`~pysnmp.smi.rfc1902.ObjectType` objects or simple tuples of OID-value objects, it is your responsibility to provide well-formed notificaton payload. Other Parameters ---------------- \*\*options : Request options: * `lookupMib` - load MIB and resolve response MIB variables at the cost of slightly reduced performance. Default is `True`. Returns ------- deferred : :class:`~twisted.internet.defer.Deferred` Twisted Deferred object representing work-in-progress. User is expected to attach his own `success` and `error` callback functions to the Deferred object though :meth:`~twisted.internet.defer.Deferred.addCallbacks` method. Raises ------ PySnmpError Or its derivative indicating that an error occurred while performing SNMP operation. Notes ----- User `success` callback is called with the following tuple as its first argument: * errorStatus (str) : True value indicates SNMP PDU error. * errorIndex (int) : Non-zero value refers to `varBinds[errorIndex-1]` * varBinds (tuple) : A sequence of :class:`~pysnmp.smi.rfc1902.ObjectType` class instances representing MIB variables returned in SNMP response. User `error` callback is called with `errorIndication` object wrapped in :class:`~twisted.python.failure.Failure` object. Examples -------- >>> from twisted.internet.task import react >>> from pysnmp.hlapi.twisted import * >>> >>> def success(args): ... (errorStatus, errorIndex, varBinds) = args ... print(errorStatus, errorIndex, varBind) ... >>> def failure(errorIndication): ... print(errorIndication) ... >>> def run(reactor): ... d = sendNotification(SnmpEngine(), ... CommunityData('public'), ... UdpTransportTarget(('demo.snmplabs.com', 162)), ... ContextData(), ... 'trap', ... NotificationType(ObjectIdentity('IF-MIB', 'linkDown'))) ... d.addCallback(success).addErrback(failure) ... return d ... >>> react(run) (0, 0, []) >>> """ def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): lookupMib, deferred = cbCtx if errorIndication: deferred.errback(Failure(errorIndication)) else: try: varBindsUnmade = vbProcessor.unmakeVarBinds( snmpEngine.cache, varBinds, lookupMib ) except Exception as e: deferred.errback(Failure(e)) else: deferred.callback((errorStatus, errorIndex, varBindsUnmade)) notifyName = lcd.configure( snmpEngine, authData, transportTarget, notifyType ) def __trapFun(deferred): deferred.callback((0, 0, [])) deferred = Deferred() ntforg.NotificationOriginator().sendVarBinds( snmpEngine, notifyName, contextData.contextEngineId, contextData.contextName, vbProcessor.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, (options.get('lookupMib', True), deferred) ) if notifyType == 'trap': reactor.callLater(0, __trapFun, deferred) return deferred
# Apply configuration to SNMP entity main.generator((snmpEngine, ctx), ast) msgmod.generator((snmpEngine, ctx), ast) secmod.generator((snmpEngine, ctx), ast) mibview.generator((snmpEngine, ctx), ast) target.generatorTrap((snmpEngine, ctx), ast) pdu.writePduGenerator((snmpEngine, ctx), ast) generator((snmpEngine, ctx), ast) v2c.apiPDU.setVarBinds( ctx['pdu'], v2c.apiPDU.getVarBinds(ctx['pdu']) + ctx['varBinds']) ntforg.NotificationOriginator().sendPdu(snmpEngine, ctx['addrName'], ctx.get('contextEngineId'), ctx.get('contextName', ''), ctx['pdu'], cbFun, ctx) snmpEngine.transportDispatcher.runDispatcher() except KeyboardInterrupt: sys.stderr.write('Shutting down...\n') except error.PySnmpError: sys.stderr.write('Error: %s\n%s' % (sys.exc_info()[1], getUsage())) sys.exit(-1) except Exception: sys.stderr.write('Process terminated: %s\n' % sys.exc_info()[1]) for line in traceback.format_exception(*sys.exc_info()): sys.stderr.write(line.replace('\n', ';'))
def sendNotification(snmpEngine, authData, transportTarget, contextData, notifyType, varBinds, **options): """Sends SNMP notification. Based on passed parameters, prepares SNMP TRAP or INFORM message (:RFC:`1905#section-4.2.6`) and schedules its transmission by :mod:`twisted` I/O framework at a later point of time. Parameters ---------- snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` Class instance representing SNMP engine. authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` Class instance representing SNMP credentials. transportTarget : :py:class:`~pysnmp.hlapi.twisted.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.twisted.Udp6TransportTarget` Class instance representing transport type along with SNMP peer address. contextData : :py:class:`~pysnmp.hlapi.ContextData` Class instance representing SNMP ContextEngineId and ContextName values. notifyType : str Indicates type of notification to be sent. Recognized literal values are *trap* or *inform*. varBinds: tuple Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class instance representing a minimum sequence of MIB variables required for particular notification type. Alternatively, a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` objects could be passed instead. In the latter case it is up to the user to ensure proper Notification PDU contents. Other Parameters ---------------- \*\*options : Request options: * `lookupMib` - load MIB and resolve response MIB variables at the cost of slightly reduced performance. Default is `True`. Returns ------- deferred : :class:`~twisted.internet.defer.Deferred` Twisted Deferred object representing work-in-progress. User is expected to attach his own `success` and `error` callback functions to the Deferred object though :meth:`~twisted.internet.defer.Deferred.addCallbacks` method. Raises ------ PySnmpError Or its derivative indicating that an error occurred while performing SNMP operation. Notes ----- User `success` callback is called with the following tuple as its first argument: * errorStatus (str) : True value indicates SNMP PDU error. * errorIndex (int) : Non-zero value refers to `varBinds[errorIndex-1]` * varBinds (tuple) : A sequence of :class:`~pysnmp.smi.rfc1902.ObjectType` class instances representing MIB variables returned in SNMP response. User `error` callback is called with `errorIndication` object wrapped in :class:`~twisted.python.failure.Failure` object. Examples -------- >>> from twisted.internet.task import react >>> from pysnmp.hlapi.twisted import * >>> >>> def success(args): ... (errorStatus, errorIndex, varBinds) = args ... print(errorStatus, errorIndex, varBind) ... >>> def failure(errorIndication): ... print(errorIndication) ... >>> def run(reactor): ... d = sendNotification(SnmpEngine(), ... CommunityData('public'), ... UdpTransportTarget(('demo.snmplabs.com', 162)), ... ContextData(), ... 'trap', ... NotificationType(ObjectIdentity('IF-MIB', 'linkDown'))) ... d.addCallback(success).addErrback(failure) ... return d ... >>> react(run) (0, 0, []) >>> """ def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): lookupMib, deferred = cbCtx if errorIndication: deferred.errback(Failure(errorIndication)) else: try: varBindsUnmade = vbProcessor.unmakeVarBinds( snmpEngine, varBinds, lookupMib) except Exception as e: deferred.errback(Failure(e)) else: deferred.callback((errorStatus, errorIndex, varBindsUnmade)) notifyName = lcd.configure(snmpEngine, authData, transportTarget, notifyType) def __trapFun(deferred): deferred.callback((0, 0, [])) deferred = Deferred() ntforg.NotificationOriginator().sendVarBinds( snmpEngine, notifyName, contextData.contextEngineId, contextData.contextName, vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun, (options.get('lookupMib', True), deferred)) if notifyType == 'trap': reactor.callLater(0, __trapFun, deferred) return deferred
def sendNotification(snmpEngine, authData, transportTarget, contextData, notifyType, varBinds, **options): """Creates a generator to send SNMP notification. When itereator 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 ---------- snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` Class instance representing SNMP engine. authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` Class instance representing SNMP credentials. transportTarget : :py:class:`~pysnmp.hlapi.asyncio.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncio.Udp6TransportTarget` Class instance representing transport type along with SNMP peer address. contextData : :py:class:`~pysnmp.hlapi.ContextData` Class instance representing SNMP ContextEngineId and ContextName values. notifyType : str Indicates type of notification to be sent. Recognized literal values are *trap* or *inform*. varBinds: tuple Single :py:class:`~pysnmp.smi.rfc1902.NotificationType` class instance representing a minimum sequence of MIB variables required for particular notification type. Alternatively, a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` objects could be passed instead. In the latter case it is up to the user to ensure proper Notification PDU contents. Other Parameters ---------------- \*\*options : Request options: * `lookupMib` - load MIB and resolve response MIB variables at the cost of slightly reduced performance. Default is `True`. 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 :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances representing MIB variables returned in SNMP response. Raises ------ PySnmpError Or its derivative indicating that an error occurred while performing SNMP operation. Notes ----- The `sendNotification` generator will be exhausted immidiately unless an instance of :py:class:`~pysnmp.smi.rfc1902.NotificationType` class or a sequence of :py:class:`~pysnmp.smi.rfc1902.ObjectType` `varBinds` are send back into running generator (supported since Python 2.6). Examples -------- >>> import asyncio >>> from pysnmp.hlapi.asyncio import * >>> >>> @asyncio.coroutine ... def run(): ... errorIndication, errorStatus, errorIndex, varBinds = yield from sendNotification( ... SnmpEngine(), ... CommunityData('public'), ... UdpTransportTarget(('demo.snmplabs.com', 162)), ... ContextData(), ... 'trap', ... NotificationType(ObjectIdentity('IF-MIB', 'linkDown'))) ... print(errorIndication, errorStatus, errorIndex, varBinds) ... >>> asyncio.get_event_loop().run_until_complete(run()) (None, 0, 0, []) >>> """ def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): lookupMib, future = cbCtx if future.cancelled(): return try: varBindsUnmade = vbProcessor.unmakeVarBinds( snmpEngine, varBinds, lookupMib) except Exception as e: future.set_exception(e) else: future.set_result( (errorIndication, errorStatus, errorIndex, varBindsUnmade)) notifyName = lcd.configure(snmpEngine, authData, transportTarget, notifyType) future = asyncio.Future() ntforg.NotificationOriginator().sendVarBinds( snmpEngine, notifyName, contextData.contextEngineId, contextData.contextName, vbProcessor.makeVarBinds(snmpEngine, varBinds), __cbFun, (options.get('lookupMib', True), future)) 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(snmpEngine, authData, transportTarget, contextData, 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 ---------- snmpEngine : :py:class:`~pysnmp.hlapi.SnmpEngine` Class instance representing SNMP engine. authData : :py:class:`~pysnmp.hlapi.CommunityData` or :py:class:`~pysnmp.hlapi.UsmUserData` Class instance representing SNMP credentials. transportTarget : :py:class:`~pysnmp.hlapi.asyncio.UdpTransportTarget` or :py:class:`~pysnmp.hlapi.asyncio.Udp6TransportTarget` Class instance representing transport type along with SNMP peer address. contextData : :py:class:`~pysnmp.hlapi.ContextData` Class instance representing SNMP ContextEngineId and ContextName values. 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 `True`. 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 :py:class:`~pysnmp.smi.rfc1902.ObjectType` class instances 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( ... SnmpEngine(), ... CommunityData('public'), ... UdpTransportTarget(('demo.snmplabs.com', 162)), ... ContextData(), ... 'trap', ... NotificationType(ObjectIdentity('IF-MIB', 'linkDown'))) ... print(errorIndication, errorStatus, errorIndex, varBinds) ... >>> asyncio.get_event_loop().run_until_complete(run()) (None, 0, 0, []) >>> """ def __cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): lookupMib, future = cbCtx if future.cancelled(): return try: varBindsUnmade = VB_PROCESSOR.unmakeVarBinds( snmpEngine.cache, varBinds, lookupMib) except Exception as e: future.set_exception(e) else: future.set_result( (errorIndication, errorStatus, errorIndex, varBindsUnmade)) notifyName = LCD.configure(snmpEngine, authData, transportTarget, notifyType, contextData.contextName) future = asyncio.Future() ntforg.NotificationOriginator().sendVarBinds( snmpEngine, notifyName, contextData.contextEngineId, contextData.contextName, VB_PROCESSOR.makeVarBinds(snmpEngine.cache, varBinds), __cbFun, (options.get('lookupMib', True), future)) 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
config.addVacmUser(snmpEngine, 3, 'usr-md5-3des', 'authPriv', (), (), (1, 3, 6)) # SNMP context snmpContext = context.SnmpContext(snmpEngine) # # Error/confirmation reciever def cbFun(sendRequestHandle, errorIndication, cbCtx): print('Notification %s, status - %s' % (sendRequestHandle, errorIndication and errorIndication or 'delivered')) sendRequestHandle = ntforg.NotificationOriginator( snmpContext).sendNotification( snmpEngine, # Notification targets 'my-notification', # Trap OID (SNMPv2-MIB::coldStart) (1, 3, 6, 1, 6, 3, 1, 1, 5, 1), # ((oid, value), ... ) (((1, 3, 6, 1, 2, 1, 1, 1), v2c.OctetString('Example Notificator')), ((1, 3, 6, 1, 2, 1, 1, 5), v2c.OctetString('Notificator Example'))), cbFun) print('Notification %s scheduled to be sent' % sendRequestHandle) # Run I/O dispatcher which would send pending message and process response snmpEngine.transportDispatcher.runDispatcher()
def main(): class LogString(LazyLogString): GROUPINGS = [ ['callflow-id'], ['trunk-id'], [ 'server-snmp-engine-id', 'server-snmp-transport-domain', 'server-snmp-peer-address', 'server-snmp-peer-port', 'server-snmp-bind-address', 'server-snmp-bind-port', 'server-snmp-security-model', 'server-snmp-security-level', 'server-snmp-security-name', 'server-snmp-context-engine-id', 'server-snmp-context-name', 'server-snmp-pdu', 'server-snmp-entity-id' ], [ 'server-snmp-credentials-id', 'server-snmp-context-id', 'server-snmp-content-id', 'server-snmp-peer-id', 'server-classification-id' ], [ 'snmp-peer-id', 'snmp-bind-address', 'snmp-bind-port', 'snmp-peer-address', 'snmp-peer-port', 'snmp-context-engine-id', 'snmp-context-name', 'snmp-pdu' ], ] FORMATTERS = { 'server-snmp-pdu': LazyLogString.prettyVarBinds, 'snmp-pdu': LazyLogString.prettyVarBinds, } def snmpCbFun(snmpEngine, sendRequestHandle, errorIndication, rspPDU, cbCtx): trunkId, msgId, trunkReq, pluginIdList, reqCtx = cbCtx trunkRsp = { 'callflow-id': trunkReq['callflow-id'], 'snmp-pdu': rspPDU, } logCtx = LogString(trunkRsp) if errorIndication: log.info('received SNMP error-indication "%s"' % errorIndication, ctx=logCtx) trunkRsp['error-indication'] = errorIndication if rspPDU: reqPdu = trunkReq['server-snmp-pdu'] for pluginId in pluginIdList: if reqPdu.tagSet in rfc3411.notificationClassPDUs: st, rspPDU = pluginManager.processNotificationResponse( pluginId, snmpEngine, rspPDU, trunkReq, reqCtx) elif reqPdu.tagSet not in rfc3411.unconfirmedClassPDUs: st, rspPDU = pluginManager.processCommandResponse( pluginId, snmpEngine, rspPDU, trunkReq, reqCtx) else: log.error('ignoring unsupported PDU', ctx=logCtx) break if st == status.BREAK: log.debug('plugin %s inhibits other plugins' % pluginId, ctx=logCtx) break elif st == status.DROP: log.debug( 'received SNMP %s, plugin %s muted response' % (errorIndication and 'error' or 'response', pluginId), ctx=logCtx) trunkRsp['snmp-pdu'] = None break try: trunkingManager.sendRsp(trunkId, msgId, trunkRsp) except SnmpfwdError: log.error('received SNMP %s message, trunk message not sent "%s"' % (msgId, sys.exc_info()[1]), ctx=logCtx) return log.debug('received SNMP %s message, forwarded as trunk message #%s' % (errorIndication and 'error' or 'response', msgId), ctx=logCtx) # # The following needs proper support in pysnmp. Meanwhile - monkey patching! # def makeTargetAddrOverride(targetAddr): endpoints = [] def getTargetAddr(snmpEngine, snmpTargetAddrName): addrInfo = list(targetAddr(snmpEngine, snmpTargetAddrName)) if endpoints: peerAddr, bindAddr = endpoints.pop(), endpoints.pop() try: addrInfo[1] = addrInfo[1].__class__( peerAddr).setLocalAddress(bindAddr) except Exception: raise PySnmpError( 'failure replacing bind address %s -> %s for transport ' 'domain %s' % (addrInfo[1], bindAddr, addrInfo[0])) return addrInfo def updateEndpoints(bindAddr, peerAddr): endpoints.extend((bindAddr, peerAddr)) return getTargetAddr, updateEndpoints lcd.getTargetAddr, updateEndpoints = makeTargetAddrOverride( lcd.getTargetAddr) def trunkCbFun(trunkId, msgId, trunkReq): for key in tuple(trunkReq): if key != 'callflow-id': trunkReq['server-' + key] = trunkReq[key] del trunkReq[key] trunkReq['trunk-id'] = trunkId k = [ str(x) for x in (trunkReq['server-snmp-engine-id'], trunkReq['server-snmp-transport-domain'], trunkReq['server-snmp-peer-address'] + ':' + str(trunkReq['server-snmp-peer-port']), trunkReq['server-snmp-bind-address'] + ':' + str(trunkReq['server-snmp-bind-port']), trunkReq['server-snmp-security-model'], trunkReq['server-snmp-security-level'], trunkReq['server-snmp-security-name'], trunkReq['server-snmp-context-engine-id'], trunkReq['server-snmp-context-name']) ] k.append(snmpPduTypesMap.get(trunkReq['server-snmp-pdu'].tagSet, '?')) k.append('|'.join([ str(x[0]) for x in v2c.apiPDU.getVarBinds(trunkReq['server-snmp-pdu']) ])) k = '#'.join(k) for x, y in origCredIdList: if y.match(k): origPeerId = trunkReq[ 'server-snmp-entity-id'] = macro.expandMacro(x, trunkReq) break else: origPeerId = None k = [ str(x) for x in (trunkReq['server-snmp-credentials-id'], trunkReq['server-snmp-context-id'], trunkReq['server-snmp-content-id'], trunkReq['server-snmp-peer-id']) ] k = '#'.join(k) for x, y in srvClassIdList: if y.match(k): srvClassId = trunkReq[ 'server-classification-id'] = macro.expandMacro( x, trunkReq) break else: srvClassId = None logCtx = LogString(trunkReq) errorIndication = None peerIdList = routingMap.get( (origPeerId, srvClassId, macro.expandMacro(trunkId, trunkReq))) if not peerIdList: log.error('unroutable trunk message #%s' % msgId, ctx=logCtx) errorIndication = 'no route to SNMP peer configured' cbCtx = trunkId, msgId, trunkReq, (), {} if errorIndication: snmpCbFun(None, None, errorIndication, None, cbCtx) return pluginIdList = pluginIdMap.get( (origPeerId, srvClassId, macro.expandMacro(trunkId, trunkReq))) for peerId in peerIdList: peerId = macro.expandMacro(peerId, trunkReq) trunkReqCopy = trunkReq.copy() (snmpEngine, contextEngineId, contextName, bindAddr, bindAddrMacro, peerAddr, peerAddrMacro) = peerIdMap[peerId] if bindAddrMacro: bindAddr = macro.expandMacro(bindAddrMacro, trunkReqCopy), 0 if peerAddrMacro: peerAddr = macro.expandMacro(peerAddrMacro, trunkReqCopy), 161 if bindAddr and peerAddr: updateEndpoints(bindAddr, peerAddr) trunkReqCopy['snmp-peer-id'] = peerId trunkReqCopy['snmp-context-engine-id'] = contextEngineId trunkReqCopy['snmp-context-name'] = contextName trunkReqCopy['snmp-bind-address'], trunkReqCopy[ 'snmp-bind-port'] = bindAddr trunkReqCopy['snmp-peer-address'], trunkReqCopy[ 'snmp-peer-port'] = peerAddr logCtx.update(trunkReqCopy) pdu = trunkReqCopy['server-snmp-pdu'] if pluginIdList: reqCtx = {} cbCtx = trunkId, msgId, trunkReqCopy, pluginIdList, reqCtx for pluginNum, pluginId in enumerate(pluginIdList): if pdu.tagSet in rfc3411.notificationClassPDUs: st, pdu = pluginManager.processNotificationRequest( pluginId, snmpEngine, pdu, trunkReqCopy, reqCtx) elif pdu.tagSet not in rfc3411.unconfirmedClassPDUs: st, pdu = pluginManager.processCommandRequest( pluginId, snmpEngine, pdu, trunkReqCopy, reqCtx) else: log.error('ignoring unsupported PDU', ctx=logCtx) break if st == status.BREAK: log.debug('plugin %s inhibits other plugins' % pluginId, ctx=logCtx) cbCtx = trunkId, msgId, trunkReqCopy, pluginIdList[: pluginNum], reqCtx break elif st == status.DROP: log.debug( 'received trunk message #%s, plugin %s muted request' % (msgId, pluginId), ctx=logCtx) snmpCbFun(snmpEngine, None, None, None, cbCtx) return elif st == status.RESPOND: log.debug( 'received trunk message #%s, plugin %s forced immediate response' % (msgId, pluginId), ctx=logCtx) snmpCbFun(snmpEngine, None, None, pdu, cbCtx) return snmpMessageSent = False if pdu.tagSet in rfc3411.notificationClassPDUs: if pdu.tagSet in rfc3411.unconfirmedClassPDUs: try: notificationOriginator.sendPdu( snmpEngine, peerId, macro.expandMacro(contextEngineId, trunkReq), macro.expandMacro(contextName, trunkReq), pdu) snmpMessageSent = True except PySnmpError: errorIndication = 'failure sending SNMP notification' log.error('trunk message #%s, SNMP error: %s' % (msgId, sys.exc_info()[1]), ctx=logCtx) else: errorIndication = None # respond to trunk right away snmpCbFun(snmpEngine, None, errorIndication, None, cbCtx) else: try: notificationOriginator.sendPdu( snmpEngine, peerId, macro.expandMacro(contextEngineId, trunkReq), macro.expandMacro(contextName, trunkReq), pdu, snmpCbFun, cbCtx) snmpMessageSent = True except PySnmpError: log.error('trunk message #%s, SNMP error: %s' % (msgId, sys.exc_info()[1]), ctx=logCtx) elif pdu.tagSet not in rfc3411.unconfirmedClassPDUs: try: commandGenerator.sendPdu( snmpEngine, peerId, macro.expandMacro(contextEngineId, trunkReq), macro.expandMacro(contextName, trunkReq), pdu, snmpCbFun, cbCtx) snmpMessageSent = True except PySnmpError: errorIndication = 'failure sending SNMP command' log.error('trunk message #%s, SNMP error: %s' % (msgId, sys.exc_info()[1]), ctx=logCtx) # respond to trunk right away snmpCbFun(snmpEngine, None, errorIndication, None, cbCtx) else: log.error('ignoring unsupported PDU', ctx=logCtx) if snmpMessageSent: log.debug( 'received trunk message #%s, forwarded as SNMP message' % msgId, ctx=logCtx) # # Main script body starts here # helpMessage = """\ Usage: %s [--help] [--version ] [--debug-snmp=<%s>] [--debug-asn1=<%s>] [--daemonize] [--process-user=<uname>] [--process-group=<gname>] [--pid-file=<file>] [--logging-method=<%s[:args>]>] [--log-level=<%s>] [--config-file=<file>]""" % (sys.argv[0], '|'.join([ x for x in getattr(pysnmp_debug, 'FLAG_MAP', getattr(pysnmp_debug, 'flagMap', ())) if x != 'mibview' ]), '|'.join([ x for x in getattr(pyasn1_debug, 'FLAG_MAP', getattr(pyasn1_debug, 'flagMap', ())) ]), '|'.join(log.methodsMap), '|'.join(log.levelsMap)) try: opts, params = getopt.getopt(sys.argv[1:], 'hv', [ 'help', 'version', 'debug=', 'debug-snmp=', 'debug-asn1=', 'daemonize', 'process-user='******'process-group=', 'pid-file=', 'logging-method=', 'log-level=', 'config-file=' ]) except Exception: sys.stderr.write('ERROR: %s\r\n%s\r\n' % (sys.exc_info()[1], helpMessage)) return if params: sys.stderr.write('ERROR: extra arguments supplied %s\r\n%s\r\n' % (params, helpMessage)) return pidFile = '' cfgFile = CONFIG_FILE foregroundFlag = True procUser = procGroup = None loggingMethod = ['stderr'] loggingLevel = None for opt in opts: if opt[0] == '-h' or opt[0] == '--help': sys.stderr.write("""\ Synopsis: SNMP Proxy Forwarder: client part. Receives SNMP PDUs via one or many encrypted trunks established with the Forwarder's Agent part(s) running elsewhere and routes PDUs to built-in SNMP Managers for further transmission towards SNMP Agents. Can implement complex routing and protocol conversion logic through analyzing parts of SNMP messages and matching them against proxying rules. Documentation: http://snmplabs.com/snmpfwd/ %s """ % helpMessage) return if opt[0] == '-v' or opt[0] == '--version': import snmpfwd import pysnmp import pyasn1 sys.stderr.write("""\ SNMP Proxy Forwarder version %s, written by Ilya Etingof <*****@*****.**> Using foundation libraries: pysnmp %s, pyasn1 %s. Python interpreter: %s Software documentation and support at http://snmplabs.com/snmpfwd/ %s """ % (snmpfwd.__version__, hasattr(pysnmp, '__version__') and pysnmp.__version__ or 'unknown', hasattr(pyasn1, '__version__') and pyasn1.__version__ or 'unknown', sys.version, helpMessage)) return elif opt[0] == '--debug-snmp': pysnmp_debug.setLogger( pysnmp_debug.Debug(*opt[1].split(','), **dict(loggerName=PROGRAM_NAME + '.pysnmp'))) elif opt[0] == '--debug-asn1': pyasn1_debug.setLogger( pyasn1_debug.Debug(*opt[1].split(','), **dict(loggerName=PROGRAM_NAME + '.pyasn1'))) elif opt[0] == '--daemonize': foregroundFlag = False elif opt[0] == '--process-user': procUser = opt[1] elif opt[0] == '--process-group': procGroup = opt[1] elif opt[0] == '--pid-file': pidFile = opt[1] elif opt[0] == '--logging-method': loggingMethod = opt[1].split(':') elif opt[0] == '--log-level': loggingLevel = opt[1] elif opt[0] == '--config-file': cfgFile = opt[1] with daemon.PrivilegesOf(procUser, procGroup): try: log.setLogger(PROGRAM_NAME, *loggingMethod, **dict(force=True)) if loggingLevel: log.setLevel(loggingLevel) except SnmpfwdError: sys.stderr.write('%s\r\n%s\r\n' % (sys.exc_info()[1], helpMessage)) return try: cfgTree = cparser.Config().load(cfgFile) except SnmpfwdError: log.error('configuration parsing error: %s' % sys.exc_info()[1]) return if cfgTree.getAttrValue('program-name', '', default=None) != PROGRAM_NAME: log.error('config file %s does not match program name %s' % (cfgFile, PROGRAM_NAME)) return if cfgTree.getAttrValue('config-version', '', default=None) != CONFIG_VERSION: log.error( 'config file %s version is not compatible with program version %s' % (cfgFile, CONFIG_VERSION)) return random.seed() # # SNMPv3 CommandGenerator & NotificationOriginator implementation # origCredIdList = [] srvClassIdList = [] peerIdMap = {} pluginIdMap = {} routingMap = {} engineIdMap = {} commandGenerator = cmdgen.CommandGenerator() notificationOriginator = ntforg.NotificationOriginator() transportDispatcher = AsynsockDispatcher() transportDispatcher.registerRoutingCbFun(lambda td, t, d: td) transportDispatcher.setSocketMap() # use global asyncore socket map pluginManager = PluginManager(macro.expandMacros( cfgTree.getAttrValue('plugin-modules-path-list', '', default=[], vector=True), {'config-dir': os.path.dirname(cfgFile)}), progId=PROGRAM_NAME, apiVer=PLUGIN_API_VERSION) for pluginCfgPath in cfgTree.getPathsToAttr('plugin-id'): pluginId = cfgTree.getAttrValue('plugin-id', *pluginCfgPath) pluginMod = cfgTree.getAttrValue('plugin-module', *pluginCfgPath) pluginOptions = macro.expandMacros( cfgTree.getAttrValue('plugin-options', *pluginCfgPath, **dict(default=[], vector=True)), {'config-dir': os.path.dirname(cfgFile)}) log.info( 'configuring plugin ID %s (at %s) from module %s with options %s...' % (pluginId, '.'.join(pluginCfgPath), pluginMod, ', '.join(pluginOptions) or '<none>')) with daemon.PrivilegesOf(procUser, procGroup): try: pluginManager.loadPlugin(pluginId, pluginMod, pluginOptions) except SnmpfwdError: log.error('plugin %s not loaded: %s' % (pluginId, sys.exc_info()[1])) return for peerEntryPath in cfgTree.getPathsToAttr('snmp-peer-id'): peerId = cfgTree.getAttrValue('snmp-peer-id', *peerEntryPath) if peerId in peerIdMap: log.error('duplicate snmp-peer-id=%s at %s' % (peerId, '.'.join(peerEntryPath))) return log.info('configuring SNMP peer %s (at %s)...' % (peerId, '.'.join(peerEntryPath))) engineId = cfgTree.getAttrValue('snmp-engine-id', *peerEntryPath) if engineId in engineIdMap: snmpEngine, snmpContext, snmpEngineMap = engineIdMap[engineId] log.info('using engine-id: %s' % snmpEngine.snmpEngineID.prettyPrint()) else: snmpEngine = engine.SnmpEngine(snmpEngineID=engineId) snmpContext = context.SnmpContext(snmpEngine) snmpEngineMap = { 'transportDomain': {}, 'securityName': {}, 'credIds': set() } engineIdMap[engineId] = snmpEngine, snmpContext, snmpEngineMap log.info('new engine-id %s' % snmpEngine.snmpEngineID.prettyPrint()) transportDomain = cfgTree.getAttrValue('snmp-transport-domain', *peerEntryPath) transportDomain = rfc1902.ObjectName(str(transportDomain)) if (transportDomain[:len(udp.domainName)] != udp.domainName and udp6 and transportDomain[:len(udp6.domainName)] != udp6.domainName): log.error('unknown transport domain %s' % (transportDomain, )) return transportOptions = cfgTree.getAttrValue( 'snmp-transport-options', *peerEntryPath, **dict(default=[], vector=True)) bindAddr = cfgTree.getAttrValue('snmp-bind-address', *peerEntryPath) try: bindAddr, bindAddrMacro = endpoint.parseTransportAddress( transportDomain, bindAddr, transportOptions) except SnmpfwdError: log.error('bad snmp-bind-address specification %s at %s' % (bindAddr, '.'.join(peerEntryPath))) return if transportDomain in snmpEngineMap['transportDomain']: log.info('using transport endpoint with transport ID %s' % (transportDomain, )) else: if transportDomain[:len(udp.domainName)] == udp.domainName: transport = udp.UdpTransport() else: transport = udp6.Udp6Transport() snmpEngine.registerTransportDispatcher(transportDispatcher, transportDomain) t = transport.openClientMode(bindAddr) if 'transparent-proxy' in transportOptions: t.enablePktInfo() t.enableTransparent() elif 'virtual-interface' in transportOptions: t.enablePktInfo() config.addSocketTransport(snmpEngine, transportDomain, t) snmpEngineMap['transportDomain'][transportDomain] = bindAddr[ 0], bindAddr[1], transportDomain log.info( 'new transport endpoint at bind address [%s]:%s, options %s, transport ID %s' % (bindAddr[0], bindAddr[1], transportOptions and '/'.join(transportOptions) or '<none>', transportDomain)) securityModel = cfgTree.getAttrValue('snmp-security-model', *peerEntryPath) securityModel = rfc1902.Integer(securityModel) securityLevel = cfgTree.getAttrValue('snmp-security-level', *peerEntryPath) securityLevel = rfc1902.Integer(securityLevel) securityName = cfgTree.getAttrValue('snmp-security-name', *peerEntryPath) contextEngineId = cfgTree.getAttrValue('snmp-context-engine-id', *peerEntryPath, **dict(default=None)) contextName = cfgTree.getAttrValue('snmp-context-name', *peerEntryPath, **dict(default='')) if securityModel in (1, 2): if securityName in snmpEngineMap['securityName']: if snmpEngineMap['securityName'][ securityName] == securityModel: log.info('using security-name %s' % securityName) else: log.error( 'security-name %s already in use at security-model %s' % (securityName, securityModel)) return else: communityName = cfgTree.getAttrValue('snmp-community-name', *peerEntryPath) config.addV1System(snmpEngine, securityName, communityName, securityName=securityName) log.info( 'new community-name %s, security-model %s, security-name %s, security-level %s' % (communityName, securityModel, securityName, securityLevel)) snmpEngineMap['securityName'][securityName] = securityModel elif securityModel == 3: if securityName in snmpEngineMap['securityName']: if snmpEngineMap['securityName'][ securityName] == securityModel: log.info('using USM security-name: %s' % securityName) else: raise SnmpfwdError( 'security-name %s already in use at security-model %s' % (securityName, securityModel)) else: usmUser = cfgTree.getAttrValue('snmp-usm-user', *peerEntryPath) securityEngineId = cfgTree.getAttrValue( 'snmp-security-engine-id', *peerEntryPath, **dict(default=None)) if securityEngineId: securityEngineId = rfc1902.OctetString(securityEngineId) log.info( 'new USM user %s, security-model %s, security-level %s, ' 'security-name %s, security-engine-id %s' % (usmUser, securityModel, securityLevel, securityName, securityEngineId and securityEngineId.prettyPrint() or '<none>')) if securityLevel in (2, 3): usmAuthProto = cfgTree.getAttrValue( 'snmp-usm-auth-protocol', *peerEntryPath, **dict(default=config.usmHMACMD5AuthProtocol)) try: usmAuthProto = authProtocols[usmAuthProto.upper()] except KeyError: pass usmAuthProto = rfc1902.ObjectName(usmAuthProto) usmAuthKey = cfgTree.getAttrValue('snmp-usm-auth-key', *peerEntryPath) log.info( 'new USM authentication key: %s, authentication protocol: %s' % (usmAuthKey, usmAuthProto)) if securityLevel == 3: usmPrivProto = cfgTree.getAttrValue( 'snmp-usm-priv-protocol', *peerEntryPath, **dict(default=config.usmDESPrivProtocol)) try: usmPrivProto = privProtocols[usmPrivProto.upper()] except KeyError: pass usmPrivProto = rfc1902.ObjectName(usmPrivProto) usmPrivKey = cfgTree.getAttrValue( 'snmp-usm-priv-key', *peerEntryPath, **dict(default=None)) log.info( 'new USM encryption key: %s, encryption protocol: %s' % (usmPrivKey, usmPrivProto)) config.addV3User( snmpEngine, usmUser, usmAuthProto, usmAuthKey, usmPrivProto, usmPrivKey, ) else: config.addV3User(snmpEngine, usmUser, usmAuthProto, usmAuthKey, securityEngineId=securityEngineId) else: config.addV3User(snmpEngine, usmUser, securityEngineId=securityEngineId) snmpEngineMap['securityName'][securityName] = securityModel else: log.error('unknown security-model: %s' % securityModel) sys.exit(1) credId = '/'.join( [str(x) for x in (securityName, securityLevel, securityModel)]) if credId in snmpEngineMap['credIds']: log.info('using credentials ID %s...' % credId) else: config.addTargetParams( snmpEngine, credId, securityName, securityLevel, securityModel == 3 and 3 or securityModel - 1) log.info( 'new credentials %s, security-name %s, security-level %s, security-model %s' % (credId, securityName, securityLevel, securityModel)) snmpEngineMap['credIds'].add(credId) peerAddr = cfgTree.getAttrValue('snmp-peer-address', *peerEntryPath) try: peerAddr, peerAddrMacro = endpoint.parseTransportAddress( transportDomain, peerAddr, transportOptions, defaultPort=161) except SnmpfwdError: log.error('bad snmp-peer-address specification %s at %s' % (peerAddr, '.'.join(peerEntryPath))) return timeout = cfgTree.getAttrValue('snmp-peer-timeout', *peerEntryPath) retries = cfgTree.getAttrValue('snmp-peer-retries', *peerEntryPath) config.addTargetAddr(snmpEngine, peerId, transportDomain, peerAddr, credId, timeout, retries) peerIdMap[ peerId] = snmpEngine, contextEngineId, contextName, bindAddr, bindAddrMacro, peerAddr, peerAddrMacro log.info( 'new peer ID %s, bind address %s, peer address %s, timeout %s*0.01 secs, retries %s, credentials ID %s' % (peerId, bindAddrMacro or '<default>', peerAddrMacro or '%s:%s' % peerAddr, timeout, retries, credId)) duplicates = {} # TODO: rename orig-* into server-* and orig-snmp-peer-id into server-snmp-entity-id for origCredCfgPath in cfgTree.getPathsToAttr('orig-snmp-peer-id'): origCredId = cfgTree.getAttrValue('orig-snmp-peer-id', *origCredCfgPath) if origCredId in duplicates: log.error('duplicate orig-snmp-peer-id=%s at %s and %s' % (origCredId, '.'.join(origCredCfgPath), '.'.join( duplicates[origCredId]))) return duplicates[origCredId] = origCredCfgPath k = '#'.join( (cfgTree.getAttrValue('orig-snmp-engine-id-pattern', *origCredCfgPath), cfgTree.getAttrValue('orig-snmp-transport-domain-pattern', *origCredCfgPath), cfgTree.getAttrValue('orig-snmp-peer-address-pattern', *origCredCfgPath), cfgTree.getAttrValue('orig-snmp-bind-address-pattern', *origCredCfgPath), cfgTree.getAttrValue('orig-snmp-security-model-pattern', *origCredCfgPath), cfgTree.getAttrValue('orig-snmp-security-level-pattern', *origCredCfgPath), cfgTree.getAttrValue('orig-snmp-security-name-pattern', *origCredCfgPath), cfgTree.getAttrValue('orig-snmp-context-engine-id-pattern', *origCredCfgPath), cfgTree.getAttrValue('orig-snmp-context-name-pattern', *origCredCfgPath), cfgTree.getAttrValue('orig-snmp-pdu-type-pattern', *origCredCfgPath), cfgTree.getAttrValue('orig-snmp-oid-prefix-pattern', *origCredCfgPath))) log.info( 'configuring original SNMP peer ID %s (at %s), composite key: %s' % (origCredId, '.'.join(origCredCfgPath), k)) origCredIdList.append((origCredId, re.compile(k))) duplicates = {} for srvClassCfgPath in cfgTree.getPathsToAttr('server-classification-id'): srvClassId = cfgTree.getAttrValue('server-classification-id', *srvClassCfgPath) if srvClassId in duplicates: log.error('duplicate server-classification-id=%s at %s and %s' % (srvClassId, '.'.join(srvClassCfgPath), '.'.join( duplicates[srvClassId]))) return duplicates[srvClassId] = srvClassCfgPath k = '#'.join( (cfgTree.getAttrValue('server-snmp-credentials-id-pattern', *srvClassCfgPath), cfgTree.getAttrValue('server-snmp-context-id-pattern', *srvClassCfgPath), cfgTree.getAttrValue('server-snmp-content-id-pattern', *srvClassCfgPath), cfgTree.getAttrValue('server-snmp-peer-id-pattern', *srvClassCfgPath))) log.info( 'configuring server classification ID %s (at %s), composite key: %s' % (srvClassId, '.'.join(srvClassCfgPath), k)) srvClassIdList.append((srvClassId, re.compile(k))) del duplicates for pluginCfgPath in cfgTree.getPathsToAttr('using-plugin-id-list'): pluginIdList = cfgTree.getAttrValue('using-plugin-id-list', *pluginCfgPath, **dict(vector=True)) log.info('configuring plugin ID(s) %s (at %s)...' % (','.join(pluginIdList), '.'.join(pluginCfgPath))) for credId in cfgTree.getAttrValue('matching-orig-snmp-peer-id-list', *pluginCfgPath, **dict(vector=True)): for srvClassId in cfgTree.getAttrValue( 'matching-server-classification-id-list', *pluginCfgPath, **dict(vector=True)): for trunkId in cfgTree.getAttrValue('matching-trunk-id-list', *pluginCfgPath, **dict(vector=True)): k = credId, srvClassId, trunkId if k in pluginIdMap: log.error( 'duplicate snmp-credentials-id=%s and server-classification-id=%s and trunk-id=%s at plugin-id %s' % (credId, srvClassId, trunkId, ','.join(pluginIdList))) return else: log.info( 'configuring plugin(s) %s (at %s), composite key: %s' % (','.join(pluginIdList), '.'.join(pluginCfgPath), '/'.join(k))) for pluginId in pluginIdList: if not pluginManager.hasPlugin(pluginId): log.error( 'undefined plugin ID %s referenced at %s' % (pluginId, '.'.join(pluginCfgPath))) return pluginIdMap[k] = pluginIdList for routeCfgPath in cfgTree.getPathsToAttr('using-snmp-peer-id-list'): peerIdList = cfgTree.getAttrValue('using-snmp-peer-id-list', *routeCfgPath, **dict(vector=True)) log.info('configuring routing entry with peer IDs %s (at %s)...' % (','.join(peerIdList), '.'.join(routeCfgPath))) for credId in cfgTree.getAttrValue('matching-orig-snmp-peer-id-list', *routeCfgPath, **dict(vector=True)): for srvClassId in cfgTree.getAttrValue( 'matching-server-classification-id-list', *routeCfgPath, **dict(vector=True)): for trunkId in cfgTree.getAttrValue('matching-trunk-id-list', *routeCfgPath, **dict(vector=True)): k = credId, srvClassId, trunkId if k in routingMap: log.error( 'duplicate snmp-credentials-id=%s and server-classification-id=%s and trunk-id=%s at snmp-peer-id %s' % (credId, srvClassId, trunkId, ','.join(peerIdList))) return else: for peerId in peerIdList: if peerId not in peerIdMap: log.error('missing peer-id %s at %s' % (peerId, '.'.join(routeCfgPath))) return routingMap[k] = peerIdList trunkingManager = TrunkingManager(trunkCbFun) for trunkCfgPath in cfgTree.getPathsToAttr('trunk-id'): trunkId = cfgTree.getAttrValue('trunk-id', *trunkCfgPath) secret = cfgTree.getAttrValue('trunk-crypto-key', *trunkCfgPath, **dict(default='')) secret = secret and (secret * ((16 // len(secret)) + 1))[:16] log.info('configuring trunk ID %s (at %s)...' % (trunkId, '.'.join(trunkCfgPath))) connectionMode = cfgTree.getAttrValue('trunk-connection-mode', *trunkCfgPath) if connectionMode == 'client': trunkingManager.addClient( trunkId, parseTrunkEndpoint( cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath)), parseTrunkEndpoint( cfgTree.getAttrValue('trunk-peer-address', *trunkCfgPath), 30201), cfgTree.getAttrValue('trunk-ping-period', *trunkCfgPath, default=0, expect=int), secret) log.info( 'new trunking client from %s to %s' % (cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath), cfgTree.getAttrValue('trunk-peer-address', *trunkCfgPath))) if connectionMode == 'server': trunkingManager.addServer( parseTrunkEndpoint( cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath), 30201), cfgTree.getAttrValue('trunk-ping-period', *trunkCfgPath, default=0, expect=int), secret) log.info( 'new trunking server at %s' % (cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath))) transportDispatcher.registerTimerCbFun(trunkingManager.setupTrunks, random.randrange(1, 5)) transportDispatcher.registerTimerCbFun(trunkingManager.monitorTrunks, random.randrange(1, 5)) if not foregroundFlag: try: daemon.daemonize(pidFile) except Exception: log.error('can not daemonize process: %s' % sys.exc_info()[1]) return # Run mainloop log.info('starting I/O engine...') transportDispatcher.jobStarted(1) # server job would never finish # Python 2.4 does not support the "finally" clause with daemon.PrivilegesOf(procUser, procGroup, final=True): while True: try: transportDispatcher.runDispatcher() except (PySnmpError, SnmpfwdError, socket.error): log.error(str(sys.exc_info()[1])) continue except Exception: transportDispatcher.closeDispatcher() raise