nsupdate: Use authoritative server for zone lookup (#62329)
Using a regular recursive resolver to lookup the zone name might not work when the zone in question belong to a private/internal domain. The authoritative server being used on the other hand will definitely know about the zone(s) it's serving. This approach is also consistent with the nsupdate module already querying the specified authoritative server for TTL values. The reason for the implementation having to loop until finding a direct match is to account for different SOA responses triggered by CNAMEs and DNAMEs. The previously used `dns.resolver.zone_for_name()` function does the same. Resolves #62052
This commit is contained in:
parent
ee91714eb2
commit
75dfe6c88a
2 changed files with 28 additions and 8 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
bugfixes:
|
||||||
|
- nsupdate - Fix zone name lookup of internal/private zones (https://github.com/ansible/ansible/issues/62052)
|
|
@ -203,14 +203,7 @@ class RecordManager(object):
|
||||||
if module.params['zone'] is None:
|
if module.params['zone'] is None:
|
||||||
if module.params['record'][-1] != '.':
|
if module.params['record'][-1] != '.':
|
||||||
self.module.fail_json(msg='record must be absolute when omitting zone parameter')
|
self.module.fail_json(msg='record must be absolute when omitting zone parameter')
|
||||||
|
self.zone = self.lookup_zone()
|
||||||
try:
|
|
||||||
self.zone = dns.resolver.zone_for_name(self.module.params['record']).to_text()
|
|
||||||
except (dns.exception.Timeout, dns.resolver.NoNameservers, dns.resolver.NoRootSOA) as e:
|
|
||||||
self.module.fail_json(msg='Zone resolver error (%s): %s' % (e.__class__.__name__, to_native(e)))
|
|
||||||
|
|
||||||
if self.zone is None:
|
|
||||||
self.module.fail_json(msg='Unable to find zone, dnspython returned None')
|
|
||||||
else:
|
else:
|
||||||
self.zone = module.params['zone']
|
self.zone = module.params['zone']
|
||||||
|
|
||||||
|
@ -251,6 +244,31 @@ class RecordManager(object):
|
||||||
return entry
|
return entry
|
||||||
return '"{text}"'.format(text=entry)
|
return '"{text}"'.format(text=entry)
|
||||||
|
|
||||||
|
def lookup_zone(self):
|
||||||
|
name = dns.name.from_text(self.module.params['record'])
|
||||||
|
while True:
|
||||||
|
query = dns.message.make_query(name, dns.rdatatype.SOA)
|
||||||
|
try:
|
||||||
|
if self.module.params['protocol'] == 'tcp':
|
||||||
|
lookup = dns.query.tcp(query, self.module.params['server'], timeout=10, port=self.module.params['port'])
|
||||||
|
else:
|
||||||
|
lookup = dns.query.udp(query, self.module.params['server'], timeout=10, port=self.module.params['port'])
|
||||||
|
except (socket_error, dns.exception.Timeout) as e:
|
||||||
|
self.module.fail_json(msg='DNS server error: (%s): %s' % (e.__class__.__name__, to_native(e)))
|
||||||
|
if lookup.rcode() in [dns.rcode.SERVFAIL, dns.rcode.REFUSED]:
|
||||||
|
self.module.fail_json(msg='Zone lookup failure: \'%s\' will not respond to queries regarding \'%s\'.' % (
|
||||||
|
self.module.params['server'], self.module.params['record']))
|
||||||
|
try:
|
||||||
|
zone = lookup.authority[0].name
|
||||||
|
if zone == name:
|
||||||
|
return zone.to_text()
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
name = name.parent()
|
||||||
|
except dns.name.NoParent:
|
||||||
|
self.module.fail_json(msg='Zone lookup of \'%s\' failed for unknown reason.' % (self.module.params['record']))
|
||||||
|
|
||||||
def __do_update(self, update):
|
def __do_update(self, update):
|
||||||
response = None
|
response = None
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in a new issue