def declared_hostinfo(monkeypatch, request): data = [[ ObjectName('.1.3.6.1.2.1.1.2.0'), ObjectIdentifier(request.param['sysobjectid']) ], [ ObjectName('.1.3.6.1.2.1.1.1.0'), OctetString(request.param['description']) ]] get_oids = request.param.get('get_oids') if get_oids: for entry in get_oids: data.append([ ObjectName(get_oids[entry]['oid']), OctetString(get_oids[entry]['value']) ]) if 'walk_oids' in request.param.keys(): get_next_return = [] for extra_oid in request.param['walk_oids']: get_next_return.append([ ObjectName('.' + request.param['walk_oids'][extra_oid]['oid']), OctetString(request.param['walk_oids'][extra_oid]['value']) ]) walk_data = [get_next_return] else: walk_data = None return GetCmd(monkeypatch, return_value=data, walk_data=walk_data, params=request.param)
def declared_hostinfo(monkeypatch): data = [ [ObjectName('.1.3.6.1.2.1.1.1.0'), OctetString('Cisco Adaptive Security Appliance Version 9.3(2)2')], [ObjectName('.1.3.6.1.2.1.1.2.0'), ObjectIdentifier('1.3.6.1.4.1.9.1.2114')], [ObjectName('.1.3.6.1.2.1.1.3.0'), OctetString('replace with uptime')], [ObjectName('.1.3.6.1.2.1.1.4.0'), OctetString('Networklore')], [ObjectName('.1.3.6.1.2.1.1.6.0'), OctetString('Westeros')], ] return GetCmd(monkeypatch, return_value=data)
def return_snmp_data(value,value_type): if value_type is None: if isinstance(value, int): data = Integer(value) elif isinstance(value, float): data = Integer(value) elif isinstance(value, str): if is_ipv4_address(value): data = IpAddress(value) else: data = OctetString(value) else: raise TypeError( "Unable to autodetect type. Please pass one of " "these strings as the value_type keyword arg: " ", ".join(TYPES.keys()) ) else: if not value_type in TYPES: raise ValueError("'{}' is not one of the supported types: {}".format( value_type, ", ".join(TYPES.keys()) )) data = TYPES[value_type](value) return data
def _get_var_binds(self, alert_values): var_binds = [(self.oids[field], OctetString(alert_values.get(field, NA))) for field in self.var_fields] return var_binds
def _get_snmpdata(self, *snmp_data): if self.return_value: return self.return_value else: for snmp in snmp_data: dat = snmp snmpdata = [[ObjectName('1.1'), OctetString(dat)]] return snmpdata
def set(self, oid, value, value_type=None): """ Sets a single OID value. If you do not pass value_type hnmp will try to guess the correct type. Autodetection is supported for: * int and float (as Integer, fractional part will be discarded) * IPv4 address (as IpAddress) * str (as OctetString) Unfortunately, pysnmp does not support the SNMP FLOAT type so please use Integer instead. """ snmpsecurity = self._get_snmp_security() if value_type is None: if isinstance(value, int): data = Integer(value) elif isinstance(value, float): data = Integer(value) elif isinstance(value, str): if is_ipv4_address(value): data = IpAddress(value) else: data = OctetString(value) else: raise TypeError( "Unable to autodetect type. Please pass one of " "these strings as the value_type keyword arg: " ", ".join(TYPES.keys()) ) else: if value_type not in TYPES: raise ValueError("'{}' is not one of the supported types: {}".format( value_type, ", ".join(TYPES.keys()) )) data = TYPES[value_type](value) try: engine_error, pdu_error, pdu_error_index, objects = self._cmdgen.setCmd( snmpsecurity, cmdgen.UdpTransportTarget((self.host, self.port), timeout=self.timeout, retries=self.retries), (oid, data), ) if engine_error: raise SNMPError(engine_error) if pdu_error: raise SNMPError(pdu_error.prettyPrint()) except Exception as e: raise SNMPError(e) _, value = objects[0] value = _convert_value_to_native(value) return value
def test_var_binds(self): oid_with_alarm_objects = \ common.GENERAL_OID + '.' + \ common.COMPANY_OID + '.' + common.ALARM_OBJECTS_OID var_binds = self.snmp_sender._get_var_binds(common.alarm_data) self.assertEqual(len(var_binds), 3) self.assertIn( (oid_with_alarm_objects + '.' + common.NAME_OID, OctetString(common.alarm_data.get(VProps.NAME, sender.NA))), var_binds) self.assertIn( (oid_with_alarm_objects + '.' + common.IS_DELETED_OID, OctetString(common.alarm_data.get(VProps.IS_DELETED, sender.NA))), var_binds) self.assertIn((oid_with_alarm_objects + '.' + common.SEVERITY_OID, OctetString( common.alarm_data.get(VProps.OPERATIONAL_SEVERITY, sender.NA))), var_binds)
def test_var_binds(self): oid_with_alarm_objects = \ common.GENERAL_OID + '.' + \ common.COMPANY_OID + '.' + common.ALARM_OBJECTS_OID var_binds = self.snmp_sender._get_var_binds(common.alarm_data) self.assertThat(var_binds, matchers.HasLength(3)) self.assertIn((oid_with_alarm_objects + '.' + common.NAME_OID, OctetString(common.alarm_data.get(VProps.NAME, sender.NA))), var_binds) self.assertIn((oid_with_alarm_objects + '.' + common.IS_DELETED_OID, OctetString(common.alarm_data.get (VProps.VITRAGE_IS_DELETED, sender.NA))), var_binds) self.assertIn((oid_with_alarm_objects + '.' + common.SEVERITY_OID, OctetString(common.alarm_data.get (VProps.VITRAGE_OPERATIONAL_SEVERITY, sender.NA))), var_binds)
def getSnmpEngine(engineId=None): """Create SNMP engine instance. Args: engineId (str): SNMP engine ID as a ASCII or hex string Returns: object: SNMP engine object """ if engineId: engineId = engineId.replace(':', '') if engineId.startswith('0x') or engineId.startswith('0X'): engineId = engineId[2:] engineId = OctetString(hexValue=engineId) return SnmpEngine(snmpEngineID=engineId)
def sendTrap(self, trap): trap_oid = trap['trap_oid'] txAddress = self.args['--ipv6-host'] txPort = self.args['--port'] userData = UsmUserData('user-sha-aes128', 'authkey1', 'privkey1', authProtocol=usmHMACSHAAuthProtocol, privProtocol=usmAesCfb128Protocol) log.info("Sending SNMP Trap", address=txAddress, port=txPort) log.info(" Notification", name=self.smd.getNameByNumOid(trap_oid), oid=trap_oid) for var_bind in trap['var_binds']: var_oid = var_bind[0] var_val = var_bind[1] log.info(" with Object", name=self.smd.getNameByNumOid(var_oid), oid=var_oid, type=type(var_val)) trapOid = trap['trap_oid'] txVarBinds = trap['var_binds'] errorIndicationTx, errorStatusTx, errorIndexTx, varBindsTx = next( sendNotification( SnmpEngine(OctetString(hexValue='8000000001020304')), userData, Udp6TransportTarget((txAddress, txPort)), ContextData(), 'trap', NotificationType( ObjectIdentity(trapOid)).addVarBinds(*txVarBinds))) if errorIndicationTx: print(errorIndicationTx) else: for varBindTx in varBindsTx: print(' = '.join([x.prettyPrint() for x in varBindTx]))
def test_extract_classmaps(): table = [[(ObjectName('1.3.6.1.4.1.9.9.166.1.7.1.1.1.748129779'), OctetString('cs6'))], [(ObjectName('1.3.6.1.4.1.9.9.166.1.7.1.1.1.1201419584'), OctetString('af4'))], [(ObjectName('1.3.6.1.4.1.9.9.166.1.7.1.1.1.1201419589'), OctetString('af1'))], [(ObjectName('1.3.6.1.4.1.9.9.166.1.7.1.1.1.1201419590'), OctetString('af2'))], [(ObjectName('1.3.6.1.4.1.9.9.166.1.7.1.1.1.1819748200'), OctetString('ef'))], [(ObjectName('1.3.6.1.4.1.9.9.166.1.7.1.1.1.1965376995'), OctetString('class-default'))]] class_maps = qos.extract_classmaps(table) expected = { '748129779': 'cs6', '1201419589': 'af1', '1201419584': 'af4', '1201419590': 'af2', '1965376995': 'class-default', '1819748200': 'ef' } assert_that(class_maps, has_entries(expected))
####################################### # Logging import structlog log = structlog.get_logger() ##################################################################### # Configuration DEFAULT_TYPE_TO_VALUE_MAP = { 'DateAndTime': '2019-1-28,12:00:01.0,-4:0', 'DisplayString': 'dummy_display_string', 'InetAddress': '1.1.1.1', 'InetAddressType': 'ipv4', 'Ipv6Address': OctetString('aaaaaaaaaaaaaaaa'), 'pysnmp.proto.rfc1902.Counter32': 10, 'pysnmp.proto.rfc1902.Gauge32': 20, 'pysnmp.proto.rfc1902.Integer32': 30, 'pysnmp.proto.rfc1902.IpAddress': '1.1.1.1', 'pysnmp.proto.rfc1902.OctetString': OctetString('abcdef'), 'pysnmp.proto.rfc1902.Unsigned32': 40, 'StarENBID': 1, 'StarentCardType': 2, 'StarLongDurTimeoutAction': 3, 'StarOSPFNeighborState': 4, 'StarShortName': 'dummy_shortname', 'TruthValue': 'true', 'InterfaceIndex': 35, # SYNTAX: Integer32 (1..2147483647), Ref - https://github.com/cisco-kusanagi/mibs.snmplabs.com/blob/master/asn1/IF-MIB#L76 }
from pysnmp.proto.rfc1902 import Integer from pysnmp.proto.rfc1902 import ObjectIdentifier from pysnmp.proto.rfc1902 import ObjectName from pysnmp.proto.rfc1902 import OctetString from pysnmp.proto.rfc1902 import TimeTicks from vitrage.snmp_parsing.service import SnmpParsingService from vitrage.tests import base BINDS_REPORTED = [ (ObjectName('1.3.6.1.2.1.1.3.0'), TimeTicks(1491462248)), (ObjectName('1.3.6.1.6.3.1.1.4.1.0'), ObjectIdentifier('1.3.6.1.4.1.3902.4101.1.4.1.2')), (ObjectName('1.3.6.1.4.1.3902.4101.1.3.1.3'), OctetString(hexValue='07e10406070408002b0800')), (ObjectName('1.3.6.1.4.1.3902.4101.1.1.2'), Integer(0)), (ObjectName('1.3.6.1.4.1.3902.4101.1.1.4'), Integer(0)), (ObjectName('1.3.6.1.4.1.3902.4101.1.1.3'), OctetString('')), (ObjectName('1.3.6.1.4.1.3902.4101.1.3.1.11'), OctetString('3305115653')), (ObjectName('1.3.6.1.4.1.3902.4101.1.3.1.2'), OctetString('host')), (ObjectName('1.3.6.1.4.1.3902.4101.1.3.1.4'), Integer(1)), (ObjectName('1.3.6.1.4.1.3902.4101.1.3.1.5'), Integer(14)), (ObjectName('1.3.6.1.4.1.3902.4101.1.3.1.6'), Integer(0)), (ObjectName('1.3.6.1.4.1.3902.4101.1.3.1.7'), OctetString('')), (ObjectName('1.3.6.1.4.1.3902.4101.1.3.1.8'), OctetString('vimid=,hid=controller_controller,' 'hostname=controller,' 'Reason: nova-compute is not available')), (ObjectName('1.3.6.1.4.1.3902.4101.1.3.1.12'), OctetString('Tecs Director')),
def load_section(self): obj = {'_name': '', '_children': []} state = 'FSM_START' while 1: # Initial state if state == 'FSM_START': try: token, symbol = self.scanner.get_token() except error.EofError: state = 'FSM_STOP' continue self.scanner.unget_token() # See if it's object closure sign if symbol == SYMBOL_SECTION_END: state = 'FSM_SECTION_END' # See if it's symbol sign elif symbol == SYMBOL_OPTION: state = 'FSM_OPTION_NAME' # Default is to start from parsing up new section else: state = 'FSM_SECTION_NAME' # If object name expected elif state == 'FSM_SECTION_NAME': self.scanner.get_token() self.scanner.unget_token() # Move to next FSM state state = 'FSM_SECTION_BEGIN' # If object body delimiter expected elif state == 'FSM_SECTION_BEGIN': self.scanner.get_token() # Get section begin token, symbol = self.scanner.get_token() # Now unget these tokens to be used at the # next FSM state self.scanner.unget_token() self.scanner.unget_token() # Make sure it's object's body start sign if symbol != SYMBOL_SECTION_BEGIN: raise error.SnmpfwdError( '%s missing object beginning sign: %s' % (self, token)) state = 'FSM_CHILD_BEGIN' # If inclusive object expected elif state == 'FSM_CHILD_BEGIN': name, symbol = self.scanner.get_token() self.scanner.get_token() child_object = self.load_section() child_object['_name'] = name # Attach child object to the list of enclosed objects obj['_children'].append(child_object) state = 'FSM_CHILD_END' # If object body closure delimiter expected elif state == 'FSM_CHILD_END': # Get next token token, symbol = self.scanner.get_token() # Make sure it's object's body end sign if symbol != SYMBOL_SECTION_END: raise error.SnmpfwdError( '%s missing object closure sign: %s' % (self, token)) # Move to the beginning of FSM state = 'FSM_START' # If object body closure delimiter expected elif state == 'FSM_SECTION_END': # Get next token token, symbol = self.scanner.get_token() # Now unget token to be used at upper level FSM instance self.scanner.unget_token() # Make sure it's object's body end sign if symbol != SYMBOL_SECTION_END: raise error.SnmpfwdError( '%s missing object closure sign: %s' % (self, token)) # Move to next FSM state state = 'FSM_STOP' # If attribute name expected elif state == 'FSM_OPTION_NAME': # Get next token token, symbol = self.scanner.get_token() # See if this attribute does not yet exist if token in obj: raise error.SnmpfwdError( '%s multiple option occurrence: %s' % (self, token)) # Accept token as attribute name obj[token] = [] # Now unget token to be used at the next FSM state self.scanner.unget_token() # Move to next FSM state state = 'FSM_OPTION_VALUE' # If option value expected elif state == 'FSM_OPTION_VALUE': option, symbol = self.scanner.get_token() # Read up one or more option values while 1: try: token, symbol = self.scanner.get_token() except error.EofError: state = 'FSM_STOP' break # If it's not a plain word if symbol != SYMBOL_WORD: self.scanner.unget_token() # See if it's object begin symbol if symbol == SYMBOL_SECTION_BEGIN: # Unget section begin sign self.scanner.unget_token() # Remove previously added last value of # the list as it turned to be section name del obj[option][-1] # Move to the beginning of FSM state = 'FSM_START' break # Accept token as attribute value if token.lower()[:2] == '0x': token = str(OctetString(hexValue=token[2:])) obj[option].append(token) # If FSM is gonna stop elif state == 'FSM_STOP': # Return object loaded return obj # If this FSM state is not known else: raise error.SnmpfwdError('%s unknown FSM state: %s' % (self, state))
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
def sendTrap(self, logRecord): """Send BDS log message as SNMP notification. Args: logRecord (dict): log record data as a Python `dict` """ self.moduleLogger.info(f'sendTrap payload: {logRecord}') self._trapCounter += 1 if self._trapCounter == 0xffffffff: self._trapCounter = 0 try: syslogMsgFacility = logRecord['host'] except KeyError: self.moduleLogger.error( f'cannot get syslog facility from {logRecord}') syslogMsgFacility = 'error' try: syslogMsgSeverity = logRecord['level'] except KeyError: self.moduleLogger.error( f'cannot get syslog severity from {logRecord}') syslogMsgSeverity = 0 try: syslogMsgText = logRecord['short_message'] except KeyError: self.moduleLogger.error( f'cannot get syslog message text from bdsLogDict ' f'{logRecord}') syslogMsgText = 'error' self.moduleLogger.info( f'data sendTrap {self._trapCounter} {syslogMsgFacility} ' f'{syslogMsgSeverity} {syslogMsgText}') def cbFun(snmpEngine, sendRequestHandle, errorIndication, errorStatus, errorIndex, varBinds, cbCtx): if errorIndication: self.moduleLogger.error( f'notification {sendRequestHandle} failed: ' f'{errorIndication}') else: self.moduleLogger.error( f'notification {sendRequestHandle} succeeded') uptime = int((time.time() - self._birthday) * 100) varBinds = [ (self._sysUpTime, TimeTicks(uptime)), (self._snmpTrapOID, self._rtbrickSyslogTrap), (self._syslogMsgNumber, Unsigned32(self._trapCounter)), (self._syslogMsgFacility, OctetString(syslogMsgFacility)), (self._syslogMsgSeverity, Integer32(syslogMsgSeverity)), (self._syslogMsgText, OctetString(syslogMsgText)) ] sendRequestHandle = self._ntfOrg.sendVarBinds( self._snmpEngine, # Notification targets self._targets, None, '', # contextEngineId, contextName varBinds, cbFun ) self.moduleLogger.info( f'notification {sendRequestHandle or ""} submitted')
def setUp(self): self.oids = {ObjectName('1.2.3.4'): OctetString('eth0')}
def set_interface_untagged_vlan(self, interface, new_vlan_id): """ As an example, Override the VLAN change, this is done Comware specific using the Comware VLAN MIB Return -1 if invalid interface, or value of _set() call """ dprint(f"Comware set_interface_untagged_vlan() port {interface.name} to {new_vlan_id}") new_vlan = self.get_vlan_by_id(new_vlan_id) if interface and new_vlan: if interface.is_tagged: dprint("Tagged/Trunk Mode!") # set the TRUNK_NATIVE_VLAN OID: low_vlan_list = PortList() low_vlan_list.from_byte_count(BYTES_FOR_2048_VLANS) high_vlan_list = PortList() high_vlan_list.from_byte_count(BYTES_FOR_2048_VLANS) # add the new vlan id: if new_vlan_id > 2048: # set the propper bit, adjust by the offset! high_vlan_list[new_vlan_id - 2048] = 1 else: low_vlan_list[new_vlan_id] = 1 # now loop through all vlans in this port and set the bit for the vlan: for vlan in interface.vlans: if vlan > 2048: # set the propper bit, adjust by the offset! high_vlan_list[vlan - 2048] = 1 else: low_vlan_list[vlan] = 1 # now setup the OIDs to send as an atomic set: # first set Low-VLANs (1-2048) on this port: # Comware needs bits in opposite order inside each byte! (go figure) # note that to_hex_string() is same as .__str__ representation, # but we use it for extra clarity! low_vlan_list.reverse_bits_in_bytes() low_oid = (f"{hh3cifVLANTrunkAllowListLow}.{interface.port_id}", OctetString(hexValue=low_vlan_list.to_hex_string())) # next High-VLANs (2049-4096) on this port: # Comware needs bits in opposite order inside each byte! (go figure) high_vlan_list.reverse_bits_in_bytes() high_oid = (f"{hh3cifVLANTrunkAllowListHigh}.{interface.port_id}", OctetString(hexValue=high_vlan_list.to_hex_string())) # finally, set untagged vlan: dot1qPvid pvid_oid = (f"{dot1qPvid}.{interface.port_id}", Gauge32(new_vlan_id)) # now send them all as an atomic set(): # get the PySNMP helper to do the work with the OctetString() BitMaps: pysnmp = pysnmpHelper(self.switch) (error_status, details) = pysnmp.set_multiple([low_oid, high_oid, pvid_oid]) if error_status: self.error.status = True self.error.description = "Error in setting vlan on tagged port!" self.error.details = details return -1 else: # regular access mode untagged port: dprint("Acces Mode!") # create a PortList() to represent the ports/bits that are in the new vlan. # we need byte size from number of ethernet ports: max_port_id = self._get_max_qbridge_port_id() bytecount = math.ceil(max_port_id / 8) dprint(f"max_port_id = {max_port_id}, bytecount = {bytecount}") new_vlan_portlist = PortList() # initialize with "00" bytes new_vlan_portlist.from_byte_count(bytecount) # now set bit to 1 for this interface (i.e. set the port_id bit!): dprint(f"interface.port_id = {interface.port_id}") new_vlan_portlist[int(interface.port_id)] = 1 # now loop to find other existing ports on this vlan: # dprint("Finding other ports on this vlan:") for (this_index, this_iface) in self.interfaces.items(): # dprint(f"{this_iface.name} (port {this_iface.port_id}), Tagged {this_iface.is_tagged}, \ # untagged vlan {this_iface.untagged_vlan}, Vlan dict: {this_iface.vlans}") if this_iface.type == IF_TYPE_ETHERNET: if this_iface.port_id > -1: # we have a valid PortId if this_iface.is_tagged: # tagged interface # dprint(" Tagged") # is the new vlanId active on this port (i.e. PVID or on trunk) ? if (this_iface.untagged_vlan == new_vlan_id) or (new_vlan_id in this_iface.vlans): # dprint(" This port is needed on new vlan") # is this port in Current Egress PortList? # if not, do NOT add! # this can happen with a PVID set on a port in trunk mode, but # the trunk does not allow that vlan! (edge use case) if self.vlans[new_vlan_id].current_egress_portlist[this_iface.port_id]: # dprint(" and in allow list!") new_vlan_portlist[this_iface.port_id] = 1 # else: # dprint(" but NOT in allow list!") else: # untagged on this new vlanId ? if (this_iface.untagged_vlan == new_vlan_id): # dprint(" Port PVID added to new vlan!") new_vlan_portlist[this_iface.port_id] = 1 else: # no switchport? "should" not happen for a valid switch port interface warning = f"Warning: {this_iface.name} - no port_id found in set_interface_untagged_vlan(Comware)!" self._add_warning(warning) # send to the switch! # Comware needs bits in opposite order inside each byte! (go figure) new_vlan_portlist.reverse_bits_in_bytes() # get the PySNMP helper to do the work with this BitMap: # note that to_hex_string() is same as .__str__ representation, # but we use it for extra clarity! octet_string = OctetString(hexValue=new_vlan_portlist.to_hex_string()) pysnmp = pysnmpHelper(self.switch) (error_status, details) = pysnmp.set(f"{hh3cdot1qVlanPorts}.{new_vlan_id}", octet_string) if error_status: self.error.status = True self.error.description = "Error in setting vlan on access port!" self.error.details = details return -1 # now trick the next switch view into showing this as the vlan on the interface # without the need to re-read SNMP data! We could also just read it here :-) # self._parse_oid_and_cache(QBRIDGE_VLAN_IFACE_UNTAGGED_PVID + "." + str(if_index), str(new_vlan_id), 'u') # now we need to reread the interface to VLAN mib part self._get_port_vlan_membership() # and force data to be added to session cache again! self._set_http_session_cache() return 0 # interface not found, return False! return -1
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': reqTime, 'startOID': startOID, 'stopOID': stopOID, 'stopFlag': oids.index(oid) == len(oids) - 1, 'variationModule': variationModule }
def mynextcmd(*junk, **lookupMib): return None, None, None, [[[ObjectName('1.1'), OctetString('b')]]]
IpAddress, ObjectName, OctetString, TimeTicks, Unsigned32, ) data = [] data.append([ObjectName('.1.'), Counter32('100'), 100]) data.append([ObjectName('.1.'), Counter64('100'), 100]) data.append([ObjectName('.1.'), Gauge32('100'), 100]) data.append([ObjectName('.1.'), Integer('100'), 100]) data.append([ObjectName('.1.'), Integer32('100'), 100]) data.append([ObjectName('.1.'), IpAddress('192.168.1.1'), '192.168.1.1']) data.append([ObjectName('.1.'), ObjectIdentifier('1'), '1']) data.append([ObjectName('.1.'), OctetString('my_string'), 'my_string']) data.append([ObjectName('.1.'), Unsigned32('100'), 100]) @pytest.fixture(scope='function', params=data) def query_data(monkeypatch, request): snmp_data = [[request.param[0], request.param[1]]] return GetCmdValues(monkeypatch, return_value=snmp_data, params=request.param) def test_return_value_types(query_data): dev = SnmpHandler(host='1.1.1.1', version='2c', community='public') varbinds = dev.get('1') for oid, value in varbinds:
def get_config(self, timeout=10): """ Метод для получения конфигурационного файла целевого оборудования. В методе определены oid'ы используемого оборудования. Метод работает следующим образом - по snmp запрашивается oid_sysname и по нему определяется тип оборудования, по типу оборудования запрашиваются соответствующие oid и на указанный TFTP сервер закачивается конфигурационный файл оборудования, далее он считывается в виде строки и удаляется с сервера. :param timeout: таймаут на получение конфигурационного файла :rtype: строка с конфигурационным файлом оборудования """ try: if not self.eqp_type: self.get_eqp_type() if not self.firmware: self.get_firmware_version() except DlinkInitException as dlink_exc: logger.error(dlink_exc) raise DlinkConfigException( self.ip, 'дальнейшая работа с оборудованием невозможна') cfg_file_name = 'config-%s.cfg' % self.ip # набор oid'ов для конфигурации обрудования DES-3*** на отдачу # конфигурационного файла на TFTP сервер oids_des = (('1.3.6.1.4.1.171.12.1.2.1.1.3.3', IpAddress(self.tftp_server)), ('1.3.6.1.4.1.171.12.1.2.1.1.4.3', Integer(2)), ('1.3.6.1.4.1.171.12.1.2.1.1.5.3', OctetString(cfg_file_name)), ('1.3.6.1.4.1.171.12.1.2.1.1.6.3', Integer(3)), ('1.3.6.1.4.1.171.12.1.2.1.1.7.3', Integer(2)), ('1.3.6.1.4.1.171.12.1.2.1.1.8.3', Integer(3))) # набор oid'ов для конфигурации обрудования DGS-3*** на отдачу # конфигурационного файла на TFTP сервер oids_dgs = (('1.3.6.1.4.1.171.12.1.2.18.1.1.3.3', IpAddress(self.tftp_server)), ('1.3.6.1.4.1.171.12.1.2.18.1.1.5.3', OctetString(cfg_file_name)), ('1.3.6.1.4.1.171.12.1.2.18.1.1.8.3', Integer(2)), ('1.3.6.1.4.1.171.12.1.2.18.1.1.12.3', Integer(3))) # набор oid'ов для конфигурации обрудования DGS-3100 на отдачу # конфигурационного файла на TFTP сервер oids_tg = (('1.3.6.1.4.1.171.10.94.89.89.87.2.1.4.1', IpAddress( self.ip)), ('1.3.6.1.4.1.171.10.94.89.89.87.2.1.5.1', Integer(1)), ('1.3.6.1.4.1.171.10.94.89.89.87.2.1.6.1', OctetString('startupConfig')), ('1.3.6.1.4.1.171.10.94.89.89.87.2.1.7.1', Integer(3)), ('1.3.6.1.4.1.171.10.94.89.89.87.2.1.8.1', Integer(3)), ('1.3.6.1.4.1.171.10.94.89.89.87.2.1.9.1', IpAddress(self.tftp_server)), ('1.3.6.1.4.1.171.10.94.89.89.87.2.1.10.1', Integer(1)), ('1.3.6.1.4.1.171.10.94.89.89.87.2.1.11.1', OctetString(cfg_file_name)), ('1.3.6.1.4.1.171.10.94.89.89.87.2.1.12.1', Integer(3)), ('1.3.6.1.4.1.171.10.94.89.89.87.2.1.17.1', Integer(4))) cfg_file_end = 'End of configuration file' # TG if 'DGS-3100' in self.eqp_type: current_eqp = oids_tg # переопределяем окончание конфигурационного файла для # оборудования DGS-3100 cfg_file_end = '! VOICE VLAN' # DES-3526, DES-3528, DES-3010G, DGS-3200 elif 'DES-3526' in self.eqp_type \ or 'DES-3528' in self.eqp_type \ or 'DES-3010G' in self.eqp_type \ or 'DGS-3200' in self.eqp_type: current_eqp = oids_des # DGS elif 'DGS-3' in self.eqp_type: current_eqp = oids_dgs # DES elif 'DES-3' in self.eqp_type: if self.firmware: if float(self.firmware[:4]) >= 4.00: current_eqp = oids_dgs else: current_eqp = oids_des else: current_eqp = oids_des else: raise DlinkConfigException( self.ip, 'не удалось определить нужный набор oid ' 'для настройки оборудования на отдачу конфигурационного файла') # получаем конфиг, если определить тип оборудование не получилось, # то выводим соответствующее сообщение try: self.snmp.set(*current_eqp) except snmp.SnmpSetTimeoutException as snmp_exc: logger.critical(snmp_exc) raise DlinkConfigException( self.ip, 'не удалось настроить оборудование на отдачу ' 'конфигурационного файла') logger.debug( '%s - оборудование настроено на отдачу конфигурационного файла ' 'успешно' % self.ip) result = None file_path = os.path.join(self.tftp_path, cfg_file_name) if self.config_load_method == 'local': open_func = open rm_func = os.remove conn_close_func = lambda: None elif self.config_load_method == 'ssh': ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.load_system_host_keys() try: ssh.connect(self.tftp_server, username=self.username, password=self.password) except socket.error as exc: logger.error('%s - %s' % (self.ip, exc)) raise DlinkConfigException( self.ip, 'не удалось подключиться к серверу %s' 'по протоколу ssh' % self.tftp_server) sftp = ssh.open_sftp() open_func = sftp.open rm_func = sftp.remove conn_close_func = ssh.close else: raise DlinkConfigException( self.ip, 'неверно указан метод загрузки конфигурационного файла') _c = 0 while 1: time.sleep(1) if _c < timeout: try: _f = open_func(file_path, mode='r') # обработка ситуации когда файл еще не создан except IOError as io_exc: _c += 1 else: cfg_file = _f.read() if cfg_file_end in cfg_file: _f.close() rm_func(file_path) conn_close_func() result = cfg_file.replace('\r\n', '\n') break else: end_not_obtained = True _c += 1 _f.close() else: conn_close_func() if 'io_exc' in locals(): raise DlinkConfigException( self.ip, 'конфигурационного файла %s не существует ' 'на сервере %s' % (file_path, self.tftp_server)) elif 'end_not_obtained' in locals(): raise DlinkConfigException( self.ip, 'конец файла %s не получен за %s секунд' % (file_path, timeout)) else: raise DlinkConfigException( self.ip, 'не удалось получить конфигурационный файл ' '%s с сервера %s по неизвестной причине' % (file_path, self.tftp_server)) logger.info('%s - конфигурационный файла получен успешно' % self.ip) self.chassis.config_file = result return result