def _TranslatePolicy(self, pol, exp_info): """Transform a policy object into a JuniperSRX object. Args: pol: policy.Policy object exp_info: print a info message when a term is set to expire in that many weeks Raises: UnsupportedFilterError: An unsupported filter was specified UnsupportedHeader: A header option exists that is not understood/usable SRXDuplicateTermError: Two terms were found with same name in same filter ConflictingTargetOptions: Two target options are conflicting in the header MixedAddrBookTypes: Global and Zone address books in the same policy ConflictingApplicationSets: When two duplicate named terms have conflicting applicaiton entries """ self.srx_policies = [] self.addressbook = collections.OrderedDict() self.applications = [] self.ports = [] self.from_zone = '' self.to_zone = '' self.addr_book_type_global = True current_date = datetime.datetime.utcnow().date() exp_info_date = current_date + datetime.timedelta(weeks=exp_info) # list is used for check if policy only utilizes one type of address book. # (global or zone) addr_book_types = [] self._FixLargePolices() for header, terms in pol.filters: if self._PLATFORM not in header.platforms: continue filter_options = header.FilterOptions(self._PLATFORM) if (len(filter_options) < 4 or filter_options[0] != 'from-zone' or filter_options[2] != 'to-zone'): raise UnsupportedFilterError( 'SRX filter arguments must specify ' 'from-zone and to-zone.') # check if to-zone is not a supported target option if filter_options[1] in self._SUPPORTED_TARGET_OPTIONS: raise UnsupportedFilterError( 'to-zone %s cannot be the same as any ' 'valid SRX target-options' % (filter_options[1])) else: self.from_zone = filter_options[1] # check if from-zone is not a supported target option if filter_options[3] in self._SUPPORTED_TARGET_OPTIONS: raise UnsupportedFilterError( 'from-zone %s cannot be the same as any ' 'valid SRX target-options' % (filter_options[3])) else: self.to_zone = filter_options[3] # variables used to collect target-options and set defaults target_options = [] filter_type = '' address_book_type = '' # parse srx target options for filter_opt in filter_options[4:]: # validate address families if filter_opt in self._SUPPORTED_AF: if not filter_type: filter_type = filter_opt else: raise ConflictingTargetOptions( 'only one address family can be ' 'specified per header "%s"' % ' '.join(filter_options)) elif filter_opt in self._SUPPORTED_TARGET_OPTIONS: target_options.append(filter_opt) # check to see if option is an address-book-type and only one # address-book-type is specified per header if filter_opt == 'address-book-zone': if not address_book_type: address_book_type = 'zone' else: raise ConflictingTargetOptions( 'only one address-book-type can ' 'be specified per header "%s"' % ' '.join(filter_options)) elif filter_opt == 'address-book-global': if not address_book_type: address_book_type = 'global' else: raise ConflictingTargetOptions( 'only one address-book-type can ' 'be specified per header "%s"' % ' '.join(filter_options)) else: raise UnsupportedHeader( 'SRX Generator currently does not ' 'support %s as a header option "%s"' % (filter_opt, ' '.join(filter_options))) else: raise UnsupportedHeader( 'SRX Generator currently does not support ' '%s as a header option "%s"' % (filter_opt, ' '.join(filter_options))) # if address-family and address-book-type have not been set then default if not filter_type: filter_type = 'mixed' if not address_book_type: address_book_type = 'global' addr_book_types.append(address_book_type) # check if policy is global if self.from_zone == 'all' and self.to_zone == 'all': if address_book_type == 'zone': raise UnsupportedFilterError( 'Zone address books cannot be used with ' 'a global policy.') elif self.from_zone == 'all' or self.to_zone == 'all': raise UnsupportedFilterError( 'The zone name all is reserved for global ' 'policies.') term_dup_check = set() new_terms = [] for term in terms: term.name = self.FixTermLength(term.name) if term.name in term_dup_check: raise SRXDuplicateTermError( 'You have a duplicate term: %s' % term.name) term_dup_check.add(term.name) if term.expiration: if term.expiration <= exp_info_date: logging.info( 'INFO: Term %s in policy %s>%s expires ' 'in less than two weeks.', term.name, self.from_zone, self.to_zone) if term.expiration <= current_date: logging.warn( 'WARNING: Term %s in policy %s>%s is expired.', term.name, self.from_zone, self.to_zone) continue for i in term.source_address_exclude: term.source_address = nacaddr.RemoveAddressFromList( term.source_address, i) for i in term.destination_address_exclude: term.destination_address = nacaddr.RemoveAddressFromList( term.destination_address, i) # SRX policies are controlled by addresses that are used within, so # policy can be at the same time inet and inet6. for addr in term.source_address: if addr.version in self._AF_MAP[filter_type]: self._BuildAddressBook(self.from_zone, addr) for addr in term.destination_address: if addr.version in self._AF_MAP[filter_type]: self._BuildAddressBook(self.to_zone, addr) new_term = Term(term, filter_options) new_terms.append(new_term) # Because SRX terms can contain inet and inet6 addresses. We have to # have ability to recover proper AF for ICMP type we need. # If protocol is empty or we cannot map to inet or inet6 we insert bogus # af_type name which will cause new_term.NormalizeIcmpTypes to fail. if not term.protocol: icmp_af_type = 'unknown_af_icmp' else: icmp_af_type = self._AF_ICMP_MAP.get( term.protocol[0], 'unknown_af_icmp') tmp_icmptype = new_term.NormalizeIcmpTypes( term.icmp_type, term.protocol, icmp_af_type) # NormalizeIcmpTypes returns [''] for empty, convert to [] for eval normalized_icmptype = tmp_icmptype if tmp_icmptype != [ '' ] else [] # rewrites the protocol icmpv6 to icmp6 if 'icmpv6' in term.protocol: protocol = list(term.protocol) protocol[protocol.index('icmpv6')] = 'icmp6' else: protocol = term.protocol new_application_set = { 'sport': self._BuildPort(term.source_port), 'dport': self._BuildPort(term.destination_port), 'name': term.name, 'protocol': protocol, 'icmp-type': normalized_icmptype, 'timeout': term.timeout } for application_set in self.applications: if (term.name == application_set['name'] and new_application_set != application_set): raise ConflictingApplicationSets( 'Application set %s has a conflicting entry' % term.name) self.applications.append(new_application_set) self.srx_policies.append((header, new_terms, filter_options)) # Check if policy only utilizes one type of address book. (global or zone) if all(p == 'global' for p in addr_book_types): self.addr_book_type_global = True elif all(p == 'zone' for p in addr_book_types): self.addr_book_type_global = False else: raise MixedAddrBookTypes( 'Global and Zone address-book-types cannot ' 'be used in the same policy')
def _TranslatePolicy(self, pol, exp_info): """Transform a policy object into a PaloAltoFW object. Args: pol: policy.Policy object exp_info: print a info message when a term is set to expire in that many weeks Raises: UnsupportedFilterError: An unsupported filter was specified UnsupportedHeader: A header option exists that is not understood/usable PaloAltoFWDuplicateTermError: Two terms were found with same name in same filter """ self.pafw_policies = [] self.addressbook = collections.OrderedDict() self.applications = [] self.pan_applications = [] self.ports = [] self.from_zone = "" self.to_zone = "" self.policy_name = "" current_date = datetime.date.today() exp_info_date = current_date + datetime.timedelta(weeks=exp_info) for header, terms in pol.filters: if self._PLATFORM not in header.platforms: continue filter_options = header.FilterOptions(self._PLATFORM) if (len(filter_options) < 4 or filter_options[0] != "from-zone" or filter_options[2] != "to-zone"): raise UnsupportedFilterError( "Palo Alto Firewall filter arguments must specify from-zone and " "to-zone." ) self.from_zone = filter_options[1] self.to_zone = filter_options[3] if len(filter_options) > 4: filter_type = filter_options[4] else: filter_type = "inet" if filter_type not in self._SUPPORTED_AF: raise UnsupportedHeader( "Palo Alto Firewall Generator currently does not support" " %s as a header option" % (filter_type)) term_dup_check = set() new_terms = [] for term in terms: term.name = self.FixTermLength(term.name) if term.name in term_dup_check: raise PaloAltoFWDuplicateTermError("You have a duplicate term: %s" % term.name) term_dup_check.add(term.name) if term.expiration: if term.expiration <= exp_info_date: logging.info("INFO: Term %s in policy %s>%s expires " "in less than two weeks.", term.name, self.from_zone, self.to_zone) if term.expiration <= current_date: logging.warn("WARNING: Term %s in policy %s>%s is expired and " "will not be rendered.", term.name, self.from_zone, self.to_zone) continue for i in term.source_address_exclude: term.source_address = nacaddr.RemoveAddressFromList( term.source_address, i) for i in term.destination_address_exclude: term.destination_address = nacaddr.RemoveAddressFromList( term.destination_address, i) for addr in term.source_address: self._BuildAddressBook(self.from_zone, addr) for addr in term.destination_address: self._BuildAddressBook(self.to_zone, addr) new_term = Term(term, filter_type, filter_options) new_terms.append(new_term) tmp_icmptype = new_term.NormalizeIcmpTypes(term.icmp_type, term.protocol, filter_type) # NormalizeIcmpTypes returns [''] for empty, convert to [] for # eval normalized_icmptype = tmp_icmptype if tmp_icmptype != [""] else [] # rewrites the protocol icmpv6 to icmp6 if "icmpv6" in term.protocol: protocol = list(term.protocol) protocol[protocol.index("icmpv6")] = "icmp6" else: protocol = term.protocol self.applications.append({ "sport": self._BuildPort(term.source_port), "dport": self._BuildPort(term.destination_port), "name": term.name, "protocol": protocol, "icmp-type": normalized_icmptype, "timeout": term.timeout }) self.pafw_policies.append((header, new_terms, filter_options)) # create Palo Alto Firewall Rule object for term in new_terms: unused_rule = Rule(self.from_zone, self.to_zone, term)
def _TranslatePolicy(self, pol, exp_info): # pylint: disable=attribute-defined-outside-init """Transform a policy object into a JuniperSRX object. Args: pol: policy.Policy object exp_info: print a info message when a term is set to expire in that many weeks Raises: UnsupportedFilterError: An unsupported filter was specified UnsupportedHeader: A header option exists that is not understood/usable SRXDuplicateTermError: Two terms were found with same name in same filter ConflictingTargetOptions: Two target options are conflicting in the header MixedAddrBookTypes: Global and Zone address books in the same policy ConflictingApplicationSets: When two duplicate named terms have conflicting application entries """ self.srx_policies = [] self.addressbook = collections.OrderedDict() self.applications = [] self.ports = [] self.from_zone = '' self.to_zone = '' self.addr_book_type = set() current_date = datetime.datetime.utcnow().date() exp_info_date = current_date + datetime.timedelta(weeks=exp_info) for header, terms in pol.filters: if self._PLATFORM not in header.platforms: continue filter_options = header.FilterOptions(self._PLATFORM) if (len(filter_options) < 4 or filter_options[0] != 'from-zone' or filter_options[2] != 'to-zone'): raise UnsupportedFilterError('SRX filter arguments must specify ' 'from-zone and to-zone.') # check if to-zone is not a supported target option if filter_options[1] in self._SUPPORTED_TARGET_OPTIONS: raise UnsupportedFilterError('to-zone %s cannot be the same as any ' 'valid SRX target-options' % (filter_options[1])) else: self.from_zone = filter_options[1] # check if from-zone is not a supported target option if filter_options[3] in self._SUPPORTED_TARGET_OPTIONS: raise UnsupportedFilterError('from-zone %s cannot be the same as any ' 'valid SRX target-options' % (filter_options[3])) else: self.to_zone = filter_options[3] # variables used to collect target-options and set defaults target_options = [] filter_type = '' # parse srx target options extra_options = filter_options[4:] if self._SUPPORTED_TARGET_OPTIONS.issubset(extra_options): raise ConflictingTargetOptions('only one address-book-type can ' 'be specified per header "%s"' % ' '.join(filter_options)) else: address_book_type = self._SUPPORTED_TARGET_OPTIONS.intersection( extra_options) if len(address_book_type) is 0: address_book_type = {self._GLOBAL_ADDR_BOOK} self.addr_book_type.update(address_book_type) if len(self.addr_book_type) > 1: raise MixedAddrBookTypes('Global and Zone address-book-types cannot ' 'be used in the same policy') if self.from_zone == 'all' and self.to_zone == 'all': if self._ZONE_ADDR_BOOK in self.addr_book_type: raise UnsupportedFilterError('Zone address books cannot be used ' 'with a global policy.') elif self.from_zone == 'all' or self.to_zone == 'all': raise UnsupportedFilterError('The zone name all is reserved for ' 'global policies.') for filter_opt in filter_options[4:]: # validate address families if filter_opt in self._SUPPORTED_AF: if not filter_type: filter_type = filter_opt else: raise ConflictingTargetOptions('only one address family can be ' 'specified per header "%s"' % ' '.join(filter_options)) elif filter_opt in self._SUPPORTED_TARGET_OPTIONS: target_options.append(filter_opt) else: raise UnsupportedHeader('SRX Generator currently does not support ' '%s as a header option "%s"' % (filter_opt, ' '.join(filter_options))) # if address-family and address-book-type have not been set then default if not filter_type: filter_type = 'mixed' term_dup_check = set() new_terms = [] self._FixLargePolices(terms, filter_type) for term in terms: term.name = self.FixTermLength(term.name) if term.name in term_dup_check: raise SRXDuplicateTermError('You have a duplicate term: %s' % term.name) term_dup_check.add(term.name) if term.expiration: if term.expiration <= exp_info_date: logging.info('INFO: Term %s in policy %s>%s expires ' 'in less than two weeks.', term.name, self.from_zone, self.to_zone) if term.expiration <= current_date: logging.warn('WARNING: Term %s in policy %s>%s is expired.', term.name, self.from_zone, self.to_zone) continue # SRX address books leverage network token names for IPs. # When excluding addresses, we lose those distinct names so we need # to create a new unique name based off the term name before excluding. if term.source_address_exclude: # If we have a naked source_exclude, we need something to exclude from if not term.source_address: term.source_address = [nacaddr.IP('0.0.0.0/0', term.name.upper(), term.name.upper())] # Use the term name as the token & parent_token new_src_parent_token = term.name.upper() + '_SRC_EXCLUDE' new_src_token = new_src_parent_token for i in term.source_address_exclude: term.source_address = nacaddr.RemoveAddressFromList( term.source_address, i) for i in term.source_address: i.token = new_src_token i.parent_token = new_src_parent_token if term.destination_address_exclude: if not term.destination_address: term.destination_address = [nacaddr.IP('0.0.0.0/0', term.name.upper(), term.name.upper())] new_dst_parent_token = term.name.upper() + '_DST_EXCLUDE' new_dst_token = new_dst_parent_token for i in term.destination_address_exclude: term.destination_address = nacaddr.RemoveAddressFromList( term.destination_address, i) for i in term.destination_address: i.token = new_dst_token i.parent_token = new_dst_parent_token # SRX policies are controlled by addresses that are used within, so # policy can be at the same time inet and inet6. if self._GLOBAL_ADDR_BOOK in self.addr_book_type: for zone in self.addressbook: for unused_name, ips in sorted(self.addressbook[zone].iteritems()): ips = [i for i in ips] if term.source_address == ips: term.source_address = ips if term.destination_address == ips: term.destination_address = ips for addr in term.source_address: if addr.version in self._AF_MAP[filter_type]: self._BuildAddressBook(self.from_zone, addr) for addr in term.destination_address: if addr.version in self._AF_MAP[filter_type]: self._BuildAddressBook(self.to_zone, addr) new_term = Term(term, filter_options) new_terms.append(new_term) # Because SRX terms can contain inet and inet6 addresses. We have to # have ability to recover proper AF for ICMP type we need. # If protocol is empty or we cannot map to inet or inet6 we insert bogus # af_type name which will cause new_term.NormalizeIcmpTypes to fail. if not term.protocol: icmp_af_type = 'unknown_af_icmp' else: icmp_af_type = self._AF_ICMP_MAP.get( term.protocol[0], 'unknown_af_icmp') tmp_icmptype = new_term.NormalizeIcmpTypes( term.icmp_type, term.protocol, icmp_af_type) # NormalizeIcmpTypes returns [''] for empty, convert to [] for eval normalized_icmptype = tmp_icmptype if tmp_icmptype != [''] else [] # rewrites the protocol icmpv6 to icmp6 if 'icmpv6' in term.protocol: protocol = list(term.protocol) protocol[protocol.index('icmpv6')] = 'icmp6' else: protocol = term.protocol new_application_set = {'sport': self._BuildPort(term.source_port), 'dport': self._BuildPort(term.destination_port), 'protocol': protocol, 'icmp-type': normalized_icmptype, 'timeout': term.timeout} for application_set in self.applications: if all(item in application_set.items() for item in new_application_set.items()): new_application_set = '' term.replacement_application_name = application_set['name'] break if (term.name == application_set['name'] and new_application_set != application_set): raise ConflictingApplicationSets( 'Application set %s has a conflicting entry' % term.name) if new_application_set: new_application_set['name'] = term.name self.applications.append(new_application_set) self.srx_policies.append((header, new_terms, filter_options))