You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

198 lines
5.6 KiB

import os
import time
from datetime import datetime
import datetime as datetimesrc
import psutil
import subprocess
from colors import Colors, getColorsDict
import ipaddress
def pretty_mac(_mac):
try:
mac_split = _mac.split(":")
mac = ""
for ch in mac_split:
if len(ch) == 2:
mac += f"{ch}:"
if len(ch) == 1:
mac += f"0{ch}:"
mac = mac[:-1]
return mac
except:
return _mac
class MacLookup:
prefixes = {}
#https://github.com/bauerj/mac_vendor_lookup/blob/master/mac_vendor_lookup.py
def __init__(self):
self.load_vendors()
pass
@staticmethod
def sanitise(_mac):
mac = _mac.replace(":", "").replace("-", "").replace(".", "").upper()
try:
int(mac, 16)
except ValueError:
raise Exception("{} contains unexpected character".format(_mac))
if len(mac) > 12:
raise Exception("{} is not a valid MAC address (too long)".format(_mac))
return mac
def lookup(self, mac):
try:
mac = self.sanitise(mac)
except:
return f"Unknown MAC ({mac})"
if not self.prefixes:
self.load_vendors()
if type(mac) == str:
mac = mac.encode("utf8")
try:
return self.prefixes[mac[:6]].decode("utf8")
except KeyError:
return f"Unknown MAC ({mac})"
def load_vendors(self):
from pathlib import Path
script_dir = Path(__file__).parent.resolve()
with open(os.path.join(script_dir, "oui.txt"), "rb") as macs:
for line in macs.readlines():
if not line:
break
if b"(base 16)" in line:
prefix, vendor = (i.strip() for i in line.split(b"(base 16)", 1))
self.prefixes[prefix] = vendor
global maclookup
maclookup = MacLookup()
global firstMacLookup
firstMacLookup = {}
def getAvg():
data = os.getloadavg()
return '{0:.2f} {1:.2f} {2:.2f}'.format(*data)
def getDateTime():
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def getCpuPercent(colors = True):
if colors:
u = psutil.cpu_percent(interval=1)
color = ""
if u > 0:
color = Colors.GREEN
if u > 33:
color = Colors.YELLOW
if u > 66:
color = Colors.RED
if u > 99:
u = 99
return "{0}{1:3}%{2}".format(color, u, Colors.END)
else:
return "{0:3}%".format(psutil.cpu_percent(interval=1))
def getMemPercent(colors = True):
if colors:
u = psutil.virtual_memory().percent
color = ""
if u > 0:
color = Colors.GREEN
if u > 33:
color = Colors.YELLOW
if u > 66:
color = Colors.RED
if u > 99:
u = 99
return "{0}{1:3}%{2}".format(color, u, Colors.END)
else:
return "{0:3}%".format(psutil.virtual_memory().percent)
def getRowSeparator():
return Colors.NEGATIVE + "".join([" " for i in range(0, 60)]) + Colors.END
def checkIpInPool(ip, pool):
if not ip or not pool:
return True
return ipaddress.ip_address(ip) in ipaddress.ip_network(pool)
def pingHostViaNMap(ip_pool = None):
if ip_pool is None:
return ""
subprocess.check_output(f"nmap -sn {ip_pool}", shell=True, text=True)
return getDateTime()
def getArp(ip_pool = None):
#pingHostViaNMap(ip_pool)
global maclookup
if maclookup is None:
maclookup = MacLookup()
global firstMacLookup
#linux | ? (192.168.1.136) at a8:7e:ea:64:85:de [ether] on eth0
#mac | mdns.mcast.net (224.0.0.251) at 1:0:5e:0:0:fb on en0 ifscope permanent [ethernet]
arp_res = subprocess.check_output("arp -a", shell=True, text=True)
result = []
found_macs = []
for line in arp_res.split("\n"):
if line:
host, ip, at, mac, *other = line.split(" ")
ip = ip[1:-1]
if checkIpInPool(ip, ip_pool):
pass
else:
continue
if mac == "(incomplete)":
continue
if mac == "FF:FF:FF:FF:FF:FF".lower():
continue
mac = pretty_mac(mac)
if mac not in firstMacLookup:
firstMacLookup[mac] = int(time.time())
found_macs.append(mac)
delta = int(time.time()) - firstMacLookup[mac]
result.append({
"host": host,
"ip": ip,
"mac": mac,
"mac_name": maclookup.lookup(mac),
"delta": delta,
"mac_first_lookup_utime": str(datetimesrc.timedelta(seconds=delta))
})
unused_macs = [mac for mac in list(firstMacLookup.keys()) if mac not in found_macs]
for mac in unused_macs:
del firstMacLookup[mac]
txt = ""
exists = []
for host in result:
host.update(getColorsDict())
if host["ip"] not in exists:
exists.append(host["ip"])
host["time_color"] = Colors.RED
if host["delta"] > 60 * 60:
host["time_color"] = Colors.YELLOW
if host["delta"] > 60 * 60 * 12:
host["time_color"] = Colors.GREEN
mac_name_len = len(host["mac_name"])
host["mac_name"] = host["mac_name"][:31] + ("..." if mac_name_len > 31 else "")
txt += "{time_color}{mac_first_lookup_utime}{END} - {BLUE}{ip}{END} - {mac_name}\n".format(**host)
return txt[:-1]
if __name__ == "__main__":
print(getArp())