Compare commits

...
Author SHA1 Message Date
Matthijs Mekking 88e33102e5 Create key files for imported DNSKEYs 2022-11-02 17:05:12 +01:00
Matthijs Mekking bc8b58d8fd Dynamic update DNSKEY to secure zone 2022-11-02 17:04:51 +01:00
Matthijs Mekking 31165bfe11 fixup! Add more multisigner tests 2022-11-02 16:50:00 +01:00
Mark AndrewsandMatthijs Mekking b793f39cf3 Fix dns_dnssec_findzonekeys name in log message
(cherry picked from commit 70bcf4fd34cb5efb5e740bb1a60658bda7138cfe)
2022-11-02 12:23:43 +01:00
Mark AndrewsandMatthijs Mekking 76fb29d800 Don't sign the raw zone
The raw zone is not supposed to be signed.  DNSKEY records in a raw zone
should not trigger zone signing.  The update code needs to be able to
identify when it is working on a raw zone.  Add dns_zone_israw() to
enable it to do this.

(cherry picked from commit 4b287ac02170351ce16f0d60a89b95a7f84ab0f2)
2022-11-02 12:23:13 +01:00
Matthijs Mekking 18dd7e36db Add notes and change entry
(cherry picked from commit c6afef236199f3ec69cd5a3db17f8cfc8a337f5e)
2022-11-02 12:23:04 +01:00
Matthijs Mekking 7e68928ee1 Add more multisigner tests
A zone in multisigner model 2 should also be possible to publish the
CDS and CDNSKEY records from their KSK into the zone operated by the
other provider.

(cherry picked from commit 3d6a6d1bc018432b2f85acec1236aa2fcc1cd961)
2022-11-02 12:21:07 +01:00
Matthijs Mekking ee2970c861 Fix dns_zone_getkasp() function
For inline-signing zones, sometimes kasp was not detected because
the function was called on the raw (unsigned) version of the zone,
but the kasp is only set on the secure (signed) version of the zone.

Fix the dns_zone_getkasp() function to check whether the zone
structure is inline_raw(), and if so, use the kasp from the
secure version.

(cherry picked from commit 681e2ae4b5cd09ea3fd7b36eb93e0d86f40521be)
2022-11-02 12:21:01 +01:00
Matthijs Mekking a092cb3d48 Update find_zone_keys for dynamic update
The find_zone_keys() function was not working properly for
inline-signed zones. It only worked if the DNSKEY records were also
published in the unsigned version of the zone. But this is not the
case when you use dnssec-policy, the DNSKEY records will only occur
in the signed version of the zone. Therefor, when looking for keys
to sign the zone, only the newly added keys in the dynamic update
were found (which could be zero), ignoring existing keys.

Also, if a DNSKEY was added, it would try to sign the zone with just
this new key, and this would only work if the key files for that key
were imported into the key-directory.

This is a design error, because the goal is to sign the zone with the
keys for which we actually have key files for. So instead of looking
for DNSKEY records to then search for the matching key files, call
dns_dnssec_findmatchingkeys() which just looks for the keys we have
on disk for the given zone. It will also set the correct DNSSEC
signing hints.

(cherry picked from commit cecb34a2b915e050550462ceeccd5d9f64c746b5)
2022-11-02 12:20:49 +01:00
Matthijs Mekking 769baa1188 Add missing dns_zone_set...() calls
When the zone uses inline-signing, it needs to set some of the
configuration options also to the raw version of the zone. This change
is incomplete: There are possibly more options that require this code
stanza.

(cherry picked from commit 624fa122a05a499b2b8c40ddb27cf3b30e427ded)
2022-11-02 12:20:42 +01:00
Matthijs Mekking 212c72b1f3 Add multisigner system test
Add a new system test to test multisigner model use cases. This
initial test just tests a small part of the model 2, and uses two
providers for the same zone, ns3 and ns4, each with their own unique
key set. This commit tests that each provider can import their ZSK
of the other provider into their DNSKEY RRset, using dynamic update.

Both providers use dnssec-policy, ns3 applies the DNSSEC records
directly, while ns4 uses inline-signing.

(cherry picked from commit 701f27dd2706b00da7b89de3d99c826901bf3f77)
2022-11-02 12:18:13 +01:00
21 changed files with 1154 additions and 168 deletions
+3
View File
@@ -1,3 +1,6 @@
6012. [bug] Fix inline-signing bugs related to the multisigner
model (RFC 8901). [GL #2710]
6011. [func] Refactor the privilege setting part of named_os unit
to make libcap on Linux mandatory and use setreuid
and setregid if available. [GL #3583]
+28
View File
@@ -1595,8 +1595,14 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
if (use_kasp) {
seconds = (uint32_t)dns_kasp_sigvalidity(kasp);
dns_zone_setsigvalidityinterval(zone, seconds);
if (raw != NULL) {
dns_zone_setsigvalidityinterval(raw, seconds);
}
seconds = (uint32_t)dns_kasp_sigrefresh(kasp);
dns_zone_setsigresigninginterval(zone, seconds);
if (raw != NULL) {
dns_zone_setsigresigninginterval(raw, seconds);
}
} else {
obj = NULL;
result = named_config_get(maps, "sig-validity-interval",
@@ -1611,6 +1617,9 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
seconds *= 86400;
}
dns_zone_setsigvalidityinterval(zone, seconds);
if (raw != NULL) {
dns_zone_setsigvalidityinterval(raw, seconds);
}
resign = cfg_tuple_get(obj, "re-sign");
if (cfg_obj_isvoid(resign)) {
@@ -1626,6 +1635,9 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
seconds = cfg_obj_asuint32(resign);
}
dns_zone_setsigresigninginterval(zone, seconds);
if (raw != NULL) {
dns_zone_setsigresigninginterval(raw, seconds);
}
}
obj = NULL;
@@ -1634,21 +1646,33 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
filename = cfg_obj_asstring(obj);
RETERR(dns_zone_setkeydirectory(zone, filename));
}
if (raw != NULL) {
RETERR(dns_zone_setkeydirectory(raw, filename));
}
obj = NULL;
result = named_config_get(maps, "sig-signing-signatures", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setsignatures(zone, cfg_obj_asuint32(obj));
if (raw != NULL) {
dns_zone_setsignatures(raw, cfg_obj_asuint32(obj));
}
obj = NULL;
result = named_config_get(maps, "sig-signing-nodes", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setnodes(zone, cfg_obj_asuint32(obj));
if (raw != NULL) {
dns_zone_setnodes(raw, cfg_obj_asuint32(obj));
}
obj = NULL;
result = named_config_get(maps, "sig-signing-type", &obj);
INSIST(result == ISC_R_SUCCESS && obj != NULL);
dns_zone_setprivatetype(zone, cfg_obj_asuint32(obj));
if (raw != NULL) {
dns_zone_setprivatetype(raw, cfg_obj_asuint32(obj));
}
obj = NULL;
result = named_config_get(maps, "update-check-ksk", &obj);
@@ -1676,6 +1700,10 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
INSIST(result == ISC_R_SUCCESS && obj != NULL);
RETERR(dns_zone_setrefreshkeyinterval(zone,
cfg_obj_asuint32(obj)));
if (raw != NULL) {
RETERR(dns_zone_setrefreshkeyinterval(
raw, cfg_obj_asuint32(obj)));
}
obj = NULL;
result = cfg_map_get(zoptions, "auto-dnssec", &obj);
+1 -1
View File
@@ -198,7 +198,7 @@ endif HAVE_PERLMOD_NET_DNS_NAMESERVER
endif HAVE_PERLMOD_NET_DNS
if HAVE_PYTHON
TESTS += kasp keymgr2kasp tcp pipelined
TESTS += kasp keymgr2kasp multisigner tcp pipelined
if HAVE_PYTEST
TESTS += checkds dispatch rpzextra shutdown timeouts
+1
View File
@@ -86,6 +86,7 @@ keyfromlabel
keymgr2kasp
legacy
logfileconfig
multisigner
nzd2nzf
pipelined
qmin
+36
View File
@@ -0,0 +1,36 @@
#!/bin/sh
# 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 -e
rm -f *.created
rm -f cdnskey.ns*
rm -f cds.ns*
rm -f created.key-*
rm -f dig.out.*
rm -f python.out.*
rm -f rndc.dnssec.status.out.*
rm -f unused.key-*
rm -f ns*/*.jbk
rm -f ns*/*.jnl
rm -f ns*/*.signed
rm -f ns*/*.signed.jnl
rm -f ns*/*.zsk
rm -f ns*/K*
rm -f ns*/keygen.out.*
rm -f ns*/managed-keys*
rm -f ns*/named.conf
rm -f ns*/named.memstats
rm -f ns*/named.run
rm -f ns*/settime.out.*
+19
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.
*/
dnssec-policy "model2" {
keys {
ksk lifetime unlimited algorithm ecdsap256sha256;
zsk lifetime unlimited algorithm ecdsap256sha256;
};
};
@@ -0,0 +1,27 @@
; 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 300
@ IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns3
ns3 A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
c A 10.0.0.3
@@ -0,0 +1,46 @@
/*
* 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.
*/
// NS3
include "../kasp.conf";
options {
query-source address 10.53.0.3;
notify-source 10.53.0.3;
transfer-source 10.53.0.3;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
allow-transfer { any; };
recursion no;
key-directory ".";
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "model2.multisigner." {
type primary;
allow-update { any; };
file "model2.multisigner.db";
dnssec-policy model2;
inline-signing no;
};
+31
View File
@@ -0,0 +1,31 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../../conf.sh
echo_i "ns3/setup.sh"
zone="model2.multisigner"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
O="OMNIPRESENT"
ksktimes="-P now -A now -P sync now"
zsktimes="-P now -A now"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -f KSK -L 3600 $ksktimes $zone 2> keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2)
$SETTIME -s -g $O -k $O now -r $O now -d $O now "$KSK" > settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O now -z $O now "$ZSK" > settime.out.$zone.2 2>&1
# ZSK will be added to the other provider with nsupdate.
cat "${ZSK}.key" | grep -v ";.*" > "${zone}.zsk"
@@ -0,0 +1,26 @@
; 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 300
@ IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns4
ns4 A 10.53.0.4
a A 10.0.0.1
b A 10.0.0.2
c A 10.0.0.3
@@ -0,0 +1,27 @@
; 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 300
@ IN SOA mname1. . (
1 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns3
ns3 A 10.53.0.3
a A 10.0.0.1
b A 10.0.0.2
c A 10.0.0.3
@@ -0,0 +1,46 @@
/*
* 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
include "../kasp.conf";
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;
key-directory ".";
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "model2.multisigner." {
type primary;
allow-update { any; };
file "model2.multisigner.db";
dnssec-policy model2;
inline-signing yes;
};
+31
View File
@@ -0,0 +1,31 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../../conf.sh
echo_i "ns4/setup.sh"
zone="model2.multisigner"
echo_i "setting up zone: $zone"
zonefile="${zone}.db"
O="OMNIPRESENT"
ksktimes="-P now -A now -P sync now"
zsktimes="-P now -A now"
KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -f KSK -L 3600 $ksktimes $zone 2> keygen.out.$zone.1)
ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone 2> keygen.out.$zone.2)
$SETTIME -s -g $O -k $O now -r $O now -d $O now "$KSK" > settime.out.$zone.1 2>&1
$SETTIME -s -g $O -k $O now -z $O now "$ZSK" > settime.out.$zone.2 2>&1
# ZSK will be added to the other provider with nsupdate.
cat "${ZSK}.key" | grep -v ";.*" > "${zone}.zsk"
+31
View File
@@ -0,0 +1,31 @@
#!/bin/sh -e
# 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.
# shellcheck source=conf.sh
. ../conf.sh
set -e
$SHELL clean.sh
copy_setports ns3/named.conf.in ns3/named.conf
copy_setports ns4/named.conf.in ns4/named.conf
(
cd ns3
$SHELL setup.sh
)
(
cd ns4
$SHELL setup.sh
)
+270
View File
@@ -0,0 +1,270 @@
#!/bin/sh
# 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.
# shellcheck source=conf.sh
. ../conf.sh
# shellcheck source=kasp.sh
. ../kasp.sh
dig_with_opts() {
$DIG +tcp +noadd +nosea +nostat +nocmd +dnssec -p $PORT "$@"
}
start_time="$(TZ=UTC date +%s)"
status=0
n=0
set_zone "model2.multisigner"
set_policy "model2" "2" "3600"
# Key properties and states.
key_clear "KEY1"
set_keyrole "KEY1" "ksk"
set_keylifetime "KEY1" "0"
set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "no"
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
set_keystate "KEY1" "STATE_DS" "omnipresent"
key_clear "KEY2"
set_keyrole "KEY2" "zsk"
set_keylifetime "KEY2" "0"
set_keyalgorithm "KEY2" "13" "ECDSAP256SHA256" "256"
set_keysigning "KEY2" "no"
set_zonesigning "KEY2" "yes"
set_keystate "KEY2" "GOAL" "omnipresent"
set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
key_clear "KEY3"
key_clear "KEY4"
set_keytimes_model2() {
# The first KSK is immediately published and activated.
created=$(key_get KEY1 CREATED)
set_keytime "KEY1" "PUBLISHED" "${created}"
set_keytime "KEY1" "ACTIVE" "${created}"
set_keytime "KEY1" "SYNCPUBLISH" "${created}"
# The first ZSKs are immediately published and activated.
created=$(key_get KEY2 CREATED)
set_keytime "KEY2" "PUBLISHED" "${created}"
set_keytime "KEY2" "ACTIVE" "${created}"
}
set_server "ns3" "10.53.0.3"
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_model2
check_keytimes
check_apex
dnssec_verify
set_server "ns4" "10.53.0.4"
check_keys
check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
set_keytimes_model2
check_keytimes
check_apex
dnssec_verify
#
# Update DNSKEY RRset.
#
# Check that the ZSKs from the other provider are published.
zsks_are_published() {
dig_with_opts "$ZONE" "@${SERVER}" DNSKEY > "dig.out.$DIR.test$n" || return 1
# We should have two ZSKs.
lines=$(grep "256 3 13" dig.out.$DIR.test$n | wc -l)
test "$lines" -eq 2 || return 1
# And one KSK.
lines=$(grep "257 3 13" dig.out.$DIR.test$n | wc -l)
test "$lines" -eq 1 || return 1
}
n=$((n+1))
echo_i "update zone ${ZONE} at ns3 with ZSK from provider ns4"
ret=0
set_server "ns3" "10.53.0.3"
(
echo zone "${ZONE}"
echo server "${SERVER}" "${PORT}"
echo update add $(cat "ns4/${ZONE}.zsk")
echo send
) | $NSUPDATE
echo_i "check zone ${ZONE} DNSKEY RRset after update ($n)"
retry_quiet 10 zsks_are_published || ret=1
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
# Verify again.
dnssec_verify
n=$((n+1))
echo_i "update zone ${ZONE} at ns4 with ZSK from provider ns3"
ret=0
set_server "ns4" "10.53.0.4"
(
echo zone "${ZONE}"
echo server "${SERVER}" "${PORT}"
echo update add $(cat "ns3/${ZONE}.zsk")
echo send
) | $NSUPDATE
echo_i "check zone ${ZONE} DNSKEY RRset after update ($n)"
retry_quiet 10 zsks_are_published || ret=1
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
# Verify again.
dnssec_verify
#
# Update CDNSKEY RRset.
#
# Check that the CDNSKEY from both providers are published.
records_published() {
_rrtype=$1
_expect=$2
dig_with_opts "$ZONE" "@${SERVER}" "${_rrtype}" > "dig.out.$DIR.test$n" || return 1
lines=$(awk -v rt="${_rrtype}" '$4 == rt {print}' dig.out.$DIR.test$n | wc -l)
test "$lines" -eq "$_expect" || return 1
}
# Retrieve CDNSKEY records from the other provider.
dig_with_opts ${ZONE} @10.53.0.3 CDNSKEY > dig.out.ns3.cdnskey
awk '$4 == "CDNSKEY" {print}' dig.out.ns3.cdnskey > cdnskey.ns3
dig_with_opts ${ZONE} @10.53.0.4 CDNSKEY > dig.out.ns4.cdnskey
awk '$4 == "CDNSKEY" {print}' dig.out.ns4.cdnskey > cdnskey.ns4
set_server "ns3" "10.53.0.3"
# Initially there should be one CDNSKEY.
n=$((n+1))
echo_i "check zone ${ZONE} ${DIR} initially CDNSKEY ($n)"
ret=0
retry_quiet 10 records_published CDNSKEY 1 || ret=1
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
n=$((n+1))
echo_i "update zone ${ZONE} at ns3 with CDNSKEY from provider ns4"
ret=0
(
echo zone "${ZONE}"
echo server "${SERVER}" "${PORT}"
echo update add $(cat "cdnskey.ns4")
echo send
) | $NSUPDATE
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
# Now there should be two CDNSKEY records (we test that BIND does not
# skip it during DNSSEC maintenance).
n=$((n+1))
echo_i "check zone ${ZONE} CDNSKEY RRset after update ($n)"
ret=0
retry_quiet 10 records_published CDNSKEY 2 || ret=1
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
set_server "ns4" "10.53.0.4"
# Initially there should be one CDNSKEY.
n=$((n+1))
echo_i "check zone ${ZONE} ${DIR} initially CDNSKEY ($n)"
ret=0
retry_quiet 10 records_published CDNSKEY 1 || ret=1
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
n=$((n+1))
echo_i "update zone ${ZONE} at ns4 with CDNSKEY from provider ns3"
ret=0
(
echo zone "${ZONE}"
echo server "${SERVER}" "${PORT}"
echo update add $(cat "cdnskey.ns3")
echo send
) | $NSUPDATE
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
# Now there should be two CDNSKEY records (we test that BIND does not
# skip it during DNSSEC maintenance).
n=$((n+1))
echo_i "check zone ${ZONE} CDNSKEY RRset after update ($n)"
ret=0
retry_quiet 10 records_published CDNSKEY 2 || ret=1
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
#
# Update CDS RRset.
#
# Retrieve CDS records from the other provider.
dig_with_opts ${ZONE} @10.53.0.3 CDS > dig.out.ns3.cds
awk '$4 == "CDS" {print}' dig.out.ns3.cds > cds.ns3
dig_with_opts ${ZONE} @10.53.0.4 CDS > dig.out.ns4.cds
awk '$4 == "CDS" {print}' dig.out.ns4.cds > cds.ns4
n=$((n+1))
echo_i "update zone ${ZONE} at ns3 with CDS from provider ns4"
ret=0
set_server "ns3" "10.53.0.3"
# Initially there should be one CDS.
retry_quiet 10 records_published CDS 1 || ret=1
(
echo zone "${ZONE}"
echo server "${SERVER}" "${PORT}"
echo update add $(cat "cds.ns4")
echo send
) | $NSUPDATE
# Now there should be two CDS records (we test that BIND does not
# skip it during DNSSEC maintenance).
echo_i "check zone ${ZONE} CDS RRset after update ($n)"
retry_quiet 10 records_published CDS 2 || ret=1
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
n=$((n+1))
echo_i "update zone ${ZONE} at ns4 with CDS from provider ns3"
ret=0
set_server "ns4" "10.53.0.4"
# Initially there should be one CDS.
retry_quiet 10 records_published CDS 1 || ret=1
(
echo zone "${ZONE}"
echo server "${SERVER}" "${PORT}"
echo update add $(cat "cds.ns3")
echo send
) | $NSUPDATE
# Now there should be two CDS records (we test that BIND does not
# skip it during DNSSEC maintenance).
echo_i "check zone ${ZONE} CDS RRset after update ($n)"
retry_quiet 10 records_published CDS 2 || ret=1
test "$ret" -eq 0 || echo_i "failed"
status=$((status+ret))
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1
+5
View File
@@ -63,3 +63,8 @@ Bug Fixes
enter into a state where it would not recover without stopping ``named``,
manually deleting ``managed-keys.bind`` and ``managed-keys.bind.jnl`` files,
and starting ``named`` again. :gl:`#2895`
- Fix bugs related to ``inline-signing`` zones that are subject to a
multisigner model (RFC 8901). In some cases it was not possible to update
the zone with a DNSKEY, CDS or CDNSKEY from the other provider, or the
record would be removed again after a re-sign of the zone. :gl:`#2710`
+11 -4
View File
@@ -828,7 +828,7 @@ dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
}
}
if (result != ISC_R_SUCCESS) {
if (true) {
char filename[DNS_NAME_FORMATSIZE +
DNS_SECALG_FORMATSIZE +
sizeof("key file for //65535")];
@@ -857,9 +857,16 @@ dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
"dns_dnssec_findzonekeys2: error "
"reading %s: %s",
filename, isc_result_totext(result));
"dns_dnssec_findzonekeys: reading %s",
filename);
if (result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
"dns_dnssec_findzonekeys: error "
"reading %s: %s",
filename, isc_result_totext(result));
}
}
if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
+6
View File
@@ -2520,9 +2520,15 @@ dns_zone_getserialupdatemethod(dns_zone_t *zone);
isc_result_t
dns_zone_link(dns_zone_t *zone, dns_zone_t *raw);
void
dns_zone_getsecure(dns_zone_t *zone, dns_zone_t **secure);
void
dns_zone_getraw(dns_zone_t *zone, dns_zone_t **raw);
bool
dns_zone_israw(dns_zone_t *zone);
isc_result_t
dns_zone_keydone(dns_zone_t *zone, const char *data);
+46 -16
View File
@@ -1057,27 +1057,58 @@ failure:
}
static isc_result_t
find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
isc_mem_t *mctx, unsigned int maxkeys, dst_key_t **keys,
unsigned int *nkeys) {
find_zone_keys(dns_zone_t *zone, isc_mem_t *mctx, unsigned int maxkeys,
dst_key_t **keys, unsigned int *nkeys) {
dns_dnsseckeylist_t keylist;
dns_dnsseckey_t *key = NULL;
dns_dnsseckey_t *key_next = NULL;
isc_result_t result;
unsigned int count = 0;
isc_stdtime_t now;
dns_dbnode_t *node = NULL;
const char *directory = dns_zone_getkeydirectory(zone);
CHECK(dns_db_findnode(db, dns_db_origin(db), false, &node));
isc_stdtime_get(&now);
ISC_LIST_INIT(keylist);
dns_zone_lock_keyfiles(zone);
result = dns_dnssec_findzonekeys(db, ver, node, dns_db_origin(db),
directory, now, mctx, maxkeys, keys,
nkeys);
result = dns_dnssec_findmatchingkeys(dns_zone_getorigin(zone),
dns_zone_getkeydirectory(zone),
now, mctx, &keylist);
dns_zone_unlock_keyfiles(zone);
failure:
if (node != NULL) {
dns_db_detachnode(db, &node);
if (result != ISC_R_SUCCESS) {
goto failure;
}
/* Add new 'dnskeys' to 'keys' */
count = 0;
for (dns_dnsseckey_t *k = ISC_LIST_HEAD(keylist); k != NULL;
k = key_next) {
key_next = ISC_LIST_NEXT(k, link);
if (count >= maxkeys) {
goto failure;
}
/* Detect inactive keys */
if (!dns_dnssec_keyactive(k->key, now)) {
dst_key_setinactive(k->key, true);
}
keys[count] = k->key;
k->key = NULL;
ISC_LIST_UNLINK(keylist, k, link);
dns_dnsseckey_destroy(mctx, &k);
count++;
}
failure:
while (!ISC_LIST_EMPTY(keylist)) {
key = ISC_LIST_HEAD(keylist);
ISC_LIST_UNLINK(keylist, key, link);
dns_dnsseckey_destroy(mctx, &key);
}
*nkeys = count;
return (result);
}
@@ -1550,9 +1581,8 @@ dns_update_signaturesinc(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
state->nkeys = 0;
state->build_nsec3 = false;
result = find_zone_keys(zone, db, newver, diff->mctx,
DNS_MAXZONEKEYS, state->zone_keys,
&state->nkeys);
result = find_zone_keys(zone, diff->mctx, DNS_MAXZONEKEYS,
state->zone_keys, &state->nkeys);
if (result != ISC_R_SUCCESS) {
update_log(log, zone, ISC_LOG_ERROR,
"could not get zone keys for secure "
+27
View File
@@ -5921,6 +5921,10 @@ dns_kasp_t *
dns_zone_getkasp(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
if (inline_raw(zone) && zone->secure != NULL) {
return (zone->secure->kasp);
}
return (zone->kasp);
}
@@ -22559,6 +22563,29 @@ dns_zone_getraw(dns_zone_t *zone, dns_zone_t **raw) {
UNLOCK(&zone->lock);
}
void
dns_zone_getsecure(dns_zone_t *zone, dns_zone_t **secure) {
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(secure != NULL && *secure == NULL);
LOCK(&zone->lock);
INSIST(zone != zone->secure);
if (zone->secure != NULL) {
dns_zone_attach(zone->secure, secure);
}
UNLOCK(&zone->lock);
}
bool
dns_zone_israw(dns_zone_t *zone) {
bool result;
REQUIRE(DNS_ZONE_VALID(zone));
LOCK(&zone->lock);
result = zone->secure != NULL;
UNLOCK(&zone->lock);
return (result);
}
struct keydone {
isc_event_t event;
bool all;
+436 -147
View File
@@ -2606,13 +2606,21 @@ static void
update_action(isc_task_t *task, isc_event_t *event) {
update_event_t *uev = (update_event_t *)event;
dns_zone_t *zone = uev->zone;
dns_zone_t *securezone = NULL;
dns_zone_t *updatezone = NULL;
ns_client_t *client = (ns_client_t *)event->ev_arg;
isc_result_t result;
dns_db_t *db = NULL;
dns_db_t *securedb = NULL;
dns_db_t *updatedb = NULL;
dns_dbversion_t *oldver = NULL;
dns_dbversion_t *ver = NULL;
dns_diff_t diff; /* Pending updates. */
dns_diff_t temp; /* Pending RR existence assertions. */
dns_dbversion_t *secureoldver = NULL;
dns_dbversion_t *securever = NULL;
dns_dbversion_t *updatever = NULL;
dns_diff_t diff; /* Pending updates. */
dns_diff_t securediff; /* Pending updates (secure zone). */
dns_diff_t temp; /* Pending RR existence assertions. */
bool soa_serial_changed = false;
isc_mem_t *mctx = client->manager->mctx;
dns_rdatatype_t covers;
@@ -2634,16 +2642,22 @@ update_action(isc_task_t *task, isc_event_t *event) {
size_t ruleslen = 0;
size_t rule;
const dns_ssurule_t **rules = NULL;
bool rawzone_done = false;
INSIST(event->ev_type == DNS_EVENT_UPDATE);
dns_diff_init(mctx, &diff);
dns_diff_init(mctx, &securediff);
dns_diff_init(mctx, &temp);
CHECK(dns_zone_getdb(zone, &db));
zonename = dns_db_origin(db);
zoneclass = dns_db_class(db);
dns_zone_getssutable(zone, &ssutable);
if (dns_zone_israw(zone)) {
dns_zone_getsecure(zone, &securezone);
CHECK(dns_zone_getdb(securezone, &securedb));
}
/*
* Update message processing can leak record existence information
@@ -2658,11 +2672,14 @@ update_action(isc_task_t *task, isc_event_t *event) {
*/
dns_db_currentversion(db, &oldver);
CHECK(dns_db_newversion(db, &ver));
if (securedb != NULL) {
dns_db_currentversion(securedb, &secureoldver);
CHECK(dns_db_newversion(securedb, &securever));
}
/*
* Check prerequisites.
*/
for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE);
result == ISC_R_SUCCESS;
result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE))
@@ -2702,8 +2719,16 @@ update_action(isc_task_t *task, isc_event_t *event) {
"satisfied");
}
} else {
CHECK(rrset_exists(db, ver, name, rdata.type,
covers, &flag));
if (rdata.type == dns_rdatatype_dnskey &&
securedb != NULL) {
CHECK(rrset_exists(securedb, securever,
name, rdata.type,
covers, &flag));
} else {
CHECK(rrset_exists(db, ver, name,
rdata.type, covers,
&flag));
}
if (!flag) {
/* RRset does not exist. */
PREREQFAILNT(DNS_R_NXRRSET, name,
@@ -2730,8 +2755,16 @@ update_action(isc_task_t *task, isc_event_t *event) {
"satisfied");
}
} else {
CHECK(rrset_exists(db, ver, name, rdata.type,
covers, &flag));
if (rdata.type == dns_rdatatype_dnskey &&
securedb != NULL) {
CHECK(rrset_exists(securedb, securever,
name, rdata.type,
covers, &flag));
} else {
CHECK(rrset_exists(db, ver, name,
rdata.type, covers,
&flag));
}
if (flag) {
/* RRset exists. */
PREREQFAILNT(DNS_R_YXRRSET, name,
@@ -3009,6 +3042,35 @@ update_action(isc_task_t *task, isc_event_t *event) {
get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name,
&rdata, &covers, &ttl, &update_class);
if (rdata.type == dns_rdatatype_dnskey && securedb != NULL) {
isc_buffer_t b;
dst_key_t *keyp = NULL;
updatedb = securedb;
updatever = securever;
/* Create key files for this new DNSKEY */
isc_buffer_init(&b, rdata.data, rdata.length);
isc_buffer_add(&b, rdata.length);
result = dst_key_fromdns(dns_db_origin(db), zoneclass,
&b, dns_zone_getmctx(zone),
&keyp);
if (result != ISC_R_SUCCESS) {
update_log(client, zone, LOGLEVEL_PROTOCOL,
"attempt to add key file failed");
} else {
result = dst_key_tofile(
keyp,
(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE),
dns_zone_getkeydirectory(zone));
}
if (result != ISC_R_SUCCESS) {
update_log(client, zone, LOGLEVEL_PROTOCOL,
"attempt to add key file failed");
}
} else {
updatedb = db;
updatever = ver;
}
if (update_class == zoneclass) {
unsigned int max = 0;
@@ -3043,7 +3105,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
}
if (rdata.type == dns_rdatatype_cname) {
CHECK(cname_incompatible_rrset_exists(
db, ver, name, &flag));
updatedb, updatever, name, &flag));
if (flag) {
update_log(client, zone,
LOGLEVEL_PROTOCOL,
@@ -3053,7 +3115,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
continue;
}
} else {
CHECK(rrset_exists(db, ver, name,
CHECK(rrset_exists(updatedb, updatever, name,
dns_rdatatype_cname, 0,
&flag));
if (flag && !dns_rdatatype_atcname(rdata.type))
@@ -3067,7 +3129,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
}
if (rdata.type == dns_rdatatype_soa) {
bool ok;
CHECK(rrset_exists(db, ver, name,
CHECK(rrset_exists(updatedb, updatever, name,
dns_rdatatype_soa, 0,
&flag));
if (!flag) {
@@ -3077,8 +3139,8 @@ update_action(isc_task_t *task, isc_event_t *event) {
"SOA ignored");
continue;
}
CHECK(check_soa_increment(db, ver, &rdata,
&ok));
CHECK(check_soa_increment(updatedb, updatever,
&rdata, &ok));
if (!ok) {
update_log(client, zone,
LOGLEVEL_PROTOCOL,
@@ -3087,7 +3149,9 @@ update_action(isc_task_t *task, isc_event_t *event) {
"ignoring it");
continue;
}
soa_serial_changed = true;
if (updatedb != securedb) {
soa_serial_changed = true;
}
}
if (dns_rdatatype_atparent(rdata.type) &&
@@ -3156,8 +3220,9 @@ update_action(isc_task_t *task, isc_event_t *event) {
}
if (max != 0) {
unsigned int count = 0;
CHECK(foreach_rr(db, ver, name, rdata.type,
covers, count_action, &count));
CHECK(foreach_rr(updatedb, updatever, name,
rdata.type, covers,
count_action, &count));
if (count >= max) {
update_log(client, zone,
LOGLEVEL_PROTOCOL,
@@ -3203,9 +3268,13 @@ update_action(isc_task_t *task, isc_event_t *event) {
/* Prepare the affected RRset for the addition. */
{
add_rr_prepare_ctx_t ctx;
ctx.db = db;
ctx.ver = ver;
ctx.diff = &diff;
ctx.db = updatedb;
ctx.ver = updatever;
if (securedb != NULL) {
ctx.diff = &securediff;
} else {
ctx.diff = &diff;
}
ctx.name = name;
ctx.oldname = name;
ctx.update_rr = &rdata;
@@ -3213,27 +3282,29 @@ update_action(isc_task_t *task, isc_event_t *event) {
ctx.ignore_add = false;
dns_diff_init(mctx, &ctx.del_diff);
dns_diff_init(mctx, &ctx.add_diff);
CHECK(foreach_rr(db, ver, name, rdata.type,
covers, add_rr_prepare_action,
&ctx));
CHECK(foreach_rr(updatedb, updatever, name,
rdata.type, covers,
add_rr_prepare_action, &ctx));
if (ctx.ignore_add) {
dns_diff_clear(&ctx.del_diff);
dns_diff_clear(&ctx.add_diff);
} else {
result = do_diff(&ctx.del_diff, db, ver,
&diff);
result = do_diff(&ctx.del_diff,
updatedb, updatever,
ctx.diff);
if (result == ISC_R_SUCCESS) {
result = do_diff(&ctx.add_diff,
db, ver,
&diff);
result = do_diff(
&ctx.add_diff, updatedb,
updatever, ctx.diff);
}
if (result != ISC_R_SUCCESS) {
dns_diff_clear(&ctx.del_diff);
dns_diff_clear(&ctx.add_diff);
goto failure;
}
CHECK(update_one_rr(db, ver, &diff,
CHECK(update_one_rr(updatedb, updatever,
ctx.diff,
DNS_DIFFOP_ADD,
name, ttl, &rdata));
}
@@ -3251,16 +3322,36 @@ update_action(isc_task_t *task, isc_event_t *event) {
"name '%s'",
namestr);
}
if (dns_name_equal(name, zonename)) {
CHECK(delete_if(type_not_soa_nor_ns_p,
db, ver, name,
dns_rdatatype_any, 0,
&rdata, &diff));
if (securedb != NULL) {
if (dns_name_equal(name, zonename)) {
CHECK(delete_if(
type_not_soa_nor_ns_p,
updatedb, updatever,
name, dns_rdatatype_any,
0, &rdata,
&securediff));
} else {
CHECK(delete_if(
type_not_dnssec,
updatedb, updatever,
name, dns_rdatatype_any,
0, &rdata,
&securediff));
}
} else {
CHECK(delete_if(type_not_dnssec, db,
ver, name,
dns_rdatatype_any, 0,
&rdata, &diff));
if (dns_name_equal(name, zonename)) {
CHECK(delete_if(
type_not_soa_nor_ns_p,
updatedb, updatever,
name, dns_rdatatype_any,
0, &rdata, &diff));
} else {
CHECK(delete_if(
type_not_dnssec,
updatedb, updatever,
name, dns_rdatatype_any,
0, &rdata, &diff));
}
}
} else if (dns_name_equal(name, zonename) &&
(rdata.type == dns_rdatatype_soa ||
@@ -3285,9 +3376,17 @@ update_action(isc_task_t *task, isc_event_t *event) {
"deleting rrset at '%s' %s",
namestr, typestr);
}
CHECK(delete_if(true_p, db, ver, name,
rdata.type, covers, &rdata,
&diff));
if (securedb != NULL) {
CHECK(delete_if(true_p, updatedb,
updatever, name,
rdata.type, covers,
&rdata, &securediff));
} else {
CHECK(delete_if(true_p, updatedb,
updatever, name,
rdata.type, covers,
&rdata, &diff));
}
}
} else if (update_class == dns_rdataclass_none) {
char namestr[DNS_NAME_FORMATSIZE];
@@ -3307,9 +3406,9 @@ update_action(isc_task_t *task, isc_event_t *event) {
}
if (rdata.type == dns_rdatatype_ns) {
int count;
CHECK(rr_count(db, ver, name,
dns_rdatatype_ns, 0,
&count));
CHECK(rr_count(updatedb, updatever,
name, dns_rdatatype_ns,
0, &count));
if (count == 1) {
update_log(client, zone,
LOGLEVEL_PROTOCOL,
@@ -3325,8 +3424,15 @@ update_action(isc_task_t *task, isc_event_t *event) {
sizeof(typestr));
update_log(client, zone, LOGLEVEL_PROTOCOL,
"deleting an RR at %s %s", namestr, typestr);
CHECK(delete_if(rr_equal_p, db, ver, name, rdata.type,
covers, &rdata, &diff));
if (securedb != NULL) {
CHECK(delete_if(rr_equal_p, updatedb, updatever,
name, rdata.type, covers,
&rdata, &securediff));
} else {
CHECK(delete_if(rr_equal_p, updatedb, updatever,
name, rdata.type, covers,
&rdata, &diff));
}
}
}
if (result != ISC_R_NOMORE) {
@@ -3338,8 +3444,15 @@ update_action(isc_task_t *task, isc_event_t *event) {
* If they don't then back out all changes to DNSKEY/NSEC3PARAM
* records.
*/
if (!ISC_LIST_EMPTY(diff.tuples)) {
CHECK(check_dnssec(client, zone, db, ver, &diff));
if (securedb != NULL) {
if (!ISC_LIST_EMPTY(securediff.tuples)) {
CHECK(check_dnssec(client, zone, securedb, securever,
&securediff));
}
} else {
if (!ISC_LIST_EMPTY(diff.tuples)) {
CHECK(check_dnssec(client, zone, db, ver, &diff));
}
}
if (!ISC_LIST_EMPTY(diff.tuples)) {
@@ -3353,26 +3466,34 @@ update_action(isc_task_t *task, isc_event_t *event) {
goto failure;
}
}
if (!ISC_LIST_EMPTY(diff.tuples)) {
result = dns_zone_cdscheck(zone, db, ver);
if (result == DNS_R_BADCDS || result == DNS_R_BADCDNSKEY) {
update_log(client, zone, LOGLEVEL_PROTOCOL,
"update rejected: bad %s RRset",
result == DNS_R_BADCDS ? "CDS" : "CDNSKEY");
result = DNS_R_REFUSED;
goto failure;
if (securedb != NULL) {
if (!ISC_LIST_EMPTY(securediff.tuples)) {
result = dns_zone_cdscheck(zone, securedb, securever);
}
if (result != ISC_R_SUCCESS) {
goto failure;
} else {
if (!ISC_LIST_EMPTY(diff.tuples)) {
result = dns_zone_cdscheck(zone, db, ver);
}
}
if (result == DNS_R_BADCDS || result == DNS_R_BADCDNSKEY) {
update_log(client, zone, LOGLEVEL_PROTOCOL,
"update rejected: bad %s RRset",
result == DNS_R_BADCDS ? "CDS" : "CDNSKEY");
result = DNS_R_REFUSED;
goto failure;
}
if (result != ISC_R_SUCCESS) {
goto failure;
}
/*
* If any changes were made, increment the SOA serial number,
* update RRSIGs and NSECs (if zone is secure), and write the update
* to the journal.
*/
if (!ISC_LIST_EMPTY(diff.tuples)) {
if (!ISC_LIST_EMPTY(diff.tuples) || !ISC_LIST_EMPTY(securediff.tuples))
{
char *journalfile;
dns_journal_t *journal;
bool has_dnskey;
@@ -3385,37 +3506,81 @@ update_action(isc_task_t *task, isc_event_t *event) {
CHECK(update_soa_serial(
db, ver, &diff, mctx,
dns_zone_getserialupdatemethod(zone)));
if (securedb != NULL) {
CHECK(update_soa_serial(
securedb, securever, &securediff, mctx,
dns_zone_getserialupdatemethod(
securezone)));
}
}
CHECK(check_mx(client, zone, db, ver, &diff));
CHECK(remove_orphaned_ds(db, ver, &diff));
CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey, 0,
&has_dnskey));
if (securedb != NULL) {
CHECK(rrset_exists(securedb, securever, zonename,
dns_rdatatype_dnskey, 0,
&has_dnskey));
} else {
CHECK(rrset_exists(db, ver, zonename,
dns_rdatatype_dnskey, 0,
&has_dnskey));
}
#define ALLOW_SECURE_TO_INSECURE(zone) \
((dns_zone_getoptions(zone) & DNS_ZONEOPT_SECURETOINSECURE) != 0)
CHECK(rrset_exists(db, oldver, zonename, dns_rdatatype_dnskey,
0, &had_dnskey));
if (!ALLOW_SECURE_TO_INSECURE(zone)) {
if (had_dnskey && !has_dnskey) {
update_log(client, zone, LOGLEVEL_PROTOCOL,
"update rejected: all DNSKEY "
"records removed and "
"'dnssec-secure-to-insecure' "
"not set");
result = DNS_R_REFUSED;
goto failure;
if (securedb != NULL) {
CHECK(rrset_exists(securedb, secureoldver, zonename,
dns_rdatatype_dnskey, 0,
&had_dnskey));
if (!ALLOW_SECURE_TO_INSECURE(zone)) {
if (had_dnskey && !has_dnskey) {
update_log(
client, securezone,
LOGLEVEL_PROTOCOL,
"update rejected: all DNSKEY "
"records removed and "
"'dnssec-secure-to-insecure' "
"not set");
result = DNS_R_REFUSED;
goto failure;
}
}
} else {
CHECK(rrset_exists(db, oldver, zonename,
dns_rdatatype_dnskey, 0,
&had_dnskey));
if (!ALLOW_SECURE_TO_INSECURE(zone)) {
if (had_dnskey && !has_dnskey) {
update_log(
client, zone, LOGLEVEL_PROTOCOL,
"update rejected: all DNSKEY "
"records removed and "
"'dnssec-secure-to-insecure' "
"not set");
result = DNS_R_REFUSED;
goto failure;
}
}
}
CHECK(rollback_private(db, privatetype, ver, &diff));
CHECK(add_signing_records(db, privatetype, ver, &diff));
CHECK(add_nsec3param_records(client, zone, db, ver, &diff));
if (securedb != NULL) {
CHECK(rollback_private(securedb, privatetype, securever,
&securediff));
CHECK(add_signing_records(securedb, privatetype,
securever, &securediff));
CHECK(add_nsec3param_records(client, securezone,
securedb, securever,
&securediff));
} else {
CHECK(rollback_private(db, privatetype, ver, &diff));
CHECK(add_signing_records(db, privatetype, ver, &diff));
CHECK(add_nsec3param_records(client, zone, updatedb,
ver, &diff));
}
if (had_dnskey && !has_dnskey) {
/*
@@ -3424,9 +3589,35 @@ update_action(isc_task_t *task, isc_event_t *event) {
* the last signature for the DNSKEY records are
* remove any NSEC chain present will also be removed.
*/
CHECK(dns_nsec3param_deletechains(db, ver, zone, true,
&diff));
} else if (has_dnskey && isdnssec(db, ver, privatetype)) {
if (securedb != NULL) {
CHECK(dns_nsec3param_deletechains(
securedb, securever, securezone, true,
&securediff));
} else {
CHECK(dns_nsec3param_deletechains(db, ver, zone,
true, &diff));
}
} else if (securezone != NULL && has_dnskey &&
isdnssec(securedb, securever, privatetype))
{
dns_update_log_t log;
uint32_t interval =
dns_zone_getsigvalidityinterval(securezone);
log.func = update_log_cb;
log.arg = client;
result = dns_update_signatures(
&log, securezone, securedb, secureoldver,
securever, &securediff, interval);
if (result != ISC_R_SUCCESS) {
update_log(client, securezone, ISC_LOG_ERROR,
"RRSIG/NSEC/NSEC3 update failed: %s",
isc_result_totext(result));
goto failure;
}
} else if (zone != NULL && has_dnskey &&
isdnssec(db, ver, privatetype)) {
dns_update_log_t log;
uint32_t interval =
dns_zone_getsigvalidityinterval(zone);
@@ -3444,11 +3635,24 @@ update_action(isc_task_t *task, isc_event_t *event) {
}
}
maxrecords = dns_zone_getmaxrecords(zone);
if (securezone != NULL) {
updatezone = securezone;
updatedb = securedb;
updatever = securever;
} else {
updatezone = zone;
updatedb = db;
updatever = ver;
rawzone_done = true;
}
apply_update:
maxrecords = dns_zone_getmaxrecords(updatezone);
if (maxrecords != 0U) {
result = dns_db_getsize(db, ver, &records, NULL);
result = dns_db_getsize(updatedb, updatever, &records,
NULL);
if (result == ISC_R_SUCCESS && records > maxrecords) {
update_log(client, zone, ISC_LOG_ERROR,
update_log(client, updatezone, ISC_LOG_ERROR,
"records in zone (%" PRIu64 ") "
"exceeds"
" max-"
@@ -3460,9 +3664,9 @@ update_action(isc_task_t *task, isc_event_t *event) {
}
}
journalfile = dns_zone_getjournal(zone);
journalfile = dns_zone_getjournal(updatezone);
if (journalfile != NULL) {
update_log(client, zone, LOGLEVEL_DEBUG,
update_log(client, updatezone, LOGLEVEL_DEBUG,
"writing journal %s", journalfile);
journal = NULL;
@@ -3472,7 +3676,13 @@ update_action(isc_task_t *task, isc_event_t *event) {
FAILS(result, "journal open failed");
}
result = dns_journal_write_transaction(journal, &diff);
if (rawzone_done) {
result = dns_journal_write_transaction(journal,
&diff);
} else {
result = dns_journal_write_transaction(
journal, &securediff);
}
if (result != ISC_R_SUCCESS) {
dns_journal_destroy(&journal);
FAILS(result, "journal write failed");
@@ -3486,20 +3696,25 @@ update_action(isc_task_t *task, isc_event_t *event) {
* to change to handle databases that need two-phase
* commit, but this isn't a priority.
*/
update_log(client, zone, LOGLEVEL_DEBUG,
update_log(client, updatezone, LOGLEVEL_DEBUG,
"committing update transaction");
dns_db_closeversion(db, &ver, true);
dns_db_closeversion(updatedb, &updatever, true);
if (rawzone_done) {
ver = NULL;
} else {
securever = NULL;
}
/*
* Mark the zone as dirty so that it will be written to disk.
*/
dns_zone_markdirty(zone);
dns_zone_markdirty(updatezone);
/*
* Notify secondaries of the change we just made.
*/
dns_zone_notify(zone);
dns_zone_notify(updatezone);
/*
* Cause the zone to be signed with the key that we
@@ -3508,76 +3723,134 @@ update_action(isc_task_t *task, isc_event_t *event) {
*
* Note: we are already committed to this course of action.
*/
for (tuple = ISC_LIST_HEAD(diff.tuples); tuple != NULL;
tuple = ISC_LIST_NEXT(tuple, link))
{
isc_region_t r;
dns_secalg_t algorithm;
uint16_t keyid;
if (tuple->rdata.type != dns_rdatatype_dnskey) {
continue;
}
dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
if ((dnskey.flags &
(DNS_KEYFLAG_OWNERMASK | DNS_KEYTYPE_NOAUTH)) !=
DNS_KEYOWNER_ZONE)
if (rawzone_done) {
for (tuple = ISC_LIST_HEAD(diff.tuples); tuple != NULL;
tuple = ISC_LIST_NEXT(tuple, link))
{
continue;
isc_region_t r;
dns_secalg_t algorithm;
uint16_t keyid;
if (tuple->rdata.type != dns_rdatatype_dnskey) {
continue;
}
dns_rdata_tostruct(&tuple->rdata, &dnskey,
NULL);
if ((dnskey.flags & (DNS_KEYFLAG_OWNERMASK |
DNS_KEYTYPE_NOAUTH)) !=
DNS_KEYOWNER_ZONE)
{
continue;
}
dns_rdata_toregion(&tuple->rdata, &r);
algorithm = dnskey.algorithm;
keyid = dst_region_computeid(&r);
result = dns_zone_signwithkey(
updatezone, algorithm, keyid,
(tuple->op == DNS_DIFFOP_DEL));
if (result != ISC_R_SUCCESS) {
update_log(client, updatezone,
ISC_LOG_ERROR,
"dns_zone_signwithkey "
"failed: %s",
isc_result_totext(result));
}
}
} else {
for (tuple = ISC_LIST_HEAD(securediff.tuples);
tuple != NULL; tuple = ISC_LIST_NEXT(tuple, link))
{
isc_region_t r;
dns_secalg_t algorithm;
uint16_t keyid;
if (tuple->rdata.type != dns_rdatatype_dnskey) {
continue;
}
dns_rdata_tostruct(&tuple->rdata, &dnskey,
NULL);
if ((dnskey.flags & (DNS_KEYFLAG_OWNERMASK |
DNS_KEYTYPE_NOAUTH)) !=
DNS_KEYOWNER_ZONE)
{
continue;
}
dns_rdata_toregion(&tuple->rdata, &r);
algorithm = dnskey.algorithm;
keyid = dst_region_computeid(&r);
result = dns_zone_signwithkey(
updatezone, algorithm, keyid,
(tuple->op == DNS_DIFFOP_DEL));
if (result != ISC_R_SUCCESS) {
update_log(client, updatezone,
ISC_LOG_ERROR,
"dns_zone_signwithkey "
"failed: %s",
isc_result_totext(result));
}
}
dns_rdata_toregion(&tuple->rdata, &r);
algorithm = dnskey.algorithm;
keyid = dst_region_computeid(&r);
/*
* Cause the zone to add/delete NSEC3 chains for the
* deferred NSEC3PARAM changes.
*
* Note: we are already committed to this course of
* action.
*/
for (tuple = ISC_LIST_HEAD(securediff.tuples);
tuple != NULL; tuple = ISC_LIST_NEXT(tuple, link))
{
unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_nsec3param_t nsec3param;
result = dns_zone_signwithkey(
zone, algorithm, keyid,
(tuple->op == DNS_DIFFOP_DEL));
if (result != ISC_R_SUCCESS) {
update_log(client, zone, ISC_LOG_ERROR,
"dns_zone_signwithkey failed: %s",
isc_result_totext(result));
if (tuple->rdata.type != privatetype ||
tuple->op != DNS_DIFFOP_ADD) {
continue;
}
if (!dns_nsec3param_fromprivate(&tuple->rdata,
&rdata, buf,
sizeof(buf))) {
continue;
}
dns_rdata_tostruct(&rdata, &nsec3param, NULL);
if (nsec3param.flags == 0) {
continue;
}
result = dns_zone_addnsec3chain(updatezone,
&nsec3param);
if (result != ISC_R_SUCCESS) {
update_log(client, updatezone,
ISC_LOG_ERROR,
"dns_zone_addnsec3chain "
"failed: %s",
isc_result_totext(result));
}
}
}
/*
* Cause the zone to add/delete NSEC3 chains for the
* deferred NSEC3PARAM changes.
*
* Note: we are already committed to this course of action.
*/
for (tuple = ISC_LIST_HEAD(diff.tuples); tuple != NULL;
tuple = ISC_LIST_NEXT(tuple, link))
{
unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_nsec3param_t nsec3param;
if (tuple->rdata.type != privatetype ||
tuple->op != DNS_DIFFOP_ADD) {
continue;
}
if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata,
buf, sizeof(buf))) {
continue;
}
dns_rdata_tostruct(&rdata, &nsec3param, NULL);
if (nsec3param.flags == 0) {
continue;
}
result = dns_zone_addnsec3chain(zone, &nsec3param);
if (result != ISC_R_SUCCESS) {
update_log(client, zone, ISC_LOG_ERROR,
"dns_zone_addnsec3chain failed: %s",
isc_result_totext(result));
}
if (!rawzone_done) {
updatezone = zone;
updatedb = db;
updatever = ver;
rawzone_done = true;
goto apply_update;
}
} else {
update_log(client, zone, LOGLEVEL_DEBUG, "redundant request");
dns_db_closeversion(db, &ver, true);
if (securedb != NULL) {
dns_db_closeversion(securedb, &securever, true);
}
}
result = ISC_R_SUCCESS;
goto common;
@@ -3590,6 +3863,10 @@ failure:
update_log(client, zone, LOGLEVEL_DEBUG, "rolling back");
dns_db_closeversion(db, &ver, false);
}
if (securever != NULL) {
update_log(client, securezone, LOGLEVEL_DEBUG, "rolling back");
dns_db_closeversion(securedb, &securever, false);
}
common:
dns_diff_clear(&temp);
@@ -3598,10 +3875,16 @@ common:
if (oldver != NULL) {
dns_db_closeversion(db, &oldver, false);
}
if (secureoldver != NULL) {
dns_db_closeversion(securedb, &secureoldver, false);
}
if (db != NULL) {
dns_db_detach(&db);
}
if (securedb != NULL) {
dns_db_detach(&securedb);
}
if (rules != NULL) {
isc_mem_put(mctx, rules, sizeof(*rules) * ruleslen);
@@ -3622,6 +3905,7 @@ common:
isc_task_send(client->manager->task, &event);
INSIST(ver == NULL);
INSIST(securever == NULL);
INSIST(event == NULL);
}
@@ -3649,6 +3933,11 @@ updatedone_action(isc_task_t *task, isc_event_t *event) {
break;
}
if (uev->zone != NULL) {
dns_zone_t *secure = NULL;
if (dns_zone_israw(uev->zone)) {
dns_zone_getsecure(uev->zone, &secure);
dns_zone_detach(&secure);
}
dns_zone_detach(&uev->zone);
}