mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
fix: usr: Fix bug where zone switches from NSEC3 to NSEC after retransfer
When a zone is re-transferred, but the zone journal on an inline-signing secondary is out of sync, the zone could fall back to using NSEC records instead of NSEC3. This has been fixed. Closes #5527 Merge branch '5527-retransfer-nsec3-bug' into 'main' See merge request isc-projects/bind9!11226
This commit is contained in:
commit
ddd1040761
8 changed files with 271 additions and 3 deletions
|
|
@ -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",
|
||||
]
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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 #}
|
||||
|
|
|
|||
31
bin/tests/system/nsec3/ns2/retransfer.kasp.db.j2
Normal file
31
bin/tests/system/nsec3/ns2/retransfer.kasp.db.j2
Normal file
|
|
@ -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
|
||||
49
bin/tests/system/nsec3/ns3/named-retransfer.conf.j2
Normal file
49
bin/tests/system/nsec3/ns3/named-retransfer.conf.j2
Normal file
|
|
@ -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 #}
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
include "named-common.conf";
|
||||
include "named-fips.conf";
|
||||
include "named-retransfer.conf";
|
||||
|
||||
{% if RSASHA1_SUPPORTED == "1" %}
|
||||
include "named-rsasha1.conf";
|
||||
|
|
|
|||
39
bin/tests/system/nsec3/ns4/named.conf.j2
Normal file
39
bin/tests/system/nsec3/ns4/named.conf.j2
Normal file
|
|
@ -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;
|
||||
};
|
||||
129
bin/tests/system/nsec3/tests_nsec3_retransfer.py
Normal file
129
bin/tests/system/nsec3/tests_nsec3_retransfer.py
Normal file
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue