Ejemplo n.º 1
0
    def __str__(self):
        """Render the output of the PF policy into config."""
        target = []
        pretty_platform = '%s%s' % (self._PLATFORM[0].upper(),
                                    self._PLATFORM[1:])

        for (header, filter_name, filter_type, terms) in self.pf_policies:
            # Add comments for this filter
            target.append('# %s %s Policy' %
                          (pretty_platform, header.FilterName(self._PLATFORM)))

            # reformat long text comments, if needed
            comments = aclgenerator.WrapWords(header.comment, 70)
            if comments and comments[0]:
                for line in comments:
                    target.append('# %s' % line)
                target.append('#')
            # add the p4 tags
            target.extend(aclgenerator.AddRepositoryTags('# '))
            target.append('# ' + filter_type)

            # add the terms
            for term in terms:
                term_str = str(term)
                if term_str:
                    target.append(term_str)
            target.append('')

        return '\n'.join(target)
Ejemplo n.º 2
0
  def __str__(self):
    """Render the output of the PF policy into config."""
    target = []
    pretty_platform = '%s%s' % (self._PLATFORM[0].upper(), self._PLATFORM[1:])
    # Create address table.
    for name in sorted(self.address_book):
      entries = ',\\\n'.join(str(x) for x in
                             sorted(self.address_book[name], key=int))
      target.append('table <%s> {%s}' % (name, entries))
    # pylint: disable=unused-variable
    for (header, filter_name, filter_type, terms) in self.pf_policies:
      # Add comments for this filter
      target.append('# %s %s Policy' % (pretty_platform,
                                        header.FilterName(self._PLATFORM)))

      # reformat long text comments, if needed
      comments = aclgenerator.WrapWords(header.comment, 70)
      if comments and comments[0]:
        for line in comments:
          target.append('# %s' % line)
        target.append('#')
      # add the p4 tags
      target.extend(aclgenerator.AddRepositoryTags('# '))
      target.append('# ' + filter_type)

      # add the terms
      for term in terms:
        term_str = str(term)
        if term_str:
          target.append(term_str)
      target.append('')

    return '\n'.join(target)
Ejemplo n.º 3
0
    def __str__(self):
        target = []
        pretty_platform = '%s%s' % (self._PLATFORM[0].upper(),
                                    self._PLATFORM[1:])

        if self._RENDER_PREFIX:
            target.append(self._RENDER_PREFIX)

        for (header, filter_name, filter_type, default_action,
             terms) in self.iptables_policies:
            # Add comments for this filter
            target.append('# %s %s Policy' %
                          (pretty_platform, header.FilterName(self._PLATFORM)))

            # reformat long text comments, if needed
            comments = aclgenerator.WrapWords(header.comment, 70)
            if comments and comments[0]:
                for line in comments:
                    target.append('# %s' % line)
                target.append('#')
            # add the p4 tags
            target.extend(aclgenerator.AddRepositoryTags('# '))
            target.append('# ' + filter_type)

            if filter_name in self._GOOD_FILTERS:
                if default_action:
                    target.append(self._DEFAULTACTION_FORMAT %
                                  (filter_name, default_action))
                elif self._PLATFORM == 'speedway':
                    # always specify the default filter states for speedway,
                    # if default action policy not specified for iptables, do nothing.
                    target.append(self._DEFAULTACTION_FORMAT %
                                  (filter_name, self._DEFAULT_ACTION))
            else:
                # Custom chains have no concept of default policy.
                target.append(self._DEFAULTACTION_FORMAT_CUSTOM_CHAIN %
                              filter_name)
            # add the terms
            for term in terms:
                term_str = str(term)
                if term_str:
                    target.append(term_str)

        if self._RENDER_SUFFIX:
            target.append(self._RENDER_SUFFIX)

        target.append('')
        return '\n'.join(target)
Ejemplo n.º 4
0
    def __str__(self):
        """Render config output from this term object."""
        # Verify platform specific terms. Skip whole term if platform does not
        # match.
        if self.term.platform:
            if 'srx' not in self.term.platform:
                return ''
        if self.term.platform_exclude:
            if 'srx' in self.term.platform_exclude:
                return ''
        ret_str = []

        # COMMENTS
        comment_max_width = 68
        if self.term.owner:
            self.term.comment.append('Owner: %s' % self.term.owner)
        comments = aclgenerator.WrapWords(self.term.comment, comment_max_width)
        if comments and comments[0]:
            ret_str.append(JuniperSRX.INDENT * 3 + '/*')
            for line in comments:
                ret_str.append(JuniperSRX.INDENT * 3 + line)
            ret_str.append(JuniperSRX.INDENT * 3 + '*/')

        ret_str.append(JuniperSRX.INDENT * 3 + 'policy ' + self.term.name +
                       ' {')
        ret_str.append(JuniperSRX.INDENT * 4 + 'match {')

        # SOURCE-ADDRESS
        if self.term.source_address:
            saddr_check = set()
            for saddr in self.term.source_address:
                saddr_check.add(saddr.parent_token)
            saddr_check = sorted(saddr_check)
            source_address_string = ''
            for addr in saddr_check:
                source_address_string += addr + ' '
            ret_str.append(JuniperSRX.INDENT * 5 + 'source-address [ ' +
                           source_address_string + '];')
        else:
            ret_str.append(JuniperSRX.INDENT * 5 + 'source-address any;')

        # DESTINATION-ADDRESS
        if self.term.destination_address:
            daddr_check = []
            for daddr in self.term.destination_address:
                daddr_check.append(daddr.parent_token)
            daddr_check = set(daddr_check)
            daddr_check = list(daddr_check)
            daddr_check.sort()
            destination_address_string = ''
            for addr in daddr_check:
                destination_address_string += addr + ' '
            ret_str.append(JuniperSRX.INDENT * 5 + 'destination-address [ ' +
                           destination_address_string + '];')
        else:
            ret_str.append(JuniperSRX.INDENT * 5 + 'destination-address any;')

        # APPLICATION
        if (not self.term.source_port and not self.term.destination_port
                and not self.term.icmp_type and not self.term.protocol):
            ret_str.append(JuniperSRX.INDENT * 5 + 'application any;')
        else:
            ret_str.append(JuniperSRX.INDENT * 5 + 'application ' +
                           self.term.name + '-app;')

        ret_str.append(JuniperSRX.INDENT * 4 + '}')

        # ACTIONS
        for action in self.term.action:
            ret_str.append(JuniperSRX.INDENT * 4 + 'then {')
            ret_str.append(JuniperSRX.INDENT * 5 +
                           self._ACTIONS.get(str(action)) + ';')

            # LOGGING
            if self.term.logging:
                ret_str.append(JuniperSRX.INDENT * 5 + 'log {')
                ret_str.append(JuniperSRX.INDENT * 6 + 'session-init;')
                ret_str.append(JuniperSRX.INDENT * 5 + '}')
            ret_str.append(JuniperSRX.INDENT * 4 + '}')

            ret_str.append(JuniperSRX.INDENT * 3 + '}')

        # OPTIONS
        if self.term.option:
            raise SRXOptionError(
                'Options are not implemented yet, please remove ' +
                'from term %s' % self.term.name)

        # VERBATIM
        if self.term.verbatim:
            raise SRXVerbatimError(
                'Verbatim is not implemented, please remove ' +
                'the offending term %s.' % self.term.name)
        return '\n'.join(ret_str)
Ejemplo n.º 5
0
  def __str__(self):
    """Render config output from this term object."""

    # 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 = []
    self._SetDefaultAction()

    # Create a new term
    ret_str.append('\n# term %s' % self.term.name)

    comments = aclgenerator.WrapWords(self.term.comment, 80)
    # append comments to output
    if comments and comments[0]:
      for line in comments:
        ret_str.append('# %s' % str(line))

    if str(self.term.action[0]) not in self._ACTION_TABLE:
      raise aclgenerator.UnsupportedFilterError('%s %s %s %s' % (
          '\n', self.term.name, self.term.action[0],
          'action not currently supported.'))

    if self.direction and str(self.direction) not in self._DIRECTION_TABLE:
      raise aclgenerator.UnsupportedFilterError('%s %s %s %s' % (
          '\n', self.term.name, self.term.direction,
          'direction not currently supported.'))
    # protocol
    if self.term.protocol:
      protocol = self.term.protocol
    else:
      protocol = []
    if self.term.protocol_except:
      raise aclgenerator.UnsupportedFilterError('%s %s %s' % (
          '\n', self.term.name,
          'protocol_except logic not currently supported.'))

    # source address
    term_saddrs = self._CheckAddressAf(self.term.source_address)
    if not term_saddrs:
      logging.debug(self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                                   direction='source',
                                                   af=self.af))
      return ''
    term_saddr = self._GenerateAddrStatement(
        term_saddrs, self.term.source_address_exclude)

    # destination address
    term_daddrs = self._CheckAddressAf(self.term.destination_address)
    if not term_daddrs:
      logging.debug(self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                                   direction='destination',
                                                   af=self.af))
      return ''
    term_daddr = self._GenerateAddrStatement(
        term_daddrs, self.term.destination_address_exclude)

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

    # icmp-type
    icmp_types = ['']
    if self.term.icmp_type:
      if self.af != 'mixed':
        af = self.af
      elif protocol == ['icmp']:
        af = 'inet'
      elif protocol == ['icmpv6']:
        af = 'inet6'
      else:
        raise aclgenerator.UnsupportedFilterError('%s %s %s' % (
            '\n', self.term.name,
            'icmp protocol is not defined or not supported.'))
      icmp_types = self.NormalizeIcmpTypes(
          self.term.icmp_type, protocol, af)

    # options
    tcp_flags_set = []
    tcp_flags_check = []
    for next_opt in [str(x) for x in self.term.option]:
      for next_flag in self._TCP_FLAGS_TABLE:
        if next_opt.find(next_flag) == 0:
          if protocol != ['tcp']:
            raise aclgenerator.UnsupportedFilterError('%s %s %s' % (
                '\n', self.term.name,
                'tcp flags may only be specified with tcp protocol.'))
          tcp_flags_set.append(self._TCP_FLAGS_TABLE.get(next_flag))
          tcp_flags_check.append(self._TCP_FLAGS_TABLE.get(next_flag))

    # If tcp-established is set, override any of the flags above with the
    # S/SA flags.  Issue an error if flags are specified with 'established'.
    for opt in [str(x) for x in self.term.option]:
      if opt == 'established' or opt == 'tcp-established':
        if tcp_flags_set or tcp_flags_check:
          raise aclgenerator.UnsupportedFilterError('%s %s %s' % (
              '\n', self.term.name,
              'tcp flags may not be specified with tcp-established.'))
        # We need to set 'flags A/A' for established regardless of whether or
        # not we're stateful:
        # - if we stateful, the default is 'flags S/SA' which prevent writing
        # rules for reply packets.
        # - if we're stateless, this is the only way to do it.
        if not protocol or 'tcp' in protocol:
          tcp_flags_set.append(self._TCP_FLAGS_TABLE.get('ack'))
          tcp_flags_check.append(self._TCP_FLAGS_TABLE.get('ack'))

    # The default behavior of pf is 'keep state flags S/SA'.  If we're not
    # stateless, and if flags have not been specified explicitly via options,
    # append that here.  Note that pf allows appending flags for udp and icmp;
    # they are just ignored, as long as TCP is in the proto.  This lets you
    # doing things like 'proto { tcp udp icmp } flags S/SA' and have the flags
    # only applied to the tcp bits that match.  However, the policy description
    # language prohibits setting flags on non-TCP, since it doesn't make sense
    # on all platforms.
    if ((not protocol or protocol == ['tcp']) and self.stateful
        and not tcp_flags_set and not tcp_flags_check):
      tcp_flags_set.append(self._TCP_FLAGS_TABLE.get('syn'))
      tcp_flags_check.append(self._TCP_FLAGS_TABLE.get('syn'))
      tcp_flags_check.append(self._TCP_FLAGS_TABLE.get('ack'))

    ret_str.extend(self._FormatPart(
        self.term.action[0],
        self.direction,
        self.term.logging,
        self.af,
        protocol,
        term_saddr,
        source_port,
        term_daddr,
        destination_port,
        tcp_flags_set,
        tcp_flags_check,
        icmp_types,
        self.options,
        self.stateful,))

    return '\n'.join(str(v) for v in ret_str if v is not '')
Ejemplo n.º 6
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 '')
Ejemplo n.º 7
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 = []

        # 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)

        v4_addresses = [
            x for x in self.term.address if type(x) != nacaddr.IPv6
        ]
        if self.filter_name.isdigit():
            ret_str.append('access-list %s remark %s' %
                           (self.filter_name, self.term.name))

            comment_max_width = 70
            comments = aclgenerator.WrapWords(self.term.comment,
                                              comment_max_width)
            if comments and comments[0]:
                for comment in comments:
                    ret_str.append('access-list %s remark %s' %
                                   (self.filter_name, comment))

            action = _ACTION_TABLE.get(str(self.term.action[0]))
            if v4_addresses:
                for addr in v4_addresses:
                    if addr.prefixlen == 32:
                        ret_str.append('access-list %s %s %s%s' %
                                       (self.filter_name, action, addr.ip,
                                        self.logstring))
                    else:
                        ret_str.append('access-list %s %s %s %s%s' %
                                       (self.filter_name, action, addr.network,
                                        addr.hostmask, self.logstring))
            else:
                ret_str.append(
                    'access-list %s %s %s%s' %
                    (self.filter_name, action, 'any', self.logstring))

        else:
            ret_str.append('remark ' + self.term.name)
            comment_max_width = 70
            comments = aclgenerator.WrapWords(self.term.comment,
                                              comment_max_width)
            if comments and comments[0]:
                for comment in comments:
                    ret_str.append('remark ' + str(comment))

            action = _ACTION_TABLE.get(str(self.term.action[0]))
            if v4_addresses:
                for addr in v4_addresses:
                    if addr.prefixlen == 32:
                        ret_str.append(' %s %s%s' %
                                       (action, addr.ip, self.logstring))
                    else:
                        ret_str.append(' %s %s %s%s' %
                                       (action, addr.network, addr.hostmask,
                                        self.logstring))
            else:
                ret_str.append(' %s %s%s' % (action, 'any', self.logstring))

        return '\n'.join(ret_str)
Ejemplo n.º 8
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 ''

        source_address_dict = {}
        destination_address_dict = {}

        ret_str = ['\n']
        ret_str.append('remark %s' % self.term.name)
        comment_max_width = 70
        comments = aclgenerator.WrapWords(self.term.comment, comment_max_width)
        if comments and comments[0]:
            for comment in comments:
                ret_str.append('remark %s' % str(comment))

        # 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:
            protocol = ['ip']
        else:
            # pylint: disable-msg=C6402
            protocol = map(self.PROTO_MAP.get, self.term.protocol,
                           self.term.protocol)
            # pylint: enable-msg=C6402

        # addresses
        source_address = self.term.source_address
        if not self.term.source_address:
            source_address = [nacaddr.IPv4('0.0.0.0/0', token='ANY')]
        source_address_dict[source_address[0].parent_token] = True

        destination_address = self.term.destination_address
        if not self.term.destination_address:
            destination_address = [nacaddr.IPv4('0.0.0.0/0', token='ANY')]
        destination_address_dict[destination_address[0].parent_token] = True
        # 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

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

        return '\n'.join(ret_str)
Ejemplo n.º 9
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)):
            logging.debug(
                self.NO_AF_LOG_PROTO.substitute(term=self.term.name,
                                                proto=self.term.protocol,
                                                af=self.af))
            return ''

        # 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
        self._SetDefaultAction()
        if self._TERM_FORMAT:
            ret_str.append(self._TERM_FORMAT.substitute(term=self.term_name))

        if self._PREJUMP_FORMAT:
            ret_str.append(
                self._PREJUMP_FORMAT.substitute(filter=self.filter,
                                                term=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(
                    self._COMMENT_FORMAT.substitute(filter=self.filter,
                                                    term=self.term_name,
                                                    comment=str(line)))

        # 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.'))

        (term_saddr, exclude_saddr, term_daddr,
         exclude_daddr) = self._CalculateAddresses(
             self.term.source_address, self.term.source_address_exclude,
             self.term.destination_address,
             self.term.destination_address_exclude)
        if not term_saddr:
            logging.debug(
                self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                               direction='source',
                                               af=self.af))
            return ''
        if not term_daddr:
            logging.debug(
                self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                               direction='destination',
                                               af=self.af))
            return ''

        # 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('', saddr, '', '', '', '', '', '', '', '', '',
                                 '', self._ACTION_TABLE.get('next')))
        for daddr in exclude_daddr:
            ret_str.extend(
                self._FormatPart('', '', '', 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(
                                    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.substitute(filter=self.filter,
                                                 term=self.term_name))

        return '\n'.join(str(v) for v in ret_str if v is not '')