47 Комити dea6ca2340 ... abb0c8af3f

Аутор SHA1 Порука Датум
  Roey Regev abb0c8af3f small enhancements пре 6 година
  Roey Regev ddb51b8a11 additional TODOs for missing documentation пре 6 година
  Roey Regev 2d75b83a49 added TODOs to function where documentation is missing and corrected some misspelling пре 6 година
  Roey Regev ed87d4723e Added documentation for the methods generate_attack_pcap and generate_attack_packets of all attacks пре 6 година
  Carlos Garcia 0626dff544 Merge branch 'temporal_efficiency_fix' of stefan.schmidt/ID2T-toolkit into master пре 6 година
  Jens Keim 84255cbc90 add MS17 efficiency test пре 6 година
  Jens Keim 92f398a6bd replace named queries in Portscan пре 6 година
  Jens Keim 6c4220c07d replace named queries in SQLiAttack пре 6 година
  Jens Keim aa3ca6a1cb replace named queries in SMBLoris пре 6 година
  Jens Keim dc13f7f992 replace named queries in M17 Scan пре 6 година
  Jens Keim f40847cd3f replace named queries in FTP Exploit пре 6 година
  Jens Keim 503e7a1100 replace named queries in EternalBlue пре 6 година
  Jens Keim 4a1bd34777 replace named queries in DDoS пре 6 година
  Jens Keim e89957dd8c replace named queries in Joomla пре 6 година
  Jens Keim d952413ed2 add named query mothods to statistics пре 6 година
  Stefan Schmidt 6c42bdd1db Accelerated get_ip_address_from_mac and get_mac_address by replacing named queries with SQL пре 6 година
  Jens Keim cb051ce5c1 update temp efficiency tests to inject 1.000 pkts пре 6 година
  Carlos Garcia ee04907762 Merge branch 'label_improvements' of stefan.schmidt/ID2T-toolkit into master пре 6 година
  Stefan Schmidt 89fb8934ae Added file information for input and output pcap to label file пре 6 година
  Stefan Schmidt a4f95d6907 Implemented saving and loading of seeds in label files пре 6 година
  Stefan Schmidt 06802ea711 Added get_seed function to AttackController пре 6 година
  Stefan Schmidt a00555a540 Store a "user_specified"-attribute in the label file for each parameter пре 6 година
  Stefan Schmidt 4e01d73d4e Store and load parameters in label files, simplified tag names пре 6 година
  Stefan Schmidt e237e6b6dc Refactored add_param_value to not always require a statistics database пре 6 година
  Stefan Schmidt 922299db21 Fixed boolean returned as integer by adding an additional cast пре 6 година
  Stefan Schmidt 5b15235a28 Changed root-tag of label file to lowercase пре 6 година
  Carlos Garcia 22e1d7219f Merge branch 'ddos_test_fix' of stefan.schmidt/ID2T-toolkit into master пре 6 година
  Stefan Schmidt 16ce9eba2e Fixed DDoS unittest hashes пре 6 година
  Carlos Garcia 51235cc2c4 Merge branch 'seed_int' of stefan.schmidt/ID2T-toolkit into master пре 6 година
  Stefan Schmidt d806904e53 Fixed type of rng_seed in the Controller class пре 6 година
  Carlos Garcia ed15b76fee Merge branch 'rng_seed_refactor' of stefan.schmidt/ID2T-toolkit into master пре 6 година
  Jens Keim 24887d1349 adjust rng seed пре 6 година
  Carlos Garcia 5d87f9b4c3 Merge branch 'efficiency_script_fix' of stefan.schmidt/ID2T-toolkit into master пре 6 година
  Carlos Garcia 1ca555363d Merge branch 'stats_summary' of stefan.schmidt/ID2T-toolkit into master пре 6 година
  Carlos Garcia 1d8e4f47a4 Merge branch 'stats_progresss_indication' of stefan.schmidt/ID2T-toolkit into master пре 6 година
  Stefan Schmidt 42e3688c5c Indicate progress every second when generating statistics database пре 6 година
  Jens Keim d52c6637dd fix potential compatibility issues пре 6 година
  Roey Regev dea6ca2340 small enhancements пре 6 година
  Roey Regev c1960f88d1 additional TODOs for missing documentation пре 6 година
  Roey Regev b87a83f83a added TODOs to function where documentation is missing and corrected some misspelling пре 6 година
  Roey Regev 4f61eba9cb Added documentation for the methods generate_attack_pcap and generate_attack_packets of all attacks пре 6 година
  Jonathan Speth 148dc54e40 added non-verbose cli argument, adjusted tests пре 6 година
  Jonathan Speth 2cf964e5fa added pdu stats to -s flag, slight beautifications пре 6 година
  Jonathan Speth d07672d77c split summary into post_injection and new_db, moved them to Statistics.py, added support for multiple attacks пре 6 година
  Jonathan Speth 355ebdd2fc moved summary back to after injection, added some stats, rephrased descriptions пре 6 година
  Jonathan Speth 55601c5ef1 moved summary to the before the injection, rephrased pdu to unknown pdu пре 6 година
  Jonathan Speth 601da89f5c added stats summary after injecting an attack пре 6 година

+ 4 - 4
build.sh

@@ -62,9 +62,9 @@ testpath="discover -s Test/"
 if [ -e "Test/test_\$1.py" ]; then
     testpath="Test/test_\$1.py"
 fi
-PYTHONWARNINGS="ignore" coverage run --source=. -m unittest \$testpath >/dev/null
-coverage html
-coverage report -m
+PYTHONWARNINGS="ignore" coverage3 run --source=. -m unittest \$testpath >/dev/null
+coverage3 html
+coverage3 report -m
 EOF
 
 # Create the test script
@@ -79,7 +79,7 @@ SCRIPT_PATH=\${ID2T_DIR%/*}
 cd \$SCRIPT_PATH/code
 # Execute tests
 set -e
-python -m unittest Test/efficiency_testing.py
+python3 -m unittest Test/efficiency_testing.py
 EOF
 
 chmod +x ./code/CLI.py

+ 30 - 16
code/Attack/BaseAttack.py

@@ -9,6 +9,7 @@ import socket
 import sys
 import tempfile
 import time
+import collections
 
 # TODO: double check this import
 # does it complain because libpcapreader is not a .py?
@@ -27,6 +28,8 @@ class BaseAttack(metaclass=abc.ABCMeta):
     Abstract base class for all attack classes. Provides basic functionalities, like parameter validation.
     """
 
+    ValuePair = collections.namedtuple('ValuePair', ['value', 'user_specified'])
+
     def __init__(self, name, description, attack_type):
         """
         To be called within the individual attack class to initialize the required parameters.
@@ -250,7 +253,7 @@ class BaseAttack(metaclass=abc.ABCMeta):
         try:
             import distutils.core
             import distutils.util
-            value = distutils.util.strtobool(value.lower())
+            value = bool(distutils.util.strtobool(value.lower()))
             is_bool = True
         except ValueError:
             is_bool = False
@@ -311,19 +314,16 @@ class BaseAttack(metaclass=abc.ABCMeta):
         """
         return self.finish_time - self.start_time
 
-    def add_param_value(self, param, value):
+    def add_param_value(self, param, value, user_specified: bool = True):
         """
         Adds the pair param : value to the dictionary of attack parameters. Prints and error message and skips the
         parameter if the validation fails.
 
         :param param: Name of the parameter that we wish to modify.
         :param value: The value we wish to assign to the specified parameter.
+        :param user_specified: Whether the value was specified by the user (or left default)
         :return: None.
         """
-        # This function call is valid only if there is a statistics object available.
-        if self.statistics is None:
-            print('Error: Attack parameter added without setting a statistics object first.')
-            exit(1)
 
         # by default no param is valid
         is_valid = False
@@ -344,14 +344,6 @@ class BaseAttack(metaclass=abc.ABCMeta):
         if param_type is None:
             print('Parameter ' + str(param_name) + ' not available for chosen attack. Skipping parameter.')
 
-        # If value is query -> get value from database
-        elif self.statistics.is_query(value):
-            value = self.statistics.process_db_query(value, False)
-            if value is not None and value is not "":
-                is_valid = True
-            else:
-                print('Error in given parameter value: ' + str(value) + '. Data could not be retrieved.')
-
         # Validate parameter depending on parameter's type
         elif param_type == atkParam.ParameterTypes.TYPE_IP_ADDRESS:
             is_valid, value = self._is_ip_address(value)
@@ -381,6 +373,11 @@ class BaseAttack(metaclass=abc.ABCMeta):
         elif param_type == atkParam.ParameterTypes.TYPE_BOOLEAN:
             is_valid, value = self._is_boolean(value)
         elif param_type == atkParam.ParameterTypes.TYPE_PACKET_POSITION:
+            # This function call is valid only if there is a statistics object available.
+            if self.statistics is None:
+                print('Error: Statistics-dependent attack parameter added without setting a statistics object first.')
+                exit(1)
+
             ts = pr.pcap_processor(self.statistics.pcap_filepath, "False").get_timestamp_mu_sec(int(value))
             if 0 <= int(value) <= self.statistics.get_packet_count() and ts >= 0:
                 is_valid = True
@@ -391,7 +388,7 @@ class BaseAttack(metaclass=abc.ABCMeta):
 
         # add value iff validation was successful
         if is_valid:
-            self.params[param_name] = value
+            self.params[param_name] = self.ValuePair(value, user_specified)
         else:
             print("ERROR: Parameter " + str(param) + " or parameter value " + str(value) +
                   " not valid. Skipping parameter.")
@@ -403,7 +400,24 @@ class BaseAttack(metaclass=abc.ABCMeta):
         :param param: The parameter whose value is wanted.
         :return: The parameter's value.
         """
-        return self.params.get(param)
+        parameter = self.params.get(param)
+        if parameter is not None:
+            return parameter.value
+        else:
+            return None
+
+    def get_param_user_specified(self, param: atkParam.Parameter) -> bool:
+        """
+        Returns whether the parameter value was specified by the user for a given parameter.
+
+        :param param: The parameter whose user-specified flag is wanted.
+        :return: The parameter's user-specified flag.
+        """
+        parameter = self.params.get(param)
+        if parameter is not None:
+            return parameter.user_specified
+        else:
+            return False
 
     def check_parameters(self):
         """

+ 4 - 4
code/Attack/DDoSAttack.py

@@ -55,7 +55,7 @@ class DDoSAttack(BaseAttack.BaseAttack):
         # attacker configuration
         num_attackers = rnd.randint(1, 16)
         # The most used IP class in background traffic
-        most_used_ip_class = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ipClass)"))
+        most_used_ip_class = Util.handle_most_used_outputs(self.statistics.get_most_used_ip_class())
 
         self.add_param_value(atkParam.Parameter.IP_SOURCE,
                              self.generate_random_ipv4_address(most_used_ip_class, num_attackers))
@@ -85,7 +85,7 @@ class DDoSAttack(BaseAttack.BaseAttack):
         if (num_attackers is not None) and (num_attackers is not 0):
             # user supplied atkParam.Parameter.NUMBER_ATTACKERS
             # The most used IP class in background traffic
-            most_used_ip_class = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ipClass)"))
+            most_used_ip_class = Util.handle_most_used_outputs(self.statistics.get_most_used_ip_class())
             # Create random attackers based on user input atkParam.Parameter.NUMBER_ATTACKERS
             ip_source_list = self.generate_random_ipv4_address(most_used_ip_class, num_attackers)
             mac_source_list = self.generate_random_mac_address(num_attackers)
@@ -167,14 +167,14 @@ class DDoSAttack(BaseAttack.BaseAttack):
             destination_win_prob_dict = lea.Lea.fromValFreqsDict(destination_win_dist)
             destination_win_value = destination_win_prob_dict.random()
         else:
-            destination_win_value = self.statistics.process_db_query("most_used(winSize)")
+            destination_win_value = self.statistics.get_most_used_win_size()
 
         destination_win_value = Util.handle_most_used_outputs(destination_win_value)
 
         # MSS that was used by IP destination in background traffic
         mss_dst = self.statistics.get_most_used_mss(ip_destination)
         if mss_dst is None:
-            mss_dst = self.statistics.process_db_query("most_used(mssValue)")
+            mss_dst = self.statistics.get_most_used_mss_value()
 
         mss_dst = Util.handle_most_used_outputs(mss_dst)
 

+ 3 - 3
code/Attack/EternalBlueExploit.py

@@ -108,7 +108,7 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
             source_ttl_prob_dict = lea.Lea.fromValFreqsDict(source_ttl_dist)
             source_ttl_value = source_ttl_prob_dict.random()
         else:
-            source_ttl_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ttlValue)"))
+            source_ttl_value = Util.handle_most_used_outputs(self.statistics.get_most_used_ttl_value())
 
         destination_ttl_dist = self.statistics.get_ttl_distribution(ip_destination)
         if len(destination_ttl_dist) > 0:
@@ -116,7 +116,7 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
             destination_ttl_value = destination_ttl_prob_dict.random()
         else:
             destination_ttl_value = Util.handle_most_used_outputs(
-                self.statistics.process_db_query("most_used(ttlValue)"))
+                self.statistics.get_most_used_ttl_value())
 
         # Set Window Size based on Window Size distribution of IP address
         source_win_dist = self.statistics.get_win_distribution(ip_source)
@@ -134,7 +134,7 @@ class EternalBlueExploit(BaseAttack.BaseAttack):
             destination_win_prob_dict = lea.Lea.fromValFreqsDict(destination_win_dist)
 
         # Set MSS (Maximum Segment Size) based on MSS distribution of IP address
-        mss_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(mssValue)"))
+        mss_value = Util.handle_most_used_outputs(self.statistics.get_most_used_mss_value())
         if not mss_value:
             mss_value = 1465
 

+ 2 - 2
code/Attack/FTPWinaXeExploit.py

@@ -50,7 +50,7 @@ class FTPWinaXeExploit(BaseAttack.BaseAttack):
         most_used_ip_address = self.statistics.get_most_used_ip_address()
 
         # The most used IP class in background traffic
-        most_used_ip_class = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ipClass)"))
+        most_used_ip_class = Util.handle_most_used_outputs(self.statistics.get_most_used_ip_class())
         attacker_ip = self.generate_random_ipv4_address(most_used_ip_class)
         self.add_param_value(atkParam.Parameter.IP_DESTINATION, attacker_ip)
         self.add_param_value(atkParam.Parameter.MAC_DESTINATION, self.generate_random_mac_address())
@@ -100,7 +100,7 @@ class FTPWinaXeExploit(BaseAttack.BaseAttack):
         # Create random victim if specified
         if self.get_param_value(atkParam.Parameter.IP_SOURCE_RANDOMIZE):
             # The most used IP class in background traffic
-            most_used_ip_class = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ipClass)"))
+            most_used_ip_class = Util.handle_most_used_outputs(self.statistics.get_most_used_ip_class())
             ip_victim = self.generate_random_ipv4_address(most_used_ip_class, 1)
             mac_victim = self.generate_random_mac_address()
 

+ 2 - 2
code/Attack/JoomlaRegPrivExploit.py

@@ -110,7 +110,7 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
             source_ttl_prob_dict = lea.Lea.fromValFreqsDict(source_ttl_dist)
             source_ttl_value = source_ttl_prob_dict.random()
         else:
-            source_ttl_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ttlValue)"))
+            source_ttl_value = Util.handle_most_used_outputs(self.statistics.get_most_used_ttl_value())
 
         destination_ttl_dist = self.statistics.get_ttl_distribution(ip_destination)
         if len(destination_ttl_dist) > 0:
@@ -118,7 +118,7 @@ class JoomlaRegPrivExploit(BaseAttack.BaseAttack):
             destination_ttl_value = destination_ttl_prob_dict.random()
         else:
             destination_ttl_value = Util.handle_most_used_outputs(
-                self.statistics.process_db_query("most_used(ttlValue)"))
+                self.statistics.get_most_used_ttl_value())
 
         # Inject Joomla_registration_privesc
         # Read joomla_registration_privesc pcap file

+ 3 - 3
code/Attack/MS17ScanAttack.py

@@ -106,7 +106,7 @@ class MS17ScanAttack(BaseAttack.BaseAttack):
             source_ttl_prob_dict = lea.Lea.fromValFreqsDict(source_ttl_dist)
             source_ttl_value = source_ttl_prob_dict.random()
         else:
-            source_ttl_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ttlValue)"))
+            source_ttl_value = Util.handle_most_used_outputs(self.statistics.get_most_used_ttl_value())
 
         destination_ttl_dist = self.statistics.get_ttl_distribution(ip_destination)
         if len(destination_ttl_dist) > 0:
@@ -114,7 +114,7 @@ class MS17ScanAttack(BaseAttack.BaseAttack):
             destination_ttl_value = destination_ttl_prob_dict.random()
         else:
             destination_ttl_value = Util.handle_most_used_outputs(
-                self.statistics.process_db_query("most_used(ttlValue)"))
+                self.statistics.get_most_used_ttl_value())
 
         # Set Window Size based on Window Size distribution of IP address
         source_win_dist = self.statistics.get_win_distribution(ip_source)
@@ -132,7 +132,7 @@ class MS17ScanAttack(BaseAttack.BaseAttack):
             destination_win_prob_dict = lea.Lea.fromValFreqsDict(destination_win_dist)
 
         # Set MSS (Maximum Segment Size) based on MSS distribution of IP address
-        mss_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(mssValue)"))
+        mss_value = Util.handle_most_used_outputs(self.statistics.get_most_used_mss_value())
         if not mss_value:
             mss_value = 1465
 

+ 6 - 9
code/Attack/PortscanAttack.py

@@ -142,14 +142,13 @@ class PortscanAttack(BaseAttack.BaseAttack):
             source_mss_prob_dict = lea.Lea.fromValFreqsDict(source_mss_dist)
             source_mss_value = source_mss_prob_dict.random()
         else:
-            source_mss_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(mssValue)"))
+            source_mss_value = Util.handle_most_used_outputs(self.statistics.get_most_used_mss_value())
         destination_mss_dist = self.statistics.get_mss_distribution(ip_destination)
         if len(destination_mss_dist) > 0:
             destination_mss_prob_dict = lea.Lea.fromValFreqsDict(destination_mss_dist)
             destination_mss_value = destination_mss_prob_dict.random()
         else:
-            destination_mss_value = Util.handle_most_used_outputs(
-                self.statistics.process_db_query("most_used(mssValue)"))
+            destination_mss_value = Util.handle_most_used_outputs(self.statistics.get_most_used_mss_value())
 
         # Set TTL based on TTL distribution of IP address
         source_ttl_dist = self.statistics.get_ttl_distribution(ip_source)
@@ -157,14 +156,13 @@ class PortscanAttack(BaseAttack.BaseAttack):
             source_ttl_prob_dict = lea.Lea.fromValFreqsDict(source_ttl_dist)
             source_ttl_value = source_ttl_prob_dict.random()
         else:
-            source_ttl_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ttlValue)"))
+            source_ttl_value = Util.handle_most_used_outputs(self.statistics.get_most_used_ttl_value())
         destination_ttl_dist = self.statistics.get_ttl_distribution(ip_destination)
         if len(destination_ttl_dist) > 0:
             destination_ttl_prob_dict = lea.Lea.fromValFreqsDict(destination_ttl_dist)
             destination_ttl_value = destination_ttl_prob_dict.random()
         else:
-            destination_ttl_value = Util.handle_most_used_outputs(
-                self.statistics.process_db_query("most_used(ttlValue)"))
+            destination_ttl_value = Util.handle_most_used_outputs(self.statistics.get_most_used_ttl_value())
 
         # Set Window Size based on Window Size distribution of IP address
         source_win_dist = self.statistics.get_win_distribution(ip_source)
@@ -172,14 +170,13 @@ class PortscanAttack(BaseAttack.BaseAttack):
             source_win_prob_dict = lea.Lea.fromValFreqsDict(source_win_dist)
             source_win_value = source_win_prob_dict.random()
         else:
-            source_win_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(winSize)"))
+            source_win_value = Util.handle_most_used_outputs(self.statistics.get_most_used_win_size())
         destination_win_dist = self.statistics.get_win_distribution(ip_destination)
         if len(destination_win_dist) > 0:
             destination_win_prob_dict = lea.Lea.fromValFreqsDict(destination_win_dist)
             destination_win_value = destination_win_prob_dict.random()
         else:
-            destination_win_value = Util.handle_most_used_outputs(
-                self.statistics.process_db_query("most_used(winSize)"))
+            destination_win_value = Util.handle_most_used_outputs(self.statistics.get_most_used_win_size())
 
         min_delay, max_delay = self.get_reply_delay(ip_destination)
 

+ 2 - 2
code/Attack/SMBLorisAttack.py

@@ -48,7 +48,7 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
         most_used_ip_address = self.statistics.get_most_used_ip_address()
 
         # The most used IP class in background traffic
-        most_used_ip_class = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ipClass)"))
+        most_used_ip_class = Util.handle_most_used_outputs(self.statistics.get_most_used_ip_class())
         num_attackers = rnd.randint(1, 16)
         source_ip = self.generate_random_ipv4_address(most_used_ip_class, num_attackers)
 
@@ -92,7 +92,7 @@ class SMBLorisAttack(BaseAttack.BaseAttack):
         # user supplied atkParam.Parameter.NUMBER_ATTACKERS
         if (num_attackers is not None) and (num_attackers is not 0):
             # The most used IP class in background traffic
-            most_used_ip_class = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ipClass)"))
+            most_used_ip_class = Util.handle_most_used_outputs(self.statistics.get_most_used_ip_class())
             # Create random attackers based on user input atkParam.Parameter.NUMBER_ATTACKERS
             ip_source = self.generate_random_ipv4_address(most_used_ip_class, num_attackers)
             mac_source = self.generate_random_mac_address(num_attackers)

+ 2 - 2
code/Attack/SQLiAttack.py

@@ -114,7 +114,7 @@ class SQLiAttack(BaseAttack.BaseAttack):
             source_ttl_prob_dict = lea.Lea.fromValFreqsDict(source_ttl_dist)
             source_ttl_value = source_ttl_prob_dict.random()
         else:
-            source_ttl_value = Util.handle_most_used_outputs(self.statistics.process_db_query("most_used(ttlValue)"))
+            source_ttl_value = Util.handle_most_used_outputs(self.statistics.get_most_used_ttl_value())
 
         destination_ttl_dist = self.statistics.get_ttl_distribution(ip_destination)
         if len(destination_ttl_dist) > 0:
@@ -122,7 +122,7 @@ class SQLiAttack(BaseAttack.BaseAttack):
             destination_ttl_value = destination_ttl_prob_dict.random()
         else:
             destination_ttl_value = Util.handle_most_used_outputs(
-                self.statistics.process_db_query("most_used(ttlValue)"))
+                self.statistics.get_most_used_ttl_value())
 
         # Inject SQLi Attack
         # Read SQLi Attack pcap file

+ 7 - 6
code/CLI.py

@@ -66,9 +66,10 @@ class CLI(object):
                             help='perform extra tests on the input pcap file, including calculating IP entropy'
                                  'in interval-wise, TCP checksum, and checking payload availability.',
                             action='store_true')
-        parser.add_argument('-S', '--randomSeed', action='append', help='sets random seed for testing or benchmarking',
+        parser.add_argument('-S', '--rngSeed', action='append', help='sets rng 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)
@@ -151,14 +152,14 @@ class CLI(object):
                 do_entropy = True
             controller.create_statistics_plot(self.args.plot, do_entropy)
 
-        # Check random seed
-        if not isinstance(self.args.randomSeed, list):
-            self.args.randomSeed = [self.args.randomSeed]
+        # Check rng seed
+        if not isinstance(self.args.rngSeed, list):
+            self.args.rngSeed = [self.args.rngSeed]
 
         # Process attack(s) with given attack params
         if self.args.attack is not None:
             # If attack is present, load attack with params
-            controller.process_attacks(self.args.attack, self.args.randomSeed, self.args.time)
+            controller.process_attacks(self.args.attack, self.args.rngSeed, self.args.time)
 
         # Parameter -q without arguments was given -> go into query loop
         if self.args.query == [None]:

+ 19 - 5
code/Core/AttackController.py

@@ -2,6 +2,7 @@ import importlib
 import sys
 import difflib
 import pkgutil
+import typing
 
 import Attack.AttackParameters as atkParam
 import Core.LabelManager as LabelManager
@@ -29,14 +30,21 @@ class AttackController:
         self.seed = None
         self.total_packets = 0
 
-    def set_seed(self, seed: int):
+    def set_seed(self, seed: int) -> None:
         """
-        Sets global seed.
+        Sets rng seed.
 
-        :param seed: random seed
+        :param seed: rng seed
         """
         self.seed = seed
 
+    def get_seed(self) -> typing.Union[int, None]:
+        """
+        Gets rng seed.
+        :return: The current rng seed
+        """
+        return self.seed
+
     @staticmethod
     def choose_attack(input_name):
         """"
@@ -108,7 +116,13 @@ class AttackController:
         self.current_attack.set_statistics(self.statistics)
         if seed is not None:
             self.current_attack.set_seed(seed=seed)
+
         self.current_attack.init_params()
+
+        # Unset the user-specified-flag for all parameters set in init_params
+        for k, v in self.current_attack.params.items():
+            self.current_attack.params[k] = self.current_attack.ValuePair(v.value, False)
+
         # Record the attack
         self.added_attacks.append(self.current_attack)
 
@@ -169,8 +183,8 @@ class AttackController:
         print(".)")
 
         # Store label into LabelManager
-        label = Label.Label(attack, self.get_attack_start_utime(),
-                            self.get_attack_end_utime(), attack_note)
+        label = Label.Label(attack, self.get_attack_start_utime(), self.get_attack_end_utime(),
+                            self.seed, self.current_attack.params, attack_note)
         self.label_mgr.add_labels(label)
 
         return temp_attack_pcap_path, duration

+ 18 - 3
code/Core/Controller.py

@@ -11,7 +11,7 @@ import ID2TLib.Utility as Util
 
 
 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.
 
@@ -22,8 +22,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)
@@ -42,9 +44,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):
         """
@@ -58,13 +62,20 @@ 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:
             if seeds is not None and len(seeds) > i:
-                self.attack_controller.set_seed(seed=seeds[i][0])
+                rng_seed = seeds[i][0]
+            else:
+                rng_seed = int.from_bytes(os.urandom(16), sys.byteorder)
+            self.attack_controller.set_seed(seed=rng_seed)
             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
 
@@ -110,6 +121,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.

+ 85 - 5
code/Core/LabelManager.py

@@ -1,23 +1,32 @@
+import importlib
 import datetime as dt
 import os.path
 import xml.dom.minidom as minidom
 
 import ID2TLib.Label as Label
+import ID2TLib.TestLibrary as Lib
 
 
 class LabelManager:
-    TAG_ROOT = 'LABELS'
+    TAG_ROOT = 'labels'
+    TAG_INPUT = 'input'
+    TAG_OUTPUT = 'output'
+    TAG_FILE_NAME = 'filename'
+    TAG_FILE_HASH = 'sha256'
     TAG_ATTACK = 'attack'
-    TAG_ATTACK_NAME = 'attack_name'
-    TAG_ATTACK_NOTE = 'attack_note'
+    TAG_ATTACK_NAME = 'name'
+    TAG_ATTACK_NOTE = 'note'
+    TAG_ATTACK_SEED = 'seed'
     TAG_TIMESTAMP_START = 'timestamp_start'
     TAG_TIMESTAMP_END = 'timestamp_end'
     TAG_TIMESTAMP = 'timestamp'
     TAG_TIMESTAMP_HR = 'timestamp_hr'
+    TAG_PARAMETERS = 'parameters'
     ATTR_VERSION = 'version_parser'
+    ATTR_PARAM_USERSPECIFIED = 'user_specified'
 
     # update this attribute if XML scheme was modified
-    ATTR_VERSION_VALUE = '0.2'
+    ATTR_VERSION_VALUE = '0.3'
 
     def __init__(self, filepath_pcap=None):
         """
@@ -26,6 +35,7 @@ class LabelManager:
         :param filepath_pcap: The path to the PCAP file associated to the labels.
         """
         self.labels = list()
+        self.filepath_input_pcap = filepath_pcap
 
         if filepath_pcap is not None:
             self.label_file_path = os.path.splitext(filepath_pcap)[0] + '_labels.xml'
@@ -58,6 +68,25 @@ class LabelManager:
         :param filepath: The path where the label file should be written to.
         """
 
+        def get_subtree_fileinfo(xml_tag_root, filename) -> minidom.Element:
+            """
+            Creates the subtree for pcap file information (filename and hash).
+
+            :return: The root node of the XML subtree
+            """
+
+            input_root = doc.createElement(xml_tag_root)
+
+            file = doc.createElement(self.TAG_FILE_NAME)
+            file.appendChild(doc.createTextNode(os.path.split(filename)[-1]))
+            input_root.appendChild(file)
+
+            hash_node = doc.createElement(self.TAG_FILE_HASH)
+            hash_node.appendChild(doc.createTextNode(Lib.get_sha256(filename)))
+            input_root.appendChild(hash_node)
+
+            return input_root
+
         def get_subtree_timestamp(xml_tag_root, timestamp_entry):
             """
             Creates the subtree for a given timestamp, consisting of the unix time format (seconds) and a human-readable
@@ -82,6 +111,23 @@ class LabelManager:
 
             return timestamp_root
 
+        def get_subtree_parameters(parameters):
+            """
+            Creates a subtree containing all parameters used to construct the attack
+
+            :param parameters: The list of parameters used to run the attack
+            :return: The root node of the XML subtree
+            """
+            parameters_root = doc.createElement(self.TAG_PARAMETERS)
+
+            for param_key, param_value in parameters.items():
+                param = doc.createElement(param_key.value)
+                param.appendChild(doc.createTextNode(str(param_value.value)))
+                param.setAttribute(self.ATTR_PARAM_USERSPECIFIED, str(param_value.user_specified))
+                parameters_root.appendChild(param)
+
+            return parameters_root
+
         if filepath is not None:
             self.label_file_path = os.path.splitext(filepath)[0] + '_labels.xml'
 
@@ -89,6 +135,9 @@ class LabelManager:
         doc = minidom.Document()
         node = doc.createElement(self.TAG_ROOT)
         node.setAttribute(self.ATTR_VERSION, self.ATTR_VERSION_VALUE)
+        node.appendChild(get_subtree_fileinfo(self.TAG_INPUT, self.filepath_input_pcap))
+        node.appendChild(get_subtree_fileinfo(self.TAG_OUTPUT, filepath))
+
         for label in self.labels:
             xml_tree = doc.createElement(self.TAG_ATTACK)
 
@@ -99,6 +148,9 @@ class LabelManager:
             attack_note = doc.createElement(self.TAG_ATTACK_NOTE)
             attack_note.appendChild(doc.createTextNode(str(label.attack_note)))
             xml_tree.appendChild(attack_note)
+            attack_seed = doc.createElement(self.TAG_ATTACK_SEED)
+            attack_seed.appendChild(doc.createTextNode(str(label.seed)))
+            xml_tree.appendChild(attack_seed)
 
             # add timestamp_start to XML tree
             xml_tree.appendChild(get_subtree_timestamp(self.TAG_TIMESTAMP_START, label.timestamp_start))
@@ -106,6 +158,9 @@ class LabelManager:
             # add timestamp_end to XML tree
             xml_tree.appendChild(get_subtree_timestamp(self.TAG_TIMESTAMP_END, label.timestamp_end))
 
+            # add parameters to XML tree
+            xml_tree.appendChild(get_subtree_parameters(label.parameters))
+
             node.appendChild(xml_tree)
 
         doc.appendChild(node)
@@ -155,6 +210,11 @@ class LabelManager:
                     "The file " + self.label_file_path + " was created by another version of ID2TLib.LabelManager. "
                                                          "Ignoring label file.")
 
+        self.input_filename = get_value_from_node(dom, self.TAG_INPUT, 1, 0)
+        self.input_hash = get_value_from_node(dom, self.TAG_INPUT, 3, 0)
+        self.output_filename = get_value_from_node(dom, self.TAG_OUTPUT, 1, 0)
+        self.output_hash = get_value_from_node(dom, self.TAG_OUTPUT, 3, 0)
+
         # Parse attacks from XML file
         attacks = dom.getElementsByTagName(self.TAG_ATTACK)
         count_labels = 0
@@ -163,7 +223,27 @@ class LabelManager:
             attack_note = get_value_from_node(a, self.TAG_ATTACK_NOTE, 0)
             timestamp_start = get_value_from_node(a, self.TAG_TIMESTAMP_START, 1, 0)
             timestamp_end = get_value_from_node(a, self.TAG_TIMESTAMP_END, 1, 0)
-            label = Label.Label(attack_name, float(timestamp_start), float(timestamp_end), attack_note)
+            attack_seed = get_value_from_node(a, self.TAG_ATTACK_SEED, 0)
+
+            # Instantiate this attack to create a parameter list with the correct types
+            attack_module = importlib.import_module("Attack." + attack_name)
+            attack_class = getattr(attack_module, attack_name)
+            attack = attack_class()
+
+            # Loop through all parameters listed in the XML file
+            param = a.getElementsByTagName(self.TAG_PARAMETERS)[0]
+            for param in param.childNodes:
+                # Skip empty text nodes returned by minidom
+                if not isinstance(param, minidom.Text):
+                    import distutils.util
+                    param_name = param.tagName
+                    param_value = param.childNodes[0].nodeValue
+                    param_userspecified = bool(distutils.util.strtobool(param.getAttribute(self.ATTR_PARAM_USERSPECIFIED)))
+                    attack.add_param_value(param_name, param_value, param_userspecified)
+
+            # Create the label from the data read
+            label = Label.Label(attack_name, float(timestamp_start), float(timestamp_end), attack_seed, attack.params,
+                                attack_note)
             self.labels.append(label)
             count_labels += 1
 

+ 107 - 9
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):
         """
@@ -560,7 +577,7 @@ class Statistics:
         :return: A randomly chosen IP address from the dataset or iff param count is greater than one, a list of
         randomly chosen IP addresses
         """
-        ip_address_list = self.process_db_query("all(ipAddress)")
+        ip_address_list = self.process_db_query("SELECT ipAddress from ip_statistics ORDER BY ipAddress ASC")
         if count == 1:
             return random.choice(ip_address_list)
         else:
@@ -576,13 +593,45 @@ class Statistics:
         :param mac_address: the MAC address of which the IP shall be returned, if existing in DB
         :return: the IP address used in the dataset by a given MAC address
         """
-        return self.process_db_query('ipAddress(macAddress=' + mac_address + ")")
+        return self.process_db_query("SELECT DISTINCT ipAddress FROM ip_mac WHERE macAddress = '" + mac_address + "'")
 
     def get_mac_address(self, ip_address: str):
         """
         :return: The MAC address used in the dataset for the given IP address.
         """
-        return self.process_db_query('macAddress(ipAddress=' + ip_address + ")")
+        return self.process_db_query("SELECT DISTINCT macAddress from ip_mac WHERE ipAddress = '" + ip_address + "'")
+
+    def get_most_used_ttl_value(self):
+        """
+        :return: The most used TTL value.
+        """
+        return self.process_db_query("SELECT ttlValue FROM (SELECT ttlValue, SUM(ttlCount) as occ FROM ip_ttl GROUP BY "
+                                     "ttlValue) WHERE occ=(SELECT SUM(ttlCount) as occ FROM ip_ttl GROUP BY ttlValue "
+                                     "ORDER BY occ DESC LIMIT 1) ORDER BY ttlValue ASC")
+
+    def get_most_used_ip_class(self):
+        """
+        :return: The most used IP class.
+        """
+        return self.process_db_query("SELECT ipClass FROM (SELECT ipClass, COUNT(*) as occ from ip_statistics GROUP BY "
+                                     "ipClass ORDER BY occ DESC) WHERE occ=(SELECT COUNT(*) as occ from ip_statistics "
+                                     "GROUP BY ipClass ORDER BY occ DESC LIMIT 1) ORDER BY ipClass ASC")
+
+    def get_most_used_win_size(self):
+        """
+        :return: The most used window size.
+        """
+        return self.process_db_query("SELECT winSize FROM (SELECT winSize, SUM(winCount) as occ FROM tcp_win GROUP BY "
+                                     "winSize) WHERE occ=(SELECT SUM(winCount) as occ FROM tcp_win GROUP BY winSize "
+                                     "ORDER BY occ DESC LIMIT 1) ORDER BY winSize ASC")
+
+    def get_most_used_mss_value(self):
+        """
+        :return: The most used mss value.
+        """
+        return self.process_db_query("SELECT mssValue FROM (SELECT mssValue, SUM(mssCount) as occ FROM tcp_mss GROUP BY"
+                                     " mssValue) WHERE occ=(SELECT SUM(mssCount) as occ FROM tcp_mss GROUP BY mssValue "
+                                     "ORDER BY occ DESC LIMIT 1) ORDER BY mssValue ASC")
 
     def get_most_used_mss(self, ip_address: str):
         """
@@ -1152,3 +1201,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("------------------------------------------------------------")

+ 4 - 1
code/ID2TLib/Label.py

@@ -3,19 +3,22 @@ import functools
 
 @functools.total_ordering
 class Label:
-    def __init__(self, attack_name, timestamp_start, timestamp_end, attack_note=""):
+    def __init__(self, attack_name, timestamp_start, timestamp_end, seed, parameters, attack_note=""):
         """
         Creates a new attack label
 
         :param attack_name: The name of the associated attack
         :param timestamp_start: The timestamp as unix time of the first attack packet
         :param timestamp_end: The timestamp as unix time of the last attack packet
+        :param parameters: The list of parameters used to run the attack
         :param attack_note: A note associated to the attack (optional)
         """
         self.attack_name = attack_name
         self.timestamp_start = timestamp_start
         self.timestamp_end = timestamp_end
+        self.seed = seed
         self.attack_note = attack_note
+        self.parameters = parameters
 
     def __eq__(self, other):
         return self.timestamp == other.timestamp

+ 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]])
 

+ 29 - 44
code/Test/efficiency_testing.py

@@ -5,65 +5,50 @@ import Test.ID2TAttackTest as Test
 
 
 class EfficiencyTests(Test.ID2TAttackTest):
-    def test_SMBLoris_10_000(self):
-        self.temporal_efficiency_test([['SMBLorisAttack', 'attackers.count=30', 'packets.per-second=8.0']],
-                                      time_limit=15, factor=10000)
+    def test_SMBLoris(self):
+        self.temporal_efficiency_test([['SMBLorisAttack', 'attackers.count=4', 'packets.per-second=8.0']],
+                                      time_limit=1.5, factor=1000)
 
-    def test_SMBLoris_100_000(self):
-        self.temporal_efficiency_test([['SMBLorisAttack', 'attackers.count=30', 'packets.per-second=98']],
-                                      time_limit=150, factor=100000)
-
-    def test_SMBScan_10_000(self):
+    def test_SMBScan(self):
         self.temporal_efficiency_test([['SMBScanAttack', 'ip.src=192.168.178.1',
-                                        'ip.dst=192.168.178.10-192.168.197.145']], time_limit=15, factor=10000)
-
-    def test_SMBScan_100_000(self):
-        self.temporal_efficiency_test([['SMBScanAttack', 'ip.src=192.168.178.1', 'ip.dst=192.168.0.1-192.168.195.76']],
-                                      time_limit=150, factor=100000)
+                                        'ip.dst=192.168.178.10-192.168.179.253']], time_limit=1.5, factor=1000)
 
-    def test_SMBScan_hosting_10_000(self):
+    def test_SMBScan_hosting(self):
         self.temporal_efficiency_test([['SMBScanAttack', 'ip.src=192.168.178.1',
-                                        'ip.dst=192.168.178.10-192.168.181.241',
-                                        'hosting.ip=192.168.178.10-192.168.181.241']], time_limit=15, factor=10000)
-
-    def test_SMBScan_hosting_100_000(self):
-        self.temporal_efficiency_test([['SMBScanAttack', 'ip.src=192.168.178.1', 'ip.dst=192.168.178.10-192.168.217.25',
-                                        'hosting.ip=192.168.178.10-192.168.217.25']], time_limit=150, factor=100000)
+                                        'ip.dst=192.168.178.10-192.168.178.109',
+                                        'hosting.ip=192.168.178.10-192.168.178.109']], time_limit=1.5, factor=1000)
 
     @mock.patch('ID2TLib.Utility.get_rnd_bytes', side_effect=Lib.get_bytes)
     @mock.patch('ID2TLib.Utility.get_rnd_x86_nop', side_effect=Lib.get_x86_nop)
     def test_FTPExploit(self, mock_get_rnd_x86_nop, mock_get_rnd_bytes):
         self.temporal_efficiency_test([['FTPWinaXeExploit', 'ip.src=192.168.178.1', 'ip.dst=192.168.178.10']],
-                                      time_limit=15, factor=10000)
+                                      time_limit=1.5, factor=1000)
 
-    def test_PortscanAttack_open_10_000(self):
-        self.temporal_efficiency_test([['PortscanAttack', 'ip.src=192.168.178.1', 'port.open=80']], time_limit=15,
-                                      factor=10000)
+    def test_PortscanAttack_open(self):
+        self.temporal_efficiency_test([['PortscanAttack', 'ip.src=192.168.178.1', 'port.open=80']], time_limit=1.5,
+                                      factor=1000)
 
-    def test_PortscanAttack_close_10_000(self):
-        self.temporal_efficiency_test([['PortscanAttack', 'ip.src=192.168.178.1', 'port.open=20']], time_limit=15,
-                                      factor=10000)
+    def test_PortscanAttack_close(self):
+        self.temporal_efficiency_test([['PortscanAttack', 'ip.src=192.168.178.1', 'port.open=20']], time_limit=1.5,
+                                      factor=1000)
 
-    def test_SQLi_10_000(self):
-        # FIXME: sometimes it takes 15.34028493521018 instead of the normal 7.150923313737726 seconds
-        self.temporal_efficiency_test([['SQLiAttack', 'ip.dst=192.168.0.1']], time_limit=15, factor=10000)
+    def test_SQLi(self):
+        self.temporal_efficiency_test([['SQLiAttack', 'ip.dst=192.168.0.1']], time_limit=1.5, factor=1000)
 
-    def test_Joomla_10_000(self):
-        self.temporal_efficiency_test([['JoomlaRegPrivExploit', 'ip.src=192.168.178.1']], time_limit=15, factor=10000)
+    def test_Joomla(self):
+        self.temporal_efficiency_test([['JoomlaRegPrivExploit', 'ip.src=192.168.178.1']], time_limit=1.5, factor=1000)
 
-    def test_SalityBotnet_10_000(self):
-        self.temporal_efficiency_test([['SalityBotnet']], time_limit=15, factor=10000)
+    def test_SalityBotnet(self):
+        self.temporal_efficiency_test([['SalityBotnet']], time_limit=1.5, factor=1000)
 
     @mock.patch('Attack.BaseAttack.BaseAttack.write_attack_pcap', side_effect=Lib.write_attack_pcap)
-    def test_DDoS_10_000(self, mock_write_attack_pcap):
-        # TODO: update attack args, when DDoS gets refactored
-        self.temporal_efficiency_test([['DDoSAttack', 'attackers.count=100', 'packets.per-second=95',
-                                        'attack.duration=150']], time_limit=15, factor=10000)
+    def test_DDoS(self, mock_write_attack_pcap):
+        self.temporal_efficiency_test([['DDoSAttack', 'attackers.count=10', 'packets.per-second=95',
+                                        'attack.duration=10']], time_limit=1.5, factor=1000)
 
-    @mock.patch('Attack.BaseAttack.BaseAttack.write_attack_pcap', side_effect=Lib.write_attack_pcap)
-    def test_DDoS_100_000(self, mock_write_attack_pcap):
-        # TODO: update attack args, when DDoS gets refactored
-        self.temporal_efficiency_test([['DDoSAttack', 'attackers.count=1000', 'packets.per-second=950',
-                                        'attack.duration=300']], time_limit=150, factor=100000)
+    def test_MS17(self):
+        self.temporal_efficiency_test([['MS17Scan', 'ip.src=192.168.178.1']], time_limit=1.5, factor=1000)
 
-        # TODO: add temporal efficiency test(s) for EternalBlue and MS17
+    # FIXME: improve EternalBlue efficiency
+    #def test_EternalBlue(self):
+    #    self.temporal_efficiency_test([['EternalBlue']], time_limit=1.5, factor=1000)

+ 7 - 7
code/Test/test_DDoSAttack.py

@@ -3,13 +3,13 @@ import unittest.mock as mock
 import ID2TLib.TestLibrary as Lib
 import Test.ID2TAttackTest as Test
 
-sha_basic_ddos = 'd30a14ba0568cb9c3be0db6a6d8e5d68b703d995015fc2215bfa150a8aff8b2a'
-sha_num_attackers_ddos = '0de1ac89bb02e0163a31a0215d59ef2e2d819ffb904f8a99be1ecb52a568a392'
-sha_dest_mac_length_zero_ddos = '55720bc3aa43a6abad2db1bd1f9c7ff71cb50f11ca5f17995b24184678c18226'
-sha_mss_none_ddos = 'd30a14ba0568cb9c3be0db6a6d8e5d68b703d995015fc2215bfa150a8aff8b2a'
-sha_one_attacker_ddos = '8bb7798e85cff15b91c5ee2c0bb65f01ff3097a417bdd2e58a540f89d542bea9'
-sha_ip_range_ddos = 'bef5deb3cc7ee7537a90a85323cf885cf5a0431e15ae7001c0c762afc643e7a6'
-sha_port_range_ddos = '082f9bee607931751087fc4004bc95bf225f23b2a54ce1f771969019a5443ee7'
+sha_basic_ddos = 'a9b75322e2a331f617250d14935b0235aa818dd08803584d9cc3560b8305b459'
+sha_num_attackers_ddos = '86f13efe33d3e07c282d0111da09dead12bda1c2047d85e3a2c2f8d02b49e151'
+sha_dest_mac_length_zero_ddos = 'df4c55d25c3e13e38294f036e8ce17d7aaea309ecb9ade4eb551ed61589c0648'
+sha_mss_none_ddos = 'a9b75322e2a331f617250d14935b0235aa818dd08803584d9cc3560b8305b459'
+sha_one_attacker_ddos = 'd706c8594f54ab31f02700366fb9bfa872f9cc0e6393a9ed80bf255432e9cce8'
+sha_ip_range_ddos = '867b560a415562ffb6e973e57cdddf856826e6931dd1dbd732c6799fdc078f25'
+sha_port_range_ddos = 'f9adfe2d86fca0c66904a9b358e4bf31e122095eb2877f4ebcaec8e60b482ade'
 
 
 class UnitTestDDoS(Test.ID2TAttackTest):

+ 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'),

+ 17 - 2
code_boost/src/cxx/pcap_processor.cpp

@@ -128,6 +128,7 @@ void pcap_processor::collect_statistics() {
         // Save timestamp of first packet
         stats.setTimestampFirstPacket(i->timestamp());
 
+        int totalPackets = 0;
         int timeIntervalCounter = 1;
         int timeIntervalsNum = 100;
         std::chrono::microseconds intervalStartTimestamp = stats.getTimestampFirstPacket();
@@ -135,7 +136,7 @@ void pcap_processor::collect_statistics() {
 
         // An empty loop to know the capture duration, then choose a suitable time interval
         SnifferIterator lastpkt; 
-        for (SnifferIterator j = snifferOverview.begin(); j != snifferOverview.end();  snifferIteratorIncrement(j)) {lastpkt = j;}          
+        for (SnifferIterator j = snifferOverview.begin(); j != snifferOverview.end(); ++j, ++totalPackets) {lastpkt = j;}
 
         std::chrono::microseconds lastTimestamp = lastpkt->timestamp();                  
         std::chrono::microseconds captureDuration = lastTimestamp - firstTimestamp;
@@ -147,6 +148,9 @@ void pcap_processor::collect_statistics() {
         std::chrono::duration<int, std::micro> timeInterval(timeInterval_microsec);
         std::chrono::microseconds barrier = timeInterval;
 
+        std::cout << "\n";
+        std::chrono::system_clock::time_point lastPrinted = std::chrono::system_clock::now();
+
         // Iterate over all packets and collect statistics
         for (; i != sniffer.end(); i++) {
             currentPktTimestamp = i->timestamp();
@@ -163,8 +167,19 @@ void pcap_processor::collect_statistics() {
 
             stats.incrementPacketCount();
             this->process_packets(*i);
+
+            // Indicate progress once every second
+            if (std::chrono::system_clock::now() - lastPrinted >= std::chrono::seconds(1)) {
+                int packetCount = stats.getPacketCount();
+                std::cout << "\rInspected packets: ";
+                std::cout << std::fixed << std::setprecision(1) << (static_cast<float>(packetCount)*100/totalPackets) << "%";
+                std::cout << " (" << packetCount << "/" << totalPackets << ")" << std::flush;
+                lastPrinted = std::chrono::system_clock::now();
+            }
         }
-        
+
+        std::cout << "\n";
+
         // Save timestamp of last packet into statistics
         stats.setTimestampLastPacket(currentPktTimestamp);
     }

+ 1 - 9
code_boost/src/cxx/utilities.cpp

@@ -74,14 +74,6 @@ std::string getIPv4Class(std::string ipAddress){
     return ipClass;
 }
 
-/**
- * Advance iterator by 10 steps.
- * @param iterator to advance.
- */
-void snifferIteratorIncrement(Tins::SnifferIterator& iterator){
-    (((((((((iterator++)++)++)++)++)++)++)++)++)++;  
-}
-
 /**
  * Convert IP address from string to array of bytes.
  * @param IP to convert.
@@ -194,4 +186,4 @@ bool check_tcpChecksum(std::string ipAddressSender, std::string ipAddressReceive
     calculatedChecsum = tcp_sum_calc(bufferArray_8.size(), ipAddressSender_bytes, ipAddressReceiver_bytes, padding, buff_16);
 
     return (calculatedChecsum == checksum);
-}
+}

+ 0 - 2
code_boost/src/cxx/utilities.h

@@ -23,8 +23,6 @@ using namespace Tins;
 
 std::string getIPv4Class(std::string ipAddress);
 
-void snifferIteratorIncrement(Tins::SnifferIterator& iterator);
-
 void convertIPv4toArray(std::string IP, unsigned short IP_bytes[]);
 
 void split_str(const std::string& s, char delim,std::vector<std::string>& v);