]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add new system test for wildcard expansion
authorPetr Špaček <pspacek@isc.org>
Mon, 21 Jun 2021 12:51:43 +0000 (14:51 +0200)
committerPetr Špaček <pspacek@isc.org>
Mon, 8 Nov 2021 12:23:05 +0000 (13:23 +0100)
This is almost minimal prototype to show how to use python-hypothesis
library in a system test. It does not fully replace existing shell-based
system test for wildcards.

bin/tests/system/.gitignore
bin/tests/system/wildcard/conftest.py [new file with mode: 0644]
bin/tests/system/wildcard/ns1/allwild.db.in [new file with mode: 0644]
bin/tests/system/wildcard/ns1/named.conf.in
bin/tests/system/wildcard/ns1/sign.sh
bin/tests/system/wildcard/tests-wildcard.py [new file with mode: 0755]
util/copyrights

index 525e889ba66b1bd36688fb4bb0643f212adb89aa..3cde7cdb6b9374276bc99642ceeda8972c7143f2 100644 (file)
@@ -1,4 +1,5 @@
 .cache
+.hypothesis
 __pycache__
 dig.out*
 rndc.out*
diff --git a/bin/tests/system/wildcard/conftest.py b/bin/tests/system/wildcard/conftest.py
new file mode 100644 (file)
index 0000000..9db7adc
--- /dev/null
@@ -0,0 +1,18 @@
+############################################################################
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# 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.
+############################################################################
+
+import os
+import pytest
+
+
+@pytest.fixture(scope='module')
+def named_port():
+    return int(os.environ.get("PORT", default=5300))
diff --git a/bin/tests/system/wildcard/ns1/allwild.db.in b/bin/tests/system/wildcard/ns1/allwild.db.in
new file mode 100644 (file)
index 0000000..43bb18f
--- /dev/null
@@ -0,0 +1,4 @@
+$ORIGIN allwild.test.
+allwild.test.                 3600 IN  SOA   . . 0 0 0 0 0
+allwild.test.                 3600     NS    ns.example.test.
+*.allwild.test.           3600     A     192.0.2.1
index 3135a5dc4f542b94b89b858fdfdfe5ad5f18f352..37f7968fe233b70bfa926f5aa92fc68b61a94258 100644 (file)
@@ -27,6 +27,7 @@ zone "." { type primary; file "root.db.signed"; };
 /*
  * RFC 4592 example zone.
  */
+zone "allwild.test" { type primary; file "allwild.db"; };
 zone "example" { type primary; file "example.db"; };
 zone "nsec" { type primary; file "nsec.db.signed"; };
 zone "private.nsec" { type primary; file "private.nsec.db.signed"; };
index 82666c610cfb57467304503bcd11bffed626b1f5..71e4c6af7cf932932e5e61f4017a784d7b379068 100755 (executable)
@@ -16,6 +16,7 @@ SYSTESTDIR=wildcard
 dssets=
 
 # RFC 4592 example zone.
+cp allwild.db.in allwild.db
 cp example.db.in example.db
 
 zone=nsec
diff --git a/bin/tests/system/wildcard/tests-wildcard.py b/bin/tests/system/wildcard/tests-wildcard.py
new file mode 100755 (executable)
index 0000000..29f8cbd
--- /dev/null
@@ -0,0 +1,103 @@
+#!/usr/bin/python3
+############################################################################
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# 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.
+############################################################################
+
+"""
+Example property-based test for wildcard synthesis.
+Verifies that otherwise-empty zone with single wildcard record * A 192.0.2.1
+produces synthesized answers for <random_label>.test. A, and returns NODATA for
+<random_label>.test. when rdtype is not A.
+
+Limitations - untested properties:
+    - expansion works with multiple labels
+    - asterisk in qname does not cause expansion
+    - empty non-terminals prevent expansion
+    - or more generally any existing node prevents expansion
+    - DNSSEC record inclusion
+    - possibly others, see RFC 4592 and company
+    - content of authority & additional sections
+    - flags beyond RCODE
+    - special behavior of rdtypes like CNAME
+"""
+import pytest
+
+pytest.importorskip("dns")
+import dns.message
+import dns.name
+import dns.query
+import dns.rcode
+import dns.rdatatype
+
+pytest.importorskip("hypothesis")
+from hypothesis import given
+from hypothesis.strategies import binary, integers
+
+
+# labels of a zone with * A 192.0.2.1 wildcard
+WILDCARD_ZONE = ('allwild', 'test', '')
+WILDCARD_RDTYPE = dns.rdatatype.A
+WILDCARD_RDATA = '192.0.2.1'
+IPADDR = '10.53.0.1'
+TIMEOUT = 5  # seconds, just a sanity check
+
+
+# Helpers
+def is_nonexpanding_rdtype(rdtype):
+    """skip meta types to avoid weird rcodes caused by AXFR etc.; RFC 6895"""
+    return not(rdtype == WILDCARD_RDTYPE
+               or dns.rdatatype.is_metatype(rdtype)  # known metatypes: OPT ...
+               or 128 <= rdtype <= 255)  # unknown meta types
+
+
+def tcp_query(where, port, qname, qtype):
+    querymsg = dns.message.make_query(qname, qtype)
+    assert len(querymsg.question) == 1
+    return querymsg, dns.query.tcp(querymsg, where, port=port, timeout=TIMEOUT)
+
+
+def query(where, port, label, rdtype):
+    labels = (label, ) + WILDCARD_ZONE
+    qname = dns.name.Name(labels)
+    return tcp_query(where, port, qname, rdtype)
+
+
+# Tests
+@given(label=binary(min_size=1, max_size=63),
+       rdtype=integers(min_value=0, max_value=65535).filter(
+           is_nonexpanding_rdtype))
+def test_wildcard_rdtype_mismatch(label, rdtype, named_port):
+    """any label non-matching rdtype must result in to NODATA"""
+    check_answer_nodata(*query(IPADDR, named_port, label, rdtype))
+
+
+def check_answer_nodata(querymsg, answer):
+    assert querymsg.is_response(answer), str(answer)
+    assert answer.rcode() == dns.rcode.NOERROR, str(answer)
+    assert answer.answer == [], str(answer)
+
+
+@given(label=binary(min_size=1, max_size=63))
+def test_wildcard_match(label, named_port):
+    """any label with maching rdtype must result in wildcard data in answer"""
+    check_answer_noerror(*query(IPADDR, named_port, label, WILDCARD_RDTYPE))
+
+
+def check_answer_noerror(querymsg, answer):
+    assert querymsg.is_response(answer), str(answer)
+    assert answer.rcode() == dns.rcode.NOERROR, str(answer)
+    assert len(querymsg.question) == 1, str(answer)
+    expected_answer = [dns.rrset.from_text(
+                            querymsg.question[0].name,
+                            300,  # TTL, ignored by dnspython comparison
+                            dns.rdataclass.IN,
+                            WILDCARD_RDTYPE,
+                            WILDCARD_RDATA)]
+    assert answer.answer == expected_answer, str(answer)
index 52a0e01dab4a0b77426916a5b7eda9618ab1984e..1d43fbd260df1d900cf36b604d218714de413fb2 100644 (file)
 ./bin/tests/system/views/setup.sh              SH      2000,2001,2004,2007,2012,2014,2016,2017,2018,2019,2020,2021
 ./bin/tests/system/views/tests.sh              SH      2000,2001,2004,2007,2012,2013,2014,2016,2018,2019,2020,2021
 ./bin/tests/system/wildcard/clean.sh           SH      2012,2013,2014,2016,2018,2019,2020,2021
+./bin/tests/system/wildcard/conftest.py                PYTHON  2021
 ./bin/tests/system/wildcard/ns1/sign.sh                SH      2012,2013,2014,2016,2018,2019,2020,2021
 ./bin/tests/system/wildcard/setup.sh           SH      2012,2014,2016,2017,2018,2019,2020,2021
+./bin/tests/system/wildcard/tests-wildcard.py  PYTHON-BIN      2021
 ./bin/tests/system/wildcard/tests.sh           SH      2012,2013,2016,2018,2019,2020,2021
 ./bin/tests/system/xfer/ans5/badkeydata                X       2011,2018,2019,2020,2021
 ./bin/tests/system/xfer/ans5/badmessageid      X       2020,2021