def checkSNMP(community, host, port, oid): mibBuilder = builder.MibBuilder() mibViewController = view.MibViewController(mibBuilder) compiler.addMibCompiler(mibBuilder, sources=['http://mibs.snmplabs.com/asn1/@mib@']) mibBuilder.loadModules('RFC1213-MIB', 'IF-MIB') objectIdentity = rfc1902.ObjectIdentity(oid).resolveWithMib( mibViewController) errorIndication, errorStatus, errorIndex, varBinds = next( getCmd(SnmpEngine(), CommunityData(community), UdpTransportTarget((host, port), timeout=1.5, retries=0), ContextData(), ObjectType(objectIdentity))) if errorIndication: print(errorIndication, " : ", host) elif errorStatus: print('%s at %s' % (errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex) - 1][0] or '?')) else: for varBind in varBinds: varB = (' = '.join([x.prettyPrint() for x in varBind])) resultado = " ".join(varB.split()[2:]) return resultado return -1
def __init__(self, args): configDict = loadConfig(args.config) self.moduleLogger = set_logging(configDict, __class__.__name__) self.moduleLogger.debug('configDict:{}'.format(configDict)) mibBuilder = builder.MibBuilder() self._mibViewController = view.MibViewController(mibBuilder) compiler.addMibCompiler( mibBuilder, sources=configDict['snmp'].get('mibs', ())) # this dict holds all OID items indexed by MIB symbols self._mibObjects = collections.defaultdict(dict) # this dict holds only recently updated OIDs (indexed by # MIB name and object) self._candidateMibObjects = collections.defaultdict(dict) # this dict holds all OID items populated from `mibObjects` self._oids = {} self._expireBy = time.time() + self.EXPIRE_PERIOD self._dirty = True # OIDs need sorting
def generator(cbCtx, ast): snmpEngine, ctx = cbCtx if 'mibViewProxy' not in ctx: ctx['mibViewProxy'] = MibViewProxy(ctx['mibViewController']) # compiler.addMibCompiler(snmpEngine.getMibBuilder()) snmpEngine, ctx = _MibViewGenerator().preorder((snmpEngine, ctx), ast) if 'MibDir' not in ctx: ctx['MibDir'] = [DEFAULT_MIB_SOURCE_URL] if 'MibBorrowers' not in ctx: ctx['MibBorrowers'] = [DEFAULT_MIB_BORROWER_URL] compiler.addMibCompiler(snmpEngine.getMibBuilder(), sources=ctx['MibDir'], borrowers=ctx['MibBorrowers']) if 'MibFiles' in ctx: mibBuilder = snmpEngine.getMibBuilder() for mibFile in ctx['MibFiles']: if mibFile.lower() == 'all': mibBuilder.loadModules() else: mibBuilder.loadModules(mibFile) return snmpEngine, ctx
def consultaSNMP(comunidad,host,oid): mibBuilder = builder.MibBuilder() mibViewController = view.MibViewController(mibBuilder) compiler.addMibCompiler(mibBuilder, sources=['file:///usr/local/lib/python2.7/dist-packages/pysnmp/smi/mibs', 'http://mibs.snmplabs.com/asn1/@mib@']) mibBuilder.loadModules('RFC1213-MIB','IF-MIB') objectIdentity = rfc1902.ObjectIdentity(oid).resolveWithMib(mibViewController) errorIndication, errorStatus, errorIndex, varBinds = next( getCmd(SnmpEngine(), CommunityData(comunidad), UdpTransportTarget((host, 161)), ContextData(), #ObjectType(ObjectIdentity(oid)))) ObjectType( objectIdentity ))) if errorIndication: print(errorIndication) elif errorStatus: print('%s at %s' % (errorStatus.prettyPrint(),errorIndex and varBinds[int(errorIndex) - 1][0] or '?')) else: for varBind in varBinds: varB=(' = '.join([x.prettyPrint() for x in varBind])) resultado= " ".join(varB.split()[2:]) return resultado
def listen( address=DEFAULT_ADDRESSS, port=DEFAULT_PORT, community=DEFAULT_COMMUNITY, mibs=DEFAULT_MIBS, ): """Listen to and SNMP trap and print events.""" # Based on pySNMP example code. mib_builder = builder.MibBuilder() compiler.addMibCompiler(mib_builder) mib_builder.loadModules(*mibs) global _view_controller _view_controller = view.MibViewController(mib_builder) loop = asyncio.get_event_loop() snmp_engine = engine.SnmpEngine() print(f"Agent is listening SNMP Trap on {address}, Port: {port}") if port < 1024: print( "WARNING: Port < 1024. Root priviledges or authbind required on *nix systems." ) print("-" * 79) config.addTransport( snmp_engine, udp.domainName + (1, ), udp.UdpTransport().openServerMode((address, port)), ) config.addV1System(snmp_engine, community, community) ntfrcv.NotificationReceiver(snmp_engine, _listen_callback) print("Press CTRL-C to quit.") loop.run_forever()
def translate_mib(custom_mib_paths, load_mib_modules, name, val): """ Translate OID to MIB custom_mib_paths: comma separated mib paths as a string load_mib_modules: MIB Module to load e.g. "MIB-FILE-1,MIB-FILE-2" Return: Translated OID string and value """ if custom_mib_paths and load_mib_modules: try: mibBuilder = builder.MibBuilder() compiler.addMibCompiler(mibBuilder, sources=custom_mib_paths) mibViewController = view.MibViewController(mibBuilder) temp_load_mib_modules = load_mib_modules.split(',') mibBuilder.loadModules(*temp_load_mib_modules) except error.MibNotFoundError as excep: testcase_Utils.pNote(" {} Mib Not Found!".format(excep), "Error") temp_type = val.__class__.__name__ if custom_mib_paths and load_mib_modules: output = rfc1902.ObjectType(rfc1902.ObjectIdentity(name), val).resolveWithMib(mibViewController).prettyPrint() op_list = output.split(" = ") name = op_list[0].strip() t_val = op_list[1].strip() if temp_type == "Integer": testcase_Utils.pNote('%s = %s(%s): %s' % (name, temp_type, val.prettyPrint(), t_val)) else: if t_val == '': #For empty String testcase_Utils.pNote('%s = %s: ""' % (name, temp_type)) else: testcase_Utils.pNote('%s = %s: %s' % (name, temp_type, t_val)) return name, t_val else: testcase_Utils.pNote('%s = %s: %s' % (name.prettyPrint(), temp_type, val.prettyPrint())) return name.prettyPrint(), val.prettyPrint()
def __init__(self, **kwargs): self.standard_mibs = [] self.mongo_client = pymongo.MongoClient(MONGO_URI) if kwargs.get("no_mongo"): self.session = Session() else: self.session = CachedLimiterSession( per_second=120, cache_name="cache_http", backend=MongoCache(connection=self.mongo_client, db_name=MONGO_DB), expire_after=1800, match_headers=False, stale_if_error=True, allowable_codes=[200], ) self.profiles = load_profiles() self.last_modified = time.time() self.snmpEngine = SnmpEngine() self.builder = self.snmpEngine.getMibBuilder() self.mib_view_controller = view.MibViewController(self.builder) compiler.addMibCompiler(self.builder, sources=[MIB_SOURCES]) # mib_standard_response = self.session.get(f"{MIB_STANDARD}", stream=True) # if mib_standard_response.status_code == 200: # for line in mib_standard_response.iter_lines(): # if line: # mib = line.decode("utf-8") # logger.info(f"MIB: {mib}") # try: # self.builder.loadModules(mib) # self.standard_mibs.append(mib) # except Exception as e: # logger.warning(f"An error occurred during loading MIB module: {mib}: {e}") # else: for mib in DEFAULT_STANDARD_MIBS: self.standard_mibs.append(mib) self.builder.loadModules(mib) mib_response = self.session.get(f"{MIB_INDEX}") self.mib_map = {} if mib_response.status_code == 200: with StringIO(mib_response.text) as index_csv: reader = csv.reader(index_csv) for each_row in reader: if len(each_row) == 2: self.mib_map[each_row[1]] = each_row[0] logger.debug(f"Loaded {len(self.mib_map.keys())} mib map entries") else: logger.error( f"Unable to load mib map from index http error {self.mib_response.status_code}" )
def mib_builder(custom_mib_path, LOAD_MIB_MODULE): mibBuilder = builder.MibBuilder() try: if custom_mib_path: compiler.addMibCompiler(mibBuilder, sources=custom_mib_path.split( ",")) global mibViewController mibViewController = view.MibViewController(mibBuilder) if LOAD_MIB_MODULE: _mibs=LOAD_MIB_MODULE.split(",") mibBuilder.loadModules(*_mibs) except error.MibNotFoundError as excep: print(" {} Mib Not Found!".format(excep))
def get_first_node_name(mib_filepath, mib_filename): """ Get the node name from the given mib file path and file name :param mib_filepath: Mib file path of the git url or abs file path :param mib_filename: MIB file name :return: oid, lable, suffix, mibView, mibBuilder """ mibBuilder = builder.MibBuilder() compiler.addMibCompiler(mibBuilder, sources=mib_filepath.split(",")) for mib in mib_filename.split(","): mibBuilder.loadModules(mib) mibView = view.MibViewController(mibBuilder) oid, label, suffix = mibView.getFirstNodeName() return oid, label, suffix, mibView, mibBuilder
def generator(cbCtx, ast): snmpEngine, ctx = cbCtx if 'mibViewProxy' not in ctx: ctx['mibViewProxy'] = MibViewProxy(ctx['mibViewController']) compiler.addMibCompiler(snmpEngine.getMibBuilder()) snmpEngine, ctx = __MibViewGenerator().preorder((snmpEngine, ctx), ast) if 'MibDir' not in ctx: ctx['MibDir'] = [defaultMibSourceUrl] if 'MibBorrowers' not in ctx: ctx['MibBorrowers'] = [defaultMibBorrowerUrl] compiler.addMibCompiler(snmpEngine.getMibBuilder(), sources=ctx['MibDir'], borrowers=ctx['MibBorrowers']) return snmpEngine, ctx
def generator(cbCtx, ast): snmpEngine, ctx = cbCtx if 'mibViewProxy' not in ctx: ctx['mibViewProxy'] = MibViewProxy(ctx['mibViewController']) compiler.addMibCompiler(snmpEngine.getMibBuilder()) snmpEngine, ctx = __MibViewGenerator().preorder((snmpEngine, ctx), ast) if 'MibDir' not in ctx: ctx['MibDir'] = [ defaultMibSourceUrl ] if 'MibBorrowers' not in ctx: ctx['MibBorrowers'] = [ defaultMibBorrowerUrl ] compiler.addMibCompiler(snmpEngine.getMibBuilder(), sources=ctx['MibDir'], borrowers=ctx['MibBorrowers']) return snmpEngine, ctx
def __init__(self, additional_mib_search_paths=[], additional_mib_load_modules=[], debug=False, load_texts=True): if debug: # Enable Debugging pysnmp_debug.setLogger(pysnmp_debug.Debug('all')) # The pysnmp libraries will compile MIB files into python files, and # store them on the system in a cache directory under ~/.pysnmp/mibs # It only needs to do this once as it encounters new MIBs, and not # every time you run this program. Order of the loading matters. mib_modules = additional_mib_load_modules + DEFAULT_MIB_LOAD_MODULES mib_sources = additional_mib_search_paths + DEFAULT_MIB_SEARCH_PATHS self.mibBuilder = builder.MibBuilder() self.mibBuilder.loadTexts = load_texts # Loads mib text descriptions compiler.addMibCompiler(self.mibBuilder, sources=mib_sources) self.mibBuilder.loadModules(*mib_modules) self.mibView = view.MibViewController(self.mibBuilder)
def create_trap_listner_job(cls, port="162"): """ Create Trap listner job :param port: :return:None """ mibBuilder = builder.MibBuilder() custom_mib_path = cls.data_repo.get("custom_mib_path") load_mib_module = cls.data_repo.get("load_mib_module") temp_custom_mib_paths = [] if custom_mib_path and load_mib_module: custom_mib_paths = custom_mib_path.split(',') for paths in custom_mib_paths: paths = paths.strip() if 'http' in paths and '@mib@' not in paths: if paths[-1] == '/': paths = paths + '/@mib@' else: paths = paths + '@mib@' if 'http' in paths and 'browse' in paths: paths = paths.replace('browse', 'raw') if 'http' in paths and 'browse' in paths: paths = paths.replace('browse', 'raw') temp_custom_mib_paths.append(paths) if os.name == 'posix' and '/usr/share/snmp/' not in custom_mib_path: temp_custom_mib_paths.append('/usr/share/snmp/') try: compiler.addMibCompiler(mibBuilder, sources=temp_custom_mib_paths) cls.mibViewController = view.MibViewController(mibBuilder) mibs = load_mib_module.split(",") mibBuilder.loadModules(*mibs) except error.MibNotFoundError as excep: testcase_Utils.pNote("{} Mib Not Found!".format(excep), "Error") snmpEngine = cls.get_asyncoredispatcher(port) udptransport = udp.UdpTransport() cls.udptransport.update({"udptransport{}".format(port): udptransport}) config.addTransport( snmpEngine, udp.domainName, udptransport.openServerMode(('0.0.0.0', int(port)))) snmpEngine.transportDispatcher.jobStarted(1)
def _configureMibObjects(self, configDict): mibBuilder = builder.MibBuilder() mibViewController = view.MibViewController(mibBuilder) compiler.addMibCompiler( mibBuilder, sources=configDict['snmp'].get('mibs', ())) self._sysUpTime = rfc1902.ObjectIdentity( 'SNMPv2-MIB', 'sysUpTime', 0).resolveWithMib(mibViewController) self._snmpTrapOID = rfc1902.ObjectIdentity( 'SNMPv2-MIB', 'snmpTrapOID', 0).resolveWithMib(mibViewController) self._rtbrickSyslogTrap = rfc1902.ObjectIdentity( 'RTBRICK-SYSLOG-MIB', 'rtbrickSyslogTrap', 1).resolveWithMib(mibViewController) self._syslogMsgNumber = rfc1902.ObjectIdentity( 'RTBRICK-SYSLOG-MIB', 'syslogMsgNumber', 0).resolveWithMib(mibViewController) self._syslogMsgFacility = rfc1902.ObjectIdentity( 'RTBRICK-SYSLOG-MIB', 'syslogMsgFacility', 0).resolveWithMib(mibViewController) self._syslogMsgSeverity = rfc1902.ObjectIdentity( 'RTBRICK-SYSLOG-MIB', 'syslogMsgSeverity', 0).resolveWithMib(mibViewController) self._syslogMsgText = rfc1902.ObjectIdentity( 'RTBRICK-SYSLOG-MIB', 'syslogMsgText', 0).resolveWithMib(mibViewController) self.moduleLogger.info( f'Notifications will include these SNMP objects: ' f'{self._sysUpTime}=TimeTicks, ' f'{self._snmpTrapOID}={self._rtbrickSyslogTrap} ' f'{self._syslogMsgNumber}=Unsigned32 ' f'{self._syslogMsgFacility}=OctetString ' f'{self._syslogMsgSeverity}=Integer32 ' f'{self._syslogMsgText}=OctetString')
def main(): parser = argparse.ArgumentParser(description=DESCRIPTION) parser.add_argument( '-v', '--version', action='version', version=utils.TITLE) parser.add_argument( '--quiet', action='store_true', help='Do not print out informational messages') parser.add_argument( '--debug', choices=debug.flagMap, action='append', type=str, default=[], help='Enable one or more categories of SNMP debugging.') parser.add_argument( '--row-hint', dest='row_hint', action='store_true', help='Hint for MIBs Type') parser.add_argument( '--mib-source', dest='mib_sources', metavar='<URI|PATH>', action='append', type=str, default=['http://mibs.snmplabs.com/asn1/@mib@'], help='One or more URIs pointing to a collection of ASN.1 MIB files.' 'Optional "@mib@" token gets replaced with desired MIB module ' 'name during MIB search.') parser.add_argument( '--mib-module', dest='mib_modules', action='append', type=str, required=True, help='MIB module to generate simulation data from') parser.add_argument( '--start-object', metavar='<MIB::Object|OID>', type=_parse_mib_object, help='Drop all simulation data records prior to this OID specified ' 'as MIB object (MIB::Object) or OID (1.3.6.)') parser.add_argument( '--stop-object', metavar='<MIB::Object|OID>', type=functools.partial(_parse_mib_object, last=True), help='Drop all simulation data records after this OID specified ' 'as MIB object (MIB::Object) or OID (1.3.6.)') parser.add_argument( '--manual-values', action='store_true', help='Fill all managed objects values interactively') parser.add_argument( '--automatic-values', type=int, default=5000, help='Probe for suitable managed object value this many times ' 'prior to failing over to manual value specification') parser.add_argument( '--table-size', type=int, default=10, help='Generate SNMP conceptual tables with this many rows') parser.add_argument( '--destination-record-type', choices=RECORD_TYPES, default='snmprec', help='Produce simulation data with record of this type') parser.add_argument( '--output-file', metavar='<FILE>', type=str, help='SNMP simulation data file to write records to') parser.add_argument( '--string-pool', metavar='<words>', action='append', help='Words to use for simulated string values') parser.add_argument( '--string-pool-file', metavar='<FILE>', type=str, help='File containing the words for simulating SNMP string values') parser.add_argument( '--integer32-range', metavar='<min,max>', type=_parse_range, default=(0, 32), help='Range of values used to populate simulated Integer32 values') parser.add_argument( '--unsigned-range', metavar='<min,max>', type=_parse_range, default=(0, 65535), help='Range of values used to populate simulated Unsigned values') parser.add_argument( '--counter-range', metavar='<min,max>', type=_parse_range, default=(0, 0xffffffff), help='Range of values used to populate simulated Counter values') parser.add_argument( '--counter64-range', metavar='<min,max>', type=_parse_range, default=(0, 0xffffffffffffffff), help='Range of values used to populate simulated Counter64 values') parser.add_argument( '--gauge-range', metavar='<min,max>', type=_parse_range, default=(0, 0xffffffff), help='Range of values used to populate simulated Gauge values') parser.add_argument( '--timeticks-range', metavar='<min,max>', type=_parse_range, default=(0, 0xffffffff), help='Range of values used to populate simulated Timeticks values') args = parser.parse_args() if args.debug: debug.setLogger(debug.Debug(*args.debug)) if args.manual_values: args.automatic_values = 0 if args.string_pool_file: with open(args.string_pool_file) as fl: args.string_pool = fl.read().split() elif args.string_pool: args.string_pool = ['Jaded', 'zombies', 'acted', 'quaintly', 'but', 'kept', 'driving', 'their', 'oxen', 'forward'] if args.output_file: ext = os.path.extsep + RECORD_TYPES[args.destination_record_type].ext if not args.output_file.endswith(ext): args.output_file += ext args.output_file = RECORD_TYPES[args.destination_record_type].open( args.output_file, 'wb') else: args.output_file = sys.stdout if sys.version_info >= (3, 0, 0): # binary mode write args.output_file = sys.stdout.buffer elif sys.platform == "win32": import msvcrt msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) def get_value(syntax, hint='', automatic_values=args.automatic_values): make_guess = args.automatic_values val = None while True: if make_guess: if isinstance(syntax, rfc1902.IpAddress): val = '.'.join([str(random.randrange(1, 256)) for x in range(4)]) elif isinstance(syntax, rfc1902.TimeTicks): val = random.randrange(args.timeticks_range[0], args.timeticks_range[1]) elif isinstance(syntax, rfc1902.Gauge32): val = random.randrange(args.gauge_range[0], args.gauge_range[1]) elif isinstance(syntax, rfc1902.Counter32): val = random.randrange(args.counter_range[0], args.counter_range[1]) elif isinstance(syntax, rfc1902.Integer32): val = random.randrange(args.integer32_range[0], args.integer32_range[1]) elif isinstance(syntax, rfc1902.Unsigned32): val = random.randrange(args.unsigned_range[0], args.unsigned_range[1]) elif isinstance(syntax, rfc1902.Counter64): val = random.randrange(args.counter64_range[0], args.counter64_range[1]) elif isinstance(syntax, univ.OctetString): maxWords = 10 val = ' '.join([args.string_pool[random.randrange(0, len(args.string_pool))] for i in range(random.randrange(1, maxWords))]) elif isinstance(syntax, univ.ObjectIdentifier): val = '.'.join(['1', '3', '6', '1', '3'] + [ '%d' % random.randrange(0, 255) for x in range(random.randrange(0, 10))]) elif isinstance(syntax, rfc1902.Bits): val = [random.randrange(0, 256) for x in range(random.randrange(0, 9))] else: val = '?' # remove value enumeration try: if syntax.tagSet == rfc1902.Integer32.tagSet: return rfc1902.Integer32(syntax.clone(val)) if syntax.tagSet == rfc1902.Unsigned32.tagSet: return rfc1902.Unsigned32(syntax.clone(val)) if syntax.tagSet == rfc1902.Bits.tagSet: return rfc1902.OctetString(syntax.clone(val)) return syntax.clone(val) except PyAsn1Error as exc: if make_guess == 1: sys.stderr.write( '*** Inconsistent value: %s\r\n*** See constraints and ' 'suggest a better one for:\r\n' % exc) if make_guess: make_guess -= 1 continue sys.stderr.write('%s# Value [\'%s\'] ? ' % ( hint, (val is None and '<none>' or val),)) sys.stderr.flush() line = sys.stdin.readline().strip() if line: if line[:2] == '0x': if line[:4] == '0x0x': line = line[2:] elif isinstance(syntax, univ.OctetString): val = syntax.clone(hexValue=line[2:]) else: val = int(line[2:], 16) else: val = line data_file_handler = snmprec.SnmprecRecord() mib_builder = builder.MibBuilder() # Load MIB tree foundation classes (MibScalar, MibTable, MibTableRow, MibTableColumn) = mib_builder.importSymbols( 'SNMPv2-SMI', 'MibScalar', 'MibTable', 'MibTableRow', 'MibTableColumn' ) mib_view_controller = view.MibViewController(mib_builder) compiler.addMibCompiler(mib_builder, sources=args.mib_sources) try: if isinstance(args.start_object, ObjectIdentity): args.start_object.resolveWithMib(mib_view_controller) if isinstance(args.stop_object, ObjectIdentity): args.stop_object.resolveWithMib(mib_view_controller) except error.PySnmpError as exc: sys.stderr.write('ERROR: %s\r\n' % exc) return 1 output = [] # MIBs walk for modName in args.mib_modules: if not args.quiet: sys.stderr.write( '# MIB module: %s, from %s till ' '%s\r\n' % (modName, args.start_object or 'the beginning', args.stop_object or 'the end')) try: oid = ObjectIdentity(modName).resolveWithMib(mib_view_controller) except error.PySnmpError as exc: sys.stderr.write('ERROR: failed on MIB %s: ' '%s\r\n' % (modName, exc)) return 1 hint = row_hint = '' row_oid = None suffix = () this_table_size = 0 while True: try: oid, label, _ = mib_view_controller.getNextNodeName(oid) except error.NoSuchObjectError: break if row_oid and not row_oid.isPrefixOf(oid): this_table_size += 1 if args.automatic_values: if this_table_size < args.table_size: oid = tuple(row_oid) if not args.quiet: sys.stderr.write( '# Synthesizing row #%d of table %s\r\n' % ( this_table_size, row_oid)) else: if not args.quiet: sys.stderr.write( '# Finished table %s (%d rows)\r\n' % ( row_oid, this_table_size)) row_oid = None else: while True: sys.stderr.write( '# Synthesize row #%d for table %s (y/n)? ' % ( this_table_size, row_oid)) sys.stderr.flush() line = sys.stdin.readline().strip() if line: if line[0] in ('y', 'Y'): oid = tuple(row_oid) break elif line[0] in ('n', 'N'): if not args.quiet: sys.stderr.write( '# Finished table %s (%d rows)\r\n' % ( row_oid, this_table_size)) row_oid = None break if args.start_object and oid < args.start_object: continue # skip on premature OID if args.stop_object and oid > args.stop_object: break # stop on out of range condition mib_name, sym_name, _ = mib_view_controller.getNodeLocation(oid) node, = mib_builder.importSymbols(mib_name, sym_name) if isinstance(node, MibTable): hint = '# Table %s::%s\r\n' % (mib_name, sym_name) if not args.quiet: sys.stderr.write( '# Starting table %s::%s (%s)\r\n' % ( mib_name, sym_name, univ.ObjectIdentifier(oid))) continue elif isinstance(node, MibTableRow): row_indices = {} suffix = () row_hint = hint + '# Row %s::%s\r\n' % (mib_name, sym_name) for (implied_flag, idx_mod_name, idx_sym_name) in node.getIndexNames(): idxNode, = mib_builder.importSymbols( idx_mod_name, idx_sym_name) row_hint += '# Index %s::%s (type %s)\r\n' % ( idx_mod_name, idx_sym_name, idxNode.syntax.__class__.__name__) row_indices[idxNode.name] = get_value( idxNode.syntax, not args.quiet and row_hint or '') suffix = suffix + node.getAsName( row_indices[idxNode.name], implied_flag) if not row_indices: if not args.quiet: sys.stderr.write( '# WARNING: %s::%s table has no index!\r\n' % ( mib_name, sym_name)) if row_oid is None: this_table_size = 0 row_oid = univ.ObjectIdentifier(oid) continue elif isinstance(node, MibTableColumn): oid = node.name if oid in row_indices: val = row_indices[oid] else: hint = '' if not args.quiet: hint += row_hint hint += ('# Column %s::%s (type' ' %s)\r\n' % (mib_name, sym_name, node.syntax.__class__.__name__)) val = get_value(node.syntax, hint) elif isinstance(node, MibScalar): hint = '' if not args.row_hint: hint += ('# Scalar %s::%s (type %s)' '\r\n' % (mib_name, sym_name, node.syntax.__class__.__name__)) oid = node.name suffix = (0,) val = get_value(node.syntax, hint) else: hint = '' continue output.append((oid + suffix, val)) output.sort(key=lambda x: univ.ObjectIdentifier(x[0])) unique = set() for oid, val in output: if oid in unique: if not args.quiet: sys.stderr.write( '# Dropping duplicate OID %s\r\n' % ( univ.ObjectIdentifier(oid),)) else: try: args.output_file.write(data_file_handler.format(oid, val)) except SnmpsimError as exc: sys.stderr.write('ERROR: %s\r\n' % (exc,)) else: unique.add(oid) if not args.quiet: sys.stderr.write( '# End of %s, %s OID(s) dumped\r\n' % (modName, len(unique))) args.output_file.flush() args.output_file.close() return 0
# Load MIB tree foundation classes (MibScalar, MibTable, MibTableRow, MibTableColumn) = mibBuilder.importSymbols( 'SNMPv2-SMI', 'MibScalar', 'MibTable', 'MibTableRow', 'MibTableColumn' ) mibViewController = view.MibViewController(mibBuilder) compiler.addMibCompiler( mibBuilder, sources=mibSources or defaultMibSources ) try: if isinstance(startOID, ObjectIdentity): startOID.resolveWithMib(mibViewController) if isinstance(stopOID, ObjectIdentity): stopOID.resolveWithMib(mibViewController) except error.PySnmpError: sys.stderr.write('ERROR: %s\r\n' % sys.exc_info()[1]) sys.exit(-1) output = []
""" PDU var-binds to MIB objects ++++++++++++++++++++++++++++ This script explains how Python application could turn SNMP PDU variable-bindings into MIB objects or the other way around. The code that configures MIB compiler is similar to what happens inside the pysnmp.hlapi API. """# from pysnmp.smi import builder, view, compiler, rfc1902 # Assemble MIB browser mibBuilder = builder.MibBuilder() mibViewController = view.MibViewController(mibBuilder) compiler.addMibCompiler(mibBuilder, sources=['file:///usr/share/snmp/mibs', 'http://mibs.snmplabs.com/asn1/@mib@']) # Pre-load MIB modules we expect to work with mibBuilder.loadModules('SNMPv2-MIB', 'SNMP-COMMUNITY-MIB') # This is what we can get in TRAP PDU varBinds = [ ('1.3.6.1.2.1.1.3.0', 12345), ('1.3.6.1.6.3.1.1.4.1.0', '1.3.6.1.6.3.1.1.5.2'), ('1.3.6.1.6.3.18.1.3.0', '0.0.0.0'), ('1.3.6.1.6.3.18.1.4.0', ''), ('1.3.6.1.6.3.1.1.4.3.0', '1.3.6.1.4.1.20408.4.1.1.2'), ('1.3.6.1.2.1.1.1.0', 'my system') ] # Run var-binds through MIB resolver
def __init__(self, host, port, raw_mibs, compiled_mibs): self.oid_mapping = {} self.databus_mediator = DatabusMediator(self.oid_mapping) # mapping between OID and databus keys # Create SNMP engine self.snmpEngine = engine.SnmpEngine() # Configure SNMP compiler mib_builder = self.snmpEngine.getMibBuilder() addMibCompiler(mib_builder, destination=compiled_mibs) mib_builder.getMibCompiler().addSources(FileReader(raw_mibs)) mib_builder.getMibCompiler().addSources( FtpReader("ftp.cisco.com", "/pub/mibs/v2/@mib@", 80)) # Transport setup udp_sock = gevent.socket.socket(gevent.socket.AF_INET, gevent.socket.SOCK_DGRAM) udp_sock.setsockopt(gevent.socket.SOL_SOCKET, gevent.socket.SO_BROADCAST, 1) udp_sock.bind((host, port)) self.server_port = udp_sock.getsockname()[1] # UDP over IPv4 self.addSocketTransport(self.snmpEngine, udp.domainName, udp_sock) # SNMPv1 config.addV1System(self.snmpEngine, "public-read", "public") # SNMPv3/USM setup # user: usr-md5-des, auth: MD5, priv DES config.addV3User( self.snmpEngine, "usr-md5-des", config.usmHMACMD5AuthProtocol, "authkey1", config.usmDESPrivProtocol, "privkey1", ) # user: usr-sha-none, auth: SHA, priv NONE config.addV3User(self.snmpEngine, "usr-sha-none", config.usmHMACSHAAuthProtocol, "authkey1") # user: usr-sha-aes128, auth: SHA, priv AES/128 config.addV3User( self.snmpEngine, "usr-sha-aes128", config.usmHMACSHAAuthProtocol, "authkey1", config.usmAesCfb128Protocol, "privkey1", ) # Allow full MIB access for each user at VACM config.addVacmUser( self.snmpEngine, 1, "public-read", "noAuthNoPriv", readSubTree=(1, 3, 6, 1, 2, 1), writeSubTree=(1, 3, 6, 1, 2, 1), ) config.addVacmUser( self.snmpEngine, 2, "public-read", "noAuthNoPriv", readSubTree=(1, 3, 6, 1, 2, 1), writeSubTree=(1, 3, 6, 1, 2, 1), ) config.addVacmUser( self.snmpEngine, 3, "usr-md5-des", "authPriv", readSubTree=(1, 3, 6, 1, 2, 1), writeSubTree=(1, 3, 6, 1, 2, 1), ) config.addVacmUser( self.snmpEngine, 3, "usr-sha-none", "authNoPriv", readSubTree=(1, 3, 6, 1, 2, 1), writeSubTree=(1, 3, 6, 1, 2, 1), ) config.addVacmUser( self.snmpEngine, 3, "usr-sha-aes128", "authPriv", readSubTree=(1, 3, 6, 1, 2, 1), writeSubTree=(1, 3, 6, 1, 2, 1), ) # Get default SNMP context this SNMP engine serves snmpContext = context.SnmpContext(self.snmpEngine) # Register SNMP Applications at the SNMP engine for particular SNMP context self.resp_app_get = conpot_cmdrsp.c_GetCommandResponder( self.snmpEngine, snmpContext, self.databus_mediator, host, port) self.resp_app_set = conpot_cmdrsp.c_SetCommandResponder( self.snmpEngine, snmpContext, self.databus_mediator, host, port) self.resp_app_next = conpot_cmdrsp.c_NextCommandResponder( self.snmpEngine, snmpContext, self.databus_mediator, host, port) self.resp_app_bulk = conpot_cmdrsp.c_BulkCommandResponder( self.snmpEngine, snmpContext, self.databus_mediator, host, port)
'pms', timeout, retryCount) log.info('Querying UNIX named pipe agent at %s' % agentUNIXEndpoint) elif agentUDPv4Endpoint: config.addSocketTransport(snmpEngine, udp.domainName, udp.UdpSocketTransport().openClientMode()) config.addTargetAddr(snmpEngine, 'tgt', udp.domainName, agentUDPv4Endpoint, 'pms', timeout, retryCount) log.info('Querying UDP/IPv4 agent at %s:%s' % agentUDPv4Endpoint) log.info('Agent response timeout: %.2f secs, retries: %s' % (timeout / 100, retryCount)) if (isinstance(startOID, ObjectIdentity) or isinstance(stopOID, ObjectIdentity)): compiler.addMibCompiler(snmpEngine.getMibBuilder(), sources=mibSources or defaultMibSources) mibViewController = view.MibViewController(snmpEngine.getMibBuilder()) if isinstance(startOID, ObjectIdentity): startOID.resolveWithMib(mibViewController) if isinstance(stopOID, ObjectIdentity): stopOID.resolveWithMib(mibViewController) # Variation module initialization if variationModule: log.info('Initializing variation module...') for x in ('init', 'record', 'shutdown'): if x not in variationModule: log.error('missing "%s" handler at variation module "%s"' % (x, variationModuleName)) sys.exit(-1)
udp.UdpSocketTransport().openClientMode()) config.addTargetAddr( snmpEngine, 'tgt', udp.domainName, agentUDPv4Endpoint, 'pms', timeout, retryCount) log.info('Querying UDP/IPv4 agent at %s:%s' % agentUDPv4Endpoint) log.info('Agent response timeout: %.2f secs, retries: ' '%s' % (timeout / 100, retryCount)) if (isinstance(startOID, ObjectIdentity) or isinstance(stopOID, ObjectIdentity)): compiler.addMibCompiler( snmpEngine.getMibBuilder(), sources=mibSources or defaultMibSources) mibViewController = view.MibViewController(snmpEngine.getMibBuilder()) try: if isinstance(startOID, ObjectIdentity): startOID.resolveWithMib(mibViewController) if isinstance(stopOID, ObjectIdentity): stopOID.resolveWithMib(mibViewController) except PySnmpError: sys.stderr.write('ERROR: %s\r\n' % sys.exc_info()[1]) sys.exit(-1)
from app import app, db from controllers import * from pysnmp.hlapi import * from pysnmp.smi import builder, view, compiler from multiprocessing import Process mibBuilder = builder.MibBuilder() mibViewController = view.MibViewController(mibBuilder) compiler.addMibCompiler(mibBuilder, sources=['file:///usr/share/snmp/mibs']) mibBuilder.loadModules('SNMPv2-MIB', 'RFC1213-MIB', 'IF-MIB') class DispositivoSNMP: def __init__(self, dispositivo): self.dispositivo = dispositivo self._ip = dispositivo.ip self.deltaTime = 600 dispController = DispositivoController() self.interfaces = [ InterfazSNMP(interfaz) for interfaz in dispController.getInterfacesDispositivo(dispositivo) ] class InterfazSNMP: def __init__(self, iface): self.number = iface.puerto self.name = iface.nombre self.deltaTime = 600 self._ifIn = 0 self._ifOut = 0
++++++++++++++++++++++++++++ This script explains how Python application could turn SNMP PDU variable-bindings into MIB objects or the other way around. The code that configures MIB compiler is similar to what happens inside the pysnmp.hlapi API. """# from pysnmp.smi import builder, view, compiler, rfc1902 # Assemble MIB browser mibBuilder = builder.MibBuilder() mibViewController = view.MibViewController(mibBuilder) compiler.addMibCompiler(mibBuilder, sources=[ 'file:///usr/share/snmp/mibs', 'http://mibs.snmplabs.com/asn1/@mib@' ]) # Pre-load MIB modules we expect to work with mibBuilder.loadModules('SNMPv2-MIB', 'SNMP-COMMUNITY-MIB') # This is what we can get in TRAP PDU varBinds = [('1.3.6.1.2.1.1.3.0', 12345), ('1.3.6.1.6.3.1.1.4.1.0', '1.3.6.1.6.3.1.1.5.2'), ('1.3.6.1.6.3.18.1.3.0', '0.0.0.0'), ('1.3.6.1.6.3.18.1.4.0', ''), ('1.3.6.1.6.3.1.1.4.3.0', '1.3.6.1.4.1.20408.4.1.1.2'), ('1.3.6.1.2.1.1.1.0', 'my system')] # Run var-binds through MIB resolver # You may want to catch and ignore resolution errors here
This script performs similar to the following Net-SNMP command: | $ snmpwalk -v1 -c public -ObentU 104.236.166.95 1.3.6.1.2.1.1 1.3.6.1.4.1.1 """# from pysnmp.entity import engine, config from pysnmp.carrier.asyncore.dgram import udp from pysnmp.entity.rfc3413 import cmdgen from pysnmp.smi import compiler, view, rfc1902 # Create SNMP engine instance snmpEngine = engine.SnmpEngine() # Attach MIB compiler to SNMP Engine (MIB Builder) # This call will fail if PySMI is not present on the system compiler.addMibCompiler(snmpEngine.getMibBuilder()) # ... alternatively, this call will not complain on missing PySMI # compiler.addMibCompiler(snmpEngine.getMibBuilder(), ifAvailable=True) # Used for MIB objects resolution mibViewController = view.MibViewController(snmpEngine.getMibBuilder()) # # # SNMPv1/2c setup # # SecurityName <-> CommunityName mapping config.addV1System(snmpEngine, 'my-area', 'public') # Specify security settings per SecurityName (SNMPv1 - 0, SNMPv2c - 1)
def main(): lost_comments = False written_count = skipped_count = duplicate_count = 0 broken_count = variation_count = 0 parser = argparse.ArgumentParser(description=DESCRIPTION) parser.add_argument('-v', '--version', action='version', version=utils.TITLE) parser.add_argument('--quiet', action='store_true', help='Do not print out informational messages') parser.add_argument('--sort-records', action='store_true', help='Order simulation data records by OID') parser.add_argument( '--ignore-broken-records', action='store_true', help='Drop malformed simulation data records rather than bailing out') parser.add_argument('--deduplicate-records', action='store_true', help='Drop duplicate simulation data records') parser.add_argument( '--escaped-strings', action='store_true', help='Produce Python-style escaped strings (e.g. "\x00") in ' 'simulation data values rather than hexify such non-ASCII ' 'values') parser.add_argument( '--start-object', metavar='<MIB::Object|OID>', type=_parse_mib_object, help='Drop all simulation data records prior to this OID specified ' 'as MIB object (MIB::Object) or OID (1.3.6.)') parser.add_argument( '--stop-object', metavar='<MIB::Object|OID>', type=functools.partial(_parse_mib_object, last=True), help='Drop all simulation data records after this OID specified ' 'as MIB object (MIB::Object) or OID (1.3.6.)') parser.add_argument( '--mib-source', dest='mib_sources', metavar='<URI|PATH>', action='append', type=str, help='One or more URIs pointing to a collection of ASN.1 MIB files.' 'Optional "@mib@" token gets replaced with desired MIB module ' 'name during MIB search.') parser.add_argument( '--source-record-type', choices=RECORD_TYPES, default='snmprec', help='Treat input as simulation data of this record type') parser.add_argument( '--destination-record-type', choices=RECORD_TYPES, default='snmprec', help='Produce simulation data with record of this type') parser.add_argument('--input-file', dest='input_files', metavar='<FILE>', action='append', type=str, required=True, help='SNMP simulation data file to read records from') parser.add_argument('--output-file', metavar='<FILE>', type=str, help='SNMP simulation data file to write records to') args = parser.parse_args() if not args.mib_source: args.mib_source = ['http://mibs.snmplabs.com/asn1/@mib@'] args.input_files = [ RECORD_TYPES[args.source_record_type].open(x) for x in args.input_files ] if args.output_file and args.output_file != '-': ext = os.path.extsep + RECORD_TYPES[args.destination_record_type].ext if not args.output_file.endswith(ext): args.output_file += ext args.output_file = RECORD_TYPES[args.destination_record_type].open( args.output_file, 'wb') else: args.output_file = sys.stdout if sys.version_info >= (3, 0, 0): # binary mode write args.output_file = sys.stdout.buffer elif sys.platform == "win32": import msvcrt msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) if not args.input_files: args.input_files.append(sys.stdin) if (isinstance(args.start_oid, rfc1902.ObjectIdentity) or isinstance(args.stop_oid, rfc1902.ObjectIdentity)): mib_builder = builder.MibBuilder() mib_view_controller = view.MibViewController(mib_builder) compiler.addMibCompiler(mib_builder, sources=args.mib_sources) try: if isinstance(args.start_oid, rfc1902.ObjectIdentity): args.start_oid.resolveWithMib(mib_view_controller) if isinstance(args.stop_oid, rfc1902.ObjectIdentity): args.stop_oid.resolveWithMib(mib_view_controller) except PySnmpError as exc: sys.stderr.write('ERROR: %s\r\n' % exc) return 1 records_list = [] for input_file in args.input_files: if not args.quiet: sys.stderr.write( '# Input file #%s, processing records from %s till ' '%s\r\n' % (args.input_files.index(input_file), args.start_oid or 'the beginning', args.stop_oid or 'the end')) line_no = 0 while True: line, rec_line_no, _ = get_record(input_file, line_no) if not line: break if rec_line_no != line_no + 1: if not args.quiet: sys.stderr.write( '# Losing comment at lines %s..%s (input file #' '%s)\r\n' % (line_no + 1, rec_line_no - 1, args.input_files.index(input_file))) line_no = rec_line_no lost_comments += 1 backdoor = {} try: oid, value = RECORD_TYPES[args.source_record_type].evaluate( line, backdoor=backdoor) except error.SnmpsimError as exc: if args.ignore_broken_records: if not args.quiet: sys.stderr.write('# Skipping broken record <%s>: ' '%s\r\n' % (line, exc)) broken_count += 1 continue else: if not args.quiet: sys.stderr.write('ERROR: broken record <%s>: ' '%s\r\n' % (line, exc)) return 1 if (args.start_oid and args.start_oid > oid or args.stop_oid and args.stop_oid < oid): skipped_count += 1 continue records_list.append((oid, value, backdoor)) if args.sort_records: records_list.sort(key=lambda x: x[0]) unique_indices = set() for record in records_list: if args.deduplicate_records: if record[0] in unique_indices: if not args.quiet: sys.stderr.write('# Skipping duplicate record ' '<%s>\r\n' % record[0]) duplicate_count += 1 continue else: unique_indices.add(record[0]) try: args.output_file.write( RECORD_TYPES[args.destination_record_type].format( record[0], record[1], backdoor=record[2], nohex=args.escaped_strings)) except Exception as exc: sys.stderr.write('ERROR: record not written: %s\r\n' % exc) break written_count += 1 if record[2]: variation_count += 1 if not args.quiet: sys.stderr.write( '# Records: written %s, filtered out %s, de-duplicated %s, ignored ' '%s, broken %s, variated %s\r\n' % (written_count, skipped_count, duplicate_count, lost_comments, broken_count, variation_count)) args.output_file.flush() args.output_file.close() return 0
if len(sys.argv) > 2: snmpip = sys.argv[2] if len(sys.argv) > 3: szOutputfile = sys.argv[3] if len(sys.argv) > 4: szSnmpLogfile = sys.argv[4] # Create output files outputFile = open(szOutputfile, "w+") logFile = open(szSnmpLogfile, "a+") # Assemble MIB viewer mibBuilder = builder.MibBuilder() compiler.addMibCompiler(mibBuilder, sources=[ 'file:///usr/share/snmp/mibs', 'file:///var/lib/snmp/mibs', '/usr/local/share/snmp/mibs/' ]) mibViewController = view.MibViewController(mibBuilder) # Pre-load MIB modules we expect to work with try: mibBuilder.loadModules('SNMPv2-MIB', 'SNMP-COMMUNITY-MIB', 'SYSLOG-MSG-MIB') except Exception: print("Failed loading MIBs") # Create SNMP engine with autogenernated engineID and pre-bound to socket transport dispatcher snmpEngine = engine.SnmpEngine() # Transport setup # UDP over IPv4, add listening interface/port
from pysnmp.smi import builder, view, compiler, error from pysnmp import debug debug.setLogger(debug.Debug('dsp')) # Create MIB loader/builder mibBuilder = builder.MibBuilder() # Optionally attach PySMI MIB compiler (if installed) print('Attaching MIB compiler...'), compiler.addMibCompiler( mibBuilder, sources=['/usr/share/snmp/mibs/', 'http://mibs.snmplabs.com/asn1/']) print('done') # Optionally set an alternative path to compiled MIBs print('Setting MIB sources...') mibBuilder.addMibSources(builder.DirMibSource('/usr/share/snmp/mibs/')) print(mibBuilder.getMibSources()) print('done') print('Loading MIB modules...'), mibBuilder.loadModules('SNMPv2-MIB', 'SNMP-FRAMEWORK-MIB', 'SNMP-COMMUNITY-MIB', 'IP-MIB', 'SNMPHANDLER-MIB') print('done') print('Indexing MIB objects...'), mibView = view.MibViewController(mibBuilder) print('done') print('MIB symbol name lookup by OID: '),
def resolveWithMib(self, mibViewController): """Perform MIB variable ID conversion. Parameters ---------- mibViewController : :py:class:`~pysnmp.smi.view.MibViewController` class instance representing MIB browsing functionality. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` reference to itself Raises ------ SmiError In case of fatal MIB hanling errora Notes ----- Calling this method might cause the following sequence of events (exact details depends on many factors): * ASN.1 MIB file downloaded and handed over to :py:class:`~pysmi.compiler.MibCompiler` for conversion into Python MIB module (based on pysnmp classes) * Python MIB module is imported by SNMP engine, internal indices created * :py:class:`~pysnmp.smi.view.MibViewController` looks up the rest of MIB identification information based on whatever information is already available, :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` class instance gets updated and ready for further use. Examples -------- >>> objectIdentity = ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> objectIdentity.resolveWithMib(mibViewController) ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> """ if self.__mibSourcesToAdd is not None: debug.logger & debug.flagMIB and debug.logger("adding MIB sources %s" % ", ".join(self.__mibSourcesToAdd)) mibViewController.mibBuilder.addMibSources(*[ZipMibSource(x) for x in self.__mibSourcesToAdd]) self.__mibSourcesToAdd = None if self.__asn1SourcesToAdd is None: addMibCompiler(mibViewController.mibBuilder, ifAvailable=True, ifNotAdded=True) else: debug.logger & debug.flagMIB and debug.logger( "adding MIB compiler with source paths %s" % ", ".join(self.__asn1SourcesToAdd) ) addMibCompiler( mibViewController.mibBuilder, sources=self.__asn1SourcesToAdd, searchers=self.__asn1SourcesOptions.get("searchers"), borrowers=self.__asn1SourcesOptions.get("borrowers"), destination=self.__asn1SourcesOptions.get("destination"), ifAvailable=self.__asn1SourcesOptions.get("ifAvailable"), ifNotAdded=self.__asn1SourcesOptions.get("ifNotAdded"), ) self.__asn1SourcesToAdd = self.__asn1SourcesOptions = None if self.__modNamesToLoad is not None: debug.logger & debug.flagMIB and debug.logger("loading MIB modules %s" % ", ".join(self.__modNamesToLoad)) mibViewController.mibBuilder.loadModules(*self.__modNamesToLoad) self.__modNamesToLoad = None if self.__state & self.stClean: return self MibScalar, MibTableColumn = mibViewController.mibBuilder.importSymbols( "SNMPv2-SMI", "MibScalar", "MibTableColumn" ) self.__indices = () if isinstance(self.__args[0], ObjectIdentity): self.__args[0].resolveWithMib(mibViewController) if len(self.__args) == 1: # OID or label or MIB module debug.logger & debug.flagMIB and debug.logger("resolving %s as OID or label" % self.__args) try: # pyasn1 ObjectIdentifier or sequence of ints or string OID self.__oid = rfc1902.ObjectName(self.__args[0]) # OID except PyAsn1Error: # sequence of sub-OIDs and labels if isinstance(self.__args[0], (list, tuple)): prefix, label, suffix = mibViewController.getNodeName(self.__args[0]) # string label elif "." in self.__args[0]: prefix, label, suffix = mibViewController.getNodeNameByOid(tuple(self.__args[0].split("."))) # MIB module name else: modName = self.__args[0] mibViewController.mibBuilder.loadModules(modName) if self.__kwargs.get("last"): prefix, label, suffix = mibViewController.getLastNodeName(modName) else: prefix, label, suffix = mibViewController.getFirstNodeName(modName) if suffix: try: suffix = tuple([int(x) for x in suffix]) except ValueError: raise SmiError("Unknown object name component %r" % (suffix,)) self.__oid = rfc1902.ObjectName(prefix + suffix) else: prefix, label, suffix = mibViewController.getNodeNameByOid(self.__oid) debug.logger & debug.flagMIB and debug.logger( "resolved %r into prefix %r and suffix %r" % (self.__args, prefix, suffix) ) modName, symName, _ = mibViewController.getNodeLocation(prefix) self.__modName = modName self.__symName = symName self.__label = label mibNode, = mibViewController.mibBuilder.importSymbols(modName, symName) self.__mibNode = mibNode debug.logger & debug.flagMIB and debug.logger("resolved prefix %r into MIB node %r" % (prefix, mibNode)) if isinstance(mibNode, MibTableColumn): # table column if suffix: rowModName, rowSymName, _ = mibViewController.getNodeLocation(mibNode.name[:-1]) rowNode, = mibViewController.mibBuilder.importSymbols(rowModName, rowSymName) self.__indices = rowNode.getIndicesFromInstId(suffix) elif isinstance(mibNode, MibScalar): # scalar if suffix: self.__indices = (rfc1902.ObjectName(suffix),) else: if suffix: self.__indices = (rfc1902.ObjectName(suffix),) self.__state |= self.stClean debug.logger & debug.flagMIB and debug.logger("resolved indices are %r" % (self.__indices,)) return self elif len(self.__args) > 1: # MIB, symbol[, index, index ...] # MIB, symbol, index, index if self.__args[0] and self.__args[1]: self.__modName = self.__args[0] self.__symName = self.__args[1] # MIB, '' elif self.__args[0]: mibViewController.mibBuilder.loadModules(self.__args[0]) if self.__kwargs.get("last"): prefix, label, suffix = mibViewController.getLastNodeName(self.__args[0]) else: prefix, label, suffix = mibViewController.getFirstNodeName(self.__args[0]) self.__modName, self.__symName, _ = mibViewController.getNodeLocation(prefix) # '', symbol, index, index else: prefix, label, suffix = mibViewController.getNodeName(self.__args[1:]) self.__modName, self.__symName, _ = mibViewController.getNodeLocation(prefix) mibNode, = mibViewController.mibBuilder.importSymbols(self.__modName, self.__symName) self.__mibNode = mibNode self.__oid = rfc1902.ObjectName(mibNode.getName()) prefix, label, suffix = mibViewController.getNodeNameByOid(self.__oid) self.__label = label debug.logger & debug.flagMIB and debug.logger( "resolved %r into prefix %r and suffix %r" % (self.__args, prefix, suffix) ) if isinstance(mibNode, MibTableColumn): # table rowModName, rowSymName, _ = mibViewController.getNodeLocation(mibNode.name[:-1]) rowNode, = mibViewController.mibBuilder.importSymbols(rowModName, rowSymName) if self.__args[2:]: try: instIds = rowNode.getInstIdFromIndices(*self.__args[2:]) self.__oid += instIds self.__indices = rowNode.getIndicesFromInstId(instIds) except PyAsn1Error: raise SmiError( "Instance index %r to OID convertion failure at object %r: %s" % (self.__args[2:], mibNode.getLabel(), sys.exc_info()[1]) ) elif self.__args[2:]: # any other kind of MIB node with indices if self.__args[2:]: instId = rfc1902.ObjectName(".".join([str(x) for x in self.__args[2:]])) self.__oid += instId self.__indices = (instId,) self.__state |= self.stClean debug.logger & debug.flagMIB and debug.logger("resolved indices are %r" % (self.__indices,)) return self else: raise SmiError("Non-OID, label or MIB symbol")
if __name__ == "__main__": args = parse_input() # Specify the absolute path of the MIB files lib_path = join(dirname(dirname(abspath(__file__))), 'labSNMP') ansi_mib_path = 'file:///' + join(lib_path, 'MIB') py_mib_path = join(lib_path, 'compiled') # FIXME: Use environmental variables to enable pysnmp to load compiled mibs # I've tried to use addMibSources, and it can load the file in advance, but # it just refuses to use it. environ['PYSNMP_MIB_PKGS'] = py_mib_path mibBuilder = builder.MibBuilder() compiler.addMibCompiler( mibBuilder, sources=[ansi_mib_path, 'http://mibs.snmplabs.com/asn1/@mib@']) # FIXME: If non-precompiled MIB is needed, it must be loaded first # mibBuilder.loadModules('WIENER-CRATE-MIB') if args.var is not None: oidtype = ObjectType(ObjectIdentity(*args.oids), args.var) else: oidtype = ObjectType(ObjectIdentity(*args.oids)) queryCmd = findCmd(args.mode)(SnmpEngine(), CommunityData(args.community), UdpTransportTarget((args.host[0], 161)), ContextData(), oidtype) try:
def main(): variation_module = None parser = argparse.ArgumentParser(description=DESCRIPTION) parser.add_argument( '-v', '--version', action='version', version=utils.TITLE) parser.add_argument( '--quiet', action='store_true', help='Do not print out informational messages') parser.add_argument( '--debug', choices=pysnmp_debug.flagMap, action='append', type=str, default=[], help='Enable one or more categories of SNMP debugging.') parser.add_argument( '--debug-asn1', choices=pyasn1_debug.FLAG_MAP, action='append', type=str, default=[], help='Enable one or more categories of ASN.1 debugging.') parser.add_argument( '--logging-method', type=lambda x: x.split(':'), metavar='=<%s[:args]>]' % '|'.join(log.METHODS_MAP), default='stderr', help='Logging method.') parser.add_argument( '--log-level', choices=log.LEVELS_MAP, type=str, default='info', help='Logging level.') v1arch_group = parser.add_argument_group('SNMPv1/v2c parameters') v1arch_group.add_argument( '--protocol-version', choices=['1', '2c'], default='2c', help='SNMPv1/v2c protocol version') v1arch_group.add_argument( '--community', type=str, default='public', help='SNMP community name') v3arch_group = parser.add_argument_group('SNMPv3 parameters') v3arch_group.add_argument( '--v3-user', metavar='<STRING>', type=functools.partial(_parse_sized_string, min_length=1), help='SNMPv3 USM user (security) name') v3arch_group.add_argument( '--v3-auth-key', type=_parse_sized_string, help='SNMPv3 USM authentication key (must be > 8 chars)') v3arch_group.add_argument( '--v3-auth-proto', choices=AUTH_PROTOCOLS, type=lambda x: x.upper(), default='NONE', help='SNMPv3 USM authentication protocol') v3arch_group.add_argument( '--v3-priv-key', type=_parse_sized_string, help='SNMPv3 USM privacy (encryption) key (must be > 8 chars)') v3arch_group.add_argument( '--v3-priv-proto', choices=PRIV_PROTOCOLS, type=lambda x: x.upper(), default='NONE', help='SNMPv3 USM privacy (encryption) protocol') v3arch_group.add_argument( '--v3-context-engine-id', type=lambda x: univ.OctetString(hexValue=x[2:]), help='SNMPv3 context engine ID') v3arch_group.add_argument( '--v3-context-name', type=str, default='', help='SNMPv3 context engine ID') parser.add_argument( '--use-getbulk', action='store_true', help='Use SNMP GETBULK PDU for mass SNMP managed objects retrieval') parser.add_argument( '--getbulk-repetitions', type=int, default=25, help='Use SNMP GETBULK PDU for mass SNMP managed objects retrieval') endpoint_group = parser.add_mutually_exclusive_group(required=True) endpoint_group.add_argument( '--agent-udpv4-endpoint', type=endpoints.parse_endpoint, metavar='<[X.X.X.X]:NNNNN>', help='SNMP agent UDP/IPv4 address to pull simulation data ' 'from (name:port)') endpoint_group.add_argument( '--agent-udpv6-endpoint', type=functools.partial(endpoints.parse_endpoint, ipv6=True), metavar='<[X:X:..X]:NNNNN>', help='SNMP agent UDP/IPv6 address to pull simulation data ' 'from ([name]:port)') parser.add_argument( '--timeout', type=int, default=3, help='SNMP command response timeout (in seconds)') parser.add_argument( '--retries', type=int, default=3, help='SNMP command retries') parser.add_argument( '--start-object', metavar='<MIB::Object|OID>', type=_parse_mib_object, default=univ.ObjectIdentifier('1.3.6'), help='Drop all simulation data records prior to this OID specified ' 'as MIB object (MIB::Object) or OID (1.3.6.)') parser.add_argument( '--stop-object', metavar='<MIB::Object|OID>', type=functools.partial(_parse_mib_object, last=True), help='Drop all simulation data records after this OID specified ' 'as MIB object (MIB::Object) or OID (1.3.6.)') parser.add_argument( '--mib-source', dest='mib_sources', metavar='<URI|PATH>', action='append', type=str, default=['http://mibs.snmplabs.com/asn1/@mib@'], help='One or more URIs pointing to a collection of ASN.1 MIB files.' 'Optional "@mib@" token gets replaced with desired MIB module ' 'name during MIB search.') parser.add_argument( '--destination-record-type', choices=variation.RECORD_TYPES, default='snmprec', help='Produce simulation data with record of this type') parser.add_argument( '--output-file', metavar='<FILE>', type=str, help='SNMP simulation data file to write records to') parser.add_argument( '--continue-on-errors', metavar='<tolerance-level>', type=int, default=0, help='Keep on pulling SNMP data even if intermittent errors occur') variation_group = parser.add_argument_group( 'Simulation data variation options') parser.add_argument( '--variation-modules-dir', action='append', type=str, help='Search variation module by this path') variation_group.add_argument( '--variation-module', type=str, help='Pass gathered simulation data through this variation module') variation_group.add_argument( '--variation-module-options', type=str, default='', help='Variation module options') args = parser.parse_args() if args.debug: pysnmp_debug.setLogger(pysnmp_debug.Debug(*args.debug)) if args.debug_asn1: pyasn1_debug.setLogger(pyasn1_debug.Debug(*args.debug_asn1)) if args.output_file: ext = os.path.extsep ext += variation.RECORD_TYPES[args.destination_record_type].ext if not args.output_file.endswith(ext): args.output_file += ext record = variation.RECORD_TYPES[args.destination_record_type] args.output_file = record.open(args.output_file, 'wb') else: args.output_file = sys.stdout if sys.version_info >= (3, 0, 0): # binary mode write args.output_file = sys.stdout.buffer elif sys.platform == "win32": import msvcrt msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) # Catch missing params if args.protocol_version == '3': if not args.v3_user: sys.stderr.write('ERROR: --v3-user is missing\r\n') parser.print_usage(sys.stderr) return 1 if args.v3_priv_key and not args.v3_auth_key: sys.stderr.write('ERROR: --v3-auth-key is missing\r\n') parser.print_usage(sys.stderr) return 1 if AUTH_PROTOCOLS[args.v3_auth_proto] == config.usmNoAuthProtocol: if args.v3_auth_key: args.v3_auth_proto = 'MD5' else: if not args.v3_auth_key: sys.stderr.write('ERROR: --v3-auth-key is missing\r\n') parser.print_usage(sys.stderr) return 1 if PRIV_PROTOCOLS[args.v3_priv_proto] == config.usmNoPrivProtocol: if args.v3_priv_key: args.v3_priv_proto = 'DES' else: if not args.v3_priv_key: sys.stderr.write('ERROR: --v3-priv-key is missing\r\n') parser.print_usage(sys.stderr) return 1 proc_name = os.path.basename(sys.argv[0]) try: log.set_logger(proc_name, *args.logging_method, force=True) if args.log_level: log.set_level(args.log_level) except error.SnmpsimError as exc: sys.stderr.write('%s\r\n' % exc) parser.print_usage(sys.stderr) return 1 if args.use_getbulk and args.protocol_version == '1': log.info('will be using GETNEXT with SNMPv1!') args.use_getbulk = False # Load variation module if args.variation_module: for variation_modules_dir in ( args.variation_modules_dir or confdir.variation): log.info( 'Scanning "%s" directory for variation ' 'modules...' % variation_modules_dir) if not os.path.exists(variation_modules_dir): log.info('Directory "%s" does not exist' % variation_modules_dir) continue mod = os.path.join(variation_modules_dir, args.variation_module + '.py') if not os.path.exists(mod): log.info('Variation module "%s" not found' % mod) continue ctx = {'path': mod, 'moduleContext': {}} try: with open(mod) as fl: exec (compile(fl.read(), mod, 'exec'), ctx) except Exception as exc: log.error('Variation module "%s" execution failure: ' '%s' % (mod, exc)) return 1 variation_module = ctx log.info('Variation module "%s" loaded' % args.variation_module) break else: log.error('variation module "%s" not found' % args.variation_module) return 1 # SNMP configuration snmp_engine = engine.SnmpEngine() if args.protocol_version == '3': if args.v3_priv_key is None and args.v3_auth_key is None: secLevel = 'noAuthNoPriv' elif args.v3_priv_key is None: secLevel = 'authNoPriv' else: secLevel = 'authPriv' config.addV3User( snmp_engine, args.v3_user, AUTH_PROTOCOLS[args.v3_auth_proto], args.v3_auth_key, PRIV_PROTOCOLS[args.v3_priv_proto], args.v3_priv_key) log.info( 'SNMP version 3, Context EngineID: %s Context name: %s, SecurityName: %s, ' 'SecurityLevel: %s, Authentication key/protocol: %s/%s, Encryption ' '(privacy) key/protocol: ' '%s/%s' % ( args.v3_context_engine_id and args.v3_context_engine_id.prettyPrint() or '<default>', args.v3_context_name and args.v3_context_name.prettyPrint() or '<default>', args.v3_user, secLevel, args.v3_auth_key is None and '<NONE>' or args.v3_auth_key, args.v3_auth_proto, args.v3_priv_key is None and '<NONE>' or args.v3_priv_key, args.v3_priv_proto)) else: args.v3_user = '******' secLevel = 'noAuthNoPriv' config.addV1System(snmp_engine, args.v3_user, args.community) log.info( 'SNMP version %s, Community name: ' '%s' % (args.protocol_version, args.community)) config.addTargetParams( snmp_engine, 'pms', args.v3_user, secLevel, VERSION_MAP[args.protocol_version]) if args.agent_udpv6_endpoint: config.addSocketTransport( snmp_engine, udp6.domainName, udp6.Udp6SocketTransport().openClientMode()) config.addTargetAddr( snmp_engine, 'tgt', udp6.domainName, args.agent_udpv6_endpoint, 'pms', args.timeout * 100, args.retries) log.info('Querying UDP/IPv6 agent at [%s]:%s' % args.agent_udpv6_endpoint) elif args.agent_udpv4_endpoint: config.addSocketTransport( snmp_engine, udp.domainName, udp.UdpSocketTransport().openClientMode()) config.addTargetAddr( snmp_engine, 'tgt', udp.domainName, args.agent_udpv4_endpoint, 'pms', args.timeout * 100, args.retries) log.info('Querying UDP/IPv4 agent at %s:%s' % args.agent_udpv4_endpoint) log.info('Agent response timeout: %d secs, retries: ' '%s' % (args.timeout, args.retries)) if (isinstance(args.start_object, ObjectIdentity) or isinstance(args.stop_object, ObjectIdentity)): compiler.addMibCompiler( snmp_engine.getMibBuilder(), sources=args.mib_sources) mib_view_controller = view.MibViewController( snmp_engine.getMibBuilder()) try: if isinstance(args.start_object, ObjectIdentity): args.start_object.resolveWithMib(mib_view_controller) if isinstance(args.stop_object, ObjectIdentity): args.stop_object.resolveWithMib(mib_view_controller) except PySnmpError as exc: sys.stderr.write('ERROR: %s\r\n' % exc) return 1 # Variation module initialization if variation_module: log.info('Initializing variation module...') for x in ('init', 'record', 'shutdown'): if x not in variation_module: log.error('missing "%s" handler at variation module ' '"%s"' % (x, args.variation_module)) return 1 try: handler = variation_module['init'] handler(snmpEngine=snmp_engine, options=args.variation_module_options, mode='recording', startOID=args.start_object, stopOID=args.stop_object) except Exception as exc: log.error( 'Variation module "%s" initialization FAILED: ' '%s' % (args.variation_module, exc)) else: log.info( 'Variation module "%s" initialization OK' % args.variation_module) data_file_handler = variation.RECORD_TYPES[args.destination_record_type] # SNMP worker def cbFun(snmp_engine, send_request_handle, error_indication, error_status, error_index, var_bind_table, cb_ctx): if error_indication and not cb_ctx['retries']: cb_ctx['errors'] += 1 log.error('SNMP Engine error: %s' % error_indication) return # SNMPv1 response may contain noSuchName error *and* SNMPv2c exception, # so we ignore noSuchName error here if error_status and error_status != 2 or error_indication: log.error( 'Remote SNMP error %s' % ( error_indication or error_status.prettyPrint())) if cb_ctx['retries']: try: next_oid = var_bind_table[-1][0][0] except IndexError: next_oid = cb_ctx['lastOID'] else: log.error('Failed OID: %s' % next_oid) # fuzzy logic of walking a broken OID if len(next_oid) < 4: pass elif (args.continue_on_errors - cb_ctx['retries']) * 10 / args.continue_on_errors > 5: next_oid = next_oid[:-2] + (next_oid[-2] + 1,) elif next_oid[-1]: next_oid = next_oid[:-1] + (next_oid[-1] + 1,) else: next_oid = next_oid[:-2] + (next_oid[-2] + 1, 0) cb_ctx['retries'] -= 1 cb_ctx['lastOID'] = next_oid log.info( 'Retrying with OID %s (%s retries left)' '...' % (next_oid, cb_ctx['retries'])) # initiate another SNMP walk iteration if args.use_getbulk: cmd_gen.sendVarBinds( snmp_engine, 'tgt', args.v3_context_engine_id, args.v3_context_name, 0, args.getbulk_repetitions, [(next_oid, None)], cbFun, cb_ctx) else: cmd_gen.sendVarBinds( snmp_engine, 'tgt', args.v3_context_engine_id, args.v3_context_name, [(next_oid, None)], cbFun, cb_ctx) cb_ctx['errors'] += 1 return if args.continue_on_errors != cb_ctx['retries']: cb_ctx['retries'] += 1 if var_bind_table and var_bind_table[-1] and var_bind_table[-1][0]: cb_ctx['lastOID'] = var_bind_table[-1][0][0] stop_flag = False # Walk var-binds for var_bind_row in var_bind_table: for oid, value in var_bind_row: # EOM if args.stop_object and oid >= args.stop_object: stop_flag = True # stop on out of range condition elif (value is None or value.tagSet in (rfc1905.NoSuchObject.tagSet, rfc1905.NoSuchInstance.tagSet, rfc1905.EndOfMibView.tagSet)): stop_flag = True # remove value enumeration if value.tagSet == rfc1902.Integer32.tagSet: value = rfc1902.Integer32(value) if value.tagSet == rfc1902.Unsigned32.tagSet: value = rfc1902.Unsigned32(value) if value.tagSet == rfc1902.Bits.tagSet: value = rfc1902.OctetString(value) # Build .snmprec record context = { 'origOid': oid, 'origValue': value, 'count': cb_ctx['count'], 'total': cb_ctx['total'], 'iteration': cb_ctx['iteration'], 'reqTime': cb_ctx['reqTime'], 'args.start_object': args.start_object, 'stopOID': args.stop_object, 'stopFlag': stop_flag, 'variationModule': variation_module } try: line = data_file_handler.format(oid, value, **context) except error.MoreDataNotification as exc: cb_ctx['count'] = 0 cb_ctx['iteration'] += 1 more_data_notification = exc if 'period' in more_data_notification: log.info( '%s OIDs dumped, waiting %.2f sec(s)' '...' % (cb_ctx['total'], more_data_notification['period'])) time.sleep(more_data_notification['period']) # initiate another SNMP walk iteration if args.use_getbulk: cmd_gen.sendVarBinds( snmp_engine, 'tgt', args.v3_context_engine_id, args.v3_context_name, 0, args.getbulk_repetitions, [(args.start_object, None)], cbFun, cb_ctx) else: cmd_gen.sendVarBinds( snmp_engine, 'tgt', args.v3_context_engine_id, args.v3_context_name, [(args.start_object, None)], cbFun, cb_ctx) stop_flag = True # stop current iteration except error.NoDataNotification: pass except error.SnmpsimError as exc: log.error(exc) continue else: args.output_file.write(line) cb_ctx['count'] += 1 cb_ctx['total'] += 1 if cb_ctx['count'] % 100 == 0: log.info('OIDs dumped: %s/%s' % ( cb_ctx['iteration'], cb_ctx['count'])) # Next request time cb_ctx['reqTime'] = time.time() # Continue walking return not stop_flag cb_ctx = { 'total': 0, 'count': 0, 'errors': 0, 'iteration': 0, 'reqTime': time.time(), 'retries': args.continue_on_errors, 'lastOID': args.start_object } if args.use_getbulk: cmd_gen = cmdgen.BulkCommandGenerator() cmd_gen.sendVarBinds( snmp_engine, 'tgt', args.v3_context_engine_id, args.v3_context_name, 0, args.getbulk_repetitions, [(args.start_object, rfc1902.Null(''))], cbFun, cb_ctx) else: cmd_gen = cmdgen.NextCommandGenerator() cmd_gen.sendVarBinds( snmp_engine, 'tgt', args.v3_context_engine_id, args.v3_context_name, [(args.start_object, rfc1902.Null(''))], cbFun, cb_ctx) log.info( 'Sending initial %s request for %s (stop at %s)' '....' % (args.use_getbulk and 'GETBULK' or 'GETNEXT', args.start_object, args.stop_object or '<end-of-mib>')) started = time.time() try: snmp_engine.transportDispatcher.runDispatcher() except KeyboardInterrupt: log.info('Shutting down process...') finally: if variation_module: log.info('Shutting down variation module ' '%s...' % args.variation_module) try: handler = variation_module['shutdown'] handler(snmpEngine=snmp_engine, options=args.variation_module_options, mode='recording') except Exception as exc: log.error( 'Variation module %s shutdown FAILED: ' '%s' % (args.variation_module, exc)) else: log.info( 'Variation module %s shutdown OK' % args.variation_module) snmp_engine.transportDispatcher.closeDispatcher() started = time.time() - started cb_ctx['total'] += cb_ctx['count'] log.info( 'OIDs dumped: %s, elapsed: %.2f sec, rate: %.2f OIDs/sec, errors: ' '%d' % (cb_ctx['total'], started, started and cb_ctx['count'] // started or 0, cb_ctx['errors'])) args.output_file.flush() args.output_file.close() return cb_ctx.get('errors', 0) and 1 or 0
def resolveWithMib(self, mibViewController): """Perform MIB variable ID conversion. Parameters ---------- mibViewController : :py:class:`~pysnmp.smi.view.MibViewController` class instance representing MIB browsing functionality. Returns ------- : :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` reference to itself Raises ------ SmiError In case of fatal MIB hanling errora Notes ----- Calling this method might cause the following sequence of events (exact details depends on many factors): * ASN.1 MIB file downloaded and handed over to :py:class:`~pysmi.compiler.MibCompiler` for conversion into Python MIB module (based on pysnmp classes) * Python MIB module is imported by SNMP engine, internal indices created * :py:class:`~pysnmp.smi.view.MibViewController` looks up the rest of MIB identification information based on whatever information is already available, :py:class:`~pysnmp.smi.rfc1902.ObjectIdentity` class instance gets updated and ready for further use. Examples -------- >>> objectIdentity = ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> objectIdentity.resolveWithMib(mibViewController) ObjectIdentity('SNMPv2-MIB', 'sysDescr') >>> """ if self.__mibSourcesToAdd is not None: debug.logger & debug.flagMIB and debug.logger('adding MIB sources %s' % ', '.join(self.__mibSourcesToAdd)) mibViewController.mibBuilder.addMibSources( *[ZipMibSource(x) for x in self.__mibSourcesToAdd] ) self.__mibSourcesToAdd = None if self.__asn1SourcesToAdd is None: addMibCompiler(mibViewController.mibBuilder, ifAvailable=True, ifNotAdded=True) else: debug.logger & debug.flagMIB and debug.logger( 'adding MIB compiler with source paths %s' % ', '.join(self.__asn1SourcesToAdd)) addMibCompiler( mibViewController.mibBuilder, sources=self.__asn1SourcesToAdd, searchers=self.__asn1SourcesOptions.get('searchers'), borrowers=self.__asn1SourcesOptions.get('borrowers'), destination=self.__asn1SourcesOptions.get('destination'), ifAvailable=self.__asn1SourcesOptions.get('ifAvailable'), ifNotAdded=self.__asn1SourcesOptions.get('ifNotAdded') ) self.__asn1SourcesToAdd = self.__asn1SourcesOptions = None if self.__modNamesToLoad is not None: debug.logger & debug.flagMIB and debug.logger('loading MIB modules %s' % ', '.join(self.__modNamesToLoad)) mibViewController.mibBuilder.loadModules(*self.__modNamesToLoad) self.__modNamesToLoad = None if self.__state & self.stClean: return self MibScalar, MibTableColumn = mibViewController.mibBuilder.importSymbols('SNMPv2-SMI', 'MibScalar', 'MibTableColumn') self.__indices = () if isinstance(self.__args[0], ObjectIdentity): self.__args[0].resolveWithMib(mibViewController) if len(self.__args) == 1: # OID or label or MIB module debug.logger & debug.flagMIB and debug.logger('resolving %s as OID or label' % self.__args) try: # pyasn1 ObjectIdentifier or sequence of ints or string OID self.__oid = rfc1902.ObjectName(self.__args[0]) # OID except PyAsn1Error: # sequence of sub-OIDs and labels if isinstance(self.__args[0], (list, tuple)): prefix, label, suffix = mibViewController.getNodeName( self.__args[0] ) # string label elif '.' in self.__args[0]: prefix, label, suffix = mibViewController.getNodeNameByOid( tuple(self.__args[0].split('.')) ) # MIB module name else: modName = self.__args[0] mibViewController.mibBuilder.loadModules(modName) if self.__kwargs.get('last'): prefix, label, suffix = mibViewController.getLastNodeName(modName) else: prefix, label, suffix = mibViewController.getFirstNodeName(modName) if suffix: try: suffix = tuple([int(x) for x in suffix]) except ValueError: raise SmiError('Unknown object name component %r' % (suffix,)) self.__oid = rfc1902.ObjectName(prefix + suffix) else: prefix, label, suffix = mibViewController.getNodeNameByOid( self.__oid ) debug.logger & debug.flagMIB and debug.logger( 'resolved %r into prefix %r and suffix %r' % (self.__args, prefix, suffix)) modName, symName, _ = mibViewController.getNodeLocation(prefix) self.__modName = modName self.__symName = symName self.__label = label mibNode, = mibViewController.mibBuilder.importSymbols( modName, symName ) self.__mibNode = mibNode debug.logger & debug.flagMIB and debug.logger('resolved prefix %r into MIB node %r' % (prefix, mibNode)) if isinstance(mibNode, MibTableColumn): # table column if suffix: rowModName, rowSymName, _ = mibViewController.getNodeLocation( mibNode.name[:-1] ) rowNode, = mibViewController.mibBuilder.importSymbols( rowModName, rowSymName ) self.__indices = rowNode.getIndicesFromInstId(suffix) elif isinstance(mibNode, MibScalar): # scalar if suffix: self.__indices = (rfc1902.ObjectName(suffix),) else: if suffix: self.__indices = (rfc1902.ObjectName(suffix),) self.__state |= self.stClean debug.logger & debug.flagMIB and debug.logger('resolved indices are %r' % (self.__indices,)) return self elif len(self.__args) > 1: # MIB, symbol[, index, index ...] # MIB, symbol, index, index if self.__args[0] and self.__args[1]: self.__modName = self.__args[0] self.__symName = self.__args[1] # MIB, '' elif self.__args[0]: mibViewController.mibBuilder.loadModules(self.__args[0]) if self.__kwargs.get('last'): prefix, label, suffix = mibViewController.getLastNodeName(self.__args[0]) else: prefix, label, suffix = mibViewController.getFirstNodeName(self.__args[0]) self.__modName, self.__symName, _ = mibViewController.getNodeLocation(prefix) # '', symbol, index, index else: prefix, label, suffix = mibViewController.getNodeName(self.__args[1:]) self.__modName, self.__symName, _ = mibViewController.getNodeLocation(prefix) mibNode, = mibViewController.mibBuilder.importSymbols( self.__modName, self.__symName ) self.__mibNode = mibNode self.__oid = rfc1902.ObjectName(mibNode.getName()) prefix, label, suffix = mibViewController.getNodeNameByOid( self.__oid ) self.__label = label debug.logger & debug.flagMIB and debug.logger( 'resolved %r into prefix %r and suffix %r' % (self.__args, prefix, suffix)) if isinstance(mibNode, MibTableColumn): # table rowModName, rowSymName, _ = mibViewController.getNodeLocation( mibNode.name[:-1] ) rowNode, = mibViewController.mibBuilder.importSymbols( rowModName, rowSymName ) if self.__args[2:]: try: instIds = rowNode.getInstIdFromIndices(*self.__args[2:]) self.__oid += instIds self.__indices = rowNode.getIndicesFromInstId(instIds) except PyAsn1Error: raise SmiError('Instance index %r to OID convertion failure at object %r: %s' % ( self.__args[2:], mibNode.getLabel(), sys.exc_info()[1])) elif self.__args[2:]: # any other kind of MIB node with indices if self.__args[2:]: instId = rfc1902.ObjectName( '.'.join([str(x) for x in self.__args[2:]]) ) self.__oid += instId self.__indices = (instId,) self.__state |= self.stClean debug.logger & debug.flagMIB and debug.logger('resolved indices are %r' % (self.__indices,)) return self else: raise SmiError('Non-OID, label or MIB symbol')
def main(): class MibTreeProxyMixIn(object): MIB_INTRUMENTATION_CALL = None def _getMgmtFun(self, contextName): return self._routeToMibTree def _routeToMibTree(self, *varBinds, **context): cbFun = context['cbFun'] mibTreeReq = gCurrentRequestContext.copy() pdu = mibTreeReq['snmp-pdu'] pluginIdList = mibTreeReq['plugins-list'] logCtx = LogString(mibTreeReq) reqCtx = {} for pluginNum, pluginId in enumerate(pluginIdList): st, pdu = pluginManager.processCommandRequest( pluginId, snmpEngine, pdu, mibTreeReq, 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) # TODO: need to report some special error to drop request cbFun(varBinds, **context) return elif st == status.RESPOND: log.debug( 'received SNMP message, plugin %s forced immediate response' % pluginId, ctx=logCtx) # TODO: should we respond something other than request? cbFun(varBinds, **context) return # Apply PDU to MIB(s) mibTreeId = mibTreeReq['mib-tree-id'] if not mibTreeId: log.error('no matching MIB tree route for the request', ctx=logCtx) cbFun(varBinds, **dict(context, error=smi_error.GenError())) return mibInstrum = mibTreeIdMap.get(mibTreeId) if not mibInstrum: log.error('MIB tree ID %s does not exist' % mibTreeId, ctx=logCtx) cbFun(varBinds, **dict(context, error=smi_error.GenError())) return log.debug('received SNMP message, applied on mib-tree-id %s' % mibTreeId, ctx=logCtx) cbCtx = pluginIdList, mibTreeId, mibTreeReq, snmpEngine, reqCtx, context[ 'cbFun'] mgmtFun = getattr(mibInstrum, self.MIB_INTRUMENTATION_CALL) mgmtFun( *varBinds, **dict(context, cbFun=self._mibTreeCbFun, cbCtx=cbCtx, acFun=None)) # TODO: it just occurred to me that `*varBinds` would look more consistent def _mibTreeCbFun(self, varBinds, **context): pluginIdList, mibTreeId, mibTreeReq, snmpEngine, reqCtx, cbFun = context[ 'cbCtx'] logCtx = LogString(mibTreeReq) err = context.get('error') if err: log.info('MIB operation resulted in error: %s' % err, ctx=logCtx) cbFun(varBinds, **dict(context, cbFun=cbFun)) # plugins need to work at var-binds level # # for key in tuple(mibTreeRsp): # pdu = mibTreeRsp['client-snmp-pdu'] # # for pluginId in pluginIdList: # st, pdu = pluginManager.processCommandResponse( # pluginId, snmpEngine, pdu, mibTreeReq, 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('mibTree message #%s, SNMP response error: %s' % (msgId, sys.exc_info()[1]), # ctx=logCtx) # # else: # log.debug('received mibTree message #%s, forwarded as SNMP message' % msgId, ctx=logCtx) class GetCommandResponder(MibTreeProxyMixIn, cmdrsp.GetCommandResponder): MIB_INTRUMENTATION_CALL = 'readMibObjects' class GetNextCommandResponder(MibTreeProxyMixIn, cmdrsp.NextCommandResponder): MIB_INTRUMENTATION_CALL = 'readNextMibObjects' class GetBulkCommandResponder(MibTreeProxyMixIn, cmdrsp.BulkCommandResponder): MIB_INTRUMENTATION_CALL = 'readNextMibObjects' class SetCommandResponder(MibTreeProxyMixIn, cmdrsp.SetCommandResponder): MIB_INTRUMENTATION_CALL = 'writeMibObjects' 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'], ['mib-tree-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 usmRequestObserver(snmpEngine, execpoint, variables, cbCtx): mibTreeReq = {'snmp-security-engine-id': variables['securityEngineId']} cbCtx.clear() cbCtx.update(mibTreeReq) def requestObserver(snmpEngine, execpoint, variables, cbCtx): mibTreeReq = { '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'], } try: mibTreeReq['snmp-security-engine-id'] = cbCtx.pop( 'snmp-security-engine-id') except KeyError: # SNMPv1/v2c mibTreeReq['snmp-security-engine-id'] = mibTreeReq[ 'snmp-engine-id'] mibTreeReq['snmp-credentials-id'] = macro.expandMacro( credIdMap.get( (str(snmpEngine.snmpEngineID), variables['transportDomain'], variables['securityModel'], variables['securityLevel'], str(variables['securityName']))), mibTreeReq) k = '#'.join([ str(x) for x in (variables['contextEngineId'], variables['contextName']) ]) for x, y in contextIdList: if y.match(k): mibTreeReq['snmp-context-id'] = macro.expandMacro( x, mibTreeReq) break else: mibTreeReq['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): mibTreeReq['snmp-peer-id'] = macro.expandMacro( peerId, mibTreeReq) break else: mibTreeReq['snmp-peer-id'] = None pdu = variables['pdu'] k = '#'.join([ snmpPduTypesMap.get(variables['pdu'].tagSet, '?'), '|'.join([str(x[0]) for x in v2c.apiPDU.getVarBinds(pdu)]) ]) for x, y in contentIdList: if y.match(k): mibTreeReq['snmp-content-id'] = macro.expandMacro( x, mibTreeReq) break else: mibTreeReq['snmp-content-id'] = None mibTreeReq['plugins-list'] = pluginIdMap.get( (mibTreeReq['snmp-credentials-id'], mibTreeReq['snmp-context-id'], mibTreeReq['snmp-peer-id'], mibTreeReq['snmp-content-id']), []) mibTreeReq['mib-tree-id'] = routingMap.get( (mibTreeReq['snmp-credentials-id'], mibTreeReq['snmp-context-id'], mibTreeReq['snmp-peer-id'], mibTreeReq['snmp-content-id'])) mibTreeReq['snmp-pdu'] = pdu cbCtx.clear() cbCtx.update(mibTreeReq) # # 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 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 Command Responder. Runs one or more SNMP command responders (agents) and one or more trees of MIB objects representing SNMP-managed entities. The tool applies received messages onto one of the MIB trees chosen by tool's configuration. Documentation: http://snmplabs.com/snmpresponder/ %s """ % helpMessage) return if opt[0] == '-v' or opt[0] == '--version': import snmpresponder import pysnmp import pyasn1 sys.stderr.write("""\ SNMP Command Responder version %s, written by Ilya Etingof <*****@*****.**> Using foundation libraries: pysnmp %s, pyasn1 %s. Python interpreter: %s Software documentation and support at http://snmplabs.com/snmpresponder/ %s """ % (snmpresponder.__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(','), loggerName=PROGRAM_NAME + '.pysnmp')) elif opt[0] == '--debug-asn1': pyasn1_debug.setLogger( pyasn1_debug.Debug(*opt[1].split(','), 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, force=True) if loggingLevel: log.setLevel(loggingLevel) except SnmpResponderError: sys.stderr.write('%s\r\n%s\r\n' % (sys.exc_info()[1], helpMessage)) return try: cfgTree = cparser.Config().load(cfgFile) except SnmpResponderError: 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 = {} routingMap = {} mibTreeIdMap = {} engineIdMap = {} transportDispatcher = AsyncoreDispatcher() 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, 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 SnmpResponderError: 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) snmpEngine.observer.registerObserver(usmRequestObserver, 'rfc3414.processIncomingMsg', cbCtx=gCurrentRequestContext) GetCommandResponder(snmpEngine, snmpContext) GetNextCommandResponder(snmpEngine, snmpContext) GetBulkCommandResponder(snmpEngine, snmpContext) SetCommandResponder(snmpEngine, snmpContext) 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[:len(udp.DOMAIN_NAME)] != udp.DOMAIN_NAME and udp6 and transportDomain[:len(udp6.DOMAIN_NAME)] != udp6.DOMAIN_NAME): log.error('unknown transport domain %s' % (transportDomain, )) return if transportDomain in snmpEngineMap['transportDomain']: bindAddr, transportDomain = snmpEngineMap['transportDomain'][ transportDomain] log.info('using transport endpoint [%s]:%s, transport ID %s' % (bindAddr[0], bindAddr[1], transportDomain)) else: bindAddr = cfgTree.getAttrValue('snmp-bind-address', *configEntryPath) transportOptions = cfgTree.getAttrValue('snmp-transport-options', *configEntryPath, default=[], vector=True) try: bindAddr, bindAddrMacro = endpoint.parseTransportAddress( transportDomain, bindAddr, transportOptions) except SnmpResponderError: log.error('bad snmp-bind-address specification %s at %s' % (bindAddr, '.'.join(configEntryPath))) return if transportDomain[:len(udp.DOMAIN_NAME)] == udp.DOMAIN_NAME: transport = udp.UdpTransport() else: transport = udp6.Udp6Transport() t = transport.openServerMode(bindAddr) if 'transparent-proxy' in transportOptions: t.enablePktInfo() t.enableTransparent() elif 'virtual-interface' in transportOptions: t.enablePktInfo() snmpEngine.registerTransportDispatcher(transportDispatcher, transportDomain) config.addSocketTransport(snmpEngine, transportDomain, t) snmpEngineMap['transportDomain'][ transportDomain] = bindAddr, transportDomain log.info( 'new transport endpoint [%s]:%s, options %s, transport ID %s' % (bindAddr[0], bindAddr[1], 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 SnmpResponderError( '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) securityEngineId = cfgTree.getAttrValue( 'snmp-security-engine-id', *configEntryPath, 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', *configEntryPath, default=config.USM_AUTH_HMAC96_MD5) try: usmAuthProto = authProtocols[usmAuthProto.upper()] except KeyError: pass 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, default=config.USM_PRIV_CBC56_DES) try: usmPrivProto = privProtocols[usmPrivProto.upper()] except KeyError: pass usmPrivProto = rfc1902.ObjectName(usmPrivProto) usmPrivKey = cfgTree.getAttrValue('snmp-usm-priv-key', *configEntryPath, default=None) log.info( 'new USM encryption key: %s, encryption protocol: %s' % (usmPrivKey, usmPrivProto)) config.addV3User(snmpEngine, usmUser, usmAuthProto, usmAuthKey, usmPrivProto, usmPrivKey, securityEngineId=securityEngineId) else: config.addV3User(snmpEngine, usmUser, usmAuthProto, usmAuthKey, securityEngineId=securityEngineId) else: config.addV3User(snmpEngine, usmUser, securityEngineId=securityEngineId) snmpEngineMap['securityName'][securityName] = securityModel configKey.append(securityModel) configKey.append(securityLevel) configKey.append(securityName) else: raise SnmpResponderError('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, vector=True): for bindAddress in cfgTree.getAttrValue( 'snmp-bind-address-pattern-list', *peerCfgPath, 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, 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, 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, vector=True): for peerId in cfgTree.getAttrValue('matching-snmp-peer-id-list', *pluginCfgPath, vector=True): for contextId in cfgTree.getAttrValue( 'matching-snmp-context-id-list', *pluginCfgPath, vector=True): for contentId in cfgTree.getAttrValue( 'matching-snmp-content-id-list', *pluginCfgPath, 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-mib-tree-id'): mibTreeId = cfgTree.getAttrValue('using-mib-tree-id', *routeCfgPath) log.info('configuring destination MIB tree ID(s) %s (at %s)...' % (mibTreeId, '.'.join(routeCfgPath))) for credId in cfgTree.getAttrValue('matching-snmp-credentials-id-list', *routeCfgPath, vector=True): for peerId in cfgTree.getAttrValue('matching-snmp-peer-id-list', *routeCfgPath, vector=True): for contextId in cfgTree.getAttrValue( 'matching-snmp-context-id-list', *routeCfgPath, vector=True): for contentId in cfgTree.getAttrValue( 'matching-snmp-content-id-list', *routeCfgPath, vector=True): k = credId, contextId, peerId, contentId if k in routingMap: log.error( 'duplicate snmp-credentials-id %s, snmp-context-id %s, snmp-peer-id %s, snmp-content-id %s at mib-tree-id(s) %s' % (credId, contextId, peerId, contentId, ','.join(mibTreeIdList))) return else: routingMap[k] = mibTreeId log.info( 'configuring MIB tree routing to %s (at %s), composite key: %s' % (mibTreeId, '.'.join(routeCfgPath), '/'.join(k))) for mibTreeCfgPath in cfgTree.getPathsToAttr('mib-tree-id'): mibTreeId = cfgTree.getAttrValue('mib-tree-id', *mibTreeCfgPath) log.info('configuring MIB tree ID %s (at %s)...' % (mibTreeId, '.'.join(mibTreeCfgPath))) mibTextPaths = cfgTree.getAttrValue('mib-text-search-path-list', *mibTreeCfgPath, default=[], vector=True) mibCodePatternPaths = macro.expandMacros( cfgTree.getAttrValue('mib-code-modules-pattern-list', *mibTreeCfgPath, default=[], vector=True), {'config-dir': os.path.dirname(cfgFile)}) mibBuilder = builder.MibBuilder() compiler.addMibCompiler(mibBuilder, sources=mibTextPaths) for topDir in mibCodePatternPaths: filenameRegExp = re.compile(os.path.basename(topDir)) topDir = os.path.dirname(topDir) for root, dirs, files in os.walk(topDir): if not files or root.endswith('__pycache__'): continue mibBuilder.setMibSources(builder.DirMibSource(root), *mibBuilder.getMibSources()) for filename in files: if not filenameRegExp.match(filename): log.debug( 'skipping non-matching file %s while loading ' 'MIB tree ID %s' % (filename, mibTreeId)) continue module, _ = os.path.splitext(filename) try: mibBuilder.loadModule(module) except PySnmpError as ex: log.error('fail to load MIB implementation from file ' '%s into MIB tree ID %s' % (os.path.join(root, filename), mibTreeId)) raise SnmpResponderError(str(ex)) log.info('loaded MIB implementation file %s into MIB tree ' 'ID %s' % (os.path.join(root, filename), mibTreeId)) mibCodePackages = macro.expandMacros( cfgTree.getAttrValue('mib-code-packages-pattern-list', *mibTreeCfgPath, default=[], vector=True), {'config-dir': os.path.dirname(cfgFile)}) for mibCodePackage in mibCodePackages: mibCodePackageRegExp = re.compile(mibCodePackage) for entryPoint in pkg_resources.iter_entry_points( 'snmpresponder.mibs'): log.debug('found extension entry point %s' % entryPoint.name) mibPackage = entryPoint.load() root = os.path.dirname(mibPackage.__file__) mibPathSet = False for filename in os.listdir(root): if filename.startswith('__init__'): continue if not os.path.isfile(os.path.join(root, filename)): continue mibPath = '.'.join((entryPoint.name, filename)) if not mibCodePackageRegExp.match(mibPath): log.debug( 'extension MIB %s from %s is NOT configured, ' 'skipping' % (mibPath, entryPoint.name)) continue if not mibPathSet: mibBuilder.setMibSources(builder.DirMibSource(root), *mibBuilder.getMibSources()) mibPathSet = True log.debug('loading extension MIB %s from %s into MIB tree ' 'ID %s' % (mibPath, entryPoint.name, mibTreeId)) module, _ = os.path.splitext(filename) try: mibBuilder.loadModule(module) except PySnmpError as ex: log.error('fail to load MIB implementation %s from ' '%s into MIB tree ID %s' % (mibPath, entryPoint.name, mibTreeId)) raise SnmpResponderError(str(ex)) log.info( 'loaded MIB implementation %s from %s into MIB tree ' 'ID %s' % (mibPath, entryPoint.name, mibTreeId)) mibTreeIdMap[mibTreeId] = instrum.MibInstrumController(mibBuilder) log.info('loaded new MIB tree ID %s' % mibTreeId) 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 with daemon.PrivilegesOf(procUser, procGroup, final=True): while True: try: transportDispatcher.runDispatcher() except (PySnmpError, SnmpResponderError, socket.error): log.error(str(sys.exc_info()[1])) continue except Exception: transportDispatcher.closeDispatcher() raise
log.setLogger(PROGRAM_NAME, *loggingMethod, force=True) if loggingLevel: log.setLevel(loggingLevel) except error.SnmpsimError: sys.stderr.write('%s\r\n%s\r\n' % (sys.exc_info()[1], helpMessage)) sys.exit(1) if isinstance(startOID, rfc1902.ObjectIdentity) or \ isinstance(stopOID, rfc1902.ObjectIdentity): mibBuilder = builder.MibBuilder() mibViewController = view.MibViewController(mibBuilder) compiler.addMibCompiler(mibBuilder, sources=mibSources or defaultMibSources) if isinstance(startOID, rfc1902.ObjectIdentity): startOID.resolveWithMib(mibViewController) if isinstance(stopOID, rfc1902.ObjectIdentity): stopOID.resolveWithMib(mibViewController) # Load variation module if variationModuleName: for variationModulesDir in confdir.variation: log.info('Scanning "%s" directory for variation modules...' % variationModulesDir) if not os.path.exists(variationModulesDir): log.info('Directory "%s" does not exist' % variationModulesDir) continue
def main(): variation_module = None endpoints = {} contexts = {} stats = { 'UDP packets': 0, 'IP packets': 0, 'bad packets': 0, 'empty packets': 0, 'unknown L2 protocol': 0, 'SNMP errors': 0, 'SNMP exceptions': 0, 'agents seen': 0, 'contexts seen': 0, 'snapshots taken': 0, 'Response PDUs seen': 0, 'OIDs seen': 0 } parser = argparse.ArgumentParser(description=DESCRIPTION) parser.add_argument('-v', '--version', action='version', version=utils.TITLE) parser.add_argument('--quiet', action='store_true', help='Do not print out informational messages') parser.add_argument( '--debug', choices=pysnmp_debug.flagMap, action='append', type=str, default=[], help='Enable one or more categories of SNMP debugging.') parser.add_argument( '--debug-asn1', choices=pyasn1_debug.FLAG_MAP, action='append', type=str, default=[], help='Enable one or more categories of ASN.1 debugging.') parser.add_argument('--logging-method', type=lambda x: x.split(':'), metavar='=<%s[:args]>]' % '|'.join(log.METHODS_MAP), default='stderr', help='Logging method.') parser.add_argument('--log-level', choices=log.LEVELS_MAP, type=str, default='info', help='Logging level.') parser.add_argument( '--start-object', metavar='<MIB::Object|OID>', type=_parse_mib_object, default=univ.ObjectIdentifier('1.3.6'), help='Drop all simulation data records prior to this OID specified ' 'as MIB object (MIB::Object) or OID (1.3.6.)') parser.add_argument( '--stop-object', metavar='<MIB::Object|OID>', type=functools.partial(_parse_mib_object, last=True), help='Drop all simulation data records after this OID specified ' 'as MIB object (MIB::Object) or OID (1.3.6.)') parser.add_argument( '--mib-source', dest='mib_sources', metavar='<URI|PATH>', action='append', type=str, default=['http://mibs.snmplabs.com/asn1/@mib@'], help='One or more URIs pointing to a collection of ASN.1 MIB files.' 'Optional "@mib@" token gets replaced with desired MIB module ' 'name during MIB search.') parser.add_argument( '--destination-record-type', choices=RECORD_TYPES, default='snmprec', help='Produce simulation data with record of this type') parser.add_argument('--output-file', metavar='<FILE>', type=str, help='SNMP simulation data file to write records to') variation_group = parser.add_argument_group( 'Simulation data variation options') variation_group.add_argument('--variation-modules-dir', action='append', type=str, help='Search variation module by this path') variation_group.add_argument( '--variation-module', type=str, help='Pass gathered simulation data through this variation module') variation_group.add_argument('--variation-module-options', type=str, default='', help='Variation module options') parser.add_argument( '--output-dir', metavar='<FILE>', type=str, default='.', help='SNMP simulation data directory to place captured traffic in ' 'form of simulation records. File names reflect traffic sources ' 'on the network.') variation_group.add_argument( '--transport-id-offset', type=int, default=0, help='When arranging simulation data files, start enumerating ' 'receiving transport endpoints from this number.') traffic_group = parser.add_argument_group('Traffic capturing options') traffic_group.add_argument( '--packet-filter', type=str, default='udp and src port 161', help='Traffic filter (in tcpdump syntax) to use for picking SNMP ' 'packets out of the rest of the traffic.') variation_group.add_argument('--listen-interface', type=str, help='Listen on this network interface.') parser.add_argument( '--promiscuous-mode', action='store_true', help='Attempt to switch NIC to promiscuous mode. Depending on the ' 'network, this may make traffic of surrounding machines visible. ' 'Might require superuser privileges.') parser.add_argument( '--capture-file', metavar='<FILE>', type=str, help='PCAP file with SNMP simulation data file to read from ' 'instead of listening on a NIC.') args = parser.parse_args() if not pcap: sys.stderr.write( 'ERROR: pylibpcap package is missing!\r\nGet it by running ' '`pip install ' 'https://downloads.sourceforge.net/project/pylibpcap/pylibpcap' '/0.6.4/pylibpcap-0.6.4.tar.gz`' '\r\n') parser.print_usage(sys.stderr) return 1 proc_name = os.path.basename(sys.argv[0]) try: log.set_logger(proc_name, *args.logging_method, force=True) if args.log_level: log.set_level(args.log_level) except error.SnmpsimError as exc: sys.stderr.write('%s\r\n%s\r\n' % exc) parser.print_usage(sys.stderr) sys.exit(1) if (isinstance(args.start_object, rfc1902.ObjectIdentity) or isinstance(args.stop_object, rfc1902.ObjectIdentity)): mib_builder = builder.MibBuilder() mib_view_controller = view.MibViewController(mib_builder) compiler.addMibCompiler(mib_builder, sources=args.mib_sources) try: if isinstance(args.start_object, rfc1902.ObjectIdentity): args.start_object.resolveWithMib(mib_view_controller) if isinstance(args.stop_object, rfc1902.ObjectIdentity): args.stop_object.resolveWithMib(mib_view_controller) except PySnmpError as exc: sys.stderr.write('ERROR: %s\r\n' % exc) return 1 # Load variation module if args.variation_module: for variation_modules_dir in (args.variation_modules_dir or confdir.variation): log.info('Scanning "%s" directory for variation ' 'modules...' % variation_modules_dir) if not os.path.exists(variation_modules_dir): log.info('Directory "%s" does not exist' % variation_modules_dir) continue mod = os.path.join(variation_modules_dir, args.variation_module + '.py') if not os.path.exists(mod): log.info('Variation module "%s" not found' % mod) continue ctx = {'path': mod, 'moduleContext': {}} try: with open(mod) as fl: exec(compile(fl.read(), mod, 'exec'), ctx) except Exception as exc: log.error('Variation module "%s" execution ' 'failure: %s' % (mod, exc)) return 1 variation_module = ctx log.info('Variation module "%s" loaded' % args.variation_module) break else: log.error('variation module "%s" not found' % args.variation_module) return 1 # Variation module initialization if variation_module: log.info('Initializing variation module...') for handler in ('init', 'record', 'shutdown'): if handler not in variation_module: log.error('missing "%s" handler at variation module ' '"%s"' % (handler, args.variation_module)) return 1 handler = variation_module['init'] try: handler(options=args.variation_module_options, mode='recording', startOID=args.start_object, stopOID=args.stop_object) except Exception as exc: log.error('Variation module "%s" initialization ' 'FAILED: %s' % (args.variation_module, exc)) else: log.info('Variation module "%s" ' 'initialization OK' % args.variation_module) pcap_obj = pcap.pcapObject() if args.listen_interface: if not args.quiet: log.info('Listening on interface %s in %spromiscuous ' 'mode' % (args.listen_interface, '' if args.promiscuous_mode else 'non-')) try: pcap_obj.open_live(args.listen_interface, 65536, args.promiscuous_mode, 1000) except Exception as exc: log.error('Error opening interface %s for snooping: ' '%s' % (args.listen_interface, exc)) return 1 elif args.capture_file: if not args.quiet: log.info('Opening capture file %s' % args.capture_file) try: pcap_obj.open_offline(args.capture_file) except Exception as exc: log.error('Error opening capture file %s for reading: ' '%s' % (args.capture_file, exc)) return 1 else: sys.stderr.write( 'ERROR: no capture file or live interface specified\r\n') parser.print_usage(sys.stderr) return 1 if args.packet_filter: if not args.quiet: log.info('Applying packet filter \"%s\"' % args.packet_filter) pcap_obj.setfilter(args.packet_filter, 0, 0) if not args.quiet: log.info('Processing records from %still ' '%s' % ('the beginning ' if args.start_object else args.start_object, args.stop_object if args.stop_object else 'the end')) def parse_packet(raw): pkt = {} # http://www.tcpdump.org/linktypes.html ll_headers = {0: 4, 1: 14, 108: 4, 228: 0} if pcap_obj.datalink() in ll_headers: raw = raw[ll_headers[pcap_obj.datalink()]:] else: stats['unknown L2 protocol'] += 1 pkt['version'] = (ord(raw[0]) & 0xf0) >> 4 pkt['header_len'] = ord(raw[0]) & 0x0f pkt['tos'] = ord(raw[1]) pkt['total_len'] = socket.ntohs(struct.unpack('H', raw[2:4])[0]) pkt['id'] = socket.ntohs(struct.unpack('H', raw[4:6])[0]) pkt['flags'] = (ord(raw[6]) & 0xe0) >> 5 pkt['fragment_offset'] = socket.ntohs( struct.unpack('H', raw[6:8])[0] & 0x1f) pkt['ttl'] = ord(raw[8]) pkt['protocol'] = ord(raw[9]) pkt['checksum'] = socket.ntohs(struct.unpack('H', raw[10:12])[0]) pkt['source_address'] = pcap.ntoa(struct.unpack('i', raw[12:16])[0]) pkt['destination_address'] = pcap.ntoa( struct.unpack('i', raw[16:20])[0]) if pkt['header_len'] > 5: pkt['options'] = raw[20:4 * (pkt['header_len'] - 5)] else: pkt['options'] = None raw = raw[4 * pkt['header_len']:] if pkt['protocol'] == 17: pkt['source_port'] = socket.ntohs(struct.unpack('H', raw[0:2])[0]) pkt['destination_port'] = socket.ntohs( struct.unpack('H', raw[2:4])[0]) raw = raw[8:] stats['UDP packets'] += 1 pkt['data'] = raw stats['IP packets'] += 1 return pkt def handle_snmp_message(d, t, private={}): msg_ver = api.decodeMessageVersion(d['data']) if msg_ver in api.protoModules: p_mod = api.protoModules[msg_ver] else: stats['bad packets'] += 1 return try: rsp_msg, whole_msg = decoder.decode(d['data'], asn1Spec=p_mod.Message()) except PyAsn1Error: stats['bad packets'] += 1 return if rsp_msg['data'].getName() == 'response': rsp_pdu = p_mod.apiMessage.getPDU(rsp_msg) error_status = p_mod.apiPDU.getErrorStatus(rsp_pdu) if error_status: stats['SNMP errors'] += 1 else: endpoint = d['source_address'], d['source_port'] if endpoint not in endpoints: endpoints[endpoint] = udp.domainName + ( args.transport_id_offset + len(endpoints), ) stats['agents seen'] += 1 context = '%s/%s' % (p_mod.ObjectIdentifier( endpoints[endpoint]), p_mod.apiMessage.getCommunity(rsp_msg)) if context not in contexts: contexts[context] = {} stats['contexts seen'] += 1 context = '%s/%s' % (p_mod.ObjectIdentifier( endpoints[endpoint]), p_mod.apiMessage.getCommunity(rsp_msg)) stats['Response PDUs seen'] += 1 if 'basetime' not in private: private['basetime'] = t for oid, value in p_mod.apiPDU.getVarBinds(rsp_pdu): if oid < args.start_object: continue if args.stop_object and oid >= args.stop_object: continue if oid in contexts[context]: if value != contexts[context][oid]: stats['snapshots taken'] += 1 else: contexts[context][oid] = [], [] contexts[context][oid][0].append(t - private['basetime']) contexts[context][oid][1].append(value) stats['OIDs seen'] += 1 def handle_packet(pktlen, data, timestamp): if not data: stats['empty packets'] += 1 return handle_snmp_message(parse_packet(data), timestamp) try: if args.listen_interface: log.info('Listening on interface "%s", kill me when you ' 'are done.' % args.listen_interface) while True: pcap_obj.dispatch(1, handle_packet) elif args.capture_file: log.info('Processing capture file "%s"....' % args.capture_file) args = pcap_obj.next() while args: handle_packet(*args) args = pcap_obj.next() except (TypeError, KeyboardInterrupt): log.info('Shutting down process...') finally: data_file_handler = SnmprecRecord() for context in contexts: ext = os.path.extsep ext += RECORD_TYPES[args.destination_record_type].ext filename = os.path.join(args.output_dir, context + ext) if not args.quiet: log.info('Creating simulation context %s at ' '%s' % (context, filename)) try: os.mkdir(os.path.dirname(filename)) except OSError: pass record = RECORD_TYPES[args.destination_record_type] try: output_file = record.open(filename, 'wb') except IOError as exc: log.error('writing %s: %s' % (filename, exc)) return 1 count = total = iteration = 0 time_offset = 0 req_time = time.time() oids = sorted(contexts[context]) oids.append(oids[-1]) # duplicate last OID to trigger stopFlag while True: for oid in oids: timeline, values = contexts[context][oid] value = values[min( len(values) - 1, bisect.bisect_left(timeline, time_offset))] if value.tagSet in (rfc1905.NoSuchObject.tagSet, rfc1905.NoSuchInstance.tagSet, rfc1905.EndOfMibView.tagSet): stats['SNMP exceptions'] += 1 continue # remove value enumeration if value.tagSet == Integer32.tagSet: value = Integer32(value) if value.tagSet == Unsigned32.tagSet: value = Unsigned32(value) if value.tagSet == Bits.tagSet: value = OctetString(value) # Build .snmprec record ctx = { 'origOid': oid, 'origValue': value, 'count': count, 'total': total, 'iteration': iteration, 'reqTime': req_time, 'startOID': args.start_object, 'stopOID': args.stop_object, 'stopFlag': oids.index(oid) == len(oids) - 1, 'variationModule': variation_module } try: line = data_file_handler.format(oid, value, **ctx) except error.MoreDataNotification as exc: count = 0 iteration += 1 moreDataNotification = exc if 'period' in moreDataNotification: time_offset += moreDataNotification['period'] log.info( '%s OIDs dumped, advancing time window to ' '%.2f sec(s)...' % (total, time_offset)) break except error.NoDataNotification: pass except error.SnmpsimError as exc: log.error(exc) continue else: output_file.write(line) count += 1 total += 1 else: break output_file.flush() output_file.close() if variation_module: log.info('Shutting down variation module ' '"%s"...' % args.variation_module) handler = variation_module['shutdown'] try: handler(options=args.variation_module_options, mode='recording') except Exception as exc: log.error('Variation module "%s" shutdown FAILED: ' '%s' % (args.variation_module, exc)) else: log.info('Variation module "%s" shutdown' ' OK' % args.variation_module) log.info("""\ PCap statistics: packets snooped: %s packets dropped: %s packets dropped: by interface %s\ """ % pcap_obj.stats()) log.info("""\ SNMP statistics: %s\ """ % ' '.join(['%s: %s\r\n' % kv for kv in stats.items()])) return 0