def _CalculateAddrList(self, addr_list, addr_exclude_list, target_af, direction): """Calculates and stores address list for target AF and direction. Args: addr_list: address list. addr_exclude_list: address exclude list of the term. target_af: target address family. direction: direction in which address list will be used. Returns: calculated address list. """ if not addr_list: addr_list = [self._all_ips] addr_list = [addr for addr in addr_list if addr.version == target_af] if addr_exclude_list: addr_exclude_list = [ addr_exclude for addr_exclude in addr_exclude_list if addr_exclude.version == target_af ] addr_list = nacaddr.ExcludeAddrs(addr_list, addr_exclude_list) if len(addr_list) > 1: set_name = self._GenerateSetName(self.term.name, direction) self.addr_sets[direction] = (set_name, addr_list) addr_list = [self._all_ips] return addr_list
def _CalculateAddrs(self, addr_list, addr_exclude_list): addr_list = [addr for addr in addr_list if addr.version == self.AF_MAP[self.af]] if addr_exclude_list: if not addr_list: addr_list = [self.all_ips] addr_list = nacaddr.ExcludeAddrs(addr_list, addr_exclude_list) return addr_list
def __str__(self): # Verify platform specific terms. Skip whole term if platform does not # match. if self.term.platform: if 'ciscoasa' not in self.term.platform: return '' if self.term.platform_exclude: if 'ciscoasa' in self.term.platform_exclude: return '' ret_str = ['\n'] # Don't render icmpv6 protocol terms under inet, or icmp under inet6 if ((self.af == 6 and 'icmp' in self.term.protocol) or (self.af == 4 and 'icmpv6' in self.term.protocol)): ret_str.append('remark Term %s' % self.term.name) ret_str.append('remark not rendered due to protocol/AF mismatch.') return '\n'.join(ret_str) ret_str.append('access-list %s remark %s' % (self.filter_name, self.term.name)) if self.term.owner: self.term.comment.append('Owner: %s' % self.term.owner) for comment in self.term.comment: for line in comment.split('\n'): ret_str.append('access-list %s remark %s' % (self.filter_name, str(line)[:100])) # Term verbatim output - this will skip over normal term creation # code by returning early. Warnings provided in policy.py. if self.term.verbatim: for next in self.term.verbatim: if next.value[0] == 'ciscoasa': ret_str.append(str(next.value[1])) return '\n'.join(ret_str) # protocol if not self.term.protocol: protocol = ['ip'] else: # fix the protocol protocol = self.term.protocol # source address if self.term.source_address: source_address = self.term.GetAddressOfVersion('source_address', self.af) source_address_exclude = self.term.GetAddressOfVersion( 'source_address_exclude', self.af) if source_address_exclude: source_address = nacaddr.ExcludeAddrs( source_address, source_address_exclude) else: # source address not set source_address = ['any'] # destination address if self.term.destination_address: destination_address = self.term.GetAddressOfVersion( 'destination_address', self.af) destination_address_exclude = self.term.GetAddressOfVersion( 'destination_address_exclude', self.af) if destination_address_exclude: destination_address = nacaddr.ExcludeAddrs( destination_address, destination_address_exclude) else: # destination address not set destination_address = ['any'] # options extra_options = [] for opt in [str(x) for x in self.term.option]: if opt.find('tcp-established') == 0 and 6 in protocol: extra_options.append('established') elif opt.find('established') == 0 and 6 in protocol: # only needed for TCP, for other protocols policy.py handles high-ports extra_options.append('established') self.options.extend(extra_options) # ports source_port = [()] destination_port = [()] if self.term.source_port: source_port = self.term.source_port if self.term.destination_port: destination_port = self.term.destination_port # logging if self.term.logging: self.options.append('log') if 'disable' in [x.value for x in self.term.logging]: self.options.append('disable') # icmp-types icmp_types = [''] if self.term.icmp_type: icmp_types = self.NormalizeIcmpTypes(self.term.icmp_type, self.term.protocol, self.af) for saddr in source_address: for daddr in destination_address: for sport in source_port: for dport in destination_port: for proto in protocol: for icmp_type in icmp_types: # only output address family appropriate IP addresses do_output = False if self.af == 4: if (((type(saddr) is nacaddr.IPv4) or (saddr == 'any')) and ((type(daddr) is nacaddr.IPv4) or (daddr == 'any'))): do_output = True if self.af == 6: if (((type(saddr) is nacaddr.IPv6) or (saddr == 'any')) and ((type(daddr) is nacaddr.IPv6) or (daddr == 'any'))): do_output = True if do_output: ret_str.extend(self._TermletToStr( self.filter_name, _ACTION_TABLE.get(str(self.term.action[0])), proto, saddr, sport, daddr, dport, icmp_type, self.options)) return '\n'.join(ret_str)
def __str__(self): """Convert term to a rule string. Returns: A rule as a string. Raises: NsxvAclTermError: When unknown icmp-types are specified """ # Verify platform specific terms. Skip whole term if platform does not # match. if self.term.platform: if 'nsxv' not in self.term.platform: return '' if self.term.platform_exclude: if 'nsxv' in self.term.platform_exclude: return '' ret_str = [''] # Don't render icmpv6 protocol terms under inet, or icmp under inet6 if ((self.af == 6 and 'icmp' in self.term.protocol) or (self.af == 4 and 'icmpv6' in self.term.protocol)): logging.debug( self.NO_AF_LOG_PROTO.substitute(term=self.term.name, proto=self.term.protocol, af=self.filter_type)) return '' # Term verbatim is not supported if self.term.verbatim: raise NsxvAclTermError( 'Verbatim are not implemented in standard ACLs') # Term option is not supported if self.term.option: raise NsxvAclTermError( 'Option are not implemented in standard ACLs') # check for keywords Nsxv does not support term_keywords = self.term.__dict__ unsupported_keywords = [] for key in term_keywords: if term_keywords[key]: # translated is obj attribute not keyword if ('translated' not in key) and (key not in _NSXV_SUPPORTED_KEYWORDS): unsupported_keywords.append(key) if unsupported_keywords: logging.warn( 'WARNING: The keywords %s in Term %s are not supported in ' 'Nsxv ', unsupported_keywords, self.term.name) name = '%s%s%s' % (_XML_TABLE.get('nameStart'), self.term.name, _XML_TABLE.get('nameEnd')) notes = '' if self.term.comment: for comment in self.term.comment: notes = '%s%s' % (notes, comment) notes = '%s%s%s' % (_XML_TABLE.get('noteStart'), notes, _XML_TABLE.get('noteEnd')) # protocol protocol = None if self.term.protocol: protocol = map(self.PROTO_MAP.get, self.term.protocol, self.term.protocol) # icmp-types icmp_types = [''] if self.term.icmp_type: icmp_types = self.NormalizeIcmpTypes(self.term.icmp_type, self.term.protocol, self.af) # for mixed filter type get both IPV4address and IPv6Address af_list = [] if self.filter_type == 'mixed': af_list = [4, 6] else: af_list = [self.af] source_address = None destination_address = None source_addr = [] destination_addr = [] for af in af_list: # source address if self.term.source_address: source_address = self.term.GetAddressOfVersion( 'source_address', af) source_address_exclude = self.term.GetAddressOfVersion( 'source_address_exclude', af) if source_address_exclude: source_address = nacaddr.ExcludeAddrs( source_address, source_address_exclude) if not source_address: logging.warn( self.NO_AF_LOG_ADDR.substitute(term=self.term.name, direction='source', af=self.filter_type)) return '' if not source_addr: source_addr.extend(source_address) else: source_addr = source_address # destination address if self.term.destination_address: destination_address = self.term.GetAddressOfVersion( 'destination_address', af) destination_address_exclude = self.term.GetAddressOfVersion( 'destination_address_exclude', af) if destination_address_exclude: destination_address = nacaddr.ExcludeAddrs( destination_address, destination_address_exclude) if not destination_address: logging.warn( self.NO_AF_LOG_ADDR.substitute(term=self.term.name, direction='destination', af=self.filter_type)) return '' destination_addr.extend(destination_address) # ports source_port = None destination_port = None if self.term.source_port: source_port = self.term.source_port if self.term.destination_port: destination_port = self.term.destination_port # logging log = 'false' if self.term.logging: log = 'true' sources = '' if source_addr: sources = '<sources excluded="false">' for saddr in source_addr: # inet4 if type(saddr) is nacaddr.IPv4: if saddr.numhosts > 1: saddr = '%s%s%s' % ( _XML_TABLE.get('srcIpv4Start'), saddr.with_prefixlen, _XML_TABLE.get('srcIpv4End'), ) else: saddr = '%s%s%s' % (_XML_TABLE.get('srcIpv4Start'), saddr.ip, _XML_TABLE.get('srcIpv4End')) sources = '%s%s' % (sources, saddr) # inet6 if type(saddr) is nacaddr.IPv6: if saddr.numhosts > 1: saddr = '%s%s%s' % ( _XML_TABLE.get('srcIpv6Start'), saddr.with_prefixlen, _XML_TABLE.get('srcIpv6End'), ) else: saddr = '%s%s%s' % (_XML_TABLE.get('srcIpv6Start'), saddr.ip, _XML_TABLE.get('srcIpv6End')) sources = '%s%s' % (sources, saddr) sources = '%s%s' % (sources, '</sources>') destinations = '' if destination_addr: destinations = '<destinations excluded="false">' for daddr in destination_addr: # inet4 if type(daddr) is nacaddr.IPv4: if daddr.numhosts > 1: daddr = '%s%s%s' % ( _XML_TABLE.get('destIpv4Start'), daddr.with_prefixlen, _XML_TABLE.get('destIpv4End'), ) else: daddr = '%s%s%s' % (_XML_TABLE.get('destIpv4Start'), daddr.ip, _XML_TABLE.get('destIpv4End')) destinations = '%s%s' % (destinations, daddr) # inet6 if type(daddr) is nacaddr.IPv6: if daddr.numhosts > 1: daddr = '%s%s%s' % ( _XML_TABLE.get('destIpv6Start'), daddr.with_prefixlen, _XML_TABLE.get('destIpv6End'), ) else: daddr = '%s%s%s' % (_XML_TABLE.get('destIpv6Start'), daddr.ip, _XML_TABLE.get('destIpv6End')) destinations = '%s%s' % (destinations, daddr) destinations = '%s%s' % (destinations, '</destinations>') services = [] if protocol: services.append('<services>') for proto in protocol: if proto != 'any': services.append( self._ServiceToString(proto, source_port, destination_port, icmp_types)) services.append('</services>') service = '' for s in services: service = '%s%s' % (service, s) # action action = '%s%s%s' % (_XML_TABLE.get('actionStart'), _ACTION_TABLE.get(str(self.term.action[0])), _XML_TABLE.get('actionEnd')) ret_lines = [] ret_lines.append( '<rule logged="%s"> %s %s %s %s %s %s </rule>' % (log, name, action, sources, destinations, service, notes)) # remove any trailing spaces and replace multiple spaces with singles stripped_ret_lines = [ re.sub(r'\s+', ' ', x).rstrip() for x in ret_lines ] ret_str.extend(stripped_ret_lines) return '\n'.join(ret_str)
def _CalculateAddresses(self, term_saddr, exclude_saddr, term_daddr, exclude_daddr): """Calculate source and destination address list for a term. Args: term_saddr: source address list of the term exclude_saddr: source address exclude list of the term term_daddr: destination address list of the term exclude_daddr: destination address exclude list of the term Returns: tuple containing source address list, source exclude address list, destination address list, destination exclude address list in that order """ # source address term_saddr_excluded = [] if not term_saddr: term_saddr = [self._all_ips] if exclude_saddr: term_saddr_excluded.extend(nacaddr.ExcludeAddrs(term_saddr, exclude_saddr)) # destination address term_daddr_excluded = [] if not term_daddr: term_daddr = [self._all_ips] if exclude_daddr: term_daddr_excluded.extend(nacaddr.ExcludeAddrs(term_daddr, exclude_daddr)) # Just to be safe, always have a result of at least 1 to avoid * by zero # returning incorrect results (10src*10dst=100, but 10src*0dst=0, not 10) bailout_count = len(exclude_saddr) + len(exclude_daddr) + ( (len(self.term.source_address) or 1) * (len(self.term.destination_address) or 1)) exclude_count = ((len(term_saddr_excluded) or 1) * (len(term_daddr_excluded) or 1)) # Use bailout jumps for excluded addresses if it results in fewer output # lines than nacaddr.ExcludeAddrs() method. if exclude_count < bailout_count: exclude_saddr = [] exclude_daddr = [] if term_saddr_excluded: term_saddr = term_saddr_excluded if term_daddr_excluded: term_daddr = term_daddr_excluded # With many sources and destinations, iptables needs to generate the # cartesian product of sources and destinations. If there are no # exclude rules, this can instead be written as exclude [0/0 - # srcs], exclude [0/0 - dsts]. v4_src_count = len([x for x in term_saddr if x.version == 4]) v4_dst_count = len([x for x in term_daddr if x.version == 4]) v6_src_count = len([x for x in term_saddr if x.version == 6]) v6_dst_count = len([x for x in term_daddr if x.version == 6]) num_pairs = v4_src_count * v4_dst_count + v6_src_count * v6_dst_count if num_pairs > 100: new_exclude_source = nacaddr.ExcludeAddrs([self._all_ips], term_saddr) new_exclude_dest = nacaddr.ExcludeAddrs([self._all_ips], term_daddr) # Invert the shortest list that does not already have exclude addresses if len(new_exclude_source) < len(new_exclude_dest) and not exclude_saddr: if len(new_exclude_source) + len(term_daddr) < num_pairs: exclude_saddr = new_exclude_source term_saddr = [self._all_ips] elif not exclude_daddr: if len(new_exclude_dest) + len(term_saddr) < num_pairs: exclude_daddr = new_exclude_dest term_daddr = [self._all_ips] term_saddr = [x for x in term_saddr if x.version == self.AF_MAP[self.af]] exclude_saddr = [x for x in exclude_saddr if x.version == self.AF_MAP[self.af]] term_daddr = [x for x in term_daddr if x.version == self.AF_MAP[self.af]] exclude_daddr = [x for x in exclude_daddr if x.version == self.AF_MAP[self.af]] return (term_saddr, exclude_saddr, term_daddr, exclude_daddr)
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) fixed_src_addresses = [self._GetIpString(x) for x in source_address] fixed_dst_addresses = [ self._GetIpString(x) for x in destination_address ] fixed_src_ports = [self._FormatPort(x) for x in source_port] fixed_dst_ports = [self._FormatPort(x) for x in destination_port] 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 fixed_src_ports: for dport in fixed_dst_ports: for proto in protocol: opts = fixed_opts[proto] for icmp_type in icmp_types: ret_str.extend( self._TermletToStr( _ACTION_TABLE.get( str(self.term.action[0])), proto, saddr, sport, daddr, dport, icmp_type, opts)) return '\n'.join(ret_str)