def execute_snmp(self): macs = set() # Process SNMP GET oids = self.get_snmp_get_oids() if oids: r = self.snmp_safe(dict(zip(oids, oids))) for k in r: v = r[k] if v: try: macs.add(MAC(v)) except ValueError: pass # Process SNMP GETNEXT requests oids = self.get_snmp_getnext_oids() try: for oid in oids: for k, v in self.snmp.getnext(oid): if v: try: macs.add(MAC(v)) except ValueError: pass except SNMPError: pass # Filter and convert macs r = [{ "first_chassis_mac": mac, "last_chassis_mac": mac } for mac in sorted(macs) if not self.is_ignored_mac(mac)] if not r: raise NotImplementedError return r
def execute_snmp(self): neighb = ( "remote_chassis_id_subtype", "remote_chassis_id", "remote_port_subtype", "remote_port", "remote_port_description", "remote_system_name", "remote_system_description", "remote_capabilities", ) r = [] local_ports = {} # Get LocalPort Table for v in self.snmp.get_tables([ "1.0.8802.1.1.2.1.3.7.1.2", # LLDP-MIB::lldpLocPortIdSubtype "1.0.8802.1.1.2.1.3.7.1.4", # LLDP-MIB::lldpLocPortDesc ]): local_ports[v[0]] = { "local_interface": self.profile.convert_interface_name(v[2]), "local_interface_subtype": v[1], } for v in self.snmp.get_tables( [ "1.0.8802.1.1.2.1.4.1.1.4", # LLDP-MIB::lldpRemChassisIdSubtype "1.0.8802.1.1.2.1.4.1.1.5", # LLDP-MIB::lldpRemChassisId "1.0.8802.1.1.2.1.4.1.1.6", # LLDP-MIB::lldpRemPortIdSubtype "1.0.8802.1.1.2.1.4.1.1.7", # LLDP-MIB::lldpRemPortId "1.0.8802.1.1.2.1.4.1.1.8", # LLDP-MIB::lldpRemPortDesc "1.0.8802.1.1.2.1.4.1.1.9", # LLDP-MIB::lldpRemSysName "1.0.8802.1.1.2.1.4.1.1.10", # LLDP-MIB::lldpRemSysDesc "1.0.8802.1.1.2.1.4.1.1.12", # LLDP-MIB::lldpRemSysCapEnabled ], display_hints={ "1.0.8802.1.1.2.1.4.1.1.7": render_bin, "1.0.8802.1.1.2.1.4.1.1.5": render_bin, }, ): neigh = dict(list(zip(neighb, v[1:]))) if neigh["remote_chassis_id_subtype"] == LLDP_CHASSIS_SUBTYPE_MAC: neigh["remote_chassis_id"] = MAC(neigh["remote_chassis_id"]) if neigh["remote_port_subtype"] == LLDP_PORT_SUBTYPE_MAC: neigh["remote_port"] = MAC(neigh["remote_port"]) for i in neigh: if isinstance(neigh[i], str): neigh[i] = neigh[i].rstrip(smart_text("\x00")) if neigh["remote_capabilities"]: neigh["remote_capabilities"] = int( "".join(x for x in reversed("{0:016b}".format( ord(neigh["remote_capabilities"]) << 8 + 0x0))), 2, ) else: neigh["remote_capabilities"] = 0 r += [{ "local_interface": local_ports[v[0].split(".")[1]]["local_interface"], "neighbors": [neigh], }] return r
def fix(): collection = DiscoveryID._get_collection() bulk = [] for d in DiscoveryID._get_collection().find(): ranges = d.get("chassis_mac", []) if not ranges: continue macs = [] for r in ranges: first = MAC(r["first_mac"]) last = MAC(r["last_mac"]) macs += [m for m in range(int(first), int(last) + 1)] bulk += [UpdateOne({"_id": d["_id"]}, {"$set": {"macs": macs}})] if len(bulk) == BATCH_SIZE: print("Commiting changes to database") try: collection.bulk_write(bulk) bulk = [] print("Database has been synced") except BulkWriteError as e: print("Bulk write error: '%s'", e.details) print("Stopping check") bulk = [] if bulk: collection.bulk_write(bulk)
def execute_cli(self): v = self.cli("show chassis mac-addresses") macs = [] for f, t in [ (mac, MAC(mac).shift(int(count) - 1)) for _, mac, count in self.rx_range.findall(v) ]: if macs and MAC(f).shift(-1) == macs[-1][1]: macs[-1][1] = t else: macs += [[f, t]] # Found in some oldest switches if macs == []: match = self.rx_range2.search(v) base = match.group("mac") count = int(match.group("count")) return [{"first_chassis_mac": base, "last_chassis_mac": MAC(base).shift(count - 1)}] try: # Found in ex4550-32f JUNOS 15.1R7-S7.1 # Chassic ID MAC somehow differs from `Public base address` v = self.cli("show lldp local-information", cached=True) match = self.rx_lldp.search(v) if match: macs += [[match.group("mac"), match.group("mac")]] except self.CLISyntaxError: # Found in m7i JUNOS 8.5R4.3 pass return [{"first_chassis_mac": f, "last_chassis_mac": t} for f, t in macs]
def execute_cli(self): v = self.cli("about", cached=True) s = parse_kv({"mac address": "mac"}, v) if s: s = s["mac"].replace(" ", ":") return [{"first_chassis_mac": MAC(s), "last_chassis_mac": MAC(s)}] else: raise self.NotSupportedError
def execute_cli(self, **kwargs): v = self.cli("admin show diag chassis eeprom-info") macs = [] for f, t in [ (mac, MAC(mac).shift(int(count) - 1)) for mac, count in self.rx_range.findall(v) ]: if macs and MAC(f).shift(-1) == macs[-1][1]: macs[-1][1] = t else: macs += [[f, t]] return [{"first_chassis_mac": f, "last_chassis_mac": t} for f, t in macs]
def execute_snmp(self): neighb = ( "remote_chassis_id_subtype", "remote_chassis_id", "remote_port_subtype", "remote_port", "remote_port_description", "remote_system_name", ) r = [] local_ports = {} if self.has_snmp(): # Get LocalPort Table for v in self.snmp.get_tables([ "1.0.8802.1.1.2.1.3.7.1.1", "1.0.8802.1.1.2.1.3.7.1.2", "1.0.8802.1.1.2.1.3.7.1.3", "1.0.8802.1.1.2.1.3.7.1.4", ]): local_ports[v[0]] = { "local_interface": v[4], "local_interface_subtype": v[2] } for v in self.snmp.get_tables( [ "1.0.8802.1.1.2.1.4.1.1.2", "1.0.8802.1.1.2.1.4.1.1.4", "1.0.8802.1.1.2.1.4.1.1.5", "1.0.8802.1.1.2.1.4.1.1.6", "1.0.8802.1.1.2.1.4.1.1.7", "1.0.8802.1.1.2.1.4.1.1.8", "1.0.8802.1.1.2.1.4.1.1.9", ], bulk=True, ): if v: neigh = dict(zip(neighb, v[2:])) if neigh["remote_chassis_id_subtype"] == 4: neigh["remote_chassis_id"] = MAC( neigh["remote_chassis_id"]) if neigh["remote_port_subtype"] == 3: neigh["remote_port"] = MAC(neigh["remote_port"]) r += [{ "local_interface": local_ports[v[0].split(".")[1]]["local_interface"], # @todo if local interface subtype != 5 # "local_interface_id": 5, "neighbors": [neigh], }] return r
def execute_snmp(self): neighb = ( "remote_chassis_id_subtype", "remote_chassis_id", "remote_port_subtype", "remote_port", "remote_port_description", "remote_system_name", ) r = [] local_ports = self.get_local_iface() if self.has_snmp(): for v in self.snmp.get_tables( [ mib["LLDP-MIB::lldpRemLocalPortNum"], mib["LLDP-MIB::lldpRemChassisIdSubtype"], mib["LLDP-MIB::lldpRemChassisId"], mib["LLDP-MIB::lldpRemPortIdSubtype"], mib["LLDP-MIB::lldpRemPortId"], mib["LLDP-MIB::lldpRemPortDesc"], mib["LLDP-MIB::lldpRemSysName"], ], bulk=True, ): if v: neigh = dict(zip(neighb, v[2:])) # cleaning if neigh[ "remote_port_subtype"] == LLDP_PORT_SUBTYPE_COMPONENT: neigh["remote_port_subtype"] = LLDP_PORT_SUBTYPE_ALIAS neigh["remote_port"] = neigh["remote_port"].strip( " \x00") # \x00 Found on some devices if neigh[ "remote_chassis_id_subtype"] == LLDP_CHASSIS_SUBTYPE_MAC: neigh["remote_chassis_id"] = MAC( neigh["remote_chassis_id"]) if neigh["remote_port_subtype"] == LLDP_PORT_SUBTYPE_MAC: try: neigh["remote_port"] = MAC(neigh["remote_port"]) except ValueError: self.logger.warning( "Bad MAC address on Remote Neighbor: %s", neigh["remote_port"]) r += [{ "local_interface": local_ports[v[0].split(".")[1]]["local_interface"], # @todo if local interface subtype != 5 # "local_interface_id": 5, "neighbors": [neigh], }] return r
def execute_cli(self): if self.is_tau4: c = self.cli("cat /tmp/.board_desc", cached=True) match = self.rx_shell_mac.search(c) elif self.is_tau8: c = self.cli("cat /tmp/board_mac", cached=True) match = self.rx_shell_mac_tau8.search(c) else: c = self.cli("cat /tmp/factory", cached=True) match = self.rx_shell_mac.search(c) if not match: return [] s = match.group("mac") return {"first_chassis_mac": MAC(s), "last_chassis_mac": MAC(s)}
def api_list(self, request): q = dict((str(k), v[0] if len(v) == 1 else v) for k, v in request.GET.lists()) # find mac request select max(ts), managed_object, interface, vlan from mac # where like(MACNumToString(mac), 'A0:AB:1B%') group by managed_object, interface, vlan; query = q.get("__query") start = q.get("__start") limit = q.get("__limit") # page = q.get("__page") out = [] if not query: return self.response(out, status=self.OK) try: mac = int(MAC(MACAddressParameter(accept_bin=False).clean(query))) out = self.api_macdb({"mac": mac}, limit=limit, offset=start) except ValueError: if self.mac_search_re.match(query): out = self.api_macdb({"mac__like": "%s%%" % str(query.upper())}, limit=limit, offset=start) elif self.mac_search_re_inv.match(query): out = self.api_macdb({"mac__like": "%%%s" % str(query.upper())}, limit=limit, offset=start) else: # Try MO search # @todo ManagedObject search self.logger.debug("MACDB ManagedObject search") mo_q = ManagedObject.get_search_Q(query) if not mo_q: mo_q = d_Q(name__contains=query) mos = [mo.bi_id for mo in ManagedObject.objects.filter(mo_q)[:2]] if mos: out = self.api_macdb({"managed_object__in": mos}, limit=limit, offset=start) # out = self.api_get_maclog(request, mac) return self.response(out, status=self.OK)
def execute(self): try: v = self.cli("show sprom backplane | include MAC") except self.CLISyntaxError: try: v = self.cli("show sprom backplane 1 | include MAC") except self.CLISyntaxError: raise self.NotSupportedError() try: v += "\n" + self.cli("show sprom fex all | include MAC") except self.CLISyntaxError: pass r = [] for match in self.rx_mac.finditer(v): base = match.group("base") count = int(match.group("count")) if count == 0: continue r += [{ "first_chassis_mac": base, "last_chassis_mac": MAC(base).shift(count - 1) }] return r
def execute(self): # Try SNMP first if self.has_snmp(): try: macs = set() for v in self.snmp.getnext(mib["IF-MIB::ifPhysAddress"]): macs.add(int(MAC(v[1]))) ranges = [] for m in sorted(macs): if not ranges or m - ranges[-1][1] != 1: ranges += [[m, m]] else: ranges[-1][1] = m return [{ "first_chassis_mac": r[0], "last_chassis_mac": r[1] } for r in ranges] except self.snmp.TimeOutError: pass # Fallback to CLI match = self.rx_mac.search(self.cli("show system", cached=True)) if match: mac_begin = match.group("mac") mac_end = match.group("mac") else: c = self.cli("show system unit 1", cached=True) match = self.rx_mac.search(c) mac_begin = match.group("mac") match = self.rx_mac2.search(c) mac_end = match.group("mac") return {"first_chassis_mac": mac_begin, "last_chassis_mac": mac_end}
def save(self, *args, **kwargs): self.mac = MAC(self.mac) if not self.last_changed: self.last_changed = datetime.datetime.now() try: super().save(*args, **kwargs) except Exception as e: raise ValueError("%s: %s" % (e.__doc__, e.message))
def execute_7200(self): """ 7200, 7301 :return: """ v = self.cli("show c%s00 | i MAC" % self.version["platform"][:2]) macs = [] for f, t in [(mac, MAC(mac).shift(int(count) - 1)) for count, mac in self.rx_7200.findall(v)]: if macs and MAC(f).shift(-1) == macs[-1][1]: macs[-1][1] = t else: macs += [[f, t]] return [{ "first_chassis_mac": f, "last_chassis_mac": t } for f, t in macs]
def execute_IOSXE(self): """ IOS XE :return: """ v = self.cli("show diag chassis eeprom detail") macs = [] for f, t in [(mac, MAC(mac).shift(int(count) - 1)) for mac, count in self.rx_iosxe.findall(v)]: if macs and MAC(f).shift(-1) == macs[-1][1]: macs[-1][1] = t else: macs += [[f, t]] return [{ "first_chassis_mac": f, "last_chassis_mac": t } for f, t in macs]
def macs_for_objects(cls, objects_ids): """ Get MAC addresses for object :param cls: :param objects_ids: Lis IDs of Managed Object Instance :type: list :return: Dictionary mac: objects :rtype: dict """ if not objects_ids: return None if isinstance(objects_ids, list): objects = objects_ids else: objects = list(objects_ids) os = cls.objects.filter(object__in=objects) if not os: return None # Discovered chassis id range c_macs = { int(did[0][0]): did[1] for did in os.scalar("macs", "object") if did[0] } # c_macs = [r.macs for r in os] # Other interface macs i_macs = { int(MAC(i[0])): i[1] for i in Interface.objects.filter(managed_object__in=objects, mac__exists=True).scalar( "mac", "managed_object") if i[0] } # Other subinterface macs (actual for DSLAM) si_macs = { int(MAC(i[0])): i[1] for i in SubInterface.objects.filter(managed_object__in=objects, mac__exists=True).scalar( "mac", "managed_object") if i[0] } c_macs.update(i_macs) c_macs.update(si_macs) return c_macs
def _macs_to_ranges(macs): """ Convert list of macs (as integers) to MACRange :param macs: List of integer :return: List of MACRange """ ranges = [] for mi in macs: if ranges and mi - ranges[-1][1] == 1: # Extend last range ranges[-1][1] = mi else: # New range ranges += [[mi, mi]] return [ MACRange(first_mac=str(MAC(r[0])), last_mac=str(MAC(r[1]))) for r in ranges ]
def execute_c3900(self): """ Cisco ISR series C3900, C2951 :return: """ v = self.cli("show diag") macs = [] for f, t in [(mac, MAC(mac).shift(int(count) - 1)) for mac, count in self.rx_iosxe.findall(v)]: if macs and MAC(f).shift(-1) == macs[-1][1]: macs[-1][1] = t else: macs += [[f, t]] return [{ "first_chassis_mac": f, "last_chassis_mac": t } for f, t in macs]
def execute_cli(self): # Does not work for Cisco CRS-16/S Version IOSXR 4.3.2. Impossible get chassis mac over CLI # must be use SNMP method if self.is_platform_crs16 and self.has_snmp(): return self.execute_snmp() v = self.cli("admin show diag chassis eeprom-info") macs = [] for f, t in [(mac, MAC(mac).shift(int(count) - 1)) for mac, count in self.rx_range.findall(v)]: if macs and MAC(f).shift(-1) == macs[-1][1]: macs[-1][1] = t else: macs += [[f, t]] return [{ "first_chassis_mac": f, "last_chassis_mac": t } for f, t in macs]
def execute_snmp(self, vrf=None, **kwargs): r = [] names = {x: y for y, x in six.iteritems(self.scripts.get_ifindexes())} for oid, mac in self.snmp.getnext( mib["RFC1213-MIB::ipNetToMediaPhysAddress"]): ifindex, ip = oid[21:].split(".", 1) ifname = names.get(int(ifindex)) if ifname: r += [{"ip": ip, "mac": MAC(mac), "interface": ifname}] return r
def execute_snmp( self, interface=None, enable_ifindex=False, enable_interface_mac=False, enable_admin_status=False, enable_oper_status=False, ): iter_tables = [] ifindex = None iter_tables += [self.iter_interface_ifindex(interface)] if enable_interface_mac: iter_tables += [ self.iter_iftable("mac", mib[self.SNMP_MAC_TABLE], ifindex=ifindex) ] if enable_admin_status: iter_tables += [ self.iter_iftable( "admin_status", mib[self.SNMP_ADMIN_STATUS_TABLE], ifindex=ifindex, clean=self.clean_status, ) ] if enable_oper_status: iter_tables += [ self.iter_iftable( "oper_status", mib[self.SNMP_OPER_STATUS_TABLE], ifindex=ifindex, clean=self.clean_status, ) ] # Collect and merge results data = self.merge_tables(*tuple(iter_tables)) # Format result result = [] for ifindex in sorted(data): v = data[ifindex] if "name" not in v: continue item = {"interface": v["name"]} if enable_ifindex and "ifindex" in v: item["ifindex"] = v["ifindex"] if (enable_interface_mac and "mac" in v and is_mac(v["mac"]) and not self.is_ignored_mac(MAC(v["mac"]))): item["mac"] = v["mac"] if enable_admin_status and "admin_status" in v: item["admin_status"] = v["admin_status"] if enable_oper_status and "oper_status" in v: item["oper_status"] = v["oper_status"] result += [item] return result
def clean(self, value): if value is None and self.default is not None: return self.default if isinstance(value, str): value = super().clean(value) if not self.accept_bin and len(value) <= 6: self.raise_error(value) try: return str(MAC(value)) except ValueError: self.raise_error(value)
def clean(self, value): if value is None and self.default is not None: return self.default if isinstance(value, six.string_types): value = super(MACAddressParameter, self).clean(value) if not self.accept_bin and len(value) <= 6: self.raise_error(value) try: return str(MAC(value)) except ValueError: self.raise_error(value)
def _macs_as_ints(ranges=None, additional=None): """ Get all MAC addresses within ranges as integers :param ranges: list of dicts {first_chassis_mac: ..., last_chassis_mac: ...} :param additional: Optional list of additional macs :return: List of integers """ ranges = ranges or [] additional = additional or [] # Apply ranges macs = set() for r in ranges: if not r: continue first = MAC(r["first_chassis_mac"]) last = MAC(r["last_chassis_mac"]) macs.update(m for m in range(int(first), int(last) + 1)) # Append additional macs macs.update(int(MAC(m)) for m in additional) return sorted(macs)
def execute(self, interface=None, vlan=None, mac=None): cmd = "show mac address-table" if interface is not None: cmd += " interface %s" % interface if vlan is not None: cmd += " vlan %s" % vlan if mac is not None: cmd += " %s" % MAC(mac).to_cisco() r = [] for i in parse_table(self.cli(cmd), allow_extend=True): r += [{"vlan_id": i[0], "mac": i[1], "interfaces": [i[3]], "type": "D"}] return r
def execute_cli(self): v = self.cli("show chassis mac-addresses") macs = [] for f, t in [(mac, MAC(mac).shift(int(count) - 1)) for _, mac, count in self.rx_range.findall(v)]: if macs and MAC(f).shift(-1) == macs[-1][1]: macs[-1][1] = t else: macs += [[f, t]] # Found in some oldest switches if macs == []: match = self.rx_range2.search(v) base = match.group("mac") count = int(match.group("count")) return [{ "first_chassis_mac": base, "last_chassis_mac": MAC(base).shift(count - 1) }] return [{ "first_chassis_mac": f, "last_chassis_mac": t } for f, t in macs]
def is_banned_mac(cls, mac: str, is_duplicated: bool = False) -> bool: """ Check if mac is banned for specified reason :param mac: :param is_duplicated: :return: """ m = MAC(mac) for item in cls._get_blacklist(): if item.from_mac <= m <= item.to_mac: if is_duplicated and item.is_duplicated: return True return False
def find_objects(cls, macs): """ Find objects for list of macs :param macs: List of MAC addresses :return: dict of MAC -> ManagedObject for resolved MACs """ r = {} if not macs: return r # Build list of macs to search mlist = sorted(int(MAC(m)) for m in macs) # Search for macs obj_ranges = {} # (first, last) -> mo for d in DiscoveryID._get_collection().find({"macs": { "$in": mlist }}, { "_id": 0, "object": 1, "chassis_mac": 1 }): mo = ManagedObject.get_by_id(d["object"]) if mo: for dd in d.get("chassis_mac", []): obj_ranges[int(MAC(dd["first_mac"])), int(MAC(dd["last_mac"]))] = mo n = 1 for s, e in obj_ranges: n += 1 # Resolve ranges start = 0 ll = len(mlist) for s, e in sorted(obj_ranges): mo = obj_ranges[s, e] start = bisect.bisect_left(mlist, s, start, ll) while start < ll and s <= mlist[start] <= e: r[MAC(mlist[start])] = mo start += 1 return r
def execute_snmp(self): macs = set() for v in self.snmp.getnext(mib["IF-MIB::ifPhysAddress"]): macs.add(int(MAC(v[1]))) ranges = [] for m in sorted(macs): if not ranges or m - ranges[-1][1] != 1: ranges += [[m, m]] else: ranges[-1][1] = m return [{ "first_chassis_mac": r[0], "last_chassis_mac": r[1] } for r in ranges]
def execute_cat4000(self): """ Cisco Catalyst 4000/4500/4500e Series :return: """ try: v = self.cli("show idprom chassis") except self.CLISyntaxError: v = self.cli("show idprom supervisor") match = self.re_search(self.rx_cat4000, v) base = match.group("id") count = int(match.group("count")) return [{ "first_chassis_mac": base, "last_chassis_mac": MAC(base).shift(count - 1) }]