def is_ip_or_alias(self, address): """ return True if address is an ip or an alias """ # Is it an alias? if (self.find_alias(address, 'host') is not None or self.find_alias(address, 'network') is not None or self.find_alias(address, 'urltable') is not None or self.find_alias(address, 'urltable_ports') is not None): return True # Is it an IP address? try: ip_address(u'{0}'.format(address)) return True except ValueError: pass # Is it an IP network? try: ip_network(u'{0}'.format(address)) return True except ValueError: pass # None of the above return False
def _check_overlaps(self, ipfield, netfield): """ check new address does not overlaps with one existing """ if not self.obj.get(ipfield) or self.obj.get(netfield) is None: return our_addr = ip_network(u'{0}/{1}'.format(self.obj[ipfield], self.obj[netfield]), strict=False) for iface in self.root_elt: if iface == self.target_elt: continue ipaddr_elt = iface.find(ipfield) subnet_elt = iface.find(netfield) if ipaddr_elt is None or subnet_elt is None or ipaddr_elt.text in [ 'dhcp', None ] or ipaddr_elt.text in ['dhcpv6', None]: continue other_addr = ip_network(u'{0}/{1}'.format(ipaddr_elt.text, subnet_elt.text), strict=False) if our_addr.overlaps(other_addr): descr_elt = iface.find('descr') if descr_elt is not None and descr_elt.text: ifname = descr_elt.text else: ifname = iface.tag msg = 'IP address {0}/{1} is being used by or overlaps with: {2} ({3}/{4})'.format( self.obj[ipfield], self.obj[netfield], ifname, ipaddr_elt.text, subnet_elt.text) self.module.fail_json(msg=msg)
def _check_overlaps(self, interface, interface_elt): """ check new address does not overlaps with one existing """ if not interface.get('ipaddr'): return our_addr = ip_network(u'{0}/{1}'.format(interface['ipaddr'], interface['subnet']), strict=False) for iface in self.interfaces: if iface == interface_elt: continue ipaddr_elt = iface.find('ipaddr') subnet_elt = iface.find('subnet') if ipaddr_elt is None or subnet_elt is None: continue other_addr = ip_network(u'{0}/{1}'.format(ipaddr_elt.text, subnet_elt.text), strict=False) if our_addr.overlaps(other_addr): descr_elt = iface.find('descr') if descr_elt is not None and descr_elt.text: ifname = descr_elt.text else: ifname = iface.tag msg = 'IPv4 address {0}/{1} is being used by or overlaps with: {2} ({3}/{4})'.format( interface['ipaddr'], interface['subnet'], ifname, ipaddr_elt.text, subnet_elt.text ) self.module.fail_json(msg=msg)
def is_ip_network(address, strict=True): """ test if address is a valid ip network """ try: ip_network(u'{0}'.format(address), strict=strict) return True except ValueError: pass return False
def normalize(self): """Normalizes a CIDR descriptor, e.g. 1.2.3.4/5 == 0.0.0.0/5.""" # ipaddress is picky and needs inputs to be unicode, i.e. not bytes==str in py2 normalized_cidr = ipaddress.ip_network(six.u(self.cidr), strict=False).compressed return self.__class__(cidr=normalized_cidr, description=self.description)
def is_ipv6_network(address, strict=True): """ test if address is a valid ipv6 network """ try: addr = ip_network(u'{0}'.format(address), strict=strict) return isinstance(addr, IPv6Network) except ValueError: pass return False
def _search_prefix(nb_endpoint, data): if data.get("prefix"): prefix = ipaddress.ip_network(data["prefix"]) elif data.get("parent"): prefix = ipaddress.ip_network(data["parent"]) network = to_text(prefix.network_address) mask = prefix.prefixlen if data.get("vrf"): if not isinstance(data["vrf"], int): raise ValueError("%s does not exist - Please create VRF" % (data["vrf"])) else: prefix = nb_endpoint.get(q=network, mask_length=mask, vrf_id=data["vrf"]) else: prefix = nb_endpoint.get(q=network, mask_length=mask, vrf="null") return prefix
def check_params(self): rules_by_host = {} for host in self.hosts: rules_by_host[host.name] = self.firewall_facts[host.name].keys() for rule_option in self.rule_options: rule_name = rule_option.get('name') if rule_name is None: self.module.fail_json( msg="Please specify rule.name for rule set" " as it is required parameter.") hosts_with_rule_name = [ h for h, r in rules_by_host.items() if rule_name in r ] hosts_without_rule_name = set([i.name for i in self.hosts ]) - set(hosts_with_rule_name) if hosts_without_rule_name: self.module.fail_json( msg="rule named '%s' wasn't found on hosts: %s" % (rule_name, hosts_without_rule_name)) if 'enabled' not in rule_option: self.module.fail_json( msg="Please specify rules.enabled for rule set" " %s as it is required parameter." % rule_name) allowed_hosts = rule_option.get('allowed_hosts', {}) ip_addresses = allowed_hosts.get('ip_address', []) ip_networks = allowed_hosts.get('ip_network', []) for ip_address in ip_addresses: try: ipaddress.ip_address(ip_address) except ValueError: self.module.fail_json( msg="The provided IP address %s is not a valid IP" " for the rule %s" % (ip_address, rule_name)) for ip_network in ip_networks: try: ipaddress.ip_network(ip_network) except ValueError: self.module.fail_json( msg="The provided IP network %s is not a valid network" " for the rule %s" % (ip_network, rule_name))
def _check_subnet(self): """ check if addr lies into interface subnets """ def _check_vips(): virtualips = self.pfsense.get_element('virtualip') if virtualips is None: return False for vip_elt in virtualips: if vip_elt.find( 'interface' ).text != self.interface_elt.tag or vip_elt.find( 'mode').text != 'other' or vip_elt.find( 'type').text != 'network': continue subnet = ip_network(u'{0}/{1}'.format( vip_elt.find('subnet').text, vip_elt.find('subnet_bits').text), strict=False) if addr in subnet: return True return False if self.params['ipprotocol'] == 'inet': inet_type = 'IPv4' f1_elt = self.interface_elt.find('ipaddr') f2_elt = self.interface_elt.find('subnet') else: inet_type = 'IPv6' f1_elt = self.interface_elt.find('ipaddrv6') f2_elt = self.interface_elt.find('subnetv6') if f1_elt is None or f1_elt.text is None or f2_elt is None or f2_elt.text is None: self.module.fail_json( msg= 'Cannot add {0} Gateway Address because no {0} address could be found on the interface.' .format(inet_type)) try: if self.params['nonlocalgateway']: return addr = ip_address(u'{0}'.format(self.params['gateway'])) subnet = ip_network(u'{0}/{1}'.format(f1_elt.text, f2_elt.text), strict=False) if addr in subnet or _check_vips(): return self.module.fail_json( msg= "The gateway address {0} does not lie within one of the chosen interface's subnets." .format(self.params['gateway'])) except ValueError: self.module.fail_json( msg= 'Cannot add {0} Gateway Address because no {0} address could be found on the interface.' .format(inet_type))
def _check_vips(): virtualips = self.pfsense.get_element('virtualip') if virtualips is None: return False for vip_elt in virtualips: if vip_elt.find('interface').text != self.interface_elt.tag or vip_elt.find('mode').text != 'other' or vip_elt.find('type').text != 'network': continue subnet = ip_network(u'{0}/{1}'.format(vip_elt.find('subnet').text, vip_elt.find('subnet_bits').text), strict=False) if addr in subnet: return True return False
def map_config_to_obj(module): obj = [] out = get_config(module, flags='| include ip route') for line in out.splitlines(): # Split by whitespace but do not split quotes, needed for description splitted_line = findall(r'[^"\s]\S*|".+?"', line) route = {} prefix_with_mask = splitted_line[2] prefix = None mask = None iface = None nhop = None if validate_ip_address(prefix_with_mask) is True: my_net = ipaddress.ip_network(prefix_with_mask) prefix = str(my_net.network_address) mask = str(my_net.netmask) route.update({ 'prefix': prefix, 'mask': mask, 'admin_distance': '1' }) if splitted_line[3] is not None: if validate_ip_address(splitted_line[3]) is False: iface = str(splitted_line[3]) route.update(interface=iface) if validate_ip_address(splitted_line[4]) is True: nhop = str(splitted_line[4]) route.update(next_hop=nhop) if splitted_line[5].isdigit(): route.update(admin_distance=str(splitted_line[5])) elif splitted_line[4].isdigit(): route.update(admin_distance=str(splitted_line[4])) else: if splitted_line[6] is not None and splitted_line[ 6].isdigit(): route.update(admin_distance=str(splitted_line[6])) else: nhop = str(splitted_line[3]) route.update(next_hop=nhop) if splitted_line[4].isdigit(): route.update(admin_distance=str(splitted_line[4])) index = 0 for word in splitted_line: if word in ('tag', 'description'): route.update(word=splitted_line[index + 1]) index = index + 1 obj.append(route) return obj
def parse_ip_network(address, strict=True, returns_ip=True): """ return cidr parts of address """ try: addr = ip_network(u'{0}'.format(address), strict=strict) if strict or not returns_ip: return (str(addr.network_address), addr.prefixlen) else: # we parse the address with ipaddr just for type checking # but we use a regex to return the result as it dont kept the address bits group = re.match(r'(.*)/(.*)', address) if group: return (group.group(1), group.group(2)) except ValueError: pass return None
def is_within_local_networks(self, address): """ test if address is contained in our local networks """ networks = self.get_interfaces_networks() try: addr = ip_address(u'{0}'.format(address)) except ValueError: return False for network in networks: try: net = ip_network(u'{0}'.format(network), strict=False) if addr in net: return True except ValueError: pass return False
def _get_prefix_id(nb_app, prefix, vrf_id=None): ipaddr_prefix = ipaddress.ip_network(prefix) network = to_text(ipaddr_prefix.network_address) mask = ipaddr_prefix.prefixlen prefix_query_params = {"prefix": network, "mask_length": mask} if vrf_id: prefix_query_params["vrf_id"] = vrf_id prefix_id = nb_app.prefixes.get(prefix_query_params) if not prefix_id: if vrf_id: raise ValueError( "Prefix %s does not exist in VRF %s - Please create it" % (prefix, vrf_id)) else: raise ValueError("Prefix %s does not exist - Please create it" % (prefix)) return prefix_id
def main(): argument_spec = scaleway_argument_spec() argument_spec.update( dict( state=dict(default='present', choices=['absent', 'present']), region=dict(required=True, choices=SCALEWAY_LOCATION.keys()), protocol=dict(required=True, choices=['TCP', 'UDP', 'ICMP']), port=dict(required=True, type=int), ip_range=dict(default='0.0.0.0/0', type=lambda x: to_text(ip_network(to_text(x)))), direction=dict(required=True, choices=['inbound', 'outbound']), action=dict(required=True, choices=['accept', 'drop']), security_group=dict(required=True), )) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) core(module)
def validate_ip_in_cidr(ip, cidr): address = ipaddress.ip_address(six.u(ip)) network = ipaddress.ip_network(six.u(cidr), strict=False) if address not in network: raise errors.ValidationError("IP {0} not in subnet CIDR {1}.".format( ip, cidr))
def ensure(self): """ Function to ensure rule set configuration """ fw_change_list = [] enable_disable_changed = False allowed_ip_changed = False results = dict(changed=False, rule_set_state=dict()) for host in self.hosts: firewall_system = host.configManager.firewallSystem if firewall_system is None: continue results['rule_set_state'][host.name] = dict() for rule_option in self.rule_options: rule_name = rule_option.get('name', None) if rule_name is None: self.module.fail_json( msg="Please specify rule.name for rule set" " as it is required parameter.") if rule_name not in self.firewall_facts[host.name]: self.module.fail_json(msg="rule named '%s' wasn't found." % rule_name) rule_enabled = rule_option.get('enabled', None) if rule_enabled is None: self.module.fail_json( msg="Please specify rules.enabled for rule set" " %s as it is required parameter." % rule_name) # validate IP addresses are valid rule_config = rule_option.get('allowed_hosts', None) if 'ip_address' in rule_config[0].keys(): for ip_addr in rule_config[0]['ip_address']: try: ip = ipaddress.ip_address(ip_addr) except ValueError: self.module.fail_json( msg= "The provided IP address %s is not a valid IP" " for the rule %s" % (ip_addr, rule_name)) # validate provided subnets are valid networks if 'ip_network' in rule_config[0].keys(): for ip_net in rule_config[0]['ip_network']: try: network_validation = ipaddress.ip_network(ip_net) except ValueError: self.module.fail_json( msg= "The provided network %s is not a valid network" " for the rule %s" % (ip_net, rule_name)) current_rule_state = self.firewall_facts[ host.name][rule_name]['enabled'] if current_rule_state != rule_enabled: try: if not self.module.check_mode: if rule_enabled: firewall_system.EnableRuleset(id=rule_name) else: firewall_system.DisableRuleset(id=rule_name) # keep track of changes as we go enable_disable_changed = True except vim.fault.NotFound as not_found: self.module.fail_json( msg="Failed to enable rule set %s as" " rule set id is unknown : %s" % (rule_name, to_native(not_found.msg))) except vim.fault.HostConfigFault as host_config_fault: self.module.fail_json( msg="Failed to enabled rule set %s as an internal" " error happened while reconfiguring" " rule set : %s" % (rule_name, to_native(host_config_fault.msg))) # save variables here for comparison later and change tracking # also covers cases where inputs may be null permitted_networking = self.firewall_facts[ host.name][rule_name] rule_allows_all = permitted_networking['allowed_hosts'][ 'all_ip'] playbook_allows_all = rule_config[0]['all_ip'] rule_allowed_ip = set( permitted_networking['allowed_hosts']['ip_address']) playbook_allowed_ip = set(rule_config[0].get('ip_address', '')) rule_allowed_networks = set( permitted_networking['allowed_hosts']['ip_network']) playbook_allowed_networks = set(rule_config[0].get( 'ip_network', '')) # compare what is configured on the firewall rule with what the playbook provides allowed_all_ips_different = bool( rule_allows_all != playbook_allows_all) ip_list_different = bool( rule_allowed_ip != playbook_allowed_ip) ip_network_different = bool( rule_allowed_networks != playbook_allowed_networks) # apply everything here in one function call if allowed_all_ips_different is True or ip_list_different is True or ip_network_different is True: try: allowed_ip_changed = True if not self.module.check_mode: # setup spec firewall_spec = vim.host.Ruleset.RulesetSpec() firewall_spec.allowedHosts = vim.host.Ruleset.IpList( ) firewall_spec.allowedHosts.allIp = rule_config[ 0].get('all_ip', True) firewall_spec.allowedHosts.ipAddress = rule_config[ 0].get('ip_address', None) firewall_spec.allowedHosts.ipNetwork = [] if 'ip_network' in rule_config[0].keys(): for allowed_network in rule_config[0].get( 'ip_network', None): tmp_ip_network_spec = vim.host.Ruleset.IpNetwork( ) tmp_ip_network_spec.network = allowed_network.split( "/")[0] tmp_ip_network_spec.prefixLength = int( allowed_network.split("/")[1]) firewall_spec.allowedHosts.ipNetwork.append( tmp_ip_network_spec) firewall_system.UpdateRuleset(id=rule_name, spec=firewall_spec) except vim.fault.NotFound as not_found: self.module.fail_json( msg="Failed to configure rule set %s as" " rule set id is unknown : %s" % (rule_name, to_native(not_found.msg))) except vim.fault.HostConfigFault as host_config_fault: self.module.fail_json( msg="Failed to configure rule set %s as an internal" " error happened while reconfiguring" " rule set : %s" % (rule_name, to_native(host_config_fault.msg))) except vim.fault.RuntimeFault as runtime_fault: self.module.fail_json( msg= "Failed to configure the rule set %s as a runtime" " error happened while applying the reconfiguration:" " %s" % (rule_name, to_native(runtime_fault.msg))) results['rule_set_state'][host.name][rule_name] = dict( current_state=rule_enabled, previous_state=current_rule_state, desired_state=rule_enabled, current_allowed_all=playbook_allows_all, previous_allowed_all=permitted_networking['allowed_hosts'] ['all_ip'], desired_allowed_all=playbook_allows_all, current_allowed_ip=playbook_allowed_ip, previous_allowed_ip=set( permitted_networking['allowed_hosts']['ip_address']), desired_allowed_ip=playbook_allowed_ip, current_allowed_networks=playbook_allowed_networks, previous_allowed_networks=set( permitted_networking['allowed_hosts']['ip_network']), desired_allowed_networks=playbook_allowed_networks) if enable_disable_changed or allowed_ip_changed: fw_change_list.append(True) if any(fw_change_list): results['changed'] = True self.module.exit_json(**results)
def run(self): """ This function should have all necessary code for endpoints within the application to create/update/delete the endpoint objects Supported endpoints: - aggregates - ipam_roles - ip_addresses - prefixes - rirs - vlans - vlan_groups - vrfs """ # Used to dynamically set key when returning results endpoint_name = ENDPOINT_NAME_MAPPING[self.endpoint] self.result = {"changed": False} application = self._find_app(self.endpoint) nb_app = getattr(self.nb, application) nb_endpoint = getattr(nb_app, self.endpoint) data = self.data if self.endpoint == "ip_addresses": if data.get("address"): try: data["address"] = to_text( ipaddress.ip_network(data["address"])) except ValueError: pass name = data.get("address") elif self.endpoint in ["aggregates", "prefixes"]: name = data.get("prefix") else: name = data.get("name") if self.endpoint in SLUG_REQUIRED: if not data.get("slug"): data["slug"] = self._to_slug(name) if self.module.params.get("first_available"): first_available = True else: first_available = False object_query_params = self._build_query_params(endpoint_name, data) if data.get("prefix") and self.endpoint == "ip_addresses": object_query_params = self._build_query_params("prefix", data) self.nb_object = self._nb_endpoint_get(nb_app.prefixes, object_query_params, name) else: self.nb_object = self._nb_endpoint_get(nb_endpoint, object_query_params, name) if self.state in ("new", "present") and endpoint_name == "ip_address": self._handle_state_new_present(nb_app, nb_endpoint, endpoint_name, name, data) elif self.state == "present" and first_available and data.get( "parent"): self._get_new_available_prefix(data, endpoint_name) elif self.state == "present": self._ensure_object_exists(nb_endpoint, endpoint_name, name, data) elif self.state == "absent": self._ensure_object_absent(endpoint_name, name) try: serialized_object = self.nb_object.serialize() except AttributeError: serialized_object = self.nb_object self.result.update({endpoint_name: serialized_object}) self.module.exit_json(**self.result)