greendns: Return answers from /etc/hosts despite nameserver errors
When calling getaddrinfo with an unspecified address family, we: * try to get an IPv6 address for the host, first trying /etc/hosts and failing that, using any external nameserver, then * try to get an IPv4 address for it, with the same /etc/hosts -> external nameserver priority. Note that if the host can be resolved using /etc/hosts but only to one of the two address families, we still attempt to contact the external nameserver to resolve it in the other family. Previously, if this timed out or raised a DNSException other than NXDOMAIN, EAI_EAGAIN_ERROR or EAI_NODATA_ERROR would be raised even though we could resolve the host. Now, those errors will only be raised if neither attempt at resolution succeeded. https://github.com/eventlet/eventlet/pull/354
This commit is contained in:
parent
4872be7700
commit
f508a7e330
@ -402,10 +402,19 @@ def _getaddrinfo_lookup(host, family, flags):
|
||||
raise EAI_NONAME_ERROR
|
||||
addrs = []
|
||||
if family == socket.AF_UNSPEC:
|
||||
err = None
|
||||
for qfamily in [socket.AF_INET6, socket.AF_INET]:
|
||||
answer = resolve(host, qfamily, False)
|
||||
if answer.rrset:
|
||||
addrs.extend([rr.address for rr in answer.rrset])
|
||||
try:
|
||||
answer = resolve(host, qfamily, False)
|
||||
except socket.gaierror as e:
|
||||
if e.errno not in (socket.EAI_AGAIN, socket.EAI_NODATA):
|
||||
raise
|
||||
err = e
|
||||
else:
|
||||
if answer.rrset:
|
||||
addrs.extend(rr.address for rr in answer.rrset)
|
||||
if err is not None and not addrs:
|
||||
raise err
|
||||
elif family == socket.AF_INET6 and flags & socket.AI_V4MAPPED:
|
||||
answer = resolve(host, socket.AF_INET6, False)
|
||||
if answer.rrset:
|
||||
|
@ -517,6 +517,62 @@ class TestGetaddrinfo(tests.LimitedTestCase):
|
||||
addr = [('dead:beef::1', 0, 0, 0)] * len(res)
|
||||
assert addr == [ai[-1] for ai in res]
|
||||
|
||||
def test_getaddrinfo_hosts_only_ans_with_timeout(self):
|
||||
def clear_raises(res_self):
|
||||
res_self.raises = None
|
||||
return greendns.dns.resolver.NoAnswer()
|
||||
|
||||
hostsres = _make_mock_base_resolver()
|
||||
hostsres.raises = clear_raises
|
||||
hostsres.rr.address = '1.2.3.4'
|
||||
greendns.resolver = greendns.ResolverProxy(hostsres())
|
||||
res = _make_mock_base_resolver()
|
||||
res.raises = greendns.dns.exception.Timeout
|
||||
greendns.resolver._resolver = res()
|
||||
|
||||
result = greendns.getaddrinfo('example.com', 0, 0)
|
||||
addr = [('1.2.3.4', 0)] * len(result)
|
||||
assert addr == [ai[-1] for ai in result]
|
||||
|
||||
def test_getaddrinfo_hosts_only_ans_with_error(self):
|
||||
def clear_raises(res_self):
|
||||
res_self.raises = None
|
||||
return greendns.dns.resolver.NoAnswer()
|
||||
|
||||
hostsres = _make_mock_base_resolver()
|
||||
hostsres.raises = clear_raises
|
||||
hostsres.rr.address = '1.2.3.4'
|
||||
greendns.resolver = greendns.ResolverProxy(hostsres())
|
||||
res = _make_mock_base_resolver()
|
||||
res.raises = greendns.dns.exception.DNSException
|
||||
greendns.resolver._resolver = res()
|
||||
|
||||
result = greendns.getaddrinfo('example.com', 0, 0)
|
||||
addr = [('1.2.3.4', 0)] * len(result)
|
||||
assert addr == [ai[-1] for ai in result]
|
||||
|
||||
def test_getaddrinfo_hosts_only_timeout(self):
|
||||
hostsres = _make_mock_base_resolver()
|
||||
hostsres.raises = greendns.dns.resolver.NoAnswer
|
||||
greendns.resolver = greendns.ResolverProxy(hostsres())
|
||||
res = _make_mock_base_resolver()
|
||||
res.raises = greendns.dns.exception.Timeout
|
||||
greendns.resolver._resolver = res()
|
||||
|
||||
with tests.assert_raises(socket.gaierror):
|
||||
greendns.getaddrinfo('example.com', 0, 0)
|
||||
|
||||
def test_getaddrinfo_hosts_only_dns_error(self):
|
||||
hostsres = _make_mock_base_resolver()
|
||||
hostsres.raises = greendns.dns.resolver.NoAnswer
|
||||
greendns.resolver = greendns.ResolverProxy(hostsres())
|
||||
res = _make_mock_base_resolver()
|
||||
res.raises = greendns.dns.exception.DNSException
|
||||
greendns.resolver._resolver = res()
|
||||
|
||||
with tests.assert_raises(socket.gaierror):
|
||||
greendns.getaddrinfo('example.com', 0, 0)
|
||||
|
||||
def test_canonname(self):
|
||||
greendns.resolve = _make_mock_resolve()
|
||||
greendns.resolve.add('host.example.com', '1.2.3.4')
|
||||
|
Loading…
Reference in New Issue
Block a user