Use aiodns instead of dnspython to query DNS records
This commit is contained in:
parent
5b41fb98de
commit
711f8dc6af
@ -8,6 +8,7 @@
|
|||||||
:license: MIT, see LICENSE for more details
|
:license: MIT, see LICENSE for more details
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import socket
|
import socket
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
@ -16,51 +17,42 @@ import random
|
|||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
#: Global flag indicating the availability of the ``dnspython`` package.
|
#: Global flag indicating the availability of the ``aiodns`` package.
|
||||||
#: Installing ``dnspython`` can be done via:
|
#: Installing ``aiodns`` can be done via:
|
||||||
#:
|
#:
|
||||||
#: .. code-block:: sh
|
#: .. code-block:: sh
|
||||||
#:
|
#:
|
||||||
#: pip install dnspython
|
#: pip install aiodns
|
||||||
#:
|
AIODNS_AVAILABLE = False
|
||||||
#: For Python3, installation may require installing from source using
|
|
||||||
#: the ``python3`` branch:
|
|
||||||
#:
|
|
||||||
#: .. code-block:: sh
|
|
||||||
#:
|
|
||||||
#: git clone http://github.com/rthalley/dnspython
|
|
||||||
#: cd dnspython
|
|
||||||
#: git checkout python3
|
|
||||||
#: python3 setup.py install
|
|
||||||
DNSPYTHON_AVAILABLE = False
|
|
||||||
try:
|
try:
|
||||||
import dns.resolver
|
import aiodns
|
||||||
DNSPYTHON_AVAILABLE = True
|
AIODNS_AVAILABLE = True
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
log.debug("Could not find dnspython package. " + \
|
log.debug("Could not find aiodns package. " + \
|
||||||
"Not all features will be available")
|
"Not all features will be available")
|
||||||
|
|
||||||
|
|
||||||
def default_resolver():
|
def default_resolver():
|
||||||
"""Return a basic DNS resolver object.
|
"""Return a basic DNS resolver object.
|
||||||
|
|
||||||
:returns: A :class:`dns.resolver.Resolver` object if dnspython
|
:returns: A :class:`aiodns.DNSResolver` object if aiodns
|
||||||
is available. Otherwise, ``None``.
|
is available. Otherwise, ``None``.
|
||||||
"""
|
"""
|
||||||
if DNSPYTHON_AVAILABLE:
|
if AIODNS_AVAILABLE:
|
||||||
return dns.resolver.get_default_resolver()
|
return aiodns.DNSResolver(loop=asyncio.get_event_loop())
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
def resolve(host, port=None, service=None, proto='tcp',
|
def resolve(host, port=None, service=None, proto='tcp',
|
||||||
resolver=None, use_ipv6=True, use_dnspython=True):
|
resolver=None, use_ipv6=True, use_aiodns=True):
|
||||||
"""Peform DNS resolution for a given hostname.
|
"""Peform DNS resolution for a given hostname.
|
||||||
|
|
||||||
Resolution may perform SRV record lookups if a service and protocol
|
Resolution may perform SRV record lookups if a service and protocol
|
||||||
are specified. The returned addresses will be sorted according to
|
are specified. The returned addresses will be sorted according to
|
||||||
the SRV priorities and weights.
|
the SRV priorities and weights.
|
||||||
|
|
||||||
If no resolver is provided, the dnspython resolver will be used if
|
If no resolver is provided, the aiodns resolver will be used if
|
||||||
available. Otherwise the built-in socket facilities will be used,
|
available. Otherwise the built-in socket facilities will be used,
|
||||||
but those do not provide SRV support.
|
but those do not provide SRV support.
|
||||||
|
|
||||||
@ -77,7 +69,7 @@ def resolve(host, port=None, service=None, proto='tcp',
|
|||||||
:param use_ipv6: Optionally control the use of IPv6 in situations
|
:param use_ipv6: Optionally control the use of IPv6 in situations
|
||||||
where it is either not available, or performance
|
where it is either not available, or performance
|
||||||
is degraded. Defaults to ``True``.
|
is degraded. Defaults to ``True``.
|
||||||
:param use_dnspython: Optionally control if dnspython is used to make
|
:param use_aiodns: Optionally control if aiodns is used to make
|
||||||
the DNS queries instead of the built-in DNS
|
the DNS queries instead of the built-in DNS
|
||||||
library.
|
library.
|
||||||
|
|
||||||
@ -85,25 +77,25 @@ def resolve(host, port=None, service=None, proto='tcp',
|
|||||||
:type port: int
|
:type port: int
|
||||||
:type service: string
|
:type service: string
|
||||||
:type proto: string
|
:type proto: string
|
||||||
:type resolver: :class:`dns.resolver.Resolver`
|
:type resolver: :class:`aiodns.DNSResolver`
|
||||||
:type use_ipv6: bool
|
:type use_ipv6: bool
|
||||||
:type use_dnspython: bool
|
:type use_aiodns: bool
|
||||||
|
|
||||||
:return: An iterable of IP address, port pairs in the order
|
:return: An iterable of IP address, port pairs in the order
|
||||||
dictated by SRV priorities and weights, if applicable.
|
dictated by SRV priorities and weights, if applicable.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not use_dnspython:
|
if not use_aiodns:
|
||||||
if DNSPYTHON_AVAILABLE:
|
if AIODNS_AVAILABLE:
|
||||||
log.debug("DNS: Not using dnspython, but dnspython is installed.")
|
log.debug("DNS: Not using aiodns, but aiodns is installed.")
|
||||||
else:
|
else:
|
||||||
log.debug("DNS: Not using dnspython.")
|
log.debug("DNS: Not using aiodns.")
|
||||||
|
|
||||||
if not use_ipv6:
|
if not use_ipv6:
|
||||||
log.debug("DNS: Use of IPv6 has been disabled.")
|
log.debug("DNS: Use of IPv6 has been disabled.")
|
||||||
|
|
||||||
if resolver is None and DNSPYTHON_AVAILABLE and use_dnspython:
|
if resolver is None and AIODNS_AVAILABLE and use_aiodns:
|
||||||
resolver = dns.resolver.get_default_resolver()
|
resolver = aiodns.DNSResolver(loop=asyncio.get_event_loop())
|
||||||
|
|
||||||
# An IPv6 literal is allowed to be enclosed in square brackets, but
|
# An IPv6 literal is allowed to be enclosed in square brackets, but
|
||||||
# the brackets must be stripped in order to process the literal;
|
# the brackets must be stripped in order to process the literal;
|
||||||
@ -113,7 +105,7 @@ def resolve(host, port=None, service=None, proto='tcp',
|
|||||||
try:
|
try:
|
||||||
# If `host` is an IPv4 literal, we can return it immediately.
|
# If `host` is an IPv4 literal, we can return it immediately.
|
||||||
ipv4 = socket.inet_aton(host)
|
ipv4 = socket.inet_aton(host)
|
||||||
yield (host, host, port)
|
return [(host, host, port)]
|
||||||
except socket.error:
|
except socket.error:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -123,7 +115,7 @@ def resolve(host, port=None, service=None, proto='tcp',
|
|||||||
# it immediately.
|
# it immediately.
|
||||||
if hasattr(socket, 'inet_pton'):
|
if hasattr(socket, 'inet_pton'):
|
||||||
ipv6 = socket.inet_pton(socket.AF_INET6, host)
|
ipv6 = socket.inet_pton(socket.AF_INET6, host)
|
||||||
yield (host, host, port)
|
return [(host, host, port)]
|
||||||
except (socket.error, ValueError):
|
except (socket.error, ValueError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -133,29 +125,31 @@ def resolve(host, port=None, service=None, proto='tcp',
|
|||||||
if not service:
|
if not service:
|
||||||
hosts = [(host, port)]
|
hosts = [(host, port)]
|
||||||
else:
|
else:
|
||||||
hosts = get_SRV(host, port, service, proto,
|
hosts = yield from get_SRV(host, port, service, proto,
|
||||||
resolver=resolver,
|
resolver=resolver,
|
||||||
use_dnspython=use_dnspython)
|
use_aiodns=use_aiodns)
|
||||||
|
results = []
|
||||||
for host, port in hosts:
|
for host, port in hosts:
|
||||||
results = []
|
|
||||||
if host == 'localhost':
|
if host == 'localhost':
|
||||||
if use_ipv6:
|
if use_ipv6:
|
||||||
results.append((host, '::1', port))
|
results.append((host, '::1', port))
|
||||||
results.append((host, '127.0.0.1', port))
|
results.append((host, '127.0.0.1', port))
|
||||||
|
|
||||||
if use_ipv6:
|
if use_ipv6:
|
||||||
for address in get_AAAA(host, resolver=resolver,
|
aaaa = yield from get_AAAA(host, resolver=resolver,
|
||||||
use_dnspython=use_dnspython):
|
use_aiodns=use_aiodns)
|
||||||
|
for address in aaaa:
|
||||||
results.append((host, address, port))
|
results.append((host, address, port))
|
||||||
for address in get_A(host, resolver=resolver,
|
|
||||||
use_dnspython=use_dnspython):
|
a = yield from get_A(host, resolver=resolver,
|
||||||
|
use_aiodns=use_aiodns)
|
||||||
|
for address in a:
|
||||||
results.append((host, address, port))
|
results.append((host, address, port))
|
||||||
|
|
||||||
for host, address, port in results:
|
return results
|
||||||
yield host, address, port
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
def get_A(host, resolver=None, use_dnspython=True):
|
def get_A(host, resolver=None, use_aiodns=True):
|
||||||
"""Lookup DNS A records for a given host.
|
"""Lookup DNS A records for a given host.
|
||||||
|
|
||||||
If ``resolver`` is not provided, or is ``None``, then resolution will
|
If ``resolver`` is not provided, or is ``None``, then resolution will
|
||||||
@ -163,46 +157,41 @@ def get_A(host, resolver=None, use_dnspython=True):
|
|||||||
|
|
||||||
:param host: The hostname to resolve for A record IPv4 addresses.
|
:param host: The hostname to resolve for A record IPv4 addresses.
|
||||||
:param resolver: Optional DNS resolver object to use for the query.
|
:param resolver: Optional DNS resolver object to use for the query.
|
||||||
:param use_dnspython: Optionally control if dnspython is used to make
|
:param use_aiodns: Optionally control if aiodns is used to make
|
||||||
the DNS queries instead of the built-in DNS
|
the DNS queries instead of the built-in DNS
|
||||||
library.
|
library.
|
||||||
|
|
||||||
:type host: string
|
:type host: string
|
||||||
:type resolver: :class:`dns.resolver.Resolver` or ``None``
|
:type resolver: :class:`aiodns.DNSResolver` or ``None``
|
||||||
:type use_dnspython: bool
|
:type use_aiodns: bool
|
||||||
|
|
||||||
:return: A list of IPv4 literals.
|
:return: A list of IPv4 literals.
|
||||||
"""
|
"""
|
||||||
log.debug("DNS: Querying %s for A records." % host)
|
log.debug("DNS: Querying %s for A records." % host)
|
||||||
|
|
||||||
# If not using dnspython, attempt lookup using the OS level
|
# If not using aiodns, attempt lookup using the OS level
|
||||||
# getaddrinfo() method.
|
# getaddrinfo() method.
|
||||||
if resolver is None or not use_dnspython:
|
if resolver is None or not use_aiodns:
|
||||||
try:
|
try:
|
||||||
recs = socket.getaddrinfo(host, None, socket.AF_INET,
|
recs = socket.getaddrinfo(host, None, socket.AF_INET,
|
||||||
socket.SOCK_STREAM)
|
socket.SOCK_STREAM)
|
||||||
return [rec[4][0] for rec in recs]
|
return [rec[4][0] for rec in recs]
|
||||||
except socket.gaierror:
|
except socket.gaierror:
|
||||||
log.debug("DNS: Error retreiving A address info for %s." % host)
|
log.debug("DNS: Error retrieving A address info for %s." % host)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# Using dnspython:
|
# Using aiodns:
|
||||||
|
future = resolver.query(host, 'A')
|
||||||
try:
|
try:
|
||||||
recs = resolver.query(host, dns.rdatatype.A)
|
recs = yield from future
|
||||||
return [rec.to_text() for rec in recs]
|
except Exception as e:
|
||||||
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
log.debug('DNS: Exception while querying for %s A records: %s', host, e)
|
||||||
log.debug("DNS: No A records for %s" % host)
|
recs = []
|
||||||
return []
|
return recs
|
||||||
except dns.exception.Timeout:
|
|
||||||
log.debug("DNS: A record resolution timed out for %s" % host)
|
|
||||||
return []
|
|
||||||
except dns.exception.DNSException as e:
|
|
||||||
log.debug("DNS: Error querying A records for %s" % host)
|
|
||||||
log.exception(e)
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def get_AAAA(host, resolver=None, use_dnspython=True):
|
@asyncio.coroutine
|
||||||
|
def get_AAAA(host, resolver=None, use_aiodns=True):
|
||||||
"""Lookup DNS AAAA records for a given host.
|
"""Lookup DNS AAAA records for a given host.
|
||||||
|
|
||||||
If ``resolver`` is not provided, or is ``None``, then resolution will
|
If ``resolver`` is not provided, or is ``None``, then resolution will
|
||||||
@ -210,23 +199,23 @@ def get_AAAA(host, resolver=None, use_dnspython=True):
|
|||||||
|
|
||||||
:param host: The hostname to resolve for AAAA record IPv6 addresses.
|
:param host: The hostname to resolve for AAAA record IPv6 addresses.
|
||||||
:param resolver: Optional DNS resolver object to use for the query.
|
:param resolver: Optional DNS resolver object to use for the query.
|
||||||
:param use_dnspython: Optionally control if dnspython is used to make
|
:param use_aiodns: Optionally control if aiodns is used to make
|
||||||
the DNS queries instead of the built-in DNS
|
the DNS queries instead of the built-in DNS
|
||||||
library.
|
library.
|
||||||
|
|
||||||
:type host: string
|
:type host: string
|
||||||
:type resolver: :class:`dns.resolver.Resolver` or ``None``
|
:type resolver: :class:`aiodns.DNSResolver` or ``None``
|
||||||
:type use_dnspython: bool
|
:type use_aiodns: bool
|
||||||
|
|
||||||
:return: A list of IPv6 literals.
|
:return: A list of IPv6 literals.
|
||||||
"""
|
"""
|
||||||
log.debug("DNS: Querying %s for AAAA records." % host)
|
log.debug("DNS: Querying %s for AAAA records." % host)
|
||||||
|
|
||||||
# If not using dnspython, attempt lookup using the OS level
|
# If not using aiodns, attempt lookup using the OS level
|
||||||
# getaddrinfo() method.
|
# getaddrinfo() method.
|
||||||
if resolver is None or not use_dnspython:
|
if resolver is None or not use_aiodns:
|
||||||
if not socket.has_ipv6:
|
if not socket.has_ipv6:
|
||||||
log.debug("Unable to query %s for AAAA records: IPv6 is not supported", host)
|
log.debug("DNS: Unable to query %s for AAAA records: IPv6 is not supported", host)
|
||||||
return []
|
return []
|
||||||
try:
|
try:
|
||||||
recs = socket.getaddrinfo(host, None, socket.AF_INET6,
|
recs = socket.getaddrinfo(host, None, socket.AF_INET6,
|
||||||
@ -237,29 +226,23 @@ def get_AAAA(host, resolver=None, use_dnspython=True):
|
|||||||
"info for %s." % host)
|
"info for %s." % host)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# Using dnspython:
|
# Using aiodns:
|
||||||
|
future = resolver.query(host, 'AAAA')
|
||||||
try:
|
try:
|
||||||
recs = resolver.query(host, dns.rdatatype.AAAA)
|
recs = yield from future
|
||||||
return [rec.to_text() for rec in recs]
|
except Exception as e:
|
||||||
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
log.debug('DNS: Exception while querying for %s AAAA records: %s', host, e)
|
||||||
log.debug("DNS: No AAAA records for %s" % host)
|
recs = []
|
||||||
return []
|
return recs
|
||||||
except dns.exception.Timeout:
|
|
||||||
log.debug("DNS: AAAA record resolution timed out for %s" % host)
|
|
||||||
return []
|
|
||||||
except dns.exception.DNSException as e:
|
|
||||||
log.debug("DNS: Error querying AAAA records for %s" % host)
|
|
||||||
log.exception(e)
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
def get_SRV(host, port, service, proto='tcp', resolver=None, use_dnspython=True):
|
def get_SRV(host, port, service, proto='tcp', resolver=None, use_aiodns=True):
|
||||||
"""Perform SRV record resolution for a given host.
|
"""Perform SRV record resolution for a given host.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
This function requires the use of the ``dnspython`` package. Calling
|
This function requires the use of the ``aiodns`` package. Calling
|
||||||
:func:`get_SRV` without ``dnspython`` will return the provided host
|
:func:`get_SRV` without ``aiodns`` will return the provided host
|
||||||
and port without performing any DNS queries.
|
and port without performing any DNS queries.
|
||||||
|
|
||||||
:param host: The hostname to resolve.
|
:param host: The hostname to resolve.
|
||||||
@ -274,32 +257,23 @@ def get_SRV(host, port, service, proto='tcp', resolver=None, use_dnspython=True)
|
|||||||
:type port: int
|
:type port: int
|
||||||
:type service: string
|
:type service: string
|
||||||
:type proto: string
|
:type proto: string
|
||||||
:type resolver: :class:`dns.resolver.Resolver`
|
:type resolver: :class:`aiodns.DNSResolver`
|
||||||
|
|
||||||
:return: A list of hostname, port pairs in the order dictacted
|
:return: A list of hostname, port pairs in the order dictacted
|
||||||
by SRV priorities and weights.
|
by SRV priorities and weights.
|
||||||
"""
|
"""
|
||||||
if resolver is None or not use_dnspython:
|
if resolver is None or not use_aiodns:
|
||||||
log.warning("DNS: dnspython not found. Can not use SRV lookup.")
|
log.warning("DNS: aiodns not found. Can not use SRV lookup.")
|
||||||
return [(host, port)]
|
return [(host, port)]
|
||||||
|
|
||||||
log.debug("DNS: Querying SRV records for %s" % host)
|
log.debug("DNS: Querying SRV records for %s" % host)
|
||||||
try:
|
try:
|
||||||
recs = resolver.query('_%s._%s.%s' % (service, proto, host),
|
future = resolver.query('_%s._%s.%s' % (service, proto, host),
|
||||||
dns.rdatatype.SRV)
|
'SRV')
|
||||||
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
recs = yield from future
|
||||||
log.debug("DNS: No SRV records for %s." % host)
|
except Exception as e:
|
||||||
return [(host, port)]
|
log.debug('DNS: Exception while querying for %s SRV records: %s', host, e)
|
||||||
except dns.exception.Timeout:
|
return []
|
||||||
log.debug("DNS: SRV record resolution timed out for %s." % host)
|
|
||||||
return [(host, port)]
|
|
||||||
except dns.exception.DNSException as e:
|
|
||||||
log.debug("DNS: Error querying SRV records for %s." % host)
|
|
||||||
log.exception(e)
|
|
||||||
return [(host, port)]
|
|
||||||
|
|
||||||
if len(recs) == 1 and recs[0].target == '.':
|
|
||||||
return [(host, port)]
|
|
||||||
|
|
||||||
answers = {}
|
answers = {}
|
||||||
for rec in recs:
|
for rec in recs:
|
||||||
@ -323,7 +297,7 @@ def get_SRV(host, port, service, proto='tcp', resolver=None, use_dnspython=True)
|
|||||||
for running_sum in sums:
|
for running_sum in sums:
|
||||||
if running_sum >= selected:
|
if running_sum >= selected:
|
||||||
rec = sums[running_sum]
|
rec = sums[running_sum]
|
||||||
host = rec.target.to_text()
|
host = rec.host
|
||||||
if host.endswith('.'):
|
if host.endswith('.'):
|
||||||
host = host[:-1]
|
host = host[:-1]
|
||||||
sorted_recs.append((host, rec.port))
|
sorted_recs.append((host, rec.port))
|
||||||
|
@ -162,7 +162,7 @@ class XMLStream(object):
|
|||||||
#: If set to ``True``, allow using the ``dnspython`` DNS library
|
#: If set to ``True``, allow using the ``dnspython`` DNS library
|
||||||
#: if available. If set to ``False``, the builtin DNS resolver
|
#: if available. If set to ``False``, the builtin DNS resolver
|
||||||
#: will be used, even if ``dnspython`` is installed.
|
#: will be used, even if ``dnspython`` is installed.
|
||||||
self.use_dnspython = True
|
self.use_aiodns = True
|
||||||
|
|
||||||
#: Use CDATA for escaping instead of XML entities. Defaults
|
#: Use CDATA for escaping instead of XML entities. Defaults
|
||||||
#: to ``False``.
|
#: to ``False``.
|
||||||
@ -287,13 +287,32 @@ class XMLStream(object):
|
|||||||
def _connect_routine(self):
|
def _connect_routine(self):
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
self.event_when_connected = "connected"
|
self.event_when_connected = "connected"
|
||||||
|
|
||||||
|
try:
|
||||||
|
record = yield from self.pick_dns_answer(self.default_domain)
|
||||||
|
except StopIteration:
|
||||||
|
# No more DNS records to try
|
||||||
|
self.dns_answers = None
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
if record:
|
||||||
|
host, address, port = record
|
||||||
|
self._service_name = host
|
||||||
|
else:
|
||||||
|
self.event('connection_failed',
|
||||||
|
'No DNS record available for %s' % self.default_domain)
|
||||||
|
self.dns_answers = None
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
yield from loop.create_connection(lambda: self,
|
yield from loop.create_connection(lambda: self,
|
||||||
self.address[0],
|
address,
|
||||||
self.address[1],
|
port,
|
||||||
ssl=self.use_ssl)
|
ssl=self.use_ssl)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
|
log.debug('Connection failed: %s', e)
|
||||||
self.event("connection_failed", e)
|
self.event("connection_failed", e)
|
||||||
|
asyncio.async(self._connect_routine())
|
||||||
|
|
||||||
def process(self, timeout=None):
|
def process(self, timeout=None):
|
||||||
"""Process all the available XMPP events (receiving or sending data on the
|
"""Process all the available XMPP events (receiving or sending data on the
|
||||||
@ -578,6 +597,7 @@ class XMLStream(object):
|
|||||||
idx += 1
|
idx += 1
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
def get_dns_records(self, domain, port=None):
|
def get_dns_records(self, domain, port=None):
|
||||||
"""Get the DNS records for a domain.
|
"""Get the DNS records for a domain.
|
||||||
|
|
||||||
@ -590,11 +610,14 @@ class XMLStream(object):
|
|||||||
resolver = default_resolver()
|
resolver = default_resolver()
|
||||||
self.configure_dns(resolver, domain=domain, port=port)
|
self.configure_dns(resolver, domain=domain, port=port)
|
||||||
|
|
||||||
return resolve(domain, port, service=self.dns_service,
|
result = yield from resolve(domain, port,
|
||||||
resolver=resolver,
|
service=self.dns_service,
|
||||||
use_ipv6=self.use_ipv6,
|
resolver=resolver,
|
||||||
use_dnspython=self.use_dnspython)
|
use_ipv6=self.use_ipv6,
|
||||||
|
use_aiodns=self.use_aiodns)
|
||||||
|
return result
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
def pick_dns_answer(self, domain, port=None):
|
def pick_dns_answer(self, domain, port=None):
|
||||||
"""Pick a server and port from DNS answers.
|
"""Pick a server and port from DNS answers.
|
||||||
|
|
||||||
@ -604,8 +627,9 @@ class XMLStream(object):
|
|||||||
:param domain: The domain in question.
|
:param domain: The domain in question.
|
||||||
:param port: If the results don't include a port, use this one.
|
:param port: If the results don't include a port, use this one.
|
||||||
"""
|
"""
|
||||||
if not self.dns_answers:
|
if self.dns_answers is None:
|
||||||
self.dns_answers = self.get_dns_records(domain, port)
|
dns_records = yield from self.get_dns_records(domain, port)
|
||||||
|
self.dns_answers = iter(dns_records)
|
||||||
|
|
||||||
return next(self.dns_answers)
|
return next(self.dns_answers)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user