From 2a51b24cb74927b6ea38aeeabbf7c486e0da98cc Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Thu, 26 Jun 2025 15:19:45 -0700 Subject: [PATCH 1/6] add helper functions to isctest added some helper functions in isctest to reduce code repetition in dnssec-related tests: - isctest.check.adflag() - checks that a response contains AD=1 - isctest.check.noadflag() - checks that a response contains AD=0 - isctest.check.rdflag() - checks that a response contains RD=1 - isctest.check.nordflag() - checks that a response contains RD=0 - isctest.check.answer_count_eq() - checks the answer count is correct - isctest.check.additional_count_eq() - same for authority count - isctest.check.authority_count_eq() - same for additional count - isctest.check.same_data() - check that two message have the same rcode and data - isctest.check.same_answer() - check that two message have the same rcode and answer - isctest.dnssec.msg() - a wrapper for dns.message.make_query() that creates a query message similar to dig +dnssec: use_edns=True, want_dnssec=True, and flags are set to (RD|AD) by default, but options exist to disable AD or enable CD. (to generate non-DNSSEC queries, use message.make_query() directly.) (cherry picked from commit b69097f139154ca0d2177f35632400200d220bdc) --- bin/tests/system/isctest/__init__.py | 1 + bin/tests/system/isctest/check.py | 72 ++++++++++++++++++++++++++++ bin/tests/system/isctest/dnssec.py | 25 ++++++++++ bin/tests/system/isctest/instance.py | 4 +- 4 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 bin/tests/system/isctest/dnssec.py diff --git a/bin/tests/system/isctest/__init__.py b/bin/tests/system/isctest/__init__.py index 08428c9372..0da6b5bb51 100644 --- a/bin/tests/system/isctest/__init__.py +++ b/bin/tests/system/isctest/__init__.py @@ -10,6 +10,7 @@ # information regarding copyright ownership. from . import check +from . import dnssec from . import instance from . import query from . import name diff --git a/bin/tests/system/isctest/check.py b/bin/tests/system/isctest/check.py index afcc2db6ff..d8cff71ea4 100644 --- a/bin/tests/system/isctest/check.py +++ b/bin/tests/system/isctest/check.py @@ -12,6 +12,7 @@ import shutil from typing import Optional +import dns.flags import dns.rcode import dns.message import dns.zone @@ -40,6 +41,53 @@ def servfail(message: dns.message.Message) -> None: rcode(message, dns_rcode.SERVFAIL) +def adflag(message: dns.message.Message) -> None: + assert (message.flags & dns.flags.AD) != 0, str(message) + + +def noadflag(message: dns.message.Message) -> None: + assert (message.flags & dns.flags.AD) == 0, str(message) + + +def rdflag(message: dns.message.Message) -> None: + assert (message.flags & dns.flags.RD) != 0, str(message) + + +def nordflag(message: dns.message.Message) -> None: + assert (message.flags & dns.flags.RD) == 0, str(message) + + +def section_equal(sec1: list, sec2: list) -> None: + # convert an RRset to a normalized string (lower case, TTL=0) + # so it can be used as a set member. + def normalized(rrset): + ttl = rrset.ttl + rrset.ttl = 0 + s = str(rrset).lower() + rrset.ttl = ttl + return s + + # convert the section contents to sets before comparison, + # in case they aren't in the same sort order. + set1 = {normalized(item) for item in sec1} + set2 = {normalized(item) for item in sec2} + assert set1 == set2 + + +def same_data(res1: dns.message.Message, res2: dns.message.Message): + assert res1.question == res2.question + section_equal(res1.answer, res2.answer) + section_equal(res1.authority, res2.authority) + section_equal(res1.additional, res2.additional) + assert res1.rcode() == res2.rcode() + + +def same_answer(res1: dns.message.Message, res2: dns.message.Message): + assert res1.question == res2.question + section_equal(res1.answer, res2.answer) + assert res1.rcode() == res2.rcode() + + def rrsets_equal( first_rrset: dns.rrset.RRset, second_rrset: dns.rrset.RRset, @@ -114,6 +162,30 @@ def empty_answer(message: dns.message.Message) -> None: assert not message.answer, str(message) +def answer_count_eq(m: dns.message.Message, expected: int): + count = sum(max(1, len(rrs)) for rrs in m.answer) + assert count == expected, str(m) + + +def authority_count_eq(m: dns.message.Message, expected: int): + count = sum(max(1, len(rrs)) for rrs in m.authority) + assert count == expected, str(m) + + +def additional_count_eq(m: dns.message.Message, expected: int): + count = sum(max(1, len(rrs)) for rrs in m.additional) + + # add one for the OPT? + opt = bool(m.opt) if hasattr(m, "opt") else bool(m.edns >= 0) + count += 1 if opt else 0 + + # add one for the TSIG? + tsig = bool(m.tsig) if hasattr(m, "tsig") else m.had_tsig + count += 1 if tsig else 0 + + assert count == expected, str(m) + + def is_response_to(response: dns.message.Message, query: dns.message.Message) -> None: single_question(response) single_question(query) diff --git a/bin/tests/system/isctest/dnssec.py b/bin/tests/system/isctest/dnssec.py new file mode 100644 index 0000000000..209671150a --- /dev/null +++ b/bin/tests/system/isctest/dnssec.py @@ -0,0 +1,25 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +from dns import flags, message + + +def msg(qname: str, qtype: str, **kwargs): + headerflags = flags.RD + # "ad" is on by default + if "ad" not in kwargs or not kwargs["ad"]: + headerflags |= flags.AD + # "cd" is off by default + if "cd" in kwargs and kwargs["cd"]: + headerflags |= flags.CD + return message.make_query( + qname, qtype, use_edns=True, want_dnssec=True, flags=headerflags + ) diff --git a/bin/tests/system/isctest/instance.py b/bin/tests/system/isctest/instance.py index ea3a8fadfb..763a8dbb59 100644 --- a/bin/tests/system/isctest/instance.py +++ b/bin/tests/system/isctest/instance.py @@ -137,13 +137,13 @@ class NamedInstance: """ return WatchLogFromHere(self.log.path, timeout) - def reconfigure(self) -> None: + def reconfigure(self, **kwargs) -> None: """ Reconfigure this named `instance` and wait until reconfiguration is finished. Raise an `RNDCException` if reconfiguration fails. """ with self.watch_log_from_here() as watcher: - self.rndc("reconfig") + self.rndc("reconfig", **kwargs) watcher.wait_for_line("any newly configured zones are now loaded") def _rndc_log(self, command: str, response: str) -> None: From eeace11202bbec0c347d009fde70958c8eb7b79d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicki=20K=C5=99=C3=AD=C5=BEek?= Date: Thu, 10 Jul 2025 16:23:48 +0200 Subject: [PATCH 2/6] Refactor isctest.check.section_equal comparison Use the same logic as dnspython uses in dns.message.Message. (cherry picked from commit b24dd20e5a8efa2ba4c277e0c48fa08ebea96702) --- bin/tests/system/isctest/check.py | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/bin/tests/system/isctest/check.py b/bin/tests/system/isctest/check.py index d8cff71ea4..fb8aa98cdc 100644 --- a/bin/tests/system/isctest/check.py +++ b/bin/tests/system/isctest/check.py @@ -57,25 +57,19 @@ def nordflag(message: dns.message.Message) -> None: assert (message.flags & dns.flags.RD) == 0, str(message) -def section_equal(sec1: list, sec2: list) -> None: - # convert an RRset to a normalized string (lower case, TTL=0) - # so it can be used as a set member. - def normalized(rrset): - ttl = rrset.ttl - rrset.ttl = 0 - s = str(rrset).lower() - rrset.ttl = ttl - return s - - # convert the section contents to sets before comparison, - # in case they aren't in the same sort order. - set1 = {normalized(item) for item in sec1} - set2 = {normalized(item) for item in sec2} - assert set1 == set2 +def section_equal(first_section: list, second_section: list) -> None: + for rrset in first_section: + assert ( + rrset in second_section + ), f"No corresponding RRset found in second section: {rrset}" + for rrset in second_section: + assert ( + rrset in first_section + ), f"No corresponding RRset found in first section: {rrset}" def same_data(res1: dns.message.Message, res2: dns.message.Message): - assert res1.question == res2.question + section_equal(res1.question, res2.question) section_equal(res1.answer, res2.answer) section_equal(res1.authority, res2.authority) section_equal(res1.additional, res2.additional) @@ -83,7 +77,7 @@ def same_data(res1: dns.message.Message, res2: dns.message.Message): def same_answer(res1: dns.message.Message, res2: dns.message.Message): - assert res1.question == res2.question + section_equal(res1.question, res2.question) section_equal(res1.answer, res2.answer) assert res1.rcode() == res2.rcode() From c92a6b85fe5b60dce38338ec3b0568391b5cbe8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicki=20K=C5=99=C3=AD=C5=BEek?= Date: Fri, 25 Jul 2025 11:09:30 +0200 Subject: [PATCH 3/6] Unify RR counting in isctest.check helper Use a common function to count the number of RRs in any section of the DNS message. For the ADDITIONAL section, stick with the dnspython convention of not including OPT and TSIG. (cherry picked from commit efd60348b9280383fe5d50042a94ea363390356d) --- bin/tests/system/isctest/check.py | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/bin/tests/system/isctest/check.py b/bin/tests/system/isctest/check.py index fb8aa98cdc..7ba0767d13 100644 --- a/bin/tests/system/isctest/check.py +++ b/bin/tests/system/isctest/check.py @@ -156,28 +156,10 @@ def empty_answer(message: dns.message.Message) -> None: assert not message.answer, str(message) -def answer_count_eq(m: dns.message.Message, expected: int): - count = sum(max(1, len(rrs)) for rrs in m.answer) - assert count == expected, str(m) - - -def authority_count_eq(m: dns.message.Message, expected: int): - count = sum(max(1, len(rrs)) for rrs in m.authority) - assert count == expected, str(m) - - -def additional_count_eq(m: dns.message.Message, expected: int): - count = sum(max(1, len(rrs)) for rrs in m.additional) - - # add one for the OPT? - opt = bool(m.opt) if hasattr(m, "opt") else bool(m.edns >= 0) - count += 1 if opt else 0 - - # add one for the TSIG? - tsig = bool(m.tsig) if hasattr(m, "tsig") else m.had_tsig - count += 1 if tsig else 0 - - assert count == expected, str(m) +def rr_count_eq(section: list, expected: int): + # NOTE: OPT and TSIG records aren't included in the count for ADDITIONAL section + count = sum(len(rrset) for rrset in section) + assert count == expected, str(section) def is_response_to(response: dns.message.Message, query: dns.message.Message) -> None: From 01ec550099bf839a72e7b6057edc2b9ea3e79811 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 29 Jul 2025 16:03:55 -0700 Subject: [PATCH 4/6] Refactor and move query helper to isctest.query.create Make the query helper function more universal and reusable across our system tests -- default to using EDNS and sending AD=1. (cherry picked from commit 989e64b9b0e2a65b8b4b0f2bc75b1f2e2a327272) --- bin/tests/system/isctest/__init__.py | 1 - bin/tests/system/isctest/dnssec.py | 25 ------------------------- bin/tests/system/isctest/query.py | 20 ++++++++++++++++++++ 3 files changed, 20 insertions(+), 26 deletions(-) delete mode 100644 bin/tests/system/isctest/dnssec.py diff --git a/bin/tests/system/isctest/__init__.py b/bin/tests/system/isctest/__init__.py index 0da6b5bb51..08428c9372 100644 --- a/bin/tests/system/isctest/__init__.py +++ b/bin/tests/system/isctest/__init__.py @@ -10,7 +10,6 @@ # information regarding copyright ownership. from . import check -from . import dnssec from . import instance from . import query from . import name diff --git a/bin/tests/system/isctest/dnssec.py b/bin/tests/system/isctest/dnssec.py deleted file mode 100644 index 209671150a..0000000000 --- a/bin/tests/system/isctest/dnssec.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (C) Internet Systems Consortium, Inc. ("ISC") -# -# SPDX-License-Identifier: MPL-2.0 -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, you can obtain one at https://mozilla.org/MPL/2.0/. -# -# See the COPYRIGHT file distributed with this work for additional -# information regarding copyright ownership. - -from dns import flags, message - - -def msg(qname: str, qtype: str, **kwargs): - headerflags = flags.RD - # "ad" is on by default - if "ad" not in kwargs or not kwargs["ad"]: - headerflags |= flags.AD - # "cd" is off by default - if "cd" in kwargs and kwargs["cd"]: - headerflags |= flags.CD - return message.make_query( - qname, qtype, use_edns=True, want_dnssec=True, flags=headerflags - ) diff --git a/bin/tests/system/isctest/query.py b/bin/tests/system/isctest/query.py index 13e6eb61e9..b11b165f85 100644 --- a/bin/tests/system/isctest/query.py +++ b/bin/tests/system/isctest/query.py @@ -74,3 +74,23 @@ def udp(*args, **kwargs) -> Any: def tcp(*args, **kwargs) -> Any: return generic_query(dns.query.tcp, *args, **kwargs) + + +def create( + qname, + qtype, + qclass=dns.rdataclass.IN, + dnssec: bool = True, + cd: bool = False, + ad: bool = True, +) -> dns.message.Message: + """Create DNS query with defaults suitable for our tests.""" + msg = dns.message.make_query( + qname, qtype, qclass, use_edns=True, want_dnssec=dnssec + ) + msg.flags = dns.flags.RD + if ad: + msg.flags |= dns.flags.AD + if cd: + msg.flags |= dns.flags.CD + return msg From ad7414de43b28634bf951ee096382fd1276081ea Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 29 Jul 2025 16:04:02 -0700 Subject: [PATCH 5/6] Add RA flag checks to isctest.check (cherry picked from commit f2a4c5dcb0556e109f7e77807c98564450b4c22a) --- bin/tests/system/isctest/check.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bin/tests/system/isctest/check.py b/bin/tests/system/isctest/check.py index 7ba0767d13..7095dd9fca 100644 --- a/bin/tests/system/isctest/check.py +++ b/bin/tests/system/isctest/check.py @@ -57,6 +57,14 @@ def nordflag(message: dns.message.Message) -> None: assert (message.flags & dns.flags.RD) == 0, str(message) +def raflag(message: dns.message.Message) -> None: + assert (message.flags & dns.flags.RA) != 0, str(message) + + +def noraflag(message: dns.message.Message) -> None: + assert (message.flags & dns.flags.RA) == 0, str(message) + + def section_equal(first_section: list, second_section: list) -> None: for rrset in first_section: assert ( From 2588b2a23c4ee74c9e26cc103049530ee9f08ddb Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 29 Jul 2025 16:08:44 -0700 Subject: [PATCH 6/6] Use isctest.query.create across system tests Rather than using the dnspython's facilities and defaults to create the queries, use the isctest.query.create function in all the cases that don't require special handling to have consistent defaults. (cherry picked from commit 64143ea077c3ddb48f808af2d0b05e21209cd268) --- bin/tests/system/checkds/tests_checkds.py | 2 +- bin/tests/system/database/tests_database.py | 6 +++--- bin/tests/system/dnstap/tests_dnstap.py | 5 ++--- bin/tests/system/doth/tests_gnutls.py | 5 +++-- bin/tests/system/dsdigest/tests_dsdigest.py | 8 ++++---- bin/tests/system/emptyzones/tests_emptyzones.py | 6 ++---- bin/tests/system/glue/tests_glue.py | 5 +++-- bin/tests/system/hooks/tests_async_plugin.py | 6 +----- .../tests_include_multiplecfg.py | 6 +++--- bin/tests/system/isctest/check.py | 12 +++++++++++- bin/tests/system/limits/tests_limits.py | 7 +++---- bin/tests/system/masterfile/tests_masterfile.py | 10 +++++----- bin/tests/system/names/tests_names.py | 4 +--- bin/tests/system/rndc/tests_cve-2023-3341.py | 5 ++--- bin/tests/system/rpzextra/tests_rpzextra.py | 13 ++++++++----- bin/tests/system/shutdown/tests_shutdown.py | 2 +- bin/tests/system/tsiggss/tests_isc_spnego_flaws.py | 2 +- bin/tests/system/ttl/tests_cache_ttl.py | 5 +---- bin/tests/system/wildcard/tests_wildcard.py | 10 +++++----- bin/tests/system/xferquota/tests_xferquota.py | 4 ++-- 20 files changed, 62 insertions(+), 61 deletions(-) diff --git a/bin/tests/system/checkds/tests_checkds.py b/bin/tests/system/checkds/tests_checkds.py index 95ddce957f..d946634913 100755 --- a/bin/tests/system/checkds/tests_checkds.py +++ b/bin/tests/system/checkds/tests_checkds.py @@ -79,7 +79,7 @@ def has_signed_apex_nsec(zone, response): def do_query(server, qname, qtype, tcp=False): - msg = dns.message.make_query(qname, qtype, use_edns=True, want_dnssec=True) + msg = isctest.query.create(qname, qtype) query_func = isctest.query.tcp if tcp else isctest.query.udp response = query_func(msg, server.ip, expected_rcode=dns.rcode.NOERROR) return response diff --git a/bin/tests/system/database/tests_database.py b/bin/tests/system/database/tests_database.py index 476b81da95..5695bf011a 100644 --- a/bin/tests/system/database/tests_database.py +++ b/bin/tests/system/database/tests_database.py @@ -9,13 +9,13 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. -import isctest +import dns -import dns.message +import isctest def test_database(servers, templates): - msg = dns.message.make_query("database.", "SOA") + msg = isctest.query.create("database.", "SOA") # checking pre reload zone res = isctest.query.tcp(msg, "10.53.0.1") diff --git a/bin/tests/system/dnstap/tests_dnstap.py b/bin/tests/system/dnstap/tests_dnstap.py index 6326ef06f8..9dec5ddcc1 100644 --- a/bin/tests/system/dnstap/tests_dnstap.py +++ b/bin/tests/system/dnstap/tests_dnstap.py @@ -18,9 +18,8 @@ import subprocess import isctest import pytest -import dns.message - pytest.importorskip("dns", minversion="2.0.0") +import dns.rrset pytestmark = pytest.mark.extra_artifacts( [ @@ -46,7 +45,7 @@ def run_rndc(server, rndc_command): def test_dnstap_dispatch_socket_addresses(): # Send some query to ns3 so that it records something in its dnstap file. - msg = dns.message.make_query("mail.example.", "A") + msg = isctest.query.create("mail.example.", "A") res = isctest.query.tcp(msg, "10.53.0.2", expected_rcode=dns.rcode.NOERROR) assert res.answer == [ dns.rrset.from_text("mail.example.", 300, "IN", "A", "10.0.0.2") diff --git a/bin/tests/system/doth/tests_gnutls.py b/bin/tests/system/doth/tests_gnutls.py index f49b4401c5..9c897714ef 100644 --- a/bin/tests/system/doth/tests_gnutls.py +++ b/bin/tests/system/doth/tests_gnutls.py @@ -20,11 +20,12 @@ import pytest pytest.importorskip("dns") import dns.exception -import dns.message import dns.name import dns.rdataclass import dns.rdatatype +import isctest + pytestmark = pytest.mark.extra_artifacts( [ "gnutls-cli.*", @@ -35,7 +36,7 @@ pytestmark = pytest.mark.extra_artifacts( def test_gnutls_cli_query(gnutls_cli_executable, named_tlsport): # Prepare the example/SOA query which will be sent over TLS. - query = dns.message.make_query("example.", dns.rdatatype.SOA) + query = isctest.query.create("example.", dns.rdatatype.SOA) query_wire = query.to_wire() query_with_length = struct.pack(">H", len(query_wire)) + query_wire diff --git a/bin/tests/system/dsdigest/tests_dsdigest.py b/bin/tests/system/dsdigest/tests_dsdigest.py index f741a21147..ccf1431e23 100644 --- a/bin/tests/system/dsdigest/tests_dsdigest.py +++ b/bin/tests/system/dsdigest/tests_dsdigest.py @@ -9,7 +9,7 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. -import dns.message +import dns.flags import pytest import isctest @@ -29,7 +29,7 @@ pytestmark = pytest.mark.extra_artifacts( def test_dsdigest_good(): """Check that validation with enabled digest types works""" - msg = dns.message.make_query("a.good.", "A", want_dnssec=True) + msg = isctest.query.create("a.good.", "A") res = isctest.query.tcp( msg, "10.53.0.3", @@ -51,7 +51,7 @@ def test_dsdigest_bad(): def test_dsdigest_insecure(): """Check that validation with not supported digest algorithms is insecure""" - msg_ds = dns.message.make_query("bad.", "DS", want_dnssec=True) + msg_ds = isctest.query.create("bad.", "DS") res_ds = isctest.query.tcp( msg_ds, "10.53.0.4", @@ -59,7 +59,7 @@ def test_dsdigest_insecure(): isctest.check.noerror(res_ds) assert res_ds.flags & dns.flags.AD - msg_a = dns.message.make_query("a.bad.", "A", want_dnssec=True) + msg_a = isctest.query.create("a.bad.", "A") res_a = isctest.query.tcp( msg_a, "10.53.0.4", diff --git a/bin/tests/system/emptyzones/tests_emptyzones.py b/bin/tests/system/emptyzones/tests_emptyzones.py index 7a8d3966bd..6c2fa56ed5 100644 --- a/bin/tests/system/emptyzones/tests_emptyzones.py +++ b/bin/tests/system/emptyzones/tests_emptyzones.py @@ -9,8 +9,6 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. -import dns.message - import isctest @@ -20,11 +18,11 @@ def test_emptyzones(servers, templates): ns1.rndc("reload") templates.render("ns1/named.conf", {"automatic_empty_zones": True}) ns1.rndc("reload") - msg = dns.message.make_query("version.bind", "TXT", "CH") + msg = isctest.query.create("version.bind", "TXT", "CH") res = isctest.query.tcp(msg, "10.53.0.1") isctest.check.noerror(res) # check that allow-transfer { none; } works - msg = dns.message.make_query("10.in-addr.arpa", "AXFR") + msg = isctest.query.create("10.in-addr.arpa", "AXFR") res = isctest.query.tcp(msg, "10.53.0.1") isctest.check.refused(res) diff --git a/bin/tests/system/glue/tests_glue.py b/bin/tests/system/glue/tests_glue.py index 77dff57158..faf251367d 100644 --- a/bin/tests/system/glue/tests_glue.py +++ b/bin/tests/system/glue/tests_glue.py @@ -10,6 +10,7 @@ # information regarding copyright ownership. +import dns.flags import dns.message import pytest @@ -20,7 +21,7 @@ pytest.importorskip("dns", minversion="2.0.0") def test_glue_full_glue_set(): """test that a ccTLD referral gets a full glue set from the root zone""" - msg = dns.message.make_query("foo.bar.fi", "A") + msg = isctest.query.create("foo.bar.fi", "A") msg.flags &= ~dns.flags.RD res = isctest.query.udp(msg, "10.53.0.1") @@ -51,7 +52,7 @@ NS.UU.NET. 172800 IN A 137.39.1.3 def test_glue_no_glue_set(): """test that out-of-zone glue is not found""" - msg = dns.message.make_query("example.net.", "A") + msg = isctest.query.create("example.net.", "A") msg.flags &= ~dns.flags.RD res = isctest.query.udp(msg, "10.53.0.1") diff --git a/bin/tests/system/hooks/tests_async_plugin.py b/bin/tests/system/hooks/tests_async_plugin.py index ac89c85ac0..cb70c5c78c 100644 --- a/bin/tests/system/hooks/tests_async_plugin.py +++ b/bin/tests/system/hooks/tests_async_plugin.py @@ -9,15 +9,11 @@ # See the COPYRIGHT file distributed with this work for additional # information regarding copyright ownership. -import pytest import isctest -pytest.importorskip("dns") -import dns.message - def test_async_hook(): - msg = dns.message.make_query("example.com.", "A") + msg = isctest.query.create("example.com.", "A") res = isctest.query.udp(msg, "10.53.0.1") # the test-async plugin changes the status of any positive answer to NOTIMP isctest.check.notimp(res) diff --git a/bin/tests/system/include-multiplecfg/tests_include_multiplecfg.py b/bin/tests/system/include-multiplecfg/tests_include_multiplecfg.py index 346f33453e..dffc917c9d 100644 --- a/bin/tests/system/include-multiplecfg/tests_include_multiplecfg.py +++ b/bin/tests/system/include-multiplecfg/tests_include_multiplecfg.py @@ -11,10 +11,10 @@ import os -import isctest +import dns.rrset import pytest -import dns.message +import isctest @pytest.mark.parametrize( @@ -26,7 +26,7 @@ import dns.message ], ) def test_include_multiplecfg(qname): - msg = dns.message.make_query(qname, "A") + msg = isctest.query.create(qname, "A") res = isctest.query.tcp(msg, "10.53.0.2") isctest.check.noerror(res) diff --git a/bin/tests/system/isctest/check.py b/bin/tests/system/isctest/check.py index 7095dd9fca..e173ed4ca0 100644 --- a/bin/tests/system/isctest/check.py +++ b/bin/tests/system/isctest/check.py @@ -13,8 +13,8 @@ import shutil from typing import Optional import dns.flags -import dns.rcode import dns.message +import dns.rcode import dns.zone import isctest.log @@ -152,6 +152,16 @@ def is_executable(cmd: str, errmsg: str) -> None: assert executable is not None, errmsg +def named_alive(named_proc, resolver_ip): + assert named_proc.poll() is None, "named isn't running" + msg = isctest.query.create("version.bind", "TXT", "CH") + isctest.query.tcp(msg, resolver_ip, expected_rcode=dns_rcode.NOERROR) + + +def notauth(message: dns.message.Message) -> None: + rcode(message, dns.rcode.NOTAUTH) + + def nxdomain(message: dns.message.Message) -> None: rcode(message, dns.rcode.NXDOMAIN) diff --git a/bin/tests/system/limits/tests_limits.py b/bin/tests/system/limits/tests_limits.py index 1fe5ea0087..ca7214a9de 100644 --- a/bin/tests/system/limits/tests_limits.py +++ b/bin/tests/system/limits/tests_limits.py @@ -14,11 +14,10 @@ import itertools import isctest import pytest -import dns.message - # Everything from getting a big answer to creating an RR set with thousands # of records takes minutes of CPU and real time with dnspython < 2.0.0. pytest.importorskip("dns", minversion="2.0.0") +import dns.rrset @pytest.mark.parametrize( @@ -32,7 +31,7 @@ pytest.importorskip("dns", minversion="2.0.0") ], ) def test_limits(name, limit): - msg_query = dns.message.make_query(f"{name}.example.", "A") + msg_query = isctest.query.create(f"{name}.example.", "A") res = isctest.query.tcp(msg_query, "10.53.0.1", log_response=False) iplist = [ @@ -46,7 +45,7 @@ def test_limits(name, limit): def test_limit_exceeded(): - msg_query = dns.message.make_query("5000.example.", "A") + msg_query = isctest.query.create("5000.example.", "A") res = isctest.query.tcp(msg_query, "10.53.0.1", log_response=False) assert res.flags & dns.flags.TC, "TC flag was not set" diff --git a/bin/tests/system/masterfile/tests_masterfile.py b/bin/tests/system/masterfile/tests_masterfile.py index 9aaaa769a5..5d7baf58b3 100644 --- a/bin/tests/system/masterfile/tests_masterfile.py +++ b/bin/tests/system/masterfile/tests_masterfile.py @@ -19,7 +19,7 @@ import isctest def test_masterfile_include_semantics(): """Test master file $INCLUDE semantics""" - msg_axfr = dns.message.make_query("include.", "AXFR") + msg_axfr = isctest.query.create("include.", "AXFR") res_axfr = isctest.query.tcp(msg_axfr, "10.53.0.1") axfr_include_semantics = """;ANSWER include. 300 IN SOA ns.include. hostmaster.include. 1 3600 1800 1814400 3600 @@ -40,7 +40,7 @@ ns.include. 300 IN A 127.0.0.1 def test_masterfile_bind_8_compat_semantics(): """Test master file BIND 8 TTL and $TTL semantics compatibility""" - msg_axfr = dns.message.make_query("ttl1.", "AXFR") + msg_axfr = isctest.query.create("ttl1.", "AXFR") res_axfr = isctest.query.tcp(msg_axfr, "10.53.0.1") axfr_ttl_semantics = """;ANSWER ttl1. 3 IN SOA ns.ttl1. hostmaster.ttl1. 1 3600 1800 1814400 3 @@ -59,7 +59,7 @@ ns.ttl1. 3 IN A 10.53.0.1 def test_masterfile_rfc_1035_semantics(): """Test master file RFC1035 TTL and $TTL semantics""" - msg_axfr = dns.message.make_query("ttl2.", "AXFR") + msg_axfr = isctest.query.create("ttl2.", "AXFR") res_axfr = isctest.query.tcp(msg_axfr, "10.53.0.1") axfr_ttl_semantics = """;ANSWER ttl2. 1 IN SOA ns.ttl2. hostmaster.ttl2. 1 3600 1800 1814400 3 @@ -78,7 +78,7 @@ ns.ttl2. 1 IN A 10.53.0.1 def test_masterfile_missing_master_file(): """Test nameserver running with a missing master file""" - msg_soa = dns.message.make_query("example.", "SOA") + msg_soa = isctest.query.create("example.", "SOA") res_soa = isctest.query.tcp(msg_soa, "10.53.0.2") expected_soa_rr = """;ANSWER example. 300 IN SOA mname1. . 2010042407 20 20 1814400 3600 @@ -89,7 +89,7 @@ example. 300 IN SOA mname1. . 2010042407 20 20 1814400 3600 def test_masterfile_missing_master_file_servfail(): """Test nameserver returning SERVFAIL for a missing master file""" - msg_soa = dns.message.make_query("missing.", "SOA") + msg_soa = isctest.query.create("missing.", "SOA") res_soa = isctest.query.tcp(msg_soa, "10.53.0.2") isctest.check.servfail(res_soa) diff --git a/bin/tests/system/names/tests_names.py b/bin/tests/system/names/tests_names.py index e4fc296277..b72fcbec98 100644 --- a/bin/tests/system/names/tests_names.py +++ b/bin/tests/system/names/tests_names.py @@ -13,8 +13,6 @@ import pytest pytest.importorskip("dns", minversion="2.7.0") - -import dns.message import isctest @@ -22,7 +20,7 @@ import isctest # about twice as large as the answer with compression enabled, while # maintaining identical content. def test_names(): - msg = dns.message.make_query("example.", "MX") + msg = isctest.query.create("example.", "MX") # Getting message size with compression enabled res_enabled = isctest.query.tcp(msg, ip="10.53.0.1", source="10.53.0.1") # Getting message size with compression disabled diff --git a/bin/tests/system/rndc/tests_cve-2023-3341.py b/bin/tests/system/rndc/tests_cve-2023-3341.py index c195a0db10..73a5117e9f 100644 --- a/bin/tests/system/rndc/tests_cve-2023-3341.py +++ b/bin/tests/system/rndc/tests_cve-2023-3341.py @@ -15,10 +15,9 @@ import socket import time import pytest + import isctest -pytest.importorskip("dns") -import dns.message pytestmark = pytest.mark.extra_artifacts( [ @@ -66,6 +65,6 @@ def test_cve_2023_3341(control_port): # Wait for named to (possibly) crash time.sleep(10) - msg = dns.message.make_query("version.bind", "TXT", "CH") + msg = isctest.query.create("version.bind", "TXT", "CH") res = isctest.query.udp(msg, "10.53.0.2") isctest.check.noerror(res) diff --git a/bin/tests/system/rpzextra/tests_rpzextra.py b/bin/tests/system/rpzextra/tests_rpzextra.py index 359b7aab43..e918fa832e 100644 --- a/bin/tests/system/rpzextra/tests_rpzextra.py +++ b/bin/tests/system/rpzextra/tests_rpzextra.py @@ -12,13 +12,16 @@ # information regarding copyright ownership. import os + import pytest pytest.importorskip("dns", minversion="2.0.0") +import dns.rcode +import dns.rrset + import isctest from isctest.compat import dns_rcode -import dns.message pytestmark = pytest.mark.extra_artifacts( [ @@ -70,7 +73,7 @@ pytestmark = pytest.mark.extra_artifacts( ) def test_rpz_multiple_views(qname, source, rcode): # Wait for the rpz-external.local zone transfer - msg = dns.message.make_query("rpz-external.local", "SOA") + msg = isctest.query.create("rpz-external.local", "SOA") isctest.query.tcp( msg, ip="10.53.0.3", @@ -84,7 +87,7 @@ def test_rpz_multiple_views(qname, source, rcode): expected_rcode=dns_rcode.NOERROR, ) - msg = dns.message.make_query(qname, "A") + msg = isctest.query.create(qname, "A") res = isctest.query.udp(msg, "10.53.0.3", source=source, expected_rcode=rcode) if rcode == dns.rcode.NOERROR: assert res.answer == [dns.rrset.from_text(qname, 300, "IN", "A", "10.53.0.2")] @@ -94,7 +97,7 @@ def test_rpz_passthru_logging(): resolver_ip = "10.53.0.3" # Should generate a log entry into rpz_passthru.txt - msg_allowed = dns.message.make_query("allowed.", "A") + msg_allowed = isctest.query.create("allowed.", "A") res_allowed = isctest.query.udp( msg_allowed, resolver_ip, source="10.53.0.1", expected_rcode=dns.rcode.NOERROR ) @@ -104,7 +107,7 @@ def test_rpz_passthru_logging(): # baddomain.com isn't allowed (CNAME .), should return NXDOMAIN # Should generate a log entry into rpz.txt - msg_not_allowed = dns.message.make_query("baddomain.", "A") + msg_not_allowed = isctest.query.create("baddomain.", "A") res_not_allowed = isctest.query.udp( msg_not_allowed, resolver_ip, diff --git a/bin/tests/system/shutdown/tests_shutdown.py b/bin/tests/system/shutdown/tests_shutdown.py index d9c7e67f61..3d0c410ee0 100755 --- a/bin/tests/system/shutdown/tests_shutdown.py +++ b/bin/tests/system/shutdown/tests_shutdown.py @@ -105,7 +105,7 @@ def do_work(named_proc, resolver_ip, instance, kill_method, n_workers, n_queries ) qname = relname + ".test" - msg = dns.message.make_query(qname, "A") + msg = isctest.query.create(qname, "A") futures[ executor.submit( isctest.query.udp, msg, resolver_ip, timeout=1, attempts=1 diff --git a/bin/tests/system/tsiggss/tests_isc_spnego_flaws.py b/bin/tests/system/tsiggss/tests_isc_spnego_flaws.py index 4c32557e89..38b424d4c5 100755 --- a/bin/tests/system/tsiggss/tests_isc_spnego_flaws.py +++ b/bin/tests/system/tsiggss/tests_isc_spnego_flaws.py @@ -56,7 +56,7 @@ class CraftedTKEYQuery: rrset = dns.rrset.from_rdata(dns.name.root, dns.rdatatype.TKEY, rdata) # Prepare complete TKEY query to send - self.msg = dns.message.make_query( + self.msg = isctest.query.create( dns.name.root, dns.rdatatype.TKEY, dns.rdataclass.ANY ) self.msg.additional.append(rrset) diff --git a/bin/tests/system/ttl/tests_cache_ttl.py b/bin/tests/system/ttl/tests_cache_ttl.py index 631c907c7e..3e7f91549e 100644 --- a/bin/tests/system/ttl/tests_cache_ttl.py +++ b/bin/tests/system/ttl/tests_cache_ttl.py @@ -13,9 +13,6 @@ import pytest import isctest -pytest.importorskip("dns") -import dns.message - @pytest.mark.parametrize( "qname,rdtype,expected_ttl", @@ -27,7 +24,7 @@ import dns.message ], ) def test_cache_ttl(qname, rdtype, expected_ttl): - msg = dns.message.make_query(qname, rdtype) + msg = isctest.query.create(qname, rdtype) response = isctest.query.udp(msg, "10.53.0.2") for rr in response.answer + response.authority: assert rr.ttl == expected_ttl diff --git a/bin/tests/system/wildcard/tests_wildcard.py b/bin/tests/system/wildcard/tests_wildcard.py index cad2eb0757..459e3397b3 100755 --- a/bin/tests/system/wildcard/tests_wildcard.py +++ b/bin/tests/system/wildcard/tests_wildcard.py @@ -94,7 +94,7 @@ def test_wildcard_rdtype_mismatch( # See RFC 4592 section 2.2.1. assume(name == SUFFIX or name.labels[-len(SUFFIX) - 1] != b"*") - query_msg = dns.message.make_query(name, rdtype) + query_msg = isctest.query.create(name, rdtype) response_msg = isctest.query.tcp(query_msg, IP_ADDR, named_port, timeout=TIMEOUT) isctest.check.is_response_to(response_msg, query_msg) @@ -111,7 +111,7 @@ def test_wildcard_match(name: dns.name.Name, named_port: int) -> None: # See RFC 4592 section 2.2.1. assume(name.labels[-len(SUFFIX) - 1] != b"*") - query_msg = dns.message.make_query(name, WILDCARD_RDTYPE) + query_msg = isctest.query.create(name, WILDCARD_RDTYPE) response_msg = isctest.query.tcp(query_msg, IP_ADDR, named_port, timeout=TIMEOUT) isctest.check.is_response_to(response_msg, query_msg) @@ -140,7 +140,7 @@ def test_wildcard_with_star_not_synthesized( name: dns.name.Name, named_port: int ) -> None: """RFC 4592 section 2.2.1 ghost.*.example.""" - query_msg = dns.message.make_query(name, WILDCARD_RDTYPE) + query_msg = isctest.query.create(name, WILDCARD_RDTYPE) response_msg = isctest.query.tcp(query_msg, IP_ADDR, named_port, timeout=TIMEOUT) isctest.check.is_response_to(response_msg, query_msg) @@ -170,7 +170,7 @@ def test_name_in_between_wildcards(name: dns.name.Name, named_port: int) -> None or name.labels[-len(NESTED_SUFFIX) - 1] != b"*" ) - query_msg = dns.message.make_query(name, WILDCARD_RDTYPE) + query_msg = isctest.query.create(name, WILDCARD_RDTYPE) response_msg = isctest.query.tcp(query_msg, IP_ADDR, named_port, timeout=TIMEOUT) isctest.check.is_response_to(response_msg, query_msg) @@ -201,7 +201,7 @@ def test_name_nested_wildcard_subdomains_not_synthesized( `foo.*.*.*.nestedwild.test. A` must not be synthesized. """ - query_msg = dns.message.make_query(name, WILDCARD_RDTYPE) + query_msg = isctest.query.create(name, WILDCARD_RDTYPE) response_msg = isctest.query.tcp(query_msg, IP_ADDR, named_port, timeout=TIMEOUT) isctest.check.is_response_to(response_msg, query_msg) diff --git a/bin/tests/system/xferquota/tests_xferquota.py b/bin/tests/system/xferquota/tests_xferquota.py index c31700e4a2..1cb169156e 100644 --- a/bin/tests/system/xferquota/tests_xferquota.py +++ b/bin/tests/system/xferquota/tests_xferquota.py @@ -60,8 +60,8 @@ def test_xferquota(named_port, servers): isctest.run.retry_with_timeout(check_line_count, timeout=360) - axfr_msg = dns.message.make_query("zone000099.example.", "AXFR") - a_msg = dns.message.make_query("a.changing.", "A") + axfr_msg = isctest.query.create("zone000099.example.", "AXFR") + a_msg = isctest.query.create("a.changing.", "A") def query_and_compare(msg): ns1response = isctest.query.tcp(msg, "10.53.0.1")