]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Apply the resolver search list, domain, and ndots settings in the same way
authorBob Halley <halley@dnspython.org>
Tue, 28 Jul 2020 00:19:11 +0000 (17:19 -0700)
committerBob Halley <halley@dnspython.org>
Tue, 28 Jul 2020 00:19:11 +0000 (17:19 -0700)
that the BIND stub resolver library does.

dns/resolver.py
tests/test_resolver.py

index 46ca30ac9ba620e1ac9ab5aa9a2faa40a031667f..9600c8e23550d579e9a4a518a9b548e36f8e59aa 100644 (file)
@@ -788,9 +788,15 @@ class Resolver:
                     self.nameservers.append(tokens[1])
                 elif tokens[0] == 'domain':
                     self.domain = dns.name.from_text(tokens[1])
+                    # domain and search are exclusive
+                    self.search = []
                 elif tokens[0] == 'search':
+                    # the last search wins
+                    self.search = []
                     for suffix in tokens[1:]:
                         self.search.append(dns.name.from_text(suffix))
+                    # We don't set domain as it is not used if
+                    # len(self.search) > 0
                 elif tokens[0] == 'options':
                     for opt in tokens[1:]:
                         if opt == 'rotate':
@@ -989,14 +995,34 @@ class Resolver:
         if qname.is_absolute():
             qnames_to_try.append(qname)
         else:
-            if len(qname) > 1 or not search:
-                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))
-            elif search:
-                qnames_to_try.append(qname.concatenate(self.domain))
+            abs_qname = qname.concatenate(dns.name.root)
+            if search:
+                if len(self.search) > 0:
+                    # There is a search list, so use it exclusively
+                    search_list = self.search[:]
+                elif self.domain != dns.name.root and self.domain is not None:
+                    # We have some notion of a domain that isn't the root, so
+                    # use it as the search list.
+                    search_list = [self.domain]
+                else:
+                    search_list = []
+                # Figure out the effective ndots (default is 1)
+                if self.ndots is None:
+                    ndots = 1
+                else:
+                    ndots = self.ndots
+                for suffix in search_list:
+                    qnames_to_try.append(qname + suffix)
+                if len(qname) > ndots:
+                    # The name has at least ndots dots, so we should try an
+                    # absolute query first.
+                    qnames_to_try.insert(0, abs_qname)
+                else:
+                    # The name has less than ndots dots, so we should search
+                    # first, then try the absolute name.
+                    qnames_to_try.append(abs_qname)
+            else:
+                qnames_to_try.append(abs_qname)
         return qnames_to_try
 
     def resolve(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN,
index d61e8c92eecfe2bca373dbcec825727c2148f951..4f5643dd8ab8db670f44bcb94af4b32c68bc8039 100644 (file)
@@ -514,7 +514,7 @@ class BaseResolverTests(unittest.TestCase):
         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']])
+                          ['www.dnspython.org', 'www.dnspython.net', 'www.']])
         qnames = res._get_qnames_to_try(qname, False)
         self.assertEqual(qnames,
                          [dns.name.from_text('www.')])
@@ -528,7 +528,27 @@ class BaseResolverTests(unittest.TestCase):
         qnames = res._get_qnames_to_try(qname, None)
         self.assertEqual(qnames,
                          [dns.name.from_text(x) for x in
-                          ['www.dnspython.org', 'www.dnspython.net']])
+                          ['www.dnspython.org', 'www.dnspython.net', 'www.']])
+        #
+        # Now test ndots
+        #
+        qname = dns.name.from_text('a.b', None)
+        res.ndots = 1
+        qnames = res._get_qnames_to_try(qname, True)
+        self.assertEqual(qnames,
+                         [dns.name.from_text(x) for x in
+                          ['a.b', 'a.b.dnspython.org', 'a.b.dnspython.net']])
+        res.ndots = 2
+        qnames = res._get_qnames_to_try(qname, True)
+        self.assertEqual(qnames,
+                         [dns.name.from_text(x) for x in
+                          ['a.b.dnspython.org', 'a.b.dnspython.net', 'a.b']])
+        qname = dns.name.from_text('a.b.c', None)
+        qnames = res._get_qnames_to_try(qname, True)
+        self.assertEqual(qnames,
+                         [dns.name.from_text(x) for x in
+                          ['a.b.c', 'a.b.c.dnspython.org',
+                           'a.b.c.dnspython.net']])
 
     def testSearchListsAbsolute(self):
         res = dns.resolver.Resolver(configure=False)