diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index cf63ca34fc..707234d281 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -25,12 +25,27 @@ /* * DNS View * - * XXX XXX + * A "view" is a DNS namespace, together with an optional resolver and a + * forwarding policy. A "DNS namespace" is a (possibly empty) set of + * authoritative zones together with an optional cache and optional + * "hints" information. + * + * XXXRTH Not all of this items can be set currently, but future revisions + * of this code will support them. + * + * Views start out "unfrozen". In this state, core attributes like + * the cache, set of zones, and forwarding policy may be set. While + * "unfrozen", the caller (e.g. nameserver configuration loading + * code), must ensure exclusive access to the view. When the view is + * "frozen", the core attributes become immutable, and the view module + * will ensure synchronization. Freezing allows the view's core attributes + * to be accessed without locking. * * MP: - * The module ensures appropriate synchronization of data structures it - * creates and manipulates, with the exception that the caller is - * responsible for the safe creation and destruction of view managers. + * Before the view is frozen, the caller must ensure synchronization. + * + * After the view is frozen, the module guarantees appropriate + * synchronization of any data structures it creates and manipulates. * * Reliability: * No anticipated impact. @@ -42,13 +57,13 @@ * No anticipated impact. * * Standards: - * None. - */ + * None. */ #include #include #include #include +#include #include #include @@ -65,9 +80,9 @@ struct dns_view { dns_resolver_t * resolver; dns_db_t * cachedb; isc_mutex_t lock; + isc_boolean_t frozen; /* Locked by lock. */ unsigned int references; - unsigned int attributes; /* Under owner's locking control. */ ISC_LINK(struct dns_view) link; }; @@ -76,29 +91,191 @@ struct dns_view { #define DNS_VIEW_VALID(view) ((view) != NULL && \ (view)->magic == DNS_VIEW_MAGIC) -#define DNS_VIEWATTR_FROZEN 0x01 - isc_result_t dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, char *name, dns_view_t **viewp); +/* + * Create a view. + * + * Notes: + * + * The newly created view has no cache, no resolver, and an empty + * zone table. The view is not frozen. + * + * Requires: + * + * 'mctx' is a valid memory context. + * + * 'rdclass' is a valid class. + * + * 'name' is a valid C string. + * + * viewp != NULL && *viewp == NULL + * + * Returns: + * + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + * + * Other errors are possible. + */ void dns_view_attach(dns_view_t *source, dns_view_t **targetp); +/* + * Attach '*targetp' to 'source'. + * + * Requires: + * + * 'source' is a valid, frozen view. + * + * 'targetp' points to a NULL dns_view_t *. + * + * Ensures: + * + * *targetp is attached to source. + */ void dns_view_detach(dns_view_t **viewp); +/* + * Detach '*viewp' from its view. + * + * Requires: + * + * 'viewp' points to a valid dns_view_t *. + * + * Ensures: + * + * *viewp is NULL. + * + * If '*viewp' is the last reference to the view, + * + * All resources used by the view will be freed. + */ void dns_view_setresolver(dns_view_t *view, dns_resolver_t *resolver); +/* + * Set the view's resolver. + * + * Requires: + * + * 'view' is a valid, unfrozen view, whose resolver has not been + * set. + * + * 'resolver' is a valid resolver whose view is 'view'. + * + * Ensures: + * + * The resolver of 'view' is 'resolver'. + */ void dns_view_setcachedb(dns_view_t *view, dns_db_t *cachedb); +/* + * Set the view's cache database. + * + * Note: + * + * WARNING! THIS ROUTINE WILL BE REPLACED WITH dns_view_setcache() + * WHEN WE HAVE INTEGRATED CACHE OBJECT SUPPORT INTO THE LIBRARY. + * + * Requires: + * + * 'view' is a valid, unfrozen view, whose cache database has not been + * set. + * + * 'cachedb' is a valid cache database. + * + * Ensures: + * + * The cache database of 'view' is 'cachedb'. + */ isc_result_t -dns_view_addzone(dns_view_t *view, dns_db_t *db); +dns_view_addzonedb(dns_view_t *view, dns_db_t *db); +/* + * Add zone database 'db' to 'view'. + * + * Note: + * + * WARNING! THIS ROUTINE WILL BE REPLACED WITH dns_view_addzone() + * WHEN WE HAVE INTEGRATED ZONE OBJECT SUPPORT INTO THE LIBRARY. + * + * Requires: + * + * 'view' is a valid, unfrozen view. + * + * 'db' is a valid zone database. + * + * Ensures: + * + * The cache database of 'view' is 'cachedb'. + */ void dns_view_freeze(dns_view_t *view); +/* + * Freeze view. + * + * Requires: + * + * 'view' is a valid, unfrozen view. + * + * Ensures: + * + * 'view' is frozen. + */ + +isc_result_t +dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, + isc_stdtime_t now, unsigned int options, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); +/* + * Find an rdataset whose owner name is 'name', and whose type is + * 'type'. + * + * Notes: + * + * This routine is appropriate for simple, exact-match queries of the + * view. + * + * See the description of dns_db_find() for information about 'options'. + * If the caller sets DNS_DBFIND_GLUEOK, it must ensure that 'name' + * and 'type' are appropriate for glue retrieval. + * + * If 'now' is zero, then the current time will be used. + * + * If 'sigrdataset' is not NULL, and there is a SIG rdataset which + * covers 'type', then 'sigrdataset' will be bound to it. + * + * Requires: + * + * 'view' is a valid, frozen view. + * + * 'name' is valid name. + * + * 'type' is a valid dns_rdatatype_t, and is not a meta query type + * (e.g. dns_rdatatype_any), or dns_rdatatype_sig. + * + * 'rdataset' is a valid, disassociated rdataset. + * + * 'sigrdataset' is NULL, or is a valid, disassociated rdataset. + * + * Ensures: + * + * If the result is ISC_R_SUCCESS or DNS_R_GLUE, then 'rdataset', and + * possibly 'sigrdataset', are bound to the found data. + * + * Returns: + * + * ISC_R_SUCCESS Success. + * DNS_R_GLUE Success; result is glue. + * ISC_R_NOTFOUND Not matching data found. + * + * Other results are possible, and indicate an error. + */ ISC_LANG_ENDDECLS diff --git a/lib/dns/view.c b/lib/dns/view.c index 4115f330d9..cdbeab9be4 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -24,18 +24,17 @@ #include #include #include -#include #include #include #include +#include +#include #include #include #include "../isc/util.h" /* XXXRTH */ -#define FROZEN(v) (((v)->attributes & DNS_VIEWATTR_FROZEN) != 0) - isc_result_t dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, char *name, dns_view_t **viewp) @@ -80,8 +79,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, char *name, view->resolver = NULL; view->mctx = mctx; view->rdclass = rdclass; + view->frozen = ISC_FALSE; view->references = 1; - view->attributes = 0; view->magic = DNS_VIEW_MAGIC; *viewp = view; @@ -102,6 +101,11 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, char *name, void dns_view_attach(dns_view_t *source, dns_view_t **targetp) { + + /* + * Attach '*targetp' to 'source'. + */ + REQUIRE(DNS_VIEW_VALID(source)); REQUIRE(targetp != NULL && *targetp == NULL); @@ -135,6 +139,10 @@ dns_view_detach(dns_view_t **viewp) { dns_view_t *view; isc_boolean_t need_destroy = ISC_FALSE; + /* + * Detach '*viewp' from its view. + */ + REQUIRE(viewp != NULL); view = *viewp; REQUIRE(DNS_VIEW_VALID(view)); @@ -156,8 +164,13 @@ dns_view_detach(dns_view_t **viewp) { void dns_view_setresolver(dns_view_t *view, dns_resolver_t *resolver) { + + /* + * Set the view's resolver. + */ + REQUIRE(DNS_VIEW_VALID(view)); - REQUIRE(!FROZEN(view)); + REQUIRE(!view->frozen); REQUIRE(view->resolver == NULL); view->resolver = resolver; @@ -165,25 +178,177 @@ dns_view_setresolver(dns_view_t *view, dns_resolver_t *resolver) { void dns_view_setcachedb(dns_view_t *view, dns_db_t *cachedb) { + + /* + * Set the view's cache database. + */ + + /* + * WARNING! THIS ROUTINE WILL BE REPLACED WITH dns_view_setcache() + * WHEN WE HAVE INTEGRATED CACHE OBJECT SUPPORT INTO THE LIBRARY. + */ + REQUIRE(DNS_VIEW_VALID(view)); - REQUIRE(!FROZEN(view)); + REQUIRE(!view->frozen); REQUIRE(view->cachedb == NULL); + REQUIRE(dns_db_iscache(cachedb)); dns_db_attach(cachedb, &view->cachedb); } isc_result_t -dns_view_addzone(dns_view_t *view, dns_db_t *db) { - REQUIRE(DNS_VIEW_VALID(view)); - REQUIRE(!FROZEN(view)); +dns_view_addzonedb(dns_view_t *view, dns_db_t *db) { + isc_result_t result; - return (dns_dbtable_add(view->dbtable, db)); + /* + * Add zone database 'db' to 'view'. + */ + + /* + * WARNING! THIS ROUTINE WILL BE REPLACED WITH dns_view_addzone() + * WHEN WE HAVE INTEGRATED ZONE OBJECT SUPPORT INTO THE LIBRARY. + */ + + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(dns_db_iszone(db)); + REQUIRE(!view->frozen); + + result = dns_dbtable_add(view->dbtable, db); + + return (result); } void dns_view_freeze(dns_view_t *view) { - REQUIRE(DNS_VIEW_VALID(view)); - REQUIRE(!FROZEN(view)); + + /* + * Freeze view. + */ - view->attributes |= DNS_VIEWATTR_FROZEN; + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(!view->frozen); + + view->frozen = ISC_TRUE; +} + +isc_result_t +dns_view_find(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, + isc_stdtime_t now, unsigned int options, + dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) +{ + isc_result_t result; + dns_fixedname_t foundname; + dns_db_t *db; + dns_dbversion_t *version; + isc_boolean_t is_zone; + dns_rdataset_t zrdataset, zsigrdataset; + + /* + * Find an rdataset whose owner name is 'name', and whose type is + * 'type'. + */ + + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(view->frozen); + REQUIRE(type != dns_rdatatype_any && type != dns_rdatatype_sig); + + /* + * Initialize. + */ + dns_rdataset_init(&zrdataset); + dns_rdataset_init(&zsigrdataset); + + /* + * Find a database to answer the query. + */ + db = NULL; + result = dns_dbtable_find(view->dbtable, name, &db); + if (result == ISC_R_NOTFOUND && view->cachedb != NULL) + dns_db_attach(view->cachedb, &db); + else if (result != ISC_R_SUCCESS && result != DNS_R_PARTIALMATCH) + goto cleanup; + + is_zone = dns_db_iszone(db); + + db_find: + /* + * Now look for an answer in the database. + */ + dns_fixedname_init(&foundname); + result = dns_db_find(db, name, NULL, type, options, + now, NULL, dns_fixedname_name(&foundname), + rdataset, sigrdataset); + + if (result == DNS_R_DELEGATION || + result == DNS_R_NOTFOUND || + result == DNS_R_NXGLUE) { + if (rdataset->methods != NULL) + dns_rdataset_disassociate(rdataset); + if (sigrdataset->methods != NULL) + dns_rdataset_disassociate(sigrdataset); + if (is_zone) { + if (view->cachedb != NULL) { + /* + * Either the answer is in the cache, or we + * don't know it. + */ + is_zone = ISC_FALSE; + version = NULL; + dns_db_detach(&db); + dns_db_attach(view->cachedb, &db); + goto db_find; + } + } else { + /* + * We don't have the data in the cache. If we've got + * glue from the zone, use it. + */ + if (zrdataset.methods != NULL) { + dns_rdataset_clone(&zrdataset, rdataset); + if (zsigrdataset.methods != NULL) + dns_rdataset_clone(&zsigrdataset, + sigrdataset); + result = DNS_R_GLUE; + goto cleanup; + } + } + /* + * We don't know the answer. + */ + result = DNS_R_NOTFOUND; + } else if (result == DNS_R_GLUE) { + if (view->cachedb != NULL) { + /* + * We found an answer, but the cache may be better. + * Remember what we've got and go look in the cache. + */ + is_zone = ISC_FALSE; + version = NULL; + dns_rdataset_clone(rdataset, &zrdataset); + dns_rdataset_disassociate(rdataset); + if (sigrdataset->methods != NULL) { + dns_rdataset_clone(sigrdataset, &zsigrdataset); + dns_rdataset_disassociate(sigrdataset); + } + dns_db_detach(&db); + dns_db_attach(view->cachedb, &db); + goto db_find; + } + /* + * Otherwise, the glue is the best answer. + */ + result = ISC_R_SUCCESS; + } else if (result != ISC_R_SUCCESS) + result = DNS_R_NOTFOUND; + + cleanup: + if (zrdataset.methods != NULL) { + dns_rdataset_disassociate(&zrdataset); + if (zsigrdataset.methods != NULL) + dns_rdataset_disassociate(&zsigrdataset); + } + if (db != NULL) + dns_db_detach(&db); + + return (result); }