def inet_pton(address_family, ip_string): # Verify IP Address # This will catch IP Addresses such as 10.1.2 if address_family == socket.AF_INET: try: ipaddress.ip_address(six.text_type(ip_string)) except ValueError: raise socket.error('illegal IP address string passed to inet_pton') return socket.inet_aton(ip_string) # Verify IP Address # The `WSAStringToAddressA` function handles notations used by Berkeley # software which includes 3 part IP Addresses such as `10.1.2`. That's why # the above check is needed to enforce more strict IP Address validation as # used by the `inet_pton` function in Unix. # See the following: # https://stackoverflow.com/a/29286098 # Docs for the `inet_addr` function on MSDN # https://msdn.microsoft.com/en-us/library/windows/desktop/ms738563.aspx addr = sockaddr() addr.sa_family = address_family addr_size = ctypes.c_int(ctypes.sizeof(addr)) if WSAStringToAddressA(ip_string.encode('ascii'), address_family, None, ctypes.byref(addr), ctypes.byref(addr_size)) != 0: raise socket.error(ctypes.FormatError()) if address_family == socket.AF_INET: return ctypes.string_at(addr.ipv4_addr, 4) if address_family == socket.AF_INET6: return ctypes.string_at(addr.ipv6_addr, 16) raise socket.error('unknown address family')
def _build_required_items(nodes): ret = {} for name, grains in nodes.items(): if grains: private_ips = [] public_ips = [] ips = grains['ipv4'] + grains['ipv6'] for adrs in ips: ip_ = ipaddress.ip_address(adrs) if not ip_.is_loopback: if ip_.is_private: private_ips.append(adrs) else: public_ips.append(adrs) ret[name] = { 'id': grains['id'], 'image': grains['salt-cloud']['profile'], 'private_ips': private_ips, 'public_ips': public_ips, 'size': '', 'state': 'running' } return ret
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 _ip_addrs(interface=None, include_loopback=False, interface_data=None, proto='inet'): ''' Return the full list of IP adresses matching the criteria proto = inet|inet6 ''' ret = set() ifaces = interface_data \ if isinstance(interface_data, dict) \ else interfaces() if interface is None: target_ifaces = ifaces else: target_ifaces = dict([(k, v) for k, v in six.iteritems(ifaces) if k == interface]) if not target_ifaces: log.error('Interface {0} not found.'.format(interface)) for ip_info in six.itervalues(target_ifaces): addrs = ip_info.get(proto, []) addrs.extend([addr for addr in ip_info.get('secondary', []) if addr.get('type') == proto]) for addr in addrs: addr = ipaddress.ip_address(addr.get('address')) if not addr.is_loopback or include_loopback: ret.add(addr) return [str(addr) for addr in sorted(ret)]
def generate_minion_id(): ''' Returns a minion id after checking multiple sources for a FQDN. If no FQDN is found you may get an ip address CLI Example: .. code-block:: bash salt '*' network.generate_minion_id ''' possible_ids = get_hostnames() # include public and private ipaddresses for addr in salt.utils.network.ip_addrs(): addr = ipaddress.ip_address(addr) if addr.is_loopback: continue possible_ids.append(str(addr)) possible_ids = _filter_localhost_names(possible_ids) # if no minion id if len(possible_ids) == 0: return 'noname' hosts = _sort_hostnames(possible_ids) return hosts[0]
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) 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, 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, 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 ip_bracket(addr): ''' Convert IP address representation to ZMQ (URL) format. ZMQ expects brackets around IPv6 literals, since they are used in URLs. ''' addr = ipaddress.ip_address(addr) return ('[{}]' if addr.version == 6 else '{}').format(addr)
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 _build_required_items(nodes): ret = {} for name, grains in nodes.items(): if grains: private_ips = [] public_ips = [] ips = grains["ipv4"] + grains["ipv6"] for adrs in ips: ip_ = ipaddress.ip_address(adrs) if not ip_.is_loopback: if ip_.is_private: private_ips.append(adrs) else: public_ips.append(adrs) ret[name] = { "id": grains["id"], "image": grains["salt-cloud"]["profile"], "private_ips": private_ips, "public_ips": public_ips, "size": "", "state": "running", } return ret
def get_address_as_decimal(addr): ''' Return the decimal representation of an IP address This function is primarily used to generate a unique mark to identify traffic for a particular IPSec tunnel using the remote address. ''' return int(ipaddress.ip_address(addr))
def is_ipv6(ip): ''' Returns a bool telling if the value passed to it was a valid IPv6 address ''' try: return ipaddress.ip_address(ip).version == 6 except ValueError: return False
def _get_master_uri(master_ip, master_port, source_ip=None, source_port=None): """ Return the ZeroMQ URI to connect the Minion to the Master. It supports different source IP / port, given the ZeroMQ syntax: // Connecting using a IP address and bind to an IP address rc = zmq_connect(socket, "tcp://192.168.1.17:5555;192.168.1.1:5555"); assert (rc == 0); Source: http://api.zeromq.org/4-1:zmq-tcp """ from salt.utils.zeromq import ip_bracket master_uri = "tcp://{master_ip}:{master_port}".format( master_ip=ip_bracket(master_ip), master_port=master_port ) if source_ip or source_port: if LIBZMQ_VERSION_INFO >= (4, 1, 6) and ZMQ_VERSION_INFO >= (16, 0, 1): # The source:port syntax for ZeroMQ has been added in libzmq 4.1.6 # which is included in the pyzmq wheels starting with 16.0.1. if source_ip and source_port: master_uri = ( "tcp://{source_ip}:{source_port};{master_ip}:{master_port}".format( source_ip=ip_bracket(source_ip), source_port=source_port, master_ip=ip_bracket(master_ip), master_port=master_port, ) ) elif source_ip and not source_port: master_uri = "tcp://{source_ip}:0;{master_ip}:{master_port}".format( source_ip=ip_bracket(source_ip), master_ip=ip_bracket(master_ip), master_port=master_port, ) elif source_port and not source_ip: ip_any = ( "0.0.0.0" if ipaddress.ip_address(master_ip).version == 4 else ip_bracket("::") ) master_uri = ( "tcp://{ip_any}:{source_port};{master_ip}:{master_port}".format( ip_any=ip_any, source_port=source_port, master_ip=ip_bracket(master_ip), master_port=master_port, ) ) else: log.warning( "Unable to connect to the Master using a specific source IP / port" ) log.warning("Consider upgrading to pyzmq >= 16.0.1 and libzmq >= 4.1.6") log.warning( "Specific source IP / port for connecting to master returner port:" " configuraion ignored" ) return master_uri
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 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 is_ipv6(ip): """ Returns a bool telling if the value passed to it was a valid IPv6 address """ # TODO: use the builtin filter (https://docs.saltstack.com/en/latest/topics/jinja/index.html#is-ipv6) # once we Salt>2017.7.0 try: return ipaddress.ip_address(ip).version == 6 except ValueError: return False
def ip_bracket(addr): ''' Ensure IP addresses are URI-compatible - specifically, add brackets around IPv6 literals if they are not already present. ''' addr = str(addr) addr = addr.lstrip('[') addr = addr.rstrip(']') addr = ipaddress.ip_address(addr) return ('[{}]' if addr.version == 6 else '{}').format(addr)
def ip_bracket(addr): """ Ensure IP addresses are URI-compatible - specifically, add brackets around IPv6 literals if they are not already present. """ addr = str(addr) addr = addr.lstrip("[") addr = addr.rstrip("]") addr = ipaddress.ip_address(addr) return ("[{}]" if addr.version == 6 else "{}").format(addr)
def ptr_name(rdata): ''' Return PTR name of given IP :param rdata: IP address :return: PTR record name ''' try: return ipaddress.ip_address(rdata).reverse_pointer except ValueError: log.error('Unable to generate PTR record; {0} is not a valid IP address'.format(rdata)) return 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 ptr_name(rdata): """ Return PTR name of given IP :param rdata: IP address :return: PTR record name """ try: return ipaddress.ip_address(rdata).reverse_pointer except ValueError: log.error("Unable to generate PTR record; %s is not a valid IP address", rdata) return False
def test_ip_bracket(self): test_ipv4 = "127.0.0.1" test_ipv6 = "::1" test_ipv6_uri = "[::1]" self.assertEqual(test_ipv4, salt.utils.zeromq.ip_bracket(test_ipv4)) self.assertEqual("[{}]".format(test_ipv6), salt.utils.zeromq.ip_bracket(test_ipv6)) self.assertEqual("[{}]".format(test_ipv6), salt.utils.zeromq.ip_bracket(test_ipv6_uri)) ip_addr_obj = ipaddress.ip_address(test_ipv4) self.assertEqual(test_ipv4, salt.utils.zeromq.ip_bracket(ip_addr_obj))
def test_ip_bracket(self): test_ipv4 = '127.0.0.1' test_ipv6 = '::1' test_ipv6_uri = '[::1]' self.assertEqual(test_ipv4, salt.utils.zeromq.ip_bracket(test_ipv4)) self.assertEqual('[{0}]'.format(test_ipv6), salt.utils.zeromq.ip_bracket(test_ipv6)) self.assertEqual('[{0}]'.format(test_ipv6), salt.utils.zeromq.ip_bracket(test_ipv6_uri)) ip_addr_obj = ipaddress.ip_address(test_ipv4) self.assertEqual(test_ipv4, salt.utils.zeromq.ip_bracket(ip_addr_obj))
def get_socket(addr, type=socket.SOCK_STREAM, proto=0): ''' Return a socket object for the addr IP-version agnostic ''' version = ipaddress.ip_address(addr).version if version == 4: family = socket.AF_INET elif version == 6: family = socket.AF_INET6 return socket.socket(family, type, proto)
def is_private(ip_addr): ''' Check if the given IP address is a private address .. versionadded:: Fluorine CLI Example: .. code-block:: bash salt '*' network.is_private 10.0.0.3 ''' return ipaddress.ip_address(ip_addr).is_private
def is_private(ip_addr): """ Check if the given IP address is a private address .. versionadded:: 2019.2.0 CLI Example: .. code-block:: bash salt '*' network.is_private 10.0.0.3 """ return ipaddress.ip_address(ip_addr).is_private
def generate_minion_id(): ''' Returns a minion id after checking multiple sources for a FQDN. If no FQDN is found you may get an ip address ''' possible_ids = get_hostnames() # include public and private ipaddresses for addr in salt.utils.network.ip_addrs(): addr = ipaddress.ip_address(addr) if addr.is_loopback: continue possible_ids.append(str(addr)) possible_ids = _filter_localhost_names(possible_ids) # if no minion id if len(possible_ids) == 0: return 'noname' hosts = _sort_hostnames(possible_ids) return hosts[0]
def resolve_network(): """ A function to determine canonical properties of networks from the nodes pillar. CLI Example: salt * node.resolve_network """ network = { "ipv4_address": "", "ipv4_gateway": "", } private_network = network.copy() interfaces = _get_property("network:interfaces", __grains__["id"], {}) for interface_name, interface in interfaces.items(): if "ipv4" not in interface: continue ipv4 = interface["ipv4"]["address"] if ipaddress.ip_address(ipv4).is_private: target = private_network else: target = network if target["ipv4_address"] != "": continue target["ipv4_address"] = ipv4 try: target["ipv4_gateway"] = interface["ipv4"]["gateway"] except KeyError: pass if network["ipv4_address"] == "": return private_network return network
def _is_ipv(ip, version, options=None): if not version: version = 4 if version not in (4, 6): return None try: ip_obj = ipaddress.ip_address(ip) except ValueError: # maybe it is an IP network try: ip_obj = ipaddress.ip_interface(ip) except ValueError: # nope, still not :( return None if not ip_obj.version == version: return None # has the right version, let's move on return _ip_options(ip_obj, version, options=options)
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 _generate_minion_id(): ''' Get list of possible host names and convention names. :return: ''' # There are three types of hostnames: # 1. Network names. How host is accessed from the network. # 2. Host aliases. They might be not available in all the network or only locally (/etc/hosts) # 3. Convention names, an internal nodename. class DistinctList(list): ''' List, which allows to append only distinct objects. Needs to work on Python 2.6, because of collections.OrderedDict only since 2.7 version. Override 'filter()' for custom filtering. ''' localhost_matchers = ['localhost.*', 'ip6-.*', '127.*', r'0\.0\.0\.0', '::1.*', 'ipv6-.*', 'fe00::.*', 'fe02::.*', '1.0.0.*.ip6.arpa'] def append(self, p_object): if p_object and p_object not in self and not self.filter(p_object): super(self.__class__, self).append(p_object) return self def extend(self, iterable): for obj in iterable: self.append(obj) return self def filter(self, element): 'Returns True if element needs to be filtered' for rgx in self.localhost_matchers: if re.match(rgx, element): return True def first(self): return self and self[0] or None hosts = DistinctList().append(socket.getfqdn()).append(platform.node()).append(socket.gethostname()) if not hosts: try: for a_nfo in socket.getaddrinfo(hosts.first() or 'localhost', None, socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP, socket.AI_CANONNAME): if len(a_nfo) > 3: hosts.append(a_nfo[3]) except socket.gaierror: log.warning('Cannot resolve address {addr} info via socket: {message}'.format( addr=hosts.first() or 'localhost (N/A)', message=socket.gaierror) ) # Universal method for everywhere (Linux, Slowlaris, Windows etc) for f_name in ['/etc/hostname', '/etc/nodename', '/etc/hosts', r'{win}\system32\drivers\etc\hosts'.format(win=os.getenv('WINDIR'))]: if not os.path.exists(f_name): continue with salt.utils.fopen(f_name) as f_hdl: for hst in (line.strip().split('#')[0].strip().split() or None for line in f_hdl.read().split(os.linesep)): if hst and (hst[0][:4] in ['127.', '::1'] or len(hst) == 1): hosts.extend(hst) # include public and private ipaddresses return hosts.extend([addr for addr in salt.utils.network.ip_addrs() if not ipaddress.ip_address(addr).is_loopback])
def _generate_minion_id(): ''' Get list of possible host names and convention names. :return: ''' # There are three types of hostnames: # 1. Network names. How host is accessed from the network. # 2. Host aliases. They might be not available in all the network or only locally (/etc/hosts) # 3. Convention names, an internal nodename. class DistinctList(list): ''' List, which allows to append only distinct objects. Needs to work on Python 2.6, because of collections.OrderedDict only since 2.7 version. Override 'filter()' for custom filtering. ''' localhost_matchers = [r'localhost.*', r'ip6-.*', r'127[.]\d', r'0\.0\.0\.0', r'::1.*', r'ipv6-.*', r'fe00::.*', r'fe02::.*', r'1.0.0.*.ip6.arpa'] def append(self, p_object): if p_object and p_object not in self and not self.filter(p_object): super(self.__class__, self).append(p_object) return self def extend(self, iterable): for obj in iterable: self.append(obj) return self def filter(self, element): 'Returns True if element needs to be filtered' for rgx in self.localhost_matchers: if re.match(rgx, element): return True def first(self): return self and self[0] or None hosts = DistinctList().append(socket.getfqdn()).append(platform.node()).append(socket.gethostname()) if not hosts: try: for a_nfo in socket.getaddrinfo(hosts.first(), None, socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP, socket.AI_CANONNAME): if len(a_nfo) > 3: hosts.append(a_nfo[3]) except socket.gaierror: log.warning('Cannot resolve address {addr} info via socket: {message}'.format( addr=hosts.first(), message=socket.gaierror) ) # Universal method for everywhere (Linux, Slowlaris, Windows etc) for f_name in ['/etc/hostname', '/etc/nodename', '/etc/hosts', r'{win}\system32\drivers\etc\hosts'.format(win=os.getenv('WINDIR'))]: if not os.path.exists(f_name): continue with salt.utils.fopen(f_name) as f_hdl: for hst in (line.strip().split('#')[0].strip().split() or None for line in f_hdl.read().split(os.linesep)): if hst and (hst[0][:4] in ['127.', '::1'] or len(hst) == 1): hosts.extend(hst) # include public and private ipaddresses return hosts.extend([addr for addr in salt.utils.network.ip_addrs() if not ipaddress.ip_address(addr).is_loopback])