LabelManager.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import importlib
  2. import datetime as dt
  3. import os.path
  4. import xml.dom.minidom as minidom
  5. import ID2TLib.Label as Label
  6. class LabelManager:
  7. TAG_ROOT = 'labels'
  8. TAG_ATTACK = 'attack'
  9. TAG_ATTACK_NAME = 'name'
  10. TAG_ATTACK_NOTE = 'note'
  11. TAG_ATTACK_SEED = 'seed'
  12. TAG_TIMESTAMP_START = 'timestamp_start'
  13. TAG_TIMESTAMP_END = 'timestamp_end'
  14. TAG_TIMESTAMP = 'timestamp'
  15. TAG_TIMESTAMP_HR = 'timestamp_hr'
  16. TAG_PARAMETERS = 'parameters'
  17. ATTR_VERSION = 'version_parser'
  18. ATTR_PARAM_USERSPECIFIED = 'user_specified'
  19. # update this attribute if XML scheme was modified
  20. ATTR_VERSION_VALUE = '0.3'
  21. def __init__(self, filepath_pcap=None):
  22. """
  23. Creates a new LabelManager for managing the attack's labels.
  24. :param filepath_pcap: The path to the PCAP file associated to the labels.
  25. """
  26. self.labels = list()
  27. if filepath_pcap is not None:
  28. self.label_file_path = os.path.splitext(filepath_pcap)[0] + '_labels.xml'
  29. # only load labels if label file is existing
  30. if os.path.exists(self.label_file_path):
  31. self.load_labels()
  32. def add_labels(self, labels):
  33. """
  34. Adds a label to the internal list of labels.
  35. :param labels: The labels to be added
  36. """
  37. if isinstance(labels, list):
  38. self.labels = self.labels + [labels]
  39. elif isinstance(labels, tuple):
  40. for l in labels:
  41. self.labels.append(l)
  42. else:
  43. self.labels.append(labels)
  44. # sorts the labels ascending by their timestamp
  45. self.labels.sort()
  46. def write_label_file(self, filepath=None):
  47. """
  48. Writes previously added/loaded labels to a XML file. Uses the given filepath as destination path, if no path is
  49. given, uses the path in label_file_path.
  50. :param filepath: The path where the label file should be written to.
  51. """
  52. def get_subtree_timestamp(xml_tag_root, timestamp_entry):
  53. """
  54. Creates the subtree for a given timestamp, consisting of the unix time format (seconds) and a human-readable
  55. output.
  56. :param xml_tag_root: The tag name for the root of the subtree
  57. :param timestamp_entry: The timestamp as unix time
  58. :return: The root node of the XML subtree
  59. """
  60. timestamp_root = doc.createElement(xml_tag_root)
  61. # add timestamp in unix format
  62. timestamp = doc.createElement(self.TAG_TIMESTAMP)
  63. timestamp.appendChild(doc.createTextNode(str(timestamp_entry)))
  64. timestamp_root.appendChild(timestamp)
  65. # add timestamp in human-readable format
  66. timestamp_hr = doc.createElement(self.TAG_TIMESTAMP_HR)
  67. timestamp_hr_text = dt.datetime.fromtimestamp(timestamp_entry).strftime('%Y-%m-%d %H:%M:%S.%f')
  68. timestamp_hr.appendChild(doc.createTextNode(timestamp_hr_text))
  69. timestamp_root.appendChild(timestamp_hr)
  70. return timestamp_root
  71. def get_subtree_parameters(parameters):
  72. """
  73. Creates a subtree containing all parameters used to construct the attack
  74. :param parameters: The list of parameters used to run the attack
  75. :return: The root node of the XML subtree
  76. """
  77. parameters_root = doc.createElement(self.TAG_PARAMETERS)
  78. for param_key, param_value in parameters.items():
  79. param = doc.createElement(param_key.value)
  80. param.appendChild(doc.createTextNode(str(param_value.value)))
  81. param.setAttribute(self.ATTR_PARAM_USERSPECIFIED, str(param_value.user_specified))
  82. parameters_root.appendChild(param)
  83. return parameters_root
  84. if filepath is not None:
  85. self.label_file_path = os.path.splitext(filepath)[0] + '_labels.xml'
  86. # Generate XML
  87. doc = minidom.Document()
  88. node = doc.createElement(self.TAG_ROOT)
  89. node.setAttribute(self.ATTR_VERSION, self.ATTR_VERSION_VALUE)
  90. for label in self.labels:
  91. xml_tree = doc.createElement(self.TAG_ATTACK)
  92. # add attack to XML tree
  93. attack_name = doc.createElement(self.TAG_ATTACK_NAME)
  94. attack_name.appendChild(doc.createTextNode(str(label.attack_name)))
  95. xml_tree.appendChild(attack_name)
  96. attack_note = doc.createElement(self.TAG_ATTACK_NOTE)
  97. attack_note.appendChild(doc.createTextNode(str(label.attack_note)))
  98. xml_tree.appendChild(attack_note)
  99. attack_seed = doc.createElement(self.TAG_ATTACK_SEED)
  100. attack_seed.appendChild(doc.createTextNode(str(label.seed)))
  101. xml_tree.appendChild(attack_seed)
  102. # add timestamp_start to XML tree
  103. xml_tree.appendChild(get_subtree_timestamp(self.TAG_TIMESTAMP_START, label.timestamp_start))
  104. # add timestamp_end to XML tree
  105. xml_tree.appendChild(get_subtree_timestamp(self.TAG_TIMESTAMP_END, label.timestamp_end))
  106. # add parameters to XML tree
  107. xml_tree.appendChild(get_subtree_parameters(label.parameters))
  108. node.appendChild(xml_tree)
  109. doc.appendChild(node)
  110. # Write XML to file
  111. file = open(self.label_file_path, 'w')
  112. file.write(doc.toprettyxml())
  113. file.close()
  114. def load_labels(self):
  115. """
  116. Loads the labels from an already existing label XML file located at label_file_path (set by constructor).
  117. """
  118. def get_value_from_node(node, tag_name, *child_number):
  119. """
  120. Returns the value located in the tag specified by tag_name from a given node. Walks therefor the
  121. node's children along as indicated by child_number, e.g., childNumber = (1,2,) first goes to the 1st child,
  122. and then to the 2nd child of the first child -> elem.childNodes[1].childNodes[2].
  123. """
  124. elem = node.getElementsByTagName(tag_name)
  125. if len(elem) == 1:
  126. elem = elem[0]
  127. for c in child_number:
  128. if len(elem.childNodes) > 0:
  129. elem = elem.childNodes[c]
  130. else:
  131. return ""
  132. return elem.data
  133. else:
  134. return ""
  135. print("Label file found. Loading labels...")
  136. try:
  137. dom = minidom.parse(self.label_file_path)
  138. except Exception:
  139. # TODO: more specific exception
  140. print('ERROR: Provided label file could not be parsed. Ignoring label file')
  141. return
  142. # Check if version of parser and version of file match
  143. version = dom.getElementsByTagName(self.TAG_ROOT)
  144. if len(version) > 0:
  145. version = version[0].getAttribute(self.ATTR_VERSION)
  146. if version == [] or not version == self.ATTR_VERSION_VALUE:
  147. print(
  148. "The file " + self.label_file_path + " was created by another version of ID2TLib.LabelManager. "
  149. "Ignoring label file.")
  150. # Parse attacks from XML file
  151. attacks = dom.getElementsByTagName(self.TAG_ATTACK)
  152. count_labels = 0
  153. for a in attacks:
  154. attack_name = get_value_from_node(a, self.TAG_ATTACK_NAME, 0)
  155. attack_note = get_value_from_node(a, self.TAG_ATTACK_NOTE, 0)
  156. timestamp_start = get_value_from_node(a, self.TAG_TIMESTAMP_START, 1, 0)
  157. timestamp_end = get_value_from_node(a, self.TAG_TIMESTAMP_END, 1, 0)
  158. attack_seed = get_value_from_node(a, self.TAG_ATTACK_SEED, 0)
  159. # Instantiate this attack to create a parameter list with the correct types
  160. attack_module = importlib.import_module("Attack." + attack_name)
  161. attack_class = getattr(attack_module, attack_name)
  162. attack = attack_class()
  163. # Loop through all parameters listed in the XML file
  164. param = a.getElementsByTagName(self.TAG_PARAMETERS)[0]
  165. for param in param.childNodes:
  166. # Skip empty text nodes returned by minidom
  167. if not isinstance(param, minidom.Text):
  168. import distutils.util
  169. param_name = param.tagName
  170. param_value = param.childNodes[0].nodeValue
  171. param_userspecified = bool(distutils.util.strtobool(param.getAttribute(self.ATTR_PARAM_USERSPECIFIED)))
  172. attack.add_param_value(param_name, param_value, param_userspecified)
  173. # Create the label from the data read
  174. label = Label.Label(attack_name, float(timestamp_start), float(timestamp_end), attack_seed, attack.params,
  175. attack_note)
  176. self.labels.append(label)
  177. count_labels += 1
  178. print("Read " + str(count_labels) + " label(s) successfully.")