From 5d850024cb41fdcb0b85efd3f7997bc52e6b33e8 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 4 Dec 2009 03:33:15 +0000 Subject: [PATCH] 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] --- CHANGES | 5 +++ bin/named/update.c | 14 +++++- bin/tests/system/nsupdate/setup.sh | 3 +- bin/tests/system/zonechecks/tests.sh | 4 +- lib/dns/include/dns/zone.h | 21 ++++++++- lib/dns/zone.c | 66 +++++++++++++++++++--------- 6 files changed, 87 insertions(+), 26 deletions(-) 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); +}