add synthesized record system tests

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.
This commit is contained in:
Colin Vidal 2025-03-31 16:00:32 +02:00
parent a0da784993
commit c201b429f4
32 changed files with 1288 additions and 0 deletions

View file

@ -0,0 +1,3 @@
named.conf
named.memstats
named.run

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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.;
};

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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

View file

@ -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.

View file

@ -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;
};
};

View file

@ -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

View file

@ -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"
)