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(str(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 _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 iter(ifaces.items()) if k == interface]) if not target_ifaces: log.error('Interface %s not found.', interface) for ip_info in target_ifaces.values(): 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 is_ipv4(ip): """ Returns a bool telling if the value passed to it was a valid IPv4 address """ try: return ipaddress.ip_address(ip).version == 4 except ValueError: return False
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 '%s'", cidr) return False if addr is None: addr = ip_addrs() addr.extend(ip_addrs6()) elif not isinstance(addr, (list, tuple)): addr = (addr, ) return any(ipaddress.ip_address(item) in cidr for item in addr)
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 one 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 hostname = socket.gethostname() hosts = DistinctList().append( hubblestack.utils.stringutils.to_unicode( socket.getfqdn( hubblestack.utils.stringutils.to_bytes(hostname)))).append( platform.node()).append(hostname) 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'))): try: with hubblestack.utils.files.fopen(f_name) as f_hdl: for line in f_hdl: line = hubblestack.utils.stringutils.to_unicode(line) hst = line.strip().split('#')[0].strip().split() if hst: if hst[0][:4] in ('127.', '::1') or len(hst) == 1: hosts.extend(hst) except IOError: pass # include public and private ipaddresses return hosts.extend([ addr for addr in ip_addrs() if not ipaddress.ip_address(addr).is_loopback ])
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 hubblestack.utils.files.fopen(src) as src_file: # pylint: disable=too-many-nested-blocks for line in src_file: line = hubblestack.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 = hubblestack.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 {}