def range2bdd(min_value, max_value, index, interval=(0, 2**8 - 1)): """Static method for construction ROBDD range Parameters ---------- min_value : int. the start of the range max_value : the end of the range index : the index for ROBDD construction variable name interval : (int, int). the interval to check (used for recursivity) Return ------ Return the corresponding ROBDD """ if interval[0] > max_value or interval[1] < min_value: return Robdd.false() if interval[0] >= min_value and interval[1] <= max_value: return Protocol(interval[0]).toBDD(index, int(math.log(interval[1] + 1 - interval[0], 2))) def new_min_interval(inter): min_v = inter[0] max_v = inter[0] + 2**(int(math.log(inter[1] + 1 - inter[0], 2)) - 1) - 1 return (min_v, max_v) def new_max_interval(inter): min_v = inter[0] + 2**(int(math.log(inter[1] + 1 - inter[0], 2)) - 1) max_v = inter[1] return (min_v, max_v) return synthesize(Protocol.range2bdd(min_value, max_value, index, new_min_interval(interval)), Bdd.OR, Protocol.range2bdd(min_value, max_value, index, new_max_interval(interval)))
def _tree_parse_detection(self, tree_path): """Detect anomalies given a rooted tree Parameters ---------- tree_path : nested list. Rooted tree representation Return ------ Return a tuple containing the accepted packets and a list of detected errors """ error_list = [] parent = tree_path[0] remain = Robdd.false() for i in xrange(1, len(tree_path)): acl_list = NetworkGraph.NetworkGraph().get_acl_list(src=tree_path[i][0], dst=parent) # test is leaf if len(tree_path[i]) == 1: res_remain, res_error = self._distributed_detection(acl_list, Robdd.true(), tree_path[i]) res_error = [] else: res_remain, res_error = self._tree_parse_detection(tree_path[i]) error_list += res_error res_remain, res_error = self._distributed_detection(acl_list, res_remain, tree_path[i]) error_list += res_error remain = synthesize(remain, Bdd.OR, res_remain) return remain, error_list
def range2bdd(min_value, max_value, index, interval=(0, 2**16 - 1)): """Static method for construction ROBDD range Parameters ---------- min_value : int. the start of the range max_value : the end of the range index : the index for ROBDD construction variable name interval : (int, int). the interval to check (used for recursivity) Return ------ Return the corresponding ROBDD """ if interval[0] > max_value or interval[1] < min_value: return Robdd.false() if interval[0] >= min_value and interval[1] <= max_value: return Port(interval[0]).toBDD(index, int(math.log(interval[1] + 1 - interval[0], 2))) def new_min_interval(inter): min_v = inter[0] max_v = inter[0] + 2**(int(math.log(inter[1] + 1 - inter[0], 2)) - 1) - 1 return (min_v, max_v) def new_max_interval(inter): min_v = inter[0] + 2**(int(math.log(inter[1] + 1 - inter[0], 2)) - 1) max_v = inter[1] return (min_v, max_v) return synthesize(Port.range2bdd(min_value, max_value, index, new_min_interval(interval)), Bdd.OR, Port.range2bdd(min_value, max_value, index, new_max_interval(interval)))
def _tree_parse_detection(self, tree_path): """Detect anomalies given a rooted tree Parameters ---------- tree_path : nested list. Rooted tree representation Return ------ Return a tuple containing the accepted packets and a list of detected errors """ error_list = [] parent = tree_path[0] remain = Robdd.false() for i in xrange(1, len(tree_path)): acl_list = NetworkGraph.NetworkGraph().get_acl_list( src=tree_path[i][0], dst=parent) # test is leaf if len(tree_path[i]) == 1: res_remain, res_error = self._distributed_detection( acl_list, Robdd.true(), tree_path[i]) res_error = [] else: res_remain, res_error = self._tree_parse_detection( tree_path[i]) error_list += res_error res_remain, res_error = self._distributed_detection( acl_list, res_remain, tree_path[i]) error_list += res_error remain = synthesize(remain, Bdd.OR, res_remain) return remain, error_list
def toBDD(self): """Compute rhe ROBDD of the rule if rule_robdd is None else return rule_robdd Return ------ Return the ROBDD """ if self.rule_robdd is None: rule_robdd = Robdd.true() protocol_bdd = Robdd.false() ip_src_bdd = Robdd.false() port_src_bdd = Robdd.false() ip_dst_bdd = Robdd.false() port_dst_bdd = Robdd.false() for i in self.protocol: protocol_bdd = synthesize(protocol_bdd, Bdd.OR, i.toBDD(0)) if self.protocol: rule_robdd = synthesize(rule_robdd, Bdd.AND, protocol_bdd) for i in self.ip_source: ip_src_bdd = synthesize(ip_src_bdd, Bdd.OR, i.toBDD(8)) if self.ip_source: rule_robdd = synthesize(rule_robdd, Bdd.AND, ip_src_bdd) for i in self.port_source: port_src_bdd = synthesize(port_src_bdd, Bdd.OR, i.toBDD(40)) if self.port_source: rule_robdd = synthesize(rule_robdd, Bdd.AND, port_src_bdd) for i in self.ip_dest: ip_dst_bdd = synthesize(ip_dst_bdd, Bdd.OR, i.toBDD(56)) if self.ip_dest: rule_robdd = synthesize(rule_robdd, Bdd.AND, ip_dst_bdd) for i in self.port_dest: port_dst_bdd = synthesize(port_dst_bdd, Bdd.OR, i.toBDD(88)) if self.port_dest: rule_robdd = synthesize(rule_robdd, Bdd.AND, port_dst_bdd) self.rule_robdd = rule_robdd return self.rule_robdd
def toBDD(self): """Compute rhe ROBDD of the rule if rule_robdd is None else return rule_robdd Return ------ Return the ROBDD """ if self.rule_robdd is None: rule_robdd = Robdd.true() protocol_bdd = Robdd.false() ip_src_bdd = Robdd.false() port_src_bdd = Robdd.false() ip_dst_bdd = Robdd.false() port_dst_bdd = Robdd.false() for i in self.protocol: protocol_bdd = synthesize(protocol_bdd, Bdd.OR, i.toBDD(0)) if self.protocol: rule_robdd = synthesize(rule_robdd, Bdd.AND, protocol_bdd) for i in self.ip_source: ip_src_bdd = synthesize(ip_src_bdd, Bdd.OR, i.toBDD(8)) if self.ip_source: rule_robdd = synthesize(rule_robdd, Bdd.AND, ip_src_bdd) for i in self.port_source: port_src_bdd = synthesize(port_src_bdd, Bdd.OR, i.toBDD(40)) if self.port_source: rule_robdd = synthesize(rule_robdd, Bdd.AND, port_src_bdd) for i in self.ip_dest: ip_dst_bdd = synthesize(ip_dst_bdd, Bdd.OR, i.toBDD(56)) if self.ip_dest: rule_robdd = synthesize(rule_robdd, Bdd.AND, ip_dst_bdd) for i in self.port_dest: port_dst_bdd = synthesize(port_dst_bdd, Bdd.OR, i.toBDD(88)) if self.port_dest: rule_robdd = synthesize(rule_robdd, Bdd.AND, port_dst_bdd) self.rule_robdd = rule_robdd return self.rule_robdd
def detect_anomaly(self): """Detect internal anomaly. Return ------ Return the list of detected errors """ t0 = time.time() result = [] jobs = [] result_queue = multiprocessing.Queue() processed_id_rules = multiprocessing.Queue() acl_list = get_rule_path(self.firewall) # create multiprocess jobs for acl in self.firewall.acl: jobs.append(multiprocessing.Process(target=_detect_anomaly, args=(acl, [], [], [], Robdd.true(), Robdd.false(), Robdd.false(), result_queue, processed_id_rules, self.deep_search))) MyGtk.Gtk_Main.Gtk_Main().create_progress_bar("Anomaly detection", sum([len(a) for a in acl_list]), self._cancel_detection, *(jobs)) # start jobs for job in jobs: job.start() # empty queue while reduce(lambda x, y: x | y, [job.is_alive() for job in jobs], False): result += [result_queue.get() for _ in xrange(result_queue.qsize())] processed = reduce(lambda x, _: x + 1, [processed_id_rules.get() for _ in xrange(processed_id_rules.qsize())], 0) MyGtk.Gtk_Main.Gtk_Main().update_progress_bar(processed) MyGtk.Gtk_Main.Gtk_Main().update_interface() time.sleep(0.1) # wait jobs finish for job in jobs: job.join() result += [result_queue.get() for i in xrange(result_queue.qsize())] self.result = result t1 = time.time() MyGtk.Gtk_Main.Gtk_Main().change_statusbar('Anomaly internal detection process in %.3f secondes' % (t1 - t0)) MyGtk.Gtk_Main.Gtk_Main().destroy_progress_bar() return result
def _distributed_detection(self, acl_list, remain, tree_path): """Detection method for a given acl with a given remain ROBDD. This algorithm is derived from the algorithm of Fireman. For more informations read : - Firewall Policy Advisor for Anomaly Detection and rules analysis, http://www.arc.uncc.edu/pubs/im03-cr.pdf - FIREMAN : A Toolkit for FIREwall Modeling and ANalysis, http://www.cs.ucdavis.edu/~su/publications/fireman.pdf Parameters ---------- acl : Rule list. The rule list to test remain : ROBDD. The remaining ROBDD Return ------ Return a tuple of remaining rules and the list error found in this context """ accept_robdd_list = [] error_list = deque() error_list_append = error_list.append for acl in acl_list: for rule_path in acl.get_rules_path(): accept = Robdd.false() deny = Robdd.false() if self.cancel: break for rule, action in rule_path: if self.cancel: break Gtk.Gtk_Main.Gtk_Main().update_progress_bar(1) Gtk.Gtk_Main.Gtk_Main().update_interface() error_rules = [] rule_action = rule.action.chain if isinstance( rule.action.chain, bool) else action if rule_action: # P ⊆ I if compare_bdd(rule.toBDD(), Bdd.IMPL, remain): pass # P ⊆ ¬I elif compare_bdd(rule.toBDD(), Bdd.IMPL, negate_bdd(remain)): if self.deep_search: # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ <Px, deny> such that Px ∩ Pj != ∅ error_rules = self.search_rules( rule, Bdd.AND, False, tree_path) error_list_append( AnomalyError.error_message( ErrorType.DIST_SHADOW, ErrorType.ERROR, rule, error_rules)) # P ∩ I != ∅ else: if self.deep_search: # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ Px such that Px ∩ Pj != ∅ error_rules = self.search_rules( rule, Bdd.AND, None, tree_path) error_list_append( AnomalyError.error_message( ErrorType.DIST_CORRELATE, ErrorType.WARNING, rule, error_rules)) else: # P ⊆ I if compare_bdd(rule.toBDD(), Bdd.IMPL, remain): if self.deep_search: # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ <Px, accept> such that Px ∩ Pj != ∅ error_rules = self.search_rules( rule, Bdd.AND, True, tree_path) error_list_append( AnomalyError.error_message( ErrorType.DIST_RAISED, ErrorType.WARNING, rule, error_rules)) # P ⊆ ¬I elif compare_bdd(rule.toBDD(), Bdd.IMPL, negate_bdd(remain)): if self.deep_search: # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ <Px, deny> such that Px ∩ Pj != ∅ error_rules = self.search_rules( rule, Bdd.AND, False, tree_path) error_list_append( AnomalyError.error_message( ErrorType.DIST_REDUNDANT, ErrorType.WARNING, rule, error_rules)) # P ∩ I != ∅ else: if self.deep_search: # ∀ ACLx < ACLj, ∀ x ∈ ACLx such that Px ∩ Pj != ∅ error_rules = self.search_rules( rule, Bdd.AND, None, tree_path) error_list_append( AnomalyError.error_message( ErrorType.DIST_CORRELATE, ErrorType.WARNING, rule, error_rules)) # update value if rule.action.is_chained() or rule.action.is_return(): if action: # D = D ∪ ¬(A ∪ P) = D ∪ (¬A ∩ ¬P) deny = synthesize( deny, Bdd.OR, negate_bdd( synthesize(accept, Bdd.OR, rule.toBDD()))) else: # D = D ∪ (¬A ∩ P) deny = synthesize( deny, Bdd.OR, synthesize(negate_bdd(accept), Bdd.AND, rule.toBDD())) else: if rule.action.chain: # A = A ∪ (¬D ∩ P) accept = synthesize( accept, Bdd.OR, synthesize(negate_bdd(deny), Bdd.AND, rule.toBDD())) else: # D = D ∪ (¬A ∩ P) deny = synthesize( deny, Bdd.OR, synthesize(negate_bdd(accept), Bdd.AND, rule.toBDD())) accept_robdd_list.append(accept) res_accept = Robdd.false() for a in accept_robdd_list: res_accept = synthesize(res_accept, Bdd.OR, a) return res_accept, error_list
def _distributed_detection(self, acl_list, remain, tree_path): """Detection method for a given acl with a given remain ROBDD. This algorithm is derived from the algorithm of Fireman. For more informations read : - Firewall Policy Advisor for Anomaly Detection and rules analysis, http://www.arc.uncc.edu/pubs/im03-cr.pdf - FIREMAN : A Toolkit for FIREwall Modeling and ANalysis, http://www.cs.ucdavis.edu/~su/publications/fireman.pdf Parameters ---------- acl : Rule list. The rule list to test remain : ROBDD. The remaining ROBDD Return ------ Return a tuple of remaining rules and the list error found in this context """ accept_robdd_list = [] error_list = deque() error_list_append = error_list.append for acl in acl_list: for rule_path in acl.get_rules_path(): accept = Robdd.false() deny = Robdd.false() if self.cancel: break for rule, action in rule_path: if self.cancel: break Gtk.Gtk_Main.Gtk_Main().update_progress_bar(1) Gtk.Gtk_Main.Gtk_Main().update_interface() error_rules = [] rule_action = rule.action.chain if isinstance(rule.action.chain, bool) else action if rule_action: # P ⊆ I if compare_bdd(rule.toBDD(), Bdd.IMPL, remain): pass # P ⊆ ¬I elif compare_bdd(rule.toBDD(), Bdd.IMPL, negate_bdd(remain)): if self.deep_search: # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ <Px, deny> such that Px ∩ Pj != ∅ error_rules = self.search_rules(rule, Bdd.AND, False, tree_path) error_list_append( AnomalyError.error_message(ErrorType.DIST_SHADOW, ErrorType.ERROR, rule, error_rules)) # P ∩ I != ∅ else: if self.deep_search: # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ Px such that Px ∩ Pj != ∅ error_rules = self.search_rules(rule, Bdd.AND, None, tree_path) error_list_append( AnomalyError.error_message(ErrorType.DIST_CORRELATE, ErrorType.WARNING, rule, error_rules)) else: # P ⊆ I if compare_bdd(rule.toBDD(), Bdd.IMPL, remain): if self.deep_search: # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ <Px, accept> such that Px ∩ Pj != ∅ error_rules = self.search_rules(rule, Bdd.AND, True, tree_path) error_list_append( AnomalyError.error_message(ErrorType.DIST_RAISED, ErrorType.WARNING, rule, error_rules)) # P ⊆ ¬I elif compare_bdd(rule.toBDD(), Bdd.IMPL, negate_bdd(remain)): if self.deep_search: # ∀ ACLx < ACLj, ∀ x ∈ ACLx, ∃ <Px, deny> such that Px ∩ Pj != ∅ error_rules = self.search_rules(rule, Bdd.AND, False, tree_path) error_list_append( AnomalyError.error_message(ErrorType.DIST_REDUNDANT, ErrorType.WARNING, rule, error_rules)) # P ∩ I != ∅ else: if self.deep_search: # ∀ ACLx < ACLj, ∀ x ∈ ACLx such that Px ∩ Pj != ∅ error_rules = self.search_rules(rule, Bdd.AND, None, tree_path) error_list_append( AnomalyError.error_message(ErrorType.DIST_CORRELATE, ErrorType.WARNING, rule, error_rules)) # update value if rule.action.is_chained() or rule.action.is_return(): if action: # D = D ∪ ¬(A ∪ P) = D ∪ (¬A ∩ ¬P) deny = synthesize(deny, Bdd.OR, negate_bdd(synthesize(accept, Bdd.OR, rule.toBDD()))) else: # D = D ∪ (¬A ∩ P) deny = synthesize(deny, Bdd.OR, synthesize(negate_bdd(accept), Bdd.AND, rule.toBDD())) else: if rule.action.chain: # A = A ∪ (¬D ∩ P) accept = synthesize(accept, Bdd.OR, synthesize(negate_bdd(deny), Bdd.AND, rule.toBDD())) else: # D = D ∪ (¬A ∩ P) deny = synthesize(deny, Bdd.OR, synthesize(negate_bdd(accept), Bdd.AND, rule.toBDD())) accept_robdd_list.append(accept) res_accept = Robdd.false() for a in accept_robdd_list: res_accept = synthesize(res_accept, Bdd.OR, a) return res_accept, error_list
def detect_anomaly(self): """Detect internal anomaly. Return ------ Return the list of detected errors """ t0 = time.time() result = [] jobs = [] result_queue = multiprocessing.Queue() processed_id_rules = multiprocessing.Queue() acl_list = get_rule_path(self.firewall) # create multiprocess jobs for acl in self.firewall.acl: jobs.append( multiprocessing.Process( target=_detect_anomaly, args=( acl, [], [], [], Robdd.true(), Robdd.false(), Robdd.false(), result_queue, processed_id_rules, self.deep_search, ), ) ) Gtk.Gtk_Main.Gtk_Main().create_progress_bar( "Anomaly detection", sum([len(a) for a in acl_list]), self._cancel_detection, *(jobs) ) # start jobs for job in jobs: job.start() # empty queue while reduce(lambda x, y: x | y, [job.is_alive() for job in jobs], False): result += [result_queue.get() for _ in xrange(result_queue.qsize())] processed = reduce( lambda x, _: x + 1, [processed_id_rules.get() for _ in xrange(processed_id_rules.qsize())], 0 ) Gtk.Gtk_Main.Gtk_Main().update_progress_bar(processed) Gtk.Gtk_Main.Gtk_Main().update_interface() time.sleep(0.1) # wait jobs finish for job in jobs: job.join() result += [result_queue.get() for i in xrange(result_queue.qsize())] self.result = result t1 = time.time() Gtk.Gtk_Main.Gtk_Main().change_statusbar("Anomaly internal detection process in %.3f secondes" % (t1 - t0)) Gtk.Gtk_Main.Gtk_Main().destroy_progress_bar() return result
def _detect_anomaly(rules, result_queue, processed_id_rules, deep_search): """Detect anomaly of the given rule set. This algorithm is derived from the algorithm of Fireman. It uses ROBDD to compare each rules. The complexity of this algorithm is in O(n). For more informations read : - Firewall Policy Advisor for Anomaly Detection and rules analysis, http://www.arc.uncc.edu/pubs/im03-cr.pdf - FIREMAN : A Toolkit for FIREwall Modeling and ANalysis, http://www.cs.ucdavis.edu/~su/publications/fireman.pdf Parameters ---------- rules : Rule list. The list of rule to inspect result_queue : multiprocessing Queue. A queue to put errors """ remain = Robdd.true() accept = Robdd.false() deny = Robdd.false() error_list = deque() error_list_append = error_list.append for rule in rules: processed_id_rules.put(rule.identifier) error_rules = deque() # Pj ⊆ Rj if compare_bdd(rule.toBDD(), Bdd.IMPL, remain): pass else: # Pj ∩ Rj = ∅ if not compare_bdd(rule.toBDD(), Bdd.AND, remain): # Pj ⊆ Dj if compare_bdd(rule.toBDD(), Bdd.IMPL, (deny if rule.action else accept)): if deep_search: for r in rules: if r == rule: break # ∀ x < j, ∃ <Px, deny> such that Px ∩ Pj != ∅ if r.action != rule.action and compare_bdd( r.toBDD(), Bdd.AND, rule.toBDD()): error_rules.append(r) error_list_append( AnomalyError.error_message(ErrorType.INT_MASK_SHADOW, ErrorType.ERROR, rule, error_rules)) # Pj ∩ Dj = ∅ elif not compare_bdd(rule.toBDD(), Bdd.AND, (deny if rule.action else accept)): if deep_search: for r in rules: if r == rule: break # ∀ x < j, ∃ <Px, accept> such that Px ∩ Pj != ∅ if r.action == rule.action and compare_bdd( r.toBDD(), Bdd.AND, rule.toBDD()): error_rules.append(r) error_list_append( AnomalyError.error_message( ErrorType.INT_MASK_REDUNDANT, ErrorType.ERROR, rule, error_rules)) else: if deep_search: for r in rules: if r == rule: break # ∀ x < j, ∃ Px such that Px ∩ Pj != ∅ if compare_bdd(r.toBDD(), Bdd.AND, rule.toBDD()): error_rules.append(r) error_list_append( AnomalyError.error_message( ErrorType.INT_MASK_REDUNDANT_CORRELATION, ErrorType.ERROR, rule, error_rules)) else: error_redudant = deque() error_generalization = deque() if deep_search: # if deep search try to distinguish overlap of generalization or redundancy for r in rules: if r == rule: break # ∀ x < j, ∃ <Px, deny> such that Px ⊆ Pj if r.action != rule.action and compare_bdd( r.toBDD(), Bdd.IMPL, rule.toBDD()): error_generalization.append(r) # ∀ x < j, ∃ <Px, accept> such that Px ⊆ Pj elif r.action == rule.action and compare_bdd( r.toBDD(), Bdd.IMPL, rule.toBDD()): error_redudant.append(r) elif compare_bdd(r.toBDD(), Bdd.AND, rule.toBDD()): error_rules.append(r) if error_redudant: error_list_append( AnomalyError.error_message( ErrorType.INT_PART_REDUNDANT, ErrorType.ERROR, rule, error_redudant)) if error_generalization: error_list_append( AnomalyError.error_message( ErrorType.INT_PART_GENERALIZATION, ErrorType.WARNING, rule, error_generalization)) if error_rules: error_list_append( AnomalyError.error_message( ErrorType.INT_PART_CORRELATION, ErrorType.WARNING, rule, error_rules)) else: error_list_append( AnomalyError.error_message( ErrorType.INT_PART_CORRELATION, ErrorType.WARNING, rule, error_rules)) if rule.action: accept = synthesize(accept, Bdd.OR, synthesize(remain, Bdd.AND, rule.toBDD())) else: deny = synthesize(deny, Bdd.OR, synthesize(remain, Bdd.AND, rule.toBDD())) remain = synthesize(Robdd.true(), Bdd.AND, negate_bdd(synthesize(accept, Bdd.OR, deny))) result_queue.put(error_list)
def _detect_anomaly(rules, result_queue, processed_id_rules, deep_search): """Detect anomaly of the given rule set. This algorithm is derived from the algorithm of Fireman. It uses ROBDD to compare each rules. The complexity of this algorithm is in O(n). For more informations read : - Firewall Policy Advisor for Anomaly Detection and rules analysis, http://www.arc.uncc.edu/pubs/im03-cr.pdf - FIREMAN : A Toolkit for FIREwall Modeling and ANalysis, http://www.cs.ucdavis.edu/~su/publications/fireman.pdf Parameters ---------- rules : Rule list. The list of rule to inspect result_queue : multiprocessing Queue. A queue to put errors """ remain = Robdd.true() accept = Robdd.false() deny = Robdd.false() error_list = deque() error_list_append = error_list.append for rule in rules: processed_id_rules.put(rule.identifier) error_rules = deque() # Pj ⊆ Rj if compare_bdd(rule.toBDD(), Bdd.IMPL, remain): pass else: # Pj ∩ Rj = ∅ if not compare_bdd(rule.toBDD(), Bdd.AND, remain): # Pj ⊆ Dj if compare_bdd(rule.toBDD(), Bdd.IMPL, (deny if rule.action else accept)): if deep_search: for r in rules: if r == rule: break # ∀ x < j, ∃ <Px, deny> such that Px ∩ Pj != ∅ if r.action != rule.action and compare_bdd(r.toBDD(), Bdd.AND, rule.toBDD()): error_rules.append(r) error_list_append(AnomalyError.error_message(ErrorType.INT_MASK_SHADOW, ErrorType.ERROR, rule, error_rules)) # Pj ∩ Dj = ∅ elif not compare_bdd(rule.toBDD(), Bdd.AND, (deny if rule.action else accept)): if deep_search: for r in rules: if r == rule: break # ∀ x < j, ∃ <Px, accept> such that Px ∩ Pj != ∅ if r.action == rule.action and compare_bdd(r.toBDD(), Bdd.AND, rule.toBDD()): error_rules.append(r) error_list_append(AnomalyError.error_message(ErrorType.INT_MASK_REDUNDANT, ErrorType.ERROR, rule, error_rules)) else: if deep_search: for r in rules: if r == rule: break # ∀ x < j, ∃ Px such that Px ∩ Pj != ∅ if compare_bdd(r.toBDD(), Bdd.AND, rule.toBDD()): error_rules.append(r) error_list_append(AnomalyError.error_message(ErrorType.INT_MASK_REDUNDANT_CORRELATION, ErrorType.ERROR, rule, error_rules)) else: error_redudant = deque() error_generalization = deque() if deep_search: # if deep search try to distinguish overlap of generalization or redundancy for r in rules: if r == rule: break # ∀ x < j, ∃ <Px, deny> such that Px ⊆ Pj if r.action != rule.action and compare_bdd(r.toBDD(), Bdd.IMPL, rule.toBDD()): error_generalization.append(r) # ∀ x < j, ∃ <Px, accept> such that Px ⊆ Pj elif r.action == rule.action and compare_bdd(r.toBDD(), Bdd.IMPL, rule.toBDD()): error_redudant.append(r) elif compare_bdd(r.toBDD(), Bdd.AND, rule.toBDD()): error_rules.append(r) if error_redudant: error_list_append(AnomalyError.error_message(ErrorType.INT_PART_REDUNDANT, ErrorType.ERROR, rule, error_redudant)) if error_generalization: error_list_append(AnomalyError.error_message(ErrorType.INT_PART_GENERALIZATION, ErrorType.WARNING, rule, error_generalization)) if error_rules: error_list_append(AnomalyError.error_message(ErrorType.INT_PART_CORRELATION, ErrorType.WARNING, rule, error_rules)) else: error_list_append(AnomalyError.error_message(ErrorType.INT_PART_CORRELATION, ErrorType.WARNING, rule, error_rules)) if rule.action: accept = synthesize(accept, Bdd.OR, synthesize(remain, Bdd.AND, rule.toBDD())) else: deny = synthesize(deny, Bdd.OR, synthesize(remain, Bdd.AND, rule.toBDD())) remain = synthesize(Robdd.true(), Bdd.AND, negate_bdd(synthesize(accept, Bdd.OR, deny))) result_queue.put(error_list)