Advertisement
Guest User

Untitled

a guest
Feb 25th, 2018
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.99 KB | None | 0 0
  1. ### Network management tool ###
  2. ### Group 8, Cisco Engineer Incubator 5.0 ###
  3. ### Authors: Anna Luszczkiewicz, Kinga Slowik, Volodymyr Ushnevych ###
  4.  
  5. ### importing necessary modules for creating website ####
  6. from flask import Flask, request, render_template, redirect, url_for, flash
  7. from flask_bootstrap import Bootstrap
  8. import os
  9. from forms import Start
  10. import ipaddress
  11. import datetime
  12. import time
  13. import subprocess
  14. import os.path
  15. import paramiko
  16. import re
  17. import matplotlib.pyplot as plt
  18. import networkx as nx
  19. import sys
  20.  
  21. ########################################
  22. ### Initialization of needed modules ###
  23. ########################################
  24.  
  25. # Web server and extensions, such as SQL database need
  26. # initialization - this is part where it takes place.
  27.  
  28. ### application initialization to start webserver ####
  29. app = Flask(__name__)
  30. app.config.from_object('config')
  31. bootstrap = Bootstrap(app)
  32.  
  33. #############################################
  34. ### Function definitions used in webpages ###
  35. #############################################
  36.  
  37. # To make part with decorators smaller functions are separated
  38. # from web server.
  39.  
  40. ### Function responsible for shutting server down ###
  41. def shutdown_server():
  42. func = request.environ.get('werkzeug.server.shutdown')
  43. if func is None:
  44. raise RuntimeError('Not running with the Werkzeug Server')
  45. func()
  46.  
  47. ### Function that reads info from scan_params.txt ###
  48. def scan_params():
  49. try:
  50. # Try to open file for reading
  51. scan_file = open("scan_params.txt", "r")
  52.  
  53. # Starting with the beginning of the file
  54. scan_file.seek(0)
  55.  
  56. # Reading the line
  57. scan = scan_file.read().splitlines()
  58.  
  59. # CLosing the file
  60. scan_file.close()
  61. except IOError:
  62. return []
  63. scan_info=[]
  64. done_well=False
  65. for data in scan:
  66. scan_info.append(data.split(":",1))
  67. if data.split(":")[0]=="Date of last successfull scan":
  68. done_well=True
  69. return scan_info,done_well
  70.  
  71. ### Function that reads valid ip range from file ###
  72. def ip_range():
  73. try:
  74. # Try to open file for reading
  75. ip_file = open("ip_range.txt","r")
  76.  
  77. # Starting with the beginning of the file
  78. ip_file.seek(0)
  79.  
  80. # Reading the line
  81. ip_list_prev = ip_file.read()
  82.  
  83. # CLosing the file
  84. ip_file.close()
  85. except IOError:
  86. flash("The file 'ip_range.txt' does not exist! Please check and try again!")
  87. return None
  88. ### Reading into list IP's delimited by "," ###
  89. ip_list_prev=ip_list_prev.strip().strip(",").split(",")
  90. ip_list=[]
  91. ### Striping each IP of excess white spaces ###
  92. for i in range(len(ip_list_prev)):
  93. if ip_list_prev[i]==[]: continue
  94. ip_list_prev[i]=ip_list_prev[i].strip()
  95.  
  96. ### Checking if adddressess are valid - if so apppending them to ip_list, else - returning []
  97. if "#" in ip_list_prev[i]:
  98. temp = ip_list_prev[i].split("#")
  99. ip_temp = temp[0]
  100. number = int(temp[1])
  101. try:
  102. ip=ipaddress.ip_address(ip_temp)
  103. ip_list.append(ip)
  104. except ValueError:
  105. flash("Invalid IP address! Check and try again.")
  106. ip_list = []
  107. return ip_list
  108. for i in range(1,number):
  109. ip_list.append(ip+i)
  110. else:
  111. try:
  112. ip_list.append(ipaddress.ip_address(ip_list_prev[i]))
  113. except ValueError:
  114. flash("Invalid IP address! Check and try again.")
  115. return ip_list
  116. flash("The file ip_range.txt has been read.")
  117. return ip_list
  118.  
  119. ### Function that reads passwords and from file and puts them in the list ###
  120. def passwords():
  121. try:
  122. # Try to open file for reading
  123. passwords_file = open("passwords.txt", "r")
  124.  
  125. # Starting with the beginning of the file
  126. passwords_file.seek(0)
  127.  
  128. # Reading the line
  129. password = passwords_file.read()
  130.  
  131. # CLosing the file
  132. passwords_file.close()
  133. except IOError:
  134. flash("The file 'passwords.txt' does not exist! Please check and start the process again!")
  135. return None
  136. flash("The file passwords.txt has been read.")
  137. return password
  138.  
  139. ### Function which is checking which addresses are available to ping ###
  140. def pingy(ip_list):
  141. ip_available = []
  142. for ip in ip_list:
  143. ping_reply = subprocess.call(['ping', '-c', '2', '-w', '2', '-q', '-n', str(ip)])
  144. ### Appending ip to list if device is pingable ###
  145. if ping_reply == 0:
  146. ip_available.append(ip)
  147. #print(ip_available)
  148. return ip_available
  149.  
  150. ### Function which is connecting to devices by ssh and exporting neccessary data to file
  151. def connect(ip_list):
  152. finaloutput = ""
  153. lista = []
  154. for line in ip_list:
  155. with open('passwords.txt', 'r') as myfile:
  156. passwords = myfile.read().replace('\n', " ").split(' ')
  157. flag = 1
  158. counter = 0
  159. while flag:
  160. try:
  161. ssh_para = paramiko.SSHClient()
  162. ssh_para.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  163. counter = counter + 1
  164. ssh_para.connect(str(line), username='admin', password=passwords[counter])
  165. flag = 0
  166. connection = ssh_para.invoke_shell()
  167. #print ("Succesfull connection with: " + line.strip() + ", Password = " + passwords[counter])
  168. del passwords[counter]
  169. except paramiko.AuthenticationException:
  170. print ("Bad password")
  171. except IndexError:
  172. print ("No pass in passwords.txt")
  173. sys.exit()
  174.  
  175. sh_int_br = "sh ip int brief | include (Ethernet|Serial)"
  176. sh_inv = "show inventory | include NAME"
  177. sh_int_ernet = "show interfaces | include Internet"
  178. cisco_commands = '''show version | include (, Version|uptime is|bytes of memory|Hz)&\
  179.  
  180. show interfaces | include bia&\
  181. show processes cpu | include CPU utilization&\
  182. show memory statistics&\
  183. show cdp neighbors detail | include Device ID&\
  184. show ip protocols | include Routing Protocol'''
  185. commands_list = cisco_commands.split("&")
  186. #print commands_list
  187.  
  188. for each_line in commands_list:
  189. connection.send(each_line + "\n")
  190. time.sleep(1)
  191.  
  192. output = connection.recv(65535).decode('utf-8')
  193.  
  194. connection.send(sh_int_br + "\n")
  195. time.sleep(1)
  196. output_int = str(connection.recv(65535).decode('utf-8'))
  197. output_int = str(output_int).split("\n",1)[-1]
  198. output_int = output_int[:output_int.rfind("\n")]
  199. output_int = output_int.replace("YES NVRAM", " ")
  200.  
  201. connection.send(sh_inv + "\n")
  202. time.sleep(1)
  203. output_inv = connection.recv(65535).decode('utf-8')
  204. output_inv = str(output_inv).split("\n", 1)[-1]
  205. output_inv = output_inv[:output_inv.rfind("\n")]
  206. output_inv = str(output_inv)
  207. #print output_inv
  208.  
  209. connection.send(sh_int_ernet + "\n")
  210. time.sleep(1)
  211. output_int_ernet = connection.recv(65535).decode('utf-8')
  212. output_int_ernet = str(output_int_ernet).split("\n", 1)[-1]
  213. output_int_ernet = output_int_ernet[:output_int_ernet.rfind("\n")]
  214. output_int_ernet = str(output_int_ernet).replace("Internet address is ","")
  215. #print output_int_ernet
  216.  
  217.  
  218.  
  219. dev_hostname = re.search(r"(.+) uptime is", output)
  220. hostname = dev_hostname.group(1)
  221.  
  222. dev_mac = re.findall(r"\(bia (.+?)\)", output)
  223. mac = dev_mac[0]
  224.  
  225. dev_model = re.search(r"(.+?) (.+?) (.+) bytes of memory", output)
  226. model = dev_model.group(2)
  227.  
  228. dev_image_name = re.search(r" \((.+)\), Version", output)
  229. image_name = dev_image_name.group(1)
  230.  
  231. dev_os = re.search(r"\), Version (.+)", output)
  232. os = dev_os.group(1)
  233.  
  234. dev_cdp_neighbors = re.findall(r"Device ID: (.+)\r\n", output)
  235. all_cdp_neighbors = " ".join(dev_cdp_neighbors)
  236. all_cdp_neighbors_st = str(all_cdp_neighbors).replace(".teo", " ")
  237.  
  238. finaloutput = finaloutput +"\n\n\n"+ "Name\t" + "MAC address\t" + "Hardware\t" +"IOS"+"\n"+\
  239. hostname + "\t" + mac + "\t" + model + "\t" + image_name + "\n" + "Neighbors:\t" + all_cdp_neighbors_st + "\n"+\
  240. "Interface\t"+" IP address\t"+"Status\t"+"Protocol"+"\n" + output_int + "\n" + "Inventory of device:"+ "\n" + output_inv
  241.  
  242. singlelist = []
  243. testlist = []
  244. wordlist = []
  245. output_int = output_int.split()
  246.  
  247. for line in output_int:
  248. try:
  249. if(ipaddress.ip_address(line)):
  250. wordlist.append(line)
  251. except ValueError:
  252. pass
  253. singlelist.append(hostname)
  254. output_int_ernet = output_int_ernet.strip().split("\n")
  255.  
  256. for line in output_int_ernet:
  257. line = line.replace('\r', '')
  258. line = line.strip()
  259. testlist.append(line)
  260. singlelist.append(wordlist)
  261. singlelist.append(testlist)
  262. lista.append(singlelist)
  263. ssh_para.close()
  264. responde_route = open("final.txt", "w")
  265. responde_route.write(finaloutput)
  266. print (lista)
  267. responde_route.close()
  268. return lista
  269.  
  270. ### Function for reading file output to prepare it to the website format ###
  271. def formatting():
  272. ### Reading file output ###
  273. output = open("final.txt", "r")
  274. out = output.read().splitlines()
  275. output.close()
  276.  
  277. all = []
  278. number = 0
  279. current = []
  280. k=0
  281. ### State machine for appropriate reading of file ###
  282. for line in out:
  283. k=k+1
  284. ### Empty line - separator for routers ###
  285. if line == '':
  286. if current != []:
  287. current.append(modules)
  288. all.append(current)
  289. current = []
  290. number = 0
  291. ### Start of reading - line with field names ###
  292. ### Used for general info ###
  293. elif line.startswith("Name"):
  294. number = 0
  295. prev = line.split(' ')
  296. elif number == 0:
  297. temp = line.split(' ')
  298. general = []
  299. for i in range(len(prev)):
  300. general.append([prev[i], temp[i]])
  301. number = 1
  302. current.append(temp[0])
  303. elif number == 1:
  304. temp = line.split(":")
  305. general.append([temp[0], temp[1].strip()])
  306. current.append(general)
  307. number = 2
  308. interfaces = []
  309. ### Lines with names and status of interfaces ###
  310. elif number == 2:
  311. names = re.split(r'\s+', line.strip())
  312. if line == "Inventory of device:":
  313. current.append(interfaces)
  314. modules = []
  315. modules.append(['Name', 'Description'])
  316. number = 3
  317. elif len(names) == 5 and names[1] == 'IP':
  318. names[1:3] = [' '.join(names[1:3])]
  319. interfaces.append(names[0:4])
  320. elif len(names) == 4:
  321. interfaces.append(names)
  322. else:
  323. names[2:4] = [' '.join(names[2:4])]
  324. interfaces.append(names[0:4])
  325. ### Part responsible for adding modules ###
  326. elif number == 3:
  327. temp = line.split("\", ")
  328. modules.append([temp[0].strip('NAME: ').strip("\""), temp[1].strip('DESCR: ').strip("\"")])
  329. if k==len(out):
  330. current.append(modules)
  331. all.append(current)
  332. return all
  333.  
  334. ### Function for keeping scan parametres ###
  335. def scan_parametres(ok,scan,person):
  336.  
  337. ### Writing to file if it is empty or not existing ###
  338. if scan==[]:
  339. out = open("scan_params.txt","w")
  340. ### Writing data if everything went successful ###
  341. if ok==False:
  342. out.write("Date of last unsuccessfull scan: "+str(datetime.date.today())+"\n")
  343. out.write("Hour of last unsuccessfull scan: "+str(datetime.datetime.now().time())+"\n")
  344. out.write("Person responsible: "+person+"\n")
  345. ### Writing data if scan went unsuccessful ###
  346. else:
  347. out.write("Date of last successfull scan: "+str(datetime.date.today())+"\n")
  348. out.write("Hour of last successfull scan: "+str(datetime.datetime.now().time())+"\n")
  349. out.write("Person responsible: "+person+"\n")
  350. out.close()
  351. ### Writing data to already existing file ###
  352. else:
  353. out = open("scan_params.txt","r")
  354. out_data = out.read().splitlines()
  355. out.close()
  356. success=False
  357. fail=False
  358. ### Reading file ###
  359. for i in range(len(out_data)):
  360. out_data[i]=out_data[i].strip().split(":",1)
  361. out_data[i][0]=out_data[i][0].strip()
  362. out_data[i][1] = out_data[i][1].strip()
  363. ### Checking if there is success or unsuccess saved ###
  364. if "Date of last successfull scan" in out_data[i]:
  365. success=True
  366. if "Date of last unsuccessfull scan" in out_data[i]:
  367. fail=True
  368. ### Writing data if it was successfull opeation ###
  369. if ok==True:
  370. ### If success was previously written ###
  371. if success==True:
  372. if out_data[0][0]=="Date of last successfull scan":
  373. out_data[0][1]=str(datetime.date.today())
  374. out_data[1][1]=str(datetime.datetime.now().time())
  375. out_data[2][1]=person
  376. else:
  377. out_data[3][1]=str(datetime.date.today())
  378. out_data[4][1]=str(datetime.datetime.now().time())
  379. out_data[5][1]=person
  380. ### if success was not previously written ###
  381. else:
  382. out_data.append(["Date of last successfull scan",str(datetime.date.today())])
  383. out_data.append(["Hour of last successfull scan", str(datetime.datetime.now().time())])
  384. out_data.append(["Person responsible",person])
  385. else:
  386. ### if fail was previously written to file ###
  387. if fail==True:
  388. if out_data[0][0]=="Date of last unsuccessfull scan":
  389. out_data[0][1]=str(datetime.date.today())
  390. out_data[1][1]=str(datetime.datetime.now().time())
  391. out_data[2][1]=person
  392. else:
  393. out_data[3][1]=str(datetime.date.today())
  394. out_data[4][1]=str(datetime.datetime.now().time())
  395. out_data[5][1]=person
  396. ### if fail was not previously written to file ###
  397. else:
  398. out_data.append(["Date of last unsuccessfull scan",str(datetime.date.today())])
  399. out_data.append(["Hour of last unsuccessfull scan", str(datetime.datetime.now().time())])
  400. out_data.append(["Person responsible",person])
  401. for i in range(len(out_data)):
  402. out_data[i]=out_data[i][0]+": "+out_data[i][1]+"\n"
  403. out=open("scan_params.txt","w")
  404. out.write(''.join(out_data))
  405. out.close()
  406.  
  407. ### Function for drawing graph ###
  408. def graph(neighbour):
  409. ### Dictionary for keeping data to create graph ###
  410. neighborship_dict = {}
  411.  
  412. ### Calculatiing and adding nodes and edges to network ###
  413. for router in neighbour:
  414. for ip in router[1]:
  415. times = 0
  416. for router_second in neighbour:
  417. if router_second == router:
  418. continue
  419. for ip_net in router_second[2]:
  420. if ipaddress.ip_address(ip) in ipaddress.ip_network(ip_net, strict=False):
  421. times = times + 1
  422. for router_second in neighbour:
  423. if router_second == router:
  424. continue
  425. for ip_net in router_second[2]:
  426. if times == 0:
  427. break
  428. if ipaddress.ip_address(ip) in ipaddress.ip_network(ip_net, strict=False) and times == 1:
  429. neighborship_dict[(router_second[0], router[0])] = ip
  430. break
  431. if ipaddress.ip_address(ip) in ipaddress.ip_network(ip_net, strict=False) and times > 1:
  432. neighborship_dict[str(ipaddress.ip_network(ip_net, strict=False)), router[0]] = ip
  433.  
  434. ### Creating graph ###
  435. G = nx.Graph()
  436.  
  437. ### Drawing graph and saving it to file ###
  438. G.add_edges_from(neighborship_dict.keys())
  439. pos = nx.spring_layout(G, k=0.1, iterations=70)
  440. nx.draw_networkx_labels(G, pos, font_size=9, font_family="sans-serif", font_weight="bold")
  441. nx.draw_networkx_edges(G, pos, width=4, alpha=0.4, edge_color='black')
  442. nx.draw_networkx_edge_labels(G, pos, neighborship_dict, label_pos=0.3, font_size=6)
  443. nx.draw(G, pos, node_size=800, with_labels=False, node_color='b')
  444. plt.savefig('static/topology.png')
  445.  
  446. ############################
  447. ### Routes in web server ###
  448. ############################
  449.  
  450. # In this part there are routes for web server - data in decorators
  451. # e.g. @app.route("/shutdown") show the end of page we should write
  452. # to have access to this part of code, e.g. 127.0.0.1:5000/shutdown
  453. # in the mentioned case.
  454.  
  455. ### main route - displaying necessary information ###
  456. @app.route("/", methods=["GET","POST"])
  457. def main():
  458.  
  459. scan,done_ok = scan_params()
  460.  
  461. if done_ok==True:
  462. empty=False
  463. data=formatting()
  464. else:
  465. empty=True
  466. data=[]
  467.  
  468. path = os.path.dirname(os.path.realpath(__file__))+"\ip_range.txt\n"
  469. path_pass = os.path.dirname(os.path.realpath(__file__)) + "\passwords.txt\n"
  470. form=Start()
  471.  
  472. if form.validate_on_submit():
  473. ip_list=ip_range()
  474. if len(ip_list)==0:
  475. scan_parametres(False,scan,form.name.data)
  476. return redirect(url_for("main"))
  477. password_list=passwords()
  478. ip_available = pingy(ip_list)
  479. print(ip_available)
  480. if len(ip_available)==0:
  481. scan_parametres(False, scan, form.name.data)
  482. flash("No ability to ping any device with given IP adress. Check IP addresses in file and try again. ")
  483. else:
  484. scan_parametres(True, scan, form.name.data)
  485. flash("Ability to connect with devices in the network. Trying to establish ssh session in order to gather information. ")
  486. graph(connect(ip_available))
  487. return redirect(url_for("main"))
  488.  
  489. if scan==[]:
  490. scan_data=False
  491. else:
  492. scan_data=True
  493. return render_template("index.html",empty=empty, form=form, path=path, path_pass=path_pass,scan_params=scan, scan_data=scan_data,id="R1", data=data)
  494.  
  495. ### shutdown route - closing web server ###
  496. @app.route("/shutdown")
  497. def shutdown():
  498. shutdown_server()
  499. return render_template("shutting.html")
  500.  
  501. ### topology route - displays topology picture ###
  502. @app.route("/topology")
  503. def topology():
  504. no_file=True
  505. if os.path.exists("topology.png")==True:
  506. no_file=False
  507. return render_template("topology.html",no_file=no_file)
  508.  
  509. ### help route - information about program and short description ###
  510. @app.route("/help")
  511. def help():
  512. return render_template("help.html")
  513.  
  514. ### run application ###
  515. # This application is placed in loopback 127.0.0.1 at the port 5000.
  516. # This can be changed if needed.
  517. if __name__=='__main__':
  518. app.run(debug=True)
  519. #######################
  520. ### Sources of help ###
  521. #######################
  522. '''
  523. flask.pocoo.org/snippets/67/
  524. https://docs.python.org/3/library/ipaddress.html
  525. Book: M. Ginberg Flask Web Development
  526. https://stackoverflow.com/questions/6256043/css-position-loading-indicator-in-the-center-of-the-screen
  527. https://stackoverflow.com/questions/17859993/basic-css-how-to-overlay-a-div-with-semi-transparent-div-on-top
  528. '''
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement