def run(self): snmpEngine = engine.SnmpEngine() if self.ipv6: domainName = udp6.domainName config.addSocketTransport(snmpEngine, domainName, udp6.Udp6Transport().openServerMode((self.host, self.port))) else: domainName = udp.domainName config.addSocketTransport(snmpEngine, domainName, udp.UdpTransport().openServerMode((self.host, self.port))) config.addV3User(snmpEngine, self.user, self.auth_proto, self.auth_key, self.priv_proto, self.priv_key) # Register SNMP Application at the SNMP engine ntfrcv.NotificationReceiver(snmpEngine, v3trap_callback) snmpEngine.transportDispatcher.jobStarted(1) # this job would never finish # Run I/O dispatcher which would receive queries and send confirmations try: snmpEngine.transportDispatcher.runDispatcher() except: # catch *all* exceptions e = sys.exc_info()[1] snmpEngine.transportDispatcher.closeDispatcher() logging.error("Looks like an error: %s" % str(e)) sys.exit(1)
def run(self) -> None: self.snmpEngine = engine.SnmpEngine() config.addSocketTransport( self.snmpEngine, udp.domainName, udp.UdpTransport().openServerMode(('127.0.0.1', 1161)) ) config.addV1System(self.snmpEngine, 'my-area', 'public', contextName='my-context') config.addVacmUser(self.snmpEngine, 2, 'my-area', 'noAuthNoPriv', (1, 3, 6), (1, 3, 6)) snmpContext = context.SnmpContext(self.snmpEngine) class SimpleController(instrum.AbstractMibInstrumController): def readVars(self, varBinds, acInfo=(None, None)): return [(ov[0], v2c.Integer(random.uniform(120, 140))) for ov in varBinds] snmpContext.registerContextName( v2c.OctetString('my-context'), # Context Name SimpleController() # Management Instrumentation ) cmdrsp.GetCommandResponder(self.snmpEngine, snmpContext) # cmdrsp.SetCommandResponder(self.snmpEngine, snmpContext) self.snmpEngine.transportDispatcher.jobStarted(1) try: self.snmpEngine.transportDispatcher.runDispatcher() except: self.snmpEngine.transportDispatcher.closeDispatcher() raise
def __init__(self, controller, cfg): threading.Thread.__init__(self) self.controller = controller self.cfg = cfg self.snmp_engine = engine.SnmpEngine() self.count = 0 # Transport setup ipv4 = True if IPAddress(self.cfg.snmp.snmp_ip).version == 6: ipv4 = False # Transport setup if ipv4: # UDP over IPv4, first listening interface/port config.addSocketTransport( self.snmp_engine, udp.domainName + (1, ), udp.UdpTransport().openServerMode( (self.cfg.snmp.snmp_ip, self.cfg.snmp.snmp_port))) else: # UDP over IPv6, first listening interface/port config.addSocketTransport( self.snmp_engine, udp6.domainName + (1, ), udp6.Udp6Transport().openServerMode( (self.cfg.snmp.snmp_ip, self.cfg.snmp.snmp_port))) # SecurityName <-> CommunityName mapping config.addV1System(self.snmp_engine, self.cfg.snmp.snmp_sec_area, self.cfg.snmp.snmp_comm_str) ntfrcv.NotificationReceiver(self.snmp_engine, self.cb_fun)
def __init__(self, mibObjects): """ mibObjects - a list of MibObject tuples that this agent will serve """ #each SNMP-based application has an engine self._snmpEngine = engine.SnmpEngine() #open a UDP socket on port 161 to listen for snmp requests config.addSocketTransport(self._snmpEngine, udp.domainName, udp.UdpTransport().openServerMode(('', 161))) #Here we configure two distinct Community Strings to control read and write #operations. public --> Read only, private --> Read/Write config.addV1System(self._snmpEngine, "agent", "public") config.addV1System(self._snmpEngine, 'my-write-area', 'private') #let anyone accessing 'public' read anything in the subtree below, #which is the enterprises subtree that we defined our MIB to be in config.addVacmUser(self._snmpEngine, 2, "agent", "noAuthNoPriv", readSubTree=(1,3,6,1,4,1)) #let anyone accessing 'private' read and write anything in the subtree below, #which is the enterprises subtree that we defined our MIB to be in config.addVacmUser(self._snmpEngine, 2, 'my-write-area', 'noAuthNoPriv', readSubTree=(1, 3, 6, 1, 4, 1), writeSubTree=(1, 3, 6, 1, 4, 1)) #Create Agent context self._snmpContext = context.SnmpContext(self._snmpEngine) #the builder is used to load mibs. tell it to look in the #current directory for our new MIB. We'll also use it to #export our symbols later mibBuilder = self._snmpContext.getMibInstrum().getMibBuilder() mibSources = mibBuilder.getMibSources() + (builder.DirMibSource('.'),) mibBuilder.setMibSources(*mibSources) MibScalarInstance, = mibBuilder.importSymbols('SNMPv2-SMI', 'MibScalarInstance') #export our custom mib for mibObject in mibObjects: nextVar, = mibBuilder.importSymbols(mibObject.mibName, mibObject.objectType) instance = createVariable(MibScalarInstance, mibObject.valueFunc, mibObject.valueSetFunc, nextVar.name, (0,), nextVar.syntax) #need to export as <var name>Instance instanceDict = {str(nextVar.name)+"Instance":instance} mibBuilder.exportSymbols(mibObject.mibName, **instanceDict) # tell pysnmp to respond to get, set, getnext, and getbulk cmdrsp.GetCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.SetCommandResponder(self._snmpEngine,self._snmpContext) cmdrsp.NextCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.BulkCommandResponder(self._snmpEngine, self._snmpContext)
def __init__(self, host, port, users, naming_scheme): """ host = public ip to listen on port = port to listen on (usually 161) users = list of ('username', 'password', 'privatekey', 'authPriv') #authentication method for snmp v3 if users is None, authentication will be snmp v1 public community string, read only """ self.naming_scheme = naming_scheme self.run = True self.users = users # Create SNMP engine self.snmpEngine = engine.SnmpEngine() # Get default SNMP context this SNMP engine serves self.snmpContext = context.SnmpContext(self.snmpEngine) # MIB builder self.mibBuilder = self.snmpContext.getMibInstrum().getMibBuilder() self.MibScalar, self.MibScalarInstance = self.mibBuilder.importSymbols( 'SNMPv2-SMI', 'MibScalar', 'MibScalarInstance') # Transport setup # UDP over IPv4 try: config.addSocketTransport( self.snmpEngine, udp.domainName, udp.UdpTransport().openServerMode((host, port))) print('Serving on port %s' % port) except error.CarrierError as carrier_error: if "[Errno 98]" in carrier_error.message: raise RuntimeError('Port %s is in use' % port) # SNMPv3/USM setup # user: usr-md5-des, auth: MD5, priv DES if users: for user in users: self._add_v3_md5_des_user(user) # Allow full MIB access for each user at VACM else: # SNMPv1 public community string setup config.addV1System(self.snmpEngine, 'my-read-area', 'public') self._add_user_permission( "1.3.6.1.2.1" ) #full walk permission, without this snmpwalk returns None # Overwrite default strings with custom name sysDescr, = self.snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMPv2-MIB', 'sysDescr') sysDescr = self.MibScalarInstance( sysDescr.name, (0, ), sysDescr.syntax.clone( "PySNMP engine - OVS 1.2.0 SNMP Agent")) # Get from config? self.snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.exportSymbols( 'SNMPv2-MIB', sysDescr) self._add_user_permission(self.naming_scheme.replace('.%s', ''))
def __init__(self, host, port, rcommunity): self.snmpEngine = engine.SnmpEngine() config.addSocketTransport(self.snmpEngine, udp.domainName, udp.UdpTransport().openServerMode((host, port))) config.addV1System(self.snmpEngine, 'my-area', rcommunity) config.addVacmUser(self.snmpEngine, 2, 'my-area', 'noAuthNoPriv', (1, 3, 6)) self.snmpContext = context.SnmpContext(self.snmpEngine) self.mibBuilder = self.snmpContext.getMibInstrum().getMibBuilder() self.MibScalar, self.MibScalarInstance = self.mibBuilder.importSymbols('SNMPv2-SMI', 'MibScalar', 'MibScalarInstance') cmdrsp.GetCommandResponder(self.snmpEngine, self.snmpContext) cmdrsp.NextCommandResponder(self.snmpEngine, self.snmpContext) cmdrsp.BulkCommandResponder(self.snmpEngine, self.snmpContext)
def __init__(self, mibObjects): """ mibObjects - a list of MibObject tuples that this agent will serve """ #each SNMP-based application has an engine self._snmpEngine = engine.SnmpEngine() #open a UDP socket to listen for snmp requests config.addSocketTransport(self._snmpEngine, udp.domainName, udp.UdpTransport().openServerMode(('', 161))) #add a v2 user with the community string public config.addV1System(self._snmpEngine, "agent", "public") #let anyone accessing 'public' read anything in the subtree below, #which is the enterprises subtree that we defined our MIB to be in config.addVacmUser(self._snmpEngine, 2, "agent", "noAuthNoPriv", readSubTree=(1, 3, 6, 1, 4, 1)) #each app has one or more contexts self._snmpContext = context.SnmpContext(self._snmpEngine) #the builder is used to load mibs. tell it to look in the #current directory for our new MIB. We'll also use it to #export our symbols later mibBuilder = self._snmpContext.getMibInstrum().getMibBuilder() mibSources = mibBuilder.getMibSources() + (builder.DirMibSource('.'), ) mibBuilder.setMibSources(*mibSources) mibBuilder.loadModules('HOST-RESOURCES-MIB') #our variables will subclass this since we only have scalar types #can't load this type directly, need to import it MibScalarInstance, = mibBuilder.importSymbols('SNMPv2-SMI', 'MibScalarInstance') #export our custom mib for mibObject in mibObjects: nextVar, = mibBuilder.importSymbols(mibObject.mibName, mibObject.objectType) instance = createVariable(MibScalarInstance, mibObject.valueFunc, nextVar.name, (0, ), nextVar.syntax) #need to export as <var name>Instance instanceDict = {str(nextVar.name) + "Instance": instance} mibBuilder.exportSymbols(mibObject.mibName, **instanceDict) # tell pysnmp to respotd to get, getnext, and getbulk cmdrsp.GetCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.NextCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.BulkCommandResponder(self._snmpEngine, self._snmpContext)
def __init__(self, host, port, mibObjects): self._snmpEngine = engine.SnmpEngine() config.addSocketTransport( self._snmpEngine, udp.domainName, udp.UdpTransport().openServerMode((host, port))) config.addV1System(self._snmpEngine, "agent", "publick") # password config.addV1System(self._snmpEngine, 'my-write-area', 'private') config.addVacmUser(self._snmpEngine, 2, "agent", "noAuthNoPriv", readSubTree=(1, 3, 6, 1, 4, 1)) config.addVacmUser(self._snmpEngine, 2, 'my-write-area', 'noAuthNoPriv', readSubTree=(1, 3, 6, 1, 4, 1), writeSubTree=(1, 3, 6, 1, 4, 1)) self._snmpContext = context.SnmpContext(self._snmpEngine) mibBuilder = self._snmpContext.getMibInstrum().getMibBuilder() mibSources = mibBuilder.getMibSources() + (builder.DirMibSource('.'), ) mibBuilder.setMibSources(*mibSources) MibScalarInstance, = mibBuilder.importSymbols('SNMPv2-SMI', 'MibScalarInstance') for mibObject in mibObjects: nextVar, = mibBuilder.importSymbols(mibObject.mibName, mibObject.objectType) instance = createVariable(MibScalarInstance, mibObject.valueFunc, mibObject.valueSetFunc, nextVar.name, (0, ), nextVar.syntax) instanceDict = {str(nextVar.name) + "Instance": instance} mibBuilder.exportSymbols(mibObject.mibName, **instanceDict) cmdrsp.GetCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.SetCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.NextCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.BulkCommandResponder(self._snmpEngine, self._snmpContext)
def __init__(self, mibObjects): # Each SNMP-based application has an engine self._snmpEngine = engine.SnmpEngine() # Open a UDP socket to listen for snmp requests (requset sudo command) config.addSocketTransport(self._snmpEngine, udp.domainName, udp.UdpTransport().openServerMode(('', 161))) config.addV1System(self._snmpEngine, 'agent', 'public') # add a v2 user with the community string public config.addVacmUser(self._snmpEngine, 2, 'agent', 'noAuthNoPriv', readSubTree=(1, 3, 6, 1, 4, 1), writeSubTree=(1, 3, 6, 1, 4, 1)) # each app has one or more contexts self._snmpContext = context.SnmpContext(self._snmpEngine) # the builder is used to load mibs. tell it to look in the # current directory for our new MIB. We'll also use it to # export our symbols later mibBuilder = self._snmpContext.getMibInstrum().getMibBuilder() mibSources = mibBuilder.getMibSources() + (builder.DirMibSource('.'), ) mibBuilder.setMibSources(*mibSources) # our variables will subclass this since we only have scalar types # can't load this type directly, need to import it (MibTable, MibTableRow, MibTableColumn, MibScalarInstance) = mibBuilder.importSymbols('SNMPv2-SMI', 'MibTable', 'MibTableRow', 'MibTableColumn', 'MibScalarInstance') # import and maintain Table maintaintable = maintainTableThread(0, mibObjects, mibBuilder, MibScalarInstance) maintaintable.start() # tell pysnmp to respotd to get, getnext, and getbulk cmdrsp.GetCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.SetCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.NextCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.BulkCommandResponder(self._snmpEngine, self._snmpContext)
def run(self): snmpEngine = engine.SnmpEngine() config.addSocketTransport( snmpEngine, udp.domainName, udp.UdpTransport().openServerMode(('127.0.0.1', self.__listening_port)) ) config.addV1System( snmpEngine, 'my-area', 'public', contextName='my-context') config.addVacmUser(snmpEngine=snmpEngine, securityModel=2, securityName='my-area', securityLevel='noAuthNoPriv', readSubTree=SNMPAgentResponder.OID_PREFIX, writeSubTree=(), notifySubTree=()) snmpContext = context.SnmpContext(snmpEngine) snmpContext.registerContextName( v2c.OctetString('my-context'), # Context Name self.__responder # Management Instrumentation ) cmdrsp.GetCommandResponder(snmpEngine, snmpContext) snmpEngine.transportDispatcher.jobStarted(1) self.__barrier.wait() # TODO with statement here! try: snmpEngine.transportDispatcher.runDispatcher() except: snmpEngine.transportDispatcher.closeDispatcher() raise
def __init__(self, objects): self._snmpEngine = engine.SnmpEngine() config.addSocketTransport( self._snmpEngine, udp.domainName, udp.UdpTransport().openServerMode((_addr, _port))) config.addV3User(self._snmpEngine, _account, config.usmHMACMD5AuthProtocol, _auth_key, config.usmDESPrivProtocol, _priv_key) config.addVacmUser(self._snmpEngine, 3, _account, "authPriv", (1, 3, 6, 1, 4, 1), (1, 3, 6, 1, 4, 1)) self._snmpContext = context.SnmpContext(self._snmpEngine) #builder create mibBuilder = self._snmpContext.getMibInstrum().getMibBuilder() mibSources = mibBuilder.getMibSources() + ( builder.DirMibSource('.'), ) + (builder.DirMibSource(filepath), ) mibBuilder.setMibSources(*mibSources) MibScalarInstance, = mibBuilder.importSymbols('SNMPv2-SMI', 'MibScalarInstance') for mibObject in objects: nextVar, = mibBuilder.importSymbols(mibObject.mibName, mibObject.objectType) instance = createVariable(MibScalarInstance, mibObject.valueGetFunc, nextVar.name, (0, ), nextVar.syntax) #need to export as <var name>Instance instanceDict = {str(nextVar.name) + "Instance": instance} mibBuilder.exportSymbols(mibObject.mibName, **instanceDict) cmdrsp.GetCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.SetCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.NextCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.BulkCommandResponder(self._snmpEngine, self._snmpContext)
from pysnmp.entity.rfc3413 import cmdrsp, cmdgen, context from pysnmp.proto.api import v2c from pysnmp.proto.acmod import void from pysnmp.carrier.asynsock.dgram import udp # Create SNMP engine with autogenernated engineID and pre-bound # to socket transport dispatcher snmpEngine = engine.SnmpEngine() # Setup UDP over IPv4 transport endpoints # Agent will listen here config.addSocketTransport( snmpEngine, udp.domainName + (1, ), # use transport domain's sub-name udp.UdpTransport().openServerMode(('127.0.0.1', 1161))) # Manager will send packets there config.addSocketTransport( snmpEngine, udp.domainName + (2, ), # use transport domain's sub-name udp.UdpTransport().openClientMode()) # SNMP credentials used by Manager # v1/2 setup config.addV1System(snmpEngine, 'dest-cmt', 'public') # v3 setup config.addV3User(snmpEngine, 'test-user', config.usmHMACMD5AuthProtocol, 'authkey1', config.usmDESPrivProtocol, 'privkey1'
def __init__(self): #each SNMP-based application has an engine self._snmpEngine = engine.SnmpEngine() # Reading configuration self._read_conf() self._serialtcp = SerialHTTPProcess( self._CONF['LOG_DIR'] if 'LOG_DIR' in self._CONF else '') #open a UDP socket to listen for snmp requests port = int(self._CONF['PORT'] ) if 'PORT' in self._CONF and self._CONF['PORT'] else 161 config.addSocketTransport( self._snmpEngine, udp.domainName, udp.UdpTransport().openServerMode(('0.0.0.0', port))) #add a v2 user with the community string public config.addV1System( self._snmpEngine, "read-area", self._CONF['PUBLIC'] if 'PUBLIC' in self._CONF and self._CONF['PUBLIC'] else "public") config.addV1System( self._snmpEngine, 'write-area', self._CONF['PRIVATE'] if 'PRIVATE' in self._CONF and self._CONF['PRIVATE'] else 'private') #let anyone accessing 'public' read anything in the subtree below, #which is the enterprises subtree that we defined our MIB to be in config.addVacmUser(self._snmpEngine, 1, "read-area", "noAuthNoPriv", readSubTree=(1, 3, 6, 1, 2)) #config.addVacmUser(self._snmpEngine, 1, "read-area", "noAuthNoPriv", # readSubTree=(1, 3, 6, 1, 2, 1, 19, 2, 1)) config.addVacmUser(self._snmpEngine, 1, "read-area", "noAuthNoPriv", readSubTree=(1, 3, 6, 1, 4, 1, 332, 11)) config.addVacmUser(self._snmpEngine, 2, "read-area", "noAuthNoPriv", readSubTree=(1, 3, 6, 1, 2, 1, 10, 33)) config.addVacmUser(self._snmpEngine, 2, "read-area", "noAuthNoPriv", readSubTree=(1, 3, 6, 1, 2, 1, 19, 2, 1)) config.addVacmUser(self._snmpEngine, 2, "read-area", "noAuthNoPriv", readSubTree=(1, 3, 6, 1, 4, 1, 332, 11)) # Write Subtree log('before enable write-area') if self._CONF and 'ALLOW' in self._CONF and self._CONF['ALLOW'].lower( ) in 'true': log('Adding Write community with write-area') config.addVacmUser(self._snmpEngine, 1, 'write-area', 'noAuthNoPriv', readSubTree=(1, 3, 6, 1, 2, 1, 10, 33), writeSubTree=(1, 3, 6, 1, 2, 1, 10, 33)) config.addVacmUser(self._snmpEngine, 2, 'write-area', 'noAuthNoPriv', readSubTree=(1, 3, 6, 1, 2, 1, 10, 33), writeSubTree=(1, 3, 6, 1, 2, 1, 10, 33)) config.addVacmUser(self._snmpEngine, 1, 'write-area', 'noAuthNoPriv', readSubTree=(1, 3, 6, 1, 2, 1, 19, 2, 1), writeSubTree=(1, 3, 6, 1, 2, 1, 19, 2, 1)) config.addVacmUser(self._snmpEngine, 2, 'write-area', 'noAuthNoPriv', readSubTree=(1, 3, 6, 1, 2, 1, 19, 2, 1), writeSubTree=(1, 3, 6, 1, 2, 1, 19, 2, 1)) #each app has one or more contexts self._snmpContext = context.SnmpContext(self._snmpEngine) #the builder is used to load mibs. tell it to look in the #MIBS directory for our new MIB. We'll also use it to #export our symbols later mibBuilder = self._snmpContext.getMibInstrum().getMibBuilder() pub = path.join(getcwd(), 'PYSNMP_MIBS') priv = path.join(getcwd(), 'MIBSPY') mibSources = mibBuilder.getMibSources() + ( builder.DirMibSource(pub), ) + (builder.DirMibSource(priv), ) mibBuilder.setMibSources(*mibSources) #export our custom mib self._exportprivMIBS(mibBuilder) self._exportpubMIBS(mibBuilder) # tell pysnmp to respotd to get, getnext, set and getbulk cmdrsp.GetCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.NextCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.SetCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.BulkCommandResponder(self._snmpEngine, self._snmpContext)
# # Transport setup # # Agent section # UDP over IPv6 config.addTransport(snmpEngine, udp6.domainName, udp6.Udp6Transport().openServerMode(('::1', 161))) # Manager section # UDP over IPv4 config.addTransport(snmpEngine, udp.domainName, udp.UdpTransport().openClientMode()) # # SNMPv1/2c setup (Agent role) # # SecurityName <-> CommunityName mapping config.addV1System(snmpEngine, '1-my-area', 'public') # # SNMPv1/v2c setup (Manager role) # # Here we configure securityName lexicographically lesser than '1-my-area' # to let it match first in snmpCommunityTable on response processing. #
def do_run(self): ''' Run sensor. ''' # Too many branches. # pylint: disable=R0912 from pysnmp.error import PySnmpError from pysnmp.entity import engine, config from pysnmp.carrier.asynsock.dgram import udp, udp6 from pysnmp.entity.rfc3413 import ntfrcv from pysnmp.proto.api import v2c # Create SNMP engine with autogenernated engineID and pre-bound # to socket transport dispatcher. snmp_engine = engine.SnmpEngine() # Transport setup. try: socket.inet_pton(socket.AF_INET, self.config['interface_ip']) # UDP over IPv4. config.addSocketTransport( snmp_engine, udp.domainName, udp.UdpTransport().openServerMode( (self.config['interface_ip'], self.config['port']) ) ) except socket.error: try: socket.inet_pton(socket.AF_INET6, self.config['interface_ip']) # UDP over IPv6. config.addSocketTransport( snmp_engine, udp6.domainName, udp6.Udp6Transport().openServerMode( (self.config['interface_ip'], self.config['port']) ) ) except socket.error: self.log('given interface_ip is neither IPv4 nor IPv6 address') return snmpv3_protocols = { 'MD5': config.usmHMACMD5AuthProtocol, 'SHA': config.usmHMACSHAAuthProtocol, 'DES': config.usmDESPrivProtocol, '3DES': config.usm3DESEDEPrivProtocol, 'AES128': config.usmAesCfb128Protocol, 'AES192': config.usmAesCfb192Protocol, 'AES256': config.usmAesCfb256Protocol } def snmpv3_setup_args(version, authentication=None, encryption=None, auth_key=None, encrypt_key=None, device_id=None): ''' Helper function, parses args. ''' # R0913: Too many arguments # pylint: disable=R0913 del version del device_id args = [snmp_engine, 'usr-{}-{}'.format( authentication.lower() if authentication else 'none', encryption.lower() if encryption else 'none' )] if authentication: # Expression not assigned # pylint: disable=W0106 args.append(snmpv3_protocols[authentication]), args.append(auth_key) if encryption: # Expression not assigned # pylint: disable=W0106 args.append(snmpv3_protocols[encryption]), args.append(encrypt_key) return args # Setup devices. for device in self.config['devices']: if device['version'] == 'v3': # SNMPv3 setup. if 'device_id' in device: config.addV3User( *snmpv3_setup_args(**device), contextEngineId=v2c.OctetString(hexValue=device['device_id']) ) else: config.addV3User(*snmpv3_setup_args(**device)) else: # SNMPv1/2c setup. # SecurityName <-> CommunityName mapping. config.addV1System( snmp_engine, device['index'], device['name'] ) def cb_fun(snmp_engine, state_reference, context_engine_id, context_name, var_binds, cb_ctx): # Too many arguments # pylint: disable=R0913 ''' Callback function for receiving notifications. ''' _, transport_address = snmp_engine.msgAndPduDsp.getTransportInfo( state_reference ) for name, val in var_binds: self.send_results(datetime.utcnow(), ( ('sender', transport_address), ('context_engine_id', context_engine_id.prettyPrint()), ('context_name', context_name.prettyPrint()), ('variable_name', name.prettyPrint()), ('variable_value', val.prettyPrint()) )) # Register SNMP Application at the SNMP engine. ntfrcv.NotificationReceiver(snmp_engine, cb_fun) # This job would never finish. snmp_engine.transportDispatcher.jobStarted(1) # Run I/O dispatcher which would receive queries and send confirmations. try: snmp_engine.transportDispatcher.runDispatcher() except PySnmpError as err: snmp_engine.transportDispatcher.closeDispatcher() self.send_results(datetime.utcnow(), (('error', err.message),)) return
# Instantiate and configure SNMP Engines for snmpEngineId, transportDomain, transportAddress in snmpEngineInfo: # Create SNMP engine with specific engineID snmpEngine = engine.SnmpEngine(rfc1902.OctetString(hexValue=snmpEngineId)) # Register SNMP Engine object with transport dispatcher. Request incoming # data from specific transport endpoint to be funneled to this SNMP Engine. snmpEngine.registerTransportDispatcher(transportDispatcher, transportDomain) # Transport setup # UDP over IPv4 config.addTransport(snmpEngine, transportDomain, udp.UdpTransport().openServerMode(transportAddress)) # SNMPv3/USM setup # user: usr-md5-des, auth: MD5, priv DES config.addV3User(snmpEngine, 'usr-md5-des', config.usmHMACMD5AuthProtocol, 'authkey1', config.usmDESPrivProtocol, 'privkey1') # Allow full MIB access for this user / securityModels at VACM config.addVacmUser(snmpEngine, 3, 'usr-md5-des', 'authPriv', (1, 3, 6), (1, 3, 6, 1, 2, 1)) # Get default SNMP context this SNMP engine serves snmpContext = context.SnmpContext(snmpEngine) # Register SNMP Applications at the SNMP engine for particular SNMP context
sys.path.append('../../ExtentionPackages') from pysnmp.entity import engine, config from pysnmp.carrier.asynsock.dgram import udp from pysnmp.entity.rfc3413 import ntfrcv from pysnmp.proto.api import v2c #from sendmail import sendTrapInfo import sys import re # Create SNMP engine with autogenernated engineID and pre-bound snmpEngine = engine.SnmpEngine() config.addSocketTransport( snmpEngine, udp.domainName, udp.UdpTransport().openServerMode(('202.100.1.138', 162))) #Callback function for receiving notifications def cbFun(snmpEngine, stateReference, contextEngineId, contextName, varBinds, cbCtx): # print('Notification received, ContextEngineId "%s", ContextName "%s"' % ( # contextEngineId.prettyPrint(), contextName.prettyPrint() # ) # ) for name, val in varBinds: # print('%s = %s' % (name.prettyPrint(), val.prettyPrint())) name = str(name) val = str(val) trapInfo = '' Interface = ''
def start_listener(self, callback, address=None, port=1162, community='public', timeout=TIMEOUT): ''' Start a TRAP v1/v2c/v3 notification receiver with predefined users. @param callback: Takes these args snmpEngine, stateReference, contextEngineId, contextName, varBinds, cbCtx @param address: The address to listen to @param port: The port to listen to @param community: The community name for v2c Predefined users: usr-md5-des usr-md5-none usr-sha-aes128 Auth: authkey1 Priv: privkey1 ''' if not address: address = get_local_ip(self.host) if timeout < 0: timeout = 10**10 # Create SNMP engine with auto-generated engineID and pre-bound # to socket transport dispatcher snmpEngine = engine.SnmpEngine() # Transport setup if IPAddress(address).version == 4: # UDP over IPv4 domain_oid = udp.domainName transport = udp.UdpTransport() else: # UDP over IPv6 domain_oid = udp6.domainName transport = udp6.Udp6Transport() # Waiting up to TIMEOUT seconds for the port to be released LOG.debug('Waiting for port %s:%d to become available...', address, port) transport = wait(lambda: transport.openServerMode((address, port)), timeout=TIMEOUT, interval=1) LOG.info('Listening for traps on %s:%d...', address, port) config.addSocketTransport(snmpEngine, domain_oid, transport) # Terrible monkey patching!! # But there's no other way to cause the dispatcher loop to end if we # don't get what we expect in a given amount of time. For now that time # is limited to TIMEOUT seconds. end = time.time() + timeout def jobsArePending(self): if self._AbstractTransportDispatcher__jobs and time.time() < end: return 1 else: return 0 snmpEngine.transportDispatcher.__class__.jobsArePending = jobsArePending # SNMPv1/2 setup config.addV1System(snmpEngine, 'test-agent', community) # SNMPv3/USM setup # user: usr-md5-des, auth: MD5, priv DES config.addV3User(snmpEngine, 'usr-md5-des', config.usmHMACMD5AuthProtocol, 'authkey1', config.usmDESPrivProtocol, 'privkey1') # user: usr-md5-des, auth: MD5, priv DES, contextEngineId: 8000000001020304 # this USM entry is used for TRAP receiving purposes config.addV3User( snmpEngine, 'usr-md5-des', config.usmHMACMD5AuthProtocol, 'authkey1', config.usmDESPrivProtocol, 'privkey1', contextEngineId=v2c.OctetString(hexValue='8000000001020304')) # user: usr-md5-none, auth: MD5, priv NONE config.addV3User(snmpEngine, 'usr-md5-none', config.usmHMACMD5AuthProtocol, 'authkey1') # user: usr-md5-none, auth: MD5, priv NONE, contextEngineId: 8000000001020304 # this USM entry is used for TRAP receiving purposes config.addV3User( snmpEngine, 'usr-md5-none', config.usmHMACMD5AuthProtocol, 'authkey1', contextEngineId=v2c.OctetString(hexValue='8000000001020304')) # user: usr-sha-aes128, auth: SHA, priv AES config.addV3User(snmpEngine, 'usr-sha-aes128', config.usmHMACSHAAuthProtocol, 'authkey1', config.usmAesCfb128Protocol, 'privkey1') # user: usr-sha-aes128, auth: SHA, priv AES, contextEngineId: 8000000001020304 # this USM entry is used for TRAP receiving purposes config.addV3User( snmpEngine, 'usr-sha-aes128', config.usmHMACSHAAuthProtocol, 'authkey1', config.usmAesCfb128Protocol, 'privkey1', contextEngineId=v2c.OctetString(hexValue='8000000001020304')) # def sample_callback(snmpEngine, stateReference, contextEngineId, contextName, # varBinds, cbCtx): # print('Notification received, ContextEngineId "%s", ContextName "%s"' % ( # contextEngineId.prettyPrint(), contextName.prettyPrint()) # ) # for name, val in varBinds: # print('%s = %s' % (name.prettyPrint(), val.prettyPrint())) # print # If callback() returns True we'll stop the loop def callback_wrapper(*args, **kwargs): if callback(*args, **kwargs): snmpEngine.transportDispatcher.jobFinished(DEFAULT_JOB) # Register SNMP Application at the SNMP engine ntfrcv.NotificationReceiver(snmpEngine, callback_wrapper) #return address, port t = TrapListener(snmpEngine) t.start() return address, port, t
# $ snmptrap -v2c -c public udp6:[::1]:162 123 1.3.6.1.6.3.1.1.5.1 1.3.6.1.2.1.1.5.0 s test # $ snmpinform -v2c -c public 127.0.0.1 123 1.3.6.1.6.3.1.1.5.1 # from pysnmp.entity import engine, config from pysnmp.carrier.asynsock.dgram import udp, udp6 from pysnmp.entity.rfc3413 import ntfrcv # Create SNMP engine with autogenernated engineID and pre-bound # to socket transport dispatcher snmpEngine = engine.SnmpEngine() # Transport setup # UDP over IPv4 config.addTransport(snmpEngine, udp.domainName, udp.UdpTransport().openServerMode(('127.0.0.1', 162))) # UDP over IPv6 config.addTransport(snmpEngine, udp6.domainName, udp6.Udp6Transport().openServerMode(('::1', 162))) # SNMPv1/2c setup # SecurityName <-> CommunityName mapping config.addV1System(snmpEngine, 'my-area', 'public') # Callback function for receiving notifications def cbFun(snmpEngine, stateReference, contextEngineId, contextName, varBinds, cbCtx): transportDomain, transportAddress = snmpEngine.msgAndPduDsp.getTransportInfo(
logger.error('Some error in configfile %s' % (e)) SENDER = os.environ.get('SENDER') SENDER_PWD = os.environ.get('SENDER_PWD') if not SENDER or not SENDER_PWD: logger.warn('Either smtp env not set ') Send_mail = Async_smtp(mail_host=mail_host, sender=SENDER, sender_pwd=SENDER_PWD) # Transport setup # UDP over IPv4 config.addSocketTransport(snmpEngine, udp.domainName, udp.UdpTransport().openServerMode(('0.0.0.0', 162))) # SNMPv3/USM setup # user: usr-sha-aes128, auth: SHA, priv AES config.addV3User( #snmpEngine, 'usr-sha-aes128', snmpEngine, snmp_user, #Add snmpv3 user config.usmHMACSHAAuthProtocol, snmp_pwd, #Auth SHA #password config.usmAesCfb128Protocol, snmp_pwd #Use Aes #password
from pysnmp.entity import engine, config from pysnmp.carrier.asynsock.dgram import udp from pysnmp.entity.rfc3413 import ntfrcv from pysnmp.proto.api import v2c # Create SNMP engine with autogenernated engineID and pre-bound # to socket transport dispatcher snmpEngine = engine.SnmpEngine() # Transport setup # UDP over IPv4 config.addSocketTransport( snmpEngine, udp.domainName, udp.UdpTransport().openServerMode(('10.100.206.223', 162)) ) # SNMPv3/USM setup config.addV3User( snmpEngine, 'Administrator', config.usmHMACSHAAuthProtocol,#authProtocol,sha 'Admin@9000',#authKey config.usmAesCfb128Protocol,#privProtocol,aes 'Admin@9000', #privKey contextEngineId=v2c.OctetString(hexValue='8000000001020304') ) # Callback function for receiving notifications def cbFun(snmpEngine,
def start(self): ''' ' 启动监听进程 ' raise Exception: 异常停止时抛出 ''' logger.info('Start trap listener...') # Create SNMP engine with autogenernated engineID and pre-bound # to socket transport dispatcher snmpEngine = engine.SnmpEngine() # Transport setup # UDP over IPv4 config.addSocketTransport( snmpEngine, udp.domainName, udp.UdpTransport().openServerMode((self._configdata.Localaddress, \ self._configdata.Listenport)) ) try: for agentip in self._configdata.Hostdata.keys(): issuccess = self._configdata.Hostdata[agentip][ HOST_CFG_KEY_ISSUCCESS] if issuccess != True: continue version = self._configdata.Hostdata[agentip][ HOST_CFG_KEY_TRAPSNMPVERSION] if 'V3' == version.upper(): # SNMPv3/USM setup authProtocol = str(self._configdata.Hostdata[agentip] [HOST_CFG_KEY_AUTHPROTOCOL]) privProtocol = str(self._configdata.Hostdata[agentip] [HOST_CFG_KEY_PRIVPROTOCOL]) username = str( self._configdata.Hostdata[agentip][HOST_CFG_KEY_USER]) password = str( self._configdata.Hostdata[agentip][HOST_CFG_KEY_PASS]) enginid = str(self._configdata.Hostdata[agentip] [HOST_CFG_KEY_ENGINID]) if enginid is None or enginid == '': logger.info( "enginid is null,please check device,ipaddr :" + str(agentip)) strEnginid = None else: strEnginid = v2c.OctetString(hexValue=enginid) if authProtocol == 'MD5' and privProtocol == "DES": config.addV3User(snmpEngine, username, config.usmHMACMD5AuthProtocol, password, config.usmDESPrivProtocol, password, contextEngineId=strEnginid) elif authProtocol == 'MD5' and privProtocol == "AES": config.addV3User(snmpEngine, username, config.usmHMACMD5AuthProtocol, password, config.usmAesCfb128Protocol, password, contextEngineId=strEnginid) elif authProtocol == 'SHA' and privProtocol == "DES": config.addV3User(snmpEngine, username, config.usmHMACSHAAuthProtocol, password, config.usmDESPrivProtocol, password, contextEngineId=strEnginid) elif authProtocol == 'SHA' and privProtocol == "AES": config.addV3User(snmpEngine, username, config.usmHMACSHAAuthProtocol, password, config.usmAesCfb128Protocol, password, contextEngineId=strEnginid) else: # v1/2 setup trapcommunity = str(self._configdata.Hostdata[agentip] [HOST_CFG_KEY_TRAPCOMMUNITY]) config.addV1System(snmpEngine, 'test-agent', trapcommunity) except Exception, err: logger.error("cache userinfor ,error :" + str(err)) snmpEngine.transportDispatcher.closeDispatcher() raise
def __init__(self, mibObjects): self._snmpEngine = engine.SnmpEngine() # open a UDP socket to listen for snmp requests config.addSocketTransport( self._snmpEngine, udp.domainName, udp.UdpTransport().openServerMode(('', 7757))) # add a v2 user with the community string public config.addV1System(self._snmpEngine, "agent", "public") # let anyone accessing 'public' read anything in the subtree below, # which is the enterprises subtree that we defined our MIB to be in config.addVacmUser(self._snmpEngine, 2, "agent", "noAuthNoPriv", readSubTree=(1, 3, 6, 1, 4, 1)) # each app has one or more contexts self._snmpContext = context.SnmpContext(self._snmpEngine) # the builder is used to load mibs. tell it to look in the # current directory for our new MIB. We'll also use it to # export our symbols later mibBuilder = self._snmpContext.getMibInstrum().getMibBuilder() mibSources = mibBuilder.getMibSources() + (builder.DirMibSource('.'), ) mibBuilder.setMibSources(*mibSources) # our variables will subclass this since we only have scalar types # can't load this type directly, need to import it MibScalarInstance, = mibBuilder.importSymbols('SNMPv2-SMI', 'MibTable') mib = Mib() (nodeEntry, profileEntry, nodeIdxColumn, profileIdxColumn, dcdColumn, profileNameColumn) = mibBuilder.importSymbols('AKSION-CONTROL-MIB', 'nodeEntry', 'profileEntry', 'nodeIdx', 'profileIdx', 'dcd', 'profileName') rowInstanceId = nodeEntry.getInstIdFromIndices(1) mibInstrumentation = self._snmpContext.getMibInstrum() mibInstrumentation.writeVars( ((dcdColumn.name + rowInstanceId, 'xx1'), )) rowProfileInstanceId = profileEntry.getInstIdFromIndices(1) mibInstrumentation = self._snmpContext.getMibInstrum() mibInstrumentation.writeVars( ((profileNameColumn.name + rowInstanceId + rowProfileInstanceId, 'ProfileNode1'), )) # rowInstanceId = nodeEntry.getInstIdFromIndices(2) mibInstrumentation = self._snmpContext.getMibInstrum() mibInstrumentation.writeVars( ((dcdColumn.name + rowInstanceId, 'xx 2'), )) rowProfileInstanceId = profileEntry.getInstIdFromIndices(2) mibInstrumentation = self._snmpContext.getMibInstrum() mibInstrumentation.writeVars( ((profileNameColumn.name + rowInstanceId + rowProfileInstanceId, 'ProfileNode2'), )) # tell pysnmp to respotd to get, getnext, and getbulk cmdrsp.GetCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.NextCommandResponder(self._snmpEngine, self._snmpContext) cmdrsp.BulkCommandResponder(self._snmpEngine, self._snmpContext)
def connect_to_server(): global snmpEngine snmpEngine = engine.SnmpEngine() # GUI變數 ip_addr = ip_entry.get() port_num = port_entry.get() global model_name model_name = model_combo.get() + "-MIB" # Setup UDP over IPv4 transport endpoint config.addTransport( snmpEngine, udp.domainName, udp.UdpTransport().openServerMode((ip_addr, int(port_num)))) # SNMPv2c setup # "my-area" -> user name / "public" -> community name config.addV1System(snmpEngine, "my-area", "public") config.addContext(snmpEngine, "") # Allow full MIB access for this user / securityModels at VACM config.addVacmUser(snmpEngine, 2, "my-area", "noAuthNoPriv", (1, 3, 6, 1, 4, 1, 8691)) # Create an SNMP context snmpContext = context.SnmpContext(snmpEngine) # Create MIB builder global mibBuilder mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder # Optionally set an alternative path to compiled MIBs print("Setting MIB sources...") MIBDIR = r"./pwd/mibfiles/" mibBuilder.addMibSources(builder.DirMibSource(MIBDIR)) print("done") # Load modules print("Loading MIB modules...") mibBuilder.loadModules(model_name) """ print("Indexing MIB objects..."), mibView = view.MibViewController(mibBuilder) print(mibView.getNodeName((1, 3, 6, 1, 4, 1, 8691, 2, 19, 1, 6, 4, 1, 1, 0))) print("done") """ # Build mib tree print("Building MIB tree...") global mibInstrum mibInstrum = snmpContext.getMibInstrum() print("done") print("Building table entry index from human-friendly representation...") global portEntry portEntry, = mibBuilder.importSymbols(model_name, "portEntry") """ networkConnEntry, = mibBuilder.importSymbols( model_name, "modbusProtocolEntry" ) """ global MibScalarInstance MibScalarInstance, = mibBuilder.importSymbols("SNMPv2-SMI", "MibScalarInstance") global power1InputStatus, power2InputStatus power1InputStatus, = mibBuilder.importSymbols(model_name, "power1InputStatus") power2InputStatus, = mibBuilder.importSymbols(model_name, "power2InputStatus") print("done") """ # Modify mibscalar value class Mypower1InputStatus(MibScalarInstance): # noinspection PyUnusedLocal def readGet(self, name, *args): # Just return a custom value return name, self.syntax.clone(power1InputStatus_Value.get()) class Mypower2InputStatus(MibScalarInstance): # noinspection PyUnusedLocal def readGet(self, name, *args): # Just return a custom value return name, self.syntax.clone(power2InputStatus_Value.get()) _power1InputStatus = Mypower1InputStatus( power1InputStatus.name, (0,), power1InputStatus.syntax ) _power2InputStatus = Mypower2InputStatus( power2InputStatus.name, (0,), power2InputStatus.syntax ) failedLoginLockedTime = MibScalarInstance( failedLoginLockedTime.name, (1, 3, 6, 1, 4, 1, 8691, 2, 19, 1, 6, 4, 1, 12, 0), failedLoginLockedTime.syntax.clone(50) ) print(failedLoginLockedTime) # Register Managed Object with a MIB tree mibBuilder.exportSymbols( # "__" prefixed MIB modules take precedence on indexing model_name, _power1InputStatus=_power1InputStatus, _power2InputStatus=_power2InputStatus ) """ print("Getting instance ID") global instanceId instanceId = portEntry.getInstIdFromIndices(10) print("done") write_var() """ # Modify mibtable value print("Create/update MOXA-NPS9450-MIB::consoleSetting table row: ") varBinds = mibInstrum.writeVars( ((portEntry.name + (2,) + instanceId, port_status),) ) #mibInstrum.writeVars(((networkConnEntry.name + (2,) + instanceId_networkConnEntry, "0"),)) #mibInstrum.writeVars(((realComEntry.name + (1,) + instanceId,"4"),)) for oid, val in varBinds: print("%s = %s" % (".".join([str(x) for x in oid]), not val.isValue and "N/A" or val.prettyPrint())) print("done") print("Read whole MIB (table walk)") oid, val = (), None while True: oid, val = mibInstrum.readNextVars(((oid, val),))[0] if exval.endOfMib.isSameTypeWith(val): break print("%s = %s\n" % (".".join([str(x) for x in oid]), not val.isValue and "N/A" or val.prettyPrint())) print("done") """ # Register SNMP Applications at the SNMP engine for particular SNMP context cmdrsp.GetCommandResponder(snmpEngine, snmpContext) cmdrsp.SetCommandResponder(snmpEngine, snmpContext) cmdrsp.NextCommandResponder(snmpEngine, snmpContext) cmdrsp.BulkCommandResponder(snmpEngine, snmpContext) # Register an imaginary never-ending job to keep I/O dispatcher running forever snmpEngine.transportDispatcher.jobStarted(1) # this job would never finish global connect_first # Run I/O dispatcher which would receive queries and send responses try: print("here") connect_first = 1 snmpEngine.transportDispatcher.runDispatcher() except: print("there") snmpEngine.transportDispatcher.closeDispatcher() raise
def snmpv3_trap(user='', hash_meth=None, hash_key=None, cry_meth=None, cry_key=None, engineid='', ip='127.0.0.1', port=162): # Create SNMP engine with autogenernated engineID and pre-bound snmp_engine = engine.SnmpEngine() config.addSocketTransport(snmp_engine, udp.domainName, udp.UdpTransport().openServerMode((ip, port))) # usmHMACMD5AuthProtocol - MD5 hashing # usmHMACSHAAuthProtocol - SHA hashing # usmNoAuthProtocol - no authentication # usmDESPrivProtocol - DES encryption # usm3DESEDEPrivProtocol - triple-DES encryption # usmAesCfb128Protocol - AES encryption, 128-bit # usmAesCfb192Protocol - AES encryption, 192-bit # usmAesCfb256Protocol - AES encryption, 256-bit # usmNoPrivProtocol - no encryption # NoAuthNoPriv if hash_meth is None and cry_meth is None: hashval = config.usmNoAuthProtocol cryval = config.usmNoPrivProtocol # AuthNoPriv elif hash_meth is not None and cry_meth is None: if hash_meth == 'md5': hashval = config.usmHMACMD5AuthProtocol elif hash_meth == 'sha': hashval = config.usmHMACSHAAuthProtocol else: print('哈希算法必须是md5 or sha!') return cryval = config.usmNoPrivProtocol # AuthPriv elif hash_meth is not None and cry_meth is not None: if hash_meth == 'md5': hashval = config.usmHMACMD5AuthProtocol elif hash_meth == 'sha': hashval = config.usmHMACSHAAuthProtocol else: print('哈希算法必须是md5 or sha!') return if cry_meth == '3des': cryval = config.usm3DESEDEPrivProtocol elif cry_meth == 'des': cryval = config.usmDESPrivProtocol elif cry_meth == 'aes128': cryval = config.usmAesCfb128Protocol elif cry_meth == 'aes192': cryval = config.usmAesCfb192Protocol elif cry_meth == 'aes256': cryval = config.usmAesCfb256Protocol else: print('加密算法必须是3des, des, aes128, aes192 or aes256 !') return # 提供的参数不符合标准时给出提示 else: print('三种USM: NoAuthNoPriv, AuthNoPriv, AuthPriv.。请选择其中一种。') return config.addV3User(snmp_engine, user, hashval, hash_key, cryval, cry_key, contextEngineId=v2c.OctetString(hexValue=engineid)) # Register SNMP Application at the SNMP engine ntfrcv.NotificationReceiver(snmp_engine, cb_fun) snmp_engine.transportDispatcher.jobStarted( 1) # this job would never finish # Run I/O dispatcher which would receive queries and send confirmations try: snmp_engine.transportDispatcher.runDispatcher() except Exception: snmp_engine.transportDispatcher.closeDispatcher() raise
def main(): class CommandResponder(cmdrsp.CommandResponderBase): pduTypes = (rfc1905.SetRequestPDU.tagSet, rfc1905.GetRequestPDU.tagSet, rfc1905.GetNextRequestPDU.tagSet, rfc1905.GetBulkRequestPDU.tagSet) def handleMgmtOperation(self, snmpEngine, stateReference, contextName, pdu, acInfo): trunkReq = gCurrentRequestContext.copy() trunkReq['snmp-pdu'] = pdu pluginIdList = trunkReq['plugins-list'] logCtx = LogString(trunkReq) reqCtx = {} for pluginNum, pluginId in enumerate(pluginIdList): st, pdu = pluginManager.processCommandRequest( pluginId, snmpEngine, pdu, trunkReq, reqCtx) if st == status.BREAK: log.debug('plugin %s inhibits other plugins' % pluginId, ctx=logCtx) pluginIdList = pluginIdList[:pluginNum] break elif st == status.DROP: log.debug( 'received SNMP message, plugin %s muted request' % pluginId, ctx=logCtx) self.releaseStateInformation(stateReference) return elif st == status.RESPOND: log.debug( 'received SNMP message, plugin %s forced immediate response' % pluginId, ctx=logCtx) try: self.sendPdu(snmpEngine, stateReference, pdu) except PySnmpError: log.error('failure sending SNMP response', ctx=logCtx) else: self.releaseStateInformation(stateReference) return # pass query to trunk trunkIdList = trunkReq['trunk-id-list'] if trunkIdList is None: log.error('no route configured', ctx=logCtx) self.releaseStateInformation(stateReference) return for trunkId in trunkIdList: cbCtx = pluginIdList, trunkId, trunkReq, snmpEngine, stateReference, reqCtx try: msgId = trunkingManager.sendReq(trunkId, trunkReq, self.trunkCbFun, cbCtx) except SnmpfwdError: log.error( 'received SNMP message, message not sent to trunk "%s"' % sys.exc_info()[1], ctx=logCtx) return log.debug( 'received SNMP message, forwarded as trunk message #%s' % msgId, ctx=logCtx) def trunkCbFun(self, msgId, trunkRsp, cbCtx): pluginIdList, trunkId, trunkReq, snmpEngine, stateReference, reqCtx = cbCtx for key in tuple(trunkRsp): if key != 'callflow-id': trunkRsp['client-' + key] = trunkRsp[key] del trunkRsp[key] trunkRsp['callflow-id'] = trunkReq['callflow-id'] logCtx = LogString(trunkRsp) if trunkRsp['client-error-indication']: log.info( 'received trunk message #%s, remote end reported error-indication "%s", NOT responding' % (msgId, trunkRsp['client-error-indication']), ctx=logCtx) elif 'client-snmp-pdu' not in trunkRsp: log.info( 'received trunk message #%s, remote end does not send SNMP PDU, NOT responding' % msgId, ctx=logCtx) else: pdu = trunkRsp['client-snmp-pdu'] for pluginId in pluginIdList: st, pdu = pluginManager.processCommandResponse( pluginId, snmpEngine, pdu, trunkReq, reqCtx) if st == status.BREAK: log.debug('plugin %s inhibits other plugins' % pluginId, ctx=logCtx) break elif st == status.DROP: log.debug('plugin %s muted response' % pluginId, ctx=logCtx) self.releaseStateInformation(stateReference) return try: self.sendPdu(snmpEngine, stateReference, pdu) except PySnmpError: log.error('failure sending SNMP response', ctx=logCtx) else: log.debug( 'received trunk message #%s, forwarded as SNMP message' % msgId, ctx=logCtx) self.releaseStateInformation(stateReference) # # SNMPv3 NotificationReceiver implementation # class NotificationReceiver(ntfrcv.NotificationReceiver): pduTypes = (rfc1157.TrapPDU.tagSet, rfc1905.SNMPv2TrapPDU.tagSet) def processPdu(self, snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, maxSizeResponseScopedPDU, stateReference): trunkReq = gCurrentRequestContext.copy() if messageProcessingModel == 0: pdu = rfc2576.v1ToV2(pdu) # TODO: why this is not automatic? v2c.apiTrapPDU.setDefaults(pdu) trunkReq['snmp-pdu'] = pdu pluginIdList = trunkReq['plugins-list'] logCtx = LogString(trunkReq) reqCtx = {} for pluginNum, pluginId in enumerate(pluginIdList): st, pdu = pluginManager.processNotificationRequest( pluginId, snmpEngine, pdu, trunkReq, reqCtx) if st == status.BREAK: log.debug('plugin %s inhibits other plugins' % pluginId, ctx=logCtx) pluginIdList = pluginIdList[:pluginNum] break elif st == status.DROP: log.debug('plugin %s muted request' % pluginId, ctx=logCtx) return elif st == status.RESPOND: log.debug('plugin %s NOT forced immediate response' % pluginId, ctx=logCtx) # TODO: implement immediate response for confirmed-class PDU return # pass query to trunk trunkIdList = trunkReq['trunk-id-list'] if trunkIdList is None: log.error('no route configured', ctx=logCtx) return for trunkId in trunkIdList: # TODO: pass messageProcessingModel to respond cbCtx = pluginIdList, trunkId, trunkReq, snmpEngine, stateReference, reqCtx try: msgId = trunkingManager.sendReq(trunkId, trunkReq, self.trunkCbFun, cbCtx) except SnmpfwdError: log.error( 'received SNMP message, message not sent to trunk "%s" %s' % (trunkId, sys.exc_info()[1]), ctx=logCtx) return log.debug( 'received SNMP message, forwarded as trunk message #%s' % msgId, ctx=logCtx) def trunkCbFun(self, msgId, trunkRsp, cbCtx): pluginIdList, trunkId, trunkReq, snmpEngine, stateReference, reqCtx = cbCtx for key in tuple(trunkRsp): if key != 'callflow-id': trunkRsp['client-' + key] = trunkRsp[key] del trunkRsp[key] trunkRsp['callflow-id'] = trunkReq['callflow-id'] logCtx = LazyLogString(trunkReq, trunkRsp) if trunkRsp['client-error-indication']: log.info( 'received trunk message #%s, remote end reported error-indication "%s", NOT responding' % (msgId, trunkRsp['client-error-indication']), ctx=logCtx) else: if 'client-snmp-pdu' not in trunkRsp: log.debug( 'received trunk message #%s -- unconfirmed SNMP message' % msgId, ctx=logCtx) return pdu = trunkRsp['client-snmp-pdu'] for pluginId in pluginIdList: st, pdu = pluginManager.processNotificationResponse( pluginId, snmpEngine, pdu, trunkReq, reqCtx) if st == status.BREAK: log.debug('plugin %s inhibits other plugins' % pluginId, ctx=logCtx) break elif st == status.DROP: log.debug( 'received trunk message #%s, plugin %s muted response' % (msgId, pluginId), ctx=logCtx) return log.debug( 'received trunk message #%s, forwarded as SNMP message' % msgId, ctx=logCtx) # TODO: implement response part # # Agent-side API complies with SMIv2 # if messageProcessingModel == 0: # PDU = rfc2576.v2ToV1(PDU, origPdu) # # statusInformation = {} # # # 3.4.3 # try: # snmpEngine.msgAndPduDsp.returnResponsePdu( # snmpEngine, messageProcessingModel, securityModel, # securityName, securityLevel, contextEngineId, # contextName, pduVersion, rspPDU, maxSizeResponseScopedPDU, # stateReference, statusInformation) # # except error.StatusInformation: # log.error('processPdu: stateReference %s, statusInformation %s' % (stateReference, sys.exc_info()[1])) class LogString(LazyLogString): GROUPINGS = [ ['callflow-id'], [ 'snmp-engine-id', 'snmp-transport-domain', 'snmp-bind-address', 'snmp-bind-port', 'snmp-security-model', 'snmp-security-level', 'snmp-security-name', 'snmp-credentials-id' ], ['snmp-context-engine-id', 'snmp-context-name', 'snmp-context-id'], ['snmp-pdu', 'snmp-content-id'], ['snmp-peer-address', 'snmp-peer-port', 'snmp-peer-id'], ['trunk-id'], ['client-snmp-pdu'], ] FORMATTERS = { 'client-snmp-pdu': LazyLogString.prettyVarBinds, 'snmp-pdu': LazyLogString.prettyVarBinds, } def securityAuditObserver(snmpEngine, execpoint, variables, cbCtx): securityModel = variables.get('securityModel', 0) logMsg = 'SNMPv%s auth failure' % securityModel logMsg += ' at %s:%s' % variables['transportAddress'].getLocalAddress() logMsg += ' from %s:%s' % variables['transportAddress'] statusInformation = variables.get('statusInformation', {}) if securityModel in (1, 2): logMsg += ' using snmp-community-name "%s"' % statusInformation.get( 'communityName', '?') elif securityModel == 3: logMsg += ' using snmp-usm-user "%s"' % statusInformation.get( 'msgUserName', '?') try: logMsg += ': %s' % statusInformation['errorIndication'] except KeyError: pass log.error(logMsg) def requestObserver(snmpEngine, execpoint, variables, cbCtx): trunkReq = { 'callflow-id': '%10.10x' % random.randint(0, 0xffffffffff), 'snmp-engine-id': snmpEngine.snmpEngineID, 'snmp-transport-domain': variables['transportDomain'], 'snmp-peer-address': variables['transportAddress'][0], 'snmp-peer-port': variables['transportAddress'][1], 'snmp-bind-address': variables['transportAddress'].getLocalAddress()[0], 'snmp-bind-port': variables['transportAddress'].getLocalAddress()[1], 'snmp-security-model': variables['securityModel'], 'snmp-security-level': variables['securityLevel'], 'snmp-security-name': variables['securityName'], 'snmp-context-engine-id': variables['contextEngineId'], 'snmp-context-name': variables['contextName'], } trunkReq['snmp-credentials-id'] = macro.expandMacro( credIdMap.get( (str(snmpEngine.snmpEngineID), variables['transportDomain'], variables['securityModel'], variables['securityLevel'], str(variables['securityName']))), trunkReq) k = '#'.join([ str(x) for x in (variables['contextEngineId'], variables['contextName']) ]) for x, y in contextIdList: if y.match(k): trunkReq['snmp-context-id'] = macro.expandMacro(x, trunkReq) break else: trunkReq['snmp-context-id'] = None addr = '%s:%s#%s:%s' % ( variables['transportAddress'][0], variables['transportAddress'][1], variables['transportAddress'].getLocalAddress()[0], variables['transportAddress'].getLocalAddress()[1]) for pat, peerId in peerIdMap.get(str(variables['transportDomain']), ()): if pat.match(addr): trunkReq['snmp-peer-id'] = macro.expandMacro(peerId, trunkReq) break else: trunkReq['snmp-peer-id'] = None pdu = variables['pdu'] if pdu.tagSet == v1.TrapPDU.tagSet: pdu = rfc2576.v1ToV2(pdu) v2c.apiTrapPDU.setDefaults(pdu) k = '#'.join([ snmpPduTypesMap.get(variables['pdu'].tagSet, '?'), '|'.join([str(x[0]) for x in v2c.apiTrapPDU.getVarBinds(pdu)]) ]) for x, y in contentIdList: if y.match(k): trunkReq['snmp-content-id'] = macro.expandMacro(x, trunkReq) break else: trunkReq['snmp-content-id'] = None trunkReq['plugins-list'] = pluginIdMap.get( (trunkReq['snmp-credentials-id'], trunkReq['snmp-context-id'], trunkReq['snmp-peer-id'], trunkReq['snmp-content-id']), []) trunkReq['trunk-id-list'] = trunkIdMap.get( (trunkReq['snmp-credentials-id'], trunkReq['snmp-context-id'], trunkReq['snmp-peer-id'], trunkReq['snmp-content-id'])) cbCtx.clear() cbCtx.update(trunkReq) # # main script 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 pysnmp_debug.flagMap.keys() if x != 'mibview' ]), '|'.join([x for x in pyasn1_debug.flagMap.keys()]), '|'.join( log.methodsMap.keys()), '|'.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: server part. Receives SNMP requests at one or many built-in SNMP Agents and routes them to encrypted trunks established with Forwarder's Manager part(s) running elsewhere. Can implement complex routing logic through analyzing parts of SNMP messages and matching them against proxying rules. Documentation: http://snmpfwd.sourceforge.io/ %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 https://github.com/etingof/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] 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() gCurrentRequestContext = {} credIdMap = {} peerIdMap = {} contextIdList = [] contentIdList = [] pluginIdMap = {} trunkIdMap = {} engineIdMap = {} transportDispatcher = AsynsockDispatcher() transportDispatcher.registerRoutingCbFun(lambda td, t, d: td) transportDispatcher.setSocketMap() # use global asyncore socket map # # Initialize plugin modules # 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>')) try: pluginManager.loadPlugin(pluginId, pluginMod, pluginOptions) except SnmpfwdError: log.error('plugin %s not loaded: %s' % (pluginId, sys.exc_info()[1])) return for configEntryPath in cfgTree.getPathsToAttr('snmp-credentials-id'): credId = cfgTree.getAttrValue('snmp-credentials-id', *configEntryPath) configKey = [] log.info('configuring snmp-credentials %s (at %s)...' % (credId, '.'.join(configEntryPath))) engineId = cfgTree.getAttrValue('snmp-engine-id', *configEntryPath) 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': {}} snmpEngine.observer.registerObserver( securityAuditObserver, 'rfc2576.prepareDataElements:sm-failure', 'rfc3412.prepareDataElements:sm-failure', cbCtx=gCurrentRequestContext) snmpEngine.observer.registerObserver( requestObserver, 'rfc3412.receiveMessage:request', cbCtx=gCurrentRequestContext) CommandResponder(snmpEngine, snmpContext) NotificationReceiver(snmpEngine, None) engineIdMap[engineId] = snmpEngine, snmpContext, snmpEngineMap log.info('new engine-id %s' % snmpEngine.snmpEngineID.prettyPrint()) configKey.append(str(snmpEngine.snmpEngineID)) transportDomain = cfgTree.getAttrValue('snmp-transport-domain', *configEntryPath) transportDomain = rfc1902.ObjectName(transportDomain) if transportDomain in snmpEngineMap['transportDomain']: h, p, transportDomain = snmpEngineMap['transportDomain'][ transportDomain] log.info('using transport endpoint %s:%s, transport ID %s' % (h, p, transportDomain)) else: if transportDomain[:len(udp.domainName)] == udp.domainName: transport = udp.UdpTransport() elif transportDomain[:len(udp6.domainName)] == udp6.domainName: transport = udp6.Udp6Transport() else: log.error('unknown transport domain %s' % (transportDomain, )) return h, p = cfgTree.getAttrValue('snmp-bind-address', *configEntryPath).split(':', 1) snmpEngine.registerTransportDispatcher(transportDispatcher, transportDomain) transportOptions = cfgTree.getAttrValue( 'snmp-transport-options', *configEntryPath, **dict(default=[], vector=True)) t = transport.openServerMode((h, int(p))) if 'transparent-proxy' in transportOptions: t.enablePktInfo() t.enableTransparent() elif 'virtual-interface' in transportOptions: t.enablePktInfo() config.addSocketTransport(snmpEngine, transportDomain, t) snmpEngineMap['transportDomain'][ transportDomain] = h, p, transportDomain log.info( 'new transport endpoint %s:%s, options %s, transport ID %s' % (h, p, transportOptions and '/'.join(transportOptions) or '<none>', transportDomain)) configKey.append(transportDomain) securityModel = cfgTree.getAttrValue('snmp-security-model', *configEntryPath) securityModel = rfc1902.Integer(securityModel) securityLevel = cfgTree.getAttrValue('snmp-security-level', *configEntryPath) securityLevel = rfc1902.Integer(securityLevel) securityName = cfgTree.getAttrValue('snmp-security-name', *configEntryPath) if securityModel in (1, 2): if securityName in snmpEngineMap['securityName']: if snmpEngineMap['securityName'][ securityModel] == securityModel: log.info('using security-name %s' % securityName) else: raise SnmpfwdError( 'snmp-security-name %s already in use at snmp-security-model %s' % (securityName, securityModel)) else: communityName = cfgTree.getAttrValue('snmp-community-name', *configEntryPath) 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 configKey.append(securityModel) configKey.append(securityLevel) configKey.append(securityName) elif securityModel == 3: if securityName in snmpEngineMap['securityName']: log.info('using USM security-name: %s' % securityName) else: usmUser = cfgTree.getAttrValue('snmp-usm-user', *configEntryPath) log.info( 'new USM user %s, security-model %s, security-level %s, security-name %s' % (usmUser, securityModel, securityLevel, securityName)) if securityLevel in (2, 3): usmAuthProto = cfgTree.getAttrValue( 'snmp-usm-auth-protocol', *configEntryPath, **dict(default=config.usmHMACMD5AuthProtocol)) usmAuthProto = rfc1902.ObjectName(usmAuthProto) usmAuthKey = cfgTree.getAttrValue('snmp-usm-auth-key', *configEntryPath) log.info( 'new USM authentication key: %s, authentication protocol: %s' % (usmAuthKey, usmAuthProto)) if securityLevel == 3: usmPrivProto = cfgTree.getAttrValue( 'snmp-usm-priv-protocol', *configEntryPath, **dict(default=config.usmDESPrivProtocol)) usmPrivProto = rfc1902.ObjectName(usmPrivProto) usmPrivKey = cfgTree.getAttrValue( 'snmp-usm-priv-key', *configEntryPath, **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) else: config.addV3User(snmpEngine, usmUser) snmpEngineMap['securityName'][securityName] = securityModel configKey.append(securityModel) configKey.append(securityLevel) configKey.append(securityName) else: raise SnmpfwdError('unknown snmp-security-model: %s' % securityModel) configKey = tuple(configKey) if configKey in credIdMap: log.error( 'ambiguous configuration for key snmp-credentials-id=%s at %s' % (credId, '.'.join(configEntryPath))) return credIdMap[configKey] = credId duplicates = {} for peerCfgPath in cfgTree.getPathsToAttr('snmp-peer-id'): peerId = cfgTree.getAttrValue('snmp-peer-id', *peerCfgPath) if peerId in duplicates: log.error( 'duplicate snmp-peer-id=%s at %s and %s' % (peerId, '.'.join(peerCfgPath), '.'.join(duplicates[peerId]))) return duplicates[peerId] = peerCfgPath log.info('configuring peer ID %s (at %s)...' % (peerId, '.'.join(peerCfgPath))) transportDomain = cfgTree.getAttrValue('snmp-transport-domain', *peerCfgPath) if transportDomain not in peerIdMap: peerIdMap[transportDomain] = [] for peerAddress in cfgTree.getAttrValue( 'snmp-peer-address-pattern-list', *peerCfgPath, **dict(vector=True)): for bindAddress in cfgTree.getAttrValue( 'snmp-bind-address-pattern-list', *peerCfgPath, **dict(vector=True)): peerIdMap[transportDomain].append( (re.compile(peerAddress + '#' + bindAddress), peerId)) duplicates = {} for contextCfgPath in cfgTree.getPathsToAttr('snmp-context-id'): contextId = cfgTree.getAttrValue('snmp-context-id', *contextCfgPath) if contextId in duplicates: log.error('duplicate snmp-context-id=%s at %s and %s' % (contextId, '.'.join(contextCfgPath), '.'.join( duplicates[contextId]))) return duplicates[contextId] = contextCfgPath k = '#'.join((cfgTree.getAttrValue('snmp-context-engine-id-pattern', *contextCfgPath), cfgTree.getAttrValue('snmp-context-name-pattern', *contextCfgPath))) log.info('configuring context ID %s (at %s), composite key: %s' % (contextId, '.'.join(contextCfgPath), k)) contextIdList.append((contextId, re.compile(k))) duplicates = {} for contentCfgPath in cfgTree.getPathsToAttr('snmp-content-id'): contentId = cfgTree.getAttrValue('snmp-content-id', *contentCfgPath) if contentId in duplicates: log.error('duplicate snmp-content-id=%s at %s and %s' % (contentId, '.'.join(contentCfgPath), '.'.join( duplicates[contentId]))) return duplicates[contentId] = contentCfgPath for x in cfgTree.getAttrValue('snmp-pdu-oid-prefix-pattern-list', *contentCfgPath, **dict(vector=True)): k = '#'.join([ cfgTree.getAttrValue('snmp-pdu-type-pattern', *contentCfgPath), x ]) log.info('configuring content ID %s (at %s), composite key: %s' % (contentId, '.'.join(contentCfgPath), k)) contentIdList.append((contentId, 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-snmp-credentials-id-list', *pluginCfgPath, **dict(vector=True)): for peerId in cfgTree.getAttrValue('matching-snmp-peer-id-list', *pluginCfgPath, **dict(vector=True)): for contextId in cfgTree.getAttrValue( 'matching-snmp-context-id-list', *pluginCfgPath, **dict(vector=True)): for contentId in cfgTree.getAttrValue( 'matching-snmp-content-id-list', *pluginCfgPath, **dict(vector=True)): k = credId, contextId, peerId, contentId if k in pluginIdMap: log.error( 'duplicate snmp-credentials-id %s, snmp-context-id %s, snmp-peer-id %s, snmp-content-id %s at plugin-id(s) %s' % (credId, contextId, peerId, contentId, ','.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-trunk-id-list'): trunkIdList = cfgTree.getAttrValue('using-trunk-id-list', *routeCfgPath, **dict(vector=True)) log.info('configuring destination trunk ID(s) %s (at %s)...' % (','.join(trunkIdList), '.'.join(routeCfgPath))) for credId in cfgTree.getAttrValue('matching-snmp-credentials-id-list', *routeCfgPath, **dict(vector=True)): for peerId in cfgTree.getAttrValue('matching-snmp-peer-id-list', *routeCfgPath, **dict(vector=True)): for contextId in cfgTree.getAttrValue( 'matching-snmp-context-id-list', *routeCfgPath, **dict(vector=True)): for contentId in cfgTree.getAttrValue( 'matching-snmp-content-id-list', *routeCfgPath, **dict(vector=True)): k = credId, contextId, peerId, contentId if k in trunkIdMap: log.error( 'duplicate snmp-credentials-id %s, snmp-context-id %s, snmp-peer-id %s, snmp-content-id %s at trunk-id(s) %s' % (credId, contextId, peerId, contentId, ','.join(trunkIdList))) return else: trunkIdMap[k] = trunkIdList log.info( 'configuring trunk routing to %s (at %s), composite key: %s' % (','.join(trunkIdList), '.'.join(routeCfgPath), '/'.join(k))) def dataCbFun(trunkId, msgId, msg): log.debug('message ID %s received from trunk %s' % (msgId, trunkId)) trunkingManager = TrunkingManager(dataCbFun) def getTrunkAddr(a, port=0): f = lambda h, p=port: (h, int(p)) try: return f(*a.split(':')) except Exception: raise SnmpfwdError('improper IPv4 endpoint %s' % a) 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, getTrunkAddr( cfgTree.getAttrValue('trunk-bind-address', *trunkCfgPath)), getTrunkAddr( 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( getTrunkAddr( 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)) try: daemon.dropPrivileges(procUser, procGroup) except Exception: log.error('can not drop privileges: %s' % sys.exc_info()[1]) return 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 while True: try: transportDispatcher.runDispatcher() except (PySnmpError, SnmpfwdError, socket.error): log.error(str(sys.exc_info()[1])) continue except Exception: transportDispatcher.closeDispatcher() raise
def _setup(self, q): """Setup a new agent in a separate process. The port the agent is listening too will be returned using the provided queue. """ port = random.randrange(22000, 22989) snmpEngine = engine.SnmpEngine() if self.ipv6: config.addSocketTransport( snmpEngine, udp6.domainName, udp6.Udp6Transport().openServerMode(('::1', port))) else: config.addSocketTransport( snmpEngine, udp.domainName, udp.UdpTransport().openServerMode(('127.0.0.1', port))) # Community is public and MIB is writable config.addV1System(snmpEngine, 'read-write', 'public') config.addVacmUser(snmpEngine, 1, 'read-write', 'noAuthNoPriv', (1, 3, 6), (1, 3, 6)) config.addVacmUser(snmpEngine, 2, 'read-write', 'noAuthNoPriv', (1, 3, 6), (1, 3, 6)) config.addV3User(snmpEngine, 'read-write', config.usmHMACMD5AuthProtocol, 'authpass', config.usmAesCfb128Protocol, 'privpass') config.addVacmUser(snmpEngine, 3, 'read-write', 'authPriv', (1, 3, 6), (1, 3, 6)) # Build MIB def stringToOid(string): return [ord(x) for x in string] def flatten(*args): result = [] for el in args: if isinstance(el, (list, tuple)): for sub in el: result.append(sub) else: result.append(el) return tuple(result) snmpContext = context.SnmpContext(snmpEngine) mibBuilder = snmpContext.getMibInstrum().getMibBuilder() (MibTable, MibTableRow, MibTableColumn, MibScalar, MibScalarInstance) = mibBuilder.importSymbols( 'SNMPv2-SMI', 'MibTable', 'MibTableRow', 'MibTableColumn', 'MibScalar', 'MibScalarInstance') mibBuilder.exportSymbols( '__MY_SNMPv2_MIB', # SNMPv2-MIB::sysDescr MibScalar((1, 3, 6, 1, 2, 1, 1, 1), v2c.OctetString()), MibScalarInstance((1, 3, 6, 1, 2, 1, 1, 1), (0, ), v2c.OctetString("Snimpy Test Agent"))) mibBuilder.exportSymbols( '__MY_IF_MIB', # IF-MIB::ifNumber MibScalar((1, 3, 6, 1, 2, 1, 2, 1), v2c.Integer()), MibScalarInstance((1, 3, 6, 1, 2, 1, 2, 1), (0, ), v2c.Integer(3)), # IF-MIB::ifTable MibTable((1, 3, 6, 1, 2, 1, 2, 2)), MibTableRow((1, 3, 6, 1, 2, 1, 2, 2, 1)).setIndexNames( (0, '__MY_IF_MIB', 'ifIndex')), # IF-MIB::ifIndex MibScalarInstance((1, 3, 6, 1, 2, 1, 2, 2, 1, 1), (1, ), v2c.Integer(1)), MibScalarInstance((1, 3, 6, 1, 2, 1, 2, 2, 1, 1), (2, ), v2c.Integer(2)), MibScalarInstance((1, 3, 6, 1, 2, 1, 2, 2, 1, 1), (3, ), v2c.Integer(3)), # IF-MIB::ifDescr MibTableColumn((1, 3, 6, 1, 2, 1, 2, 2, 1, 2), v2c.OctetString()), MibScalarInstance((1, 3, 6, 1, 2, 1, 2, 2, 1, 2), (1, ), v2c.OctetString("lo")), MibScalarInstance((1, 3, 6, 1, 2, 1, 2, 2, 1, 2), (2, ), v2c.OctetString("eth0")), MibScalarInstance((1, 3, 6, 1, 2, 1, 2, 2, 1, 2), (3, ), v2c.OctetString("eth1")), # IF-MIB::ifType MibTableColumn((1, 3, 6, 1, 2, 1, 2, 2, 1, 3), v2c.Integer()), MibScalarInstance((1, 3, 6, 1, 2, 1, 2, 2, 1, 3), (1, ), v2c.Integer(24)), MibScalarInstance((1, 3, 6, 1, 2, 1, 2, 2, 1, 3), (2, ), v2c.Integer(6)), MibScalarInstance((1, 3, 6, 1, 2, 1, 2, 2, 1, 3), (3, ), v2c.Integer(6)), # IF-MIB::ifIndex ifIndex=MibTableColumn((1, 3, 6, 1, 2, 1, 2, 2, 1, 1), v2c.Integer())) mibBuilder.exportSymbols( '__MY_SNIMPY-MIB', # SNIMPY-MIB::snimpyIpAddress MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 1), v2c.OctetString()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 1), (0, ), v2c.OctetString("AAAA")), # SNIMPY-MIB::snimpyString MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 2), v2c.OctetString()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 2), (0, ), v2c.OctetString("bye")), # SNIMPY-MIB::snimpyInteger MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 3), v2c.Integer()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 3), (0, ), v2c.Integer(19)), # SNIMPY-MIB::snimpyEnum MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 4), v2c.Integer()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 4), (0, ), v2c.Integer(2)), # SNIMPY-MIB::snimpyObjectId MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 5), v2c.ObjectIdentifier()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 5), (0, ), v2c.ObjectIdentifier((1, 3, 6, 4454, 0, 0))), # SNIMPY-MIB::snimpyBoolean MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 6), v2c.Integer()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 6), (0, ), v2c.Integer(1)), # SNIMPY-MIB::snimpyCounter MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 7), v2c.Counter32()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 7), (0, ), v2c.Counter32(47)), # SNIMPY-MIB::snimpyGauge MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 8), v2c.Gauge32()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 8), (0, ), v2c.Gauge32(18)), # SNIMPY-MIB::snimpyTimeticks MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 9), v2c.TimeTicks()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 9), (0, ), v2c.TimeTicks(12111100)), # SNIMPY-MIB::snimpyCounter64 MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 10), v2c.Counter64()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 10), (0, ), v2c.Counter64(2**48 + 3)), # SNIMPY-MIB::snimpyBits MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 11), v2c.OctetString()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 11), (0, ), v2c.OctetString(b"\xa0")), # SNIMPY-MIB::snimpyMacAddress MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 15), v2c.OctetString()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 15), (0, ), v2c.OctetString(b"\x11\x12\x13\x14\x15\x16")), # SNIMPY-MIB::snimpyMacAddressInvalid MibScalar((1, 3, 6, 1, 2, 1, 45121, 1, 16), v2c.OctetString()).setMaxAccess("readwrite"), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 1, 16), (0, ), v2c.OctetString(b"\xf1\x12\x13\x14\x15\x16")), # SNIMPY-MIB::snimpyIndexTable MibTable((1, 3, 6, 1, 2, 1, 45121, 2, 3)), MibTableRow((1, 3, 6, 1, 2, 1, 45121, 2, 3, 1)).setIndexNames( (0, "__MY_SNIMPY-MIB", "snimpyIndexVarLen"), (0, "__MY_SNIMPY-MIB", "snimpyIndexOidVarLen"), (0, "__MY_SNIMPY-MIB", "snimpyIndexFixedLen"), (1, "__MY_SNIMPY-MIB", "snimpyIndexImplied")), # SNIMPY-MIB::snimpyIndexInt MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 2, 3, 1, 6), flatten(4, stringToOid('row1'), 3, 1, 2, 3, stringToOid('alpha5'), stringToOid('end of row1')), v2c.Integer(4571)), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 2, 3, 1, 6), flatten(4, stringToOid('row2'), 4, 1, 0, 2, 3, stringToOid('beta32'), stringToOid('end of row2')), v2c.Integer(78741)), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 2, 3, 1, 6), flatten(4, stringToOid('row3'), 4, 120, 1, 2, 3, stringToOid('gamma7'), stringToOid('end of row3')), v2c.Integer(4110)), # SNIMPY-MIB::snimpyInvalidTable MibTable((1, 3, 6, 1, 2, 1, 45121, 2, 5)), MibTableRow((1, 3, 6, 1, 2, 1, 45121, 2, 5, 1)).setIndexNames( (0, "__MY_SNIMPY-MIB", "snimpyInvalidIndex")), # SNIMPY-MIB::snimpyInvalidDescr MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 2, 5, 1, 2), (1, ), v2c.OctetString(b"Hello")), MibScalarInstance((1, 3, 6, 1, 2, 1, 45121, 2, 5, 1, 2), (2, ), v2c.OctetString(b"\xf1\x12\x13\x14\x15\x16")), # Indexes snimpyIndexVarLen=MibTableColumn( (1, 3, 6, 1, 2, 1, 45121, 2, 3, 1, 1), v2c.OctetString()).setMaxAccess("noaccess"), snimpyIndexIntIndex=MibTableColumn( (1, 3, 6, 1, 2, 1, 45121, 2, 3, 1, 2), v2c.Integer()).setMaxAccess("noaccess"), snimpyIndexOidVarLen=MibTableColumn( (1, 3, 6, 1, 2, 1, 45121, 2, 3, 1, 3), v2c.ObjectIdentifier()).setMaxAccess("noaccess"), snimpyIndexFixedLen=MibTableColumn( (1, 3, 6, 1, 2, 1, 45121, 2, 3, 1, 4), v2c.OctetString().setFixedLength(6)).setMaxAccess("noaccess"), snimpyIndexImplied=MibTableColumn( (1, 3, 6, 1, 2, 1, 45121, 2, 3, 1, 5), v2c.OctetString()).setMaxAccess("noaccess"), snimpyIndexInt=MibTableColumn( (1, 3, 6, 1, 2, 1, 45121, 2, 3, 1, 6), v2c.Integer()).setMaxAccess("readwrite"), snimpyInvalidIndex=MibTableColumn( (1, 3, 6, 1, 2, 1, 45121, 2, 5, 1, 1), v2c.Integer()).setMaxAccess("noaccess"), snimpyInvalidDescr=MibTableColumn( (1, 3, 6, 1, 2, 1, 45121, 2, 5, 1, 2), v2c.OctetString()).setMaxAccess("readwrite")) # Start agent cmdrsp.GetCommandResponder(snmpEngine, snmpContext) cmdrsp.SetCommandResponder(snmpEngine, snmpContext) cmdrsp.NextCommandResponder(snmpEngine, snmpContext) cmdrsp.BulkCommandResponder(snmpEngine, snmpContext) q.put(port) snmpEngine.transportDispatcher.jobStarted(1) snmpEngine.transportDispatcher.runDispatcher()
log.msg('new engine-id %s' % snmpEngine.snmpEngineID.prettyPrint()) configKey.append(str(snmpEngine.snmpEngineID)) transportDomain = cfgTree.getAttrValue('snmp-transport-domain', *configEntryPath) transportDomain = rfc1902.ObjectName(transportDomain) if transportDomain in snmpEngineMap['transportDomain']: h, p, transportDomain = snmpEngineMap['transportDomain'][ transportDomain] log.msg('using transport endpoint %s:%s, transport ID %s' % (h, p, transportDomain)) else: if transportDomain[:len(udp.domainName)] == udp.domainName: transport = udp.UdpTransport() elif transportDomain[:len(udp6.domainName)] == udp6.domainName: transport = udp6.Udp6Transport() else: log.msg('unknown transport domain %s' % (transportDomain, )) sys.exit(-1) h, p = cfgTree.getAttrValue('snmp-bind-address', *configEntryPath).split(':', 1) snmpEngine.registerTransportDispatcher(transportDispatcher, transportDomain) transportOptions = cfgTree.getAttrValue( 'snmp-transport-options', *configEntryPath, **dict(default=[], vector=True))
with open(FolderPath + '/json/Comm.json') as json_data: Comm = json.load(json_data) sysOID = Comm['sysOID'].split('.')[1:] sysOID = list(map(int, sysOID)) sysOID = tuple(sysOID) # Create SNMP engine snmpEngine = engine.SnmpEngine() # Transport setup # UDP over IPv4 config.addSocketTransport( snmpEngine, udp.domainName, udp.UdpTransport().openServerMode( (Comm['ipAddress'], int(Comm['snmpPort'])))) # SNMPv2c setup # SecurityName <-> CommunityName mapping. config.addV1System(snmpEngine, 'my-area', Comm['snmpCommunity']) # Allow read MIB access for this user / securityModels at VACM config.addVacmUser(snmpEngine, int(Comm['snmpVersion']), 'my-area', 'noAuthNoPriv', sysOID, sysOID) # Create an SNMP context snmpContext = context.SnmpContext(snmpEngine) # --- create custom Managed Object Instance ---
def _configure_udp_transport(self, listen_address, listen_port): pysnmp.entity.config.addSocketTransport( self._snmp_engine, udp.domainName, udp.UdpTransport().openServerMode((listen_address, listen_port))) log.info("TrapReceiver: Initialized SNMP UDP Transport on %s:%s" % (listen_address, listen_port))