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)])
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)
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)])
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) ])
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) ])
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), ])
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)
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)
def testSummarizeEmptyList(self): nets = [] result = summarizer.Summarize(nets) self.assertEqual(result, [])
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)