diff --git a/lib/dns/db.c b/lib/dns/db.c index c95883d5ee..53f8a2791e 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -514,7 +514,7 @@ dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_result_t dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_stdtime_t now, dns_rdataset_t *rdataset, - isc_boolean_t merge, dns_rdataset_t *addedrdataset) + unsigned int options, dns_rdataset_t *addedrdataset) { /* * Add 'rdataset' to 'node' in version 'version' of 'db'. @@ -524,7 +524,7 @@ dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, REQUIRE(node != NULL); REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL)|| ((db->attributes & DNS_DBATTR_CACHE) != 0 && - version == NULL && !merge)); + version == NULL && (options & DNS_DBADD_MERGE) == 0)); REQUIRE(DNS_RDATASET_VALID(rdataset)); REQUIRE(rdataset->methods != NULL); REQUIRE(rdataset->rdclass == db->rdclass); @@ -533,7 +533,7 @@ dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, addedrdataset->methods == NULL)); return ((db->methods->addrdataset)(db, node, version, now, rdataset, - merge, addedrdataset)); + options, addedrdataset)); } isc_result_t diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index c303b223b3..80b5645c5d 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -131,7 +131,7 @@ typedef struct dns_dbmethods { dns_dbversion_t *version, isc_stdtime_t now, dns_rdataset_t *rdataset, - isc_boolean_t merge, + unsigned int options, dns_rdataset_t *addedrdataset); isc_result_t (*subtractrdataset)(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, @@ -177,9 +177,10 @@ struct dns_db { #define DNS_DBFIND_PENDINGOK 0x08 /* - * Options that can be specified for dns_db_findzonecut(). + * Options that can be specified for dns_db_addrdataset(). */ -#define DNS_DBFIND_ONLYANCESTORS 0x08 +#define DNS_DBADD_MERGE 0x01 +#define DNS_DBADD_FORCE 0x02 /***** ***** Methods @@ -969,24 +970,29 @@ dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_result_t dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_stdtime_t now, dns_rdataset_t *rdataset, - isc_boolean_t merge, dns_rdataset_t *addedrdataset); + unsigned int options, dns_rdataset_t *addedrdataset); /* * Add 'rdataset' to 'node' in version 'version' of 'db'. * * Notes: * - * If the database has zone semantics, 'merge' is ISC_TRUE, and an - * rdataset of the same type as 'rdataset' already exists at 'node', - * then the contents of 'rdataset' will be merged with the existing - * rdataset. If merge is ISC_FALSE, then rdataset will replace any - * existing rdataset of the same type. + * If the database has zone semantics, the DNS_DBADD_MERGE option is set, + * and an rdataset of the same type as 'rdataset' already exists at + * 'node' then the contents of 'rdataset' will be merged with the existing + * rdataset. If the option is not set, then rdataset will replace any + * existing rdataset of the same type. If not merging and the + * DNS_DBADD_FORCE option is set, then the data will update the database + * without regard to trust levels. If not forcing the data, then the + * rdataset will only be added if its trust level is >= the trust level of + * any existing rdataset. Forcing is only meaningful for cache databases. * * The 'now' field is ignored if 'db' is a zone database. If 'db' is * a cache database, then the added rdataset will expire no later than * now + rdataset->ttl. * * If 'addedrdataset' is not NULL, then it will be attached to the - * resulting new rdataset in the database. + * resulting new rdataset in the database, or to the existing data if + * the existing data was better. * * Requires: * @@ -1003,7 +1009,8 @@ dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, * read-write version, or the database has cache semantics * and version is NULL. * - * If the database has cache semantics, 'merge' must be ISC_FALSE. + * If the database has cache semantics, the DNS_DBADD_MERGE option must + * not be set. * * Returns: * diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 926d8723be..061b98edb2 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -2524,8 +2524,7 @@ cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options, result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node, &search.chain, ISC_TRUE, NULL, &search); - if (result == DNS_R_PARTIALMATCH || - ((options & DNS_DBFIND_ONLYANCESTORS) != 0)) { + if (result == DNS_R_PARTIALMATCH) { find_ns: result = find_deepest_zonecut(&search, node, nodep, foundname, rdataset, sigrdataset); @@ -2988,7 +2987,7 @@ allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, static isc_result_t add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, - rdatasetheader_t *newheader, isc_boolean_t merge, isc_boolean_t loading, + rdatasetheader_t *newheader, unsigned int options, isc_boolean_t loading, dns_rdataset_t *addedrdataset, isc_stdtime_t now) { rbtdb_changed_t *changed = NULL; @@ -2998,7 +2997,9 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, isc_boolean_t force = ISC_FALSE; isc_boolean_t header_nx; isc_boolean_t newheader_nx; + isc_boolean_t merge; dns_rdatatype_t nxtype, rdtype, covers; + dns_trust_t trust; /* * Add an rdatasetheader_t to a node. @@ -3008,6 +3009,16 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * Caller must be holding the node lock. */ + if ((options & DNS_DBADD_MERGE) != 0) + merge = ISC_TRUE; + else + merge = ISC_FALSE; + + if ((options & DNS_DBADD_FORCE) != 0) + trust = dns_trust_authsecure; + else + trust = newheader->trust; + if (rbtversion != NULL && !loading) { /* * We always add a changed record, even if no changes end up @@ -3070,7 +3081,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, /* * Found one. */ - if (newheader->trust < topheader->trust) { + if (trust < topheader->trust) { /* * The NXDOMAIN is more trusted. */ @@ -3129,7 +3140,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, * Trying to add an rdataset with lower trust to a cache DB * has no effect, provided that the cache data isn't stale. */ - if (rbtversion == NULL && newheader->trust < header->trust && + if (rbtversion == NULL && trust < header->trust && (header->ttl > now || header_nx)) { free_rdataset(rbtdb->common.mctx, newheader); if (addedrdataset != NULL) @@ -3158,10 +3169,6 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion, merged = NULL; if (newheader->ttl != header->ttl) force = ISC_TRUE; - /* - * XXXRTH we're going to have to deal with signatures - * somehow here... - */ result = dns_rdataslab_merge( (unsigned char *)header, (unsigned char *)newheader, @@ -3279,7 +3286,7 @@ delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, static isc_result_t addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, - isc_stdtime_t now, dns_rdataset_t *rdataset, isc_boolean_t merge, + isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options, dns_rdataset_t *addedrdataset) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; @@ -3332,7 +3339,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, LOCK(&rbtdb->node_locks[rbtnode->locknum].lock); - result = add(rbtdb, rbtnode, rbtversion, newheader, merge, ISC_FALSE, + result = add(rbtdb, rbtnode, rbtversion, newheader, options, ISC_FALSE, addedrdataset, now); if (result == DNS_R_SUCCESS && delegating) rbtnode->find_callback = 1; @@ -3499,7 +3506,7 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, LOCK(&rbtdb->node_locks[rbtnode->locknum].lock); - result = add(rbtdb, rbtnode, rbtversion, newheader, ISC_FALSE, + result = add(rbtdb, rbtnode, rbtversion, newheader, 0, ISC_FALSE, NULL, 0); UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock); @@ -3573,8 +3580,8 @@ loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) { newheader->trust = rdataset->trust; newheader->serial = 1; - result = add(rbtdb, node, rbtdb->current_version, newheader, ISC_TRUE, - ISC_TRUE, NULL, 0); + result = add(rbtdb, node, rbtdb->current_version, newheader, + DNS_DBADD_MERGE, ISC_TRUE, NULL, 0); if (result == DNS_R_SUCCESS && delegating_type(rbtdb, node, rdataset->type)) node->find_callback = 1;