Skip to content

Commit

Permalink
dig: Support multiple domains in a single lookup (#6334)
Browse files Browse the repository at this point in the history
The docs for this plugin indicated that multiple domains could be
specified at once, but the code did not support multiple domains.
  • Loading branch information
kpfleming committed Apr 14, 2023
1 parent 42bc2cb commit 2f0b6b6
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 51 deletions.
3 changes: 3 additions & 0 deletions changelogs/fragments/6334-dig-support-multiple-domains.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
bugfixes:
- dig - Support multiple domains to be queried as indicated in docs.
(https:/ansible-collections/community.general/pull/6334).
126 changes: 75 additions & 51 deletions plugins/lookup/dig.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
description:
- Return empty result without empty strings, and return empty list instead of C(NXDOMAIN).
- The default for this option will likely change to C(true) in the future.
- This option will be forced to C(true) if multiple domains to be queried are specified.
default: false
type: bool
version_added: 6.0.0
Expand Down Expand Up @@ -95,6 +96,21 @@
msg: "MX record for gmail.com {{ item }}"
with_items: "{{ lookup('community.general.dig', 'gmail.com./MX', wantlist=true) }}"
- name: lookup multiple names at once
ansible.builtin.debug:
msg: "A record found {{ item }}"
loop: "{{'community.general.dig', 'example.org.', 'example.com.', 'gmail.com.', wantlist=true) }}"
- name: lookup multiple names at once (from list variable)
ansible.builtin.debug:
msg: "A record found {{ item }}"
loop: "{{'community.general.dig', *hosts, wantlist=true) }}"
vars:
hosts:
- example.org.
- example.com.
- gmail.com.
- ansible.builtin.debug:
msg: "Reverse DNS for 192.0.2.5 is {{ lookup('community.general.dig', '192.0.2.5/PTR') }}"
- ansible.builtin.debug:
Expand Down Expand Up @@ -308,7 +324,7 @@ def run(self, terms, variables=None, **kwargs):
edns_size = 4096
myres.use_edns(0, ednsflags=dns.flags.DO, payload=edns_size)

domain = None
domains = []
qtype = self.get_option('qtype')
flat = self.get_option('flat')
fail_on_error = self.get_option('fail_on_error')
Expand Down Expand Up @@ -365,63 +381,71 @@ def run(self, terms, variables=None, **kwargs):
if '/' in t:
try:
domain, qtype = t.split('/')
domains.append(domain)
except Exception:
domain = t
domains.append(t)
else:
domain = t
domains.append(t)

# print "--- domain = {0} qtype={1} rdclass={2}".format(domain, qtype, rdclass)

if qtype.upper() == 'PTR':
reversed_domains = []
for domain in domains:
try:
n = dns.reversename.from_address(domain)
reversed_domains.append(n.to_text())
except dns.exception.SyntaxError:
pass
except Exception as e:
raise AnsibleError("dns.reversename unhandled exception %s" % to_native(e))
domains = reversed_domains

if len(domains) > 1:
real_empty = True

ret = []

if qtype.upper() == 'PTR':
for domain in domains:
try:
n = dns.reversename.from_address(domain)
domain = n.to_text()
except dns.exception.SyntaxError:
pass
except Exception as e:
raise AnsibleError("dns.reversename unhandled exception %s" % to_native(e))

try:
answers = myres.query(domain, qtype, rdclass=rdclass)
for rdata in answers:
s = rdata.to_text()
if qtype.upper() == 'TXT':
s = s[1:-1] # Strip outside quotes on TXT rdata

if flat:
ret.append(s)
else:
try:
rd = make_rdata_dict(rdata)
rd['owner'] = answers.canonical_name.to_text()
rd['type'] = dns.rdatatype.to_text(rdata.rdtype)
rd['ttl'] = answers.rrset.ttl
rd['class'] = dns.rdataclass.to_text(rdata.rdclass)

ret.append(rd)
except Exception as err:
if fail_on_error:
raise AnsibleError("Lookup failed: %s" % str(err))
ret.append(str(err))

except dns.resolver.NXDOMAIN as err:
if fail_on_error:
raise AnsibleError("Lookup failed: %s" % str(err))
if not real_empty:
ret.append('NXDOMAIN')
except dns.resolver.NoAnswer as err:
if fail_on_error:
raise AnsibleError("Lookup failed: %s" % str(err))
if not real_empty:
ret.append("")
except dns.resolver.Timeout as err:
if fail_on_error:
raise AnsibleError("Lookup failed: %s" % str(err))
if not real_empty:
ret.append("")
except dns.exception.DNSException as err:
raise AnsibleError("dns.resolver unhandled exception %s" % to_native(err))
answers = myres.query(domain, qtype, rdclass=rdclass)
for rdata in answers:
s = rdata.to_text()
if qtype.upper() == 'TXT':
s = s[1:-1] # Strip outside quotes on TXT rdata

if flat:
ret.append(s)
else:
try:
rd = make_rdata_dict(rdata)
rd['owner'] = answers.canonical_name.to_text()
rd['type'] = dns.rdatatype.to_text(rdata.rdtype)
rd['ttl'] = answers.rrset.ttl
rd['class'] = dns.rdataclass.to_text(rdata.rdclass)

ret.append(rd)
except Exception as err:
if fail_on_error:
raise AnsibleError("Lookup failed: %s" % str(err))
ret.append(str(err))

except dns.resolver.NXDOMAIN as err:
if fail_on_error:
raise AnsibleError("Lookup failed: %s" % str(err))
if not real_empty:
ret.append('NXDOMAIN')
except dns.resolver.NoAnswer as err:
if fail_on_error:
raise AnsibleError("Lookup failed: %s" % str(err))
if not real_empty:
ret.append("")
except dns.resolver.Timeout as err:
if fail_on_error:
raise AnsibleError("Lookup failed: %s" % str(err))
if not real_empty:
ret.append("")
except dns.exception.DNSException as err:
raise AnsibleError("dns.resolver unhandled exception %s" % to_native(err))

return ret

0 comments on commit 2f0b6b6

Please sign in to comment.