Example #1
0
  def _CalculateAddresses(self, src_addr_list, src_ex_addr_list,
                          dst_addr_list, dst_ex_addr_list):
    """Calculate source and destination address list for a term.

    Since ipset is very efficient at matching large number of
    addresses, we never return eny exclude addresses. Instead
    least positive match is calculated for both source and destination
    addresses.

    For source and destination address list, three cases are possible.
    First case is when there is no addresses. In that case we return
    _all_ips.
    Second case is when there is strictly one address. In that case,
    we optimize by not generating a set, and it's then the only
    element of returned set.
    Third case case is when there is more than one address in a set.
    In that case we generate a set and also return _all_ips. Note the
    difference to the first case where no set is actually generated.

    Args:
      src_addr_list: source address list of the term.
      src_ex_addr_list: source address exclude list of the term.
      dst_addr_list: destination address list of the term.
      dst_ex_addr_list: destination address exclude list of the term.

    Returns:
      tuple containing source address list, source exclude address list,
      destination address list, destination exclude address list in
      that order.

    """
    if not src_addr_list:
      src_addr_list = [self._all_ips]
    src_addr_list = [src_addr for src_addr in src_addr_list if
                     src_addr.version == self.AF_MAP[self.af]]
    if src_ex_addr_list:
      src_ex_addr_list = [src_ex_addr for src_ex_addr in src_ex_addr_list if
                          src_ex_addr.version == self.AF_MAP[self.af]]
      src_addr_list = nacaddr.ExcludeAddrs(src_addr_list, src_ex_addr_list)
    if len(src_addr_list) > 1:
      set_name = self._GenerateSetName(self.term.name, 'src')
      self.addr_sets['src'] = (set_name, src_addr_list)
      src_addr_list = [self._all_ips]

    if not dst_addr_list:
      dst_addr_list = [self._all_ips]
    dst_addr_list = [dst_addr for dst_addr in dst_addr_list if
                     dst_addr.version == self.AF_MAP[self.af]]
    if dst_ex_addr_list:
      dst_ex_addr_list = [dst_ex_addr for dst_ex_addr in dst_ex_addr_list if
                          dst_ex_addr.version == self.AF_MAP[self.af]]
      dst_addr_list = nacaddr.ExcludeAddrs(dst_addr_list, dst_ex_addr_list)
    if len(dst_addr_list) > 1:
      set_name = self._GenerateSetName(self.term.name, 'dst')
      self.addr_sets['dst'] = (set_name, dst_addr_list)
      dst_addr_list = [self._all_ips]
    return (src_addr_list, [], dst_addr_list, [])
Example #2
0
  def _CalculateAddrList(self, addr_list, addr_exclude_list,
                         target_af, direction):
    """Calculates and stores address list for target AF and direction.

    Args:
      addr_list: address list.
      addr_exclude_list: address exclude list of the term.
      target_af: target address family.
      direction: direction in which address list will be used.

    Returns:
      calculated address list.

    """
    if not addr_list:
      addr_list = [self._all_ips]
    addr_list = [addr for addr in addr_list if addr.version == target_af]
    if addr_exclude_list:
      addr_exclude_list = [addr_exclude for addr_exclude in addr_exclude_list if
                           addr_exclude.version == target_af]
      addr_list = nacaddr.ExcludeAddrs(addr_list, addr_exclude_list)
    if len(addr_list) > 1:
      set_name = self._GenerateSetName(self.term.name, direction)
      self.addr_sets[direction] = (set_name, addr_list)
      addr_list = [self._all_ips]
    return addr_list
Example #3
0
    def __str__(self):
        # Verify platform specific terms. Skip whole term if platform does not
        # match.
        if self.term.platform:
            if 'ciscoasa' not in self.term.platform:
                return ''
        if self.term.platform_exclude:
            if 'ciscoasa' in self.term.platform_exclude:
                return ''

        ret_str = ['\n']

        # Don't render icmpv6 protocol terms under inet, or icmp under inet6
        if ((self.af == 6 and 'icmp' in self.term.protocol)
                or (self.af == 4 and 'icmpv6' in self.term.protocol)):
            ret_str.append('remark Term %s' % self.term.name)
            ret_str.append('remark not rendered due to protocol/AF mismatch.')
            return '\n'.join(ret_str)

        ret_str.append('access-list %s remark %s' %
                       (self.filter_name, self.term.name))
        if self.term.owner:
            self.term.comment.append('Owner: %s' % self.term.owner)
        for comment in self.term.comment:
            for line in comment.split('\n'):
                ret_str.append('access-list %s remark %s' %
                               (self.filter_name, str(line)[:100]))

        # Term verbatim output - this will skip over normal term creation
        # code by returning early.  Warnings provided in policy.py.
        if self.term.verbatim:
            for next in self.term.verbatim:
                if next.value[0] == 'ciscoasa':
                    ret_str.append(str(next.value[1]))
                return '\n'.join(ret_str)

        # protocol
        if not self.term.protocol:
            protocol = ['ip']
        else:
            # fix the protocol
            protocol = self.term.protocol

        # source address
        if self.term.source_address:
            source_address = self.term.GetAddressOfVersion(
                'source_address', self.af)
            source_address_exclude = self.term.GetAddressOfVersion(
                'source_address_exclude', self.af)
            if source_address_exclude:
                source_address = nacaddr.ExcludeAddrs(source_address,
                                                      source_address_exclude)
        else:
            # source address not set
            source_address = ['any']

        # destination address
        if self.term.destination_address:
            destination_address = self.term.GetAddressOfVersion(
                'destination_address', self.af)
            destination_address_exclude = self.term.GetAddressOfVersion(
                'destination_address_exclude', self.af)
            if destination_address_exclude:
                destination_address = nacaddr.ExcludeAddrs(
                    destination_address, destination_address_exclude)
        else:
            # destination address not set
            destination_address = ['any']

        # options
        extra_options = []
        for opt in [str(x) for x in self.term.option]:
            if opt.find('tcp-established') == 0 and 6 in protocol:
                extra_options.append('established')
            elif opt.find('established') == 0 and 6 in protocol:
                # only needed for TCP, for other protocols policy.py handles high-ports
                extra_options.append('established')
        self.options.extend(extra_options)

        # ports
        source_port = [()]
        destination_port = [()]
        if self.term.source_port:
            source_port = self.term.source_port
        if self.term.destination_port:
            destination_port = self.term.destination_port

        # logging
        if self.term.logging:
            self.options.append('log')
            if 'disable' in [x.value for x in self.term.logging]:
                self.options.append('disable')

        # icmp-types
        icmp_types = ['']
        if self.term.icmp_type:
            icmp_types = self.NormalizeIcmpTypes(self.term.icmp_type,
                                                 self.term.protocol, self.af)

        for saddr in source_address:
            for daddr in destination_address:
                for sport in source_port:
                    for dport in destination_port:
                        for proto in protocol:
                            for icmp_type in icmp_types:
                                # only output address family appropriate IP addresses
                                do_output = False
                                if self.af == 4:
                                    if (((type(saddr) is nacaddr.IPv4) or
                                         (saddr == 'any')) and
                                        ((type(daddr) is nacaddr.IPv4) or
                                         (daddr == 'any'))):
                                        do_output = True
                                if self.af == 6:
                                    if (((type(saddr) is nacaddr.IPv6) or
                                         (saddr == 'any')) and
                                        ((type(daddr) is nacaddr.IPv6) or
                                         (daddr == 'any'))):
                                        do_output = True
                                if do_output:
                                    ret_str.extend(
                                        self._TermletToStr(
                                            self.filter_name,
                                            _ACTION_TABLE.get(
                                                str(self.term.action[0])),
                                            proto, saddr, sport, daddr, dport,
                                            icmp_type, self.options))

        return '\n'.join(ret_str)
Example #4
0
    def __str__(self):
        """Convert term to a rule string.

    Returns:
      A rule as a string.

    Raises:
      NsxvAclTermError: When unknown icmp-types are specified

    """
        # Verify platform specific terms. Skip whole term if platform does not
        # match.
        if self.term.platform:
            if 'nsxv' not in self.term.platform:
                return ''
        if self.term.platform_exclude:
            if 'nsxv' in self.term.platform_exclude:
                return ''

        ret_str = ['']

        # Don't render icmpv6 protocol terms under inet, or icmp under inet6
        if ((self.af == 6 and 'icmp' in self.term.protocol)
                or (self.af == 4 and 'icmpv6' in self.term.protocol)):
            logging.debug(
                self.NO_AF_LOG_PROTO.substitute(term=self.term.name,
                                                proto=self.term.protocol,
                                                af=self.text_af))
            return ''

        # Term verbatim is not supported
        if self.term.verbatim:
            raise NsxvAclTermError(
                'Verbatim are not implemented in standard ACLs')

        # Term option is not supported
        if self.term.option:
            raise NsxvAclTermError(
                'Option are not implemented in standard ACLs')

        # check for keywords Nsxv does not support
        term_keywords = self.term.__dict__
        unsupported_keywords = []
        for key in term_keywords:
            if term_keywords[key]:
                # translated is obj attribute not keyword
                if ('translated'
                        not in key) and (key not in _NSXV_SUPPORTED_KEYWORDS):
                    unsupported_keywords.append(key)
        if unsupported_keywords:
            logging.warn(
                'WARNING: The keywords %s in Term %s are not supported in Nsxv ',
                unsupported_keywords, self.term.name)

        name = '%s%s%s' % (_XML_TABLE.get('nameStart'), self.term.name,
                           _XML_TABLE.get('nameEnd'))

        notes = ''
        if self.term.comment:
            for comment in self.term.comment:
                notes = '%s%s' % (notes, comment)
            notes = '%s%s%s' % (_XML_TABLE.get('noteStart'), notes,
                                _XML_TABLE.get('noteEnd'))

        # protocol
        protocol = None

        if self.term.protocol:
            protocol = map(self.PROTO_MAP.get, self.term.protocol,
                           self.term.protocol)

            # icmp-types
            icmp_types = ['']
            if self.term.icmp_type:
                icmp_types = self.NormalizeIcmpTypes(self.term.icmp_type,
                                                     self.term.protocol,
                                                     self.af)

        # for mixed filter type get both IPV4address and IPv6Address
        af_list = []
        if self.filter_type == 'mixed':
            af_list = [4, 6]
        else:
            af_list = [self.af]

        source_address = None
        destination_address = None
        source_addr = []
        destination_addr = []

        for af in af_list:
            # source address
            if self.term.source_address:
                source_address = self.term.GetAddressOfVersion(
                    'source_address', af)
                source_address_exclude = self.term.GetAddressOfVersion(
                    'source_address_exclude', af)
                if source_address_exclude:
                    source_address = nacaddr.ExcludeAddrs(
                        source_address, source_address_exclude)
                if not source_address:
                    logging.warn(
                        self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                                       direction='source',
                                                       af=self.text_af))
                    return ''
                if not source_addr:
                    source_addr.append(source_address)
                else:
                    source_addr = source_address

            # destination address
            if self.term.destination_address:
                destination_address = self.term.GetAddressOfVersion(
                    'destination_address', af)
                destination_address_exclude = self.term.GetAddressOfVersion(
                    'destination_address_exclude', af)
                if destination_address_exclude:
                    destination_address = nacaddr.ExcludeAddrs(
                        destination_address, destination_address_exclude)
                if not destination_address:
                    logging.warn(
                        self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                                       direction='destination',
                                                       af=self.text_af))
                    return ''
                destination_addr.append(destination_address)
        # creating single list out of lists of lists
        source_addresses = [val for sublist in source_addr for val in sublist]
        destination_addresses = [
            val for sublist in destination_addr for val in sublist
        ]

        # ports
        source_port = None
        destination_port = None
        if self.term.source_port:
            source_port = self.term.source_port
        if self.term.destination_port:
            destination_port = self.term.destination_port

        # logging
        log = 'false'
        if self.term.logging:
            log = 'true'

        sources = ''
        if source_addresses:
            sources = '<sources excluded="false">'
            for saddr in source_addresses:

                #inet4
                if type(saddr) is nacaddr.IPv4 or type(
                        saddr) is ipaddr.IPv4Network:
                    if saddr.numhosts > 1:
                        saddr = '%s%s%s' % (
                            _XML_TABLE.get('srcIpv4Start'),
                            saddr.with_prefixlen,
                            _XML_TABLE.get('srcIpv4End'),
                        )
                    else:
                        saddr = '%s%s%s' % (_XML_TABLE.get('srcIpv4Start'),
                                            saddr.ip,
                                            _XML_TABLE.get('srcIpv4End'))
                    sources = '%s%s' % (sources, saddr)
                # inet6
                if type(saddr) is nacaddr.IPv6 or type(
                        saddr) is ipaddr.IPv6Network:
                    if saddr.numhosts > 1:
                        saddr = '%s%s%s' % (
                            _XML_TABLE.get('srcIpv6Start'),
                            saddr.with_prefixlen,
                            _XML_TABLE.get('srcIpv6End'),
                        )
                    else:
                        saddr = '%s%s%s' % (_XML_TABLE.get('srcIpv6Start'),
                                            saddr.ip,
                                            _XML_TABLE.get('srcIpv6End'))
                    sources = '%s%s' % (sources, saddr)
            sources = '%s%s' % (sources, '</sources>')

        destinations = ''
        if destination_addresses:
            destinations = '<destinations excluded="false">'
            for daddr in destination_addresses:
                #inet4
                if type(daddr) is nacaddr.IPv4 or type(
                        daddr) is ipaddr.IPv4Network:
                    if daddr.numhosts > 1:
                        daddr = '%s%s%s' % (
                            _XML_TABLE.get('destIpv4Start'),
                            daddr.with_prefixlen,
                            _XML_TABLE.get('destIpv4End'),
                        )
                    else:
                        daddr = '%s%s%s' % (_XML_TABLE.get('destIpv4Start'),
                                            daddr.ip,
                                            _XML_TABLE.get('destIpv4End'))
                    destinations = '%s%s' % (destinations, daddr)
                #inet6
                if type(daddr) is nacaddr.IPv6 or type(
                        daddr) is ipaddr.IPv6Network:
                    if daddr.numhosts > 1:
                        daddr = '%s%s%s' % (
                            _XML_TABLE.get('destIpv6Start'),
                            daddr.with_prefixlen,
                            _XML_TABLE.get('destIpv6End'),
                        )
                    else:
                        daddr = '%s%s%s' % (_XML_TABLE.get('destIpv6Start'),
                                            daddr.ip,
                                            _XML_TABLE.get('destIpv6End'))
                    destinations = '%s%s' % (destinations, daddr)
            destinations = '%s%s' % (destinations, '</destinations>')

        services = []
        if protocol:
            services.append('<services>')
            for proto in protocol:
                if proto != 'any':
                    services.append(
                        self._ServiceToString(proto, source_port,
                                              destination_port, icmp_types))

            services.append('</services>')

        service = ''
        for s in services:
            service = '%s%s' % (service, s)

        #action
        action = '%s%s%s' % (_XML_TABLE.get('actionStart'),
                             _ACTION_TABLE.get(str(self.term.action[0])),
                             _XML_TABLE.get('actionEnd'))

        ret_lines = []
        ret_lines.append(
            '<rule logged="%s"> %s %s %s %s %s %s </rule>' %
            (log, name, action, sources, destinations, service, notes))

        # remove any trailing spaces and replace multiple spaces with singles
        stripped_ret_lines = [
            re.sub(r'\s+', ' ', x).rstrip() for x in ret_lines
        ]
        ret_str.extend(stripped_ret_lines)
        return '\n'.join(ret_str)
Example #5
0
    def __str__(self):
        # Verify platform specific terms. Skip whole term if platform does not
        # match.
        if self.term.platform:
            if self._PLATFORM not in self.term.platform:
                return ''
        if self.term.platform_exclude:
            if self._PLATFORM in self.term.platform_exclude:
                return ''

        ret_str = []

        # Don't render icmpv6 protocol terms under inet, or icmp under inet6
        if ((self.af == 'inet6' and 'icmp' in self.term.protocol)
                or (self.af == 'inet' and 'icmpv6' in self.term.protocol)):
            ret_str.append('# Term %s' % self.term.name)
            ret_str.append('# not rendered due to protocol/AF mismatch.')
            return '\n'.join(ret_str)

        # Term verbatim output - this will skip over most normal term
        # creation code by returning early. Warnings provided in policy.py
        if self.term.verbatim:
            for next_verbatim in self.term.verbatim:
                if next_verbatim.value[0] == self._PLATFORM:
                    ret_str.append(str(next_verbatim.value[1]))
            return '\n'.join(ret_str)

        # We don't support these keywords for filtering, so unless users
        # put in a "verbatim:: iptables" statement, any output we emitted
        # would misleadingly suggest that we applied their filters.
        # Instead, we fail loudly.
        if self.term.ether_type:
            raise UnsupportedFilterError(
                '\n%s %s %s %s' % ('ether_type unsupported by', self._PLATFORM,
                                   '\nError in term', self.term.name))
        if self.term.address:
            raise UnsupportedFilterError(
                '\n%s %s %s %s %s' % ('address unsupported by', self._PLATFORM,
                                      '- specify source or dest',
                                      '\nError in term:', self.term.name))
        if self.term.port:
            raise UnsupportedFilterError(
                '\n%s %s %s %s %s' % ('port unsupported by', self._PLATFORM,
                                      '- specify source or dest',
                                      '\nError in term:', self.term.name))

        # Create a new term
        ret_str.append('-N %s' % self.term_name)  # New term

        if self._PREJUMP_FORMAT:
            ret_str.append(self._PREJUMP_FORMAT %
                           (self.filter, self.term_name))

        if self.term.owner:
            self.term.comment.append('Owner: %s' % self.term.owner)
        # reformat long comments, if needed
        #
        # iptables allows individual comments up to 256 chars.
        # But our generator will limit a single comment line to < 120, using:
        # max = 119 - 27 (static chars in comment command) - [length of term name]
        comment_max_width = 92 - len(self.term_name)
        if comment_max_width < 40:
            comment_max_width = 40
        comments = aclgenerator.WrapWords(self.term.comment, comment_max_width)
        # append comments to output
        if comments and comments[0]:
            for line in comments:
                if not line:
                    continue  # iptables-restore does not like 0-length comments.
                # term comments
                ret_str.append('-A %s -m comment --comment "%s"' %
                               (self.term_name, str(line)))

        # if terms does not specify action, use filter default action
        if not self.term.action:
            self.term.action[0].value = self.default_action

        # Unsupported configuration; in the case of 'accept' or 'next', we
        # skip the rule.  In other cases, we blow up (raise an exception)
        # to ensure that this is not considered valid configuration.
        if self.term.source_prefix or self.term.destination_prefix:
            if str(self.term.action[0]) not in set(['accept', 'next']):
                raise UnsupportedFilterError(
                    '%s %s %s %s %s %s %s %s' %
                    ('\nTerm', self.term.name, 'has action',
                     str(self.term.action[0]),
                     'with source_prefix or destination_prefix,',
                     ' which is unsupported in', self._PLATFORM,
                     'iptables output.'))
            return ('# skipped %s due to source or destination prefix rule' %
                    self.term.name)

        # protocol
        if self.term.protocol:
            protocol = self.term.protocol
        else:
            protocol = ['all']
        if self.term.protocol_except:
            raise UnsupportedFilterError(
                '%s %s %s' %
                ('\n', self.term.name,
                 'protocol_except logic not currently supported.'))

        # source address
        term_saddr = self.term.source_address
        exclude_saddr = self.term.source_address_exclude
        term_saddr_excluded = []
        if not term_saddr:
            term_saddr = [self._all_ips]
        if exclude_saddr:
            term_saddr_excluded.extend(
                nacaddr.ExcludeAddrs(term_saddr, exclude_saddr))

        # destination address
        term_daddr = self.term.destination_address
        exclude_daddr = self.term.destination_address_exclude
        term_daddr_excluded = []
        if not term_daddr:
            term_daddr = [self._all_ips]
        if exclude_daddr:
            term_daddr_excluded.extend(
                nacaddr.ExcludeAddrs(term_daddr, exclude_daddr))

        # Just to be safe, always have a result of at least 1 to avoid * by zero
        # returning incorrect results (10src*10dst=100, but 10src*0dst=0, not 10)
        bailout_count = len(exclude_saddr) + len(exclude_daddr) + (
            (len(self.term.source_address) or 1) *
            (len(self.term.destination_address) or 1))
        exclude_count = ((len(term_saddr_excluded) or 1) *
                         (len(term_daddr_excluded) or 1))

        # Use bailout jumps for excluded addresses if it results in fewer output
        # lines than nacaddr.ExcludeAddrs() method.
        if exclude_count < bailout_count:
            exclude_saddr = []
            exclude_daddr = []
            if term_saddr_excluded:
                term_saddr = term_saddr_excluded
            if term_daddr_excluded:
                term_daddr = term_daddr_excluded

        # With many sources and destinations, iptables needs to generate the
        # cartesian product of sources and destinations.  If there are no
        # exclude rules, this can instead be written as exclude [0/0 -
        # srcs], exclude [0/0 - dsts].
        v4_src_count = len([x for x in term_saddr if x.version == 4])
        v4_dst_count = len([x for x in term_daddr if x.version == 4])
        v6_src_count = len([x for x in term_saddr if x.version == 6])
        v6_dst_count = len([x for x in term_daddr if x.version == 6])
        num_pairs = v4_src_count * v4_dst_count + v6_src_count * v6_dst_count
        if num_pairs > 100:
            new_exclude_source = nacaddr.ExcludeAddrs([self._all_ips],
                                                      term_saddr)
            new_exclude_dest = nacaddr.ExcludeAddrs([self._all_ips],
                                                    term_daddr)
            # Invert the shortest list that does not already have exclude addresses
            if len(new_exclude_source) < len(
                    new_exclude_dest) and not exclude_saddr:
                if len(new_exclude_source) + len(term_daddr) < num_pairs:
                    exclude_saddr = new_exclude_source
                    term_saddr = [self._all_ips]
            elif not exclude_daddr:
                if len(new_exclude_dest) + len(term_saddr) < num_pairs:
                    exclude_daddr = new_exclude_dest
                    term_daddr = [self._all_ips]

        # ports
        source_port = []
        destination_port = []
        if self.term.source_port:
            source_port = self.term.source_port
        if self.term.destination_port:
            destination_port = self.term.destination_port

        # icmp-types
        icmp_types = ['']
        if self.term.icmp_type:
            icmp_types = self.NormalizeIcmpTypes(self.term.icmp_type, protocol,
                                                 self.af)

        source_interface = ''
        if self.term.source_interface:
            source_interface = self.term.source_interface

        destination_interface = ''
        if self.term.destination_interface:
            destination_interface = self.term.destination_interface

        log_hits = False
        if self.term.logging:
            # Iptables sends logs to hosts configured syslog
            log_hits = True

        # options
        tcp_flags = []
        tcp_track_options = []
        for next_opt in [str(x) for x in self.term.option]:
            #
            # Sanity checking and high-ports are added as appropriate in
            # pre-processing that is done in __str__ within class Iptables.
            # Option established will add destination port high-ports if protocol
            # contains only tcp, udp or both.  This is done earlier in class Iptables.
            #
            if ((next_opt.find('established') == 0
                 or next_opt.find('tcp-established') == 0)
                    and 'ESTABLISHED' not in [x.strip()
                                              for x in self.options]):
                if next_opt.find(
                        'tcp-established') == 0 and protocol != ['tcp']:
                    raise TcpEstablishedError('%s %s %s' % (
                        '\noption tcp-established can only be applied for proto tcp.',
                        '\nError in term:', self.term.name))

                if self.trackstate:
                    # Use nf_conntrack to track state -- works with any proto
                    self.options.append('-m state --state ESTABLISHED,RELATED')
                elif protocol == ['tcp']:
                    # Simple established-only rule for TCP: Must have ACK field
                    # (SYN/ACK or subsequent ACK), or RST and no other flags.
                    tcp_track_options = [(['ACK'], ['ACK']),
                                         (['SYN', 'FIN', 'ACK',
                                           'RST'], ['RST'])]

            # Iterate through flags table, and create list of tcp-flags to append
            for next_flag in self._TCP_FLAGS_TABLE:
                if next_opt.find(next_flag) == 0:
                    tcp_flags.append(self._TCP_FLAGS_TABLE.get(next_flag))
            if next_opt in self._KNOWN_OPTIONS_MATCHERS:
                self.options.append(self._KNOWN_OPTIONS_MATCHERS[next_opt])
        if self.term.packet_length:
            # Policy format is "#-#", but iptables format is "#:#"
            self.options.append('-m length --length %s' %
                                self.term.packet_length.replace('-', ':'))
        if self.term.fragment_offset:
            self.options.append('-m u32 --u32 4&0x1FFF=%s' %
                                self.term.fragment_offset.replace('-', ':'))

        for saddr in exclude_saddr:
            ret_str.extend(
                self._FormatPart(self.af, '', saddr, '', '', '', '', '',
                                 '', '', '', '', '',
                                 self._ACTION_TABLE.get('next')))
        for daddr in exclude_daddr:
            ret_str.extend(
                self._FormatPart(self.af, '', '', '', daddr, '', '', '',
                                 '', '', '', '', '',
                                 self._ACTION_TABLE.get('next')))

        for saddr in term_saddr:
            for daddr in term_daddr:
                for icmp in icmp_types:
                    for proto in protocol:
                        for tcp_matcher in tcp_track_options or (([], []), ):
                            ret_str.extend(
                                self._FormatPart(
                                    self.af, str(proto), saddr, source_port,
                                    daddr, destination_port, self.options,
                                    tcp_flags, icmp, tcp_matcher,
                                    source_interface, destination_interface,
                                    log_hits,
                                    self._ACTION_TABLE.get(
                                        str(self.term.action[0]))))

        if self._POSTJUMP_FORMAT:
            ret_str.append(self._POSTJUMP_FORMAT %
                           (self.filter, self.term_name))

        return '\n'.join(str(v) for v in ret_str if v is not '')
Example #6
0
    def __str__(self):
        # Verify platform specific terms. Skip whole term if platform does not
        # match.
        if self.term.platform:
            if 'cisco' not in self.term.platform:
                return ''
        if self.term.platform_exclude:
            if 'cisco' in self.term.platform_exclude:
                return ''

        ret_str = ['\n']

        # Don't render icmpv6 protocol terms under inet, or icmp under inet6
        if ((self.af == 6 and 'icmp' in self.term.protocol)
                or (self.af == 4 and 'icmpv6' in self.term.protocol)):
            ret_str.append('remark Term %s' % self.term.name)
            ret_str.append('remark not rendered due to protocol/AF mismatch.')
            return '\n'.join(ret_str)

        ret_str.append('remark ' + self.term.name)
        if self.term.owner:
            self.term.comment.append('Owner: %s' % self.term.owner)
        for comment in self.term.comment:
            for line in comment.split('\n'):
                ret_str.append('remark ' + str(line)[:100])

        # Term verbatim output - this will skip over normal term creation
        # code by returning early.  Warnings provided in policy.py.
        if self.term.verbatim:
            for next_verbatim in self.term.verbatim:
                if next_verbatim.value[0] == 'cisco':
                    ret_str.append(str(next_verbatim.value[1]))
                return '\n'.join(ret_str)

        # protocol
        if not self.term.protocol:
            if self.af == 6:
                protocol = ['ipv6']
            else:
                protocol = ['ip']
        else:
            # pylint: disable-msg=C6402
            protocol = map(self.PROTO_MAP.get, self.term.protocol,
                           self.term.protocol)
            # pylint: disable-msg=C6402

        # source address
        if self.term.source_address:
            source_address = self.term.GetAddressOfVersion(
                'source_address', self.af)
            source_address_exclude = self.term.GetAddressOfVersion(
                'source_address_exclude', self.af)
            if source_address_exclude:
                source_address = nacaddr.ExcludeAddrs(source_address,
                                                      source_address_exclude)
            if not source_address:
                logging.warn(
                    self.NO_AF_LOG_FORMAT.substitute(term=self.term.name,
                                                     direction='source',
                                                     af=self.text_af))
                return ''
        else:
            # source address not set
            source_address = ['any']

        # destination address
        if self.term.destination_address:
            destination_address = self.term.GetAddressOfVersion(
                'destination_address', self.af)
            destination_address_exclude = self.term.GetAddressOfVersion(
                'destination_address_exclude', self.af)
            if destination_address_exclude:
                destination_address = nacaddr.ExcludeAddrs(
                    destination_address, destination_address_exclude)
            if not destination_address:
                logging.warn(
                    self.NO_AF_LOG_FORMAT.substitute(term=self.term.name,
                                                     direction='destination',
                                                     af=self.text_af))
                return ''
        else:
            # destination address not set
            destination_address = ['any']

        # options
        opts = [str(x) for x in self.term.option]
        if self.PROTO_MAP['tcp'] in protocol and ('tcp-established' in opts
                                                  or 'established' in opts):
            self.options.extend(['established'])

        # ports
        source_port = [()]
        destination_port = [()]
        if self.term.source_port:
            source_port = self.term.source_port
        if self.term.destination_port:
            destination_port = self.term.destination_port

        # logging
        if self.term.logging:
            self.options.append('log')

        # icmp-types
        icmp_types = ['']
        if self.term.icmp_type:
            icmp_types = self.NormalizeIcmpTypes(self.term.icmp_type,
                                                 self.term.protocol, self.af)

        for saddr in source_address:
            for daddr in destination_address:
                for sport in source_port:
                    for dport in destination_port:
                        for proto in protocol:
                            for icmp_type in icmp_types:
                                ret_str.extend(
                                    self._TermletToStr(
                                        _ACTION_TABLE.get(
                                            str(self.term.action[0])), proto,
                                        saddr, sport, daddr, dport, icmp_type,
                                        self.options))

        return '\n'.join(ret_str)
Example #7
0
    def _CalculateAddresses(self, term_saddr, exclude_saddr, term_daddr,
                            exclude_daddr):
        """Calculate source and destination address list for a term.

    Args:
      term_saddr: source address list of the term
      exclude_saddr: source address exclude list of the term
      term_daddr: destination address list of the term
      exclude_daddr: destination address exclude list of the term

    Returns:
      tuple containing source address list, source exclude address list,
      destination address list, destination exclude address list in
      that order

    """
        # source address
        term_saddr_excluded = []
        if not term_saddr:
            term_saddr = [self._all_ips]
        if exclude_saddr:
            term_saddr_excluded.extend(
                nacaddr.ExcludeAddrs(term_saddr, exclude_saddr))

        # destination address
        term_daddr_excluded = []
        if not term_daddr:
            term_daddr = [self._all_ips]
        if exclude_daddr:
            term_daddr_excluded.extend(
                nacaddr.ExcludeAddrs(term_daddr, exclude_daddr))

        # Just to be safe, always have a result of at least 1 to avoid * by zero
        # returning incorrect results (10src*10dst=100, but 10src*0dst=0, not 10)
        bailout_count = len(exclude_saddr) + len(exclude_daddr) + (
            (len(self.term.source_address) or 1) *
            (len(self.term.destination_address) or 1))
        exclude_count = ((len(term_saddr_excluded) or 1) *
                         (len(term_daddr_excluded) or 1))

        # Use bailout jumps for excluded addresses if it results in fewer output
        # lines than nacaddr.ExcludeAddrs() method.
        if exclude_count < bailout_count:
            exclude_saddr = []
            exclude_daddr = []
            if term_saddr_excluded:
                term_saddr = term_saddr_excluded
            if term_daddr_excluded:
                term_daddr = term_daddr_excluded

        # With many sources and destinations, iptables needs to generate the
        # cartesian product of sources and destinations.  If there are no
        # exclude rules, this can instead be written as exclude [0/0 -
        # srcs], exclude [0/0 - dsts].
        v4_src_count = len([x for x in term_saddr if x.version == 4])
        v4_dst_count = len([x for x in term_daddr if x.version == 4])
        v6_src_count = len([x for x in term_saddr if x.version == 6])
        v6_dst_count = len([x for x in term_daddr if x.version == 6])
        num_pairs = v4_src_count * v4_dst_count + v6_src_count * v6_dst_count
        if num_pairs > 100:
            new_exclude_source = nacaddr.ExcludeAddrs([self._all_ips],
                                                      term_saddr)
            new_exclude_dest = nacaddr.ExcludeAddrs([self._all_ips],
                                                    term_daddr)
            # Invert the shortest list that does not already have exclude addresses
            if len(new_exclude_source) < len(
                    new_exclude_dest) and not exclude_saddr:
                if len(new_exclude_source) + len(term_daddr) < num_pairs:
                    exclude_saddr = new_exclude_source
                    term_saddr = [self._all_ips]
            elif not exclude_daddr:
                if len(new_exclude_dest) + len(term_saddr) < num_pairs:
                    exclude_daddr = new_exclude_dest
                    term_daddr = [self._all_ips]
        term_saddr = [
            x for x in term_saddr if x.version == self.AF_MAP[self.af]
        ]
        exclude_saddr = [
            x for x in exclude_saddr if x.version == self.AF_MAP[self.af]
        ]
        term_daddr = [
            x for x in term_daddr if x.version == self.AF_MAP[self.af]
        ]
        exclude_daddr = [
            x for x in exclude_daddr if x.version == self.AF_MAP[self.af]
        ]
        return (term_saddr, exclude_saddr, term_daddr, exclude_daddr)