diff --git a/bin/tests/system/nsec3/common.py b/bin/tests/system/nsec3/common.py index 678cc4cbed..c7312cd324 100644 --- a/bin/tests/system/nsec3/common.py +++ b/bin/tests/system/nsec3/common.py @@ -35,9 +35,7 @@ pytestmark = pytest.mark.extra_artifacts( "ns*/*.jnl", "ns*/*.signed", "ns*/keygen.out.*", - "ns3/named-common.conf", - "ns3/named-fips.conf", - "ns3/named-rsasha1.conf", + "ns3/named-*.conf", ] ) diff --git a/bin/tests/system/nsec3/ns2/named.conf.j2 b/bin/tests/system/nsec3/ns2/named.conf.j2 index 904abbf81d..ec680db677 100644 --- a/bin/tests/system/nsec3/ns2/named.conf.j2 +++ b/bin/tests/system/nsec3/ns2/named.conf.j2 @@ -46,3 +46,13 @@ zone "nsec3-xfr-inline.kasp" { dnssec-policy "nsec3"; }; {% endif %}{# nsec3-xfr-inline.kasp #} + +{% if "retransfer.kasp" in zones %} +zone "retransfer.kasp" { + type primary; + file "retransfer.kasp.db"; + notify explicit; + also-notify { 10.53.0.3; }; + allow-transfer { any; }; +}; +{% endif %}{# nsec3-xfr-inline.kasp #} diff --git a/bin/tests/system/nsec3/ns2/retransfer.kasp.db.j2 b/bin/tests/system/nsec3/ns2/retransfer.kasp.db.j2 new file mode 100644 index 0000000000..f8a138c603 --- /dev/null +++ b/bin/tests/system/nsec3/ns2/retransfer.kasp.db.j2 @@ -0,0 +1,31 @@ +; 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 serial = serial | default(1) %} + +$ORIGIN retransfer.kasp. +$TTL 300 + +retransfer.kasp. IN SOA mname1. . ( + @serial@ ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + + NS ns2 +ns2 A 10.53.0.2 +ns3 A 10.53.0.3 + +a A 10.0.0.1 +b A 10.0.0.2 +c A 10.0.0.3 diff --git a/bin/tests/system/nsec3/ns3/named-retransfer.conf.j2 b/bin/tests/system/nsec3/ns3/named-retransfer.conf.j2 new file mode 100644 index 0000000000..e521f96621 --- /dev/null +++ b/bin/tests/system/nsec3/ns3/named-retransfer.conf.j2 @@ -0,0 +1,49 @@ +/* + * 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. + */ + +remote-servers "ns2" { + 10.53.0.2 port @PORT@; +}; + +remote-servers "ns4" { + 10.53.0.4 port @PORT@; +}; + +dnssec-policy "nsec3rsa256" { + cdnskey no; + keys { + ksk lifetime unlimited algorithm RSASHA256 2048; + zsk lifetime P90D algorithm RSASHA256 2048; + }; + max-zone-ttl P2D; + signatures-refresh P8D; + + nsec3param; +}; + +{% if "retransfer.kasp" in zones %} +zone "retransfer.kasp" { + type secondary; + primaries { "ns2"; }; + file "retransfer.kasp.db"; + allow-transfer { any; }; + allow-notify { any; }; + also-notify { "ns4"; }; + notify explicit; + + dnssec-policy "nsec3rsa256"; + inline-signing yes; + sig-signing-signatures 100; + checkds no; +}; +{% endif %}{# retransfer.kasp #} diff --git a/bin/tests/system/nsec3/ns3/named.conf.j2 b/bin/tests/system/nsec3/ns3/named.conf.j2 index 7dd06ad83c..7aa4f17194 100644 --- a/bin/tests/system/nsec3/ns3/named.conf.j2 +++ b/bin/tests/system/nsec3/ns3/named.conf.j2 @@ -15,6 +15,7 @@ include "named-common.conf"; include "named-fips.conf"; +include "named-retransfer.conf"; {% if RSASHA1_SUPPORTED == "1" %} include "named-rsasha1.conf"; diff --git a/bin/tests/system/nsec3/ns4/named.conf.j2 b/bin/tests/system/nsec3/ns4/named.conf.j2 new file mode 100644 index 0000000000..59a126b6f4 --- /dev/null +++ b/bin/tests/system/nsec3/ns4/named.conf.j2 @@ -0,0 +1,39 @@ +/* + * 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. + */ + +// NS4 + +options { + query-source address 10.53.0.4; + notify-source 10.53.0.4; + transfer-source 10.53.0.4; + port @PORT@; + pid-file "named.pid"; + listen-on { 10.53.0.4; }; + listen-on-v6 { none; }; + allow-transfer { any; }; + recursion no; + dnssec-validation no; +}; + +remote-servers "ns3" { + 10.53.0.3 port @PORT@; +}; + +zone "retransfer.kasp" { + type secondary; + file "retransfer.kasp.db"; + primaries { "ns3"; }; + allow-notify { any; }; + notify no; +}; diff --git a/bin/tests/system/nsec3/tests_nsec3_retransfer.py b/bin/tests/system/nsec3/tests_nsec3_retransfer.py new file mode 100644 index 0000000000..96a23761b5 --- /dev/null +++ b/bin/tests/system/nsec3/tests_nsec3_retransfer.py @@ -0,0 +1,129 @@ +# 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. + +# pylint: disable=redefined-outer-name,unused-import + +import os +import shutil + +from datetime import timedelta + +import dns.update +import pytest + +pytest.importorskip("dns", minversion="2.0.0") +import isctest +import isctest.mark +from isctest.vars.algorithms import RSASHA256 +from nsec3.common import ( + pytestmark, + check_auth_nsec3, + check_nsec3param, +) + +DNSKEY_TTL = int(timedelta(hours=1).total_seconds()) +ZSK_LIFETIME = int(timedelta(days=90).total_seconds()) + +# include the following zones when rendering named configs +ZONES = { + "retransfer.kasp", +} + + +def bootstrap(): + return { + "zones": ZONES, + } + + +def perform_nsec3_tests(server, params): + # Get test parameters. + zone = params["zone"] + fqdn = f"{zone}." + policy = params["policy"] + keydir = server.identifier + minimum = params.get("soa-minimum", 3600) + expected = isctest.kasp.policy_to_properties( + ttl=DNSKEY_TTL, keys=params["key-properties"] + ) + + iterations = 0 + optout = 0 + saltlen = 0 + + match = f"{fqdn} {minimum} IN NSEC3PARAM 1 0 {iterations}" + + # Test case. + isctest.log.info(f"check nsec3 case zone {zone} policy {policy}") + + # First make sure the zone is properly signed. + isctest.kasp.wait_keymgr_done(server, zone) + + keys = isctest.kasp.keydir_to_keylist(zone, keydir) + ksks = [k for k in keys if k.is_ksk()] + zsks = [k for k in keys if k.is_zsk()] + isctest.kasp.check_keys(zone, keys, expected) + isctest.kasp.check_dnssec_verify(server, zone) + isctest.kasp.check_apex(server, zone, ksks, zsks) + + query = isctest.query.create(fqdn, dns.rdatatype.NSEC3PARAM) + response = isctest.query.tcp(query, server.ip, server.ports.dns, timeout=3) + assert response.rcode() == dns.rcode.NOERROR + + salt = check_nsec3param(response, match, saltlen) + + query = isctest.query.create(f"nosuchname.{fqdn}", dns.rdatatype.A) + response = isctest.query.tcp(query, server.ip, server.ports.dns, timeout=3) + assert response.rcode() == dns.rcode.NXDOMAIN + check_auth_nsec3(response, iterations, optout, salt) + + return salt + + +def test_nsec3_retransfer(servers, templates): + ns2 = servers["ns2"] + ns3 = servers["ns3"] + + params = { + "zone": "retransfer.kasp", + "policy": "nsec3rsa256", + "key-properties": [ + f"ksk 0 {RSASHA256.number} 2048 goal:omnipresent dnskey:rumoured krrsig:rumoured ds:hidden", + f"zsk {ZSK_LIFETIME} {RSASHA256.number} 2048 goal:omnipresent dnskey:rumoured zrrsig:rumoured", + ], + } + + zone = params["zone"] + salt = perform_nsec3_tests(ns3, params) + + # Stop primary. + ns2.stop() + + # Update the zone. + serial = 10 + templates.render(f"{ns2.identifier}/{zone}.db", {"serial": serial}) + + with ns2.watch_log_from_here() as watcher: + ns2.start(["--noclean", "--restart", "--port", os.environ["PORT"]]) + watcher.wait_for_line("all zones loaded") + + # Test NSEC3 and NSEC3PARAM is the same after retransfer. + isctest.log.info(f"check zone {zone} after retransfer has salt {salt}") + prevsalt = salt + + # Retransfer zone, NSEC3 should stay the same. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"retransfer {zone}") + # When sending notifies, the zone should be up to date. + watcher.wait_for_line(f"zone {zone}/IN (signed): sending notify to 10.53.0.4") + + salt = perform_nsec3_tests(ns3, params) + assert prevsalt == salt diff --git a/lib/dns/zone.c b/lib/dns/zone.c index a46969b3e8..2b70bdc93a 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -16312,6 +16312,17 @@ sync_secure_db(dns_zone_t *seczone, dns_zone_t *raw, dns_db_t *secdb, ISC_LIST_FOREACH(diff->tuples, tuple, link) { dns_difftuplelist_t *al = &add, *dl = &del; + /* + * Skip private records that BIND maintains with inline-signing. + */ + if (seczone->privatetype != 0 && + tuple->rdata.type == seczone->privatetype) + { + ISC_LIST_UNLINK(diff->tuples, tuple, link); + dns_difftuple_free(&tuple); + continue; + } + /* * Skip DNSSEC records that BIND maintains with inline-signing. */