Controller.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import os
  2. import sys
  3. import shutil
  4. from ID2TLib.AttackController import AttackController
  5. from ID2TLib.LabelManager import LabelManager
  6. from ID2TLib.PcapFile import PcapFile
  7. from ID2TLib.Statistics import Statistics
  8. from ID2TLib.AttackContext import AttackContext
  9. class Controller:
  10. def __init__(self, in_pcap_file_path: str, do_extra_tests: bool, out_pcap_file_path):
  11. """
  12. Creates a new Controller, acting as a central coordinator for the whole application.
  13. :param pcap_file_path:
  14. """
  15. # Fields
  16. self.pcap_src_path = in_pcap_file_path.strip()
  17. if out_pcap_file_path:
  18. self.pcap_out_path = out_pcap_file_path.strip()
  19. else:
  20. self.pcap_out_path = None
  21. self.pcap_dest_path = ''
  22. self.written_pcaps = []
  23. self.do_extra_tests = do_extra_tests
  24. # Initialize class instances
  25. print("Input file: %s" % self.pcap_src_path)
  26. self.pcap_file = PcapFile(self.pcap_src_path)
  27. self.label_manager = LabelManager(self.pcap_src_path)
  28. self.statistics = Statistics(self.pcap_file)
  29. self.statistics.do_extra_tests = self.do_extra_tests
  30. self.statisticsDB = self.statistics.get_statistics_database()
  31. self.attack_controller = AttackController(self.pcap_file, self.statistics, self.label_manager)
  32. def load_pcap_statistics(self, flag_write_file: bool, flag_recalculate_stats: bool, flag_print_statistics: bool):
  33. """
  34. Loads the PCAP statistics either from the database, if the statistics were calculated earlier, or calculates
  35. the statistics and creates a new database.
  36. :param flag_write_file: Writes the statistics to a file.
  37. :param flag_recalculate_stats: Forces the recalculation of statistics.
  38. :param flag_print_statistics: Prints the statistics on the terminal.
  39. :return: None
  40. """
  41. self.statistics.load_pcap_statistics(flag_write_file, flag_recalculate_stats, flag_print_statistics)
  42. def process_attacks(self, attacks_config: list):
  43. """
  44. Creates the attack based on the attack name and the attack parameters given in the attacks_config. The
  45. attacks_config is a list of attacks, e.g.
  46. [['PortscanAttack', 'ip.src="192.168.178.2",'dst.port=80'],['PortscanAttack', 'ip.src="10.10.10.2"]].
  47. Merges the individual temporary attack pcaps into one single pcap and merges this single pcap with the
  48. input dataset.
  49. :param attacks_config: A list of attacks with their attack parameters.
  50. """
  51. # context for the attack(s)
  52. context = AttackContext()
  53. # note if new xml file has been created by MembersMgmtCommAttack
  54. created_xml = None
  55. # load attacks sequentially
  56. for attack in attacks_config:
  57. # check if new xml file has been created by MembersMgmtCommAttack
  58. if attack[0] == "MembersMgmtCommAttack":
  59. for param in attack[1:]:
  60. key, value = param.split("=")
  61. if key == "file.csv":
  62. if os.path.isfile(value):
  63. created_xml, _ = os.path.splitext(value)
  64. created_xml += ".xml"
  65. break
  66. temp_attack_pcap = self.attack_controller.process_attack(attack[0], attack[1:], context)
  67. self.written_pcaps.append(temp_attack_pcap)
  68. # merge attack pcaps to get single attack pcap
  69. if len(self.written_pcaps) > 1:
  70. print("\nMerging temporary attack pcaps into single pcap file...", end=" ")
  71. sys.stdout.flush() # force python to print text immediately
  72. for i in range(0, len(self.written_pcaps) - 1):
  73. attacks_pcap = PcapFile(self.written_pcaps[i])
  74. attacks_pcap_path = attacks_pcap.merge_attack(self.written_pcaps[i + 1])
  75. os.remove(self.written_pcaps[i + 1]) # remove merged pcap
  76. print("done.")
  77. else:
  78. attacks_pcap_path = self.written_pcaps[0]
  79. # merge single attack pcap with all attacks into base pcap
  80. print("Merging base pcap with single attack pcap...", end=" ")
  81. sys.stdout.flush() # force python to print text immediately
  82. # cp merged PCAP to output path
  83. self.pcap_dest_path = self.pcap_file.merge_attack(attacks_pcap_path)
  84. if self.pcap_out_path:
  85. if not self.pcap_out_path.endswith(".pcap"):
  86. self.pcap_out_path += ".pcap"
  87. os.rename(self.pcap_dest_path, self.pcap_out_path)
  88. self.pcap_dest_path = self.pcap_out_path
  89. print("done.")
  90. # delete intermediate PCAP files
  91. print('Deleting intermediate attack pcap...', end=" ")
  92. sys.stdout.flush() # force python to print text immediately
  93. os.remove(attacks_pcap_path)
  94. print("done.")
  95. # write label file with attacks
  96. self.label_manager.write_label_file(self.pcap_dest_path)
  97. # if MembersMgmtCommAttack created an xml file, move it into input pcap directory
  98. if created_xml:
  99. pcap_dir = os.path.splitext(self.pcap_dest_path)[0]
  100. if "/" in pcap_dir:
  101. pcap_dir = "/".join(pcap_dir.split("/")[:-1])
  102. xml_name = os.path.splitext(created_xml)[0] + ".xml"
  103. if "/" in xml_name:
  104. xml_name = xml_name.split("/")[-1]
  105. new_xml_path = pcap_dir + "/" + xml_name
  106. os.rename(created_xml, new_xml_path)
  107. # pcap_base contains the name of the pcap-file without the ".pcap" extension
  108. pcap_base = os.path.splitext(self.pcap_dest_path)[0]
  109. for suffix, filename in context.get_allocated_files():
  110. print(filename, pcap_base + suffix)
  111. shutil.move(filename, pcap_base + suffix)
  112. context.reset()
  113. # print status message
  114. if created_xml:
  115. print('\nOutput files created: \n', self.pcap_dest_path, '\n', self.label_manager.label_file_path, '\n', new_xml_path)
  116. else:
  117. print('\nOutput files created: \n', self.pcap_dest_path, '\n', self.label_manager.label_file_path)
  118. def process_db_queries(self, query, print_results=False):
  119. """
  120. Processes a statistics database query. This can be a standard SQL query or a named query.
  121. :param query: The query as a string or multiple queries as a list of strings.
  122. :param print_results: Must be True if the results should be printed to terminal.
  123. :return: The query's result
  124. """
  125. print("Processing database query/queries...")
  126. if isinstance(query, list) or isinstance(query, tuple):
  127. for q in query:
  128. self.statisticsDB.process_db_query(q, print_results)
  129. else:
  130. self.statisticsDB.process_db_query(query, print_results)
  131. def enter_query_mode(self):
  132. """
  133. Enters into the query mode. This is a read-eval-print-loop, where the user can input named queries or SQL
  134. queries and the results are printed.
  135. """
  136. print("Entering into query mode...")
  137. print("Enter statement ending by ';' and press ENTER to send query. Exit by sending an empty query..")
  138. buffer = ""
  139. while True:
  140. line = input("> ")
  141. if line == "":
  142. break
  143. buffer += line
  144. import sqlite3
  145. if sqlite3.complete_statement(buffer):
  146. try:
  147. buffer = buffer.strip()
  148. self.statisticsDB.process_db_query(buffer, True)
  149. except sqlite3.Error as e:
  150. print("An error occurred:", e.args[0])
  151. buffer = ""
  152. def create_statistics_plot(self, params: str):
  153. """
  154. Plots the statistics to a file by using the given customization parameters.
  155. """
  156. if params is not None and params[0] is not None:
  157. params_dict = dict([z.split("=") for z in params])
  158. self.statistics.plot_statistics(format=params_dict['format'])
  159. else:
  160. self.statistics.plot_statistics()