def _normalize_pools(existing, desired): pools = {'existing': {4: None, 6: None}, 'desired': {4: None, 6: None}} for pool in existing['Config']: subnet = ipaddress.ip_network(pool.get('Subnet')) pools['existing'][subnet.version] = pool for pool in desired['Config']: subnet = ipaddress.ip_network(pool.get('Subnet')) if pools['desired'][subnet.version] is not None: raise ValueError('Only one IPv{0} pool is permitted'.format( subnet.version)) else: pools['desired'][subnet.version] = pool if pools['desired'][6] and not pools['desired'][4]: raise ValueError( 'An IPv4 pool is required when an IPv6 pool is used. See the ' 'documentation for details.') # The pools will be sorted when comparing existing['Config'] = [ pools['existing'][x] for x in (4, 6) if pools['existing'][x] is not None ] desired['Config'] = [ pools['desired'][x] for x in (4, 6) if pools['desired'][x] is not None ]
def _normalize_pools(existing, desired): pools = {"existing": {4: None, 6: None}, "desired": {4: None, 6: None}} for pool in existing["Config"]: subnet = ipaddress.ip_network(pool.get("Subnet")) pools["existing"][subnet.version] = pool for pool in desired["Config"]: subnet = ipaddress.ip_network(pool.get("Subnet")) if pools["desired"][subnet.version] is not None: raise ValueError("Only one IPv{} pool is permitted".format(subnet.version)) else: pools["desired"][subnet.version] = pool if pools["desired"][6] and not pools["desired"][4]: raise ValueError( "An IPv4 pool is required when an IPv6 pool is used. See the " "documentation for details." ) # The pools will be sorted when comparing existing["Config"] = [ pools["existing"][x] for x in (4, 6) if pools["existing"][x] is not None ] desired["Config"] = [ pools["desired"][x] for x in (4, 6) if pools["desired"][x] is not None ]
def _parse_member(settype, member, strict=False): subtypes = settype.split(":")[1].split(",") all_parts = member.split(" ", 1) parts = all_parts[0].split(",") parsed_member = [] for i in range(len(subtypes)): subtype = subtypes[i] part = parts[i] if subtype in ["ip", "net"]: try: if "/" in part: part = ipaddress.ip_network(part, strict=strict) elif "-" in part: start, end = list( map(ipaddress.ip_address, part.split("-"))) part = list(ipaddress.summarize_address_range(start, end)) else: part = ipaddress.ip_address(part) except ValueError: pass elif subtype == "port": part = int(part) parsed_member.append(part) if len(all_parts) > 1: parsed_member.append(all_parts[1]) return parsed_member
def _parse_member(settype, member, strict=False): subtypes = settype.split(':')[1].split(',') all_parts = member.split(' ', 1) parts = all_parts[0].split(',') parsed_member = [] for i in range(len(subtypes)): subtype = subtypes[i] part = parts[i] if subtype in ['ip', 'net']: try: if '/' in part: part = ipaddress.ip_network(part, strict=strict) elif '-' in part: start, end = list(map(ipaddress.ip_address, part.split('-'))) part = list(ipaddress.summarize_address_range(start, end)) else: part = ipaddress.ip_address(part) except ValueError: pass elif subtype == 'port': part = int(part) parsed_member.append(part) if len(all_parts) > 1: parsed_member.append(all_parts[1]) return parsed_member
def targets(self): ''' Return ip addrs based on netmask, sitting in the "glob" spot because it is the default ''' addrs = () ret = {} ports = __opts__['ssh_scan_ports'] if not isinstance(ports, list): # Comma-separate list of integers ports = list(map(int, str(ports).split(','))) try: addrs = [ipaddress.ip_address(self.tgt)] except ValueError: try: addrs = ipaddress.ip_network(self.tgt).hosts() except ValueError: pass for addr in addrs: addr = str(addr) log.trace('Scanning host: {0}'.format(addr)) for port in ports: log.trace('Scanning port: {0}'.format(port)) try: sock = salt.utils.network.get_socket(addr, socket.SOCK_STREAM) sock.settimeout(float(__opts__['ssh_scan_timeout'])) sock.connect((addr, port)) sock.shutdown(socket.SHUT_RDWR) sock.close() ret[addr] = {'host': addr, 'port': port} except socket.error: pass return ret
def targets(self): ''' Return ip addrs based on netmask, sitting in the "glob" spot because it is the default ''' addrs = () ret = {} ports = __opts__['ssh_scan_ports'] if not isinstance(ports, list): # Comma-separate list of integers ports = list(map(int, str(ports).split(','))) try: addrs = [ipaddress.ip_address(self.tgt)] except ValueError: try: addrs = ipaddress.ip_network(self.tgt).hosts() except ValueError: pass for addr in addrs: addr = str(addr) ret[addr] = copy.deepcopy(__opts__.get('roster_defaults', {})) log.trace('Scanning host: {0}'.format(addr)) for port in ports: log.trace('Scanning port: {0}'.format(port)) try: sock = salt.utils.network.get_socket(addr, socket.SOCK_STREAM) sock.settimeout(float(__opts__['ssh_scan_timeout'])) sock.connect((addr, port)) sock.shutdown(socket.SHUT_RDWR) sock.close() ret[addr].update({'host': addr, 'port': port}) except socket.error: pass return ret
def targets(self): """ Return ip addrs based on netmask, sitting in the "glob" spot because it is the default """ addrs = () ret = {} ports = __opts__["ssh_scan_ports"] if not isinstance(ports, list): # Comma-separate list of integers ports = list(map(int, six.text_type(ports).split(","))) try: addrs = [ipaddress.ip_address(self.tgt)] except ValueError: try: addrs = ipaddress.ip_network(self.tgt).hosts() except ValueError: pass for addr in addrs: addr = six.text_type(addr) ret[addr] = copy.deepcopy(__opts__.get("roster_defaults", {})) log.trace("Scanning host: %s", addr) for port in ports: log.trace("Scanning port: %s", port) try: sock = salt.utils.network.get_socket( addr, socket.SOCK_STREAM) sock.settimeout(float(__opts__["ssh_scan_timeout"])) sock.connect((addr, port)) sock.shutdown(socket.SHUT_RDWR) sock.close() ret[addr].update({"host": addr, "port": port}) except socket.error: pass return ret
def match(tgt, opts=None): """ Matches based on IP address or CIDR notation """ if not opts: opts = __opts__ try: # Target is an address? tgt = ipaddress.ip_address(tgt) except: # pylint: disable=bare-except try: # Target is a network? tgt = ipaddress.ip_network(tgt) except: # pylint: disable=bare-except log.error("Invalid IP/CIDR target: %s", tgt) return [] proto = "ipv{}".format(tgt.version) grains = opts["grains"] if proto not in grains: match = False elif isinstance(tgt, (ipaddress.IPv4Address, ipaddress.IPv6Address)): match = str(tgt) in grains[proto] else: match = salt.utils.network.in_subnet(tgt, grains[proto]) return match
def _minion_lookup(minion_id, key, minion): grains, pillar, addrs, mine = minion if key == 'id': # Just paste in the minion ID return minion_id elif isinstance(key, dict): # Lookup the key in the dict for data_id, lookup in key.items(): ref = { 'pillar': pillar, 'grain': grains, 'mine': mine, }[data_id] for k in _data_lookup(ref, lookup): if k: return k return None elif re.match(r'^[0-9a-fA-F:./]+$', key): # It smells like a CIDR block try: net = ipaddress.ip_network(key, strict=True) except ValueError: log.error('{0} is an invalid CIDR network'.format(net)) return None for addr in addrs[net.version]: if addr in net: return str(addr) else: # Take the addresses from the grains and filter them filters = { 'global': lambda addr: addr.is_global if addr.version == 6 else not addr.is_private, 'public': lambda addr: not addr.is_private, 'private': lambda addr: addr.is_private and not addr.is_loopback and not addr. is_link_local, 'local': lambda addr: addr.is_loopback, } ip_vers = [4, 6] if key.startswith('ipv'): ip_vers = [int(key[3])] key = key[5:] for ip_ver in ip_vers: try: for addr in addrs[ip_ver]: if filters[key](addr): return str(addr) except KeyError: raise KeyError( 'Invalid filter {0} specified in roster_order'.format(key))
def _minion_lookup(minion_id, key, minion): grains, pillar, addrs, mine = minion if key == "id": # Just paste in the minion ID return minion_id elif isinstance(key, dict): # Lookup the key in the dict for data_id, lookup in key.items(): ref = {"pillar": pillar, "grain": grains, "mine": mine}[data_id] for k in _data_lookup(ref, lookup): if k: return k return None elif key.startswith("sdb://"): # It's a Salt SDB url return salt["sdb.get"](key) elif re.match(r"^[0-9a-fA-F:./]+$", key): # It smells like a CIDR block try: net = ipaddress.ip_network(key, strict=True) except ValueError: log.error("%s is an invalid CIDR network", net) return None for addr in addrs[net.version]: if addr in net: return str(addr) else: # Take the addresses from the grains and filter them filters = { "global": lambda addr: addr.is_global if addr.version == 6 else not addr.is_private, "public": lambda addr: not addr.is_private, "private": lambda addr: addr.is_private and not addr.is_loopback and not addr. is_link_local, "local": lambda addr: addr.is_loopback, } ip_vers = [4, 6] if key.startswith("ipv"): ip_vers = [int(key[3])] key = key[5:] for ip_ver in ip_vers: try: for addr in addrs[ip_ver]: if filters[key](addr): return str(addr) except KeyError: raise KeyError( "Invalid filter {} specified in roster_order".format(key))
def _check_ipcidr_minions(self, expr, greedy): ''' Return the minions found by looking via ipcidr ''' cache_enabled = self.opts.get('minion_data_cache', False) if greedy: minions = self._pki_minions() elif cache_enabled: minions = self.cache.list('minions') else: return {'minions': [], 'missing': []} if cache_enabled: if greedy: cminions = self.cache.list('minions') else: cminions = minions if cminions is None: return {'minions': minions, 'missing': []} tgt = expr try: # Target is an address? tgt = ipaddress.ip_address(tgt) except Exception: try: # Target is a network? tgt = ipaddress.ip_network(tgt) except Exception: log.error('Invalid IP/CIDR target: %s', tgt) return {'minions': [], 'missing': []} proto = 'ipv{0}'.format(tgt.version) minions = set(minions) for id_ in cminions: mdata = self.cache.fetch('minions/{0}'.format(id_), 'data') if mdata is None: if not greedy: minions.remove(id_) continue grains = mdata.get('grains') if grains is None or proto not in grains: match = False elif isinstance(tgt, (ipaddress.IPv4Address, ipaddress.IPv6Address)): match = six.text_type(tgt) in grains[proto] else: match = salt.utils.network.in_subnet(tgt, grains[proto]) if not match and id_ in minions: minions.remove(id_) return {'minions': list(minions), 'missing': []}
def calc_net(ipaddr, netmask=None): ''' Takes IP (CIDR notation supported) and optionally netmask and returns the network in CIDR-notation. (The IP can be any IP inside the subnet) ''' if netmask is not None: ipaddr = '{0}/{1}'.format(ipaddr, netmask) return str(ipaddress.ip_network(ipaddr, strict=False))
def _check_ipcidr_minions(self, expr, greedy): """ Return the minions found by looking via ipcidr """ cache_enabled = self.opts.get("minion_data_cache", False) if greedy: minions = self._pki_minions() elif cache_enabled: minions = self.cache.list("minions") else: return {"minions": [], "missing": []} if cache_enabled: if greedy: cminions = self.cache.list("minions") else: cminions = minions if cminions is None: return {"minions": minions, "missing": []} tgt = expr try: # Target is an address? tgt = ipaddress.ip_address(tgt) except Exception: # pylint: disable=broad-except try: # Target is a network? tgt = ipaddress.ip_network(tgt) except Exception: # pylint: disable=broad-except log.error("Invalid IP/CIDR target: %s", tgt) return {"minions": [], "missing": []} proto = "ipv{}".format(tgt.version) minions = set(minions) for id_ in cminions: mdata = self.cache.fetch("minions/{}".format(id_), "data") if mdata is None: if not greedy: minions.remove(id_) continue grains = mdata.get("grains") if grains is None or proto not in grains: match = False elif isinstance( tgt, (ipaddress.IPv4Address, ipaddress.IPv6Address)): match = str(tgt) in grains[proto] else: match = salt.utils.network.in_subnet(tgt, grains[proto]) if not match and id_ in minions: minions.remove(id_) return {"minions": list(minions), "missing": []}
def __init__(self, name, **kwargs): self.kwargs = kwargs self.name = name try: self.net = ipaddress.ip_network(self.kwargs['subnet']) self._rand_indexes = random.sample( range(2, self.net.num_addresses - 1), self.net.num_addresses - 3) self.ip_arg = 'ipv{0}_address'.format(self.net.version) except KeyError: # No explicit subnet passed self.net = self.ip_arg = None
def mac2eui64(mac, prefix=None): ''' Convert a MAC address to a EUI64 identifier or, with prefix provided, a full IPv6 address ''' # http://tools.ietf.org/html/rfc4291#section-2.5.1 eui64 = re.sub(r'[.:-]', '', mac).lower() eui64 = eui64[0:6] + 'fffe' + eui64[6:] eui64 = hex(int(eui64[0:2], 16) | 2)[2:].zfill(2) + eui64[2:] if prefix is None: return ':'.join(re.findall(r'.{4}', eui64)) else: try: net = ipaddress.ip_network(prefix, strict=False) euil = int('0x{0}'.format(eui64), 16) return '{0}/{1}'.format(net[euil], net.prefixlen) except: # pylint: disable=bare-except return
def in_subnet(cidr, addr=None): ''' Returns True if host or (any of) addrs is within specified subnet, otherwise False ''' try: cidr = ipaddress.ip_network(cidr) except ValueError: log.error('Invalid CIDR \'{0}\''.format(cidr)) return False if addr is None: addr = ip_addrs() elif isinstance(addr, six.string_types): return ipaddress.ip_address(addr) in cidr for ip_addr in addr: if ipaddress.ip_address(ip_addr) in cidr: return True return False
def get_net_start(ipaddr, netmask): ''' Return the address of the network ''' net = ipaddress.ip_network('{0}/{1}'.format(ipaddr, netmask), strict=False) return str(net.network_address)
def get_ssh_config(name, network_mask='', get_private_key=False): r''' Retrieve hints of how you might connect to a Vagrant VM. :param name: the salt_id of the machine :param network_mask: a CIDR mask to search for the VM's address :param get_private_key: (default: False) return the key used for ssh login :return: a dict of ssh login information for the VM CLI Example: .. code-block:: bash salt <host> vagrant.get_ssh_config <salt_id> salt my_laptop vagrant.get_ssh_config quail1 network_mask=10.0.0.0/8 get_private_key=True The returned dictionary contains: - key_filename: the name of the private key file on the VM host computer - ssh_username: the username to be used to log in to the VM - ssh_host: the IP address used to log in to the VM. (This will usually be `127.0.0.1`) - ssh_port: the TCP port used to log in to the VM. (This will often be `2222`) - \[ip_address:\] (if `network_mask` is defined. see below) - \[private_key:\] (if `get_private_key` is True) the private key for ssh_username About `network_mask`: Vagrant usually uses a redirected TCP port on its host computer to log in to a VM using ssh. This redirected port and its IP address are "ssh_port" and "ssh_host". The ssh_host is usually the localhost (127.0.0.1). This makes it impossible for a third machine (such as a salt-cloud master) to contact the VM unless the VM has another network interface defined. You will usually want a bridged network defined by having a `config.vm.network "public_network"` statement in your `Vagrantfile`. The IP address of the bridged adapter will typically be assigned by DHCP and unknown to you, but you should be able to determine what IP network the address will be chosen from. If you enter a CIDR network mask, Salt will attempt to find the VM's address for you. The host machine will send an "ifconfig" command to the VM (using ssh to `ssh_host`:`ssh_port`) and return the IP address of the first interface it can find which matches your mask. ''' vm_ = get_vm_info(name) ssh_config = _vagrant_ssh_config(vm_) try: ans = { 'key_filename': ssh_config['IdentityFile'], 'ssh_username': ssh_config['User'], 'ssh_host': ssh_config['HostName'], 'ssh_port': ssh_config['Port'], } except KeyError: raise CommandExecutionError( 'Insufficient SSH information to contact VM {}. ' 'Is it running?'.format(vm_.get('machine', '(default)'))) if network_mask: # ask the new VM to report its network address command = 'ssh -i {IdentityFile} -p {Port} ' \ '-oStrictHostKeyChecking={StrictHostKeyChecking} ' \ '-oUserKnownHostsFile={UserKnownHostsFile} ' \ '-oControlPath=none ' \ '{User}@{HostName} ifconfig'.format(**ssh_config) log.info('Trying ssh -p {Port} {User}@{HostName} ifconfig'.format( **ssh_config)) reply = __salt__['cmd.shell'](command) log.info('--->\n%s', reply) target_network_range = ipaddress.ip_network(network_mask, strict=False) for line in reply.split('\n'): try: # try to find a bridged network address # the lines we are looking for appear like: # "inet addr:10.124.31.185 Bcast:10.124.31.255 Mask:255.255.248.0" # or "inet6 addr: fe80::a00:27ff:fe04:7aac/64 Scope:Link" tokens = line.replace( 'addr:', '', 1).split() # remove "addr:" if it exists, then split found_address = None if "inet" in tokens: nxt = tokens.index("inet") + 1 found_address = ipaddress.ip_address(tokens[nxt]) elif "inet6" in tokens: nxt = tokens.index("inet6") + 1 found_address = ipaddress.ip_address( tokens[nxt].split('/')[0]) if found_address in target_network_range: ans['ip_address'] = six.text_type(found_address) break # we have located a good matching address except (IndexError, AttributeError, TypeError): pass # all syntax and type errors loop here # falling out if the loop leaves us remembering the last candidate log.info('Network IP address in %s detected as: %s', target_network_range, ans.get('ip_address', '(not found)')) if get_private_key: # retrieve the Vagrant private key from the host try: with salt.utils.files.fopen(ssh_config['IdentityFile']) as pks: ans['private_key'] = salt.utils.stringutils.to_unicode( pks.read()) except (OSError, IOError) as e: raise CommandExecutionError( "Error processing Vagrant private key file: {}".format(e)) return ans
def parse_resolv(src='/etc/resolv.conf'): ''' Parse a resolver configuration file (traditionally /etc/resolv.conf) ''' nameservers = [] ip4_nameservers = [] ip6_nameservers = [] search = [] sortlist = [] domain = '' options = [] try: with salt.utils.files.fopen(src) as src_file: # pylint: disable=too-many-nested-blocks for line in src_file: line = salt.utils.stringutils.to_unicode(line).strip().split() try: (directive, arg) = (line[0].lower(), line[1:]) # Drop everything after # or ; (comments) arg = list( itertools.takewhile(lambda x: x[0] not in ('#', ';'), arg)) if directive == 'nameserver': # Split the scope (interface) if it is present addr, scope = arg[0].split( '%', 1) if '%' in arg[0] else (arg[0], '') try: ip_addr = ipaddress.ip_address(addr) version = ip_addr.version # Rejoin scope after address validation if scope: ip_addr = '%'.join((str(ip_addr), scope)) if ip_addr not in nameservers: nameservers.append(ip_addr) if version == 4 and ip_addr not in ip4_nameservers: ip4_nameservers.append(ip_addr) elif version == 6 and ip_addr not in ip6_nameservers: ip6_nameservers.append(ip_addr) except ValueError as exc: log.error('%s: %s', src, exc) elif directive == 'domain': domain = arg[0] elif directive == 'search': search = arg elif directive == 'sortlist': # A sortlist is specified by IP address netmask pairs. # The netmask is optional and defaults to the natural # netmask of the net. The IP address and optional # network pairs are separated by slashes. for ip_raw in arg: try: ip_net = ipaddress.ip_network(ip_raw) except ValueError as exc: log.error('%s: %s', src, exc) else: if '/' not in ip_raw: # No netmask has been provided, guess # the "natural" one if ip_net.version == 4: ip_addr = six.text_type( ip_net.network_address) # pylint: disable=protected-access mask = salt.utils.network.natural_ipv4_netmask( ip_addr) ip_net = ipaddress.ip_network( '{0}{1}'.format(ip_addr, mask), strict=False) if ip_net.version == 6: # TODO pass if ip_net not in sortlist: sortlist.append(ip_net) elif directive == 'options': # Options allows certain internal resolver variables to # be modified. if arg[0] not in options: options.append(arg[0]) except IndexError: continue if domain and search: # The domain and search keywords are mutually exclusive. If more # than one instance of these keywords is present, the last instance # will override. log.debug( '%s: The domain and search keywords are mutually exclusive.', src) return { 'nameservers': nameservers, 'ip4_nameservers': ip4_nameservers, 'ip6_nameservers': ip6_nameservers, 'sortlist': [ip.with_netmask for ip in sortlist], 'domain': domain, 'search': search, 'options': options } except IOError: return {}
def _network_size(ip_addr_entry): return ipaddress.ip_network(ip_addr_entry, strict=False).num_addresses
def _network_hosts(ip_addr_entry): return [ str(host) for host in ipaddress.ip_network(ip_addr_entry, strict=False).hosts() ]
def _net(self): return ipaddress.ip_network(self.subnet)
def parse_resolv(src="/etc/resolv.conf"): """ Parse a resolver configuration file (traditionally /etc/resolv.conf) """ nameservers = [] ip4_nameservers = [] ip6_nameservers = [] search = [] sortlist = [] domain = "" options = [] try: with salt.utils.files.fopen(src) as src_file: # pylint: disable=too-many-nested-blocks for line in src_file: line = salt.utils.stringutils.to_unicode(line).strip().split() try: (directive, arg) = (line[0].lower(), line[1:]) # Drop everything after # or ; (comments) arg = list( itertools.takewhile(lambda x: x[0] not in ("#", ";"), arg)) if directive == "nameserver": addr = arg[0] try: ip_addr = ipaddress.ip_address(addr) version = ip_addr.version ip_addr = str(ip_addr) if ip_addr not in nameservers: nameservers.append(ip_addr) if version == 4 and ip_addr not in ip4_nameservers: ip4_nameservers.append(ip_addr) elif version == 6 and ip_addr not in ip6_nameservers: ip6_nameservers.append(ip_addr) except ValueError as exc: log.error("%s: %s", src, exc) elif directive == "domain": domain = arg[0] elif directive == "search": search = arg elif directive == "sortlist": # A sortlist is specified by IP address netmask pairs. # The netmask is optional and defaults to the natural # netmask of the net. The IP address and optional # network pairs are separated by slashes. for ip_raw in arg: try: ip_net = ipaddress.ip_network(ip_raw) except ValueError as exc: log.error("%s: %s", src, exc) else: if "/" not in ip_raw: # No netmask has been provided, guess # the "natural" one if ip_net.version == 4: ip_addr = str(ip_net.network_address) # pylint: disable=protected-access mask = salt.utils.network.natural_ipv4_netmask( ip_addr) ip_net = ipaddress.ip_network( "{}{}".format(ip_addr, mask), strict=False) if ip_net.version == 6: # TODO pass if ip_net not in sortlist: sortlist.append(ip_net) elif directive == "options": # Options allows certain internal resolver variables to # be modified. if arg[0] not in options: options.append(arg[0]) except IndexError: continue if domain and search: # The domain and search keywords are mutually exclusive. If more # than one instance of these keywords is present, the last instance # will override. log.debug( "%s: The domain and search keywords are mutually exclusive.", src) return { "nameservers": nameservers, "ip4_nameservers": ip4_nameservers, "ip6_nameservers": ip6_nameservers, "sortlist": [ip.with_netmask for ip in sortlist], "domain": domain, "search": search, "options": options, } except OSError: return {}
def parse_resolv(src='/etc/resolv.conf'): ''' Parse a resolver configuration file (traditionally /etc/resolv.conf) ''' nameservers = [] search = [] sortlist = [] domain = '' options = [] try: with salt.utils.fopen(src) as src_file: # pylint: disable=too-many-nested-blocks for line in src_file: line = line.strip().split() try: (directive, arg) = (line[0].lower(), line[1:]) # Drop everything after # or ; (comments) arg = list(itertools.takewhile( lambda x: x[0] not in ('#', ';'), arg)) if directive == 'nameserver': try: ip_addr = ipaddress.ip_address(arg[0]) if ip_addr not in nameservers: nameservers.append(ip_addr) except ValueError as exc: log.error('{0}: {1}'.format(src, exc)) elif directive == 'domain': domain = arg[0] elif directive == 'search': search = arg elif directive == 'sortlist': # A sortlist is specified by IP address netmask pairs. # The netmask is optional and defaults to the natural # netmask of the net. The IP address and optional # network pairs are separated by slashes. for ip_raw in arg: try: ip_net = ipaddress.ip_network(ip_raw) except ValueError as exc: log.error('{0}: {1}'.format(src, exc)) else: if '/' not in ip_raw: # No netmask has been provided, guess # the "natural" one if ip_net.version == 4: ip_addr = str(ip_net.network_address) # pylint: disable=protected-access mask = salt.utils.network.\ natural_ipv4_netmask(ip_addr) ip_net = ipaddress.ip_network( '{0}{1}'.format(ip_addr, mask), strict=False ) if ip_net.version == 6: # TODO pass if ip_net not in sortlist: sortlist.append(ip_net) elif directive == 'options': # Options allows certain internal resolver variables to # be modified. if arg[0] not in options: options.append(arg[0]) except IndexError: continue if domain and search: # The domain and search keywords are mutually exclusive. If more # than one instance of these keywords is present, the last instance # will override. log.debug('{0}: The domain and search keywords are mutually ' 'exclusive.'.format(src)) return { 'nameservers': nameservers, 'ip4_nameservers': [ip for ip in nameservers if ip.version == 4], 'ip6_nameservers': [ip for ip in nameservers if ip.version == 6], 'sortlist': [ip.with_netmask for ip in sortlist], 'domain': domain, 'search': search, 'options': options } except IOError: return {}
def network_address(value): try: return str(ipaddress.ip_network(value, False)) except Exception: log.exception("Failed to determine network address from '%s'", value) return ''