Example #1
0
def _detect_anomaly_n2(rules, result_queue):
    """Detect anomaly of the given rule set.
    This algorithm is a light version who compare rules 2 by 2.
    It uses ROBDD to compare relation between each rules.
    The complexity of this algorithm is in O(n^2).

    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
    """
    error_list = deque()
    error_list_append = error_list.append

    for x in xrange(len(rules)):
        rx = rules[x]
        y = x + 1
        while y < len(rules):
            ry = rules[y]
            # Rx ∩ Ry = ∅
            if not compare_bdd(rx.toBDD(), Bdd.AND, ry.toBDD()):
                pass
            # Ry ⊆ Rx
            elif compare_bdd(rx.toBDD(), Bdd.IMPL, ry.toBDD()):
                error_list_append(
                    AnomalyError.error_message(ErrorType.INT_MASK_SHADOW,
                                               ErrorType.ERROR, ry, rx))
            # Rx ⊆ Ry
            elif compare_bdd(ry.toBDD(), Bdd.IMPL, rx.toBDD()):
                error_list_append(
                    AnomalyError.error_message(
                        ErrorType.INT_PART_GENERALIZATION, ErrorType.WARNING,
                        rx, ry))
            # Rx ∩ Ry != ∅
            else:
                error_list_append(
                    AnomalyError.error_message(ErrorType.INT_PART_CORRELATION,
                                               ErrorType.ERROR, rx, ry))
            y += 1

    result_queue.put(error_list)
Example #2
0
def _detect_anomaly_n2(rules, result_queue):
    """Detect anomaly of the given rule set.
    This algorithm is a light version who compare rules 2 by 2.
    It uses ROBDD to compare relation between each rules.
    The complexity of this algorithm is in O(n^2).

    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
    """
    error_list = deque()
    error_list_append = error_list.append

    for x in xrange(len(rules)):
        rx = rules[x]
        y = x + 1
        while y < len(rules):
            ry = rules[y]
            # Rx ∩ Ry = ∅
            if not compare_bdd(rx.toBDD(), Bdd.AND, ry.toBDD()):
                pass
            # Ry ⊆ Rx
            elif compare_bdd(rx.toBDD(), Bdd.IMPL, ry.toBDD()):
                error_list_append(AnomalyError.error_message(ErrorType.INT_MASK_SHADOW, ErrorType.ERROR, ry, rx))
            # Rx ⊆ Ry
            elif compare_bdd(ry.toBDD(), Bdd.IMPL, rx.toBDD()):
                error_list_append(
                    AnomalyError.error_message(ErrorType.INT_PART_GENERALIZATION, ErrorType.WARNING, rx, ry)
                )
            # Rx ∩ Ry != ∅
            else:
                error_list_append(AnomalyError.error_message(ErrorType.INT_PART_CORRELATION, ErrorType.ERROR, rx, ry))
            y += 1

    result_queue.put(error_list)
Example #3
0
def _classify_anomaly(rule, rules, remain, accept, deny, result_queue, 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
    ----------
    rule : Rule. The rule to inspect
    rules : Rule list. List of preceding rule.
    result_queue : multiprocessing Queue. A queue to put errors
    """
    error_list = deque()
    error_list_append = error_list.append
    error_rules = deque()

    # Pj ⊆ Rj
    if compare_bdd(rule.toBDD(), Bdd.IMPL, remain):
        return
    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.chain else accept)):
                if deep_search:
                    for r, a, b in rules:
                        # ∀ x < j, ∃ <Px, deny> such that Px ∩ Pj != ∅
                        if a != rule.action.chain and compare_bdd(b, 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.chain else accept)):
                if deep_search:
                    for r, a, b in rules:
                        # ∀ x < j, ∃ <Px, accept> such that Px ∩ Pj != ∅
                        if a == rule.action.chain and compare_bdd(b, 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, a, b in rules:
                        # ∀ x < j, ∃ Px such that Px ∩ Pj != ∅
                        if compare_bdd(b, 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_redundant = deque()
            error_generalization = deque()
            if deep_search:
                # if deep search try to distinguish overlap of generalization or redundancy
                for r, a, b in rules:
                    # ∀ x < j, ∃ <Px, deny> such that Px ⊆ Pj
                    if a != rule.action.chain and compare_bdd(b, Bdd.IMPL, rule.toBDD()):
                        error_generalization.append(r)
                    # ∀ x < j, ∃ <Px, accept> such that Px ⊆ Pj
                    elif a == rule.action.chain and compare_bdd(b, Bdd.IMPL, rule.toBDD()):
                        error_redundant.append(r)
                    elif compare_bdd(b, Bdd.AND, rule.toBDD()):
                        error_rules.append(r)
                if error_redundant:
                    error_list_append(
                        AnomalyError.error_message(ErrorType.INT_PART_REDUNDANT, ErrorType.ERROR, rule, error_redundant))
                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))

    result_queue.put(error_list)
Example #4
0
    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
Example #6
0
def _classify_anomaly(rule, rules, remain, accept, deny, result_queue, 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
    ----------
    rule : Rule. The rule to inspect
    rules : Rule list. List of preceding rule.
    result_queue : multiprocessing Queue. A queue to put errors
    """
    error_list = deque()
    error_list_append = error_list.append
    error_rules = deque()

    # Pj ⊆ Rj
    if compare_bdd(rule.toBDD(), Bdd.IMPL, remain):
        return
    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.chain else accept)):
                if deep_search:
                    for r, a, b in rules:
                        # ∀ x < j, ∃ <Px, deny> such that Px ∩ Pj != ∅
                        if a != rule.action.chain and compare_bdd(b, 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.chain else accept)):
                if deep_search:
                    for r, a, b in rules:
                        # ∀ x < j, ∃ <Px, accept> such that Px ∩ Pj != ∅
                        if a == rule.action.chain and compare_bdd(b, 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, a, b in rules:
                        # ∀ x < j, ∃ Px such that Px ∩ Pj != ∅
                        if compare_bdd(b, 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_redundant = deque()
            error_generalization = deque()
            if deep_search:
                # if deep search try to distinguish overlap of generalization or redundancy
                for r, a, b in rules:
                    # ∀ x < j, ∃ <Px, deny> such that Px ⊆ Pj
                    if a != rule.action.chain and compare_bdd(b, Bdd.IMPL, rule.toBDD()):
                        error_generalization.append(r)
                    # ∀ x < j, ∃ <Px, accept> such that Px ⊆ Pj
                    elif a == rule.action.chain and compare_bdd(b, Bdd.IMPL, rule.toBDD()):
                        error_redundant.append(r)
                    elif compare_bdd(b, Bdd.AND, rule.toBDD()):
                        error_rules.append(r)
                if error_redundant:
                    error_list_append(
                        AnomalyError.error_message(ErrorType.INT_PART_REDUNDANT, ErrorType.ERROR, rule, error_redundant)
                    )
                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)
                )

    result_queue.put(error_list)
Example #7
0
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)