fix(dns): query correct NS if MNAME server is hidden

replaces #870
fix #851
This commit is contained in:
missytake
2026-05-07 14:18:02 +02:00
committed by holger krekel
parent 129b8a20bc
commit c3e65147ba
2 changed files with 39 additions and 8 deletions

View File

@@ -64,18 +64,22 @@ def get_dkim_entry(mail_domain, pre_command, dkim_selector):
) )
def query_dns(typ, domain): def get_authoritative_ns(domain):
# Get autoritative nameserver from the SOA record. """Get autoritative nameserver from the SOA record."""
soa_answers = [ ns_replies = [
x.split() x.split()
for x in shell( for x in shell(
f"dig -r -q {domain} -t SOA +noall +authority +answer", print=log_progress f"dig -r -q {domain} -t NS +noall +authority +answer", print=log_progress
).split("\n") ).split("\n")
] ]
soa = [a for a in soa_answers if len(a) >= 3 and a[3] == "SOA"] filtered_replies = [a for a in ns_replies if len(a) >= 3 and a[3] in ("SOA", "NS")]
if not soa: if not filtered_replies:
return return
ns = soa[0][4] return filtered_replies[0][4]
def query_dns(typ, domain):
ns = get_authoritative_ns(domain)
# Query authoritative nameserver directly to bypass DNS cache. # Query authoritative nameserver directly to bypass DNS cache.
res = shell(f"dig @{ns} -r -q {domain} -t {typ} +short", print=log_progress) res = shell(f"dig @{ns} -r -q {domain} -t {typ} +short", print=log_progress)

View File

@@ -4,6 +4,7 @@ import pytest
from cmdeploy import remote from cmdeploy import remote
from cmdeploy.dns import check_full_zone, check_initial_remote_data, parse_zone_records from cmdeploy.dns import check_full_zone, check_initial_remote_data, parse_zone_records
from cmdeploy.remote.rdns import get_authoritative_ns
@pytest.fixture @pytest.fixture
@@ -14,7 +15,22 @@ def mockdns_base(monkeypatch):
if command.startswith("dig"): if command.startswith("dig"):
if command == "dig": if command == "dig":
return "." return "."
if "SOA" in command: if "with.public.soa" in command:
return (
"domain.with.public.soa. 2419 IN SOA ns1.first-ns.de. dns.hetzner.com."
" 2026050300 7200 1800 604800 3600"
)
if "with.hidden.soa" in command and "SOA" in command:
return (
"domain.with.hidden.soa. 300 IN SOA get.desec.io. get.desec.io."
" 2026025451 86400 3600 2419200 3600"
)
if "with.hidden.soa" in command and "NS" in command:
return (
"domain.with.hidden.soa. 2137 IN NS ns1.desec.io.\n"
"domain.with.hidden.soa. 2137 IN NS ns2.desec.org."
)
if "NS" in command:
return ( return (
"delta.chat. 21600 IN SOA ns1.first-ns.de. dns.hetzner.com." "delta.chat. 21600 IN SOA ns1.first-ns.de. dns.hetzner.com."
" 2025102800 14400 1800 604800 3600" " 2025102800 14400 1800 604800 3600"
@@ -125,6 +141,17 @@ class TestPerformInitialChecks:
assert not l assert not l
@pytest.mark.parametrize(
("domain", "ns"),
[
("domain.with.public.soa", "ns1.first-ns.de."),
("domain.with.hidden.soa", "ns1.desec.io.")
]
)
def test_get_authoritative_ns(domain, ns, mockdns):
assert get_authoritative_ns(domain) == ns
def test_parse_zone_records(): def test_parse_zone_records():
text = """ text = """
; This is a comment ; This is a comment