#!/usr/bin/python3
#
# Script by Wouter Barendsen
# Created : 2017-10-30
# modified: 2024-02-11 11:42:42
#
# Module: netmiko
import subprocess, sys, time, datetime, re, os
import netmiko
from operator import itemgetter
### Editable variables ######################
# IP of naam van de core router
Device="192.168.2.254"
# credentials
User="user"
Pass="password"
# script directory
ProgDir="/home/sjaak/scripts/macinvent/"
# dir waar html files moeten komen
ExportDir="/home/sjaak/public_html/macinvent/"
# Namen van bestanden hoeven niet gewijzigd te worden
Csv=ProgDir+"mac-invent.csv"
Export=ExportDir+"mac-invent.html"
Export2=ExportDir+"mac-invent-date.html"
IpArp="shiparp.txt"
# html kleuren evt aan te passen
ColorLine="#ffe300"
ColorBg="#fefecc"
### Variables ###############################
SecsStart=time.time()
Epoch=int(time.time())
MacInvent=[]
LineCnt=0
Appended=0
Updated=0
Secs=0
def help():
print("mac-invent2.py by Wouter Barendsen 2017-2024")
print(" -h, --help help")
print(" ")
print(" Doet een ssh naar een (core) router/L3-switch en doet 'sh ip arp',")
print(" de output gaat door grep zodat alleen de mac adres regels erin staan.")
print(" Dit bestand wordt doorlopen en vergeleken met het bestaande CSV bestand.")
print(" Nieuwe mac adressen worden toegevoegd en bestaande mac adressen worden ")
print(" geupdate met het laatst gezien ip adres, vlan en datum.")
print(" ")
exit(1)
if len(sys.argv) >1:
if sys.argv[1]=="-h" or sys.argv[1]=="--help":
help()
def getIpArp(Ip,Dest):
if Ip == "none":
exit
ssh_connection = netmiko.ConnectHandler(device_type='cisco_ios',ip=Ip,username=User,password=Pass)
result = ssh_connection.send_command("sh ip arp", delay_factor=1)
ssh_connection.disconnect()
resultList=result.split('\n')
try:
with open(Dest,'w') as F:
for line in resultList:
if "Vlan" in line: F.write(line+'\n')
except IOError as E:
print("Error writing",Dest,"!!")
sys.exit(1)
getIpArp(Device,ProgDir+IpArp)
# lees de csv-file in een list of lists
with open(Csv) as f:
for Line in f:
Line=Line.strip()
Record=Line.split(sep=";")
MacInvent.append(Record)
LineCnt+=1
TotalRec=len(MacInvent)
with open(ProgDir+IpArp) as f:
for Line in f:
# ontleed ip,vlan en mac
Match=re.search(r'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}',Line)
if Match:
Ip=Match.group()
Match=re.search(r'Vlan([0-9]*)',Line)
if Match:
Vlan=Match.group(1)
Match=re.search(r'[0-9a-z]{4}\.[0-9a-z]{4}\.[0-9a-z]{4}',Line)
if Match:
Mac=Match.group()
#print("DEBUG: ",Ip,Vlan,Mac)
# check of mac in list
Index=0
Found=False
for Effe in MacInvent:
if Effe[0]==Mac:
# ja: edit die regel met nieuwe ip, vlan en Epoch
Found=True
MacInvent[Index][1]=Vlan
MacInvent[Index][2]=Ip
MacInvent[Index][4]=str(Epoch)
Updated+=1
Index=Index+1
if Found==False:
# nee: append list met [mac,vlan,ip,Epoch,Epoch]
MacInvent.append([Mac,Vlan,Ip,str(Epoch),str(Epoch)])
Appended+=1
print("Toegevoegd: "+Mac+" "+Vlan+" "+Ip)
# sorteer list op vlan
MacInvent2=sorted(MacInvent, key=itemgetter(1,2))
# sorteer op epoch laatste gezien
MacInvent3=sorted(MacInvent, key=itemgetter(4))
# mv csv naar backup
os.rename(Csv,Csv+".backup")
# schrijf csv weg
with open(Csv,'w') as f:
for Effe in MacInvent2:
f.write(Effe[0]+";"+Effe[1]+";"+Effe[2]+";"+Effe[3]+";"+Effe[4]+"\n")
# Schrijf html export weg met dattime ipv epoch gesorteerd op mac adres
Fseen=""
Lseen=""
Class="een"
with open(Export,'w') as f:
f.write("
Mac-address | vlan | IP | First seen | Last seen |
")
f.write("")
f.write("mac-invent
")
f.write("Deze export van mac-invent laat alle mac adressen zien die op het netwerk zijn geweest (gerouteerd!).
Het vlan en ip adres zijn de laatste waarmee dit mac adres gezien is op datum en tijd in de laatste kolom.
Bijzondere mac adressen die dubbel voorkomen (L3 switches) worden maar een keer getoond.
")
for Effe in MacInvent2:
Fs=datetime.datetime.fromtimestamp(int(Effe[3]))
Ls=datetime.datetime.fromtimestamp(int(Effe[4]))
Fseen=str.format("%04d-%02d-%02d_%02d:%02d" % (Fs.year,Fs.month,Fs.day,Fs.hour,Fs.minute))
Lseen=str.format("%04d-%02d-%02d_%02d:%02d" % (Ls.year,Ls.month,Ls.day,Ls.hour,Ls.minute))
Line=""+Effe[0]+" | "+Effe[1]+" | "+Effe[2]+" | "+Fseen+" | "+Lseen+" |
\n"
f.write(Line)
if Class=="een":
Class="twee"
else:
Class="een"
f.write("")
# schrijf html export weg van op date_last_seen gesorteerde list
with open(Export2,'w') as f:
f.write("Mac-address | vlan | IP | First seen | Last seen |
")
f.write("")
f.write("mac-invent
")
f.write("Deze export van mac-invent laat alle mac adressen zien die op het netwerk zijn geweest (gerouteerd!).
Het vlan en ip adres zijn de laatste waarmee dit mac adres gezien is op datum en tijd in de laatste kolom.
Bijzondere mac adressen die dubbel voorkomen (L3 switches) worden maar een keer getoond.
")
for Effe in MacInvent3:
Fs=datetime.datetime.fromtimestamp(int(Effe[3]))
Ls=datetime.datetime.fromtimestamp(int(Effe[4]))
Fseen=str.format("%04d-%02d-%02d_%02d:%02d" % (Fs.year,Fs.month,Fs.day,Fs.hour,Fs.minute))
Lseen=str.format("%04d-%02d-%02d_%02d:%02d" % (Ls.year,Ls.month,Ls.day,Ls.hour,Ls.minute))
Line=""+Effe[0]+" | "+Effe[1]+" | "+Effe[2]+" | "+Fseen+" | "+Lseen+" |
\n"
f.write(Line)
if Class=="een":
Class="twee"
else:
Class="een"
f.write("")
# Rapport, hoeveel updated, hoeveel nieuwe.
SecsStop=time.time()
print("Timestamp : "+Lseen)
print("Records updated: "+str(Updated))
print("Records added : "+str(Appended))
print("Total records : "+str(TotalRec))
print("total time : %-.2f" % (SecsStop-SecsStart))
print("")