def getaddrinfo(self, host, port, family=0, socktype=0, proto=0, flags=0): if ((host in (u'localhost', b'localhost') or (is_ipv6_addr(host) and host.startswith('fe80'))) or not isinstance(host, str) or (flags & AI_NUMERICHOST)): # this handles cases which do not require network access # 1) host is None # 2) host is of an invalid type # 3) host is localhost or a link-local ipv6; dnspython returns the wrong # scope-id for those. # 3) AI_NUMERICHOST flag is set return _socket.getaddrinfo(host, port, family, socktype, proto, flags) if family == AF_UNSPEC: # This tends to raise in the case that a v6 address did not exist # but a v4 does. So we break it into two parts. # Note that if there is no ipv6 in the hosts file, but there *is* # an ipv4, and there *is* an ipv6 in the nameservers, we will return # both (from the first call). The system resolver on OS X only returns # the results from the hosts file. doubleclick.com is one example. # See also https://github.com/gevent/gevent/issues/1012 try: return _getaddrinfo(host, port, family, socktype, proto, flags) except socket.gaierror: try: return _getaddrinfo(host, port, AF_INET6, socktype, proto, flags) except socket.gaierror: return _getaddrinfo(host, port, AF_INET, socktype, proto, flags) else: return _getaddrinfo(host, port, family, socktype, proto, flags)
def load(self): # pylint:disable=too-many-locals # Load hosts file # This will (re)load the data from the hosts # file if it has changed. try: load_time = os.stat(self.fname).st_mtime needs_load = load_time > self._last_load except (IOError, OSError): from gevent import get_hub get_hub().handle_error(self, *sys.exc_info()) needs_load = False if not needs_load: return v4 = {} v6 = {} aliases = {} reverse = {} for line in self._readlines(): parts = line.split() if len(parts) < 2: continue ip = parts.pop(0) if is_ipv4_addr(ip): ipmap = v4 elif is_ipv6_addr(ip): if ip.startswith('fe80'): # Do not use link-local addresses, OSX stores these here continue ipmap = v6 else: continue cname = parts.pop(0).lower() ipmap[cname] = ip for alias in parts: alias = alias.lower() ipmap[alias] = ip aliases[alias] = cname # XXX: This is wrong for ipv6 if ipmap is v4: ptr = '.'.join(reversed(ip.split('.'))) + '.in-addr.arpa' else: ptr = ip + '.ip6.arpa.' if ptr not in reverse: reverse[ptr] = cname self._last_load = load_time self.v4 = v4 self.v6 = v6 self.aliases = aliases self.reverse = reverse
def getaddrinfo(self, host, port, family=0, socktype=0, proto=0, flags=0): host = self._hostname_to_bytes(host) if host is not None else None if (not isinstance(host, bytes) # 1, 2 or (flags & AI_NUMERICHOST) # 3 or host in self._LOCAL_HOSTNAMES # 4 or (is_ipv6_addr(host) and host.startswith(b'fe80')) # 5 ): # This handles cases which do not require network access # 1) host is None # 2) host is of an invalid type # 3) AI_NUMERICHOST flag is set # 4) It's a well-known alias. TODO: This is special casing for c-ares that we don't # really want to do. It's here because it resolves a discrepancy with the system # resolvers caught by test cases. In gevent 20.4.0, this only worked correctly on # Python 3 and not Python 2, by accident. # 5) host is a link-local ipv6; dnspython returns the wrong # scope-id for those. return native_getaddrinfo(host, port, family, socktype, proto, flags) return self._getaddrinfo(host, port, family, socktype, proto, flags)