diff --git a/CHANGES b/CHANGES index d3549c72ff..b10379a239 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +2800. [func] Reject zones which have NS records which refer to + CNAMEs, DNAMEs or don't have address record (class IN + only). Reject UPDATEs which would cause the zone + to fail the above checks if committed. [RT #20678] + 2799. [cleanup] Changed the "secure-to-insecure" option to "dnssec-secure-to-insecure", and "dnskey-ksk-only" to "dnssec-dnskey-kskonly", for clarity. [RT #20586] diff --git a/bin/named/update.c b/bin/named/update.c index 32feb5a11f..ad03826eb8 100644 --- a/bin/named/update.c +++ b/bin/named/update.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: update.c,v 1.173 2009/12/03 23:48:22 tbox Exp $ */ +/* $Id: update.c,v 1.174 2009/12/04 03:33:14 marka Exp $ */ #include @@ -4088,6 +4088,18 @@ update_action(isc_task_t *task, isc_event_t *event) { if (! ISC_LIST_EMPTY(diff.tuples)) CHECK(check_dnssec(client, zone, db, ver, &diff)); + if (! ISC_LIST_EMPTY(diff.tuples)) { + unsigned int errors = 0; + CHECK(dns_zone_nscheck(zone, db, ver, &errors)); + if (errors != 0) { + update_log(client, zone, LOGLEVEL_PROTOCOL, + "update rejected: post update name server " + "sanity check failed"); + result = DNS_R_REFUSED; + goto failure; + } + } + /* * If any changes were made, increment the SOA serial number, * update RRSIGs and NSECs (if zone is secure), and write the update diff --git a/bin/tests/system/nsupdate/setup.sh b/bin/tests/system/nsupdate/setup.sh index c051b1ce3d..8ade441e84 100644 --- a/bin/tests/system/nsupdate/setup.sh +++ b/bin/tests/system/nsupdate/setup.sh @@ -15,7 +15,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: setup.sh,v 1.13 2009/07/30 15:11:41 each Exp $ +# $Id: setup.sh,v 1.14 2009/12/04 03:33:15 marka Exp $ SYSTEMTESTTOP=.. . $SYSTEMTESTTOP/conf.sh @@ -43,6 +43,7 @@ update.nil IN SOA ns1.example.nil. hostmaster.example.nil. ( ) update.nil. NS ns1.update.nil. ns1.update.nil. A 10.53.0.2 +ns2.update.nil. AAAA ::1 EOF ../../../tools/genrandom 400 random.data diff --git a/bin/tests/system/zonechecks/tests.sh b/bin/tests/system/zonechecks/tests.sh index 2a1b850f59..0875b72350 100644 --- a/bin/tests/system/zonechecks/tests.sh +++ b/bin/tests/system/zonechecks/tests.sh @@ -14,7 +14,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: tests.sh,v 1.4 2007/06/19 23:47:07 tbox Exp $ +# $Id: tests.sh,v 1.5 2009/12/04 03:33:15 marka Exp $ SYSTEMTESTTOP=.. . $SYSTEMTESTTOP/conf.sh @@ -161,4 +161,4 @@ else echo "I:failed (status)"; status=1 fi echo "I:exit status: $status" -exit $? +exit $status diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 0be5b633a8..4ee5d32e06 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.h,v 1.171 2009/12/03 23:18:17 each Exp $ */ +/* $Id: zone.h,v 1.172 2009/12/04 03:33:15 marka Exp $ */ #ifndef DNS_ZONE_H #define DNS_ZONE_H 1 @@ -1782,6 +1782,25 @@ dns_zone_rekey(dns_zone_t *zone); * Update the zone's DNSKEY set from the key repository. */ +isc_result_t +dns_zone_nscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, + unsigned int *errors); +/*% + * Check if the name servers for the zone are sane (have address, don't + * refer to CNAMEs/DNAMEs. The number of constiancy errors detected in + * returned in '*errors' + * + * Requires: + * \li 'zone' to be valid. + * \li 'db' to be valid. + * \li 'version' to be valid or NULL. + * \li 'errors' to be non NULL. + * + * Returns: + * ISC_R_SUCCESS if there were no errors examining the zone contents. + */ + + ISC_LANG_ENDDECLS #endif /* DNS_ZONE_H */ diff --git a/lib/dns/zone.c b/lib/dns/zone.c index dc4e6419e0..83b1561337 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.534 2009/12/03 15:40:02 each Exp $ */ +/* $Id: zone.c,v 1.535 2009/12/04 03:33:15 marka Exp $ */ /*! \file */ @@ -3540,7 +3540,9 @@ exit_check(dns_zone_t *zone) { } static isc_boolean_t -zone_check_ns(dns_zone_t *zone, dns_db_t *db, dns_name_t *name) { +zone_check_ns(dns_zone_t *zone, dns_db_t *db, dns_name_t *name, + isc_boolean_t logit) +{ isc_result_t result; char namebuf[DNS_NAME_FORMATSIZE]; char altbuf[DNS_NAME_FORMATSIZE]; @@ -3571,30 +3573,33 @@ zone_check_ns(dns_zone_t *zone, dns_db_t *db, dns_name_t *name) { return (ISC_TRUE); } - dns_name_format(name, namebuf, sizeof namebuf); if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN || result == DNS_R_EMPTYNAME) { - dns_zone_log(zone, level, - "NS '%s' has no address records (A or AAAA)", - namebuf); - /* XXX950 Make fatal ISC_FALSE for 9.5.0. */ - return (ISC_TRUE); + if (logit) { + dns_name_format(name, namebuf, sizeof namebuf); + dns_zone_log(zone, level, "NS '%s' has no address " + "records (A or AAAA)", namebuf); + } + return (ISC_FALSE); } if (result == DNS_R_CNAME) { - dns_zone_log(zone, level, "NS '%s' is a CNAME (illegal)", - namebuf); - /* XXX950 Make fatal ISC_FALSE for 9.5.0. */ - return (ISC_TRUE); + if (logit) { + dns_name_format(name, namebuf, sizeof namebuf); + dns_zone_log(zone, level, "NS '%s' is a CNAME " + "(illegal)", namebuf); + } + return (ISC_FALSE); } if (result == DNS_R_DNAME) { - dns_name_format(foundname, altbuf, sizeof altbuf); - dns_zone_log(zone, level, - "NS '%s' is below a DNAME '%s' (illegal)", - namebuf, altbuf); - /* XXX950 Make fatal ISC_FALSE for 9.5.0. */ - return (ISC_TRUE); + if (logit) { + dns_name_format(name, namebuf, sizeof namebuf); + dns_name_format(foundname, altbuf, sizeof altbuf); + dns_zone_log(zone, level, "NS '%s' is below a DNAME " + "'%s' (illegal)", namebuf, altbuf); + } + return (ISC_FALSE); } return (ISC_TRUE); @@ -3603,7 +3608,7 @@ zone_check_ns(dns_zone_t *zone, dns_db_t *db, dns_name_t *name) { static isc_result_t zone_count_ns_rr(dns_zone_t *zone, dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, unsigned int *nscount, - unsigned int *errors) + unsigned int *errors, isc_boolean_t logit) { isc_result_t result; unsigned int count = 0; @@ -3634,7 +3639,7 @@ zone_count_ns_rr(dns_zone_t *zone, dns_db_t *db, dns_dbnode_t *node, result = dns_rdata_tostruct(&rdata, &ns, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); if (dns_name_issubdomain(&ns.name, &zone->origin) && - !zone_check_ns(zone, db, &ns.name)) + !zone_check_ns(zone, db, &ns.name, logit)) ecount++; } count++; @@ -3763,7 +3768,7 @@ zone_get_from_db(dns_zone_t *zone, dns_db_t *db, unsigned int *nscount, if (nscount != NULL || errors != NULL) { result = zone_count_ns_rr(zone, db, node, version, - nscount, errors); + nscount, errors, ISC_TRUE); if (result != ISC_R_SUCCESS) answer = result; } @@ -13607,3 +13612,22 @@ dns_zone_rekey(dns_zone_t *zone) { UNLOCK_ZONE(zone); return (result); } + +isc_result_t +dns_zone_nscheck(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, + unsigned int *errors) +{ + isc_result_t result; + dns_dbnode_t *node = NULL; + + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(errors != NULL); + + result = dns_db_getoriginnode(db, &node); + if (result != ISC_R_SUCCESS) + return (result); + result = zone_count_ns_rr(zone, db, node, version, NULL, errors, + ISC_FALSE); + dns_db_detachnode(db, &node); + return (result); +}