From: Mark Andrews Date: Thu, 6 Nov 2008 02:58:29 +0000 (+0000) Subject: 2485. [bug] Change update's the handling of obscured RRSIG X-Git-Tag: v9.5.1rc1~18 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=bd0d066d97981d58abab712fc3e6970f5d71c0a8;p=thirdparty%2Fbind9.git 2485. [bug] Change update's the handling of obscured RRSIG records. Not all orphand DS records were being removed. [RT #18828] --- diff --git a/CHANGES b/CHANGES index 0066e8c9556..8093cd8f49d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +2485. [bug] Change update's the handling of obscured RRSIG + records. Not all orphand DS records were being + removed. [RT #18828] + 2482. [port] libxml2: support versions 2.7.* in addition to 2.6.*. [RT #18806] @@ -51,7 +55,8 @@ 2463. [port] linux: POSIX doesn't include the IPv6 Advanced Socket API and glibc hides parts of the IPv6 Advanced Socket API as a result. This is stupid as it breaks how the - two halves (Basic and Advanced) of the IPv6 Socket API were designed to be used but we have to live with it. + two halves (Basic and Advanced) of the IPv6 Socket API + were designed to be used but we have to live with it. Define _GNU_SOURCE to pull in the IPv6 Advanced Socket API. [RT #18388] diff --git a/bin/named/update.c b/bin/named/update.c index 0c6e44bb57a..7b59d444014 100644 --- a/bin/named/update.c +++ b/bin/named/update.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: update.c,v 1.138.2.4 2008/04/03 06:10:19 marka Exp $ */ +/* $Id: update.c,v 1.138.2.5 2008/11/06 02:58:29 marka Exp $ */ #include @@ -664,6 +664,45 @@ rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, RETURN_EXISTENCE_FLAG; } +/*% + * Set '*visible' to true if the RRset exists and is part of the + * visible zone. Otherwise '*visible' is set to false unless a + * error occurs. + */ +static isc_result_t +rrset_visible(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + dns_rdatatype_t type, isc_boolean_t *visible) +{ + isc_result_t result; + dns_fixedname_t fixed; + + dns_fixedname_init(&fixed); + result = dns_db_find(db, name, ver, type, DNS_DBFIND_NOWILD, + (isc_stdtime_t) 0, NULL, + dns_fixedname_name(&fixed), NULL, NULL); + switch (result) { + case ISC_R_SUCCESS: + *visible = ISC_TRUE; + break; + /* + * Glue, obsured, deleted or replaced records. + */ + case DNS_R_DELEGATION: + case DNS_R_DNAME: + case DNS_R_CNAME: + case DNS_R_NXDOMAIN: + case DNS_R_NXRRSET: + case DNS_R_EMPTYNAME: + case DNS_R_COVERINGNSEC: + *visible = ISC_FALSE; + result = ISC_R_SUCCESS; + break; + default: + break; + } + return (result); +} + /*% * Helper function for cname_incompatible_rrset_exists. */ @@ -1053,6 +1092,16 @@ true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { return (ISC_TRUE); } +/*% + * Return true if the record is a RRSIG. + */ +static isc_boolean_t +rrsig_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { + UNUSED(update_rr); + return ((db_rr->type == dns_rdatatype_rrsig) ? + ISC_TRUE : ISC_FALSE); +} + /*% * Return true iff the two RRs have identical rdata. */ @@ -1458,10 +1507,9 @@ uniqify_name_list(dns_diff_t *list) { return (result); } - static isc_result_t -is_glue(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, - isc_boolean_t *flag) +is_active(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, + isc_boolean_t *flag, isc_boolean_t *cut, isc_boolean_t *unsecure) { isc_result_t result; dns_fixedname_t foundname; @@ -1469,19 +1517,37 @@ is_glue(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, result = dns_db_find(db, name, ver, dns_rdatatype_any, DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD, (isc_stdtime_t) 0, NULL, - dns_fixedname_name(&foundname), NULL, NULL); - if (result == ISC_R_SUCCESS) { - *flag = ISC_FALSE; + dns_fixedname_name(&foundname), + NULL, NULL); + if (result == ISC_R_SUCCESS || result == DNS_R_EMPTYNAME) { + *flag = ISC_TRUE; + *cut = ISC_FALSE; + if (unsecure != NULL) + *unsecure = ISC_FALSE; return (ISC_R_SUCCESS); } else if (result == DNS_R_ZONECUT) { - /* - * We are at the zonecut. The name will have an NSEC, but - * non-delegation will be omitted from the type bit map. - */ - *flag = ISC_FALSE; - return (ISC_R_SUCCESS); - } else if (result == DNS_R_GLUE || result == DNS_R_DNAME) { *flag = ISC_TRUE; + *cut = ISC_TRUE; + if (unsecure != NULL) { + /* + * We are at the zonecut. Check to see if there + * is a DS RRset. + */ + if (dns_db_find(db, name, ver, dns_rdatatype_ds, 0, + (isc_stdtime_t) 0, NULL, + dns_fixedname_name(&foundname), + NULL, NULL) == DNS_R_NXRRSET) + *unsecure = ISC_TRUE; + else + *unsecure = ISC_FALSE; + } + return (ISC_R_SUCCESS); + } else if (result == DNS_R_GLUE || result == DNS_R_DNAME || + result == DNS_R_DELEGATION || result == DNS_R_NXDOMAIN) { + *flag = ISC_FALSE; + *cut = ISC_FALSE; + if (unsecure != NULL) + *unsecure = ISC_FALSE; return (ISC_R_SUCCESS); } else { return (result); @@ -1688,7 +1754,7 @@ static isc_result_t add_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys, - isc_mem_t *mctx, isc_stdtime_t inception, isc_stdtime_t expire, + isc_stdtime_t inception, isc_stdtime_t expire, isc_boolean_t check_ksk) { isc_result_t result; @@ -1699,6 +1765,7 @@ add_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, unsigned char data[1024]; /* XXX */ unsigned int i; isc_boolean_t added_sig = ISC_FALSE; + isc_mem_t *mctx = client->mctx; dns_rdataset_init(&rdataset); isc_buffer_init(&buffer, data, sizeof(data)); @@ -1745,6 +1812,73 @@ add_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, return (result); } +static isc_result_t +add_exposed_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, + dns_dbversion_t *ver, dns_name_t *name, isc_boolean_t cut, + dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys, + isc_stdtime_t inception, isc_stdtime_t expire, + isc_boolean_t check_ksk) +{ + isc_result_t result; + dns_dbnode_t *node; + dns_rdatasetiter_t *iter; + + node = NULL; + result = dns_db_findnode(db, name, ISC_FALSE, &node); + if (result == ISC_R_NOTFOUND) + return (ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + return (result); + + iter = NULL; + result = dns_db_allrdatasets(db, node, ver, + (isc_stdtime_t) 0, &iter); + if (result != ISC_R_SUCCESS) + goto cleanup_node; + + for (result = dns_rdatasetiter_first(iter); + result == ISC_R_SUCCESS; + result = dns_rdatasetiter_next(iter)) + { + dns_rdataset_t rdataset; + dns_rdatatype_t type; + isc_boolean_t flag; + + dns_rdataset_init(&rdataset); + dns_rdatasetiter_current(iter, &rdataset); + type = rdataset.type; + dns_rdataset_disassociate(&rdataset); + + /* + * We don't need to sign unsigned NSEC records at the cut + * as they are handled elsewhere. + */ + if ((type == dns_rdatatype_rrsig) || + (cut && type != dns_rdatatype_ds)) + continue; + result = rrset_exists(db, ver, name, dns_rdatatype_rrsig, + type, &flag); + if (result != ISC_R_SUCCESS) + goto cleanup_iterator; + if (flag) + continue;; + result = add_sigs(client, zone, db, ver, name, type, diff, + keys, nkeys, inception, expire, check_ksk); + if (result != ISC_R_SUCCESS) + goto cleanup_iterator; + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + cleanup_iterator: + dns_rdatasetiter_destroy(&iter); + + cleanup_node: + dns_db_detachnode(db, &node); + + return (result); +} + /*% * Update RRSIG and NSEC records affected by an update. The original * update, including the SOA serial update but exluding the RRSIG & NSEC @@ -1779,6 +1913,7 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, dns_rdataset_t rdataset; dns_dbnode_t *node = NULL; isc_boolean_t check_ksk; + isc_boolean_t cut; dns_diff_init(client->mctx, &diffnames); dns_diff_init(client->mctx, &affected); @@ -1861,15 +1996,15 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, NULL, &sig_diff)); /* - * If this RRset still exists after the update, + * If this RRset is still visible after the update, * add a new signature for it. */ - CHECK(rrset_exists(db, newver, name, type, 0, &flag)); + CHECK(rrset_visible(db, newver, name, type, &flag)); if (flag) { CHECK(add_sigs(client, zone, db, newver, name, type, &sig_diff, zone_keys, - nkeys, client->mctx, inception, - expire, check_ksk)); + nkeys, inception, expire, + check_ksk)); } skip: /* Skip any other updates to the same RRset. */ @@ -1976,27 +2111,34 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, t = ISC_LIST_NEXT(t, link)) { isc_boolean_t exists; - CHECK(name_exists(db, newver, &t->name, &exists)); + dns_name_t *name = &t->name; + + CHECK(name_exists(db, newver, name, &exists)); if (! exists) continue; - CHECK(is_glue(db, newver, &t->name, &flag)); - if (flag) { + CHECK(is_active(db, newver, name, &flag, &cut, NULL)); + if (!flag) { /* * This name is obscured. Delete any * existing NSEC record. */ - CHECK(delete_if(true_p, db, newver, &t->name, + CHECK(delete_if(true_p, db, newver, name, dns_rdatatype_nsec, 0, NULL, &nsec_diff)); + CHECK(delete_if(rrsig_p, db, newver, name, + dns_rdatatype_any, 0, NULL, diff)); } else { /* * This name is not obscured. It should have a NSEC. */ - CHECK(rrset_exists(db, newver, &t->name, + CHECK(rrset_exists(db, newver, name, dns_rdatatype_nsec, 0, &flag)); if (! flag) CHECK(add_placeholder_nsec(db, newver, &t->name, diff)); + CHECK(add_exposed_sigs(client, zone, db, newver, name, + cut, diff, zone_keys, nkeys, + inception, expire, check_ksk)); } } @@ -2054,8 +2196,8 @@ update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, } else if (t->op == DNS_DIFFOP_ADD) { CHECK(add_sigs(client, zone, db, newver, &t->name, dns_rdatatype_nsec, &sig_diff, - zone_keys, nkeys, client->mctx, - inception, expire, check_ksk)); + zone_keys, nkeys, inception, expire, + check_ksk)); } else { INSIST(0); } @@ -2231,22 +2373,20 @@ ns_update_start(ns_client_t *client, isc_result_t sigresult) { static isc_result_t remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) { isc_result_t result; - isc_boolean_t ns_exists, ds_exists; + isc_boolean_t ns_exists; dns_difftuple_t *t; for (t = ISC_LIST_HEAD(diff->tuples); t != NULL; t = ISC_LIST_NEXT(t, link)) { - if (t->op != DNS_DIFFOP_ADD || - t->rdata.type != dns_rdatatype_ns) + if (!((t->op == DNS_DIFFOP_DEL && + t->rdata.type == dns_rdatatype_ns) || + (t->op == DNS_DIFFOP_ADD && + t->rdata.type == dns_rdatatype_ds))) continue; CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0, &ns_exists)); - if (ns_exists) - continue; - CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ds, 0, - &ds_exists)); - if (!ds_exists) + if (ns_exists && !dns_name_equal(&t->name, dns_db_origin(db))) continue; CHECK(delete_if(true_p, db, newver, &t->name, dns_rdatatype_ds, 0, NULL, diff));