예제 #1
0
    def evaluate_simple_operand_with_operation(simple_operand,
                                               operation,
                                               check_nested_NOT=False):
        """If the simple operand is allowed append it to all the allowed terms,
        else put it at the start.

        NOTE: All nested OR's terms are expected to be allowed!
        """
        result = []
        if simple_operand.allow:
            for op_term in operation:
                if op_term.allow:
                    op_term.members.append(simple_operand)
                elif check_nested_NOT:
                    raise errors.UnimplementedError("No support for nested "
                                                    "operation which includes "
                                                    "NOT!")
                result.append(op_term)
        else:
            term = Term(simple_operand.allow)
            term.members = [simple_operand]
            result.append(term)
            for op_term in operation:
                if check_nested_NOT and not op_term.allow:
                    raise errors.UnimplementedError("No support for nested "
                                                    "operation which includes "
                                                    "NOT!")
                else:
                    result.append(op_term)
        return result
예제 #2
0
def _NOT(queue):
    """Performs the NOT functionality of RPSL on queue's next node.

    .. warning:: Currently supports only NOT'ing a single operand.
    """

    try:
        a = queue.pop()
        if a[0] in ['AND', 'OR']:
            raise errors.UnimplementedError("NOT'ing a non simple operand is "
                                            "not yet suported!")
        a, a_has_nested_operation = _execute_node(a, queue)
    except IndexError:
        raise errors.FilterCompositionError("Not enough operands for "
                                            "operation <NOT>!")

    if a[0] in ['AND', 'OR']:
        pass
        # XXX Not supported functionality! Keep here for now!
        # result = deque()
        # for term in a[1]:
        #    if term.allow:
        #        for member in term.members:
        #            new_term = Term(not term.allow)
        #            new_term.members = [member]
        #            result.appendleft(new_term)
        #    else:
        #        term.allow = not term.allow
        #        result.append(term)
        # return (a[0], result)
    else:
        a[1].allow = False
        return ((a[0], a[1]), a_has_nested_operation)
예제 #3
0
    def evaluate_AND_with_AND(and_operation_1, and_operation_2):
        """The result is populated with all the terms.

        NOTE: All the nested AND's terms are expected to be allowed!
        """
        result = []
        for and_operation in [and_operation_1, and_operation_2]:
            for and_term in and_operation:
                if and_term.allow:
                    result.append(and_term)
                else:
                    raise errors.UnimplementedError("No support for nested "
                                                    "operation which includes "
                                                    "NOT!")
        return result
예제 #4
0
    def visit(self, expression):
        hook = self._hooks.get(expression.operation)

        if hook:
            if hook.type == 1:
                return hook(self, expression)

            else:
                hook(self, expression)

        result = super(LLILVisitor, self).visit(expression)

        if result is None:
            raise errors.UnimplementedError(expression.operation)

        return result
예제 #5
0
    def evaluate_AND_with_OR(and_operation, or_operation):
        """Move the AND's terms to the result and add the OR's terms;
        allowed at the front, denied at the rear.

        NOTE: All the nested AND's terms are expected to be allowed!
        """
        result = deque()
        for and_term in and_operation:
            if and_term.allow:
                result.append(and_term)
            else:
                raise errors.UnimplementedError("No support for nested "
                                                "operation which includes "
                                                "NOT!")
        for or_term in or_operation:
            if or_term.allow:
                result.appendleft(or_term)
            else:
                result.append(or_term)
        return result
예제 #6
0
    def evaluate_AND_with_OR(and_operation, or_operation):
        """For every OR's term and every allowed AND's term create a new term
        with both members.

        NOTE: All the nested OR's terms are expected to be allowed!
        """
        result = []
        for and_term in and_operation:
            if and_term.allow:
                for or_term in or_operation:
                    if or_term.allow:
                        new_term = copy.deepcopy(and_term)
                        new_term.members.extend(or_term.members)
                        result.append(new_term)
                    else:
                        raise errors.UnimplementedError("No support for "
                                                        "nested operation "
                                                        "which includes NOT!")
            else:
                result.append(and_term)
        return result
예제 #7
0
    def evaluate_simple_operand_with_operation(simple_operand,
                                               operation,
                                               check_nested_NOT=False):
        """Put the simple operand at the front or rear of the result depending
        on its policy.

        NOTE: All nested AND's terms are expected to be allowed!
        """
        result = deque()
        for op_term in operation:
            if check_nested_NOT and not op_term.allow:
                raise errors.UnimplementedError("No support for nested "
                                                "operation which includes "
                                                "NOT!")
            else:
                result.append(op_term)
        term = Term(simple_operand.allow)
        term.members = [simple_operand]
        if term.allow:
            result.appendleft(term)
        else:
            result.append(term)
        return result
예제 #8
0
def _get_tokens(filter_text, ASes, AS_sets, RS_sets):
    """Constructs a list of identified tokens to be used by the Shunting-Yard
    algorithm.

    Additional actions:
        - Inserts 'OR' where it is ommited to ease calculation later.
        - Updates the given sets with seen values.

    Parameters
    ----------
    filter_text : str
        The filter expression.
    ASes : set
        The set to update with AS values.
    AS_sets : set
        The set to update with AS_set values.
    RS_sets : set
        The set to update with RS_set values.

    Returns
    -------
    identified_tokens : list
        The identified tokens.

    Raises
    ------
    FilterAnalysisError
    UnimplementedError
    """
    inside_ASPATH = False
    inside_PREFIX = False
    identified_tokens = []

    # Used to determine if the previously pushed identified token was an
    # operator (e.g., 'OR') or a term (e.g., AS, AS-PATH, group of terms).
    pushed_term = False

    tokens = _explode_filter(filter_text).strip().split()
    for token in tokens:
        if token == ASPATH_END:
            if not inside_ASPATH:
                raise errors.FilterAnalysisError("Could not analyze AS-PATH!")

            identified_tokens[-1][1].append(token)
            inside_ASPATH = False
            pushed_term = True

        elif inside_ASPATH:
            if not rpsl.is_as_path_member(token):
                raise errors.FilterAnalysisError("Not a valid member of "
                                                 "AS-PATH: "
                                                 "'{}'!".format(token))

            identified_tokens[-1][1].append(token)
            pushed_term = False

        # The PREFIX_END may be followed by a range operator.
        elif token[0] == PREFIX_END:
            if not inside_PREFIX:
                raise errors.FilterAnalysisError("Could not analyze PREFIX!")

            if token[1:]:
                identified_tokens[-1][1].append(token[1:])

            inside_PREFIX = False
            pushed_term = True

        elif inside_PREFIX:
            l, sep, r = token.rpartition(',')
            if l and sep:
                token = l

            if not rpsl.is_pfx(token):
                raise errors.FilterAnalysisError("Invalid member inside "
                                                 "PREFIX list: "
                                                 "'{}'!".format(token))

            identified_tokens[-1][1].append(token)
            pushed_term = False

        elif token in ['AND', 'OR']:
            identified_tokens.append((token, ops[token]))
            pushed_term = False

        elif token == GROUP_END:
            identified_tokens.append(
                (token, op_details(precedence=0, associativity='Left')))
            pushed_term = True

        else:
            if pushed_term:
                identified_tokens.append(('OR', ops['OR']))

            if token == 'NOT':
                identified_tokens.append((token, ops[token]))
                pushed_term = False

            elif token == GROUP_START:
                identified_tokens.append(
                    (token, op_details(precedence=0, associativity='Left')))
                pushed_term = False

            elif token == ASPATH_START:
                # No need to check if already inside an AS path. Members inside
                # an AS path are validated above.
                inside_ASPATH = True
                identified_tokens.append((AS_PATH, ['<']))
                pushed_term = False

            elif token == PREFIX_START:
                # No need to check if already inside a prefix list. Members
                # inside a prefix list are validated above.
                inside_PREFIX = True
                identified_tokens.append((PREFIX_LIST, []))
                pushed_term = False

            elif rpsl.is_ASN(token):
                identified_tokens.append((AS, token))
                ASes.add(token)
                pushed_term = True

            elif rpsl.is_AS_set(token):
                identified_tokens.append((AS_SET, token))
                AS_sets.add(token)
                pushed_term = True

            elif rpsl.is_rs_set(token):
                identified_tokens.append((RS_SET, token))
                RS_sets.add(token)
                pushed_term = True

            elif token == ANY:
                identified_tokens.append((ANY, token))
                pushed_term = True

            else:
                raise errors.UnimplementedError("Unimplemented element: "
                                                "'{}'!".format(token))

    if inside_ASPATH:
        raise errors.FilterAnalysisError("AS-PATH is not closed!")
    elif inside_PREFIX:
        raise errors.FilterAnalysisError("PREFIX is not closed!")

    return identified_tokens
예제 #9
0
def _OR(queue):
    """Performs the OR functionality of RPSL on the queue's next two nodes."""
    try:
        a = queue.pop()
        a, a_has_nested_operation = _execute_node(a, queue)
        b = queue.pop()
        b, b_has_nested_operation = _execute_node(b, queue)
    except IndexError:
        raise errors.FilterCompositionError("Not enough operands for "
                                            "operation <OR>!")

    if a[0] == 'AND' and a_has_nested_operation:
        raise errors.UnimplementedError("More depth in operations than we "
                                        "can handle!")
    elif b[0] == 'AND' and b_has_nested_operation:
        raise errors.UnimplementedError("More depth in operations than we "
                                        "can handle!")

    def evaluate_simple_operand_with_operation(simple_operand,
                                               operation,
                                               check_nested_NOT=False):
        """Put the simple operand at the front or rear of the result depending
        on its policy.

        NOTE: All nested AND's terms are expected to be allowed!
        """
        result = deque()
        for op_term in operation:
            if check_nested_NOT and not op_term.allow:
                raise errors.UnimplementedError("No support for nested "
                                                "operation which includes "
                                                "NOT!")
            else:
                result.append(op_term)
        term = Term(simple_operand.allow)
        term.members = [simple_operand]
        if term.allow:
            result.appendleft(term)
        else:
            result.append(term)
        return result

    def evaluate_AND_with_OR(and_operation, or_operation):
        """Move the AND's terms to the result and add the OR's terms;
        allowed at the front, denied at the rear.

        NOTE: All the nested AND's terms are expected to be allowed!
        """
        result = deque()
        for and_term in and_operation:
            if and_term.allow:
                result.append(and_term)
            else:
                raise errors.UnimplementedError("No support for nested "
                                                "operation which includes "
                                                "NOT!")
        for or_term in or_operation:
            if or_term.allow:
                result.appendleft(or_term)
            else:
                result.append(or_term)
        return result

    def evaluate_OR_with_OR(or_operation_1, or_operation_2):
        """The result is populated with all the terms. Allowed terms are put at
        the start.
        """
        result = deque()
        for or_operation in [or_operation_1, or_operation_2]:
            for or_term in or_operation:
                if or_term.allow:
                    result.appendleft(or_term)
                else:
                    result.append(or_term)
        return result

    def evaluate_AND_with_AND(and_operation_1, and_operation_2):
        """The result is populated with all the terms.

        NOTE: All the nested AND's terms are expected to be allowed!
        """
        result = []
        for and_operation in [and_operation_1, and_operation_2]:
            for and_term in and_operation:
                if and_term.allow:
                    result.append(and_term)
                else:
                    raise errors.UnimplementedError("No support for nested "
                                                    "operation which includes "
                                                    "NOT!")
        return result

    def handle_ANY(result):
        """Handles ANY's existence in the result.

        If ANY is a member of:
        - an allowed term, a term with ANY as its sole member is returned as
                           the result,
        - a non allowed term, that term is discarded.
        """
        for term in result:
            for term_member in term.members:
                if term_member.category == ANY:
                    if term.allow:
                        new_term = Term(term.allow)
                        new_term.members = [term_member]
                        result = [new_term]
                    else:
                        result = [t for t in result if t != term]
                    return result
        return result

    result = deque()
    simple_operands = []
    temp_result = []
    has_nested_operation = False

    # Operand 'a'
    if a[0] == 'OR':
        temp_result = a
    elif a[0] == 'AND':
        has_nested_operation = True
        temp_result = a
    elif a[0] == 'OPERAND':
        simple_operands.append(a[1])
    else:
        raise errors.FilterCompositionError("Unknown operand: "
                                            "'{}'".format(a[0]))

    # Operand 'b'
    if b[0] == 'OR':
        # If 'a' was a simple operand.
        if simple_operands:
            result = evaluate_simple_operand_with_operation(
                simple_operands.pop(), b[1])
        elif temp_result:
            # If 'a' was an OR operation.
            if temp_result[0] == 'OR':
                result = evaluate_OR_with_OR(temp_result[1], b[1])
            # If 'a' was an AND operation.
            elif temp_result[0] == 'AND':
                result = evaluate_AND_with_OR(temp_result[1], b[1])
            else:
                raise errors.FilterCompositionError("Unknown operation "
                                                    "'{}'".format(
                                                        temp_result[0]))

    elif b[0] == 'AND':
        has_nested_operation = True
        # If 'a' was a simple operand.
        if simple_operands:
            result = evaluate_simple_operand_with_operation(
                simple_operands.pop(), b[1], check_nested_NOT=True)
        elif temp_result:
            # If 'a' was an OR operation.
            if temp_result[0] == 'OR':
                result = evaluate_AND_with_OR(b[1], temp_result[1])
            elif temp_result[0] == 'AND':
                result = evaluate_AND_with_AND(b[1], temp_result[1])
            else:
                raise errors.FilterCompositionError("Unknown operation "
                                                    "'{}'".format(
                                                        temp_result[0]))

    elif b[0] == 'OPERAND':
        if temp_result:
            if temp_result[0] == 'OR':
                result = evaluate_simple_operand_with_operation(
                    b[1], temp_result[1])
            elif temp_result[0] == 'AND':
                result = evaluate_simple_operand_with_operation(
                    b[1], temp_result[1], check_nested_NOT=True)
            else:
                raise errors.FilterCompositionError("Unknown operation "
                                                    "'{}'".format(
                                                        temp_result[0]))
        # If both operands are simple also add this to the simple_operands
        # list.
        else:
            simple_operands.append(b[1])

    else:
        raise errors.FilterCompositionError("Unknown operand: "
                                            "'{}'".format(a[0]))

    # Only True when *both* operands are simple operands. Otherwise the simple
    # operands are consumed from the operations above.
    while simple_operands:
        simple_operand = simple_operands.pop()
        term = Term(simple_operand.allow)
        term.members = [simple_operand]
        if term.allow:
            result.appendleft(term)
        else:
            result.append(term)

    result = handle_ANY(result)

    return (('OR', result), has_nested_operation)
예제 #10
0
def _AND(queue):
    """Performs the AND functionality of RPSL on queue's next two nodes."""
    try:
        a = queue.pop()
        a, a_has_nested_operation = _execute_node(a, queue)
        b = queue.pop()
        b, b_has_nested_operation = _execute_node(b, queue)
    except IndexError:
        raise errors.FilterCompositionError("Not enough operands for "
                                            "operation <AND>!")

    if a[0] == 'OR' and a_has_nested_operation:
        raise errors.UnimplementedError("More depth in operations than we can "
                                        "handle!")
    elif b[0] == 'OR' and b_has_nested_operation:
        raise errors.UnimplementedError("More depth in operations than we can "
                                        "handle!")

    def evaluate_simple_operand_with_operation(simple_operand,
                                               operation,
                                               check_nested_NOT=False):
        """If the simple operand is allowed append it to all the allowed terms,
        else put it at the start.

        NOTE: All nested OR's terms are expected to be allowed!
        """
        result = []
        if simple_operand.allow:
            for op_term in operation:
                if op_term.allow:
                    op_term.members.append(simple_operand)
                elif check_nested_NOT:
                    raise errors.UnimplementedError("No support for nested "
                                                    "operation which includes "
                                                    "NOT!")
                result.append(op_term)
        else:
            term = Term(simple_operand.allow)
            term.members = [simple_operand]
            result.append(term)
            for op_term in operation:
                if check_nested_NOT and not op_term.allow:
                    raise errors.UnimplementedError("No support for nested "
                                                    "operation which includes "
                                                    "NOT!")
                else:
                    result.append(op_term)
        return result

    def evaluate_AND_with_OR(and_operation, or_operation):
        """For every OR's term and every allowed AND's term create a new term
        with both members.

        NOTE: All the nested OR's terms are expected to be allowed!
        """
        result = []
        for and_term in and_operation:
            if and_term.allow:
                for or_term in or_operation:
                    if or_term.allow:
                        new_term = copy.deepcopy(and_term)
                        new_term.members.extend(or_term.members)
                        result.append(new_term)
                    else:
                        raise errors.UnimplementedError("No support for "
                                                        "nested operation "
                                                        "which includes NOT!")
            else:
                result.append(and_term)
        return result

    def evaluate_AND_with_AND(and_operation_1, and_operation_2):
        """All the reject terms are put at the start of the result and all the
        allowed terms are combined together.
        """
        result = deque()
        seen_all_and_2_terms = False
        for and_1_term in and_operation_1:
            if and_1_term.allow:
                for and_2_term in and_operation_2:
                    if and_2_term.allow:
                        seen_all_and_2_terms = True
                        and_1_term.members.extend(and_2_term.members)
                result.append(and_1_term)
            else:
                result.appendleft(and_1_term)
        for and_2_term in and_operation_2:
            if not and_2_term.allow:
                result.appendleft(and_2_term)
            elif not seen_all_and_2_terms:
                result.append(and_2_term)
        return result

    def evaluate_OR_with_OR(or_operation_1, or_operation_2):
        """For OR's every term create new terms equal to the number of the
        other OR's terms.

        NOTE: All the nested OR's terms are expected to be allowed!
        """
        result = []
        for or_1_term in or_operation_1:
            for or_2_term in or_operation_2:
                new_term = Term(or_1_term.allow)
                new_term.members.extend(or_1_term.members)
                new_term.members.extend(or_2_term.members)
                result.append(new_term)
        return result

    def handle_ANY(result):
        """Handles ANY's existence in the result.

        If ANY is a member of:
        - an allowed term, ANY is discarded from that term,
        - a non allowed term, a non allowed term with ANY as its sole member is
                              returned as the result.
        """
        for term in result:
            for term_member in term.members:
                if term_member.category == ANY:
                    if term.allow:
                        new_term = Term(term.allow)
                        new_term.members = [
                            m for m in term.members if m != term_member
                        ]
                        if new_term.members:
                            result = [
                                t if t != term else new_term for t in result
                            ]
                        else:
                            result = [t for t in result if t != term]
                    else:
                        new_term = Term(term.allow)
                        new_term.members = [term_member]
                        result = [new_term]
                    return result
        return result

    result = deque()
    simple_operands = []
    temp_result = []
    has_nested_operation = False

    # Operand 'a'
    if a[0] == 'OR':
        has_nested_operation = True
        temp_result = a
    elif a[0] == 'AND':
        temp_result = a
    elif a[0] == 'OPERAND':
        simple_operands.append(a[1])
    else:
        raise errors.FilterCompositionError("Unknown operand: "
                                            "'{}'".format(a[0]))

    # Operand 'b'
    if b[0] == 'OR':
        has_nested_operation = True
        # If 'a' was a simple operand.
        if simple_operands:
            result = evaluate_simple_operand_with_operation(
                simple_operands.pop(), b[1], check_nested_NOT=True)
        elif temp_result:
            # If 'a' was an OR operation.
            if temp_result[0] == 'OR':
                result = evaluate_OR_with_OR(temp_result[1], b[1])
            # If 'a' was an AND operation.
            elif temp_result[0] == 'AND':
                result = evaluate_AND_with_OR(temp_result[1], b[1])
            else:
                raise errors.FilterCompositionError("Unknown operation "
                                                    "'{}'".format(
                                                        temp_result[0]))

    elif b[0] == 'AND':
        # If 'a' was a simple operand.
        if simple_operands:
            result = evaluate_simple_operand_with_operation(
                simple_operands.pop(), b[1])
        elif temp_result:
            # If 'a' was an OR operation.
            if temp_result[0] == 'OR':
                result = evaluate_AND_with_OR(b[1], temp_result[1])
            # If 'a' was an AND operation.
            elif temp_result[0] == 'AND':
                result = evaluate_AND_with_AND(temp_result[1], b[1])

    elif b[0] == 'OPERAND':
        if temp_result:
            # If 'a' was an OR operation.
            if temp_result[0] == 'OR':
                result = evaluate_simple_operand_with_operation(
                    b[1], temp_result[1], check_nested_NOT=True)
            # If 'a' was an AND operation.
            elif temp_result[0] == 'AND':
                result = evaluate_simple_operand_with_operation(
                    b[1], temp_result[1])
            else:
                raise errors.FilterCompositionError("Unknown operation "
                                                    "'{}'".format(
                                                        temp_result[0]))
        # If both operands are simple also add this to the simple_operands
        # list.
        else:
            simple_operands.append(b[1])

    else:
        raise errors.FilterCompositionError("Unknown operand: "
                                            "'{}'".format(a[0]))

    # Only True when *both* operands are simple operands. Otherwise the simple
    # operands are consumed from the operations above.
    while simple_operands:
        simple_operand = simple_operands.pop()
        if not result:
            term = Term(simple_operand.allow)
            term.members = [simple_operand]
            result.append(term)
        else:
            if result[0].allow and simple_operand.allow:
                result[0].members.append(simple_operand)
            else:
                term = Term(simple_operand.allow)
                term.members = [simple_operand]
                if term.allow:
                    result.append(term)
                else:
                    result.appendleft(term)

    result = handle_ANY(result)

    return (('AND', result), has_nested_operation)
 def unmap_memory(self, base, size):
     raise errors.UnimplementedError('Unmapping memory not implemented')