#79 Statistics summary

Merged
carlos.garcia merged 6 commits from stefan.schmidt/stats_summary into SPIN/master 6 years ago
5 changed files with 101 additions and 16 deletions
  1. 2 1
      code/CLI.py
  2. 14 2
      code/Core/Controller.py
  3. 72 6
      code/Core/Statistics.py
  4. 3 3
      code/Test/ID2TAttackTest.py
  5. 10 4
      code/Test/test_Queries.py

+ 2 - 1
code/CLI.py

@@ -69,6 +69,7 @@ class CLI(object):
         parser.add_argument('-S', '--randomSeed', action='append', help='sets random seed for testing or benchmarking',
                             nargs='+', default=[])
         parser.add_argument('-T', '--time', help='measures packet generation time', action='store_true', default=False)
+        parser.add_argument('-V', '--non-verbose', help='reduces terminal clutter', action='store_true', default=False)
 
         # Attack arguments
         parser.add_argument('-a', '--attack', metavar="ATTACK", action='append',
@@ -139,7 +140,7 @@ class CLI(object):
         Evaluates given queries.
         """
         # Create Core Controller
-        controller = Controller(self.args.input, self.args.extraTests)
+        controller = Controller(self.args.input, self.args.extraTests, self.args.non_verbose)
 
         # Load PCAP statistics
         controller.load_pcap_statistics(self.args.export, self.args.recalculate, self.args.statistics)

+ 14 - 2
code/Core/Controller.py

@@ -10,7 +10,7 @@ import ID2TLib.PcapFile as PcapFile
 
 
 class Controller:
-    def __init__(self, pcap_file_path: str, do_extra_tests: bool):
+    def __init__(self, pcap_file_path: str, do_extra_tests: bool, non_verbose: bool):
         """
         Creates a new Controller, acting as a central coordinator for the whole application.
 
@@ -21,8 +21,10 @@ class Controller:
         self.pcap_dest_path = ''
         self.written_pcaps = []
         self.do_extra_tests = do_extra_tests
+        self.non_verbose = non_verbose
         self.seed = None
         self.durations = []
+        self.added_packets = 0
 
         # Initialize class instances
         print("Input file: %s" % self.pcap_src_path)
@@ -41,9 +43,11 @@ class Controller:
         :param flag_write_file: Writes the statistics to a file.
         :param flag_recalculate_stats: Forces the recalculation of statistics.
         :param flag_print_statistics: Prints the statistics on the terminal.
+        :param flag_non_verbose: Reduces terminal clutter.
         :return: None
         """
-        self.statistics.load_pcap_statistics(flag_write_file, flag_recalculate_stats, flag_print_statistics)
+        self.statistics.load_pcap_statistics(flag_write_file, flag_recalculate_stats, flag_print_statistics,
+                                             self.non_verbose)
 
     def process_attacks(self, attacks_config: list, seeds=None, time=False):
         """
@@ -57,6 +61,7 @@ class Controller:
         :param seeds: A list of random seeds for the given attacks.
         :param time: Measure time for packet generation.
         """
+
         # load attacks sequentially
         i = 0
         for attack in attacks_config:
@@ -64,6 +69,9 @@ class Controller:
                 self.attack_controller.set_seed(seed=seeds[i][0])
             temp_attack_pcap, duration = self.attack_controller.process_attack(attack[0], attack[1:], time)
             self.durations.append(duration)
+            self.added_packets += self.attack_controller.total_packets
+            if not self.non_verbose:
+                self.statistics.stats_summary_post_attack(self.added_packets)
             self.written_pcaps.append(temp_attack_pcap)
             i += 1
 
@@ -109,6 +117,10 @@ class Controller:
         # print status message
         print('\nOutput files created: \n', self.pcap_dest_path, '\n', self.label_manager.label_file_path)
 
+        # print summary statistics
+        if not self.non_verbose:
+            self.statistics.stats_summary_post_attack(self.added_packets)
+
     def process_db_queries(self, query, print_results=False):
         """
         Processes a statistics database query. This can be a standard SQL query or a named query.

+ 72 - 6
code/Core/Statistics.py

@@ -39,7 +39,8 @@ class Statistics:
         # Class instances
         self.stats_db = statsDB.StatsDatabase(self.path_db)
 
-    def load_pcap_statistics(self, flag_write_file: bool, flag_recalculate_stats: bool, flag_print_statistics: bool):
+    def load_pcap_statistics(self, flag_write_file: bool, flag_recalculate_stats: bool, flag_print_statistics: bool,
+                             flag_non_verbose: bool):
         """
         Loads the PCAP statistics for the file specified by pcap_filepath. If the database is not existing yet, the
         statistics are calculated by the PCAP file processor and saved into the newly created database. Otherwise the
@@ -49,6 +50,7 @@ class Statistics:
         or not (False)
         :param flag_recalculate_stats: Indicates whether eventually existing statistics should be recalculated
         :param flag_print_statistics: Indicates whether the gathered basic statistics should be printed to the terminal
+        :param flag_non_verbose: Indicates whether certain prints should be made or not, to reduce terminal clutter
         """
         # Load pcap and get loading time
         time_start = time.clock()
@@ -63,6 +65,10 @@ class Statistics:
             self.pcap_proc.collect_statistics()
             self.pcap_proc.write_to_database(self.path_db)
             outstring_datasource = "by PCAP file processor."
+
+            # only print summary of new db if -s flag not set
+            if not flag_print_statistics and not flag_non_verbose:
+                self.stats_summary_new_db()
         else:
             outstring_datasource = "from statistics database."
 
@@ -86,11 +92,22 @@ class Statistics:
 
         :return: a list of tuples, each consisting of (description, value, unit), where unit is optional.
         """
-        return [("Pcap file", self.pcap_filepath),
-                ("Packets", self.get_packet_count(), "packets"),
-                ("Capture length", self.get_capture_duration(), "seconds"),
-                ("Capture start", self.get_pcap_timestamp_start()),
-                ("Capture end", self.get_pcap_timestamp_end())]
+
+        pdu_count = self.process_db_query("SELECT SUM(pktCount) FROM unrecognized_pdus")
+        pdu_share = pdu_count / self.get_packet_count() * 100
+        last_pdu_timestamp = self.process_db_query(
+            "SELECT MAX(timestampLastOccurrence) FROM unrecognized_pdus")
+
+        return [("Pcap file path", self.pcap_filepath),
+                ("Total packet count", self.get_packet_count(), "packets"),
+                ("Recognized packets", self.get_packet_count() - pdu_count, "packets"),
+                ("Unrecognized packets", pdu_count, "PDUs"),
+                ("% Recognized packets", 100 - pdu_share, "%"),
+                ("% Unrecognized packets", pdu_share, "%"),
+                ("Last unknown PDU", last_pdu_timestamp),
+                ("Capture duration", self.get_capture_duration(), "seconds"),
+                ("Capture start", "\t" + str(self.get_pcap_timestamp_start())),
+                ("Capture end", "\t" + str(self.get_pcap_timestamp_end()))]
 
     def get_general_file_statistics(self):
         """
@@ -1011,3 +1028,52 @@ class Statistics:
         # ip_dst_out_path = plot_ip_dst('.' + format)
 
         print("Saved plots in the input PCAP directory.")
+
+    def stats_summary_post_attack(self, added_packets):
+        """
+        Prints a summary of relevant statistics after an attack is injected
+
+        :param added_packets: sum of packets added by attacks, gets updated if more than one attack
+        :return: None
+        """
+
+        total_packet_count = self.get_packet_count() + added_packets
+        added_packets_share = added_packets / total_packet_count * 100
+        timespan = self.get_capture_duration()
+
+        summary = [("Total packet count", total_packet_count, "packets"),
+                   ("Added packet count", added_packets, "packets"),
+                   ("Share of added packets", added_packets_share, "%"),
+                   ("Capture duration", timespan, "seconds")]
+
+        print("\nPOST INJECTION STATISTICS SUMMARY  --------------------------")
+        self.write_list(summary, print, "")
+        print("------------------------------------------------------------")
+
+    def stats_summary_new_db(self):
+        """
+        Prints a summary of relevant statistics when a new db is created
+
+        :return: None
+        """
+
+        self.file_info = self.stats_db.get_file_info()
+        print("\nNew database has been generated, printing statistics summary... ")
+        total_packet_count = self.get_packet_count()
+        pdu_count = self.process_db_query("SELECT SUM(pktCount) FROM unrecognized_pdus")
+        pdu_share = pdu_count / total_packet_count * 100
+        last_pdu_timestamp = self.process_db_query(
+            "SELECT MAX(timestampLastOccurrence) FROM unrecognized_pdus")
+        timespan = self.get_capture_duration()
+
+        summary = [("Total packet count", total_packet_count, "packets"),
+                   ("Recognized packets", total_packet_count - pdu_count, "packets"),
+                   ("Unrecognized packets", pdu_count, "PDUs"),
+                   ("% Recognized packets", 100 - pdu_share, "%"),
+                   ("% Unrecognized packets", pdu_share, "%"),
+                   ("Last unknown PDU", last_pdu_timestamp),
+                   ("Capture duration", timespan, "seconds")]
+
+        print("\nPCAP FILE STATISTICS SUMMARY  ------------------------------")
+        self.write_list(summary, print, "")
+        print("------------------------------------------------------------")

+ 3 - 3
code/Test/ID2TAttackTest.py

@@ -31,7 +31,7 @@ class ID2TAttackTest(unittest.TestCase):
         :param time: Measure time for packet generation.
         """
 
-        controller = Ctrl.Controller(pcap_file_path=pcap, do_extra_tests=False)
+        controller = Ctrl.Controller(pcap_file_path=pcap, do_extra_tests=False, non_verbose=True)
         controller.load_pcap_statistics(flag_write_file, flag_recalculate_stats, flag_print_statistics)
 
         controller.process_attacks(attack_args, [[seed]], time)
@@ -69,7 +69,7 @@ class ID2TAttackTest(unittest.TestCase):
         :param test_sub_dir: create sub-directory for each test-function/case if True
         """
 
-        controller = Ctrl.Controller(pcap_file_path=pcap, do_extra_tests=False)
+        controller = Ctrl.Controller(pcap_file_path=pcap, do_extra_tests=False, non_verbose=True)
         controller.load_pcap_statistics(flag_write_file, flag_recalculate_stats, flag_print_statistics)
 
         if seed is None:
@@ -110,7 +110,7 @@ class ID2TAttackTest(unittest.TestCase):
         :param test_sub_dir: create sub-directory for each test-function/case if True
         """
 
-        controller = Ctrl.Controller(pcap_file_path=pcap, do_extra_tests=False)
+        controller = Ctrl.Controller(pcap_file_path=pcap, do_extra_tests=False, non_verbose=True)
         controller.load_pcap_statistics(flag_write_file, flag_recalculate_stats, flag_print_statistics)
         controller.process_attacks(attack_args, [[seed]])
 

+ 10 - 4
code/Test/test_Queries.py

@@ -6,12 +6,18 @@ import ID2TLib.TestLibrary as Test
 
 # TODO: improve coverage
 
-controller = Ctrl.Controller(pcap_file_path=Test.test_pcap, do_extra_tests=False)
+controller = Ctrl.Controller(pcap_file_path=Test.test_pcap, do_extra_tests=False, non_verbose=True)
 controller.load_pcap_statistics(flag_write_file=False, flag_recalculate_stats=True, flag_print_statistics=False)
 
-file_information = [('Pcap file', Test.test_pcap),
-                    ('Packets', 1998, 'packets'), ('Capture length', '25.4294414520264', 'seconds'),
-                    ('Capture start', '1970-01-01 01:01:45.647675'), ('Capture end', '1970-01-01 01:08:10.102034')]
+file_information = [('Pcap file path', Test.test_pcap),
+                    ('Total packet count', 1998, 'packets'),
+                    ("Recognized packets", 1988, "packets"),
+                    ("Unrecognized packets", 10, "PDUs"), ("% Recognized packets", 99.49949949949949, "%"),
+                    ("% Unrecognized packets", 0.5005005005005005, "%"),
+                    ("Last unknown PDU", '1970-01-01 01:07:39.604899'),
+                    ('Capture duration', '25.4294414520264', 'seconds'),
+                    ('Capture start', '\t1970-01-01 01:01:45.647675'),
+                    ('Capture end', '\t1970-01-01 01:08:10.102034')]
 
 file_statistics = [('Avg. packet rate', 78.57034301757812, 'packets/sec'), ('Avg. packet size', 0.0, 'kbytes'),
                    ('Avg. packets sent', 90.0, 'packets'), ('Avg. bandwidth in', 9.5290, 'kbit/s'),