Esempio n. 1
0
 def testSummarizeToAllSpace(self):
     nets = [
         nacaddr.IPv4('0.0.0.0/1'),
         nacaddr.IPv4('128.0.0.0/1'),
     ]
     random.shuffle(nets)
     result = summarizer.Summarize(nets)
     self.assertEqual(result, [summarizer.DSMNet(0, 0)])
Esempio n. 2
0
 def testSummarizeNoNetworks(self):
     nets = []
     for octet in range(0, 256):
         net = nacaddr.IPv4('192.' + str(255 - octet) + '.' + str(octet) +
                            '.64/27')
         nets.append(net)
     random.shuffle(nets)
     result = summarizer.Summarize(nets)
     self.assertEqual(len(result), 256)
Esempio n. 3
0
 def testSummarizeAllNetworks(self):
     nets = []
     for octet in range(0, 256):
         net = nacaddr.IPv4('192.168.' + str(octet) + '.64/27')
         nets.append(net)
     random.shuffle(nets)
     result = summarizer.Summarize(nets)
     # summarizes to 192.168.0.64 / 255.255.0.224
     self.assertEqual(result, [summarizer.DSMNet(3232235584, 4294901984)])
Esempio n. 4
0
 def testOrder(self):
     nets = [
         # not discontinously summarizable with the other two
         nacaddr.IPv4('209.85.147.129/32'),
         # discontinuosly summarizable, but should come before the first one
         nacaddr.IPv4('74.125.20.129/32'),
         nacaddr.IPv4('74.125.21.129/32'),
     ]
     result = summarizer.Summarize(nets)
     self.assertEqual(result, [
         summarizer.DSMNet(1249711233, 4294967039),
         summarizer.DSMNet(3512046465, 4294967295)
     ])
Esempio n. 5
0
 def testSummarizeSomeNetworks(self):
     nets = [
         # continiously summarizable to one /25
         nacaddr.IPv4('192.168.0.0/27'),
         nacaddr.IPv4('192.168.0.32/27'),
         nacaddr.IPv4('192.168.0.64/27'),
         nacaddr.IPv4('192.168.0.96/27'),
         # discontiniously summarizable with above
         nacaddr.IPv4('128.168.0.0/25'),
         # not summarizable with above
         nacaddr.IPv4('10.0.0.0/8'),
     ]
     for octet in range(0, 256):
         net = nacaddr.IPv4('172.16.' + str(octet) + '.96/30')
         nets.append(net)
     random.shuffle(nets)
     result = summarizer.Summarize(nets)
     self.assertEqual(result, [
         summarizer.DSMNet(167772160, 4278190080),
         summarizer.DSMNet(2158493696, 3221225344),
         summarizer.DSMNet(2886729824, 4294902012)
     ])
Esempio n. 6
0
    def testSummarizeDSMONetworks(self):
        fourth_octet = [
            2, 8, 20, 26, 28, 32, 40, 52, 58, 86, 130, 136, 148, 154, 156, 160,
            168, 180, 186, 214
        ]
        nets = list()

        for octet3 in range(56, 60):
            for octet4 in fourth_octet:
                nets.append(
                    nacaddr.IPv4('192.168.' + str(octet3) + '.' + str(octet4) +
                                 '/31'))

        result = summarizer.Summarize(nets)
        self.assertEqual(result, [
            summarizer.DSMNet(3232249858, 4294966398),
            summarizer.DSMNet(3232249864, 4294966366),
            summarizer.DSMNet(3232249876, 4294966390),
            summarizer.DSMNet(3232249882, 4294966366),
            summarizer.DSMNet(3232249888, 4294966398),
            summarizer.DSMNet(3232249908, 4294966398),
            summarizer.DSMNet(3232249942, 4294966398),
        ])
Esempio n. 7
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 ''

        config = Config(indent=self._DEFAULT_INDENT)
        from_str = []
        # Don't render icmpv6 protocol terms under inet, or icmp under inet6
        if ((self.term_type == 'inet6' and 'icmp' in self.term.protocol) or
            (self.term_type == 'inet' and ('icmpv6' in self.term.protocol
                                           or 'icmp6' in self.term.protocol))):
            logging.debug(
                self.NO_AF_LOG_PROTO.substitute(term=self.term.name,
                                                proto=', '.join(
                                                    self.term.protocol),
                                                af=self.term_type))
            return ''

        # comment
        # this deals just fine with multi line comments, but we could probably
        # output them a little cleaner; do things like make sure the
        # len(output) < 80, etc. Note, if 'noverbose' is set for the filter, skip
        # all comment processing.
        if self.term.owner and not self.noverbose:
            self.term.comment.append('Owner: %s' % self.term.owner)
        if self.term.comment and not self.noverbose:
            config.Append('/*')
            for comment in self.term.comment:
                for line in comment.split('\n'):
                    config.Append('** ' + line)
            config.Append('*/')

        # Term verbatim output - this will skip over normal term creation
        # code.  Warning generated from policy.py if appropriate.
        if self.term.verbatim:
            for next_term in self.term.verbatim:
                if next_term[0] == self._PLATFORM:
                    config.Append(str(next_term[1]), verbatim=True)
            return str(config)

        # Helper for per-address-family keywords.
        family_keywords = self._TERM_TYPE.get(self.term_type)

        # option
        # this is going to be a little ugly b/c there are a few little messed
        # up options we can deal with.
        if self.term.option:
            for opt in [str(x) for x in self.term.option]:
                # there should be a better way to search the array of protocols
                if opt.startswith('sample'):
                    self.extra_actions.append('sample')

                # only append tcp-established for option established when
                # tcp is the only protocol, otherwise other protos break on juniper
                elif opt.startswith('established'):
                    if self.term.protocol == ['tcp']:
                        if 'tcp-established;' not in from_str:
                            from_str.append(family_keywords['tcp-est'] + ';')

                # if tcp-established specified, but more than just tcp is included
                # in the protocols, raise an error
                elif opt.startswith('tcp-established'):
                    flag = family_keywords['tcp-est'] + ';'
                    if self.term.protocol == ['tcp']:
                        if flag not in from_str:
                            from_str.append(flag)
                    else:
                        raise TcpEstablishedWithNonTcpError(
                            'tcp-established can only be used with tcp protocol in term %s'
                            % self.term.name)
                elif opt.startswith('rst'):
                    from_str.append('tcp-flags "rst";')
                elif opt.startswith('initial') and 'tcp' in self.term.protocol:
                    from_str.append('tcp-initial;')
                elif opt.startswith('first-fragment'):
                    from_str.append('first-fragment;')

                # we don't have a special way of dealing with this, so we output it and
                # hope the user knows what they're doing.
                else:
                    from_str.append('%s;' % opt)

        # if the term is inactive we have to set the prefix
        if self.term.inactive:
            term_prefix = 'inactive:'
        else:
            term_prefix = ''

        # term name
        config.Append('%s term %s {' % (term_prefix, self.term.name))

        # The "filter" keyword is not compatible with from or then
        if self.term.filter_term:
            config.Append('filter %s;' % self.term.filter_term)
            config.Append('}')  # end term accept-foo-to-bar { ... }
            return str(config)

        # a default action term doesn't have any from { clause
        has_match_criteria = (
            self.term.address or self.term.dscp_except or self.term.dscp_match
            or self.term.destination_address or self.term.destination_port
            or self.term.destination_prefix
            or self.term.destination_prefix_except or self.term.encapsulate
            or self.term.ether_type or self.term.flexible_match_range
            or self.term.forwarding_class or self.term.forwarding_class_except
            or self.term.fragment_offset or self.term.hop_limit
            or self.term.next_ip or self.term.port or self.term.precedence
            or self.term.protocol or self.term.protocol_except
            or self.term.source_address or self.term.source_port
            or self.term.source_prefix or self.term.source_prefix_except
            or self.term.traffic_type or self.term.ttl)

        if has_match_criteria:
            config.Append('from {')

            term_af = self.AF_MAP.get(self.term_type)

            # address
            address = self.term.GetAddressOfVersion('address', term_af)
            if self.enable_dsmo:
                address = summarizer.Summarize(address)

            if address:
                config.Append('%s {' % family_keywords['addr'])
                for addr in address:
                    for comment in self._Comment(addr):
                        config.Append('%s' % comment)
                    if self.enable_dsmo:
                        config.Append(
                            '%s/%s;' %
                            summarizer.ToDottedQuad(addr, nondsm=True))
                    else:
                        config.Append('%s;' % addr)
                config.Append('}')
            elif self.term.address:
                logging.debug(
                    self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                                   af=self.term_type))
                return ''

            # source address

            src_addr = self.term.GetAddressOfVersion('source_address', term_af)
            src_addr_ex = self.term.GetAddressOfVersion(
                'source_address_exclude', term_af)
            if self.enable_dsmo:
                src_addr = summarizer.Summarize(src_addr)
                src_addr_ex = summarizer.Summarize(src_addr_ex)
            else:
                src_addr, src_addr_ex = self._MinimizePrefixes(
                    src_addr, src_addr_ex)

            if src_addr:
                config.Append('%s {' % family_keywords['saddr'])
                for addr in src_addr:
                    for comment in self._Comment(addr):
                        config.Append('%s' % comment)
                    if self.enable_dsmo:
                        config.Append(
                            '%s/%s;' %
                            summarizer.ToDottedQuad(addr, nondsm=True))
                    else:
                        config.Append('%s;' % addr)
                for addr in src_addr_ex:
                    for comment in self._Comment(addr, exclude=True):
                        config.Append('%s' % comment)
                    if self.enable_dsmo:
                        config.Append(
                            '%s/%s except;' %
                            summarizer.ToDottedQuad(addr, nondsm=True))
                    else:
                        config.Append('%s except;' % addr)
                config.Append('}')
            elif self.term.source_address:
                logging.debug(
                    self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                                   direction='source',
                                                   af=self.term_type))
                return ''

            # destination address
            dst_addr = self.term.GetAddressOfVersion('destination_address',
                                                     term_af)
            dst_addr_ex = self.term.GetAddressOfVersion(
                'destination_address_exclude', term_af)
            if self.enable_dsmo:
                dst_addr = summarizer.Summarize(dst_addr)
                dst_addr_ex = summarizer.Summarize(dst_addr_ex)
            else:
                dst_addr, dst_addr_ex = self._MinimizePrefixes(
                    dst_addr, dst_addr_ex)

            if dst_addr:
                config.Append('%s {' % family_keywords['daddr'])
                for addr in dst_addr:
                    for comment in self._Comment(addr):
                        config.Append('%s' % comment)
                    if self.enable_dsmo:
                        config.Append(
                            '%s/%s;' %
                            summarizer.ToDottedQuad(addr, nondsm=True))
                    else:
                        config.Append('%s;' % addr)
                for addr in dst_addr_ex:
                    for comment in self._Comment(addr, exclude=True):
                        config.Append('%s' % comment)
                    if self.enable_dsmo:
                        config.Append(
                            '%s/%s except;' %
                            summarizer.ToDottedQuad(addr, nondsm=True))
                    else:
                        config.Append('%s except;' % addr)
                config.Append('}')
            elif self.term.destination_address:
                logging.debug(
                    self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                                   direction='destination',
                                                   af=self.term_type))
                return ''

            # forwarding-class
            if self.term.forwarding_class:
                config.Append(
                    'forwarding-class %s' %
                    self._Group(self.term.forwarding_class, lc=False))

            # forwarding-class-except
            if self.term.forwarding_class_except:
                config.Append(
                    'forwarding-class-except %s' %
                    self._Group(self.term.forwarding_class_except, lc=False))

            # source prefix <except> list
            if self.term.source_prefix or self.term.source_prefix_except:
                config.Append('source-prefix-list {')
                for pfx in self.term.source_prefix:
                    config.Append(pfx + ';')
                for epfx in self.term.source_prefix_except:
                    config.Append(epfx + ' except;')
                config.Append('}')

            # destination prefix <except> list
            if self.term.destination_prefix or self.term.destination_prefix_except:
                config.Append('destination-prefix-list {')
                for pfx in self.term.destination_prefix:
                    config.Append(pfx + ';')
                for epfx in self.term.destination_prefix_except:
                    config.Append(epfx + ' except;')
                config.Append('}')

            # Only generate ttl if inet, inet6 uses hop-limit instead.
            if self.term.ttl and self.term_type == 'inet':
                config.Append('ttl %s;' % self.term.ttl)

            # protocol
            if self.term.protocol:
                # both are supported on JunOS, but only icmp6 is supported
                # on SRX loopback stateless filter
                config.Append(family_keywords['protocol'] + ' ' +
                              self._Group(self.term.protocol))

            # protocol
            if self.term.protocol_except:
                # same as above
                config.Append(family_keywords['protocol-except'] + ' ' +
                              self._Group(self.term.protocol_except))

            # port
            if self.term.port:
                config.Append('port %s' % self._Group(self.term.port))

            # source port
            if self.term.source_port:
                config.Append('source-port %s' %
                              self._Group(self.term.source_port))

            # destination port
            if self.term.destination_port:
                config.Append('destination-port %s' %
                              self._Group(self.term.destination_port))

            # append any options beloging in the from {} section
            for next_str in from_str:
                config.Append(next_str)

            # packet length
            if self.term.packet_length:
                config.Append('packet-length %s;' % self.term.packet_length)

            # fragment offset
            if self.term.fragment_offset:
                config.Append('fragment-offset %s;' %
                              self.term.fragment_offset)

            # icmp-types
            icmp_types = ['']
            if self.term.icmp_type:
                icmp_types = self.NormalizeIcmpTypes(self.term.icmp_type,
                                                     self.term.protocol,
                                                     self.term_type)
            if icmp_types != ['']:
                config.Append('icmp-type %s' % self._Group(icmp_types))
            if self.term.icmp_code:
                config.Append('icmp-code %s' %
                              self._Group(self.term.icmp_code))
            if self.term.ether_type:
                config.Append('ether-type %s' %
                              self._Group(self.term.ether_type))

            if self.term.traffic_type:
                config.Append('traffic-type %s' %
                              self._Group(self.term.traffic_type))

            if self.term.precedence:
                # precedence may be a single integer, or a space separated list
                policy_precedences = set()
                # precedence values may only be 0 through 7
                for precedence in self.term.precedence:
                    if int(precedence) in range(0, 8):
                        policy_precedences.add(precedence)
                    else:
                        raise PrecedenceError(
                            'Precedence value %s is out of bounds in %s' %
                            (precedence, self.term.name))
                config.Append('precedence %s' %
                              self._Group(sorted(policy_precedences)))

            # DSCP Match
            if self.term.dscp_match:
                if self.term_type == 'inet6':
                    config.Append('traffic-class [ %s ];' %
                                  (' '.join(self.term.dscp_match)))
                else:
                    config.Append('dscp [ %s ];' %
                                  ' '.join(self.term.dscp_match))

            # DSCP Except
            if self.term.dscp_except:
                if self.term_type == 'inet6':
                    config.Append('traffic-class-except [ %s ];' %
                                  (' '.join(self.term.dscp_except)))
                else:
                    config.Append('dscp-except [ %s ];' %
                                  ' '.join(self.term.dscp_except))

            if self.term.hop_limit:
                # Only generate a hop-limit if inet6, inet4 has not hop-limit.
                if self.term_type == 'inet6':
                    config.Append('hop-limit %s;' % (self.term.hop_limit))

            # flexible-match
            if self.term.flexible_match_range:
                config.Append('flexible-match-range {')
                for fm_opt in self.term.flexible_match_range:
                    config.Append('%s %s;' % (fm_opt[0], fm_opt[1]))
                config.Append('}')

            config.Append('}')  # end from { ... }

        ####
        # ACTIONS go below here
        ####

        # If the action is only one line, include it in the same line as "then "
        # statement.
        # For example, if the action is only accept, it should be:
        # "then accept;" rather than:
        # "then {
        #     accept;
        # }"
        #
        self.CheckTerminatingAction()
        unique_actions = set(self.extra_actions)
        if not self.term.routing_instance:
            unique_actions.update(self.term.action)
        if self.term.encapsulate:
            unique_actions.add('encapsulate')
        if len(unique_actions) <= 1:
            for action in [
                    self.term.logging, self.term.routing_instance,
                    self.term.counter, self.term.policer, self.term.qos,
                    self.term.loss_priority, self.term.dscp_set,
                    self.term.next_ip, self.term.traffic_class_count
            ]:
                if action:
                    try:
                        unique_actions.update(action)
                    except TypeError:
                        unique_actions.add(action)
                    if len(unique_actions) > 1:
                        break

        if len(unique_actions) == 1:
            # b/21795531: Juniper device treats a set of IPv4 actions differently
            # than any other actions.
            # For example, if the term is in IPv4 and the action is only discard,
            # it should be:
            # "then {
            #     discard;
            # }" rather than:
            # "then discard;"
            current_action = self.ACTIONS.get(unique_actions.pop(), 'next_ip')
            if (self.term_type == 'inet' and current_action in [
                    'discard', 'reject', 'reject tcp-reset'
            ]) or (self.term_type == 'inet6'
                   and current_action in ['reject', 'reject tcp-reset']):
                config.Append('then {')
                config.Append('%s;' % current_action)
                config.Append('}')
            elif current_action == 'next_ip':
                self.NextIpCheck(self.term.next_ip, self.term.name)
                config.Append('then {')
                if self.term.next_ip[0].version == 4:
                    config.Append('next-ip %s;' % str(self.term.next_ip[0]))
                else:
                    config.Append('next-ip6 %s;' % str(self.term.next_ip[0]))
                config.Append('}')
            elif current_action == 'encapsulate':
                config.Append('then {')
                config.Append('encapsulate %s;' % str(self.term.encapsulate))
                config.Append('}')
            else:
                config.Append('then %s;' % current_action)
        elif len(unique_actions) > 1:
            config.Append('then {')
            # logging
            if self.term.logging:
                for log_target in self.term.logging:
                    if str(log_target) == 'local':
                        config.Append('log;')
                    else:
                        config.Append('syslog;')

            if self.term.routing_instance:
                config.Append('routing-instance %s;' %
                              self.term.routing_instance)

            if self.term.counter:
                config.Append('count %s;' % self.term.counter)

            if self.term.traffic_class_count:
                config.Append('traffic-class-count %s;' %
                              self.term.traffic_class_count)

            oid_length = 128
            if self.term.policer:
                config.Append('policer %s;' % self.term.policer)
                if len(self.term.policer) > oid_length:
                    logging.warning(
                        'WARNING: %s is longer than %d bytes. Due to '
                        'limitation in JUNOS, OIDs longer than %dB can '
                        'cause SNMP timeout issues.', self.term.policer,
                        oid_length, oid_length)

            if self.term.qos:
                config.Append('forwarding-class %s;' % self.term.qos)

            if self.term.loss_priority:
                config.Append('loss-priority %s;' % self.term.loss_priority)
            if self.term.next_ip:
                self.NextIpCheck(self.term.next_ip, self.term.name)
                if self.term.next_ip[0].version == 4:
                    config.Append('next-ip %s;' % str(self.term.next_ip[0]))
                else:
                    config.Append('next-ip6 %s;' % str(self.term.next_ip[0]))
            if self.term.encapsulate:
                config.Append('encapsulate %s;' % str(self.term.encapsulate))
            for action in self.extra_actions:
                config.Append(action + ';')

            # If there is a routing-instance defined, skip reject/accept/etc actions.
            if not self.term.routing_instance:
                for action in self.term.action:
                    config.Append(self.ACTIONS.get(action) + ';')

            # DSCP SET
            if self.term.dscp_set:
                if self.term_type == 'inet6':
                    config.Append('traffic-class %s;' % self.term.dscp_set)
                else:
                    config.Append('dscp %s;' % self.term.dscp_set)

            config.Append('}')  # end then{...}

        config.Append('}')  # end term accept-foo-to-bar { ... }

        return str(config)
Esempio n. 8
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 = ['\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)):
            logging.debug(
                self.NO_AF_LOG_PROTO.substitute(term=self.term.name,
                                                proto=', '.join(
                                                    self.term.protocol),
                                                af=self.text_af))
            return ''
        if self.verbose:
            if self.term_remark:
                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].rstrip())

        # 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[0] == self.platform:
                    ret_str.append(str(next_verbatim[1]))
                return '\n'.join(ret_str)

        # protocol
        if not self.term.protocol:
            if self.af == 6:
                protocol = ['ipv6']
            elif self.platform == 'ciscoxr':
                protocol = ['ipv4']
            else:
                protocol = ['ip']
        elif self.term.protocol == ['hopopt']:
            protocol = ['hbh']
        elif self.proto_int:
            protocol = [
                proto if proto in self.ALLOWED_PROTO_STRINGS else
                self.PROTO_MAP.get(proto) for proto in self.term.protocol
            ]
        else:
            protocol = self.term.protocol
        # Arista can not process acls with esp/ah, these must appear as integers.
        if self.platform == 'arista':
            if 'esp' in protocol:
                protocol = [x if x != 'esp' else '50' for x in protocol]
            if 'ah' in protocol:
                protocol = [x if x != 'ah' else '51' for x in 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)
            if not source_address:
                logging.debug(
                    self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                                   direction='source',
                                                   af=self.text_af))
                return ''
            if self.enable_dsmo:
                source_address = summarizer.Summarize(source_address)
        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.debug(
                    self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                                   direction='destination',
                                                   af=self.text_af))
                return ''
            if self.enable_dsmo:
                destination_address = summarizer.Summarize(destination_address)
        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 or 'tcp' in protocol)
                and ('tcp-established' in opts or 'established' in opts)):
            if 'established' not in self.options:
                self.options.append('established')
        # Using both 'fragments' and 'is-fragment', ref Github Issue #187
        if ('ip' in protocol) and (('fragments' in opts) or
                                   ('is-fragment' in opts)):
            if 'fragments' not in self.options:
                self.options.append('fragments')
        # ACL-based Forwarding
        if (self.platform == 'ciscoxr'
            ) and not self.term.action and self.term.next_ip and ('nexthop1'
                                                                  not in opts):
            if len(self.term.next_ip) > 1:
                raise CiscoNextIpError(
                    'The following term has more than one next IP '
                    'value: %s' % self.term.name)
            if (not isinstance(self.term.next_ip[0], nacaddr.IPv4)
                    and not isinstance(self.term.next_ip[0], nacaddr.IPv6)):
                raise CiscoNextIpError('Next IP value must be an IP address. '
                                       'Invalid term: %s' % self.term.name)
            if self.term.next_ip[0].num_addresses > 1:
                raise CiscoNextIpError(
                    'The following term has a subnet instead of a '
                    'host: %s' % self.term.name)
            nexthop = self.term.next_ip[0].network_address
            nexthop_protocol = 'ipv4' if nexthop.version == 4 else 'ipv6'
            self.options.append('nexthop1 %s %s' % (nexthop_protocol, nexthop))
            action = _ACTION_TABLE.get('accept')

        if self.term.action:
            action = _ACTION_TABLE.get(str(self.term.action[0]))

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

        if self.term.destination_port:
            destination_port = self._FixConsecutivePorts(
                self.term.destination_port)

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

        # dscp; unlike srx, cisco only supports single, non-except values
        if self.term.dscp_match:
            if len(self.term.dscp_match) > 1:
                raise ExtendedACLTermError(
                    'Extended ACLs cannot specify more than one dscp match value'
                )
            else:
                self.options.append('dscp %s' % ' '.join(self.term.dscp_match))

        # icmp-types
        icmp_types = ['']
        if self.term.icmp_type:
            icmp_types = self.NormalizeIcmpTypes(self.term.icmp_type,
                                                 self.term.protocol, self.af)
        icmp_codes = ['']
        if self.term.icmp_code:
            icmp_codes = self.term.icmp_code
        fixed_src_addresses = [self._GetIpString(x) for x in source_address]
        fixed_dst_addresses = [
            self._GetIpString(x) for x in destination_address
        ]
        fixed_opts = {}
        for p in protocol:
            fixed_opts[p] = self._FixOptions(p, self.options)
        for saddr in fixed_src_addresses:
            for daddr in fixed_dst_addresses:
                for sport in source_port:
                    for dport in destination_port:
                        for proto in protocol:
                            opts = fixed_opts[proto]
                            for icmp_type in icmp_types:
                                for icmp_code in icmp_codes:
                                    ret_str.extend(
                                        self._TermletToStr(
                                            action, proto, saddr,
                                            self._FormatPort(sport,
                                                             proto), daddr,
                                            self._FormatPort(dport, proto),
                                            icmp_type, icmp_code, opts))

        return '\n'.join(ret_str)
Esempio n. 9
0
 def testSummarizeEmptyList(self):
     nets = []
     result = summarizer.Summarize(nets)
     self.assertEqual(result, [])
Esempio n. 10
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 = ['\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)):
            logging.debug(
                self.NO_AF_LOG_PROTO.substitute(term=self.term.name,
                                                proto=self.term.protocol,
                                                af=self.text_af))
            return ''

        if self.term_remark:
            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].rstrip())

        # 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] == self.platform:
                    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']
            elif self.platform == 'ciscoxr':
                protocol = ['ipv4']
            else:
                protocol = ['ip']
        elif self.term.protocol == ['hopopt']:
            protocol = ['hbh']
        elif self.proto_int:
            protocol = [
                proto if proto in self.ALLOWED_PROTO_STRINGS else
                self.PROTO_MAP.get(proto) for proto in self.term.protocol
            ]
        else:
            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)
            if not source_address:
                logging.debug(
                    self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                                   direction='source',
                                                   af=self.text_af))
                return ''
            if self.enable_dsmo:
                source_address = summarizer.Summarize(source_address)
        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.debug(
                    self.NO_AF_LOG_ADDR.substitute(term=self.term.name,
                                                   direction='destination',
                                                   af=self.text_af))
                return ''
            if self.enable_dsmo:
                destination_address = summarizer.Summarize(destination_address)
        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 or 'tcp' in protocol)
                and ('tcp-established' in opts or 'established' in opts)):
            if 'established' not in self.options:
                self.options.append('established')

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

        if self.term.destination_port:
            destination_port = self._FixConsecutivePorts(
                self.term.destination_port)

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

        # dscp; unlike srx, cisco only supports single, non-except values
        if self.term.dscp_match:
            if len(self.term.dscp_match) > 1:
                raise ExtendedACLTermError(
                    'Extended ACLs cannot specify more than one dscp match value'
                )
            else:
                self.options.append('dscp %s' % ' '.join(self.term.dscp_match))

        # icmp-types
        icmp_types = ['']
        if self.term.icmp_type:
            icmp_types = self.NormalizeIcmpTypes(self.term.icmp_type,
                                                 self.term.protocol, self.af)
        icmp_codes = ['']
        if self.term.icmp_code:
            icmp_codes = self.term.icmp_code
        fixed_src_addresses = [self._GetIpString(x) for x in source_address]
        fixed_dst_addresses = [
            self._GetIpString(x) for x in destination_address
        ]
        fixed_opts = {}
        for p in protocol:
            fixed_opts[p] = self._FixOptions(p, self.options)
        for saddr in fixed_src_addresses:
            for daddr in fixed_dst_addresses:
                for sport in source_port:
                    for dport in destination_port:
                        for proto in protocol:
                            opts = fixed_opts[proto]
                            for icmp_type in icmp_types:
                                for icmp_code in icmp_codes:
                                    ret_str.extend(
                                        self._TermletToStr(
                                            _ACTION_TABLE.get(
                                                str(self.term.action[0])),
                                            proto, saddr,
                                            self._FormatPort(sport,
                                                             proto), daddr,
                                            self._FormatPort(dport, proto),
                                            icmp_type, icmp_code, opts))

        return '\n'.join(ret_str)