summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Halley <halley@dnspython.org>2020-05-15 05:50:10 -0700
committerBob Halley <halley@dnspython.org>2020-05-15 05:50:10 -0700
commit997e913cd19553413a7545c7568f2917c0e396c2 (patch)
tree36fe651f1e44807dfcfacee9143911cc70660f0f
parent26642eb9e77e4c44ee6852016ec14d7d748db8fc (diff)
downloaddnspython-997e913cd19553413a7545c7568f2917c0e396c2.tar.gz
Add resolver resolve(), deprecate query().
-rw-r--r--dns/e164.py2
-rw-r--r--dns/resolver.py115
-rw-r--r--dns/resolver.pyi32
-rw-r--r--doc/resolver-functions.rst1
-rw-r--r--tests/test_nsec3_hash.py2
-rw-r--r--tests/test_resolver.py19
6 files changed, 128 insertions, 43 deletions
diff --git a/dns/e164.py b/dns/e164.py
index d6e695b..83731b2 100644
--- a/dns/e164.py
+++ b/dns/e164.py
@@ -98,7 +98,7 @@ def query(number, domains, resolver=None):
domain = dns.name.from_text(domain)
qname = dns.e164.from_e164(number, domain)
try:
- return resolver.query(qname, 'NAPTR')
+ return resolver.resolve(qname, 'NAPTR')
except dns.resolver.NXDOMAIN as e:
e_nx += e
raise e_nx
diff --git a/dns/resolver.py b/dns/resolver.py
index ee4a191..3c250b0 100644
--- a/dns/resolver.py
+++ b/dns/resolver.py
@@ -22,6 +22,7 @@ import socket
import sys
import time
import random
+import warnings
try:
import threading as _threading
except ImportError:
@@ -805,9 +806,26 @@ class Resolver(object):
raise Timeout(timeout=duration)
return min(lifetime - duration, self.timeout)
- def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN,
- tcp=False, source=None, raise_on_no_answer=True, source_port=0,
- lifetime=None):
+ def _get_qnames_to_try(self, qname, search):
+ # This is a separate method so we can unit test the search
+ # rules without requiring the Internet.
+ qnames_to_try = []
+ if qname.is_absolute():
+ qnames_to_try.append(qname)
+ else:
+ if len(qname) > 1:
+ qnames_to_try.append(qname.concatenate(dns.name.root))
+ if search and self.search:
+ for suffix in self.search:
+ if self.ndots is None or len(qname.labels) >= self.ndots:
+ qnames_to_try.append(qname.concatenate(suffix))
+ else:
+ qnames_to_try.append(qname.concatenate(self.domain))
+ return qnames_to_try
+
+ def resolve(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN,
+ tcp=False, source=None, raise_on_no_answer=True, source_port=0,
+ lifetime=None, search=False):
"""Query nameservers to find the answer to the question.
The *qname*, *rdtype*, and *rdclass* parameters may be objects
@@ -830,7 +848,12 @@ class Resolver(object):
*source_port*, an ``int``, the port from which to send the message.
- *lifetime*, a ``float``, how many seconds a query should run before timing out.
+ *lifetime*, a ``float``, how many seconds a query should run
+ before timing out.
+
+ *search*, a ``bool``, determines whether search lists configured
+ in the system's resolver configuration are used. The default is
+ ``False``.
Raises ``dns.exception.Timeout`` if no answers could be found
in the specified lifetime.
@@ -848,6 +871,7 @@ class Resolver(object):
nameservers are available to answer the question.
Returns a ``dns.resolver.Answer`` instance.
+
"""
if isinstance(qname, str):
@@ -860,18 +884,7 @@ class Resolver(object):
rdclass = dns.rdataclass.from_text(rdclass)
if dns.rdataclass.is_metaclass(rdclass):
raise NoMetaqueries
- qnames_to_try = []
- if qname.is_absolute():
- qnames_to_try.append(qname)
- else:
- if len(qname) > 1:
- qnames_to_try.append(qname.concatenate(dns.name.root))
- if self.search:
- for suffix in self.search:
- if self.ndots is None or len(qname.labels) >= self.ndots:
- qnames_to_try.append(qname.concatenate(suffix))
- else:
- qnames_to_try.append(qname.concatenate(self.domain))
+ qnames_to_try = self._get_qnames_to_try(qname, search)
all_nxdomain = True
nxdomain_responses = {}
start = time.time()
@@ -1035,22 +1048,40 @@ class Resolver(object):
self.cache.put((_qname, rdtype, rdclass), answer)
return answer
- def reverse_query(self, ipaddr, *args, **kwargs):
- """Use a resolver to run a Reverse IP Query for PTR records.
+ def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN,
+ tcp=False, source=None, raise_on_no_answer=True, source_port=0,
+ lifetime=None):
+ """Query nameservers to find the answer to the question.
+
+ This method calls resolve() with ``search=True``, and is
+ provided for backwards compatbility with prior versions of
+ dnspython. See the documentation for the resolve() method for
+ further details.
+ """
+ warnings.warn('please use dns.resolver.Resolver.resolve() instead',
+ DeprecationWarning, stacklevel=2)
+ return self.resolve(qname, rdtype, rdclass, tcp, source,
+ raise_on_no_answer, source_port, lifetime,
+ True)
+
+ def resolve_address(self, ipaddr, *args, **kwargs):
+ """Use a resolver to run a reverse query for PTR records.
- This utilizes the in-built query function to perform a PTR lookup on the
+ This utilizes the resolve() method to perform a PTR lookup on the
specified IP address.
- *ipaddr*, a ``str``, the IP address you want to get the PTR record for.
+ *ipaddr*, a ``str``, the IPv4 or IPv6 address you want to get
+ the PTR record for.
- All other arguments that can be passed to the query function except for
- rdtype and rdclass are also supported by this function.
+ All other arguments that can be passed to the resolve() function
+ except for rdtype and rdclass are also supported by this
+ function.
"""
- return self.query(dns.reversename.from_address(ipaddr),
- rdtype=dns.rdatatype.PTR,
- rdclass=dns.rdataclass.IN,
- *args, **kwargs)
+ return self.resolve(dns.reversename.from_address(ipaddr),
+ rdtype=dns.rdatatype.PTR,
+ rdclass=dns.rdataclass.IN,
+ *args, **kwargs)
def use_tsig(self, keyring, keyname=None,
algorithm=dns.tsig.default_algorithm):
@@ -1148,21 +1179,37 @@ def reset_default_resolver():
default_resolver = Resolver()
-def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN,
- tcp=False, source=None, raise_on_no_answer=True,
- source_port=0, lifetime=None):
+def resolve(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN,
+ tcp=False, source=None, raise_on_no_answer=True,
+ source_port=0, lifetime=None, search=False):
"""Query nameservers to find the answer to the question.
This is a convenience function that uses the default resolver
object to make the query.
- See ``dns.resolver.Resolver.query`` for more information on the
+ See ``dns.resolver.Resolver.resolve`` for more information on the
parameters.
"""
- return get_default_resolver().query(qname, rdtype, rdclass, tcp, source,
- raise_on_no_answer, source_port,
- lifetime)
+ return get_default_resolver().resolve(qname, rdtype, rdclass, tcp, source,
+ raise_on_no_answer, source_port,
+ lifetime, search)
+
+def query(qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN,
+ tcp=False, source=None, raise_on_no_answer=True,
+ source_port=0, lifetime=None):
+ """Query nameservers to find the answer to the question.
+
+ This method calls resolve() with ``search=True``, and is
+ provided for backwards compatbility with prior versions of
+ dnspython. See the documentation for the resolve() method for
+ further details.
+ """
+ warnings.warn('please use dns.resolver.resolve() instead',
+ DeprecationWarning, stacklevel=2)
+ return resolve(qname, rdtype, rdclass, tcp, source,
+ raise_on_no_answer, source_port, lifetime,
+ True)
def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False, resolver=None):
@@ -1192,7 +1239,7 @@ def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False, resolver=None):
raise NotAbsolute(name)
while 1:
try:
- answer = resolver.query(name, dns.rdatatype.SOA, rdclass, tcp)
+ answer = resolver.resolve(name, dns.rdatatype.SOA, rdclass, tcp)
if answer.rrset.name == name:
return name
# otherwise we were CNAMEd or DNAMEd and need to look higher
diff --git a/dns/resolver.pyi b/dns/resolver.pyi
index 39f1e65..3fb2931 100644
--- a/dns/resolver.pyi
+++ b/dns/resolver.pyi
@@ -14,11 +14,18 @@ class NoMetaqueries(exception.DNSException): ...
class NoResolverConfiguration(exception.DNSException): ...
Timeout = exception.Timeout
-def query(qname : str, rdtype : Union[int,str] = 0, rdclass : Union[int,str] = 0,
+def resolve(qname : str, rdtype : Union[int,str] = 0,
+ rdclass : Union[int,str] = 0,
+ tcp=False, source=None, raise_on_no_answer=True,
+ source_port=0, lifetime : Optional[float]=None,
+ search : bool = False):
+ ...
+def query(qname : str, rdtype : Union[int,str] = 0,
+ rdclass : Union[int,str] = 0,
tcp=False, source=None, raise_on_no_answer=True,
- source_port=0):
+ source_port=0, lifetime : Optional[float]=None):
...
-def reverse_query(self, ipaddr: str, *args: Any, **kwargs: Optional[Dict]):
+def resolve_address(self, ipaddr: str, *args: Any, **kwargs: Optional[Dict]):
...
class LRUCache:
def __init__(self, max_size=1000):
@@ -31,12 +38,23 @@ class Answer:
def __init__(self, qname, rdtype, rdclass, response,
raise_on_no_answer=True):
...
-def zone_for_name(name, rdclass : int = rdataclass.IN, tcp=False, resolver : Optional[Resolver] = None):
+def zone_for_name(name, rdclass : int = rdataclass.IN, tcp=False,
+ resolver : Optional[Resolver] = None):
...
class Resolver:
- def __init__(self, filename : Optional[str] = '/etc/resolv.conf', configure : Optional[bool] = True):
+ def __init__(self, filename : Optional[str] = '/etc/resolv.conf',
+ configure : Optional[bool] = True):
self.nameservers : List[str]
- def query(self, qname : str, rdtype : Union[int,str] = rdatatype.A, rdclass : Union[int,str] = rdataclass.IN,
- tcp : bool = False, source : Optional[str] = None, raise_on_no_answer=True, source_port : int = 0):
+ def resolve(self, qname : str, rdtype : Union[int,str] = rdatatype.A,
+ rdclass : Union[int,str] = rdataclass.IN,
+ tcp : bool = False, source : Optional[str] = None,
+ raise_on_no_answer=True, source_port : int = 0,
+ lifetime : Optional[float]=None, search : bool = False):
+ ...
+ def query(self, qname : str, rdtype : Union[int,str] = rdatatype.A,
+ rdclass : Union[int,str] = rdataclass.IN,
+ tcp : bool = False, source : Optional[str] = None,
+ raise_on_no_answer=True, source_port : int = 0,
+ lifetime : Optional[float]=None):
...
diff --git a/doc/resolver-functions.rst b/doc/resolver-functions.rst
index d3c5dcc..1fb432c 100644
--- a/doc/resolver-functions.rst
+++ b/doc/resolver-functions.rst
@@ -3,6 +3,7 @@
Resolver Functions and The Default Resolver
===========================================
+.. autofunction:: dns.resolver.resolve
.. autofunction:: dns.resolver.query
.. autofunction:: dns.resolver.zone_for_name
.. autodata:: dns.resolver.default_resolver
diff --git a/tests/test_nsec3_hash.py b/tests/test_nsec3_hash.py
index 58bdeb3..6f18240 100644
--- a/tests/test_nsec3_hash.py
+++ b/tests/test_nsec3_hash.py
@@ -1,6 +1,6 @@
import unittest
-from dns import dnssec,name
+from dns import dnssec, name
class NSEC3Hash(unittest.TestCase):
diff --git a/tests/test_resolver.py b/tests/test_resolver.py
index 5809650..f6ad762 100644
--- a/tests/test_resolver.py
+++ b/tests/test_resolver.py
@@ -264,6 +264,25 @@ class BaseResolverTests(unittest.TestCase):
for a in answer:
pass
+ def testSearchLists(self):
+ res = dns.resolver.Resolver()
+ res.domain = dns.name.from_text('example')
+ res.search = [dns.name.from_text(x) for x in
+ ['dnspython.org', 'dnspython.net']]
+ qname = dns.name.from_text('www', None)
+ qnames = res._get_qnames_to_try(qname, True)
+ self.assertEqual(qnames,
+ [dns.name.from_text(x) for x in
+ ['www.dnspython.org', 'www.dnspython.net']])
+ qnames = res._get_qnames_to_try(qname, False)
+ self.assertEqual(qnames,
+ [dns.name.from_text('www.example.')])
+ qname = dns.name.from_text('absolute')
+ qnames = res._get_qnames_to_try(qname, True)
+ self.assertEqual(qnames, [qname])
+ qnames = res._get_qnames_to_try(qname, False)
+ self.assertEqual(qnames, [qname])
+
class PollingMonkeyPatchMixin(object):
def setUp(self):
self.__native_polling_backend = dns.query._polling_backend