]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
add synthesized record system tests
authorColin Vidal <colin@isc.org>
Mon, 31 Mar 2025 14:00:32 +0000 (16:00 +0200)
committerColin Vidal <colin@isc.org>
Wed, 1 Oct 2025 10:16:05 +0000 (12:16 +0200)
Add system tests for the dynamically synthesized record plugin. This
covers the various cases the plugin should handle: generating a PTR
record only when (1) no answer is found locally and (2) the IP address
extracted from the query name is part of an allowed network. This also
covered the cases of forward synthesized records; answering a A/AAAA/ANY
query from a PTR address when this match the prefix, ACL and origin.

32 files changed:
bin/tests/system/synthrecord/.gitignore [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-forward-missing-origin.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-lib-path.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-multi-label-prefix.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-neg-ttl.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-no-mode.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-no-origin.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-no-prefix.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-origin-name.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-origin-no-absolute.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-origin-type.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-prefix-type.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-tsig.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-unknown-mode.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-wrong-mode.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/bad-wrong-ttl-type.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/good-no-allow-synth.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/good-no-ttl.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/good1.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/good2.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/conf/good3.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/ns1/0.0.0.0.ip6.arpa.db [new file with mode: 0644]
bin/tests/system/synthrecord/ns1/0.16.172.in-addr.arpa.db [new file with mode: 0644]
bin/tests/system/synthrecord/ns1/0.53.10.in-addr.arpa.db [new file with mode: 0644]
bin/tests/system/synthrecord/ns1/1.53.10.in-addr.arpa.db [new file with mode: 0644]
bin/tests/system/synthrecord/ns1/168.192.in-addr.arpa.db [new file with mode: 0644]
bin/tests/system/synthrecord/ns1/e.f.a.c.e.f.a.c.ip6.arpa.db [new file with mode: 0644]
bin/tests/system/synthrecord/ns1/example.db [new file with mode: 0644]
bin/tests/system/synthrecord/ns1/f.f.f.f.ip6.arpa.db [new file with mode: 0644]
bin/tests/system/synthrecord/ns1/named.conf.j2 [new file with mode: 0644]
bin/tests/system/synthrecord/ns1/root.db [new file with mode: 0644]
bin/tests/system/synthrecord/tests_synthrecord.py [new file with mode: 0644]

diff --git a/bin/tests/system/synthrecord/.gitignore b/bin/tests/system/synthrecord/.gitignore
new file mode 100644 (file)
index 0000000..75f7b7c
--- /dev/null
@@ -0,0 +1,3 @@
+named.conf
+named.memstats
+named.run
diff --git a/bin/tests/system/synthrecord/conf/bad-forward-missing-origin.conf.j2 b/bin/tests/system/synthrecord/conf/bad-forward-missing-origin.conf.j2
new file mode 100644 (file)
index 0000000..685a843
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix "dynamic-";
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       ttl 60;
+       mode forward;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-lib-path.conf.j2 b/bin/tests/system/synthrecord/conf/bad-lib-path.conf.j2
new file mode 100644 (file)
index 0000000..e216496
--- /dev/null
@@ -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.
+ */
+
+plugin query "../../../plugins/.libs/synthrecordwrong.so" {
+       prefix "dynamic-";
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin example.;
+       ttl 60;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-multi-label-prefix.conf.j2 b/bin/tests/system/synthrecord/conf/bad-multi-label-prefix.conf.j2
new file mode 100644 (file)
index 0000000..6ee9ce2
--- /dev/null
@@ -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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix "dynam.ic-";
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin example.;
+       ttl 60;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-neg-ttl.conf.j2 b/bin/tests/system/synthrecord/conf/bad-neg-ttl.conf.j2
new file mode 100644 (file)
index 0000000..6756d06
--- /dev/null
@@ -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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix "dynamic-";
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin example.;
+       ttl -60;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-no-mode.conf.j2 b/bin/tests/system/synthrecord/conf/bad-no-mode.conf.j2
new file mode 100644 (file)
index 0000000..2e9157d
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix "dynamic-";
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin example.;
+       ttl 60;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-no-origin.conf.j2 b/bin/tests/system/synthrecord/conf/bad-no-origin.conf.j2
new file mode 100644 (file)
index 0000000..d8225d9
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix dynamic-;
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       ttl 60;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-no-prefix.conf.j2 b/bin/tests/system/synthrecord/conf/bad-no-prefix.conf.j2
new file mode 100644 (file)
index 0000000..63ca413
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin "example.";
+       ttl 60;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-origin-name.conf.j2 b/bin/tests/system/synthrecord/conf/bad-origin-name.conf.j2
new file mode 100644 (file)
index 0000000..47392f5
--- /dev/null
@@ -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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix dynamic-;
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin _e/x'ample.;
+       ttl 60;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-origin-no-absolute.conf.j2 b/bin/tests/system/synthrecord/conf/bad-origin-no-absolute.conf.j2
new file mode 100644 (file)
index 0000000..a22ff91
--- /dev/null
@@ -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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix dynamic-;
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin "example";
+       ttl 60;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-origin-type.conf.j2 b/bin/tests/system/synthrecord/conf/bad-origin-type.conf.j2
new file mode 100644 (file)
index 0000000..a89a0e7
--- /dev/null
@@ -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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix dynamic-;
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin { 10.0.0.1/24; };
+       ttl 60;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-prefix-type.conf.j2 b/bin/tests/system/synthrecord/conf/bad-prefix-type.conf.j2
new file mode 100644 (file)
index 0000000..d3047ed
--- /dev/null
@@ -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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix { 10.43.4.5/2; };
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin "example.";
+       ttl 60;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-tsig.conf.j2 b/bin/tests/system/synthrecord/conf/bad-tsig.conf.j2
new file mode 100644 (file)
index 0000000..be5575a
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+key "test-tsig." {
+    algorithm hmac-sha256;
+    secret "DAopyf1mhCbFVZw7pgmNPBoLUq8wEUT7UuPoLENP2HY=";
+};
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix "dynamic-";
+       allow-synth {
+               192.168.1.5;
+               key test-tsig.;
+       };
+       origin example.;
+       ttl 50;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-unknown-mode.conf.j2 b/bin/tests/system/synthrecord/conf/bad-unknown-mode.conf.j2
new file mode 100644 (file)
index 0000000..d09e3e0
--- /dev/null
@@ -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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix "dynamic-";
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin example.;
+       ttl 60;
+       mode foobar;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-wrong-mode.conf.j2 b/bin/tests/system/synthrecord/conf/bad-wrong-mode.conf.j2
new file mode 100644 (file)
index 0000000..901506d
--- /dev/null
@@ -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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix "dynamic-";
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin example.;
+       ttl 60;
+       mode 123;
+};
diff --git a/bin/tests/system/synthrecord/conf/bad-wrong-ttl-type.conf.j2 b/bin/tests/system/synthrecord/conf/bad-wrong-ttl-type.conf.j2
new file mode 100644 (file)
index 0000000..77021e6
--- /dev/null
@@ -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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix "dynamic-";
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin example.;
+       ttl "foobar";
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/good-no-allow-synth.conf.j2 b/bin/tests/system/synthrecord/conf/good-no-allow-synth.conf.j2
new file mode 100644 (file)
index 0000000..9908910
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix dynamic-;
+       origin "example.";
+       ttl 60;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/good-no-ttl.conf.j2 b/bin/tests/system/synthrecord/conf/good-no-ttl.conf.j2
new file mode 100644 (file)
index 0000000..8f63b55
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix "dynamic-";
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin example.;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/good1.conf.j2 b/bin/tests/system/synthrecord/conf/good1.conf.j2
new file mode 100644 (file)
index 0000000..6ff0739
--- /dev/null
@@ -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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix "dynamic-";
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin example.;
+       ttl 60;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/good2.conf.j2 b/bin/tests/system/synthrecord/conf/good2.conf.j2
new file mode 100644 (file)
index 0000000..a0b176e
--- /dev/null
@@ -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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix dynamic-;
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       origin "example.";
+       ttl 60;
+       mode reverse;
+};
diff --git a/bin/tests/system/synthrecord/conf/good3.conf.j2 b/bin/tests/system/synthrecord/conf/good3.conf.j2
new file mode 100644 (file)
index 0000000..aa36d5b
--- /dev/null
@@ -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.
+ */
+
+plugin query "@TOP_BUILDDIR@/synthrecord.so" {
+       prefix "dynamic-";
+       allow-synth {
+               10.53.0.0/16;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+       };
+       ttl 60;
+       mode forward;
+       origin example.;
+};
diff --git a/bin/tests/system/synthrecord/ns1/0.0.0.0.ip6.arpa.db b/bin/tests/system/synthrecord/ns1/0.0.0.0.ip6.arpa.db
new file mode 100644 (file)
index 0000000..facf0b5
--- /dev/null
@@ -0,0 +1,14 @@
+; 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.
+
+$TTL   120
+@              SOA     ns.example.  hostmaster.ns.example. ( 1 3600 1200 604800 60 )
+@              NS      ns.example.
diff --git a/bin/tests/system/synthrecord/ns1/0.16.172.in-addr.arpa.db b/bin/tests/system/synthrecord/ns1/0.16.172.in-addr.arpa.db
new file mode 100644 (file)
index 0000000..facf0b5
--- /dev/null
@@ -0,0 +1,14 @@
+; 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.
+
+$TTL   120
+@              SOA     ns.example.  hostmaster.ns.example. ( 1 3600 1200 604800 60 )
+@              NS      ns.example.
diff --git a/bin/tests/system/synthrecord/ns1/0.53.10.in-addr.arpa.db b/bin/tests/system/synthrecord/ns1/0.53.10.in-addr.arpa.db
new file mode 100644 (file)
index 0000000..370de64
--- /dev/null
@@ -0,0 +1,16 @@
+; 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.
+
+$TTL   120
+@              SOA     ns.example.  hostmaster.ns.example. ( 1 3600 1200 604800 60 )
+@              NS      ns.example.
+4              PTR     a.example.
+28             PTR     b.example.
diff --git a/bin/tests/system/synthrecord/ns1/1.53.10.in-addr.arpa.db b/bin/tests/system/synthrecord/ns1/1.53.10.in-addr.arpa.db
new file mode 100644 (file)
index 0000000..facf0b5
--- /dev/null
@@ -0,0 +1,14 @@
+; 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.
+
+$TTL   120
+@              SOA     ns.example.  hostmaster.ns.example. ( 1 3600 1200 604800 60 )
+@              NS      ns.example.
diff --git a/bin/tests/system/synthrecord/ns1/168.192.in-addr.arpa.db b/bin/tests/system/synthrecord/ns1/168.192.in-addr.arpa.db
new file mode 100644 (file)
index 0000000..16a8fa7
--- /dev/null
@@ -0,0 +1,15 @@
+; 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.
+
+$TTL   120
+@              SOA     ns.example.  hostmaster.ns.example. ( 1 3600 1200 604800 60 )
+@              NS      ns.example.
+1      IN      NS      ns2.example.
diff --git a/bin/tests/system/synthrecord/ns1/e.f.a.c.e.f.a.c.ip6.arpa.db b/bin/tests/system/synthrecord/ns1/e.f.a.c.e.f.a.c.ip6.arpa.db
new file mode 100644 (file)
index 0000000..ddc4188
--- /dev/null
@@ -0,0 +1,15 @@
+; 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.
+
+$TTL   120
+@              SOA     ns.example.  hostmaster.ns.example. ( 1 3600 1200 604800 60 )
+@              NS      ns.example.
+e.f.a.c.f.e.e.b.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.e.f.a.c.e.f.a.c.ip6.arpa. PTR  aaaa.example.
diff --git a/bin/tests/system/synthrecord/ns1/example.db b/bin/tests/system/synthrecord/ns1/example.db
new file mode 100644 (file)
index 0000000..32ddf33
--- /dev/null
@@ -0,0 +1,18 @@
+; 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.
+
+$TTL    120
+@                      SOA     ns.example.  hostmaster.ns.example. ( 1 3600 1200 604800 60 )
+@                      NS      ns
+ns                     A       10.53.0.1
+ns2                    A       10.53.0.2
+a                      A       10.53.0.4
+dynamic-10-53-0-30     A       10.53.0.30
diff --git a/bin/tests/system/synthrecord/ns1/f.f.f.f.ip6.arpa.db b/bin/tests/system/synthrecord/ns1/f.f.f.f.ip6.arpa.db
new file mode 100644 (file)
index 0000000..facf0b5
--- /dev/null
@@ -0,0 +1,14 @@
+; 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.
+
+$TTL   120
+@              SOA     ns.example.  hostmaster.ns.example. ( 1 3600 1200 604800 60 )
+@              NS      ns.example.
diff --git a/bin/tests/system/synthrecord/ns1/named.conf.j2 b/bin/tests/system/synthrecord/ns1/named.conf.j2
new file mode 100644 (file)
index 0000000..a58dd8c
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+{% set inview = inview | default(False) %}
+
+options {
+       query-source address 10.53.0.1;
+       port @PORT@;
+       pid-file "named.pid";
+       listen-on { 10.53.0.1; };
+       listen-on-v6 { fd92:7065:b8e:ffff::1; };
+       recursion no;
+};
+
+key rndc_key {
+       secret "1234abcd8765";
+       algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+       inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
+
+{% if inview %}
+plugin query "@TOP_BUILDDIR@/synthrecord" {
+       prefix "dynamic-";
+       allow-synth {
+               10.53.0.0/24;
+               10.53.1.0/29;
+               192.168.1.0/24;
+               192.180.0.0/18;
+               cafe:cafe::/32;
+               ::/16;
+       };
+       origin example.;
+       ttl 3600;
+       mode reverse;
+};
+{% endif %}
+
+zone "example" {
+       type primary;
+       file "example.db";
+       plugin query "@TOP_BUILDDIR@/synthrecord" {
+               prefix "dynamic-";
+               allow-synth {
+                       10.53.0.0/24;
+                       10.53.1.0/29;
+                       192.168.1.0/24;
+                       192.180.0.0/18;
+                       cafe:cafe::/32;
+                       ::/16;
+               };
+               origin example.;
+               ttl 3600;
+               mode forward;
+       };
+};
+
+zone "0.53.10.in-addr.arpa." {
+       type primary;
+       file "0.53.10.in-addr.arpa.db";
+       plugin query "@TOP_BUILDDIR@/synthrecord" {
+               prefix "dynamic-";
+               allow-synth {
+                       10.53.0.0/24;
+               };
+               origin example.;
+               ttl 3600;
+               mode reverse;
+       };
+};
+
+zone "1.53.10.in-addr.arpa." {
+       type primary;
+       file "1.53.10.in-addr.arpa.db";
+       plugin query "@TOP_BUILDDIR@/synthrecord" {
+               prefix "dynamic-";
+               allow-synth {
+                       10.53.1.0/29;
+               };
+               origin example.;
+               ttl 3600;
+               mode reverse;
+       };
+};
+
+zone "0.16.172.in-addr.arpa." {
+       type primary;
+       file "0.16.172.in-addr.arpa.db";
+};
+
+zone "e.f.a.c.e.f.a.c.ip6.arpa." {
+       type primary;
+       file "e.f.a.c.e.f.a.c.ip6.arpa.db";
+       plugin query "@TOP_BUILDDIR@/synthrecord" {
+               prefix "dynamic-";
+               allow-synth {
+                       cafe:cafe::/32;
+               };
+               origin example.;
+               ttl 3600;
+               mode reverse;
+       };
+};
+
+zone "f.f.f.f.ip6.arpa." {
+       type primary;
+       file "f.f.f.f.ip6.arpa.db";
+       plugin query "@TOP_BUILDDIR@/synthrecord" {
+               prefix "dynamicdefaults-";
+               origin example.;
+               mode reverse;
+       };
+};
+
+zone "0.0.0.0.ip6.arpa." {
+       type primary;
+       file "0.0.0.0.ip6.arpa.db";
+       plugin query "@TOP_BUILDDIR@/synthrecord" {
+               prefix "dynamic-";
+               allow-synth {
+                       ::/16;
+               };
+               origin example.;
+               ttl 3600;
+               mode reverse;
+       };
+};
+
+zone "168.192.in-addr.arpa." {
+       type primary;
+       file "168.192.in-addr.arpa.db";
+       plugin query "@TOP_BUILDDIR@/synthrecord" {
+               prefix "dynamic-";
+               allow-synth {
+                       192.168/16;
+               };
+               origin example.;
+               ttl 3600;
+               mode reverse;
+       };
+};
diff --git a/bin/tests/system/synthrecord/ns1/root.db b/bin/tests/system/synthrecord/ns1/root.db
new file mode 100644 (file)
index 0000000..aae7f3d
--- /dev/null
@@ -0,0 +1,23 @@
+; 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.
+
+$TTL   120
+@              SOA     ns.utld hostmaster.ns.utld ( 1 3600 1200 604800 60 )
+@              NS      ns.utld
+ns.utld                A       10.53.0.1
+ns.utld                AAAA    fd92:7065:b8e:ffff::1
+;
+
+example                NS      ns.example
+ns.example     A       10.53.0.1
+ns.example     AAAA    fd92:7065:b8e:ffff::1
+
+10.53.0.1      PTR     ns.example
diff --git a/bin/tests/system/synthrecord/tests_synthrecord.py b/bin/tests/system/synthrecord/tests_synthrecord.py
new file mode 100644 (file)
index 0000000..ceeca8a
--- /dev/null
@@ -0,0 +1,498 @@
+# 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.
+import glob
+import os
+import subprocess
+
+from ipaddress import IPv4Address, IPv6Address
+import hypothesis
+from hypothesis import assume
+import pytest
+import isctest
+import isctest.hypothesis
+from isctest.hypothesis.strategies import dns_names
+import dns.message
+import dns.reversename
+from dns.reversename import ipv4_reverse_domain
+from dns.reversename import ipv6_reverse_domain
+
+
+SERVER = "10.53.0.1"
+
+pytestmark = pytest.mark.extra_artifacts(
+    [
+        "conf/*.conf",
+        "managed-keys.bind.jnl",
+    ]
+)
+
+
+def test_synthrecord_checkconf():
+    for filename in glob.glob("conf/good*.conf"):
+        isctest.run.cmd([os.environ["CHECKCONF"], filename])
+    for filename in glob.glob("conf/bad*.conf"):
+        with pytest.raises(subprocess.CalledProcessError):
+            isctest.run.cmd([os.environ["CHECKCONF"], filename])
+
+
+@pytest.mark.parametrize(
+    "qname, rname, ttl",
+    [
+        ("5.2.168.192.in-addr.arpa", "dynamic-192-168-2-5.example.", 3600),
+        ("44.0.53.10.IN-ADDR.ARPA", "dynamic-10-53-0-44.example.", 3600),
+        ("44.0.53.10.In-adDR.ArPA", "dynamic-10-53-0-44.example.", 3600),
+        ("44.0.53.10.in-addr.arpa", "dynamic-10-53-0-44.example.", 3600),
+        ("44.0.53.10.in-addr.arpa.", "dynamic-10-53-0-44.example.", 3600),
+        ("4.0.53.10.in-addr.arpa", "a.example.", 120),
+        ("4.0.53.10.in-addr.arpa.", "a.example.", 120),
+        ("4.1.53.10.in-addr.arpa.", "dynamic-10-53-1-4.example.", 3600),
+        ("28.0.53.10.in-addr.arpa", "b.example.", 120),
+        ("28.0.53.10.in-addr.arpa.", "b.example.", 120),
+        ("2.1.53.10.in-addr.arpa.", "dynamic-10-53-1-2.example.", 3600),
+        (
+            "e.f.a.c.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.e.f.a.c.e.f.a.c.ip6.arpa",
+            "dynamic-cafe-cafe--cafe.example.",
+            3600,
+        ),
+        (
+            "e.F.a.C.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.e.f.A.C.E.f.a.c.iP6.ArpA",
+            "dynamic-cafe-cafe--cafe.example.",
+            3600,
+        ),
+        (
+            "e.f.a.c.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.e.f.a.c.e.f.a.c.ip6.arpa.",
+            "dynamic-cafe-cafe--cafe.example.",
+            3600,
+        ),
+        (
+            "e.f.a.c.f.e.e.b.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.e.f.a.c.e.f.a.c.ip6.arpa.",
+            "aaaa.example.",
+            120,
+        ),
+    ],
+)
+def test_synthrecord_reverse_hasdata(qname, rname, ttl):
+    msg = dns.message.make_query(qname, "PTR")
+    res = isctest.query.udp(msg, SERVER)
+    isctest.check.noerror(res)
+    if qname[-1] != ".":
+        qname += "."
+    assert len(res.answer) == 1
+    assert res.answer[0].ttl == ttl
+    assert res.answer[0] == dns.rrset.from_text(qname, ttl, "IN", "PTR", rname)
+
+
+@pytest.mark.parametrize(
+    "qname, qtype, rname, rtype, ttl",
+    [
+        ("dynamic-10-53-0-44.example.", "A", "10.53.0.44", "A", 3600),
+        ("dYnAmIc-10-53-0-44.example.", "A", "10.53.0.44", "A", 3600),
+        ("dYnAmIc-10-53-0-44.example.", "ANY", "10.53.0.44", "A", 3600),
+        ("dynamic-10-53-0-30.example.", "A", "10.53.0.30", "A", 120),
+        ("a.example.", "A", "10.53.0.4", "A", 120),
+        ("dynamic-cafe-cafe--cafe.example", "AAAA", "cafe:cafe::cafe", "AAAA", 3600),
+        ("dynamic-cafe-cafe--cafe.example", "ANY", "cafe:cafe::cafe", "AAAA", 3600),
+    ],
+)
+def test_synthrecord_forward(qname, qtype, rname, rtype, ttl):
+    msg = dns.message.make_query(qname, qtype)
+    res = isctest.query.udp(msg, SERVER)
+    isctest.check.noerror(res)
+    if qname[-1] != ".":
+        qname += "."
+    assert len(res.answer) == 1
+    assert res.answer[0].ttl == ttl
+    assert res.answer[0] == dns.rrset.from_text(qname, ttl, "IN", rtype, rname)
+
+
+@pytest.mark.parametrize(
+    "qname, qtype",
+    [("dynamic-10-53-0-44.example.", "AAAA"), ("dynamic-cafe-cafe--cafe.example", "A")],
+)
+def test_synthrecord_forward_wrongtype(qname, qtype):
+    msg = dns.message.make_query(qname, qtype)
+    res = isctest.query.udp(msg, SERVER)
+    isctest.check.rcode(res, dns.rcode.NOERROR)
+    if qname[-1] != ".":
+        qname += "."
+    assert len(res.answer) == 0
+
+
+@pytest.mark.parametrize(
+    "qname, qtype, rcode",
+    [
+        ("dynamic-10-53-1-10a.example", "A", dns.rcode.NXDOMAIN),
+        ("dynamic-10-53-4-3.example", "A", dns.rcode.NXDOMAIN),
+        ("dynamic-10.53.1-3.example", "A", dns.rcode.NXDOMAIN),
+        ("dynamic-172-16-0-3.example", "A", dns.rcode.NXDOMAIN),
+        ("dynamic-cafe:: .example", "AAAA", dns.rcode.NXDOMAIN),
+        ("dynamic-cafe.example", "AAAA", dns.rcode.NXDOMAIN),
+        ("dynamic-cafe-cafe--cafez.example", "AAAA", dns.rcode.NXDOMAIN),
+        ("dynamic-10-53-1-10", "A", dns.rcode.REFUSED),
+        ("dynamic-cafe-cafe--cafe", "AAAA", dns.rcode.REFUSED),
+        ("example", "A", dns.rcode.NOERROR),
+    ],
+)
+def test_synthrecord_forward_nodata(qname, qtype, rcode):
+    msg = dns.message.make_query(qname, qtype)
+    res = isctest.query.udp(msg, SERVER)
+    assert len(res.answer) == 0
+    assert res.rcode() == rcode
+
+
+@pytest.mark.parametrize(
+    "qname, qtype, rcode",
+    [
+        ("ab.0.53.10.in-addr.arpa.", "PTR", dns.rcode.NXDOMAIN),
+        ("1.0.53.10.in-addr.arpa.", "A", dns.rcode.NOERROR),
+        ("1.0.53.10.in-addr.arpa.", "AAAA", dns.rcode.NOERROR),
+        (
+            "z.f.a.c.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.e.f.a.c.e.f.a.c.ip6.arpa.",
+            "PTR",
+            dns.rcode.NXDOMAIN,
+        ),
+        (
+            "e.f.a.c.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.e.f.a.c.f.e.e.b.ip6.arpa",
+            "PTR",
+            dns.rcode.REFUSED,
+        ),
+        ("foo.bar", "PTR", dns.rcode.REFUSED),
+        ("foo.bar", "A", dns.rcode.REFUSED),
+        ("1.64.180.192.in-addr.arpa", "PTR", dns.rcode.REFUSED),
+        ("254.63.180.192.in-addr.arpa.", "PTR", dns.rcode.REFUSED),
+        ("254.63.180.192.in-addr.arpa.", "A", dns.rcode.REFUSED),
+        ("5.1.167.192.in-addr.arpa", "PTR", dns.rcode.REFUSED),
+        ("80.80.80.80.in-addr.arpa", "PTR", dns.rcode.REFUSED),
+        ("10.1.16.172.in-addr.arpa", "PTR", dns.rcode.REFUSED),
+        ("2.1.53.10.in-addr.arpa.", "A", dns.rcode.NOERROR),
+        ("5.0.16.172.in-addr.arpa", "PTR", dns.rcode.NXDOMAIN),
+        ("1.53.10.in-addr.arpa", "PTR", dns.rcode.NOERROR),
+        ("1.53.10.in-addr.arpa", "A", dns.rcode.NOERROR),
+        ("1.53.10.in-addr.arpa", "AAAA", dns.rcode.NOERROR),
+        ("6.1.168.192.in-addr.arpa", "A", dns.rcode.NOERROR),
+        ("5.1.168.192.in-addr.arpa", "A", dns.rcode.NOERROR),
+        (
+            "e.f.a.c.e.f.a.c.ip6.arpa",
+            "PTR",
+            dns.rcode.NOERROR,
+        ),
+        (
+            "e.f.a.c.e.f.a.c.ip6.arpa",
+            "A",
+            dns.rcode.NOERROR,
+        ),
+        (
+            "e.f.a.c.e.f.a.c.ip6.arpa",
+            "AAAA",
+            dns.rcode.NOERROR,
+        ),
+        (
+            "1.0. . .0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.",
+            "PTR",
+            dns.rcode.NXDOMAIN,
+        ),
+        (
+            "1.0. . .0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.e.f.a.c.e.f.a.c.ip6.arpa.",
+            "PTR",
+            dns.rcode.NXDOMAIN,
+        ),
+    ],
+)
+def test_synthrecord_reverse_hasnodata(qname, qtype, rcode):
+    msg = dns.message.make_query(qname, qtype)
+    res = isctest.query.udp(msg, SERVER)
+    assert len(res.answer) == 0
+    assert res.rcode() == rcode
+
+
+@pytest.mark.parametrize(
+    "qname, rcode",
+    [
+        ("6.1.168.192.in-addr.arpa", dns.rcode.NOERROR),
+        ("5.1.168.192.in-addr.arpa", dns.rcode.NOERROR),
+    ],
+)
+def test_synthrecord_reverse_delegate(qname, rcode):
+    msg = dns.message.make_query(qname, "PTR")
+    res = isctest.query.udp(msg, SERVER)
+    assert len(res.answer) == 0
+    assert res.rcode() == rcode
+    assert len(res.authority) == 1
+    assert (
+        res.authority[0].to_text() == "1.168.192.in-addr.arpa. 120 IN NS ns2.example."
+    )
+
+
+# Tests the any allow-syth (as the whole subnet matching the zone is accepted)
+# as well as the TTL
+@pytest.mark.parametrize(
+    "qname, rname",
+    [
+        (
+            "f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.ip6.arpa",
+            "dynamicdefaults-ffff-ffff-ffff-ffff-ffff-ffff-ffff-ffff.example.",
+        ),
+        (
+            "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.f.f.f.f.f.f.f.f.ip6.arpa",
+            "dynamicdefaults-ffff-ffff--0.example.",
+        ),
+    ],
+)
+def test_synthrecord_defaults(qname, rname):
+    ttl = 300
+    msg = dns.message.make_query(qname, "PTR")
+    res = isctest.query.udp(msg, SERVER)
+    isctest.check.noerror(res)
+    if qname[-1] != ".":
+        qname += "."
+    assert len(res.answer) == 1
+    assert res.answer[0].ttl == ttl
+    assert res.answer[0] == dns.rrset.from_text(qname, ttl, "IN", "PTR", rname)
+
+
+@pytest.mark.parametrize(
+    "qname, qtype, rcode, answerscount",
+    [
+        ("55.0.53.10.in-addr.arpa", "ANY", dns.rcode.NOERROR, 1),
+        ("55.1.53.10.in-addr.arpa", "ANY", dns.rcode.NXDOMAIN, 0),
+        (
+            "e.f.a.c.d.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.e.f.a.c.e.f.a.c.ip6.arpa",
+            "ANY",
+            dns.rcode.NOERROR,
+            1,
+        ),
+    ],
+)
+def test_synthrecord_reverse_anysoa(qname, qtype, rcode, answerscount):
+    msg = dns.message.make_query(qname, qtype)
+    res = isctest.query.udp(msg, SERVER)
+    assert len(res.answer) == answerscount
+    assert res.rcode() == rcode
+
+
+def build_synthetic_name_v4(prefix, ip, domain):
+    return dns.name.from_text(
+        "{0}{1}.{2}".format(prefix, format(ip).replace(".", "-"), domain)
+    )
+
+
+def build_synthetic_name_v6(prefix, ip, domain):
+    return dns.name.from_text(
+        "{0}{1}.{2}".format(prefix, format(ip).replace(":", "-"), domain)
+    )
+
+
+example_domain = dns.name.from_text("example.")
+
+
+@hypothesis.given(domain=dns_names())
+def test_synthrecord_reverse_randomdomains(domain):
+    assume(
+        not (
+            domain.is_subdomain(ipv4_reverse_domain)
+            or domain.is_subdomain(ipv6_reverse_domain)
+            or domain.is_subdomain(example_domain)
+        )
+    )
+    query = dns.message.make_query(domain, "PTR")
+    res = isctest.query.udp(query, SERVER)
+    assert res.rcode() == dns.rcode.REFUSED
+
+
+@hypothesis.given(ip=hypothesis.strategies.ip_addresses(network="10.53.0.0/24"))
+def test_sythreverse_noerror_hasdata_v4(ip):
+    assume(ip not in [IPv4Address("10.53.0.28"), IPv4Address("10.53.0.4")])
+    query = dns.message.make_query(ip.reverse_pointer, "PTR")
+    res = isctest.query.udp(query, SERVER)
+    assert res.rcode() == dns.rcode.NOERROR
+    assert res.answer == [
+        dns.rrset.from_text(
+            ip.reverse_pointer + ".",
+            0,
+            "IN",
+            "PTR",
+            build_synthetic_name_v4("dynamic-", ip, "example").to_text(),
+        )
+    ]
+
+
+@hypothesis.given(ip=hypothesis.strategies.ip_addresses(network="10.53.2.0/24"))
+def test_sythreverse_refused_v4(ip):
+    query = dns.message.make_query(ip.reverse_pointer, "PTR")
+    res = isctest.query.udp(query, SERVER)
+    assert res.rcode() == dns.rcode.REFUSED
+
+
+arpa_cafecafe = dns.name.from_text("e.f.a.c.e.f.a.c.ip6.arpa.")
+arpa_zeros16 = dns.name.from_text("0.0.0.0.ip6.arpa.")
+
+
+@hypothesis.given(ip=hypothesis.strategies.ip_addresses(v=6))
+def test_sythreverse_refused_v6(ip):
+    assume(not dns.name.from_text(ip.reverse_pointer).is_subdomain(arpa_cafecafe))
+    assume(not dns.name.from_text(ip.reverse_pointer).is_subdomain(arpa_zeros16))
+    query = dns.message.make_query(ip.reverse_pointer, "PTR")
+    res = isctest.query.udp(query, SERVER)
+    assert res.rcode() == dns.rcode.REFUSED
+
+
+@pytest.mark.parametrize(
+    "addr, expected",
+    [
+        ("cafe:cafe::", "dynamic-cafe-cafe--0.example."),
+        ("::1", "dynamic-0--1.example."),
+        ("::", "dynamic-0--0.example."),
+    ],
+)
+def test_synthreverse_idn_compat(addr, expected):
+    ip = IPv6Address(addr)
+    query = dns.message.make_query(ip.reverse_pointer, "PTR")
+    res = isctest.query.udp(query, SERVER)
+    assert res.rcode() == dns.rcode.NOERROR
+    assert res.answer == [
+        dns.rrset.from_text(ip.reverse_pointer + ".", 0, "IN", "PTR", expected)
+    ]
+
+
+@hypothesis.given(ip=hypothesis.strategies.ip_addresses(network="cafe:cafe::/32"))
+def test_sythreverse_noerror_hasdata_v6(ip):
+    assume(not ip == IPv6Address("cafe:cafe::"))
+    query = dns.message.make_query(ip.reverse_pointer, "PTR")
+    res = isctest.query.udp(query, SERVER)
+    assert res.rcode() == dns.rcode.NOERROR
+    assert res.answer == [
+        dns.rrset.from_text(
+            ip.reverse_pointer + ".",
+            0,
+            "IN",
+            "PTR",
+            build_synthetic_name_v6("dynamic-", ip, "example").to_text(),
+        )
+    ]
+
+
+@hypothesis.given(ip=hypothesis.strategies.ip_addresses(network="10.53.1.0/24"))
+def test_sythreverse_unallowed_subnet_v4(ip):
+    # allow-nets is 10.53.1.0/29, so only addresses below 10.53.1.9 are allowed
+    # to have a synthetic record (_allow_subnet_v4 below checks the opposite)
+    assume(ip > IPv4Address("10.53.1.8"))
+    query = dns.message.make_query(ip.reverse_pointer, "PTR")
+    res = isctest.query.udp(query, SERVER)
+    assert len(res.answer) == 0
+    assert res.rcode() == dns.rcode.NXDOMAIN
+
+
+@hypothesis.given(ip=hypothesis.strategies.ip_addresses(network="10.53.1.0/29"))
+def test_sythreverse_allowed_subnet_v4(ip):
+    query = dns.message.make_query(ip.reverse_pointer, "PTR")
+    res = isctest.query.udp(query, SERVER)
+    assert res.rcode() == dns.rcode.NOERROR
+    assert res.answer == [
+        dns.rrset.from_text(
+            ip.reverse_pointer + ".",
+            0,
+            "IN",
+            "PTR",
+            build_synthetic_name_v4("dynamic-", ip, "example").to_text(),
+        )
+    ]
+
+
+@hypothesis.given(
+    domain=isctest.hypothesis.strategies.dns_names(
+        suffix=dns.name.from_text("1.53.10.in-addr.arpa."), min_labels=8, max_labels=34
+    )
+)
+def test_sythreverse_arpa_v4_nxdomain_toomanylabel(domain):
+    query = dns.message.make_query(domain, "PTR")
+    res = isctest.query.udp(query, SERVER)
+    assert len(res.answer) == 0
+    assert res.rcode() == dns.rcode.NXDOMAIN
+
+
+@hypothesis.given(
+    domain=isctest.hypothesis.strategies.dns_names(
+        prefix=dns.name.from_text("dynamic-10-53-0-20"),
+        suffix=dns.name.from_text("example"),
+        min_labels=4,
+        max_labels=34,
+    )
+)
+def test_sythforward_arpa_v4_nxdomain_toomanylabel(domain):
+    query = dns.message.make_query(domain, "A")
+    res = isctest.query.udp(query, SERVER)
+    assert len(res.answer) == 0
+    assert res.rcode() == dns.rcode.NXDOMAIN
+
+
+@hypothesis.given(
+    domain=isctest.hypothesis.strategies.dns_names(
+        prefix=dns.name.from_text("dynamic-cafe-cafe--cafe"),
+        suffix=dns.name.from_text("example"),
+        min_labels=4,
+        max_labels=34,
+    )
+)
+def test_sythforward_arpa_v6_nxdomain_toomanylabel(domain):
+    query = dns.message.make_query(domain, "AAAA")
+    res = isctest.query.udp(query, SERVER)
+    assert len(res.answer) == 0
+    assert res.rcode() == dns.rcode.NXDOMAIN
+
+
+@hypothesis.given(
+    domain=isctest.hypothesis.strategies.dns_names(
+        prefix=dns.name.from_text("dynamic-cafe--cafe--cafe"),
+        suffix=dns.name.from_text("example"),
+        min_labels=2,
+        max_labels=34,
+    )
+)
+def test_sythforward_arpa_v6_nxdomain_unallowednet(domain):
+    query = dns.message.make_query(domain, "AAAA")
+    res = isctest.query.udp(query, SERVER)
+    assert len(res.answer) == 0
+    assert res.rcode() == dns.rcode.NXDOMAIN
+
+
+@hypothesis.given(
+    domain=isctest.hypothesis.strategies.dns_names(
+        suffix=dns.name.from_text("a.e.f.a.c.e.f.a.c.ip6.arpa."), max_labels=34
+    )
+)
+def test_sythreverse_arpa_v6_nxdomain_toofewlabels(domain):
+    query = dns.message.make_query(domain, "PTR")
+    res = isctest.query.udp(query, SERVER)
+    assert len(res.answer) == 0
+    assert res.rcode() == dns.rcode.NXDOMAIN
+
+
+@hypothesis.given(
+    domain=isctest.hypothesis.strategies.dns_names(
+        suffix=dns.name.from_text("e.f.a.c.e.f.a.c.ip6.arpa."), min_labels=36
+    )
+)
+def test_sythreverse_arpa_v6_nxdomain_toomanylabels(domain):
+    query = dns.message.make_query(domain, "PTR")
+    res = isctest.query.udp(query, SERVER)
+    assert len(res.answer) == 0
+    assert res.rcode() == dns.rcode.NXDOMAIN
+
+
+def test_synthrecord_inview(ns1, templates):
+    templates.render("ns1/named.conf", {"inview": True})
+    with ns1.watch_log_from_here() as watcher:
+        try:
+            ns1.rndc("reconfig")
+        except isctest.rndc.RNDCException:
+            watcher.wait_for_line(
+                "registering 'synthrecord' failed as it was not configured as a zone plugin"
+            )