Пример #1
0
    def _TranslatePolicy(self, pol, exp_info):
        """Transform a policy object into a PaloAltoFW object.

    Args:
      pol: policy.Policy object
      exp_info: print a info message when a term is set to expire in that many
        weeks

    Raises:
      UnsupportedFilterError: An unsupported filter was specified
      UnsupportedHeaderError: A header option exists that is not
      understood/usable
      PaloAltoFWDuplicateTermError: Two terms were found with same name in
      same filter
      PaloAltoFWBadIcmpTypeError: The referenced ICMP type is not supported
      by the policy term.
      PaloAltoFWUnsupportedProtocolError: The term contains unsupporter protocol
      name.
    """
        current_date = datetime.date.today()
        exp_info_date = current_date + datetime.timedelta(weeks=exp_info)
        first_addr_obj = None

        for header, terms in pol.filters:
            if self._PLATFORM not in header.platforms:
                continue

            # The filter_options is a list of options from header, e.g.
            # ['from-zone', 'internal', 'to-zone', 'external']
            filter_options = header.FilterOptions(self._PLATFORM)

            if (len(filter_options) < 4 or filter_options[0] != "from-zone"
                    or filter_options[2] != "to-zone"):
                raise UnsupportedFilterError(
                    "Palo Alto Firewall filter arguments must specify from-zone and "
                    "to-zone.")

            self.from_zone = filter_options[1]
            self.to_zone = filter_options[3]

            # The filter_type values are either inet, inet6, or mixed. Later, the
            # code analyzes source and destination IP addresses and determines whether
            # it is an appropriate type for the filter_type value.
            if len(filter_options) > 4:
                filter_type = filter_options[4]
            else:
                filter_type = "inet"

            if filter_type not in self._SUPPORTED_AF:
                raise UnsupportedHeaderError(
                    'Palo Alto Firewall Generator invalid address family option: "%s"'
                    '; expect {%s}' %
                    (filter_type, '|'.join(self._SUPPORTED_AF)))

            valid_addr_obj = ["addr-obj", "no-addr-obj"]
            if len(filter_options
                   ) > 5 and filter_options[5] not in valid_addr_obj:
                raise UnsupportedHeaderError(
                    'Palo Alto Firewall Generator invalid address objects option: "%s"'
                    '; expect {%s}' %
                    (filter_options[5], '|'.join(valid_addr_obj)))
            no_addr_obj = True if (
                len(filter_options) > 5
                and filter_options[5] == "no-addr-obj") else False
            if first_addr_obj is None:
                first_addr_obj = no_addr_obj
            if first_addr_obj != no_addr_obj:
                raise UnsupportedHeaderError(
                    "Cannot mix addr-obj and no-addr-obj header option in "
                    "a single policy file")

            term_dup_check = set()
            new_terms = []

            for term in terms:
                if term.stateless_reply:
                    logging.warning(
                        "WARNING: Term %s in policy %s>%s is a stateless reply "
                        "term and will not be rendered.", term.name,
                        self.from_zone, self.to_zone)
                    continue
                if "established" in term.option:
                    logging.warning(
                        "WARNING: Term %s in policy %s>%s is a established "
                        "term and will not be rendered.", term.name,
                        self.from_zone, self.to_zone)
                    continue
                if "tcp-established" in term.option:
                    logging.warning(
                        "WARNING: Term %s in policy %s>%s is a tcp-established "
                        "term and will not be rendered.", term.name,
                        self.from_zone, self.to_zone)
                    continue

                # Verify platform specific terms. Skip whole term if platform does not
                # match.
                if term.platform:
                    if self._PLATFORM not in term.platform:
                        continue
                if term.platform_exclude:
                    if self._PLATFORM in term.platform_exclude:
                        continue

                term.name = self.FixTermLength(term.name)
                if term.name in term_dup_check:
                    raise PaloAltoFWDuplicateTermError(
                        "You have a duplicate term: %s" % term.name)
                term_dup_check.add(term.name)

                services = {"tcp", "udp"} & set(term.protocol)
                others = set(term.protocol) - services
                if others and term.pan_application:
                    raise UnsupportedFilterError(
                        "Term %s contains non tcp, udp protocols with pan-application: %s: %s"
                        "\npan-application can only be used with protocols tcp, udp"
                        % (term.name, ', '.join(
                            term.pan_application), ', '.join(term.protocol)))

                if term.expiration:
                    if term.expiration <= exp_info_date:
                        logging.info(
                            "INFO: Term %s in policy %s>%s expires "
                            "in less than two weeks.", term.name,
                            self.from_zone, self.to_zone)
                    if term.expiration <= current_date:
                        logging.warning(
                            "WARNING: Term %s in policy %s>%s is expired and "
                            "will not be rendered.", term.name, self.from_zone,
                            self.to_zone)
                        continue

                for i in term.source_address_exclude:
                    term.source_address = nacaddr.RemoveAddressFromList(
                        term.source_address, i)
                for i in term.destination_address_exclude:
                    term.destination_address = nacaddr.RemoveAddressFromList(
                        term.destination_address, i)

                # Count the number of occurencies of a particular version of the
                # address family, i.e. v4/v6 in source and destination IP addresses.
                afc = {
                    4: {
                        "src": 0,
                        "dst": 0
                    },
                    6: {
                        "src": 0,
                        "dst": 0
                    },
                }
                # Determine the address families in the source and destination
                # addresses references in the term. Next, determine IPv4 and IPv6
                # traffic flow patterns.
                exclude_address_family = []
                flows = []
                src_any = False
                dst_any = False
                if not term.source_address:
                    src_any = True
                if not term.destination_address:
                    dst_any = True
                for addr in term.source_address:
                    afc[addr.version]["src"] += 1
                for addr in term.destination_address:
                    afc[addr.version]["dst"] += 1
                for v in [4, 6]:
                    if src_any and dst_any:
                        flows.append("ip%d-ip%d" % (v, v))
                        continue
                    if (afc[v]["src"] == 0
                            and not src_any) and (afc[v]["dst"] == 0
                                                  and not dst_any):
                        continue
                    if (afc[v]["src"] > 0 or src_any) and (afc[v]["dst"] > 0
                                                           or dst_any):
                        flows.append("ip%d-ip%d" % (v, v))
                        continue
                    if (afc[v]["src"] > 0 or src_any) and afc[v]["dst"] == 0:
                        flows.append("ip%d-src-only" % v)
                        flows.append("ip%d-only" % v)
                        continue
                    if afc[v]["src"] == 0 and (afc[v]["dst"] > 0 or dst_any):
                        flows.append("ip%d-dst-only" % v)
                        flows.append("ip%d-only" % v)

                if filter_type == "inet":
                    if "icmpv6" in term.protocol:
                        logging.warning(
                            "WARNING: Term %s in policy %s>%s references ICMPv6 protocol, "
                            "term will not be rendered.", term.name,
                            self.from_zone, self.to_zone)
                        continue
                    if "ip4-ip4" not in flows:
                        logging.warning(
                            "WARNING: Term %s in policy %s>%s has one or more invalid "
                            "src-dest combinations %s, term will not be rendered.",
                            term.name, self.from_zone, self.to_zone, flows)
                        continue
                    # exclude IPv6 addresses
                    exclude_address_family.append(6)
                elif filter_type == "inet6":
                    if "icmp" in term.protocol:
                        logging.warning(
                            "WARNING: Term %s in policy %s>%s references ICMP protocol, "
                            "term and will not be rendered.", term.name,
                            self.from_zone, self.to_zone)
                        continue
                    if "ip6-ip6" not in flows:
                        logging.warning(
                            "WARNING: Term %s in policy %s>%s has one or more invalid "
                            "src-dest combinations %s, term will not be rendered.",
                            term.name, self.from_zone, self.to_zone, flows)
                        continue
                    exclude_address_family.append(4)
                elif filter_type == "mixed":
                    if "ip4-ip4" in flows and "ip6-ip6" not in flows:
                        exclude_address_family.append(6)
                        pass
                    elif "ip6-ip6" in flows and "ip4-ip4" not in flows:
                        exclude_address_family.append(4)
                        pass
                    elif "ip4-ip4" in flows and "ip6-ip6" in flows:
                        pass
                    elif "ip4-only" in flows and "ip6-only" in flows:
                        logging.warning(
                            "WARNING: Term %s in policy %s>%s has source and destinations "
                            "of different address families %s, term will not be "
                            "rendered.", term.name, self.from_zone,
                            self.to_zone,
                            filter(lambda p: re.search(p, "(src|dst)-only"),
                                   flows))
                        continue
                    else:
                        logging.warning(
                            "WARNING: Term %s in policy %s>%s has invalid src-dest "
                            "combinations %s, the term will be rendered without them.",
                            term.name, self.from_zone, self.to_zone,
                            filter(lambda p: re.search(p, "(src|dst)-only"),
                                   flows))
                        if "ip4-ip4" in flows:
                            exclude_address_family.append(6)
                        else:
                            exclude_address_family.append(4)

                # Build address book for the addresses referenced in the term.
                for addr in term.source_address:
                    if addr.version in exclude_address_family:
                        continue
                    self._BuildAddressBook(self.from_zone, addr)
                for addr in term.destination_address:
                    if addr.version in exclude_address_family:
                        continue
                    self._BuildAddressBook(self.to_zone, addr)

                # Handle ICMP/ICMPv6 terms.
                if term.icmp_type and ("icmp" not in term.protocol
                                       and "icmpv6" not in term.protocol):
                    raise UnsupportedFilterError(
                        "Palo Alto Firewall filter must have ICMP or ICMPv6 protocol "
                        + "specified when using icmp_type keyword")

                for icmp_version in ["icmp", "icmpv6"]:
                    if ("icmp" not in term.protocol
                            and "icmpv6" not in term.protocol):
                        # the protocol is not ICMP or ICMPv6
                        break
                    if icmp_version not in term.protocol:
                        # skip if this icmp_version isn't in the term protocol.
                        continue
                    if icmp_version == "icmp" and "ip4-ip4" not in flows:
                        # skip if there is no ip4 to ipv4 communication
                        continue
                    if icmp_version == "icmpv6" and "ip6-ip6" not in flows:
                        # skip if there is no ip4 to ipv4 communication
                        continue
                    if icmp_version == "icmp":
                        if filter_type == "inet6":
                            continue
                        if not term.icmp_type:
                            term.pan_application.append("icmp")
                            continue
                        icmp_type_keyword = "ident-by-icmp-type"
                        # The risk level 4 is the default PANOS' risk level for ICMP.
                        risk_level = 4
                    else:
                        if filter_type == "inet":
                            continue
                        if not term.icmp_type:
                            term.pan_application.append("ipv6-icmp")
                            continue
                        icmp_type_keyword = "ident-by-icmp6-type"
                        # The risk level 2 is the default PANOS' risk level for ICMPv6.
                        risk_level = 2
                    # The term contains ICMP types
                    for term_icmp_type_name in term.icmp_type:
                        if icmp_version == "icmp":
                            icmp_app_name = "icmp-%s" % term_icmp_type_name
                            if term_icmp_type_name not in policy.Term.ICMP_TYPE[
                                    4]:
                                raise PaloAltoFWBadIcmpTypeError(
                                    "term with bad icmp type: %s, icmp_type: %s"
                                    % (term.name, term_icmp_type_name))
                            term_icmp_type = policy.Term.ICMP_TYPE[4][
                                term_icmp_type_name]
                        else:
                            icmp_app_name = "icmp6-%s" % term_icmp_type_name
                            if term_icmp_type_name not in policy.Term.ICMP_TYPE[
                                    6]:
                                raise PaloAltoFWBadIcmpTypeError(
                                    "term with bad icmp type: %s, icmp_type: %s"
                                    % (term.name, term_icmp_type_name))
                            term_icmp_type = policy.Term.ICMP_TYPE[6][
                                term_icmp_type_name]
                        if icmp_app_name in self.application_refs:
                            # the custom icmp application already exists
                            continue
                        app_entry = {
                            "category": "networking",
                            "subcategory": "ip-protocol",
                            "technology": "network-protocol",
                            "description": icmp_app_name,
                            "default": {
                                icmp_type_keyword: "%d" % term_icmp_type,
                            },
                            "risk": "%d" % risk_level,
                        }
                        self.application_refs[icmp_app_name] = app_entry
                        self.applications.append(icmp_app_name)
                        if icmp_app_name not in term.pan_application:
                            term.pan_application.append(icmp_app_name)

                # Filter out unsupported protocols
                for proto_name in term.protocol:
                    if proto_name in self._SUPPORTED_PROTO_NAMES:
                        continue
                    raise PaloAltoFWUnsupportedProtocolError(
                        "protocol %s is not supported" % proto_name)

                if term.icmp_type:
                    if set(term.protocol) == {'icmp', 'icmpv6'}:
                        raise UnsupportedFilterError('%s %s' % (
                            'icmp-type specified for both icmp and icmpv6 protocols'
                            ' in a single term:', term.name))
                    if term.protocol != ['icmp'
                                         ] and term.protocol != ['icmpv6']:
                        raise UnsupportedFilterError('%s %s' % (
                            'icmp-type specified for non-icmp protocols in term:',
                            term.name))

                new_terms.append(term)

            # Create a ruleset. It contains the rules for the terms defined under
            # a single header on a particular platform.
            ruleset = {}

            for term in new_terms:
                current_rule = Rule(self.from_zone, self.to_zone, term,
                                    self.service_map)
                if len(current_rule.options) > 1:
                    for i, v in enumerate(current_rule.options):
                        name = "%s-%d" % (term.name, i + 1)
                        name = self.FixTermLength(name)
                        ruleset[name] = v
                else:
                    ruleset[term.name] = current_rule.options[0]

            self.pafw_policies.append((header, ruleset, filter_options))
Пример #2
0
    def _TranslatePolicy(self, pol, exp_info):
        # pylint: disable=attribute-defined-outside-init
        """Transform a policy object into a JuniperSRX object.

    Args:
      pol: policy.Policy object
      exp_info: print a info message when a term is set to expire
                in that many weeks

    Raises:
      UnsupportedFilterError: An unsupported filter was specified
      UnsupportedHeader: A header option exists that is not understood/usable
      SRXDuplicateTermError: Two terms were found with same name in same filter
      ConflictingTargetOptions: Two target options are conflicting in the header
      MixedAddrBookTypes: Global and Zone address books in the same policy
      ConflictingApplicationSets: When two duplicate named terms have
                                  conflicting application entries
    """
        self.srx_policies = []
        self.addressbook = collections.OrderedDict()
        self.applications = []
        self.ports = []
        self.from_zone = ''
        self.to_zone = ''
        self.addr_book_type = set()

        current_date = datetime.datetime.utcnow().date()
        exp_info_date = current_date + datetime.timedelta(weeks=exp_info)

        for header, terms in pol.filters:
            if self._PLATFORM not in header.platforms:
                continue

            filter_options = header.FilterOptions(self._PLATFORM)

            verbose = True
            if self._NOVERBOSE in filter_options[4:]:
                verbose = False

            # TODO(robankeny): Clean up option section.
            if (len(filter_options) < 4 or filter_options[0] != 'from-zone'
                    or filter_options[2] != 'to-zone'):
                raise UnsupportedFilterError(
                    'SRX filter arguments must specify '
                    'from-zone and to-zone.')

            # check if to-zone is not a supported target option
            if filter_options[1] in self._SUPPORTED_TARGET_OPTIONS:
                raise UnsupportedFilterError(
                    'to-zone %s cannot be the same as any '
                    'valid SRX target-options' % (filter_options[1]))
            else:
                self.from_zone = filter_options[1]

            # check if from-zone is not a supported target option
            if filter_options[3] in self._SUPPORTED_TARGET_OPTIONS:
                raise UnsupportedFilterError(
                    'from-zone %s cannot be the same as any '
                    'valid SRX target-options' % (filter_options[3]))
            else:
                self.to_zone = filter_options[3]

            # variables used to collect target-options and set defaults
            filter_type = ''

            # parse srx target options
            extra_options = filter_options[4:]
            if self._ADDRESSBOOK_TYPES.issubset(extra_options):
                raise ConflictingTargetOptions(
                    'only one address-book-type can '
                    'be specified per header "%s"' % ' '.join(filter_options))
            else:
                address_book_type = set(
                    [self._ZONE_ADDR_BOOK,
                     self._GLOBAL_ADDR_BOOK]).intersection(extra_options)
                if len(address_book_type) is 0:
                    address_book_type = {self._GLOBAL_ADDR_BOOK}
                self.addr_book_type.update(address_book_type)
                if len(self.addr_book_type) > 1:
                    raise MixedAddrBookTypes(
                        'Global and Zone address-book-types cannot '
                        'be used in the same policy')
                if self.from_zone == 'all' and self.to_zone == 'all':
                    if self._ZONE_ADDR_BOOK in self.addr_book_type:
                        raise UnsupportedFilterError(
                            'Zone address books cannot be used '
                            'with a global policy.')
                elif self.from_zone == 'all' or self.to_zone == 'all':
                    raise UnsupportedFilterError(
                        'The zone name all is reserved for '
                        'global policies.')

            if self._EXPRESSPATH in filter_options[4:]:
                self.expresspath = True
            else:
                self.expresspath = False

            for filter_opt in filter_options[4:]:
                # validate address families
                if filter_opt in self._SUPPORTED_AF:
                    if not filter_type:
                        filter_type = filter_opt
                    else:
                        raise ConflictingTargetOptions(
                            'only one address family can be '
                            'specified per header "%s"' %
                            ' '.join(filter_options))
                elif filter_opt in self._SUPPORTED_TARGET_OPTIONS:
                    continue
                else:
                    raise UnsupportedHeader(
                        'SRX Generator currently does not support '
                        '%s as a header option "%s"' %
                        (filter_opt, ' '.join(filter_options)))

            # if address-family and address-book-type have not been set then default
            if not filter_type:
                filter_type = 'mixed'

            term_dup_check = set()

            new_terms = []
            self._FixLargePolices(terms, filter_type)
            for term in terms:
                if set(['established',
                        'tcp-established']).intersection(term.option):
                    logging.debug(
                        'Skipping established term %s ' +
                        'because SRX is stateful.', term.name)
                    continue
                term.name = self.FixTermLength(term.name)
                if term.name in term_dup_check:
                    raise SRXDuplicateTermError(
                        'You have a duplicate term: %s' % term.name)
                term_dup_check.add(term.name)

                if term.expiration:
                    if term.expiration <= exp_info_date:
                        logging.info(
                            'INFO: Term %s in policy %s>%s expires '
                            'in less than two weeks.', term.name,
                            self.from_zone, self.to_zone)
                    if term.expiration <= current_date:
                        logging.warn(
                            'WARNING: Term %s in policy %s>%s is expired.',
                            term.name, self.from_zone, self.to_zone)
                        continue

                # SRX address books leverage network token names for IPs.
                # When excluding addresses, we lose those distinct names so we need
                # to create a new unique name based off the term name before excluding.
                if term.source_address_exclude:
                    # If we have a naked source_exclude, we need something to exclude from
                    if not term.source_address:
                        term.source_address = [
                            nacaddr.IP('0.0.0.0/0', term.name.upper(),
                                       term.name.upper())
                        ]
                    # Use the term name as the token & parent_token
                    new_src_parent_token = term.name.upper() + '_SRC_EXCLUDE'
                    new_src_token = new_src_parent_token
                    for i in term.source_address_exclude:
                        term.source_address = nacaddr.RemoveAddressFromList(
                            term.source_address, i)
                        for i in term.source_address:
                            i.token = new_src_token
                            i.parent_token = new_src_parent_token

                if term.destination_address_exclude:
                    if not term.destination_address:
                        term.destination_address = [
                            nacaddr.IP('0.0.0.0/0', term.name.upper(),
                                       term.name.upper())
                        ]
                    new_dst_parent_token = term.name.upper() + '_DST_EXCLUDE'
                    new_dst_token = new_dst_parent_token
                    for i in term.destination_address_exclude:
                        term.destination_address = nacaddr.RemoveAddressFromList(
                            term.destination_address, i)
                        for i in term.destination_address:
                            i.token = new_dst_token
                            i.parent_token = new_dst_parent_token

                # SRX policies are controlled by addresses that are used within, so
                # policy can be at the same time inet and inet6.
                if self._GLOBAL_ADDR_BOOK in self.addr_book_type:
                    for zone in self.addressbook:
                        for unused_name, ips in sorted(
                                six.iteritems(self.addressbook[zone])):
                            ips = [i for i in ips]
                            if term.source_address == ips:
                                term.source_address = ips
                            if term.destination_address == ips:
                                term.destination_address = ips
                for addr in term.source_address:
                    if addr.version in self._AF_MAP[filter_type]:
                        self._BuildAddressBook(self.from_zone, addr)
                for addr in term.destination_address:
                    if addr.version in self._AF_MAP[filter_type]:
                        self._BuildAddressBook(self.to_zone, addr)

                new_term = Term(term, self.from_zone, self.to_zone,
                                self.expresspath, verbose)
                new_terms.append(new_term)

                # Because SRX terms can contain inet and inet6 addresses. We have to
                # have ability to recover proper AF for ICMP type we need.
                # If protocol is empty or we cannot map to inet or inet6 we insert bogus
                # af_type name which will cause new_term.NormalizeIcmpTypes to fail.
                if not term.protocol:
                    icmp_af_type = 'unknown_af_icmp'
                else:
                    icmp_af_type = self._AF_ICMP_MAP.get(
                        term.protocol[0], 'unknown_af_icmp')
                tmp_icmptype = new_term.NormalizeIcmpTypes(
                    term.icmp_type, term.protocol, icmp_af_type)
                # NormalizeIcmpTypes returns [''] for empty, convert to [] for eval
                normalized_icmptype = tmp_icmptype if tmp_icmptype != [
                    ''
                ] else []
                # rewrites the protocol icmpv6 to icmp6
                if 'icmpv6' in term.protocol:
                    protocol = list(term.protocol)
                    protocol[protocol.index('icmpv6')] = 'icmp6'
                else:
                    protocol = term.protocol
                new_application_set = {
                    'sport': self._BuildPort(term.source_port),
                    'dport': self._BuildPort(term.destination_port),
                    'protocol': protocol,
                    'icmp-type': normalized_icmptype,
                    'timeout': term.timeout
                }

                for application_set in self.applications:
                    if all(item in list(application_set.items())
                           for item in new_application_set.items()):
                        new_application_set = ''
                        term.replacement_application_name = application_set[
                            'name']
                        break
                    if (term.name == application_set['name']
                            and new_application_set != application_set):
                        raise ConflictingApplicationSets(
                            'Application set %s has a conflicting entry' %
                            term.name)

                if new_application_set:
                    new_application_set['name'] = term.name
                    self.applications.append(new_application_set)

            self.srx_policies.append((header, new_terms, filter_options))
Пример #3
0
    def _TranslatePolicy(self, pol, exp_info):
        """Transform a policy object into a PaloAltoFW object.

    Args:
      pol: policy.Policy object
      exp_info: print a info message when a term is set to expire
                in that many weeks

    Raises:
      UnsupportedFilterError: An unsupported filter was specified
      UnsupportedHeader: A header option exists that is not
      understood/usable
      PaloAltoFWDuplicateTermError: Two terms were found with same name in
      same filter
    """
        current_date = datetime.date.today()
        exp_info_date = current_date + datetime.timedelta(weeks=exp_info)
        for header, terms in pol.filters:
            if self._PLATFORM not in header.platforms:
                continue

            filter_options = header.FilterOptions(self._PLATFORM)

            if (len(filter_options) < 4 or filter_options[0] != "from-zone"
                    or filter_options[2] != "to-zone"):
                raise UnsupportedFilterError(
                    "Palo Alto Firewall filter arguments must specify from-zone and "
                    "to-zone.")

            self.from_zone = filter_options[1]
            self.to_zone = filter_options[3]

            if len(filter_options) > 4:
                filter_type = filter_options[4]
            else:
                filter_type = "inet"

            if filter_type not in self._SUPPORTED_AF:
                raise UnsupportedHeader(
                    "Palo Alto Firewall Generator currently does not support"
                    " %s as a header option" % (filter_type))

            term_dup_check = set()
            new_terms = []
            for term in terms:
                term.name = self.FixTermLength(term.name)
                if term.name in term_dup_check:
                    raise PaloAltoFWDuplicateTermError(
                        "You have a duplicate term: %s" % term.name)
                term_dup_check.add(term.name)

                if term.expiration:
                    if term.expiration <= exp_info_date:
                        logging.info(
                            "INFO: Term %s in policy %s>%s expires "
                            "in less than two weeks.", term.name,
                            self.from_zone, self.to_zone)
                    if term.expiration <= current_date:
                        logging.warn(
                            "WARNING: Term %s in policy %s>%s is expired and "
                            "will not be rendered.", term.name, self.from_zone,
                            self.to_zone)
                        continue

                for i in term.source_address_exclude:
                    term.source_address = nacaddr.RemoveAddressFromList(
                        term.source_address, i)
                for i in term.destination_address_exclude:
                    term.destination_address = nacaddr.RemoveAddressFromList(
                        term.destination_address, i)

                for addr in term.source_address:
                    self._BuildAddressBook(self.from_zone, addr)
                for addr in term.destination_address:
                    self._BuildAddressBook(self.to_zone, addr)

                new_term = Term(term, filter_type, filter_options)
                new_terms.append(new_term)
                tmp_icmptype = new_term.NormalizeIcmpTypes(
                    term.icmp_type, term.protocol, filter_type)
                # NormalizeIcmpTypes returns [''] for empty, convert to [] for
                # eval
                normalized_icmptype = tmp_icmptype if tmp_icmptype != [
                    ""
                ] else []
                # rewrites the protocol icmpv6 to icmp6
                if "icmpv6" in term.protocol:
                    protocol = list(term.protocol)
                    protocol[protocol.index("icmpv6")] = "icmp6"
                else:
                    protocol = term.protocol
                self.applications.append({
                    "sport":
                    self._BuildPort(term.source_port),
                    "dport":
                    self._BuildPort(term.destination_port),
                    "name":
                    term.name,
                    "protocol":
                    protocol,
                    "icmp-type":
                    normalized_icmptype,
                    "timeout":
                    term.timeout
                })
            self.pafw_policies.append((header, new_terms, filter_options))
            # create Palo Alto Firewall Rule object
            for term in new_terms:
                unused_rule = Rule(self.from_zone, self.to_zone, term)