From 5ad703ac64026f88a401880b52fb25dab49237bc Mon Sep 17 00:00:00 2001
From: n0p90 <36303164+n0p90@users.noreply.github.com>
Date: Tue, 17 Jan 2023 20:03:38 +0000
Subject: [PATCH] nsupdate: fix zone lookup (#5818)

The SOA record for an existing zone is returned as an answer RR and not
as an authority RR. It can be returned as an authority RR for subdomains
of a zone.

$ dig -t SOA example.com
;; ANSWER SECTION:
example.com.	3530	IN	SOA	ns.icann.org. noc.dns.icann.org. 2022091184 7200 3600 1209600 3600

$ dig -t SOA www.example.com
;; AUTHORITY SECTION:
example.com.	3600	IN	SOA	ns.icann.org. noc.dns.icann.org. 2022091184 7200 3600 1209600 3600
---
 .../fragments/5818-nsupdate-fix-zone-lookup.yml  |  2 ++
 plugins/modules/nsupdate.py                      | 16 ++++++++++------
 2 files changed, 12 insertions(+), 6 deletions(-)
 create mode 100644 changelogs/fragments/5818-nsupdate-fix-zone-lookup.yml

diff --git a/changelogs/fragments/5818-nsupdate-fix-zone-lookup.yml b/changelogs/fragments/5818-nsupdate-fix-zone-lookup.yml
new file mode 100644
index 0000000000..4f6ed6a125
--- /dev/null
+++ b/changelogs/fragments/5818-nsupdate-fix-zone-lookup.yml
@@ -0,0 +1,2 @@
+bugfixes:
+  - nsupdate - fix zone lookup. The SOA record for an existing zone is returned as an answer RR and not as an authority RR (https://github.com/ansible-collections/community.general/issues/5817, https://github.com/ansible-collections/community.general/pull/5818).
diff --git a/plugins/modules/nsupdate.py b/plugins/modules/nsupdate.py
index 2be4863b68..bc31521cdb 100644
--- a/plugins/modules/nsupdate.py
+++ b/plugins/modules/nsupdate.py
@@ -269,12 +269,16 @@ class RecordManager(object):
             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
+            # If the response contains an Answer SOA RR whose name matches the queried name,
+            # this is the name of the zone in which the record needs to be inserted.
+            for rr in lookup.answer:
+                if rr.rdtype == dns.rdatatype.SOA and rr.name == name:
+                    return rr.name.to_text()
+            # If the response contains an Authority SOA RR whose name is a subdomain of the queried name,
+            # this SOA name is the zone in which the record needs to be inserted.
+            for rr in lookup.authority:
+                if rr.rdtype == dns.rdatatype.SOA and name.fullcompare(rr.name)[0] == dns.name.NAMERELN_SUBDOMAIN:
+                    return rr.name.to_text()
             try:
                 name = name.parent()
             except dns.name.NoParent: