From: Michał Kępień Date: Fri, 16 Mar 2018 23:12:23 +0000 (+0100) Subject: Apply raw zone deltas to yet unsigned secure zones X-Git-Tag: v9.9.13rc1~32^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b0f7f1b8d8056185ea2d6d76e99b119808fa0b0;p=thirdparty%2Fbind9.git Apply raw zone deltas to yet unsigned secure zones When inline signing is enabled for a zone without creating signing keys for it, changes subsequently applied to the raw zone will not be reflected in the secure zone due to the dns_update_signaturesinc() call inside receive_secure_serial() failing. Given that an inline zone will be served (without any signatures) even with no associated signing keys being present, keep applying raw zone deltas to the secure zone until keys become available in an attempt to follow the principle of least astonishment. (cherry picked from commit 6acf326969862c68559d699be113c28dc35b35e6) (cherry picked from commit 8a58a607723682c167d22e1bc5372e84a21e7f1f) (cherry picked from commit fcbdeed802e21bc9a761003b9dbf30514807f2dd) --- diff --git a/bin/tests/system/inline/clean.sh b/bin/tests/system/inline/clean.sh index 34c4c76f496..0f9092186b5 100644 --- a/bin/tests/system/inline/clean.sh +++ b/bin/tests/system/inline/clean.sh @@ -15,6 +15,7 @@ rm -f */named.conf rm -f */named.memstats rm -f */named.run +rm -f */named.run.prev rm -f */trusted.conf rm -f ns1/K* rm -f ns1/dsset-* @@ -28,6 +29,10 @@ rm -f ns2/inactiveksk.db rm -f ns2/inactiveksk.db.jnl rm -f ns2/inactivezsk.db rm -f ns2/inactivezsk.db.jnl +rm -f ns2/nokeys.db +rm -f ns2/nokeys.db.jnl +rm -f ns2/removedkeys-secondary.db +rm -f ns2/removedkeys-secondary.db.jnl rm -f ns2/retransfer.db rm -f ns2/retransfer.db.jnl rm -f ns2/retransfer3.db @@ -65,10 +70,22 @@ rm -f ns3/inactivezsk.bk rm -f ns3/inactivezsk.bk.jnl rm -f ns3/inactivezsk.bk.signed rm -f ns3/inactivezsk.bk.signed.jnl +rm -f ns3/nokeys.bk +rm -f ns3/nokeys.bk.jnl +rm -f ns3/nokeys.bk.signed +rm -f ns3/nokeys.bk.signed.jnl rm -f ns3/nsec3.db rm -f ns3/nsec3.db.jnl rm -f ns3/nsec3.db.signed rm -f ns3/nsec3.db.signed.jnl +rm -f ns3/removedkeys-primary.db +rm -f ns3/removedkeys-primary.db.jnl +rm -f ns3/removedkeys-primary.db.signed +rm -f ns3/removedkeys-primary.db.signed.jnl +rm -f ns3/removedkeys-secondary.bk +rm -f ns3/removedkeys-secondary.bk.jnl +rm -f ns3/removedkeys-secondary.bk.signed +rm -f ns3/removedkeys-secondary.bk.signed.jnl rm -f ns3/retransfer.bk rm -f ns3/retransfer.bk.jnl rm -f ns3/retransfer.bk.signed @@ -105,3 +122,4 @@ rm -f import.key Kimport* rm -f checkgost checkdsa checkecdsa rm -f ns3/a-file rm -f dig.out.* +rm -rf ns3/removedkeys diff --git a/bin/tests/system/inline/ns2/named.conf.in b/bin/tests/system/inline/ns2/named.conf.in index 81c2072f874..c7841d3321a 100644 --- a/bin/tests/system/inline/ns2/named.conf.in +++ b/bin/tests/system/inline/ns2/named.conf.in @@ -73,3 +73,15 @@ zone "inactivezsk" { file "inactivezsk.db"; allow-update { any; }; }; + +zone "nokeys" { + type master; + file "nokeys.db"; + allow-update { any; }; +}; + +zone "removedkeys-secondary" { + type master; + file "removedkeys-secondary.db"; + allow-update { any; }; +}; diff --git a/bin/tests/system/inline/ns3/named.conf.in b/bin/tests/system/inline/ns3/named.conf.in index 1cf78a4f418..4f0b67bfd9b 100644 --- a/bin/tests/system/inline/ns3/named.conf.in +++ b/bin/tests/system/inline/ns3/named.conf.in @@ -137,3 +137,28 @@ zone "inactivezsk" { auto-dnssec maintain; file "inactivezsk.bk"; }; + +zone "nokeys" { + type slave; + masters { 10.53.0.2; }; + inline-signing yes; + auto-dnssec maintain; + file "nokeys.bk"; +}; + +zone "removedkeys-primary" { + type master; + inline-signing yes; + auto-dnssec maintain; + allow-update { any; }; + also-notify { 10.53.0.2; }; + file "removedkeys-primary.db"; +}; + +zone "removedkeys-secondary" { + type slave; + masters { 10.53.0.2; }; + inline-signing yes; + auto-dnssec maintain; + file "removedkeys-secondary.bk"; +}; diff --git a/bin/tests/system/inline/ns3/sign.sh b/bin/tests/system/inline/ns3/sign.sh index e53681124bd..7b8fa59aaee 100755 --- a/bin/tests/system/inline/ns3/sign.sh +++ b/bin/tests/system/inline/ns3/sign.sh @@ -101,6 +101,18 @@ keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA256 -b 1024 -n zone $zone` keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA256 -b 1024 -n zone -f KSK $zone` $DSFROMKEY -T 1200 $keyname >> ../ns1/root.db +zone=removedkeys-primary +rm -f K${zone}.+*+*.key +rm -f K${zone}.+*+*.private +keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone $zone` +keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone -f KSK $zone` + +zone=removedkeys-secondary +rm -f K${zone}.+*+*.key +rm -f K${zone}.+*+*.private +keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone $zone` +keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone -f KSK $zone` + for s in a c d h k l m q z do zone=test-$s diff --git a/bin/tests/system/inline/setup.sh b/bin/tests/system/inline/setup.sh index f3f1abaafa0..434ac5544af 100644 --- a/bin/tests/system/inline/setup.sh +++ b/bin/tests/system/inline/setup.sh @@ -26,6 +26,8 @@ touch ns2/trusted.conf cp ns2/bits.db.in ns2/bits.db cp ns2/bits.db.in ns2/inactiveksk.db cp ns2/bits.db.in ns2/inactivezsk.db +cp ns2/bits.db.in ns2/nokeys.db +cp ns2/bits.db.in ns2/removedkeys-secondary.db cp ns2/bits.db.in ns2/retransfer.db cp ns2/bits.db.in ns2/retransfer3.db rm -f ns2/bits.db.jnl @@ -36,6 +38,9 @@ cp ns3/master.db.in ns3/updated.db cp ns3/master.db.in ns3/expired.db cp ns3/master.db.in ns3/nsec3.db cp ns3/master.db.in ns3/externalkey.db +cp ns3/master.db.in ns3/removedkeys-primary.db + +mkdir ns3/removedkeys touch ns4/trusted.conf cp ns4/noixfr.db.in ns4/noixfr.db diff --git a/bin/tests/system/inline/tests.sh b/bin/tests/system/inline/tests.sh index 95ab9756539..02afcef2f1f 100755 --- a/bin/tests/system/inline/tests.sh +++ b/bin/tests/system/inline/tests.sh @@ -1003,5 +1003,164 @@ grep "DNSKEY 8 1 [0-9]* [0-9]* [0-9]* ${kskid} " dig.out.ns3.test$n > /dev/null if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` +# Wait until an update to the raw part of a given inline signed zone is fully +# processed. As waiting for a fixed amount of time is suboptimal and there is +# no single message that would signify both a successful modification and an +# error in a race-free manner, instead wait until either notifies are sent +# (which means the secure zone was modified) or a receive_secure_serial() error +# is logged (which means the zone was not modified and will not be modified any +# further in response to the relevant raw zone update). +wait_until_raw_zone_update_is_processed() { + zone="$1" + for i in 1 2 3 4 5 6 7 8 9 10 + do + if nextpart ns3/named.run | egrep "zone ${zone}.*(sending notifies|receive_secure_serial)" > /dev/null; then + return + fi + sleep 1 + done +} + +n=`expr $n + 1` +echo_i "checking that changes to raw zone are applied to a previously unsigned secure zone ($n)" +ret=0 +# Query for bar.nokeys/A and ensure the response is negative. As this zone +# does not have any signing keys set up, the response must be unsigned. +$DIG $DIGOPTS @10.53.0.3 bar.nokeys. A > dig.out.ns3.pre.test$n 2>&1 || ret=1 +grep "status: NOERROR" dig.out.ns3.pre.test$n > /dev/null && ret=1 +grep "RRSIG" dig.out.ns3.pre.test$n > /dev/null && ret=1 +# Ensure the wait_until_raw_zone_update_is_processed() call below will ignore +# log messages generated before the raw zone is updated. +nextpart ns3/named.run > /dev/null +# Add a record to the raw zone on the master. +$NSUPDATE << EOF || ret=1 +zone nokeys. +server 10.53.0.2 ${PORT} +update add bar.nokeys. 0 A 127.0.0.1 +send +EOF +wait_until_raw_zone_update_is_processed "nokeys" +# Query for bar.nokeys/A again and ensure the signer now returns a positive, +# yet still unsigned response. +$DIG $DIGOPTS @10.53.0.3 bar.nokeys. A > dig.out.ns3.post.test$n 2>&1 +grep "status: NOERROR" dig.out.ns3.post.test$n > /dev/null || ret=1 +grep "RRSIG" dig.out.ns3.pre.test$n > /dev/null && ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking that changes to raw zone are not applied to a previously signed secure zone with no keys available (primary) ($n)" +ret=0 +# Query for bar.removedkeys-primary/A and ensure the response is negative. As +# this zone has signing keys set up, the response must be signed. +$DIG $DIGOPTS @10.53.0.3 bar.removedkeys-primary. A > dig.out.ns3.pre.test$n 2>&1 || ret=1 +grep "status: NOERROR" dig.out.ns3.pre.test$n > /dev/null && ret=1 +grep "RRSIG" dig.out.ns3.pre.test$n > /dev/null || ret=1 +# Remove the signing keys for this zone. +mv -f ns3/Kremovedkeys-primary* ns3/removedkeys +# Ensure the wait_until_raw_zone_update_is_processed() call below will ignore +# log messages generated before the raw zone is updated. +nextpart ns3/named.run > /dev/null +# Add a record to the raw zone on the master. +$NSUPDATE << EOF || ret=1 +zone removedkeys-primary. +server 10.53.0.3 ${PORT} +update add bar.removedkeys-primary. 0 A 127.0.0.1 +send +EOF +wait_until_raw_zone_update_is_processed "removedkeys-primary" +# Query for bar.removedkeys-primary/A again and ensure the signer still returns +# a negative, signed response. +$DIG $DIGOPTS @10.53.0.3 bar.removedkeys-primary. A > dig.out.ns3.post.test$n 2>&1 +grep "status: NOERROR" dig.out.ns3.post.test$n > /dev/null && ret=1 +grep "RRSIG" dig.out.ns3.pre.test$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking that backlogged changes to raw zone are applied after keys become available (primary) ($n)" +ret=0 +# Restore the signing keys for this zone. +mv ns3/removedkeys/Kremovedkeys-primary* ns3 +$RNDCCMD 10.53.0.3 loadkeys removedkeys-primary > /dev/null 2>&1 +# Determine what a SOA record with a bumped serial number should look like. +BUMPED_SOA=`sed -n 's/.*\(add removedkeys-primary.*IN.*SOA\)/\1/p;' ns3/named.run | tail -1 | awk '{$8 += 1; print $0}'` +# Ensure the wait_until_raw_zone_update_is_processed() call below will ignore +# log messages generated before the raw zone is updated. +nextpart ns3/named.run > /dev/null +# Bump the SOA serial number of the raw zone. +$NSUPDATE << EOF || ret=1 +zone removedkeys-primary. +server 10.53.0.3 ${PORT} +update del removedkeys-primary. SOA +update ${BUMPED_SOA} +send +EOF +wait_until_raw_zone_update_is_processed "removedkeys-primary" +# Query for bar.removedkeys-primary/A again and ensure the signer now returns a +# positive, signed response. +$DIG $DIGOPTS @10.53.0.3 bar.removedkeys-primary. A > dig.out.ns3.test$n 2>&1 +grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1 +grep "RRSIG" dig.out.ns3.test$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking that changes to raw zone are not applied to a previously signed secure zone with no keys available (secondary) ($n)" +ret=0 +# Query for bar.removedkeys-secondary/A and ensure the response is negative. As this +# zone does have signing keys set up, the response must be signed. +$DIG $DIGOPTS @10.53.0.3 bar.removedkeys-secondary. A > dig.out.ns3.pre.test$n 2>&1 || ret=1 +grep "status: NOERROR" dig.out.ns3.pre.test$n > /dev/null && ret=1 +grep "RRSIG" dig.out.ns3.pre.test$n > /dev/null || ret=1 +# Remove the signing keys for this zone. +mv -f ns3/Kremovedkeys-secondary* ns3/removedkeys +# Ensure the wait_until_raw_zone_update_is_processed() call below will ignore +# log messages generated before the raw zone is updated. +nextpart ns3/named.run > /dev/null +# Add a record to the raw zone on the master. +$NSUPDATE << EOF || ret=1 +zone removedkeys-secondary. +server 10.53.0.2 ${PORT} +update add bar.removedkeys-secondary. 0 A 127.0.0.1 +send +EOF +wait_until_raw_zone_update_is_processed "removedkeys-secondary" +# Query for bar.removedkeys-secondary/A again and ensure the signer still returns a +# negative, signed response. +$DIG $DIGOPTS @10.53.0.3 bar.removedkeys-secondary. A > dig.out.ns3.post.test$n 2>&1 +grep "status: NOERROR" dig.out.ns3.post.test$n > /dev/null && ret=1 +grep "RRSIG" dig.out.ns3.pre.test$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + +n=`expr $n + 1` +echo_i "checking that backlogged changes to raw zone are applied after keys become available (secondary) ($n)" +ret=0 +# Restore the signing keys for this zone. +mv ns3/removedkeys/Kremovedkeys-secondary* ns3 +$RNDCCMD 10.53.0.3 loadkeys removedkeys-secondary > /dev/null 2>&1 +# Determine what a SOA record with a bumped serial number should look like. +BUMPED_SOA=`sed -n 's/.*\(add removedkeys-secondary.*IN.*SOA\)/\1/p;' ns2/named.run | tail -1 | awk '{$8 += 1; print $0}'` +# Ensure the wait_until_raw_zone_update_is_processed() call below will ignore +# log messages generated before the raw zone is updated. +nextpart ns3/named.run > /dev/null +# Bump the SOA serial number of the raw zone on the master. +$NSUPDATE << EOF || ret=1 +zone removedkeys-secondary. +server 10.53.0.2 ${PORT} +update del removedkeys-secondary. SOA +update ${BUMPED_SOA} +send +EOF +wait_until_raw_zone_update_is_processed "removedkeys-secondary" +# Query for bar.removedkeys-secondary/A again and ensure the signer now returns +# a positive, signed response. +$DIG $DIGOPTS @10.53.0.3 bar.removedkeys-secondary. A > dig.out.ns3.test$n 2>&1 +grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1 +grep "RRSIG" dig.out.ns3.test$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1 diff --git a/lib/dns/zone.c b/lib/dns/zone.c index a840cc6c54d..208ba9ce3f0 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -13516,8 +13516,17 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) { fprintf(stderr, "looping on dns_update_signaturesinc\n"); return; } - if (result != ISC_R_SUCCESS) + /* + * If something went wrong while trying to update the secure zone and + * the latter was already signed before, do not apply raw zone deltas + * to it as that would break existing DNSSEC signatures. However, if + * the secure zone was not yet signed (e.g. because no signing keys + * were created for it), commence applying raw zone deltas to it so + * that contents of the raw zone and the secure zone are kept in sync. + */ + if (result != ISC_R_SUCCESS && dns_db_issecure(zone->rss_db)) { goto failure; + } if (rjournal == NULL) CHECK(dns_journal_open(zone->rss_raw->mctx,