Ver código fonte

AttackParameters
- Adds the parameter NUMBER.ATTACKERS used by DDoSAttack

BaseAttack
- Improves parameter validation
- Adds method to generate random MAC address

DDoSAttack
- Improves derivation of attack parameters

Patrick Jattke 7 anos atrás
pai
commit
c26b45f9d5

+ 2 - 1
code/Attack/AttackParameters.py

@@ -18,7 +18,8 @@ class Parameter(Enum):
     PORT_DESTINATION = 'port.dst'  # destination ports
     PORT_DESTINATION = 'port.dst'  # destination ports
     PORT_SOURCE = 'port.src'  # source ports
     PORT_SOURCE = 'port.src'  # source ports
     # recommended type: Integer positive -------------------------
     # recommended type: Integer positive -------------------------
-    PACKETS_LIMIT = 'packets.limit'  # the
+    PACKETS_LIMIT = 'packets.limit'
+    NUMBER_ATTACKERS = 'attackers.count'
     # recommended type: Float ------------------------------------
     # recommended type: Float ------------------------------------
     PACKETS_PER_SECOND = 'packets.per-second'  # packets per second
     PACKETS_PER_SECOND = 'packets.per-second'  # packets per second
     INJECT_AT_TIMESTAMP = 'inject.at-timestamp'  # unix epoch time (seconds.millis) where attack should be injected
     INJECT_AT_TIMESTAMP = 'inject.at-timestamp'  # unix epoch time (seconds.millis) where attack should be injected

+ 56 - 12
code/Attack/BaseAttack.py

@@ -58,8 +58,16 @@ class BaseAttack(metaclass=ABCMeta):
         :param mac_address: The MAC address as string.
         :param mac_address: The MAC address as string.
         :return: True if the MAC address is valid, otherwise False.
         :return: True if the MAC address is valid, otherwise False.
         """
         """
-        result = re.match('^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$', mac_address, re.MULTILINE)
-        return result is not None
+        pattern = re.compile('^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$', re.MULTILINE)
+        if isinstance(mac_address, list):
+            for mac in mac_address:
+                if re.match(pattern, mac) is None:
+                    return False
+        else:
+            if re.match(pattern, mac_address) is None:
+                return False
+
+        return True
 
 
     @staticmethod
     @staticmethod
     def _is_ip_address(ip_address: str):
     def _is_ip_address(ip_address: str):
@@ -110,6 +118,8 @@ class BaseAttack(metaclass=ABCMeta):
 
 
         if isinstance(ports_input, str):
         if isinstance(ports_input, str):
             ports_input = ports_input.replace(' ', '').split(',')
             ports_input = ports_input.replace(' ', '').split(',')
+        elif isinstance(ports_input, int):
+            ports_input = [ports_input]
 
 
         ports_output = []
         ports_output = []
 
 
@@ -198,7 +208,7 @@ class BaseAttack(metaclass=ABCMeta):
     # HELPER METHODS
     # HELPER METHODS
     #########################################
     #########################################
 
 
-    def add_param_value(self, param, value: str):
+    def add_param_value(self, param, value):
         """
         """
         Adds the pair param : value to the dictionary of attack parameters. Prints and error message and skips the
         Adds the pair param : value to the dictionary of attack parameters. Prints and error message and skips the
         parameter if the validation fails.
         parameter if the validation fails.
@@ -280,24 +290,27 @@ class BaseAttack(metaclass=ABCMeta):
         :param param: The parameter whose value is wanted.
         :param param: The parameter whose value is wanted.
         :return: The parameter's value.
         :return: The parameter's value.
         """
         """
-        return self.params[param]
+        return self.params.get(param)
 
 
     def check_parameters(self):
     def check_parameters(self):
         """
         """
         Checks whether all parameter values are defined. If a value is not defined, the application is terminated.
         Checks whether all parameter values are defined. If a value is not defined, the application is terminated.
         However, this should not happen as all attack should define default parameter values.
         However, this should not happen as all attack should define default parameter values.
         """
         """
+        # parameters which do not require default values
+        non_obligatory_params = [Parameter.INJECT_AFTER_PACKET, Parameter.NUMBER_ATTACKERS]
         for param, type in self.supported_params.items():
         for param, type in self.supported_params.items():
             # checks whether all params have assigned values, INJECT_AFTER_PACKET must not be considered because the
             # checks whether all params have assigned values, INJECT_AFTER_PACKET must not be considered because the
             # timestamp derived from it is set to Parameter.INJECT_AT_TIMESTAMP
             # timestamp derived from it is set to Parameter.INJECT_AT_TIMESTAMP
-            if param not in self.params.keys() and param is not Parameter.INJECT_AFTER_PACKET:
+            if param not in self.params.keys() and param not in non_obligatory_params:
                 print("\033[91mCRITICAL ERROR: Attack '" + self.attack_name + "' does not define the parameter '" +
                 print("\033[91mCRITICAL ERROR: Attack '" + self.attack_name + "' does not define the parameter '" +
                       str(param) + "'.\n The attack must define default values for all parameters."
                       str(param) + "'.\n The attack must define default values for all parameters."
                       + "\n Cannot continue attack generation.\033[0m")
                       + "\n Cannot continue attack generation.\033[0m")
                 import sys
                 import sys
                 sys.exit(0)
                 sys.exit(0)
 
 
-    def generate_random_ipv4_address(self, n: int = 1):
+    @staticmethod
+    def generate_random_ipv4_address(n: int = 1):
         """
         """
         Generates n random IPv4 addresses.
         Generates n random IPv4 addresses.
         :param n: The number of IP addresses to be generated
         :param n: The number of IP addresses to be generated
@@ -306,7 +319,7 @@ class BaseAttack(metaclass=ABCMeta):
 
 
         def is_invalid(ipAddress: ipaddress.IPv4Address):
         def is_invalid(ipAddress: ipaddress.IPv4Address):
             return ipAddress.is_multicast or ipAddress.is_unspecified or ipAddress.is_loopback or \
             return ipAddress.is_multicast or ipAddress.is_unspecified or ipAddress.is_loopback or \
-                   ipAddress.is_link_local or ipAddress.is_reserved
+                   ipAddress.is_link_local or ipAddress.is_private or ipAddress.is_reserved
 
 
         def generate_address():
         def generate_address():
             return ipaddress.IPv4Address(random.randint(0, 2 ** 32 - 1))
             return ipaddress.IPv4Address(random.randint(0, 2 ** 32 - 1))
@@ -314,7 +327,7 @@ class BaseAttack(metaclass=ABCMeta):
         ip_addresses = []
         ip_addresses = []
         for i in range(0, n):
         for i in range(0, n):
             address = generate_address()
             address = generate_address()
-            while (is_invalid(address)):
+            while is_invalid(address):
                 address = generate_address()
                 address = generate_address()
             ip_addresses.append(str(address))
             ip_addresses.append(str(address))
 
 
@@ -323,7 +336,8 @@ class BaseAttack(metaclass=ABCMeta):
         else:
         else:
             return ip_addresses
             return ip_addresses
 
 
-    def generate_random_ipv6_address(self, n: int = 1):
+    @staticmethod
+    def generate_random_ipv6_address(n: int = 1):
         """
         """
         Generates n random IPv6 addresses.
         Generates n random IPv6 addresses.
         :param n: The number of IP addresses to be generated
         :param n: The number of IP addresses to be generated
@@ -332,15 +346,15 @@ class BaseAttack(metaclass=ABCMeta):
 
 
         def is_invalid(ipAddress: ipaddress.IPv6Address):
         def is_invalid(ipAddress: ipaddress.IPv6Address):
             return ipAddress.is_multicast or ipAddress.is_unspecified or ipAddress.is_loopback or \
             return ipAddress.is_multicast or ipAddress.is_unspecified or ipAddress.is_loopback or \
-                   ipAddress.is_link_local or ipAddress.is_reserved
+                   ipAddress.is_link_local or ipAddress.is_private or ipAddress.is_reserved
 
 
         def generate_address():
         def generate_address():
-            return str(ipaddress.IPv6Address(random.randint(0, 2 ** 128 - 1)))
+            return ipaddress.IPv6Address(random.randint(0, 2 ** 128 - 1))
 
 
         ip_addresses = []
         ip_addresses = []
         for i in range(0, n):
         for i in range(0, n):
             address = generate_address()
             address = generate_address()
-            while (is_invalid(address)):
+            while is_invalid(address):
                 address = generate_address()
                 address = generate_address()
             ip_addresses.append(str(address))
             ip_addresses.append(str(address))
 
 
@@ -348,3 +362,33 @@ class BaseAttack(metaclass=ABCMeta):
             return ip_addresses[0]
             return ip_addresses[0]
         else:
         else:
             return ip_addresses
             return ip_addresses
+
+    @staticmethod
+    def generate_random_mac_address(n: int = 1):
+        """
+        Generates n random MAC addresses.
+        :param n: The number of MAC addresses to be generated.
+        :return: A single MAC addres, or if n>1, a list of MAC addresses
+        """
+
+        def is_invalid(address: str):
+            first_octet = int(address[0:2], 16)
+            is_multicast_address = bool(first_octet & 0b01)
+            is_locally_administered = bool(first_octet & 0b10)
+            return is_multicast_address or is_locally_administered
+
+        def generate_address():
+            mac = [random.randint(0x00, 0xff) for i in range(0, 6)]
+            return ':'.join(map(lambda x: "%02x" % x, mac))
+
+        mac_addresses = []
+        for i in range(0, n):
+            address = generate_address()
+            while is_invalid(address):
+                address = generate_address()
+            mac_addresses.append(address)
+
+        if n == 1:
+            return mac_addresses[0]
+        else:
+            return mac_addresses

+ 176 - 0
code/Attack/DDoSAttack.py

@@ -0,0 +1,176 @@
+import logging
+from random import randint, choice, uniform
+from lea import Lea
+from scipy.stats import stats, gamma
+
+from Attack import BaseAttack
+from Attack.AttackParameters import Parameter as Param
+from Attack.AttackParameters import ParameterTypes
+logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
+# noinspection PyPep8
+from scapy.layers.inet import IP, Ether, TCP, RandShort
+from collections import deque
+
+
+class DDoSAttack(BaseAttack.BaseAttack):
+    def __init__(self, statistics, pcap_file_path):
+        """
+        Creates a new instance of the DDoS attack.
+
+        :param statistics: A reference to the statistics class.
+        """
+        # Initialize attack
+        super(DDoSAttack, self).__init__(statistics, "DDoS Attack", "Injects a DDoS attack'",
+                                        "Resource Exhaustion")
+
+        # Define allowed parameters and their type
+        self.supported_params = {
+            Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
+            Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
+            Param.PORT_SOURCE: ParameterTypes.TYPE_PORT,
+            Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
+            Param.MAC_DESTINATION: ParameterTypes.TYPE_MAC_ADDRESS,
+            Param.PORT_DESTINATION: ParameterTypes.TYPE_PORT,
+            Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
+            Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
+            Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
+            Param.PACKETS_LIMIT: ParameterTypes.TYPE_INTEGER_POSITIVE,
+            Param.NUMBER_ATTACKERS: ParameterTypes.TYPE_INTEGER_POSITIVE
+        }
+
+        # PARAMETERS: initialize with default values
+        # (values are overwritten if user specifies them)
+
+        self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
+        # attacker configuration
+        num_attackers = randint(1, 16)
+        self.add_param_value(Param.IP_SOURCE, self.generate_random_ipv4_address(num_attackers))
+        self.add_param_value(Param.MAC_SOURCE, self.generate_random_mac_address(num_attackers))
+        self.add_param_value(Param.PORT_SOURCE, str(RandShort()))
+        self.add_param_value(Param.PACKETS_PER_SECOND, randint(1, 64))
+        # victim configuration
+        random_ip_address = self.statistics.get_random_ip_address()
+        self.add_param_value(Param.IP_DESTINATION, random_ip_address)
+        self.add_param_value(Param.MAC_DESTINATION, self.statistics.get_mac_address(random_ip_address))
+        port_destination = self.statistics.process_db_query(
+            "SELECT portNumber FROM ip_ports WHERE portDirection='in' ORDER BY RANDOM() LIMIT 1;")
+        if port_destination is None:
+            port_destination = str(RandShort())
+        self.add_param_value(Param.PORT_DESTINATION, port_destination)
+        self.add_param_value(Param.PACKETS_LIMIT, randint(1000, 5000))
+
+    def get_packets(self):
+        def update_timestamp(timestamp, pps, maxdelay):
+            """
+            Calculates the next timestamp to be used based on the packet per second rate (pps) and the maximum delay.
+
+            :return: Timestamp to be used for the next packet.
+            """
+            return timestamp + uniform(0.1 / pps, maxdelay)
+
+        def get_nth_random_element(*element_list):
+            """
+            Returns the n-th element of every list from an arbitrary number of given lists.
+            For example, list1 contains IP addresses, list 2 contains MAC addresses. Use of this function ensures that
+            the n-th IP address uses always the n-th MAC address.
+            :param element_list: An arbitrary number of lists.
+            :return: A tuple of the n-th element of every list.
+            """
+            range_max = min([len(x) for x in element_list])
+            if range_max > 0: range_max -= 1
+            n = randint(0, range_max)
+            return tuple(x[n] for x in element_list)
+
+        def index_increment(number: int, max: int):
+            if number + 1 < max:
+                return number + 1
+            else:
+                return 0
+
+        def get_attacker_config(ipAddress: str):
+            """
+
+            :param ipAddress:
+            :return:
+            """
+            # Determine port
+            port = attacker_port_mapping.get(ipAddress)
+            if port is not None:  # use next port
+                next_port = attacker_port_mapping.get(ipAddress) + 1
+                if next_port > (2 ** 16 - 1):
+                    next_port = 1
+            else:  # generate starting port
+                next_port = RandShort()
+            attacker_port_mapping[ipAddress] = next_port
+            # Determine TTL value
+            ttl = attacker_ttl_mapping.get(ipAddress)
+            if ttl is None:  # determine TTL value
+                is_invalid = True
+                pos = ip_source_list.index(ipAddress)
+                pos_max = len(gd)
+                while is_invalid:
+                    ttl = int(round(gd[pos]))
+                    if 0 < ttl < 256:  # validity check
+                        is_invalid = False
+                        pos = index_increment(pos, pos_max)
+                attacker_ttl_mapping[ipAddress] = ttl
+            # return port and TTL
+            return next_port, ttl
+
+        # Determine source IP and MAC address
+        num_attackers = self.get_param_value(Param.NUMBER_ATTACKERS)
+        if num_attackers is not None:  # user supplied Param.NUMBER_ATTACKERS
+            # Create random attackers based on user input Param.NUMBER_ATTACKERS
+            ip_source_list = self.generate_random_ipv4_address(num_attackers)
+            mac_source_list = self.generate_random_mac_address(num_attackers)
+        else:  # user did not supply Param.NUMBER_ATTACKS
+            # use default values for IP_SOURCE/MAC_SOURCE or overwritten values
+            # if user supplied any values for those params
+            ip_source_list = self.get_param_value(Param.IP_SOURCE)
+            mac_source_list = self.get_param_value(Param.MAC_SOURCE)
+
+        BUFFER_SIZE_PACKETS = self.get_param_value(Param.PACKETS_LIMIT)
+
+        # Timestamp
+        timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
+        pps = self.get_param_value(Param.PACKETS_PER_SECOND)
+        randomdelay = Lea.fromValFreqsDict({1 / pps: 70, 2 / pps: 30, 5 / pps: 15, 10 / pps: 3})
+
+        # Initialize parameters
+        packets = deque(maxlen=BUFFER_SIZE_PACKETS)
+        port_source_list = self.get_param_value(Param.PORT_SOURCE)
+        mac_destination = self.get_param_value(Param.MAC_DESTINATION)
+        ip_destination = self.get_param_value(Param.IP_DESTINATION)
+        port_destination = self.get_param_value(Param.PORT_DESTINATION)
+        attacker_port_mapping = {}
+        attacker_ttl_mapping = {}
+
+        # Gamma distribution parameters derived from MAWI 13.8G dataset
+        alpha, loc, beta = (2.3261710235, -0.188306914406, 44.4853123884)
+        gd = gamma.rvs(alpha, loc=loc, scale=beta, size=len(ip_source_list))
+
+        for pkt_num in range(self.get_param_value(Param.PACKETS_LIMIT)):
+            # Select one IP address and its corresponding MAC address
+            (ip_source, mac_source) = get_nth_random_element(ip_source_list, mac_source_list)
+
+            # Determine source port
+            (port_source, ttl_value) = get_attacker_config(ip_source)
+
+            maxdelay = randomdelay.random()
+
+            request_ether = Ether(dst=mac_destination, src=mac_source)
+            request_ip = IP(src=ip_source, dst=ip_destination, ttl=ttl_value)
+            request_tcp = TCP(sport=port_source, dport=port_destination, flags='S', ack=0)
+
+            request = (request_ether / request_ip / request_tcp)
+            request.time = timestamp_next_pkt
+            packets.append(request)
+
+            timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, maxdelay)
+
+        # Store timestamp of first and last packet
+        self.attack_start_utime = packets[0].time
+        self.attack_end_utime = packets[-1].time
+
+        # return packets sorted by packet time_sec_start
+        return sorted(packets, key=lambda pkt: pkt.time)

+ 0 - 134
code/Attack/DosAttack.py

@@ -1,134 +0,0 @@
-import logging
-from random import randint, choice, uniform
-from lea import Lea
-from Attack import BaseAttack
-from Attack.AttackParameters import Parameter as Param
-from Attack.AttackParameters import ParameterTypes
-
-logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
-# noinspection PyPep8
-from scapy.layers.inet import IP, Ether, TCP, RandShort
-from collections import deque
-
-
-class DosAttack(BaseAttack.BaseAttack):
-    def __init__(self, statistics, pcap_file_path):
-        """
-        Creates a new instance of the PortscanAttack.
-
-        :param statistics: A reference to the statistics class.
-        """
-        # Initialize attack
-        super(DosAttack, self).__init__(statistics, "DoS Attack", "Injects a DoS attack'",
-                                        "Resource Exhaustion")
-
-        # Define allowed parameters and their type
-        self.supported_params = {
-            Param.IP_SOURCE: ParameterTypes.TYPE_IP_ADDRESS,
-            Param.MAC_SOURCE: ParameterTypes.TYPE_MAC_ADDRESS,
-            Param.PORT_SOURCE: ParameterTypes.TYPE_PORT,
-            Param.PORT_SOURCE_RANDOMIZE: ParameterTypes.TYPE_BOOLEAN,
-            Param.IP_DESTINATION: ParameterTypes.TYPE_IP_ADDRESS,
-            Param.MAC_DESTINATION: ParameterTypes.TYPE_MAC_ADDRESS,
-            Param.PORT_DESTINATION: ParameterTypes.TYPE_PORT,
-            Param.INJECT_AT_TIMESTAMP: ParameterTypes.TYPE_FLOAT,
-            Param.INJECT_AFTER_PACKET: ParameterTypes.TYPE_PACKET_POSITION,
-            Param.PACKETS_PER_SECOND: ParameterTypes.TYPE_FLOAT,
-            Param.PACKETS_LIMIT: ParameterTypes.TYPE_INTEGER_POSITIVE
-        }
-
-        # PARAMETERS: initialize with default values
-        # (values are overwritten if user specifies them)
-        most_used_ip_address = self.statistics.get_most_used_ip_address()
-        if isinstance(most_used_ip_address, list): most_used_ip_address = most_used_ip_address[0]
-        self.add_param_value(Param.INJECT_AFTER_PACKET, randint(0, self.statistics.get_packet_count()))
-        # sender configuration
-        self.add_param_value(Param.IP_SOURCE, most_used_ip_address)
-        self.add_param_value(Param.MAC_SOURCE, self.statistics.get_mac_address(most_used_ip_address))
-        self.add_param_value(Param.PORT_SOURCE, str(RandShort()))
-        self.add_param_value(Param.PORT_SOURCE_RANDOMIZE, False)
-        self.add_param_value(Param.PACKETS_PER_SECOND,
-                             (self.statistics.get_pps_sent(most_used_ip_address) +
-                              self.statistics.get_pps_received(most_used_ip_address)) / 2)
-        # receiver configuration
-        random_ip_address = self.statistics.get_random_ip_address()
-        self.add_param_value(Param.IP_DESTINATION, random_ip_address)
-        self.add_param_value(Param.MAC_DESTINATION, self.statistics.get_mac_address(random_ip_address))
-        self.add_param_value(Param.PORT_DESTINATION, '80')
-        self.add_param_value(Param.PACKETS_LIMIT, randint(10, 1000))
-
-    def get_packets(self):
-        def update_timestamp(timestamp, pps, maxdelay):
-            """
-            Calculates the next timestamp to be used based on the packet per second rate (pps) and the maximum delay.
-
-            :return: Timestamp to be used for the next packet.
-            """
-            return timestamp + uniform(0.1 / pps, maxdelay)
-
-        def get_nth_random_element(*element_list):
-            """
-
-            :param element_list:
-            :return:
-            """
-            range_max = min([len(x) for x in element_list])
-            if range_max > 0: range_max -= 1
-            n = randint(0, range_max)
-            return tuple(x[n] for x in element_list)
-
-        BUFFER_SIZE_PACKETS = self.get_param_value(Param.PACKETS_LIMIT)
-
-        # Timestamp
-        timestamp_next_pkt = self.get_param_value(Param.INJECT_AT_TIMESTAMP)
-        # store start time of attack
-        self.attack_start_utime = timestamp_next_pkt
-        pps = self.get_param_value(Param.PACKETS_PER_SECOND)
-        randomdelay = Lea.fromValFreqsDict({1 / pps: 70, 2 / pps: 30, 5 / pps: 15, 10 / pps: 3})
-
-        # Initialize parameters
-        packets = deque(maxlen=BUFFER_SIZE_PACKETS)
-        # packets = []
-        mac_source = self.get_param_value(Param.MAC_SOURCE)
-        ip_source = self.get_param_value(Param.IP_SOURCE)
-        port_source = self.get_param_value(Param.PORT_SOURCE)
-        mac_destination = self.get_param_value(Param.MAC_DESTINATION)
-        ip_destination = self.get_param_value(Param.IP_DESTINATION)
-        port_destination = self.get_param_value(Param.PORT_DESTINATION)
-
-        # Set TTL based on TTL distribution of IP address
-        ttl_dist = self.statistics.get_ttl_distribution(ip_source)
-        if len(ttl_dist) > 0:
-            ttl_prob_dict = Lea.fromValFreqsDict(ttl_dist)
-            ttl_value = ttl_prob_dict.random()
-        else:
-            ttl_value = self.statistics.process_db_query("most_used(ttlValue)")
-
-        # MSS (Maximum Segment Size) for Ethernet. Allowed values [536,1500]
-        mss = self.statistics.get_mss(ip_destination)
-
-        for pkt_num in range(self.get_param_value(Param.PACKETS_LIMIT)):
-            # Determine source port
-            if self.get_param_value(Param.PORT_SOURCE_RANDOMIZE):
-                cur_port_source = RandShort()
-            elif isinstance(port_source, list):
-                cur_port_source = choice(port_source)
-            else:
-                cur_port_source = port_source
-
-            maxdelay = randomdelay.random()
-
-            request_ether = Ether(dst=mac_destination, src=mac_source)
-            request_ip = IP(src=ip_source, dst=ip_destination, ttl=ttl_value)
-            request_tcp = TCP(sport=cur_port_source, dport=port_destination, flags='S', ack=0)
-
-            request = (request_ether / request_ip / request_tcp)
-            request.time = timestamp_next_pkt
-            packets.append(request)
-
-            timestamp_next_pkt = update_timestamp(timestamp_next_pkt, pps, maxdelay)
-
-        self.attack_end_utime = request.time
-
-        # return packets sorted by packet time_sec_start
-        return sorted(packets, key=lambda pkt: pkt.time)

+ 3 - 3
code/ID2TLib/Controller.py

@@ -57,12 +57,12 @@ class Controller:
             os.remove(self.written_pcaps[i])
             os.remove(self.written_pcaps[i])
         print("done.")
         print("done.")
 
 
-        # print status message
-        print('\nOutput file created: ', self.pcap_dest_path)
-
         # write label file with attacks
         # write label file with attacks
         self.label_manager.write_label_file(self.pcap_dest_path)
         self.label_manager.write_label_file(self.pcap_dest_path)
 
 
+        # print status message
+        print('\nOutput files created: \n', self.pcap_dest_path, '\n', self.label_manager.label_file_path)
+
     def process_db_queries(self, query, print_results=False):
     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.
         Processes a statistics database query. This can be a standard SQL query or a named query.