from haircontrol.data import * from haircontrol.inspectors import * class Discovery: def __init__(self): #, inspector): self.net = EtherDomain() self.dummy_inspector = DummyInspector() self.linux_inspector = LinuxInspector() self.ubnt_inspector = UbntInspector() self.toughswitch_inspector = ToughSwitchInspector() self.edgemax_inspector = EdgeMaxInspector() self.netonix_inspector = NetonixInspector() self.mikrotik_inspector = MikrotikInspector() self.openwrt_inspector = OpenWRTInspector() self.inspector_by_mac = { # Mikrotik 'd4:ca:6d': self.mikrotik_inspector, 'e4:8d:8c': self.mikrotik_inspector, # Netonix 'ec:13:b2': self.netonix_inspector, 'ec:13:b3': self.netonix_inspector, # PC '0c:c4:7a': self.linux_inspector, # SuperMicro '52:54:00': self.linux_inspector, # VM # TP-Link '10:fe:ed': self.openwrt_inspector, '14:cc:20': self.openwrt_inspector, '30:b5:c2': self.openwrt_inspector, '54:e6:fc': self.openwrt_inspector, '60:e3:27': self.openwrt_inspector, '64:66:b3': self.openwrt_inspector, '64:70:02': self.openwrt_inspector, '90:f6:52': self.openwrt_inspector, 'a0:f3:c1': self.openwrt_inspector, 'b0:48:7a': self.openwrt_inspector, 'c0:4a:00': self.openwrt_inspector, 'c4:6e:1f': self.openwrt_inspector, 'c4:e9:84': self.openwrt_inspector, 'f4:ec:38': self.openwrt_inspector, 'f8:1a:67': self.openwrt_inspector, 'f8:d1:11': self.openwrt_inspector, # Ubnt '00:15:6d': self.ubnt_inspector, '00:27:22': self.ubnt_inspector, '04:18:d6:07': self.toughswitch_inspector, '04:18:d6': self.ubnt_inspector, '06:18:d6': self.ubnt_inspector, # Non globaly unique ?! '24:a4:3c:05': self.toughswitch_inspector, '24:a4:3c:06': self.toughswitch_inspector, '24:a4:3c:07': self.toughswitch_inspector, '24:a4:3c:3c': self.toughswitch_inspector, '24:a4:3c:3d': self.toughswitch_inspector, '24:a4:3c:b3': self.toughswitch_inspector, '24:a4:3c': self.ubnt_inspector, '44:d9:e7': self.edgemax_inspector, 'dc:9f:db:80': self.toughswitch_inspector, 'dc:9f:db:81': self.toughswitch_inspector, 'dc:9f:db': self.ubnt_inspector, } def inspector(self, mac): if mac: return self.inspector_by_mac.get(mac[:11]) \ or self.inspector_by_mac.get(mac[:8]) \ or self.dummy_inspector else: return self.dummy_inspector def discover_static_hinting(self, name_ip_tuples): for name, ip in name_ip_tuples: self.net.add_equipment(Equipment(name, ip)) def discover_lldp_hinting(self, e_lldp): self.net.add_equipment(e_lldp) self.linux_inspector.connect(e_lldp) # Learn local interfaces of e_lldp result = self.linux_inspector.command('ip-link') for (ifname, mac) in result: if ifname not in [ 'lo' ]: # XXX configurable filter e_lldp.add_iface(ifname, mac) # Create equipments and ifaces from LLDP neighbour discovery result = self.linux_inspector.command('lldpctl') for (local_ifname, local_mac, remote_name, remote_ipmgmt, ports) in result: e = Equipment(remote_name, remote_ipmgmt) self.net.add_equipment(e) # lldp returns logical port, not physicial port for remote bridges for remote_ifname in ports: if remote_ifname not in [ 'br0' ]: # XXX configurable filter e.add_seen_mac(remote_ifname, local_mac) self.linux_inspector.disconnect() def discover_from_root(self, e_root): self.net.add_equipment(e_root) self.linux_inspector.connect(e_root) # Learn root neighbours (directly or indirectly connected via trasparent bridges) result = self.linux_inspector.command('ip-neigh') for (ip, ifname, mac) in result: self.net.index_mac_ip(mac, ip) e_root.add_seen_mac(ifname, mac) self.linux_inspector.disconnect() # Create/Update Equipment object for all neighbours # (could be already created by hinting) for iface in e_root.ifaces.values(): local_ifname = iface.name local_mac = iface.mac for remote_mac in iface.mac_seen: remote_ip = self.net.mac2ip.get(remote_mac) if remote_ip: e = self.net.equipments.get(remote_ip) if e and not e.ifaces: e.add_iface(None, remote_mac) elif not e: e = Equipment('?', remote_ip) e.add_iface('?', remote_mac) self.net.add_equipment(e) # Inspect all non-already inspected equipement done = False while not done: done = True for ip,e in self.net.equipments.items(): if not e.inspected: done = False # Find the right inspector from equipment's first iface mac address if e.ifaces: e_first_mac = next(iter(e.ifaces.values())).mac i = self.inspector(e_first_mac) else: # XXX Custom hack if e.mgmtip.startswith('172.16.1'): i = self.ubnt_inspector elif e.mgmtip == '172.16.30.23': i = self.edgemax_inspector elif e.mgmtip.startswith('172.16.3'): i = self.toughswitch_inspector else: i = self.dummy_inspector i.connect(e) # Inspect antennas if isinstance(i, UbntInspector): # Learn local interfaces result = i.command('status.cgi') for (ifname, mac) in result: if ifname not in [ 'lo', 'wifi0', 'br0' ]: # XXX configurable filter e.add_iface(ifname, mac) # Learn bridge tables result = i.command('brmacs.cgi') for (ifname, mac) in result: e.add_seen_mac(ifname, mac) # Inspect switches elif isinstance(i, ToughSwitchInspector): result = i.command('ip-link') switch_mac = '?' for (ifname, mac) in result: if ifname == 'br0': # XXX configurable filter switch_mac = mac result = i.command('mactable_data.cgi') for (ifname, mac) in result: e.add_iface(ifname, switch_mac) # XXX many non-usefull calls e.add_seen_mac(ifname, mac) elif isinstance(i, EdgeMaxInspector): switch_mac = '?' result = i.command('show-version') for (key, value) in result: if key == 'Burned In MAC Address': switch_mac = value result = i.command('mac-addr-table') for (mac, ifname) in result: e.add_iface(ifname, switch_mac) # XXX many non-usefull calls e.add_seen_mac(ifname, mac) else: print("Notice: Nothing inspected on %s"%e) i.disconnect() def compute_neighbourhood(self): print("**********compute_neighbourhood************") # net.equipments[].ifaces[].mac_seen[i] # Fake algorithm random_e = '172.16.0.254' for (mgmt_ip,e) in self.net.equipments.items(): for (ifname,i) in e.ifaces.items(): last = None for mac_seen in i.mac_seen: last = mac_seen if last and last in self.net.mac2ip: random_e = self.net.mac2ip[last] i.direct_neighbours.append(random_e) # for (mgmt_ip,e) in self.net.equipments.items(): # print("%s (%s)"%(mgmt_ip,e.name)) # for (ifname,i) in e.ifaces.items(): # print("\t%s"%i.name) # for mac_seen in i.mac_seen: # print("\t\tseen %s"%mac_seen) # for remote_mgmtip in i.direct_neighbours: # e = self.net.equipments[remote_mgmtip] # print("\t\tdirect_neighbour %s (%s)"%(remote_mgmtip, e.name)) print("**********compute_neighbourhood************")