diff options
author | Bob Halley <halley@dnspython.org> | 2020-07-18 07:00:28 -0700 |
---|---|---|
committer | Bob Halley <halley@dnspython.org> | 2020-07-18 07:00:28 -0700 |
commit | f4d609b82189ca24eefb9c8a118783070ccc7535 (patch) | |
tree | 986cb6c586a0d6e435972054714570f5b97c8d1a | |
parent | 89e50894704484acefddd9112f381197fd7493d5 (diff) | |
download | dnspython-canonical_name.tar.gz |
Add canonical_name() method to resolver.canonical_name
-rw-r--r-- | dns/resolver.py | 33 | ||||
-rw-r--r-- | doc/resolver-functions.rst | 1 | ||||
-rw-r--r-- | tests/test_resolver.py | 14 |
3 files changed, 48 insertions, 0 deletions
diff --git a/dns/resolver.py b/dns/resolver.py index 513841e..eb38ba2 100644 --- a/dns/resolver.py +++ b/dns/resolver.py @@ -1109,6 +1109,29 @@ class Resolver: rdclass=dns.rdataclass.IN, *args, **kwargs) + def canonical_name(self, name): + """Determine the canonical name of *name*. + + The canonical name is the name the resolver uses for queries + after all CNAME and DNAME renamings have been applied. + + *name*, a ``dns.name.Name`` or ``str``, the query name. + + This method can raise any exception that ``resolve()`` can + raise, other than `dns.resolver.NoAnswer`` and + ``dns.resolver.NXDOMAIN``. + + Returns a ``dns.name.Name``. + """ + if isinstance(name, str): + name = dns.name.from_text(name) + try: + answer = self.resolve(name, raise_on_no_answer=False) + canonical_name = answer.canonical_name + except dns.resolver.NXDOMAIN as e: + canonical_name = e.canonical_name + return canonical_name + def use_tsig(self, keyring, keyname=None, algorithm=dns.tsig.default_algorithm): """Add a TSIG signature to each query. @@ -1233,6 +1256,16 @@ def resolve_address(ipaddr, *args, **kwargs): return get_default_resolver().resolve_address(ipaddr, *args, **kwargs) +def canonical_name(name): + """Determine the canonical name of *name*. + + See ``dns.resolver.Resolver.canonical_name`` for more information on the + parameters and possible exceptions. + """ + + return get_default_resolver().canonical_name(name) + + def zone_for_name(name, rdclass=dns.rdataclass.IN, tcp=False, resolver=None): """Find the name of the zone which contains the specified name. diff --git a/doc/resolver-functions.rst b/doc/resolver-functions.rst index 6e57957..179484c 100644 --- a/doc/resolver-functions.rst +++ b/doc/resolver-functions.rst @@ -5,6 +5,7 @@ Resolver Functions and The Default Resolver .. autofunction:: dns.resolver.resolve .. autofunction:: dns.resolver.resolve_address +.. autofunction:: dns.resolver.canonical_name .. autofunction:: dns.resolver.zone_for_name .. autofunction:: dns.resolver.query .. autodata:: dns.resolver.default_resolver diff --git a/tests/test_resolver.py b/tests/test_resolver.py index cadf224..83e8d66 100644 --- a/tests/test_resolver.py +++ b/tests/test_resolver.py @@ -475,6 +475,20 @@ class LiveResolverTests(unittest.TestCase): answer2 = res.resolve('dns.google.', 'A') self.assertIs(answer2, answer1) + def testCanonicalNameNoCNAME(self): + cname = dns.name.from_text('www.google.com') + self.assertTrue(dns.resolver.canonical_name('www.google.com') == cname) + + def testCanonicalNameCNAME(self): + name = dns.name.from_text('www.dnspython.org') + cname = dns.name.from_text('dmfrjf4ips8xa.cloudfront.net') + self.assertTrue(dns.resolver.canonical_name(name) == cname) + + def testCanonicalNameDangling(self): + name = dns.name.from_text('dangling-cname.dnspython.org') + cname = dns.name.from_text('dangling-target.dnspython.org') + self.assertTrue(dns.resolver.canonical_name(name) == cname) + class PollingMonkeyPatchMixin(object): def setUp(self): self.__native_selector_class = dns.query._selector_class |