+4605. [performance] Improve performance for delegation heavy answers
+ and also general query performance. Removes the
+ acache feature that didn't significantly improve
+ performance. Adds a glue cache. Removes
+ additional-from-cache and additional-from-auth
+ features. Enables minimal-responses by
+ default. Improves performance of compression
+ code, owner case restoration, hash function,
+ etc. Uses inline buffer implementation by
+ default. Many other performance changes and fixes.
+ [RT #44029]
+
4604. [bug] Don't use ERR_load_crypto_strings() when building
with OpenSSL 1.1.0. [RT #45117]
"\
recursive-clients 1000;\n\
resolver-query-timeout 10;\n\
- rrset-order { order random; };\n\
# serial-queries <obsolete>;\n\
serial-query-rate 20;\n\
server-id none;\n\
# topology <none>\n\
auth-nxdomain false;\n\
minimal-any false;\n\
- minimal-responses false;\n\
+ minimal-responses true;\n\
recursion true;\n\
provide-ixfr true;\n\
request-ixfr true;\n\
request-expire true;\n\
# fetch-glue <obsolete>;\n\
# rfc2308-type1 <obsolete>;\n\
- additional-from-auth true;\n\
- additional-from-cache true;\n\
query-source address *;\n\
query-source-v6 address *;\n\
notify-source *;\n\
check-dup-records warn;\n\
check-mx warn;\n\
check-spf warn;\n\
- acache-enable no;\n\
- acache-cleaning-interval 60;\n\
- max-acache-size 16M;\n\
dnssec-enable yes;\n\
dnssec-validation yes; \n\
dnssec-accept-expired no;\n\
unsigned int dispatchgen;
ns_dispatchlist_t dispatches;
- dns_acache_t *acache;
-
ns_statschannellist_t statschannels;
dns_tsigkey_t *sessionkey;
#define SAVE(a, b) do { INSIST(a == NULL); a = b; b = NULL; } while (0)
#define RESTORE(a, b) SAVE(a, b)
-typedef struct client_additionalctx {
- ns_client_t *client;
- dns_rdataset_t *rdataset;
-} client_additionalctx_t;
-
static isc_boolean_t
validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
* CNAMES or DNAMES into other zones and prevents returning
* additional data from other zones.
*/
- if (!client->view->additionalfromauth &&
- client->query.authdbset &&
- db != client->query.authdb)
+ if (client->query.rpz_st == NULL &&
+ client->query.authdbset && db != client->query.authdb)
+ {
return (DNS_R_REFUSED);
+ }
/*
* Non recursive query to a static-stub zone is prohibited; its
dns_rdataset_t *rdataset, *sigrdataset, *trdataset;
isc_buffer_t *dbuf;
isc_buffer_t b;
+ ns_dbversion_t *dbversion;
dns_dbversion_t *version;
isc_boolean_t added_something, need_addname;
- dns_zone_t *zone;
dns_rdatatype_t type;
dns_clientinfomethods_t cm;
dns_clientinfo_t ci;
node = NULL;
added_something = ISC_FALSE;
need_addname = ISC_FALSE;
- zone = NULL;
additionaltype = dns_rdatasetadditional_fromauth;
dns_clientinfomethods_init(&cm, ns_client_sourceip);
}
/*
- * Look for a zone database that might contain authoritative
+ * If we want only minimal responses and are here, then it must
+ * be for glue.
+ */
+ if (client->view->minimalresponses == dns_minimal_yes)
+ goto try_glue;
+
+ /*
+ * Look within the same zone database for authoritative
* additional data.
*/
- result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG,
- &zone, &db, &version);
- if (result != ISC_R_SUCCESS)
+ if (!client->query.authdbset || client->query.authdb == NULL)
goto try_cache;
+ dbversion = query_findversion(client, client->query.authdb);
+ if (dbversion == NULL)
+ goto try_cache;
+
+ dns_db_attach(client->query.authdb, &db);
+ version = dbversion->version;
+
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: db_find");
/*
*/
try_cache:
+ if (!client->view->recursion)
+ goto try_glue;
+
additionaltype = dns_rdatasetadditional_fromcache;
result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS) {
/*
* Most likely the client isn't allowed to query the cache.
*/
goto try_glue;
+ }
/*
* Attempt to validate glue.
*/
if (sigrdataset == NULL)
goto cleanup;
}
+
+ version = NULL;
result = dns_db_findext(db, name, version, type,
client->query.dboptions |
DNS_DBFIND_GLUEOK | DNS_DBFIND_ADDITIONALOK,
if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb)))
goto cleanup;
- dns_db_attach(client->query.gluedb, &db);
+ dbversion = query_findversion(client, client->query.gluedb);
+ if (dbversion == NULL)
+ goto cleanup;
+ dns_db_attach(client->query.gluedb, &db);
+ version = dbversion->version;
additionaltype = dns_rdatasetadditional_fromglue;
result = dns_db_findext(db, name, version, type,
client->query.dboptions | DNS_DBFIND_GLUEOK,
dns_rdatatype_a, 0,
client->now,
rdataset, sigrdataset);
- if (result == DNS_R_NCACHENXDOMAIN)
+ if (result == DNS_R_NCACHENXDOMAIN) {
goto addname;
- if (result == DNS_R_NCACHENXRRSET) {
+ } else if (result == DNS_R_NCACHENXRRSET) {
dns_rdataset_disassociate(rdataset);
if (sigrdataset != NULL &&
dns_rdataset_isassociated(sigrdataset))
dns_rdataset_disassociate(sigrdataset);
- }
- if (result == ISC_R_SUCCESS) {
+ } else if (result == ISC_R_SUCCESS) {
mname = NULL;
#ifdef ALLOW_FILTER_AAAA
have_a = ISC_TRUE;
dns_rdatatype_aaaa, 0,
client->now,
rdataset, sigrdataset);
- if (result == DNS_R_NCACHENXDOMAIN)
+ if (result == DNS_R_NCACHENXDOMAIN) {
goto addname;
- if (result == DNS_R_NCACHENXRRSET) {
+ } else if (result == DNS_R_NCACHENXRRSET) {
dns_rdataset_disassociate(rdataset);
if (sigrdataset != NULL &&
dns_rdataset_isassociated(sigrdataset))
dns_rdataset_disassociate(sigrdataset);
- }
- if (result == ISC_R_SUCCESS) {
+ } else if (result == ISC_R_SUCCESS) {
mname = NULL;
/*
* There's an A; check whether we're filtering AAAA
dns_db_detachnode(db, &node);
if (db != NULL)
dns_db_detach(&db);
- if (zone != NULL)
- dns_zone_detach(&zone);
CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: done");
return (eresult);
}
-static inline void
-query_discardcache(ns_client_t *client, dns_rdataset_t *rdataset_base,
- dns_rdatasetadditional_t additionaltype,
- dns_rdatatype_t type, dns_zone_t **zonep, dns_db_t **dbp,
- dns_dbversion_t **versionp, dns_dbnode_t **nodep,
- dns_name_t *fname)
-{
- dns_rdataset_t *rdataset;
-
- while ((rdataset = ISC_LIST_HEAD(fname->list)) != NULL) {
- ISC_LIST_UNLINK(fname->list, rdataset, link);
- query_putrdataset(client, &rdataset);
- }
- if (*versionp != NULL)
- dns_db_closeversion(*dbp, versionp, ISC_FALSE);
- if (*nodep != NULL)
- dns_db_detachnode(*dbp, nodep);
- if (*dbp != NULL)
- dns_db_detach(dbp);
- if (*zonep != NULL)
- dns_zone_detach(zonep);
- (void)dns_rdataset_putadditional(client->view->acache, rdataset_base,
- additionaltype, type);
-}
-
-static inline isc_result_t
-query_iscachevalid(dns_zone_t *zone, dns_db_t *db, dns_db_t *db0,
- dns_dbversion_t *version)
-{
- isc_result_t result = ISC_R_SUCCESS;
- dns_dbversion_t *version_current = NULL;
- dns_db_t *db_current = db0;
-
- if (db_current == NULL) {
- result = dns_zone_getdb(zone, &db_current);
- if (result != ISC_R_SUCCESS)
- return (result);
- }
- dns_db_currentversion(db_current, &version_current);
- if (db_current != db || version_current != version) {
- result = ISC_R_FAILURE;
- goto cleanup;
- }
-
- cleanup:
- dns_db_closeversion(db_current, &version_current, ISC_FALSE);
- if (db0 == NULL && db_current != NULL)
- dns_db_detach(&db_current);
-
- return (result);
-}
-
-static isc_result_t
-query_addadditional2(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) {
- client_additionalctx_t *additionalctx = arg;
- dns_rdataset_t *rdataset_base;
- ns_client_t *client;
- isc_result_t result, eresult;
- dns_dbnode_t *node, *cnode;
- dns_db_t *db, *cdb;
- dns_name_t *fname, *mname0, cfname;
- dns_rdataset_t *rdataset, *sigrdataset;
- dns_rdataset_t *crdataset, *crdataset_next;
- isc_buffer_t *dbuf;
- isc_buffer_t b;
- dns_dbversion_t *version, *cversion;
- isc_boolean_t added_something, need_addname, needadditionalcache;
- isc_boolean_t need_sigrrset;
- dns_zone_t *zone;
- dns_rdatatype_t type;
- dns_rdatasetadditional_t additionaltype;
- dns_clientinfomethods_t cm;
- dns_clientinfo_t ci;
-
- /*
- * If we don't have an additional cache call query_addadditional.
- */
- client = additionalctx->client;
- REQUIRE(NS_CLIENT_VALID(client));
-
- if (qtype != dns_rdatatype_a || client->view->acache == NULL) {
- /*
- * This function is optimized for "address" types. For other
- * types, use a generic routine.
- * XXX: ideally, this function should be generic enough.
- */
- return (query_addadditional(additionalctx->client,
- name, qtype));
- }
-
- /*
- * Initialization.
- */
- rdataset_base = additionalctx->rdataset;
- eresult = ISC_R_SUCCESS;
- fname = NULL;
- rdataset = NULL;
- sigrdataset = NULL;
- db = NULL;
- cdb = NULL;
- version = NULL;
- cversion = NULL;
- node = NULL;
- cnode = NULL;
- added_something = ISC_FALSE;
- need_addname = ISC_FALSE;
- zone = NULL;
- needadditionalcache = ISC_FALSE;
- POST(needadditionalcache);
- additionaltype = dns_rdatasetadditional_fromauth;
- dns_name_init(&cfname, NULL);
- dns_clientinfomethods_init(&cm, ns_client_sourceip);
- dns_clientinfo_init(&ci, client, NULL);
-
- CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2");
-
- /*
- * We treat type A additional section processing as if it
- * were "any address type" additional section processing.
- * To avoid multiple lookups, we do an 'any' database
- * lookup and iterate over the node.
- * XXXJT: this approach can cause a suboptimal result when the cache
- * DB only has partial address types and the glue DB has remaining
- * ones.
- */
- type = dns_rdatatype_any;
-
- /*
- * Get some resources.
- */
- dbuf = query_getnamebuf(client);
- if (dbuf == NULL)
- goto cleanup;
- fname = query_newname(client, dbuf, &b);
- if (fname == NULL)
- goto cleanup;
- dns_name_setbuffer(&cfname, &b); /* share the buffer */
-
- /* Check additional cache */
- result = dns_rdataset_getadditional(rdataset_base, additionaltype,
- type, client->view->acache, &zone,
- &cdb, &cversion, &cnode, &cfname,
- client->message, client->now);
- if (result != ISC_R_SUCCESS)
- goto findauthdb;
- if (zone == NULL) {
- CTRACE(ISC_LOG_DEBUG(3),
- "query_addadditional2: auth zone not found");
- goto try_cache;
- }
-
- /* Is the cached DB up-to-date? */
- result = query_iscachevalid(zone, cdb, NULL, cversion);
- if (result != ISC_R_SUCCESS) {
- CTRACE(ISC_LOG_DEBUG(3),
- "query_addadditional2: old auth additional cache");
- query_discardcache(client, rdataset_base, additionaltype,
- type, &zone, &cdb, &cversion, &cnode,
- &cfname);
- goto findauthdb;
- }
-
- if (cnode == NULL) {
- /*
- * We have a negative cache. We don't have to check the zone
- * ACL, since the result (not using this zone) would be same
- * regardless of the result.
- */
- CTRACE(ISC_LOG_DEBUG(3),
- "query_addadditional2: negative auth additional cache");
- dns_db_closeversion(cdb, &cversion, ISC_FALSE);
- dns_db_detach(&cdb);
- dns_zone_detach(&zone);
- goto try_cache;
- }
-
- result = query_validatezonedb(client, name, qtype, DNS_GETDB_NOLOG,
- zone, cdb, NULL);
- if (result != ISC_R_SUCCESS) {
- query_discardcache(client, rdataset_base, additionaltype,
- type, &zone, &cdb, &cversion, &cnode,
- &cfname);
- goto try_cache;
- }
-
- /* We've got an active cache. */
- CTRACE(ISC_LOG_DEBUG(3),
- "query_addadditional2: auth additional cache");
- dns_db_closeversion(cdb, &cversion, ISC_FALSE);
- db = cdb;
- node = cnode;
- dns_name_clone(&cfname, fname);
- query_keepname(client, fname, dbuf);
- goto foundcache;
-
- /*
- * Look for a zone database that might contain authoritative
- * additional data.
- */
- findauthdb:
- result = query_getzonedb(client, name, qtype, DNS_GETDB_NOLOG,
- &zone, &db, &version);
- if (result != ISC_R_SUCCESS) {
- /* Cache the negative result */
- (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
- type, client->view->acache,
- NULL, NULL, NULL, NULL,
- NULL);
- goto try_cache;
- }
-
- CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: db_find");
-
- /*
- * Since we are looking for authoritative data, we do not set
- * the GLUEOK flag. Glue will be looked for later, but not
- * necessarily in the same database.
- */
- node = NULL;
- result = dns_db_findext(db, name, version, type,
- client->query.dboptions,
- client->now, &node, fname, &cm, &ci,
- NULL, NULL);
- if (result == ISC_R_SUCCESS)
- goto found;
-
- /* Cache the negative result */
- (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
- type, client->view->acache, zone, db,
- version, NULL, fname);
-
- if (node != NULL)
- dns_db_detachnode(db, &node);
- version = NULL;
- dns_db_detach(&db);
-
- /*
- * No authoritative data was found. The cache is our next best bet.
- */
-
- try_cache:
- additionaltype = dns_rdatasetadditional_fromcache;
- result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG);
- if (result != ISC_R_SUCCESS)
- /*
- * Most likely the client isn't allowed to query the cache.
- */
- goto try_glue;
-
- result = dns_db_findext(db, name, version, type,
- client->query.dboptions |
- DNS_DBFIND_GLUEOK | DNS_DBFIND_ADDITIONALOK,
- client->now, &node, fname, &cm, &ci,
- NULL, NULL);
- if (result == ISC_R_SUCCESS)
- goto found;
-
- if (node != NULL)
- dns_db_detachnode(db, &node);
- dns_db_detach(&db);
-
- try_glue:
- /*
- * No cached data was found. Glue is our last chance.
- * RFC1035 sayeth:
- *
- * NS records cause both the usual additional section
- * processing to locate a type A record, and, when used
- * in a referral, a special search of the zone in which
- * they reside for glue information.
- *
- * This is the "special search". Note that we must search
- * the zone where the NS record resides, not the zone it
- * points to, and that we only do the search in the delegation
- * case (identified by client->query.gluedb being set).
- */
- if (client->query.gluedb == NULL)
- goto cleanup;
-
- /*
- * Don't poison caches using the bailiwick protection model.
- */
- if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb)))
- goto cleanup;
-
- /* Check additional cache */
- additionaltype = dns_rdatasetadditional_fromglue;
- result = dns_rdataset_getadditional(rdataset_base, additionaltype,
- type, client->view->acache, NULL,
- &cdb, &cversion, &cnode, &cfname,
- client->message, client->now);
- if (result != ISC_R_SUCCESS)
- goto findglue;
-
- result = query_iscachevalid(zone, cdb, client->query.gluedb, cversion);
- if (result != ISC_R_SUCCESS) {
- CTRACE(ISC_LOG_DEBUG(3),
- "query_addadditional2: old glue additional cache");
- query_discardcache(client, rdataset_base, additionaltype,
- type, &zone, &cdb, &cversion, &cnode,
- &cfname);
- goto findglue;
- }
-
- if (cnode == NULL) {
- /* We have a negative cache. */
- CTRACE(ISC_LOG_DEBUG(3),
- "query_addadditional2: negative glue additional cache");
- dns_db_closeversion(cdb, &cversion, ISC_FALSE);
- dns_db_detach(&cdb);
- goto cleanup;
- }
-
- /* Cache hit. */
- CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: glue additional cache");
- dns_db_closeversion(cdb, &cversion, ISC_FALSE);
- db = cdb;
- node = cnode;
- dns_name_clone(&cfname, fname);
- query_keepname(client, fname, dbuf);
- goto foundcache;
-
- findglue:
- dns_db_attach(client->query.gluedb, &db);
- result = dns_db_findext(db, name, version, type,
- client->query.dboptions | DNS_DBFIND_GLUEOK,
- client->now, &node, fname, &cm, &ci,
- NULL, NULL);
- if (!(result == ISC_R_SUCCESS ||
- result == DNS_R_ZONECUT ||
- result == DNS_R_GLUE)) {
- /* cache the negative result */
- (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
- type, client->view->acache,
- NULL, db, version, NULL,
- fname);
- goto cleanup;
- }
-
- found:
- /*
- * We have found a DB node to iterate over from a DB.
- * We are going to look for address RRsets (i.e., A and AAAA) in the DB
- * node we've just found. We'll then store the complete information
- * in the additional data cache.
- */
- dns_name_clone(fname, &cfname);
- query_keepname(client, fname, dbuf);
- needadditionalcache = ISC_TRUE;
-
- rdataset = query_newrdataset(client);
- if (rdataset == NULL)
- goto cleanup;
-
- sigrdataset = query_newrdataset(client);
- if (sigrdataset == NULL)
- goto cleanup;
-
- if (additionaltype == dns_rdatasetadditional_fromcache &&
- query_isduplicate(client, fname, dns_rdatatype_a, NULL))
- goto aaaa_lookup;
- /*
- * Find A RRset with sig RRset. Even if we don't find a sig RRset
- * for a client using DNSSEC, we'll continue the process to make a
- * complete list to be cached. However, we need to cancel the
- * caching when something unexpected happens, in order to avoid
- * caching incomplete information.
- */
- result = dns_db_findrdataset(db, node, version, dns_rdatatype_a, 0,
- client->now, rdataset, sigrdataset);
- /*
- * If we can't promote glue/pending from the cache to secure
- * then drop it.
- */
- if (result == ISC_R_SUCCESS &&
- additionaltype == dns_rdatasetadditional_fromcache &&
- (DNS_TRUST_PENDING(rdataset->trust) ||
- DNS_TRUST_GLUE(rdataset->trust)) &&
- !validate(client, db, fname, rdataset, sigrdataset)) {
- dns_rdataset_disassociate(rdataset);
- if (dns_rdataset_isassociated(sigrdataset))
- dns_rdataset_disassociate(sigrdataset);
- result = ISC_R_NOTFOUND;
- }
- if (result == DNS_R_NCACHENXDOMAIN)
- goto setcache;
- if (result == DNS_R_NCACHENXRRSET) {
- dns_rdataset_disassociate(rdataset);
- if (dns_rdataset_isassociated(sigrdataset))
- dns_rdataset_disassociate(sigrdataset);
- }
- if (result == ISC_R_SUCCESS) {
- /* Remember the result as a cache */
- ISC_LIST_APPEND(cfname.list, rdataset, link);
- if (dns_rdataset_isassociated(sigrdataset)) {
- ISC_LIST_APPEND(cfname.list, sigrdataset, link);
- sigrdataset = query_newrdataset(client);
- }
- rdataset = query_newrdataset(client);
- if (sigrdataset == NULL || rdataset == NULL) {
- /* do not cache incomplete information */
- goto foundcache;
- }
- }
-
- aaaa_lookup:
- if (additionaltype == dns_rdatasetadditional_fromcache &&
- query_isduplicate(client, fname, dns_rdatatype_aaaa, NULL))
- goto foundcache;
- /* Find AAAA RRset with sig RRset */
- result = dns_db_findrdataset(db, node, version, dns_rdatatype_aaaa,
- 0, client->now, rdataset, sigrdataset);
- /*
- * If we can't promote glue/pending from the cache to secure
- * then drop it.
- */
- if (result == ISC_R_SUCCESS &&
- additionaltype == dns_rdatasetadditional_fromcache &&
- (DNS_TRUST_PENDING(rdataset->trust) ||
- DNS_TRUST_GLUE(rdataset->trust)) &&
- !validate(client, db, fname, rdataset, sigrdataset)) {
- dns_rdataset_disassociate(rdataset);
- if (dns_rdataset_isassociated(sigrdataset))
- dns_rdataset_disassociate(sigrdataset);
- result = ISC_R_NOTFOUND;
- }
- if (result == ISC_R_SUCCESS) {
- ISC_LIST_APPEND(cfname.list, rdataset, link);
- rdataset = NULL;
- if (dns_rdataset_isassociated(sigrdataset)) {
- ISC_LIST_APPEND(cfname.list, sigrdataset, link);
- sigrdataset = NULL;
- }
- }
-
- setcache:
- /*
- * Set the new result in the cache if required. We do not support
- * caching additional data from a cache DB.
- */
- if (needadditionalcache == ISC_TRUE &&
- (additionaltype == dns_rdatasetadditional_fromauth ||
- additionaltype == dns_rdatasetadditional_fromglue)) {
- (void)dns_rdataset_setadditional(rdataset_base, additionaltype,
- type, client->view->acache,
- zone, db, version, node,
- &cfname);
- }
-
- foundcache:
- need_sigrrset = ISC_FALSE;
- mname0 = NULL;
- for (crdataset = ISC_LIST_HEAD(cfname.list);
- crdataset != NULL;
- crdataset = crdataset_next) {
- dns_name_t *mname;
-
- crdataset_next = ISC_LIST_NEXT(crdataset, link);
-
- mname = NULL;
- if (crdataset->type == dns_rdatatype_a ||
- crdataset->type == dns_rdatatype_aaaa) {
- if (!query_isduplicate(client, fname, crdataset->type,
- &mname)) {
- if (mname != fname) {
- if (mname != NULL) {
- /*
- * A different type of this
- * name is already stored
- * in the additional
- * section. We'll reuse
- * the name. Note that
- * this should happen at
- * most once. Otherwise,
- * fname->link could leak
- * below.
- */
- INSIST(mname0 == NULL);
-
- query_releasename(client,
- &fname);
- fname = mname;
- mname0 = mname;
- } else
- need_addname = ISC_TRUE;
- }
- ISC_LIST_UNLINK(cfname.list, crdataset, link);
- ISC_LIST_APPEND(fname->list, crdataset, link);
- added_something = ISC_TRUE;
- need_sigrrset = ISC_TRUE;
- } else
- need_sigrrset = ISC_FALSE;
- } else if (crdataset->type == dns_rdatatype_rrsig &&
- need_sigrrset && WANTDNSSEC(client)) {
- ISC_LIST_UNLINK(cfname.list, crdataset, link);
- ISC_LIST_APPEND(fname->list, crdataset, link);
- added_something = ISC_TRUE; /* just in case */
- need_sigrrset = ISC_FALSE;
- }
- }
-
- CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: addname");
-
- /*
- * If we haven't added anything, then we're done.
- */
- if (!added_something)
- goto cleanup;
-
- /*
- * We may have added our rdatasets to an existing name, if so, then
- * need_addname will be ISC_FALSE. Whether we used an existing name
- * or a new one, we must set fname to NULL to prevent cleanup.
- */
- if (need_addname)
- dns_message_addname(client->message, fname,
- DNS_SECTION_ADDITIONAL);
- fname = NULL;
-
- cleanup:
- CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: cleanup");
-
- if (rdataset != NULL)
- query_putrdataset(client, &rdataset);
- if (sigrdataset != NULL)
- query_putrdataset(client, &sigrdataset);
- while ((crdataset = ISC_LIST_HEAD(cfname.list)) != NULL) {
- ISC_LIST_UNLINK(cfname.list, crdataset, link);
- query_putrdataset(client, &crdataset);
- }
- if (fname != NULL)
- query_releasename(client, &fname);
- if (node != NULL)
- dns_db_detachnode(db, &node);
- if (db != NULL)
- dns_db_detach(&db);
- if (zone != NULL)
- dns_zone_detach(&zone);
-
- CTRACE(ISC_LOG_DEBUG(3), "query_addadditional2: done");
- return (eresult);
-}
-
static inline void
query_addrdataset(ns_client_t *client, dns_name_t *fname,
dns_rdataset_t *rdataset)
{
- client_additionalctx_t additionalctx;
-
/*
* Add 'rdataset' and any pertinent additional data to
* 'fname', a name in the response message for 'client'.
if (NOADDITIONAL(client))
return;
+ /*
+ * Try to process glue directly.
+ */
+ if ((client->view->minimalresponses == dns_minimal_yes) &&
+ (rdataset->type == dns_rdatatype_ns) &&
+ (client->query.gluedb != NULL) &&
+ dns_db_iszone(client->query.gluedb))
+ {
+ isc_result_t result;
+ ns_dbversion_t *dbversion;
+ unsigned int options = 0;
+
+ dbversion = query_findversion(client, client->query.gluedb);
+ if (dbversion == NULL)
+ goto regular;
+
+#ifdef ALLOW_FILTER_AAAA
+ if (client->filter_aaaa == dns_aaaa_filter ||
+ client->filter_aaaa == dns_aaaa_break_dnssec)
+ {
+ options |= DNS_RDATASETADDGLUE_FILTERAAAA;
+ }
+#endif
+
+ result = dns_rdataset_addglue(rdataset, dbversion->version,
+ options, client->message);
+ if (result == ISC_R_SUCCESS)
+ return;
+ }
+
+regular:
/*
* Add additional data.
*
* We don't care if dns_rdataset_additionaldata() fails.
*/
- additionalctx.client = client;
- additionalctx.rdataset = rdataset;
- (void)dns_rdataset_additionaldata(rdataset, query_addadditional2,
- &additionalctx);
+ (void)dns_rdataset_additionaldata(rdataset, query_addadditional,
+ client);
CTRACE(ISC_LOG_DEBUG(3), "query_addrdataset: done");
}
break;
}
- if (client->view->cachedb == NULL || !client->view->additionalfromcache)
- {
+ if (client->view->cachedb == NULL || !client->view->recursion) {
/*
* We don't have a cache. Turn off cache support and
* recursion.
#include <bind9/check.h>
-#include <dns/acache.h>
#include <dns/adb.h>
#include <dns/badcache.h>
#include <dns/cache.h>
#if DNS_RDATASET_FIXED
mode = DNS_RDATASETATTR_FIXEDORDER;
#else
- mode = 0;
+ mode = DNS_RDATASETATTR_CYCLIC;
#endif /* DNS_RDATASET_FIXED */
else if (!strcasecmp(str, "random"))
mode = DNS_RDATASETATTR_RANDOMIZE;
else if (!strcasecmp(str, "cyclic"))
- mode = 0;
+ mode = DNS_RDATASETATTR_CYCLIC;
+ else if (!strcasecmp(str, "none"))
+ mode = DNS_RDATASETATTR_NONE;
else
INSIST(0);
RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
dns_zone_setview(dnszone, view);
- if (view->acache != NULL)
- dns_zone_setacache(dnszone, view->acache);
dns_view_addzone(view, dnszone);
}
unsigned int cleaning_interval;
size_t max_cache_size;
isc_uint32_t max_cache_size_percent = 0;
- size_t max_acache_size;
size_t max_adb_size;
isc_uint32_t lame_ttl, fail_ttl;
dns_tsig_keyring_t *ring = NULL;
CHECKM(ns_config_getport(config, &port), "port");
dns_view_setdstport(view, port);
- /*
- * Create additional cache for this view and zones under the view
- * if explicitly enabled.
- * XXX950 default to on.
- */
- obj = NULL;
- (void)ns_config_get(maps, "acache-enable", &obj);
- if (obj != NULL && cfg_obj_asboolean(obj)) {
- cmctx = NULL;
- CHECK(isc_mem_create(0, 0, &cmctx));
- CHECK(dns_acache_create(&view->acache, cmctx, ns_g_taskmgr,
- ns_g_timermgr));
- isc_mem_setname(cmctx, "acache", NULL);
- isc_mem_detach(&cmctx);
- }
- if (view->acache != NULL) {
- obj = NULL;
- result = ns_config_get(maps, "acache-cleaning-interval", &obj);
- INSIST(result == ISC_R_SUCCESS);
- dns_acache_setcleaninginterval(view->acache,
- cfg_obj_asuint32(obj) * 60);
-
- obj = NULL;
- result = ns_config_get(maps, "max-acache-size", &obj);
- INSIST(result == ISC_R_SUCCESS);
- if (cfg_obj_isstring(obj)) {
- str = cfg_obj_asstring(obj);
- INSIST(strcasecmp(str, "unlimited") == 0);
- max_acache_size = 0;
- } else {
- isc_resourcevalue_t value;
- value = cfg_obj_asuint64(obj);
- if (value > SIZE_MAX) {
- cfg_obj_log(obj, ns_g_lctx,
- ISC_LOG_WARNING,
- "'max-acache-size "
- "%" ISC_PRINT_QUADFORMAT "u' "
- "is too large for this "
- "system; reducing to %lu",
- value, (unsigned long)SIZE_MAX);
- value = SIZE_MAX;
- }
- max_acache_size = (size_t) value;
- }
- dns_acache_setcachesize(view->acache, max_acache_size);
- }
-
CHECK(configure_view_acl(vconfig, config, "allow-query", NULL, actx,
ns_g_mctx, &view->queryacl));
if (view->queryacl == NULL) {
INSIST(result == ISC_R_SUCCESS);
view->trust_anchor_telemetry = cfg_obj_asboolean(obj);
- /*
- * Set sources where additional data and CNAME/DNAME
- * targets for authoritative answers may be found.
- */
- obj = NULL;
- result = ns_config_get(maps, "additional-from-auth", &obj);
- INSIST(result == ISC_R_SUCCESS);
- view->additionalfromauth = cfg_obj_asboolean(obj);
- if (view->recursion && ! view->additionalfromauth) {
- cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
- "'additional-from-auth no' is only supported "
- "with 'recursion no'");
- view->additionalfromauth = ISC_TRUE;
- }
-
- obj = NULL;
- result = ns_config_get(maps, "additional-from-cache", &obj);
- INSIST(result == ISC_R_SUCCESS);
- view->additionalfromcache = cfg_obj_asboolean(obj);
- if (view->recursion && ! view->additionalfromcache) {
- cfg_obj_log(obj, ns_g_lctx, ISC_LOG_WARNING,
- "'additional-from-cache no' is only supported "
- "with 'recursion no'");
- view->additionalfromcache = ISC_TRUE;
- }
-
/*
* Set "allow-query-cache", "allow-query-cache-on",
* "allow-recursion", and "allow-recursion-on" acls if
* new view.
*/
dns_zone_setview(zone, view);
- if (view->acache != NULL)
- dns_zone_setacache(zone, view->acache);
} else {
/*
* We cannot reuse an existing zone, we have
CHECK(dns_zonemgr_createzone(ns_g_server->zonemgr, &zone));
CHECK(dns_zone_setorigin(zone, origin));
dns_zone_setview(zone, view);
- if (view->acache != NULL)
- dns_zone_setacache(zone, view->acache);
CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
dns_zone_setstats(zone, ns_g_server->zonestats);
}
CHECK(dns_zone_create(&raw, mctx));
CHECK(dns_zone_setorigin(raw, origin));
dns_zone_setview(raw, view);
- if (view->acache != NULL)
- dns_zone_setacache(raw, view->acache);
dns_zone_setstats(raw, ns_g_server->zonestats);
CHECK(dns_zone_link(zone, raw));
}
CHECK(dns_zonemgr_managezone(ns_g_server->zonemgr, zone));
- if (view->acache != NULL)
- dns_zone_setacache(zone, view->acache);
-
CHECK(dns_acl_none(mctx, &none));
dns_zone_setqueryacl(zone, none);
dns_zone_setqueryonacl(zone, none);
notify-source 10.53.0.1;
transfer-source 10.53.0.1;
recursion no;
- additional-from-auth no;
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.1; };
notify-source 10.53.0.1;
transfer-source 10.53.0.1;
recursion no;
- additional-from-auth no;
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.1; };
notify-source 10.53.0.1;
transfer-source 10.53.0.1;
recursion no;
- additional-from-auth no;
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.1; };
notify-source 10.53.0.1;
transfer-source 10.53.0.1;
recursion no;
- additional-from-auth no;
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.1; };
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-rm -f */K* */dsset-* */*.signed */trusted.conf */tmp* */*.jnl */*.bk
+rm -f */K* */dsset-* */*.signed */tmp* */*.jnl */*.bk
+rm -f */trusted.conf */private.conf
rm -f */core
rm -f */example.bk
rm -f */named.memstats
zone=private.secure.example
zonefile="${zone}.db"
infile="${zonefile}.in"
-cp $infile $zonefile
-$KEYGEN -3 -q -r $RANDFILE -fk $zone > /dev/null
+ksk=`$KEYGEN -3 -q -r $RANDFILE -fk $zone`
$KEYGEN -3 -q -r $RANDFILE $zone > /dev/null
+cat $ksk.key | grep -v '^; ' | $PERL -n -e '
+local ($dn, $class, $type, $flags, $proto, $alg, @rest) = split;
+local $key = join("", @rest);
+print <<EOF
+trusted-keys {
+ "$dn" $flags $proto $alg "$key";
+};
+EOF
+' > private.conf
+cp private.conf ../ns4/private.conf
+$SIGNER -S -3 beef -A -o $zone -f $zonefile $infile > /dev/null 2>&1
# Extract saved keys for the revoke-to-duplicate-key test
zone=bar
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named.conf,v 1.3 2009/11/30 23:48:02 tbox Exp $ */
-
// NS4
controls { /* empty */ };
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
dnssec-enable yes;
dnssec-validation yes;
dnssec-must-be-secure mustbesecure.example yes;
};
include "trusted.conf";
+include "private.conf";
listen-on { 10.53.0.5; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
dnssec-enable yes;
dnssec-validation yes;
};
> dig.out.ns4.test$n || ret=1
$PERL ../digcomp.pl dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
grep "NOERROR" dig.out.ns4.test$n > /dev/null || ret=1
-# Note - this is looking for failure, hence the &&
-grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
echo "I:checking privately secure to nxdomain works ($n)"
ret=0
-$DIG $DIGOPTS +noauth private2secure-nxdomain.private.secure.example. SOA @10.53.0.2 \
- > dig.out.ns2.test$n || ret=1
-$DIG $DIGOPTS +noauth private2secure-nxdomain.private.secure.example. SOA @10.53.0.4 \
- > dig.out.ns4.test$n || ret=1
-$PERL ../digcomp.pl dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
-# Note - this is looking for failure, hence the &&
-grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
+$DIG $DIGOPTS +noauth private2secure-nxdomain.private.secure.example. SOA @10.53.0.4 > dig.out.ns4.test$n || ret=1
+grep "NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named.conf,v 1.11 2011/08/02 23:47:52 tbox Exp $ */
-
controls { /* empty */ };
options {
recursion no;
notify yes;
check-integrity no;
+ minimal-responses no;
};
zone "." {
notify yes;
ixfr-from-differences yes;
check-integrity no;
+ minimal-responses no;
};
zone "example" {
ixfr-from-differences yes;
check-integrity no;
no-case-compress { 10.53.0.2; };
+ minimal-responses no;
};
zone "example" {
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
check-names response warn;
notify yes;
};
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
check-names response fail;
notify yes;
};
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
check-names master ignore;
notify yes;
};
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
deny-answer-addresses { 192.0.2.0/24; 2001:db8:beef::/48; }
except-from { "example.org"; };
deny-answer-aliases { "example.org"; }
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
recursion no;
- acache-enable yes;
send-cookie yes;
nocookie-udp-size 512;
};
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
deny-answer-addresses { 192.0.2.0/24; 2001:db8:beef::/48; }
except-from { "example.org"; };
deny-answer-aliases { "example.org"; }
listen-on { 10.53.0.3; };
listen-on-v6 { fd92:7065:b8e:ffff::3; };
recursion yes;
- acache-enable yes;
dnssec-enable no;
dnssec-validation no;
server-id "ns3";
listen-on { 10.53.0.5; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
dnssec-enable yes;
dnssec-validation yes;
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named.conf,v 1.36 2011/03/21 23:47:21 tbox Exp $ */
-
// NS2
controls { /* empty */ };
dnssec-enable yes;
dnssec-validation yes;
notify-delay 1;
+ minimal-responses no;
};
zone "." {
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named.conf,v 1.49 2011/10/28 06:20:05 each Exp $ */
-
// NS3
controls { /* empty */ };
dnssec-enable yes;
dnssec-validation yes;
session-keyfile "session.key";
+ minimal-responses no;
};
key rndc_key {
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named1.conf,v 1.3 2011/01/04 23:47:13 tbox Exp $ */
-
// NS4
controls { /* empty */ };
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
dnssec-enable yes;
dnssec-validation yes;
dnssec-must-be-secure mustbesecure.example yes;
+ minimal-responses no;
nta-lifetime 10s;
nta-recheck 7s;
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named2.conf,v 1.3 2011/01/04 23:47:13 tbox Exp $ */
-
// NS4
controls { /* empty */ };
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
dnssec-enable yes;
dnssec-validation auto;
bindkeys-file "managed.conf";
+ minimal-responses no;
};
key rndc_key {
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named2.conf,v 1.3 2011/01/04 23:47:13 tbox Exp $ */
-
// NS4
controls { /* empty */ };
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
dnssec-enable yes;
dnssec-validation auto;
bindkeys-file "managed.conf";
dnssec-accept-expired yes;
+ minimal-responses no;
};
key rndc_key {
zone "." {
type hint;
file "../../common/root.hint";
+}
+
+key auth {
+ secret "1234abcd8765";
+ algorithm hmac-sha256;
+};
+
+include "trusted.conf";
+
+view rec {
+ match-recursive-only yes;
+ recursion yes;
+ dnssec-validation yes;
+ dnssec-accept-expired yes;
+
+ zone "." {
+ type hint;
+ file "../../common/root.hint";
+ };
+
+ zone secure.example {
+ type static-stub;
+ server-addresses { 10.53.0.4; };
+ };
+
+ zone insecure.secure.example {
+ type static-stub;
+ server-addresses { 10.53.0.4; };
+ };
+};
+
+view auth {
+ recursion no;
+ allow-recursion { none; };
+
+ zone secure.example {
+ type slave;
+ masters { 10.53.0.3; };
+ };
+
+ zone insecure.secure.example {
+ type slave;
+ masters { 10.53.0.2; };
+ };
};
listen-on { 10.53.0.5; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
dnssec-enable yes;
dnssec-validation yes;
};
listen-on { 10.53.0.6; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
disable-algorithms . { DSA; };
dnssec-enable yes;
echo "I:checking privately secure to nxdomain works ($n)"
ret=0
-$DIG $DIGOPTS +noauth private2secure-nxdomain.private.secure.example. SOA @10.53.0.2 \
- > dig.out.ns2.test$n || ret=1
$DIG $DIGOPTS +noauth private2secure-nxdomain.private.secure.example. SOA @10.53.0.4 \
> dig.out.ns4.test$n || ret=1
-$PERL ../digcomp.pl dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
# Note - this is looking for failure, hence the &&
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
n=`expr $n + 1`
echo "I:checking privately secure wildcard to nxdomain works ($n)"
ret=0
-$DIG $DIGOPTS +noauth a.wild.private.secure.example. SOA @10.53.0.2 \
- > dig.out.ns2.test$n || ret=1
$DIG $DIGOPTS +noauth a.wild.private.secure.example. SOA @10.53.0.4 \
> dig.out.ns4.test$n || ret=1
-$PERL ../digcomp.pl dig.out.ns2.test$n dig.out.ns4.test$n || ret=1
+grep "NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
# Note - this is looking for failure, hence the &&
grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null && ret=1
n=`expr $n + 1`
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
deny-answer-addresses { 192.0.2.0/24; 2001:db8:beef::/48; }
except-from { "example.org"; };
deny-answer-aliases { "example.org"; }
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
deny-answer-addresses { 192.0.2.0/24; 2001:db8:beef::/48; }
except-from { "example.org"; };
deny-answer-aliases { "example.org"; }
notify yes;
filter-aaaa-on-v4 yes;
filter-aaaa { 10.53.0.1; };
+ minimal-responses no;
};
key rndc_key {
notify yes;
filter-aaaa-on-v6 yes;
filter-aaaa { fd92:7065:b8e:ffff::1; };
+ minimal-responses no;
};
key rndc_key {
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
-; $Id: root.db,v 1.4 2012/01/31 23:47:32 tbox Exp $
-
$TTL 120
@ SOA ns.utld hostmaster.ns.utld ( 1 3600 1200 604800 60 )
@ NS ns.utld
ns.utld A 10.53.0.1
ns.utld AAAA fd92:7065:b8e:ffff::1
;
-signed NS ns.utld
-unsigned NS ns.utld
+
+signed NS ns.signed
+ns.signed A 10.53.0.1
+ns.signed AAAA fd92:7065:b8e:ffff::1
+
+unsigned NS ns.unsigned
+ns.unsigned A 10.53.0.1
+ns.unsigned AAAA fd92:7065:b8e:ffff::1
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
-; $Id: signed.db.in,v 1.4 2012/01/31 23:47:32 tbox Exp $
-
$TTL 120
-@ SOA ns.utld. hostmaster.ns.utld. ( 1 3600 1200 604800 60 )
-@ NS ns.utld.
+@ SOA ns.signed. hostmaster.ns.signed. ( 1 3600 1200 604800 60 )
+@ NS ns
@ MX 10 mx
+
+ns A 10.53.0.1
+ AAAA fd92:7065:b8e:ffff::1
+
a-only NS 1.0.0.1
aaaa-only AAAA 2001:db8::2
dual A 1.0.0.3
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
-; $Id: unsigned.db,v 1.4 2012/01/31 23:47:32 tbox Exp $
-
$TTL 120
-@ SOA ns.utld. hostmaster.ns.utld. ( 1 3600 1200 604800 60 )
-@ NS ns.utld.
+@ SOA ns.unsigned. hostmaster.ns.unsigned. ( 1 3600 1200 604800 60 )
+@ NS ns
@ MX 10 mx
+
+ns A 10.53.0.1
+ AAAA fd92:7065:b8e:ffff::1
+
a-only NS 1.0.0.4
aaaa-only AAAA 2001:db8::5
dual A 1.0.0.6
notify yes;
filter-aaaa-on-v4 yes;
filter-aaaa { 10.53.0.2; };
+ minimal-responses no;
};
key rndc_key {
notify yes;
filter-aaaa-on-v6 yes;
filter-aaaa { fd92:7065:b8e:ffff::2; };
+ minimal-responses no;
};
key rndc_key {
notify yes;
filter-aaaa-on-v4 break-dnssec;
filter-aaaa { 10.53.0.3; };
+ minimal-responses no;
};
key rndc_key {
notify yes;
filter-aaaa-on-v6 break-dnssec;
filter-aaaa { fd92:7065:b8e:ffff::3; };
+ minimal-responses no;
};
key rndc_key {
notify yes;
filter-aaaa-on-v4 break-dnssec;
filter-aaaa { 10.53.0.4; };
+ minimal-responses no;
};
key rndc_key {
notify yes;
filter-aaaa-on-v6 break-dnssec;
filter-aaaa { fd92:7065:b8e:ffff::4; };
+ minimal-responses no;
};
key rndc_key {
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
; $Id: root.db,v 1.4 2012/01/31 23:47:32 tbox Exp $
-
-$TTL 120
@ SOA ns.utld hostmaster.ns.utld ( 1 3600 1200 604800 60 )
@ NS ns.utld
-ns.utld A 10.53.0.1
-ns.utld AAAA fd92:7065:b8e:ffff::1
+ns.utld A 10.53.0.4
+ns.utld AAAA fd92:7065:b8e:ffff::4
;
-signed NS ns.utld
-unsigned NS ns.utld
+
+signed NS ns.signed
+ns.signed A 10.53.0.4
+ns.signed AAAA fd92:7065:b8e:ffff::4
+
+unsigned NS ns.unsigned
+ns.unsigned A 10.53.0.4
+ns.unsigned AAAA fd92:7065:b8e:ffff::4
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
-; $Id: signed.db.in,v 1.4 2012/01/31 23:47:32 tbox Exp $
-
$TTL 120
-@ SOA ns.utld. hostmaster.ns.utld. ( 1 3600 1200 604800 60 )
-@ NS ns.utld.
+@ SOA ns.signed. hostmaster.ns.signed. ( 1 3600 1200 604800 60 )
+@ NS ns
@ MX 10 mx
+
+ns A 10.53.0.4
+ AAAA fd92:7065:b8e:ffff::4
+
a-only NS 1.0.0.1
aaaa-only AAAA 2001:db8::2
dual A 1.0.0.3
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
-; $Id: unsigned.db,v 1.4 2012/01/31 23:47:32 tbox Exp $
-
$TTL 120
-@ SOA ns.utld. hostmaster.ns.utld. ( 1 3600 1200 604800 60 )
-@ NS ns.utld.
+@ SOA ns.unsigned. hostmaster.ns.unsigned. ( 1 3600 1200 604800 60 )
+@ NS ns
@ MX 10 mx
+
+ns A 10.53.0.4
+ AAAA fd92:7065:b8e:ffff::4
+
a-only NS 1.0.0.4
aaaa-only AAAA 2001:db8::5
dual A 1.0.0.6
NS.EU.NET. 172800 IN A 192.16.202.11
SPARKY.ARL.MIL. 172800 IN A 128.63.58.18
SUNIC.SUNET.SE. 172800 IN A 192.36.125.2
-
-;
-; A hypothetical ccTLD where we are authoritative for the NS glue.
-;
-xx. 172800 IN NS b.root-servers.nil.
-
-;
-; A hypothetical ccTLD where we have cached NS glue.
-;
-yy. 172800 IN NS ns.zz.
$DIG +norec @10.53.0.1 -p 5300 foo.bar.fi. A >dig.out || status=1
$PERL ../digcomp.pl --lc fi.good dig.out || status=1
-echo "I:testing that we find glue A RRs we are authoritative for"
-$DIG +norec @10.53.0.1 -p 5300 foo.bar.xx. a >dig.out || status=1
-$PERL ../digcomp.pl xx.good dig.out || status=1
-
-echo "I:testing that we find glue A/AAAA RRs in the cache"
-$DIG +norec @10.53.0.1 -p 5300 foo.bar.yy. a >dig.out || status=1
-$PERL ../digcomp.pl yy.good dig.out || status=1
-
echo "I:testing that we don't find out-of-zone glue"
$DIG +norec @10.53.0.1 -p 5300 example.net. a > dig.out || status=1
$PERL ../digcomp.pl noglue.good dig.out || status=1
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named.conf,v 1.14 2007/06/19 23:47:03 tbox Exp $ */
-
controls { /* empty */ };
options {
listen-on-v6 { none; };
recursion no;
notify yes;
+ minimal-responses no;
};
zone "." {
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
};
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
};
listen-on { 10.53.0.5; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
};
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named.conf,v 1.22 2011/07/01 02:25:47 marka Exp $ */
-
controls { /* empty */ };
options {
listen-on-v6 { none; };
recursion no;
notify yes;
+ minimal-responses no;
};
key rndc_key {
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
};
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
deny-answer-addresses { 192.0.2.0/24; 2001:db8:beef::/48; }
except-from { "example.org"; };
deny-answer-aliases { "example.org"; }
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id$ */
-
controls { /* empty */ };
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
notify no;
+ minimal-responses no;
};
zone "." {type master; file "root.db";};
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id$ */
-
-
controls { /* empty */ };
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
notify no;
+ minimal-responses no;
};
key rndc_key {
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id$ */
-
-
/*
* Main rpz test DNS server.
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
notify no;
+ minimal-responses no;
response-policy {
zone "bl" max-policy-ttl 100;
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id$ */
-
controls { /* empty */ };
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
notify no;
+ minimal-responses no;
};
include "../trusted.conf";
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id$ */
-
-
/*
* Test rpz performance.
ixfr-from-differences yes;
notify-delay 1;
notify yes;
+ minimal-responses no;
# turn rpz on or off
include "rpz-switch";
listen-on-v6 { none; };
forward only;
forwarders { 10.53.0.3; };
+ minimal-responses no;
response-policy { zone "policy1" min-update-interval 0; };
};
session-keyfile "session.key";
listen-on { 10.53.0.7; };
listen-on-v6 { none; };
+ minimal-responses no;
response-policy { zone "policy2"; }
qname-wait-recurse no
min-table-size 0;
max-table-size 0;
};
-
- additional-from-cache no;
};
key rndc_key {
// small enough to force a table expansion
min-table-size 75;
};
-
- additional-from-cache no;
};
key rndc_key {
// small enough to force a table expansion
min-table-size 75;
};
-
- additional-from-cache no;
};
key rndc_key {
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-# $Id: clean.sh,v 1.10 2011/12/23 23:47:13 tbox Exp $
-
rm -f dig.out.test*
-rm -f dig.out.cyclic dig.out.fixed dig.out.random
+rm -f dig.out.cyclic dig.out.fixed dig.out.random dig.out.nomatch
rm -f dig.out.0 dig.out.1 dig.out.2 dig.out.3
rm -f dig.out.cyclic2
rm -f ns2/root.bk
cyclic2.example. A 1.2.3.3
cyclic2.example. A 1.2.3.2
cyclic2.example. A 1.2.3.1
+;
+nomatch.example. A 1.2.3.1
+nomatch.example. A 1.2.3.2
+nomatch.example. A 1.2.3.3
+nomatch.example. A 1.2.3.4
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
rrset-order {
name "fixed.example" order fixed;
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
rrset-order {
class IN type A name "host.example.com" order random;
if [ $match -lt 8 ]; then echo ret=1; fi
if [ $ret != 0 ]; then echo "I:failed"; fi
-echo "I: Checking default order no match in rrset-order (random)"
+echo "I: Checking default order no match in rrset-order (no shuffling)"
ret=0
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
do
for i in a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 9
do
$DIG +nosea +nocomm +nocmd +noquest +noadd +noauth +nocomm +nostat +short \
- -p 5300 @10.53.0.4 random.example > dig.out.random|| ret=1
+ -p 5300 @10.53.0.4 nomatch.example > dig.out.nomatch|| ret=1
match=0
for j in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
do
- eval "$DIFF dig.out.random dig.out.random.good$j >/dev/null && match$j=1 match=1"
+ eval "$DIFF dig.out.nomatch dig.out.random.good$j >/dev/null && match$j=1 match=1"
if [ $match -eq 1 ]; then break; fi
done
if [ $match -eq 0 ]; then ret=1; fi
do
eval "match=\`expr \$match + \$match$i\`"
done
-echo "I: Random selection return $match of 24 possible orders in 36 samples"
-if [ $match -lt 8 ]; then echo ret=1; fi
+echo "I: Consistent selection return $match of 24 possible orders in 36 samples"
+if [ $match -ne 1 ]; then echo ret=1; fi
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
listen-on { 10.53.0.5; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
dnssec-enable yes;
dnssec-validation yes;
servfail-ttl 30;
listen-on-v6 { none; };
recursion no;
notify yes;
+ minimal-responses no;
version none; // make statistics independent of the version number
};
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
};
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
};
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named.conf,v 1.14 2007/06/19 23:47:05 tbox Exp $ */
-
controls { /* empty */ };
options {
listen-on-v6 { none; };
recursion no;
notify yes;
+ minimal-responses no;
};
zone "." {
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named.conf,v 1.14 2007/06/19 23:47:05 tbox Exp $ */
-
controls { /* empty */ };
options {
listen-on-v6 { none; };
recursion no;
notify yes;
+ minimal-responses no;
};
zone "." {
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named.conf,v 1.16 2007/06/18 23:47:31 tbox Exp $ */
-
controls { /* empty */ };
options {
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
+ minimal-responses no;
};
zone "." {
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: named.conf.in,v 1.10 2011/11/03 23:46:26 tbox Exp $ */
-
controls { /* empty */ };
options {
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-# $Id: tests.sh,v 1.11 2011/11/03 23:46:26 tbox Exp $
-
SYSTEMTESTTOP=..
. $SYSTEMTESTTOP/conf.sh
echo "I:checking the new key"
ret=0
- $DIG $DIGOPTS . ns -k $keyname > dig.out.1 || ret=1
+ $DIG $DIGOPTS txt txt.example -k $keyname > dig.out.1 || ret=1
grep "status: NOERROR" dig.out.1 > /dev/null || ret=1
grep "TSIG.*hmac-md5.*NOERROR" dig.out.1 > /dev/null || ret=1
grep "Some TSIG could not be validated" dig.out.1 > /dev/null && ret=1
echo "I:checking that new key has been deleted"
ret=0
- $DIG $DIGOPTS . ns -k $keyname > dig.out.2 || ret=1
+ $DIG $DIGOPTS txt txt.example -k $keyname > dig.out.2 || ret=1
grep "status: NOERROR" dig.out.2 > /dev/null && ret=1
grep "TSIG.*hmac-md5.*NOERROR" dig.out.2 > /dev/null && ret=1
grep "Some TSIG could not be validated" dig.out.2 > /dev/null || ret=1
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
};
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
};
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
};
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
};
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
allow-v6-synthesis { any; };
};
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
notify yes;
};
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
recursion no;
- acache-enable yes;
};
zone "." {
listen-on { 10.53.0.2; };
listen-on-v6 { none; };
recursion no;
- acache-enable yes;
};
zone "example" {
listen-on { 10.53.0.3; };
listen-on-v6 { none; };
recursion yes;
- acache-enable yes;
};
zone "." {
listen-on { 10.53.0.4; };
listen-on-v6 { none; };
recursion no;
- acache-enable yes;
};
zone "example" {
option can be used to limit the amount of memory used by the cache,
at the expense of reducing cache hit rates and causing more <acronym>DNS</acronym>
traffic.
- Additionally, if additional section caching
- (<xref linkend="acache"/>) is enabled,
- the <command>max-acache-size</command> option can be used to
- limit the amount
- of memory used by the mechanism.
It is still good practice to have enough memory to load
all zone and cache data into memory — unfortunately, the best
way
[ <command>nta-recheck</command> <replaceable>duration</replaceable> ; ]
[ <command>port</command> <replaceable>ip_port</replaceable> ; ]
[ <command>dscp</command> <replaceable>ip_dscp</replaceable> ; ]
- [ <command>additional-from-auth</command> <replaceable>yes_or_no</replaceable> ; ]
- [ <command>additional-from-cache</command> <replaceable>yes_or_no</replaceable> ; ]
[ <command>random-device</command> <replaceable>path_name</replaceable> ; ]
[ <command>max-cache-size</command> <replaceable>size_or_percent</replaceable> ; ]
[ <command>match-mapped-addresses</command> <replaceable>yes_or_no</replaceable> ; ]
[ <command>querylog</command> <replaceable>yes_or_no</replaceable> ; ]
[ <command>disable-algorithms</command> <replaceable>domain</replaceable> <command>{</command> <replaceable>algorithm</replaceable> ; ... <command>}</command> ; ]
[ <command>disable-ds-digests</command> <replaceable>domain</replaceable> <command>{</command> <replaceable>digest_type</replaceable> ; ... <command>}</command> ; ]
- [ <command>acache-enable</command> <replaceable>yes_or_no</replaceable> ; ]
- [ <command>acache-cleaning-interval</command> <replaceable>number</replaceable> ; ]
- [ <command>max-acache-size</command> <replaceable>size_spec</replaceable> ; ]
[ <command>max-recursion-depth</command> <replaceable>number</replaceable> ; ]
[ <command>max-recursion-queries</command> <replaceable>number</replaceable> ; ]
[ <command>masterfile-format</command> ( <option>text</option> | <option>raw</option> | <option>map</option> ) ; ]
both authoritative and recursive queries.
</para>
<para>
- The default is <userinput>no</userinput>.
+ The default is <userinput>yes</userinput>.
</para>
</listitem>
</varlistentry>
</listitem>
</varlistentry>
- <varlistentry>
- <term><command>additional-from-auth</command></term>
- <term><command>additional-from-cache</command></term>
- <listitem>
-
- <para>
- These options control the behavior of an authoritative
- server when
- answering queries which have additional data, or when
- following CNAME
- and DNAME chains.
- </para>
-
- <para>
- When both of these options are set to <userinput>yes</userinput>
- (the default) and a
- query is being answered from authoritative data (a zone
- configured into the server), the additional data section of
- the
- reply will be filled in using data from other authoritative
- zones
- and from the cache. In some situations this is undesirable,
- such
- as when there is concern over the correctness of the cache,
- or
- in servers where slave zones may be added and modified by
- untrusted third parties. Also, avoiding
- the search for this additional data will speed up server
- operations
- at the possible expense of additional queries to resolve
- what would
- otherwise be provided in the additional section.
- </para>
-
- <para>
- For example, if a query asks for an MX record for host <literal>foo.example.com</literal>,
- and the record found is "<literal>MX 10 mail.example.net</literal>", normally the address
- records (A and AAAA) for <literal>mail.example.net</literal> will be provided as well,
- if known, even though they are not in the example.com zone.
- Setting these options to <command>no</command>
- disables this behavior and makes
- the server only search for additional data in the zone it
- answers from.
- </para>
-
- <para>
- These options are intended for use in authoritative-only
- servers, or in authoritative-only views. Attempts to set
- them to <command>no</command> without also
- specifying
- <command>recursion no</command> will cause the
- server to
- ignore the options and log a warning message.
- </para>
-
- <para>
- Specifying <command>additional-from-cache no</command> actually
- disables the use of the cache not only for additional data
- lookups
- but also when looking up the answer. This is usually the
- desired
- behavior in an authoritative-only server where the
- correctness of
- the cached data is an issue.
- </para>
-
- <para>
- When a name server is non-recursively queried for a name
- that is not
- below the apex of any served zone, it normally answers with
- an
- "upwards referral" to the root servers or the servers of
- some other
- known parent of the query name. Since the data in an
- upwards referral
- comes from the cache, the server will not be able to provide
- upwards
- referrals when <command>additional-from-cache no</command>
- has been specified. Instead, it will respond to such
- queries
- with REFUSED. This should not cause any problems since
- upwards referrals are not required for the resolution
- process.
- </para>
-
- </listitem>
- </varlistentry>
-
<varlistentry>
<term><command>match-mapped-addresses</command></term>
<listitem>
<para>
The response to a DNS query may consist of multiple resource
- records (RRs) forming a resource records set (RRset).
+ records (RRs) forming a resource record set (RRset).
The name server will normally return the
RRs within the RRset in an indeterminate order
(but see the <command>rrset-order</command>
<para>
When multiple records are returned in an answer it may be
useful to configure the order of the records placed into the
- response.
- The <command>rrset-order</command> statement permits
- configuration
- of the ordering of the records in a multiple record response.
+ response. The <command>rrset-order</command> statement permits
+ configuration of the ordering of the records in a
+ multiple-record response.
See also the <command>sortlist</command> statement,
<xref linkend="the_sortlist_statement"/>.
</para>
-
<para>
- An <command>order_spec</command> is defined as
- follows:
+ An <command>order_spec</command> is defined as follows:
</para>
<para>
<optional>class <replaceable>class_name</replaceable></optional>
<entry colname="2">
<para>
Records are returned in the order they
- are defined in the zone file.
+ are defined in the zone file. This option
+ is only available if <acronym>BIND</acronym>
+ is configured with "--enable-fixed-rrset" at
+ compile time.
</para>
</entry>
</row>
</entry>
<entry colname="2">
<para>
- Records are returned in a cyclic round-robin order.
+ Records are returned in a cyclic round-robin order,
+ rotating by one record per query.
</para>
<para>
- If <acronym>BIND</acronym> is configured with the
- "--enable-fixed-rrset" option at compile time, then
+ If <acronym>BIND</acronym> is configured with
+ "--enable-fixed-rrset" at compile time, then
the initial ordering of the RRset will match the
- one specified in the zone file.
+ one specified in the zone file; otherwise the
+ initial ordering is indeterminate.
+ </para>
+ </entry>
+ </row>
+ <row rowsep="0">
+ <entry colname="1">
+ <para><command>none</command></para>
+ </entry>
+ <entry colname="2">
+ <para>
+ Records are returned in whatever order they were
+ retrieved from the database. This order is
+ indeterminate, but will be consistent as long as the
+ database is not modified. When no ordering is
+ specified, this is the default.
</para>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
+ <para>
+ </para>
<para>
For example:
</para>
-
<programlisting>rrset-order {
class IN type A name "host.example.com" order random;
order cyclic;
};
</programlisting>
-
<para>
will cause any responses for type A records in class IN that
have "<literal>host.example.com</literal>" as a
appear, they are not combined — the last one applies.
</para>
<para>
- By default, all records are returned in random order.
+ By default, records are returned in indeterminate but
+ consistent order (see <command>none</command> above).
</para>
<note>
</variablelist>
</section>
- <section xml:id="acache"><info><title>Additional Section Caching</title></info>
-
-
- <para>
- The additional section cache, also called <command>acache</command>,
- is an internal cache to improve the response performance of BIND 9.
- When additional section caching is enabled, BIND 9 will
- cache an internal short-cut to the additional section content for
- each answer RR.
- Note that <command>acache</command> is an internal caching
- mechanism of BIND 9, and is not related to the DNS caching
- server function.
- </para>
-
- <para>
- Additional section caching does not change the
- response content (except the RRsets ordering of the additional
- section, see below), but can improve the response performance
- significantly.
- It is particularly effective when BIND 9 acts as an authoritative
- server for a zone that has many delegations with many glue RRs.
- </para>
-
- <para>
- In order to obtain the maximum performance improvement
- from additional section caching, setting
- <command>additional-from-cache</command>
- to <command>no</command> is recommended, since the current
- implementation of <command>acache</command>
- does not short-cut of additional section information from the
- DNS cache data.
- </para>
-
- <para>
- One obvious disadvantage of <command>acache</command> is
- that it requires much more
- memory for the internal cached data.
- Thus, if the response performance does not matter and memory
- consumption is much more critical, the
- <command>acache</command> mechanism can be
- disabled by setting <command>acache-enable</command> to
- <command>no</command>.
- It is also possible to specify the upper limit of memory
- consumption
- for acache by using <command>max-acache-size</command>.
- </para>
-
- <para>
- Additional section caching also has a minor effect on the
- RRset ordering in the additional section.
- Without <command>acache</command>,
- <command>cyclic</command> order is effective for the additional
- section as well as the answer and authority sections.
- However, additional section caching fixes the ordering when it
- first caches an RRset for the additional section, and the same
- ordering will be kept in succeeding responses, regardless of the
- setting of <command>rrset-order</command>.
- The effect of this should be minor, however, since an
- RRset in the additional section
- typically only contains a small number of RRs (and in many cases
- it only contains a single RR), in which case the
- ordering does not matter much.
- </para>
-
- <para>
- The following is a summary of options related to
- <command>acache</command>.
- </para>
-
- <variablelist>
-
- <varlistentry>
- <term><command>acache-enable</command></term>
- <listitem>
- <para>
- If <command>yes</command>, additional section caching is
- enabled. The default value is <command>no</command>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><command>acache-cleaning-interval</command></term>
- <listitem>
- <para>
- The server will remove stale cache entries, based on an LRU
- based
- algorithm, every <command>acache-cleaning-interval</command> minutes.
- The default is 60 minutes.
- If set to 0, no periodic cleaning will occur.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><command>max-acache-size</command></term>
- <listitem>
- <para>
- The maximum amount of memory in bytes to use for the server's acache.
- When the amount of data in the acache reaches this limit,
- the server
- will clean more aggressively so that the limit is not
- exceeded.
- In a server with multiple views, the limit applies
- separately to the
- acache of each view.
- The default is <literal>16M</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- </section>
-
<section xml:id="content_filtering"><info><title>Content Filtering</title></info>
<para>
<integer> ] ) [ key <string> ]; ... }; // may occur multiple times
options {
- acache-cleaning-interval <integer>;
- acache-enable <boolean>;
- additional-from-auth <boolean>;
- additional-from-cache <boolean>;
+ acache-cleaning-interval <integer>; // obsolete
+ acache-enable <boolean>; // obsolete
+ additional-from-auth <boolean>; // obsolete
+ additional-from-cache <boolean>; // obsolete
allow-new-zones <boolean>;
allow-notify { <address_match_element>; ... };
allow-query { <address_match_element>; ... };
masterfile-format ( map | raw | text );
masterfile-style ( full | relative );
match-mapped-addresses <boolean>;
- max-acache-size ( unlimited | <sizeval> );
+ max-acache-size ( unlimited | <sizeval> ); // obsolete
max-cache-size ( default | unlimited | <sizeval> | <percentage> );
max-cache-ttl <integer>;
max-clients-per-query <integer>;
<integer> <quoted_string>; ... }; // may occur multiple times
view <string> [ <class> ] {
- acache-cleaning-interval <integer>;
- acache-enable <boolean>;
- additional-from-auth <boolean>;
- additional-from-cache <boolean>;
+ acache-cleaning-interval <integer>; // obsolete
+ acache-enable <boolean>; // obsolete
+ additional-from-auth <boolean>; // obsolete
+ additional-from-cache <boolean>; // obsolete
allow-new-zones <boolean>;
allow-notify { <address_match_element>; ... };
allow-query { <address_match_element>; ... };
match-clients { <address_match_element>; ... };
match-destinations { <address_match_element>; ... };
match-recursive-only <boolean>;
- max-acache-size ( unlimited | <sizeval> );
+ max-acache-size ( unlimited | <sizeval> ); // obsolete
max-cache-size ( default | unlimited | <sizeval> | <percentage> );
max-cache-ttl <integer>;
max-clients-per-query <integer>;
"compilation time");
#endif
} else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
- strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
+ strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0 &&
+ strcasecmp(cfg_obj_asstring(obj), "none") != 0) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"rrset-order: invalid order '%s'",
cfg_obj_asstring(obj));
DNSTAPOBJS = dnstap.@O@ dnstap.pb-c.@O@
# Alphabetically
-DNSOBJS = acache.@O@ acl.@O@ adb.@O@ badcache.@O@ byaddr.@O@ \
+DNSOBJS = acl.@O@ adb.@O@ badcache.@O@ byaddr.@O@ \
cache.@O@ callbacks.@O@ catz.@O@ clientinfo.@O@ compress.@O@ \
db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \
dlz.@O@ dns64.@O@ dnssec.@O@ ds.@O@ dyndb.@O@ ecs.@O@ \
DNSTAPSRCS = dnstap.c dnstap.pb-c.c
-DNSSRCS = acache.c acl.c adb.c badcache. byaddr.c \
+DNSSRCS = acl.c adb.c badcache. byaddr.c \
cache.c callbacks.c clientinfo.c compress.c \
db.c dbiterator.c dbtable.c diff.c dispatch.c \
dlz.c dns64.c dnssec.c ds.c dyndb.c ecs.c forward.c \
+++ /dev/null
-/*
- * Copyright (C) 2004-2008, 2012, 2013, 2015, 2016 Internet Systems Consortium, Inc. ("ISC")
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-/* $Id: acache.c,v 1.22 2008/02/07 23:46:54 tbox Exp $ */
-
-#include <config.h>
-
-#include <isc/atomic.h>
-#include <isc/event.h>
-#include <isc/hash.h>
-#include <isc/magic.h>
-#include <isc/mem.h>
-#include <isc/mutex.h>
-#include <isc/random.h>
-#include <isc/refcount.h>
-#include <isc/rwlock.h>
-#include <isc/serial.h>
-#include <isc/task.h>
-#include <isc/time.h>
-#include <isc/timer.h>
-
-#include <dns/acache.h>
-#include <dns/db.h>
-#include <dns/events.h>
-#include <dns/log.h>
-#include <dns/message.h>
-#include <dns/name.h>
-#include <dns/rdataset.h>
-#include <dns/result.h>
-#include <dns/zone.h>
-
-#define ACACHE_MAGIC ISC_MAGIC('A', 'C', 'H', 'E')
-#define DNS_ACACHE_VALID(acache) ISC_MAGIC_VALID(acache, ACACHE_MAGIC)
-
-#define ACACHEENTRY_MAGIC ISC_MAGIC('A', 'C', 'E', 'T')
-#define DNS_ACACHEENTRY_VALID(entry) ISC_MAGIC_VALID(entry, ACACHEENTRY_MAGIC)
-
-#define DBBUCKETS 67
-
-#if 0
-#define ATRACE(m) isc_log_write(dns_lctx, \
- DNS_LOGCATEGORY_DATABASE, \
- DNS_LOGMODULE_ACACHE, \
- ISC_LOG_DEBUG(3), \
- "acache %p: %s", acache, (m))
-#define AATRACE(a,m) isc_log_write(dns_lctx, \
- DNS_LOGCATEGORY_DATABASE, \
- DNS_LOGMODULE_ACACHE, \
- ISC_LOG_DEBUG(3), \
- "acache %p: %s", (a), (m))
-#else
-#define ATRACE(m)
-#define AATRACE(a, m)
-#endif
-
-/*
- * The following variables control incremental cleaning.
- * MINSIZE is how many bytes is the floor for dns_acache_setcachesize().
- * CLEANERINCREMENT is how many entries are examined in one pass.
- * (XXX simply derived from definitions in cache.c There may be better
- * constants here.)
- */
-#define DNS_ACACHE_MINSIZE 2097152U /* Bytes. 2097152 = 2 MB */
-#define DNS_ACACHE_CLEANERINCREMENT 1000 /* Number of entries. */
-
-#define DEFAULT_ACACHE_ENTRY_LOCK_COUNT 1009 /*%< Should be prime. */
-
-#if defined(ISC_RWLOCK_USEATOMIC) && defined(ISC_PLATFORM_HAVEATOMICSTORE)
-#define ACACHE_USE_RWLOCK 1
-#endif
-
-#ifdef ACACHE_USE_RWLOCK
-#define ACACHE_INITLOCK(l) isc_rwlock_init((l), 0, 0)
-#define ACACHE_DESTROYLOCK(l) isc_rwlock_destroy(l)
-#define ACACHE_LOCK(l, t) RWLOCK((l), (t))
-#define ACACHE_UNLOCK(l, t) RWUNLOCK((l), (t))
-
-#define acache_storetime(entry, t) \
- (isc_atomic_store((isc_int32_t *)&(entry)->lastused, (t)))
-#else
-#define ACACHE_INITLOCK(l) isc_mutex_init(l)
-#define ACACHE_DESTROYLOCK(l) DESTROYLOCK(l)
-#define ACACHE_LOCK(l, t) LOCK(l)
-#define ACACHE_UNLOCK(l, t) UNLOCK(l)
-
-#define acache_storetime(entry, t) ((entry)->lastused = (t))
-#endif
-
-/* Locked by acache lock */
-typedef struct dbentry {
- ISC_LINK(struct dbentry) link;
-
- dns_db_t *db;
- ISC_LIST(dns_acacheentry_t) originlist;
- ISC_LIST(dns_acacheentry_t) referlist;
-} dbentry_t;
-
-typedef ISC_LIST(dbentry_t) dbentrylist_t;
-
-typedef struct acache_cleaner acache_cleaner_t;
-
-typedef enum {
- cleaner_s_idle, /* Waiting for cleaning-interval to expire. */
- cleaner_s_busy, /* Currently cleaning. */
- cleaner_s_done /* Freed enough memory after being overmem. */
-} cleaner_state_t;
-
-/*
- * Convenience macros for comprehensive assertion checking.
- */
-#define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle && \
- (c)->resched_event != NULL)
-#define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy && \
- (c)->resched_event == NULL)
-
-struct acache_cleaner {
- isc_mutex_t lock;
- /*
- * Locks overmem_event, overmem. (See cache.c)
- */
-
- dns_acache_t *acache;
- unsigned int cleaning_interval; /* The cleaning-interval
- from named.conf,
- in seconds. */
-
- isc_stdtime_t last_cleanup_time; /* The time when the last
- cleanup task completed */
-
- isc_timer_t *cleaning_timer;
- isc_event_t *resched_event; /* Sent by cleaner task to
- itself to reschedule */
- isc_event_t *overmem_event;
-
- dns_acacheentry_t *current_entry; /* The bookmark entry to
- restart the cleaning.
- Locked by acache lock. */
- int increment; /* Number of entries to
- clean in one increment */
-
- unsigned long ncleaned; /* Number of entries cleaned
- up (for logging purposes) */
- cleaner_state_t state; /* Idle/Busy/Done. */
- isc_boolean_t overmem; /* The acache is in an overmem
- state. */
-};
-
-struct dns_acachestats {
- unsigned int hits;
- unsigned int queries;
- unsigned int misses;
- unsigned int adds;
- unsigned int deleted;
- unsigned int cleaned;
- unsigned int cleaner_runs;
- unsigned int overmem;
- unsigned int overmem_nocreates;
- unsigned int nomem;
-};
-
-/*
- * The actual acache object.
- */
-
-struct dns_acache {
- unsigned int magic;
-
- isc_mem_t *mctx;
- isc_refcount_t refs;
-
-#ifdef ACACHE_USE_RWLOCK
- isc_rwlock_t *entrylocks;
-#else
- isc_mutex_t *entrylocks;
-#endif
-
- isc_mutex_t lock;
-
- int live_cleaners;
- acache_cleaner_t cleaner;
- ISC_LIST(dns_acacheentry_t) entries;
- unsigned int dbentries;
- dbentrylist_t dbbucket[DBBUCKETS];
-
- isc_boolean_t shutting_down;
-
- isc_task_t *task;
- isc_event_t cevent;
- isc_boolean_t cevent_sent;
-
- dns_acachestats_t stats;
-};
-
-struct dns_acacheentry {
- unsigned int magic;
-
- unsigned int locknum;
- isc_refcount_t references;
-
- dns_acache_t *acache;
-
- /* Data for Management of cache entries */
- ISC_LINK(dns_acacheentry_t) link;
- ISC_LINK(dns_acacheentry_t) olink;
- ISC_LINK(dns_acacheentry_t) rlink;
-
- dns_db_t *origdb; /* reference to the DB
- holding this entry */
-
- /* Cache data */
- dns_zone_t *zone; /* zone this entry
- belongs to */
- dns_db_t *db; /* DB this entry belongs to */
- dns_dbversion_t *version; /* the version of the DB */
- dns_dbnode_t *node; /* node this entry
- belongs to */
- dns_name_t *foundname; /* corresponding DNS name
- and rdataset */
-
- /* Callback function and its argument */
- void (*callback)(dns_acacheentry_t *, void **);
- void *cbarg;
-
- /* Timestamp of the last time this entry is referred to */
- isc_stdtime32_t lastused;
-};
-
-/*
- * Internal functions (and prototypes).
- */
-static inline isc_boolean_t check_noentry(dns_acache_t *acache);
-static void destroy(dns_acache_t *acache);
-static void shutdown_entries(dns_acache_t *acache);
-static void shutdown_buckets(dns_acache_t *acache);
-static void destroy_entry(dns_acacheentry_t *ent);
-static inline void unlink_dbentries(dns_acache_t *acache,
- dns_acacheentry_t *ent);
-static inline isc_result_t finddbent(dns_acache_t *acache,
- dns_db_t *db, dbentry_t **dbentryp);
-static inline void clear_entry(dns_acache_t *acache, dns_acacheentry_t *entry);
-static isc_result_t acache_cleaner_init(dns_acache_t *acache,
- isc_timermgr_t *timermgr,
- acache_cleaner_t *cleaner);
-static void acache_cleaning_timer_action(isc_task_t *task, isc_event_t *event);
-static void acache_incremental_cleaning_action(isc_task_t *task,
- isc_event_t *event);
-static void acache_overmem_cleaning_action(isc_task_t *task,
- isc_event_t *event);
-static void acache_cleaner_shutdown_action(isc_task_t *task,
- isc_event_t *event);
-
-/*
- * acache should be locked. If it is not, the stats can get out of whack,
- * which is not a big deal for us since this is for debugging / stats
- */
-static void
-reset_stats(dns_acache_t *acache) {
- acache->stats.hits = 0;
- acache->stats.queries = 0;
- acache->stats.misses = 0;
- acache->stats.adds = 0;
- acache->stats.deleted = 0;
- acache->stats.cleaned = 0;
- acache->stats.overmem = 0;
- acache->stats.overmem_nocreates = 0;
- acache->stats.nomem = 0;
-}
-
-/*
- * The acache must be locked before calling.
- */
-static inline isc_boolean_t
-check_noentry(dns_acache_t *acache) {
- if (ISC_LIST_EMPTY(acache->entries) && acache->dbentries == 0) {
- return (ISC_TRUE);
- }
-
- return (ISC_FALSE);
-}
-
-/*
- * The acache must be locked before calling.
- */
-static void
-shutdown_entries(dns_acache_t *acache) {
- dns_acacheentry_t *entry, *entry_next;
-
- REQUIRE(DNS_ACACHE_VALID(acache));
- INSIST(acache->shutting_down);
-
- /*
- * Release the dependency of all entries, and detach them.
- */
- for (entry = ISC_LIST_HEAD(acache->entries);
- entry != NULL;
- entry = entry_next) {
- entry_next = ISC_LIST_NEXT(entry, link);
-
- ACACHE_LOCK(&acache->entrylocks[entry->locknum],
- isc_rwlocktype_write);
-
- /*
- * If the cleaner holds this entry, it will be unlinked and
- * freed in the cleaner later.
- */
- if (acache->cleaner.current_entry != entry)
- ISC_LIST_UNLINK(acache->entries, entry, link);
- unlink_dbentries(acache, entry);
- if (entry->callback != NULL) {
- (entry->callback)(entry, &entry->cbarg);
- entry->callback = NULL;
- }
-
- ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
- isc_rwlocktype_write);
-
- if (acache->cleaner.current_entry != entry)
- dns_acache_detachentry(&entry);
- }
-}
-
-/*
- * The acache must be locked before calling.
- */
-static void
-shutdown_buckets(dns_acache_t *acache) {
- int i;
- dbentry_t *dbent;
-
- REQUIRE(DNS_ACACHE_VALID(acache));
- INSIST(acache->shutting_down);
-
- for (i = 0; i < DBBUCKETS; i++) {
- while ((dbent = ISC_LIST_HEAD(acache->dbbucket[i])) != NULL) {
- INSIST(ISC_LIST_EMPTY(dbent->originlist) &&
- ISC_LIST_EMPTY(dbent->referlist));
- ISC_LIST_UNLINK(acache->dbbucket[i], dbent, link);
-
- dns_db_detach(&dbent->db);
-
- isc_mem_put(acache->mctx, dbent, sizeof(*dbent));
-
- acache->dbentries--;
- }
- }
-
- INSIST(acache->dbentries == 0);
-}
-
-static void
-shutdown_task(isc_task_t *task, isc_event_t *ev) {
- dns_acache_t *acache;
-
- UNUSED(task);
-
- acache = ev->ev_arg;
- INSIST(DNS_ACACHE_VALID(acache));
-
- isc_event_free(&ev);
-
- LOCK(&acache->lock);
-
- shutdown_entries(acache);
- shutdown_buckets(acache);
-
- UNLOCK(&acache->lock);
-
- dns_acache_detach(&acache);
-}
-
-/* The acache and the entry must be locked before calling. */
-static inline void
-unlink_dbentries(dns_acache_t *acache, dns_acacheentry_t *ent) {
- isc_result_t result;
- dbentry_t *dbent;
-
- if (ISC_LINK_LINKED(ent, olink)) {
- INSIST(ent->origdb != NULL);
- dbent = NULL;
- result = finddbent(acache, ent->origdb, &dbent);
- INSIST(result == ISC_R_SUCCESS);
-
- ISC_LIST_UNLINK(dbent->originlist, ent, olink);
- }
- if (ISC_LINK_LINKED(ent, rlink)) {
- INSIST(ent->db != NULL);
- dbent = NULL;
- result = finddbent(acache, ent->db, &dbent);
- INSIST(result == ISC_R_SUCCESS);
-
- ISC_LIST_UNLINK(dbent->referlist, ent, rlink);
- }
-}
-
-/* There must not be a reference to this entry. */
-static void
-destroy_entry(dns_acacheentry_t *entry) {
- dns_acache_t *acache;
-
- REQUIRE(DNS_ACACHEENTRY_VALID(entry));
-
- acache = entry->acache;
- REQUIRE(DNS_ACACHE_VALID(acache));
-
- /*
- * Since there is no reference to this entry, it is safe to call
- * clear_entry() here.
- */
- clear_entry(acache, entry);
-
- isc_mem_put(acache->mctx, entry, sizeof(*entry));
-
- dns_acache_detach(&acache);
-}
-
-static void
-destroy(dns_acache_t *acache) {
- int i;
-
- REQUIRE(DNS_ACACHE_VALID(acache));
-
- ATRACE("destroy");
-
- isc_mem_setwater(acache->mctx, NULL, NULL, 0, 0);
-
- if (acache->cleaner.overmem_event != NULL)
- isc_event_free(&acache->cleaner.overmem_event);
-
- if (acache->cleaner.resched_event != NULL)
- isc_event_free(&acache->cleaner.resched_event);
-
- if (acache->task != NULL)
- isc_task_detach(&acache->task);
-
- for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++)
- ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
- isc_mem_put(acache->mctx, acache->entrylocks,
- sizeof(*acache->entrylocks) *
- DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
-
- DESTROYLOCK(&acache->cleaner.lock);
-
- DESTROYLOCK(&acache->lock);
- acache->magic = 0;
-
- isc_mem_putanddetach(&acache->mctx, acache, sizeof(*acache));
-}
-
-static inline isc_result_t
-finddbent(dns_acache_t *acache, dns_db_t *db, dbentry_t **dbentryp) {
- int bucket;
- dbentry_t *dbentry;
-
- REQUIRE(DNS_ACACHE_VALID(acache));
- REQUIRE(db != NULL);
- REQUIRE(dbentryp != NULL && *dbentryp == NULL);
-
- /*
- * The caller must be holding the acache lock.
- */
-
- bucket = isc_hash_function(&db, sizeof(db), ISC_TRUE, NULL) % DBBUCKETS;
-
- for (dbentry = ISC_LIST_HEAD(acache->dbbucket[bucket]);
- dbentry != NULL;
- dbentry = ISC_LIST_NEXT(dbentry, link)) {
- if (dbentry->db == db)
- break;
- }
-
- *dbentryp = dbentry;
-
- if (dbentry == NULL)
- return (ISC_R_NOTFOUND);
- else
- return (ISC_R_SUCCESS);
-}
-
-static inline void
-clear_entry(dns_acache_t *acache, dns_acacheentry_t *entry) {
- REQUIRE(DNS_ACACHE_VALID(acache));
- REQUIRE(DNS_ACACHEENTRY_VALID(entry));
-
- /*
- * The caller must be holing the entry lock.
- */
-
- if (entry->foundname) {
- dns_rdataset_t *rdataset, *rdataset_next;
-
- for (rdataset = ISC_LIST_HEAD(entry->foundname->list);
- rdataset != NULL;
- rdataset = rdataset_next) {
- rdataset_next = ISC_LIST_NEXT(rdataset, link);
- ISC_LIST_UNLINK(entry->foundname->list,
- rdataset, link);
- dns_rdataset_disassociate(rdataset);
- isc_mem_put(acache->mctx, rdataset, sizeof(*rdataset));
- }
- if (dns_name_dynamic(entry->foundname))
- dns_name_free(entry->foundname, acache->mctx);
- isc_mem_put(acache->mctx, entry->foundname,
- sizeof(*entry->foundname));
- entry->foundname = NULL;
- }
-
- if (entry->node != NULL) {
- INSIST(entry->db != NULL);
- dns_db_detachnode(entry->db, &entry->node);
- }
- if (entry->version != NULL) {
- INSIST(entry->db != NULL);
- dns_db_closeversion(entry->db, &entry->version, ISC_FALSE);
- }
- if (entry->db != NULL)
- dns_db_detach(&entry->db);
- if (entry->zone != NULL)
- dns_zone_detach(&entry->zone);
-
- if (entry->origdb != NULL)
- dns_db_detach(&entry->origdb);
-}
-
-static isc_result_t
-acache_cleaner_init(dns_acache_t *acache, isc_timermgr_t *timermgr,
- acache_cleaner_t *cleaner)
-{
- int result;
-
- ATRACE("acache cleaner init");
-
- result = isc_mutex_init(&cleaner->lock);
- if (result != ISC_R_SUCCESS)
- goto fail;
-
- cleaner->increment = DNS_ACACHE_CLEANERINCREMENT;
- cleaner->state = cleaner_s_idle;
- cleaner->acache = acache;
- cleaner->overmem = ISC_FALSE;
-
- cleaner->cleaning_timer = NULL;
- cleaner->resched_event = NULL;
- cleaner->overmem_event = NULL;
- cleaner->current_entry = NULL;
-
- if (timermgr != NULL) {
- cleaner->acache->live_cleaners++;
-
- result = isc_task_onshutdown(acache->task,
- acache_cleaner_shutdown_action,
- acache);
- if (result != ISC_R_SUCCESS) {
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- "acache cleaner: "
- "isc_task_onshutdown() failed: %s",
- dns_result_totext(result));
- goto cleanup;
- }
-
- cleaner->cleaning_interval = 0; /* Initially turned off. */
- isc_stdtime_get(&cleaner->last_cleanup_time);
- result = isc_timer_create(timermgr, isc_timertype_inactive,
- NULL, NULL,
- acache->task,
- acache_cleaning_timer_action,
- cleaner, &cleaner->cleaning_timer);
- if (result != ISC_R_SUCCESS) {
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- "isc_timer_create() failed: %s",
- dns_result_totext(result));
- result = ISC_R_UNEXPECTED;
- goto cleanup;
- }
-
- cleaner->resched_event =
- isc_event_allocate(acache->mctx, cleaner,
- DNS_EVENT_ACACHECLEAN,
- acache_incremental_cleaning_action,
- cleaner, sizeof(isc_event_t));
- if (cleaner->resched_event == NULL) {
- result = ISC_R_NOMEMORY;
- goto cleanup;
- }
-
- cleaner->overmem_event =
- isc_event_allocate(acache->mctx, cleaner,
- DNS_EVENT_ACACHEOVERMEM,
- acache_overmem_cleaning_action,
- cleaner, sizeof(isc_event_t));
- if (cleaner->overmem_event == NULL) {
- result = ISC_R_NOMEMORY;
- goto cleanup;
- }
- }
-
- return (ISC_R_SUCCESS);
-
- cleanup:
- if (cleaner->overmem_event != NULL)
- isc_event_free(&cleaner->overmem_event);
- if (cleaner->resched_event != NULL)
- isc_event_free(&cleaner->resched_event);
- if (cleaner->cleaning_timer != NULL)
- isc_timer_detach(&cleaner->cleaning_timer);
- cleaner->acache->live_cleaners--;
- DESTROYLOCK(&cleaner->lock);
- fail:
- return (result);
-}
-
-static void
-begin_cleaning(acache_cleaner_t *cleaner) {
- dns_acacheentry_t *head;
- dns_acache_t *acache = cleaner->acache;
-
- /*
- * This function does not have to lock the cleaner, since critical
- * parameters (except current_entry, which is locked by acache lock,)
- * are only used in a single task context.
- */
-
- REQUIRE(CLEANER_IDLE(cleaner));
- INSIST(DNS_ACACHE_VALID(acache));
- INSIST(cleaner->current_entry == NULL);
-
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
- DNS_LOGMODULE_ACACHE, ISC_LOG_DEBUG(1),
- "begin acache cleaning, mem inuse %lu",
- (unsigned long)isc_mem_inuse(cleaner->acache->mctx));
-
- LOCK(&acache->lock);
-
- head = ISC_LIST_HEAD(acache->entries);
- if (head != NULL)
- dns_acache_attachentry(head, &cleaner->current_entry);
-
- UNLOCK(&acache->lock);
-
- if (cleaner->current_entry != NULL) {
- cleaner->ncleaned = 0;
- cleaner->state = cleaner_s_busy;
- isc_task_send(acache->task, &cleaner->resched_event);
- }
-
- return;
-}
-
-static void
-end_cleaning(acache_cleaner_t *cleaner, isc_event_t *event) {
- dns_acache_t *acache = cleaner->acache;
-
- REQUIRE(CLEANER_BUSY(cleaner));
- REQUIRE(event != NULL);
- REQUIRE(DNS_ACACHEENTRY_VALID(cleaner->current_entry));
-
- /* No need to lock the cleaner (see begin_cleaning()). */
-
- LOCK(&acache->lock);
-
- /*
- * Even if the cleaner has the last reference to the entry, which means
- * the entry has been unused, it may still be linked if unlinking the
- * entry has been delayed due to the reference.
- */
- if (isc_refcount_current(&cleaner->current_entry->references) == 1) {
- INSIST(cleaner->current_entry->callback == NULL);
-
- if (ISC_LINK_LINKED(cleaner->current_entry, link)) {
- ISC_LIST_UNLINK(acache->entries,
- cleaner->current_entry, link);
- }
- }
- dns_acache_detachentry(&cleaner->current_entry);
-
- if (cleaner->overmem)
- acache->stats.overmem++;
- acache->stats.cleaned += cleaner->ncleaned;
- acache->stats.cleaner_runs++;
-
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
- ISC_LOG_NOTICE,
- "acache %p stats: hits=%d misses=%d queries=%d "
- "adds=%d deleted=%d "
- "cleaned=%d cleaner_runs=%d overmem=%d "
- "overmem_nocreates=%d nomem=%d",
- acache,
- acache->stats.hits, acache->stats.misses,
- acache->stats.queries,
- acache->stats.adds, acache->stats.deleted,
- acache->stats.cleaned, acache->stats.cleaner_runs,
- acache->stats.overmem, acache->stats.overmem_nocreates,
- acache->stats.nomem);
- reset_stats(acache);
-
- isc_stdtime_get(&cleaner->last_cleanup_time);
-
- UNLOCK(&acache->lock);
-
- dns_acache_setcleaninginterval(cleaner->acache,
- cleaner->cleaning_interval);
-
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
- ISC_LOG_DEBUG(1), "end acache cleaning, "
- "%lu entries cleaned, mem inuse %lu",
- cleaner->ncleaned,
- (unsigned long)isc_mem_inuse(cleaner->acache->mctx));
-
- if (cleaner->overmem) {
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
- DNS_LOGMODULE_ACACHE, ISC_LOG_NOTICE,
- "acache is still in overmem state "
- "after cleaning");
- }
-
- cleaner->ncleaned = 0;
- cleaner->state = cleaner_s_idle;
- cleaner->resched_event = event;
-}
-
-/*
- * This is run once for every acache-cleaning-interval as defined
- * in named.conf.
- */
-static void
-acache_cleaning_timer_action(isc_task_t *task, isc_event_t *event) {
- acache_cleaner_t *cleaner = event->ev_arg;
-
- UNUSED(task);
-
- INSIST(event->ev_type == ISC_TIMEREVENT_TICK);
-
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
- ISC_LOG_DEBUG(1), "acache cleaning timer fired, "
- "cleaner state = %d", cleaner->state);
-
- if (cleaner->state == cleaner_s_idle)
- begin_cleaning(cleaner);
-
- isc_event_free(&event);
-}
-
-/* The caller must hold entry lock. */
-static inline isc_boolean_t
-entry_stale(acache_cleaner_t *cleaner, dns_acacheentry_t *entry,
- isc_stdtime32_t now32, unsigned int interval)
-{
- /*
- * If the callback has been canceled, we definitely do not need the
- * entry.
- */
- if (entry->callback == NULL)
- return (ISC_TRUE);
-
- if (interval > cleaner->cleaning_interval)
- interval = cleaner->cleaning_interval;
-
- if (entry->lastused + interval < now32)
- return (ISC_TRUE);
-
- /*
- * If the acache is in the overmem state, probabilistically decide if
- * the entry should be purged, based on the time passed from its last
- * use and the cleaning interval.
- */
- if (cleaner->overmem) {
- unsigned int passed;
- isc_uint32_t val;
-
- if (isc_serial_ge(now32, entry->lastused))
- passed = now32 - entry->lastused; /* <= interval */
- else
- passed = 0;
-
- if (passed > interval / 2)
- return (ISC_TRUE);
- isc_random_get(&val);
- if (passed > interval / 4)
- return (ISC_TF(val % 4 == 0));
- return (ISC_TF(val % 8 == 0));
- }
-
- return (ISC_FALSE);
-}
-
-/*
- * Do incremental cleaning.
- */
-static void
-acache_incremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
- acache_cleaner_t *cleaner = event->ev_arg;
- dns_acache_t *acache = cleaner->acache;
- dns_acacheentry_t *entry, *next = NULL;
- int n_entries;
- isc_stdtime32_t now32, last32;
- isc_stdtime_t now;
- unsigned int interval;
-
- INSIST(DNS_ACACHE_VALID(acache));
- INSIST(task == acache->task);
- INSIST(event->ev_type == DNS_EVENT_ACACHECLEAN);
-
- if (cleaner->state == cleaner_s_done) {
- cleaner->state = cleaner_s_busy;
- end_cleaning(cleaner, event);
- return;
- }
-
- INSIST(CLEANER_BUSY(cleaner));
-
- n_entries = cleaner->increment;
-
- isc_stdtime_get(&now);
- isc_stdtime_convert32(now, &now32);
-
- LOCK(&acache->lock);
-
- entry = cleaner->current_entry;
- isc_stdtime_convert32(cleaner->last_cleanup_time, &last32);
- if (isc_serial_ge(now32, last32))
- interval = now32 - last32;
- else
- interval = 0;
-
- while (n_entries-- > 0) {
- isc_boolean_t is_stale = ISC_FALSE;
-
- INSIST(entry != NULL);
-
- next = ISC_LIST_NEXT(entry, link);
-
- ACACHE_LOCK(&acache->entrylocks[entry->locknum],
- isc_rwlocktype_write);
-
- is_stale = entry_stale(cleaner, entry, now32, interval);
- if (is_stale) {
- ISC_LIST_UNLINK(acache->entries, entry, link);
- unlink_dbentries(acache, entry);
- if (entry->callback != NULL)
- (entry->callback)(entry, &entry->cbarg);
- entry->callback = NULL;
-
- cleaner->ncleaned++;
- }
-
- ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
- isc_rwlocktype_write);
-
- if (is_stale)
- dns_acache_detachentry(&entry);
-
- if (next == NULL) {
- if (cleaner->overmem) {
- entry = ISC_LIST_HEAD(acache->entries);
- if (entry != NULL) {
- /*
- * If we are still in the overmem
- * state, keep cleaning. In case we
- * exit from the loop immediately after
- * this, reset next to the head entry
- * as we'll expect it will be never
- * NULL.
- */
- isc_log_write(dns_lctx,
- DNS_LOGCATEGORY_DATABASE,
- DNS_LOGMODULE_ACACHE,
- ISC_LOG_DEBUG(1),
- "acache cleaner: "
- "still overmem, "
- "reset and try again");
- next = entry;
- continue;
- }
- }
-
- UNLOCK(&acache->lock);
- end_cleaning(cleaner, event);
- return;
- }
-
- entry = next;
- }
-
- /*
- * We have successfully performed a cleaning increment but have
- * not gone through the entire cache. Remember the entry that will
- * be the starting point in the next clean-up, and reschedule another
- * batch. If it fails, just try to continue anyway.
- */
- INSIST(next != NULL);
- dns_acache_detachentry(&cleaner->current_entry);
- dns_acache_attachentry(next, &cleaner->current_entry);
-
- UNLOCK(&acache->lock);
-
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
- ISC_LOG_DEBUG(1), "acache cleaner: checked %d entries, "
- "mem inuse %lu, sleeping", cleaner->increment,
- (unsigned long)isc_mem_inuse(cleaner->acache->mctx));
-
- isc_task_send(task, &event);
- INSIST(CLEANER_BUSY(cleaner));
-
- return;
-}
-
-/*
- * This is called when the acache either surpasses its upper limit
- * or shrinks beyond its lower limit.
- */
-static void
-acache_overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
- acache_cleaner_t *cleaner = event->ev_arg;
- isc_boolean_t want_cleaning = ISC_FALSE;
-
- UNUSED(task);
-
- INSIST(event->ev_type == DNS_EVENT_ACACHEOVERMEM);
- INSIST(cleaner->overmem_event == NULL);
-
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
- ISC_LOG_DEBUG(1), "overmem_cleaning_action called, "
- "overmem = %d, state = %d", cleaner->overmem,
- cleaner->state);
-
- LOCK(&cleaner->lock);
-
- if (cleaner->overmem) {
- if (cleaner->state == cleaner_s_idle)
- want_cleaning = ISC_TRUE;
- } else {
- if (cleaner->state == cleaner_s_busy)
- /*
- * end_cleaning() can't be called here because
- * then both cleaner->overmem_event and
- * cleaner->resched_event will point to this
- * event. Set the state to done, and then
- * when the acache_incremental_cleaning_action() event
- * is posted, it will handle the end_cleaning.
- */
- cleaner->state = cleaner_s_done;
- }
-
- cleaner->overmem_event = event;
-
- UNLOCK(&cleaner->lock);
-
- if (want_cleaning)
- begin_cleaning(cleaner);
-}
-
-static void
-water(void *arg, int mark) {
- dns_acache_t *acache = arg;
- isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
-
- REQUIRE(DNS_ACACHE_VALID(acache));
-
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
- DNS_LOGMODULE_ACACHE, ISC_LOG_DEBUG(1),
- "acache memory reaches %s watermark, mem inuse %lu",
- overmem ? "high" : "low",
- (unsigned long)isc_mem_inuse(acache->mctx));
-
- LOCK(&acache->cleaner.lock);
-
- if (acache->cleaner.overmem != overmem) {
- acache->cleaner.overmem = overmem;
-
- if (acache->cleaner.overmem_event != NULL)
- isc_task_send(acache->task,
- &acache->cleaner.overmem_event);
- isc_mem_waterack(acache->mctx, mark);
- }
-
- UNLOCK(&acache->cleaner.lock);
-}
-
-/*
- * The cleaner task is shutting down; do the necessary cleanup.
- */
-static void
-acache_cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) {
- dns_acache_t *acache = event->ev_arg;
- isc_boolean_t should_free = ISC_FALSE;
-
- INSIST(task == acache->task);
- INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
- INSIST(DNS_ACACHE_VALID(acache));
-
- ATRACE("acache cleaner shutdown");
-
- if (CLEANER_BUSY(&acache->cleaner))
- end_cleaning(&acache->cleaner, event);
- else
- isc_event_free(&event);
-
- LOCK(&acache->lock);
-
- acache->live_cleaners--;
- INSIST(acache->live_cleaners == 0);
-
- if (isc_refcount_current(&acache->refs) == 0) {
- INSIST(check_noentry(acache) == ISC_TRUE);
- should_free = ISC_TRUE;
- }
-
- /*
- * By detaching the timer in the context of its task,
- * we are guaranteed that there will be no further timer
- * events.
- */
- if (acache->cleaner.cleaning_timer != NULL)
- isc_timer_detach(&acache->cleaner.cleaning_timer);
-
- /* Make sure we don't reschedule anymore. */
- (void)isc_task_purge(task, NULL, DNS_EVENT_ACACHECLEAN, NULL);
-
- UNLOCK(&acache->lock);
-
- if (should_free)
- destroy(acache);
-}
-
-/*
- * Public functions.
- */
-
-isc_result_t
-dns_acache_create(dns_acache_t **acachep, isc_mem_t *mctx,
- isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr)
-{
- int i;
- isc_result_t result;
- dns_acache_t *acache;
-
- REQUIRE(acachep != NULL && *acachep == NULL);
- REQUIRE(mctx != NULL);
- REQUIRE(taskmgr != NULL);
-
- acache = isc_mem_get(mctx, sizeof(*acache));
- if (acache == NULL)
- return (ISC_R_NOMEMORY);
-
- ATRACE("create");
-
- result = isc_refcount_init(&acache->refs, 1);
- if (result != ISC_R_SUCCESS) {
- isc_mem_put(mctx, acache, sizeof(*acache));
- return (result);
- }
-
- result = isc_mutex_init(&acache->lock);
- if (result != ISC_R_SUCCESS) {
- isc_refcount_decrement(&acache->refs, NULL);
- isc_refcount_destroy(&acache->refs);
- isc_mem_put(mctx, acache, sizeof(*acache));
- return (result);
- }
-
- acache->mctx = NULL;
- isc_mem_attach(mctx, &acache->mctx);
- ISC_LIST_INIT(acache->entries);
-
- acache->shutting_down = ISC_FALSE;
-
- acache->task = NULL;
- acache->entrylocks = NULL;
-
- result = isc_task_create(taskmgr, 1, &acache->task);
- if (result != ISC_R_SUCCESS) {
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- "isc_task_create() failed(): %s",
- dns_result_totext(result));
- result = ISC_R_UNEXPECTED;
- goto cleanup;
- }
- isc_task_setname(acache->task, "acachetask", acache);
- ISC_EVENT_INIT(&acache->cevent, sizeof(acache->cevent), 0, NULL,
- DNS_EVENT_ACACHECONTROL, shutdown_task, NULL,
- NULL, NULL, NULL);
- acache->cevent_sent = ISC_FALSE;
-
- acache->dbentries = 0;
- for (i = 0; i < DBBUCKETS; i++)
- ISC_LIST_INIT(acache->dbbucket[i]);
-
- acache->entrylocks = isc_mem_get(mctx, sizeof(*acache->entrylocks) *
- DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
- if (acache->entrylocks == NULL) {
- result = ISC_R_NOMEMORY;
- goto cleanup;
- }
- for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++) {
- result = ACACHE_INITLOCK(&acache->entrylocks[i]);
- if (result != ISC_R_SUCCESS) {
- while (i-- > 0)
- ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
- isc_mem_put(mctx, acache->entrylocks,
- sizeof(*acache->entrylocks) *
- DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
- acache->entrylocks = NULL;
- goto cleanup;
- }
- }
-
- acache->live_cleaners = 0;
- result = acache_cleaner_init(acache, timermgr, &acache->cleaner);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
-
- acache->stats.cleaner_runs = 0;
- reset_stats(acache);
-
- acache->magic = ACACHE_MAGIC;
-
- *acachep = acache;
- return (ISC_R_SUCCESS);
-
- cleanup:
- if (acache->task != NULL)
- isc_task_detach(&acache->task);
- DESTROYLOCK(&acache->lock);
- isc_refcount_decrement(&acache->refs, NULL);
- isc_refcount_destroy(&acache->refs);
- if (acache->entrylocks != NULL) {
- for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++)
- ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
- isc_mem_put(mctx, acache->entrylocks,
- sizeof(*acache->entrylocks) *
- DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
- }
- isc_mem_put(mctx, acache, sizeof(*acache));
- isc_mem_detach(&mctx);
-
- return (result);
-}
-
-void
-dns_acache_attach(dns_acache_t *source, dns_acache_t **targetp) {
- REQUIRE(DNS_ACACHE_VALID(source));
- REQUIRE(targetp != NULL && *targetp == NULL);
-
- AATRACE(source, "attach");
-
- isc_refcount_increment(&source->refs, NULL);
-
- *targetp = source;
-}
-
-void
-dns_acache_countquerymiss(dns_acache_t *acache) {
- acache->stats.misses++; /* XXXSK danger: unlocked! */
- acache->stats.queries++; /* XXXSK danger: unlocked! */
-}
-
-void
-dns_acache_detach(dns_acache_t **acachep) {
- dns_acache_t *acache;
- unsigned int refs;
- isc_boolean_t should_free = ISC_FALSE;
-
- REQUIRE(acachep != NULL && DNS_ACACHE_VALID(*acachep));
- acache = *acachep;
-
- ATRACE("detach");
-
- isc_refcount_decrement(&acache->refs, &refs);
- if (refs == 0) {
- INSIST(check_noentry(acache) == ISC_TRUE);
- should_free = ISC_TRUE;
- }
-
- *acachep = NULL;
-
- /*
- * If we're exiting and the cleaner task exists, let it free the cache.
- */
- if (should_free && acache->live_cleaners > 0) {
- isc_task_shutdown(acache->task);
- should_free = ISC_FALSE;
- }
-
- if (should_free)
- destroy(acache);
-}
-
-void
-dns_acache_shutdown(dns_acache_t *acache) {
- REQUIRE(DNS_ACACHE_VALID(acache));
-
- LOCK(&acache->lock);
-
- ATRACE("shutdown");
-
- if (!acache->shutting_down) {
- isc_event_t *event;
- dns_acache_t *acache_evarg = NULL;
-
- INSIST(!acache->cevent_sent);
-
- acache->shutting_down = ISC_TRUE;
-
- isc_mem_setwater(acache->mctx, NULL, NULL, 0, 0);
-
- /*
- * Self attach the object in order to prevent it from being
- * destroyed while waiting for the event.
- */
- dns_acache_attach(acache, &acache_evarg);
- event = &acache->cevent;
- event->ev_arg = acache_evarg;
- isc_task_send(acache->task, &event);
- acache->cevent_sent = ISC_TRUE;
- }
-
- UNLOCK(&acache->lock);
-}
-
-isc_result_t
-dns_acache_setdb(dns_acache_t *acache, dns_db_t *db) {
- int bucket;
- dbentry_t *dbentry;
- isc_result_t result = ISC_R_SUCCESS;
-
- REQUIRE(DNS_ACACHE_VALID(acache));
- REQUIRE(db != NULL);
-
- ATRACE("setdb");
-
- LOCK(&acache->lock);
-
- dbentry = NULL;
- result = finddbent(acache, db, &dbentry);
- if (result == ISC_R_SUCCESS) {
- result = ISC_R_EXISTS;
- goto end;
- }
- result = ISC_R_SUCCESS;
-
- dbentry = isc_mem_get(acache->mctx, sizeof(*dbentry));
- if (dbentry == NULL) {
- result = ISC_R_NOMEMORY;
- goto end;
- }
-
- ISC_LINK_INIT(dbentry, link);
- ISC_LIST_INIT(dbentry->originlist);
- ISC_LIST_INIT(dbentry->referlist);
-
- dbentry->db = NULL;
- dns_db_attach(db, &dbentry->db);
-
- bucket = isc_hash_function(&db, sizeof(db), ISC_TRUE, NULL) % DBBUCKETS;
-
- ISC_LIST_APPEND(acache->dbbucket[bucket], dbentry, link);
-
- acache->dbentries++;
-
- end:
- UNLOCK(&acache->lock);
-
- return (result);
-}
-
-isc_result_t
-dns_acache_putdb(dns_acache_t *acache, dns_db_t *db) {
- int bucket;
- isc_result_t result;
- dbentry_t *dbentry;
- dns_acacheentry_t *entry;
-
- REQUIRE(DNS_ACACHE_VALID(acache));
- REQUIRE(db != NULL);
-
- ATRACE("putdb");
-
- LOCK(&acache->lock);
-
- dbentry = NULL;
- result = finddbent(acache, db, &dbentry);
- if (result != ISC_R_SUCCESS) {
- /*
- * The entry may have not been created due to memory shortage.
- */
- UNLOCK(&acache->lock);
- return (ISC_R_NOTFOUND);
- }
-
- /*
- * Release corresponding cache entries: for each entry, release all
- * links the entry has, and then callback to the entry holder (if any).
- * If no other external references exist (this can happen if the
- * original holder has canceled callback,) destroy it here.
- */
- while ((entry = ISC_LIST_HEAD(dbentry->originlist)) != NULL) {
- ACACHE_LOCK(&acache->entrylocks[entry->locknum],
- isc_rwlocktype_write);
-
- /*
- * Releasing olink first would avoid finddbent() in
- * unlink_dbentries().
- */
- ISC_LIST_UNLINK(dbentry->originlist, entry, olink);
- if (acache->cleaner.current_entry != entry)
- ISC_LIST_UNLINK(acache->entries, entry, link);
- unlink_dbentries(acache, entry);
-
- if (entry->callback != NULL)
- (entry->callback)(entry, &entry->cbarg);
- entry->callback = NULL;
-
- ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
- isc_rwlocktype_write);
-
- if (acache->cleaner.current_entry != entry)
- dns_acache_detachentry(&entry);
- }
- while ((entry = ISC_LIST_HEAD(dbentry->referlist)) != NULL) {
- ACACHE_LOCK(&acache->entrylocks[entry->locknum],
- isc_rwlocktype_write);
-
- ISC_LIST_UNLINK(dbentry->referlist, entry, rlink);
- if (acache->cleaner.current_entry != entry)
- ISC_LIST_UNLINK(acache->entries, entry, link);
- unlink_dbentries(acache, entry);
-
- if (entry->callback != NULL)
- (entry->callback)(entry, &entry->cbarg);
- entry->callback = NULL;
-
- ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
- isc_rwlocktype_write);
-
- if (acache->cleaner.current_entry != entry)
- dns_acache_detachentry(&entry);
- }
-
- INSIST(ISC_LIST_EMPTY(dbentry->originlist) &&
- ISC_LIST_EMPTY(dbentry->referlist));
-
- bucket = isc_hash_function(&db, sizeof(db), ISC_TRUE, NULL) % DBBUCKETS;
-
- ISC_LIST_UNLINK(acache->dbbucket[bucket], dbentry, link);
- dns_db_detach(&dbentry->db);
-
- isc_mem_put(acache->mctx, dbentry, sizeof(*dbentry));
-
- acache->dbentries--;
-
- acache->stats.deleted++;
-
- UNLOCK(&acache->lock);
-
- return (ISC_R_SUCCESS);
-}
-
-isc_result_t
-dns_acache_createentry(dns_acache_t *acache, dns_db_t *origdb,
- void (*callback)(dns_acacheentry_t *, void **),
- void *cbarg, dns_acacheentry_t **entryp)
-{
- dns_acacheentry_t *newentry;
- isc_result_t result;
- isc_uint32_t r;
-
- REQUIRE(DNS_ACACHE_VALID(acache));
- REQUIRE(entryp != NULL && *entryp == NULL);
- REQUIRE(origdb != NULL);
-
- /*
- * Should we exceed our memory limit for some reason (for
- * example, if the cleaner does not run aggressively enough),
- * then we will not create additional entries.
- *
- * XXXSK: It might be better to lock the acache->cleaner->lock,
- * but locking may be an expensive bottleneck. If we misread
- * the value, we will occasionally refuse to create a few
- * cache entries, or create a few that we should not. I do not
- * expect this to happen often, and it will not have very bad
- * effects when it does. So no lock for now.
- */
- if (acache->cleaner.overmem) {
- acache->stats.overmem_nocreates++; /* XXXSK danger: unlocked! */
- return (ISC_R_NORESOURCES);
- }
-
- newentry = isc_mem_get(acache->mctx, sizeof(*newentry));
- if (newentry == NULL) {
- acache->stats.nomem++; /* XXXMLG danger: unlocked! */
- return (ISC_R_NOMEMORY);
- }
-
- isc_random_get(&r);
- newentry->locknum = r % DEFAULT_ACACHE_ENTRY_LOCK_COUNT;
-
- result = isc_refcount_init(&newentry->references, 1);
- if (result != ISC_R_SUCCESS) {
- isc_mem_put(acache->mctx, newentry, sizeof(*newentry));
- return (result);
- };
-
- ISC_LINK_INIT(newentry, link);
- ISC_LINK_INIT(newentry, olink);
- ISC_LINK_INIT(newentry, rlink);
-
- newentry->acache = NULL;
- dns_acache_attach(acache, &newentry->acache);
-
- newentry->zone = NULL;
- newentry->db = NULL;
- newentry->version = NULL;
- newentry->node = NULL;
- newentry->foundname = NULL;
-
- newentry->callback = callback;
- newentry->cbarg = cbarg;
- newentry->origdb = NULL;
- dns_db_attach(origdb, &newentry->origdb);
-
- isc_stdtime_get(&newentry->lastused);
-
- newentry->magic = ACACHEENTRY_MAGIC;
-
- *entryp = newentry;
-
- return (ISC_R_SUCCESS);
-}
-
-isc_result_t
-dns_acache_getentry(dns_acacheentry_t *entry, dns_zone_t **zonep,
- dns_db_t **dbp, dns_dbversion_t **versionp,
- dns_dbnode_t **nodep, dns_name_t *fname,
- dns_message_t *msg, isc_stdtime_t now)
-{
- isc_result_t result = ISC_R_SUCCESS;
- dns_rdataset_t *erdataset;
- isc_stdtime32_t now32;
- dns_acache_t *acache;
- int locknum;
-
- REQUIRE(DNS_ACACHEENTRY_VALID(entry));
- REQUIRE(zonep == NULL || *zonep == NULL);
- REQUIRE(dbp != NULL && *dbp == NULL);
- REQUIRE(versionp != NULL && *versionp == NULL);
- REQUIRE(nodep != NULL && *nodep == NULL);
- REQUIRE(fname != NULL);
- REQUIRE(msg != NULL);
- acache = entry->acache;
- REQUIRE(DNS_ACACHE_VALID(acache));
-
- locknum = entry->locknum;
- ACACHE_LOCK(&acache->entrylocks[locknum], isc_rwlocktype_read);
-
- isc_stdtime_convert32(now, &now32);
- acache_storetime(entry, now32);
-
- if (entry->zone != NULL && zonep != NULL)
- dns_zone_attach(entry->zone, zonep);
-
- if (entry->db == NULL) {
- *dbp = NULL;
- *versionp = NULL;
- } else {
- dns_db_attach(entry->db, dbp);
- dns_db_attachversion(entry->db, entry->version, versionp);
- }
- if (entry->node == NULL)
- *nodep = NULL;
- else {
- dns_db_attachnode(entry->db, entry->node, nodep);
-
- INSIST(entry->foundname != NULL);
- dns_name_copy(entry->foundname, fname, NULL);
- for (erdataset = ISC_LIST_HEAD(entry->foundname->list);
- erdataset != NULL;
- erdataset = ISC_LIST_NEXT(erdataset, link)) {
- dns_rdataset_t *ardataset;
-
- ardataset = NULL;
- result = dns_message_gettemprdataset(msg, &ardataset);
- if (result != ISC_R_SUCCESS) {
- ACACHE_UNLOCK(&acache->entrylocks[locknum],
- isc_rwlocktype_read);
- goto fail;
- }
-
- /*
- * XXXJT: if we simply clone the rdataset, we'll get
- * lost wrt cyclic ordering. We'll need an additional
- * trick to get the latest counter from the original
- * header.
- */
- dns_rdataset_clone(erdataset, ardataset);
- ISC_LIST_APPEND(fname->list, ardataset, link);
- }
- }
-
- entry->acache->stats.hits++; /* XXXMLG danger: unlocked! */
- entry->acache->stats.queries++;
-
- ACACHE_UNLOCK(&acache->entrylocks[locknum], isc_rwlocktype_read);
-
- return (result);
-
- fail:
- while ((erdataset = ISC_LIST_HEAD(fname->list)) != NULL) {
- ISC_LIST_UNLINK(fname->list, erdataset, link);
- dns_rdataset_disassociate(erdataset);
- dns_message_puttemprdataset(msg, &erdataset);
- }
- if (*nodep != NULL)
- dns_db_detachnode(*dbp, nodep);
- if (*versionp != NULL)
- dns_db_closeversion(*dbp, versionp, ISC_FALSE);
- if (*dbp != NULL)
- dns_db_detach(dbp);
- if (zonep != NULL && *zonep != NULL)
- dns_zone_detach(zonep);
-
- return (result);
-}
-
-isc_result_t
-dns_acache_setentry(dns_acache_t *acache, dns_acacheentry_t *entry,
- dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
- dns_dbnode_t *node, dns_name_t *fname)
-{
- isc_result_t result;
- dbentry_t *odbent;
- dbentry_t *rdbent = NULL;
- isc_boolean_t close_version = ISC_FALSE;
- dns_acacheentry_t *dummy_entry = NULL;
-
- REQUIRE(DNS_ACACHE_VALID(acache));
- REQUIRE(DNS_ACACHEENTRY_VALID(entry));
-
- LOCK(&acache->lock); /* XXX: need to lock it here for ordering */
- ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write);
-
- /* Set zone */
- if (zone != NULL)
- dns_zone_attach(zone, &entry->zone);
- /* Set DB */
- if (db != NULL)
- dns_db_attach(db, &entry->db);
- /*
- * Set DB version. If the version is not given by the caller,
- * which is the case for glue or cache DBs, use the current version.
- */
- if (version == NULL) {
- if (db != NULL) {
- dns_db_currentversion(db, &version);
- close_version = ISC_TRUE;
- }
- }
- if (version != NULL) {
- INSIST(db != NULL);
- dns_db_attachversion(db, version, &entry->version);
- }
- if (close_version)
- dns_db_closeversion(db, &version, ISC_FALSE);
- /* Set DB node. */
- if (node != NULL) {
- INSIST(db != NULL);
- dns_db_attachnode(db, node, &entry->node);
- }
-
- /*
- * Set list of the corresponding rdatasets, if given.
- * To minimize the overhead and memory consumption, we'll do this for
- * positive cache only, in which case the DB node is non NULL.
- * We do not want to cache incomplete information, so give up the
- * entire entry when a memory shortage happen during the process.
- */
- if (node != NULL) {
- dns_rdataset_t *ardataset, *crdataset;
-
- entry->foundname = isc_mem_get(acache->mctx,
- sizeof(*entry->foundname));
-
- if (entry->foundname == NULL) {
- result = ISC_R_NOMEMORY;
- goto fail;
- }
- dns_name_init(entry->foundname, NULL);
- result = dns_name_dup(fname, acache->mctx,
- entry->foundname);
- if (result != ISC_R_SUCCESS)
- goto fail;
-
- for (ardataset = ISC_LIST_HEAD(fname->list);
- ardataset != NULL;
- ardataset = ISC_LIST_NEXT(ardataset, link)) {
- crdataset = isc_mem_get(acache->mctx,
- sizeof(*crdataset));
- if (crdataset == NULL) {
- result = ISC_R_NOMEMORY;
- goto fail;
- }
-
- dns_rdataset_init(crdataset);
- dns_rdataset_clone(ardataset, crdataset);
- ISC_LIST_APPEND(entry->foundname->list, crdataset,
- link);
- }
- }
-
- odbent = NULL;
- result = finddbent(acache, entry->origdb, &odbent);
- if (result != ISC_R_SUCCESS)
- goto fail;
- if (db != NULL) {
- rdbent = NULL;
- result = finddbent(acache, db, &rdbent);
- if (result != ISC_R_SUCCESS)
- goto fail;
- }
-
- ISC_LIST_APPEND(acache->entries, entry, link);
- ISC_LIST_APPEND(odbent->originlist, entry, olink);
- if (rdbent != NULL)
- ISC_LIST_APPEND(rdbent->referlist, entry, rlink);
-
- /*
- * The additional cache needs an implicit reference to entries in its
- * link.
- */
- dns_acache_attachentry(entry, &dummy_entry);
-
- ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
- isc_rwlocktype_write);
-
- acache->stats.adds++;
- UNLOCK(&acache->lock);
-
- return (ISC_R_SUCCESS);
-
- fail:
- clear_entry(acache, entry);
-
- ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
- isc_rwlocktype_write);
- UNLOCK(&acache->lock);
-
- return (result);
-}
-
-isc_boolean_t
-dns_acache_cancelentry(dns_acacheentry_t *entry) {
- dns_acache_t *acache;
- isc_boolean_t callback_active;
-
- REQUIRE(DNS_ACACHEENTRY_VALID(entry));
-
- acache = entry->acache;
-
- INSIST(DNS_ACACHE_VALID(entry->acache));
-
- LOCK(&acache->lock);
- ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write);
-
- callback_active = ISC_TF(entry->cbarg != NULL);
-
- /*
- * Release dependencies stored in this entry as much as possible.
- * The main link cannot be released, since the acache object has
- * a reference to this entry; the empty entry will be released in
- * the next cleaning action.
- */
- unlink_dbentries(acache, entry);
- clear_entry(entry->acache, entry);
-
- entry->callback = NULL;
- entry->cbarg = NULL;
-
- ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
- isc_rwlocktype_write);
- UNLOCK(&acache->lock);
-
- return (callback_active);
-}
-
-void
-dns_acache_attachentry(dns_acacheentry_t *source,
- dns_acacheentry_t **targetp)
-{
- REQUIRE(DNS_ACACHEENTRY_VALID(source));
- REQUIRE(targetp != NULL && *targetp == NULL);
-
- isc_refcount_increment(&source->references, NULL);
-
- *targetp = source;
-}
-
-void
-dns_acache_detachentry(dns_acacheentry_t **entryp) {
- dns_acacheentry_t *entry;
- unsigned int refs;
-
- REQUIRE(entryp != NULL && DNS_ACACHEENTRY_VALID(*entryp));
- entry = *entryp;
-
- isc_refcount_decrement(&entry->references, &refs);
-
- /*
- * If there are no references to the entry, the entry must have been
- * unlinked and can be destroyed safely.
- */
- if (refs == 0) {
- INSIST(!ISC_LINK_LINKED(entry, link));
- (*entryp)->acache->stats.deleted++;
- destroy_entry(entry);
- }
-
- *entryp = NULL;
-}
-
-void
-dns_acache_setcleaninginterval(dns_acache_t *acache, unsigned int t) {
- isc_interval_t interval;
- isc_result_t result;
-
- REQUIRE(DNS_ACACHE_VALID(acache));
-
- ATRACE("dns_acache_setcleaninginterval");
-
- LOCK(&acache->lock);
-
- /*
- * It may be the case that the acache has already shut down.
- * If so, it has no timer. (Not sure if this can really happen.)
- */
- if (acache->cleaner.cleaning_timer == NULL)
- goto unlock;
-
- acache->cleaner.cleaning_interval = t;
-
- if (t == 0) {
- result = isc_timer_reset(acache->cleaner.cleaning_timer,
- isc_timertype_inactive,
- NULL, NULL, ISC_TRUE);
- } else {
- isc_interval_set(&interval, acache->cleaner.cleaning_interval,
- 0);
- result = isc_timer_reset(acache->cleaner.cleaning_timer,
- isc_timertype_ticker,
- NULL, &interval, ISC_FALSE);
- }
- if (result != ISC_R_SUCCESS)
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
- DNS_LOGMODULE_ACACHE, ISC_LOG_WARNING,
- "could not set acache cleaning interval: %s",
- isc_result_totext(result));
- else
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
- DNS_LOGMODULE_ACACHE, ISC_LOG_NOTICE,
- "acache %p cleaning interval set to %d.",
- acache, t);
-
- unlock:
- UNLOCK(&acache->lock);
-}
-
-/*
- * This function was derived from cache.c:dns_cache_setcachesize(). See the
- * function for more details about the logic.
- */
-void
-dns_acache_setcachesize(dns_acache_t *acache, size_t size) {
- size_t hiwater, lowater;
-
- REQUIRE(DNS_ACACHE_VALID(acache));
-
- if (size != 0U && size < DNS_ACACHE_MINSIZE)
- size = DNS_ACACHE_MINSIZE;
-
- hiwater = size - (size >> 3);
- lowater = size - (size >> 2);
-
- if (size == 0U || hiwater == 0U || lowater == 0U)
- isc_mem_setwater(acache->mctx, water, acache, 0, 0);
- else
- isc_mem_setwater(acache->mctx, water, acache,
- hiwater, lowater);
-}
#define DCTX_MAGIC ISC_MAGIC('D', 'C', 'T', 'X')
#define VALID_DCTX(x) ISC_MAGIC_VALID(x, DCTX_MAGIC)
-#define TABLE_READY \
- do { \
- unsigned int i; \
- \
- if ((cctx->allowed & DNS_COMPRESS_READY) == 0) { \
- cctx->allowed |= DNS_COMPRESS_READY; \
- for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) \
- cctx->table[i] = NULL; \
- } \
- } while (0)
+static unsigned char maptolower[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+/*
+ * The tableindex array below is of size 256, one entry for each
+ * unsigned char value. The tableindex array elements are dependent on
+ * DNS_COMPRESS_TABLESIZE. The table was created using the following
+ * function.
+ *
+ * static void
+ * gentable(unsigned char *table) {
+ * unsigned int i;
+ * const unsigned int left = DNS_COMPRESS_TABLESIZE - 38;
+ * long r;
+ *
+ * for (i = 0; i < 26; i++) {
+ * table['A' + i] = i;
+ * table['a' + i] = i;
+ * }
+ *
+ * for (i = 0; i <= 9; i++)
+ * table['0' + i] = i + 26;
+ *
+ * table['-'] = 36;
+ * table['_'] = 37;
+ *
+ * for (i = 0; i < 256; i++) {
+ * if ((i >= 'a' && i <= 'z') ||
+ * (i >= 'A' && i <= 'Z') ||
+ * (i >= '0' && i <= '9') ||
+ * (i == '-') ||
+ * (i == '_'))
+ * continue;
+ * r = random() % left;
+ * table[i] = 38 + r;
+ * }
+ * }
+ */
+static unsigned char tableindex[256] = {
+ 0x3e, 0x3e, 0x33, 0x2d, 0x30, 0x38, 0x31, 0x3c,
+ 0x2b, 0x33, 0x30, 0x3f, 0x2d, 0x3c, 0x36, 0x3a,
+ 0x28, 0x2c, 0x2a, 0x37, 0x3d, 0x34, 0x35, 0x2d,
+ 0x39, 0x2b, 0x2f, 0x2c, 0x3b, 0x32, 0x2b, 0x39,
+ 0x30, 0x38, 0x28, 0x3c, 0x32, 0x33, 0x39, 0x38,
+ 0x27, 0x2b, 0x39, 0x30, 0x27, 0x24, 0x2f, 0x2b,
+ 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
+ 0x22, 0x3a, 0x29, 0x36, 0x31, 0x3c, 0x35, 0x26,
+ 0x31, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0x3e, 0x3b, 0x39, 0x2f, 0x25,
+ 0x27, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0x36, 0x3b, 0x2f, 0x2f, 0x2e,
+ 0x29, 0x33, 0x2a, 0x36, 0x28, 0x3f, 0x2e, 0x29,
+ 0x2c, 0x29, 0x36, 0x2d, 0x32, 0x3d, 0x33, 0x2a,
+ 0x2e, 0x2f, 0x3b, 0x30, 0x3d, 0x39, 0x2b, 0x36,
+ 0x2a, 0x2f, 0x2c, 0x26, 0x3a, 0x37, 0x30, 0x3d,
+ 0x2a, 0x36, 0x33, 0x2c, 0x38, 0x3d, 0x32, 0x3e,
+ 0x26, 0x2a, 0x2c, 0x35, 0x27, 0x39, 0x3b, 0x31,
+ 0x2a, 0x37, 0x3c, 0x27, 0x32, 0x29, 0x39, 0x37,
+ 0x34, 0x3f, 0x39, 0x2e, 0x38, 0x2b, 0x2c, 0x3e,
+ 0x3b, 0x3b, 0x2d, 0x33, 0x3b, 0x3b, 0x32, 0x3d,
+ 0x3f, 0x3a, 0x34, 0x26, 0x35, 0x30, 0x31, 0x39,
+ 0x27, 0x2f, 0x3d, 0x35, 0x35, 0x36, 0x2e, 0x29,
+ 0x38, 0x27, 0x34, 0x32, 0x2c, 0x3c, 0x31, 0x28,
+ 0x37, 0x38, 0x37, 0x34, 0x33, 0x29, 0x32, 0x34,
+ 0x3f, 0x26, 0x34, 0x34, 0x32, 0x27, 0x30, 0x33,
+ 0x33, 0x2d, 0x2b, 0x28, 0x3f, 0x33, 0x2b, 0x39,
+ 0x37, 0x39, 0x2c, 0x3d, 0x35, 0x39, 0x27, 0x2f
+};
/***
*** Compression
cctx->mctx = mctx;
cctx->count = 0;
cctx->allowed = DNS_COMPRESS_ENABLED;
+
+ memset(&cctx->table[0], 0, sizeof(cctx->table));
+
cctx->magic = CCTX_MAGIC;
+
return (ISC_R_SUCCESS);
}
REQUIRE(VALID_CCTX(cctx));
- if ((cctx->allowed & DNS_COMPRESS_READY) != 0) {
- for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) {
- while (cctx->table[i] != NULL) {
- node = cctx->table[i];
- cctx->table[i] = cctx->table[i]->next;
- if ((node->offset & 0x8000) != 0)
- isc_mem_put(cctx->mctx, node->r.base,
- node->r.length);
- if (node->count < DNS_COMPRESS_INITIALNODES)
- continue;
- isc_mem_put(cctx->mctx, node, sizeof(*node));
- }
+ for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) {
+ while (cctx->table[i] != NULL) {
+ node = cctx->table[i];
+ cctx->table[i] = cctx->table[i]->next;
+ if ((node->offset & 0x8000) != 0)
+ isc_mem_put(cctx->mctx, node->r.base,
+ node->r.length);
+ if (node->count < DNS_COMPRESS_INITIALNODES)
+ continue;
+ isc_mem_put(cctx->mctx, node, sizeof(*node));
}
}
+
cctx->magic = 0;
cctx->allowed = 0;
cctx->edns = -1;
return (cctx->edns);
}
-#define NODENAME(node, name) \
-do { \
- (name)->length = (node)->r.length; \
- (name)->labels = (node)->labels; \
- (name)->ndata = (node)->r.base; \
- (name)->attributes = DNS_NAMEATTR_ABSOLUTE; \
-} while (0)
-
/*
* Find the longest match of name in the table.
* If match is found return ISC_TRUE. prefix, suffix and offset are updated.
dns_compress_findglobal(dns_compress_t *cctx, const dns_name_t *name,
dns_name_t *prefix, isc_uint16_t *offset)
{
- dns_name_t tname, nname;
+ dns_name_t tname;
dns_compressnode_t *node = NULL;
- unsigned int labels, hash, n;
+ unsigned int labels, index, n;
+ unsigned int numlabels;
+ unsigned char *p;
REQUIRE(VALID_CCTX(cctx));
REQUIRE(dns_name_isabsolute(name) == ISC_TRUE);
REQUIRE(offset != NULL);
- if ((cctx->allowed & DNS_COMPRESS_ENABLED) == 0)
+ if (ISC_UNLIKELY((cctx->allowed & DNS_COMPRESS_ENABLED) == 0))
return (ISC_FALSE);
- TABLE_READY;
-
if (cctx->count == 0)
return (ISC_FALSE);
INSIST(labels > 0);
dns_name_init(&tname, NULL);
- dns_name_init(&nname, NULL);
- for (n = 0; n < labels - 1; n++) {
- dns_name_getlabelsequence(name, n, labels - n, &tname);
- hash = dns_name_hash(&tname, ISC_FALSE) %
- DNS_COMPRESS_TABLESIZE;
- for (node = cctx->table[hash]; node != NULL; node = node->next)
+ numlabels = labels > 3U ? 3U : labels;
+ p = name->ndata;
+
+ for (n = 0; n < numlabels - 1; n++) {
+ unsigned char ch, llen;
+ unsigned int firstoffset, length;
+
+ firstoffset = p - name->ndata;
+ length = name->length - firstoffset;
+
+ /*
+ * We calculate the table index using the first
+ * character in the first label of the suffix name.
+ */
+ ch = p[1];
+ index = tableindex[ch];
+ if (ISC_LIKELY((cctx->allowed &
+ DNS_COMPRESS_CASESENSITIVE) != 0))
{
- NODENAME(node, &nname);
- if ((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0) {
- if (dns_name_caseequal(&nname, &tname))
- break;
- } else {
- if (dns_name_equal(&nname, &tname))
- break;
+ for (node = cctx->table[index];
+ node != NULL;
+ node = node->next)
+ {
+ if (ISC_UNLIKELY(node->name.length != length))
+ continue;
+
+ if (ISC_LIKELY(memcmp(node->name.ndata,
+ p, length) == 0))
+ goto found;
+ }
+ } else {
+ for (node = cctx->table[index];
+ node != NULL;
+ node = node->next)
+ {
+ unsigned int l, count;
+ unsigned char c;
+ unsigned char *label1, *label2;
+
+ if (ISC_UNLIKELY(node->name.length != length))
+ continue;
+
+ l = labels - n;
+ if (ISC_UNLIKELY(node->name.labels != l))
+ continue;
+
+ label1 = node->name.ndata;
+ label2 = p;
+ while (ISC_LIKELY(l-- > 0)) {
+ count = *label1++;
+ if (count != *label2++)
+ goto cont1;
+
+ /* no bitstring support */
+ INSIST(count <= 63);
+
+ /* Loop unrolled for performance */
+ while (ISC_LIKELY(count > 3)) {
+ c = maptolower[label1[0]];
+ if (c != maptolower[label2[0]])
+ goto cont1;
+ c = maptolower[label1[1]];
+ if (c != maptolower[label2[1]])
+ goto cont1;
+ c = maptolower[label1[2]];
+ if (c != maptolower[label2[2]])
+ goto cont1;
+ c = maptolower[label1[3]];
+ if (c != maptolower[label2[3]])
+ goto cont1;
+ count -= 4;
+ label1 += 4;
+ label2 += 4;
+ }
+ while (ISC_LIKELY(count-- > 0)) {
+ c = maptolower[*label1++];
+ if (c != maptolower[*label2++])
+ goto cont1;
+ }
+ }
+ break;
+ cont1:
+ continue;
}
}
+
if (node != NULL)
break;
+
+ llen = *p;
+ p += llen + 1;
}
+ found:
/*
* If node == NULL, we found no match at all.
*/
unsigned int start;
unsigned int n;
unsigned int count;
- unsigned int hash;
+ unsigned int index;
dns_compressnode_t *node;
unsigned int length;
unsigned int tlength;
REQUIRE(VALID_CCTX(cctx));
REQUIRE(dns_name_isabsolute(name));
- if ((cctx->allowed & DNS_COMPRESS_ENABLED) == 0)
+ if (ISC_UNLIKELY((cctx->allowed & DNS_COMPRESS_ENABLED) == 0))
return;
- TABLE_READY;
-
if (offset >= 0x4000)
return;
dns_name_init(&tname, NULL);
r.base = tmp;
dns_name_fromregion(&xname, &r);
+ if (count > 2U)
+ count = 2U;
+
while (count > 0) {
+ unsigned char ch;
+
dns_name_getlabelsequence(&xname, start, n, &tname);
- hash = dns_name_hash(&tname, ISC_FALSE) %
- DNS_COMPRESS_TABLESIZE;
+ /*
+ * We calculate the table index using the first
+ * character in the first label of tname.
+ */
+ ch = tname.ndata[1];
+ index = tableindex[ch];
tlength = name_length(&tname);
toffset = (isc_uint16_t)(offset + (length - tlength));
if (toffset >= 0x4000)
toffset |= 0x8000;
node->offset = toffset;
dns_name_toregion(&tname, &node->r);
- node->labels = (isc_uint8_t)dns_name_countlabels(&tname);
- node->next = cctx->table[hash];
- cctx->table[hash] = node;
+ dns_name_init(&node->name, NULL);
+ node->name.length = node->r.length;
+ node->name.ndata = node->r.base;
+ node->name.labels = tname.labels;
+ node->name.attributes = DNS_NAMEATTR_ABSOLUTE;
+ node->next = cctx->table[index];
+ cctx->table[index] = node;
start++;
n--;
count--;
REQUIRE(VALID_CCTX(cctx));
- if ((cctx->allowed & DNS_COMPRESS_ENABLED) == 0)
- return;
-
- if ((cctx->allowed & DNS_COMPRESS_READY) == 0)
+ if (ISC_UNLIKELY((cctx->allowed & DNS_COMPRESS_ENABLED) == 0))
return;
for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) {
NULL, /* getnoqname */
NULL, /* addclosest */
NULL, /* getclosest */
- NULL, /* getadditional */
- NULL, /* setadditional */
- NULL, /* putadditional */
rdataset_settrust, /* settrust */
NULL, /* expire */
NULL, /* clearprefetch */
NULL, /* setownercase */
- NULL /* getownercase */
+ NULL, /* getownercase */
+ NULL /* addglue */
};
typedef struct ecdb_rdatasetiter {
VERSION=@BIND9_VERSION@
-HEADERS = acache.h acl.h adb.h badcache.h bit.h byaddr.h \
+HEADERS = acl.h adb.h badcache.h bit.h byaddr.h \
cache.h callbacks.h catz.h cert.h \
client.h clientinfo.h compress.h \
db.h dbiterator.h dbtable.h diff.h dispatch.h \
+++ /dev/null
-/*
- * Copyright (C) 2004, 2006, 2007, 2013, 2016 Internet Systems Consortium, Inc. ("ISC")
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-/* $Id: acache.h,v 1.8 2007/06/19 23:47:16 tbox Exp $ */
-
-#ifndef DNS_ACACHE_H
-#define DNS_ACACHE_H 1
-
-/*****
- ***** Module Info
- *****/
-
-/*
- * Acache
- *
- * The Additional Cache Object
- *
- * This module manages internal caching entries that correspond to
- * the additional section data of a DNS DB node (an RRset header, more
- * accurately). An additional cache entry is expected to be (somehow)
- * attached to a particular RR in a particular DB node, and contains a set
- * of information of an additional data for the DB node.
- *
- * An additional cache object is intended to be created as a per-view
- * object, and manages all cache entries within the view.
- *
- * The intended usage of the additional caching is to provide a short cut
- * to additional glue RRs of an NS RR. For each NS RR, it is often
- * necessary to look for glue RRs to make a proper response. Once the
- * glue RRs are known, the additional caching allows the client to
- * associate the information to the original NS RR so that further
- * expensive lookups can be avoided for the NS RR.
- *
- * Each additional cache entry contains information to identify a
- * particular DB node and (optionally) an associated RRset. The
- * information consists of its zone, database, the version of the
- * database, database node, and RRset.
- *
- * A "negative" information can also be cached. For example, if a glue
- * RR does not exist as an authoritative data in the same zone as that
- * of the NS RR, this fact can be cached by specifying a NULL pointer
- * for the database, version, and node. (See the description for
- * dns_acache_getentry() below for more details.)
- *
- * Since each member stored in an additional cache entry holds a reference
- * to a corresponding object, a stale cache entry may cause unnecessary
- * memory consumption. For instance, when a zone is reloaded, additional
- * cache entries that have a reference to the zone (and its DB and/or
- * DB nodes) can delay the cleanup of the referred objects. In order to
- * minimize such a bad effect, this module provides several cleanup
- * mechanisms.
- *
- * The first one is a shutdown procedure called when the associated view
- * is shut down. In this case, dns_acache_shutdown() will be called and
- * all cache entries will be purged. This mechanism will help the
- * situation when the configuration is reloaded or the main server is
- * stopped.
- *
- * Per-DB cleanup mechanism is also provided. Each additional cache entry
- * is associated with related DB, which is expected to have been
- * registered when the DB was created by dns_acache_setdb(). If a
- * particular DB is going to be destroyed, the primary holder of the DB,
- * a typical example of which is a zone, will call dns_acache_putdb().
- * Then this module will clean-up all cache entries associated with the
- * DB. This mechanism is effective when a secondary zone DB is going to
- * be stale after a zone transfer.
- *
- * Finally, this module supports for periodic clean-up of stale entries.
- * Each cache entry has a timestamp field, which is updated every time
- * the entry is referred. A periodically invoked cleaner checks the
- * timestamp of each entry, and purge entries that have not been referred
- * for a certain period. The cleaner interval can be specified by
- * dns_acache_setcleaninginterval(). If the periodic clean-up is not
- * enough, it is also possible to specify the upper limit of entries
- * in terms of the memory consumption. If the maximum value is
- * specified, the cleaner is invoked when the memory consumption reaches
- * the high watermark inferred from the maximum value. In this case,
- * the cleaner will use more aggressive algorithm to decide the "victim"
- * entries. The maximum value can be specified by
- * dns_acache_setcachesize().
- *
- * When a cache entry is going to be purged within this module, the
- * callback function specified at the creation time will be called.
- * The callback function is expected to release all internal resources
- * related to the entry, which will typically be specific to DB
- * implementation, and to call dns_acache_detachentry(). The callback
- * mechanism is very important, since the holder of an additional cache
- * entry may not be able to initiate the clean-up of the entry, due to
- * the reference ordering. For example, as long as an additional cache
- * entry has a reference to a DB object, the DB cannot be freed, in which
- * a DB node may have a reference to the cache entry.
- *
- * Credits:
- * The basic idea of this kind of short-cut for frequently used
- * information is similar to the "pre-compiled answer" approach adopted
- * in nsd by NLnet LABS with RIPE NCC. Our work here is an independent
- * effort, but the success of nsd encouraged us to pursue this path.
- *
- * The design and implementation of the periodic memory management and
- * the upper limitation of memory consumption was derived from the cache
- * DB implementation of BIND9.
- *
- * MP:
- * There are two main locks in this module. One is for each entry, and
- * the other is for the additional cache object.
- *
- * Reliability:
- * The callback function for a cache entry is called with holding the
- * entry lock. Thus, it implicitly assumes the callback function does not
- * call a function that can require the lock. Typically, the only
- * function that can be called from the callback function safely is
- * dns_acache_detachentry(). The breakage of this implicit assumption
- * may cause a deadlock.
- *
- * Resources:
- * In a 32-bit architecture (such as i386), the following additional
- * memory is required comparing to the case that disables this module.
- * - 76 bytes for each additional cache entry
- * - if the entry has a DNS name and associated RRset,
- * * 44 bytes + size of the name (1-255 bytes)
- * * 52 bytes x number_of_RRs
- * - 28 bytes for each DB related to this module
- *
- * Using the additional cache also requires extra memory consumption in
- * the DB implementation. In the current implementation for rbtdb, we
- * need:
- * - two additional pointers for each DB node (8 bytes for a 32-bit
- * architecture
- * - for each RR associated to an RR in a DB node, we also need
- * a pointer and management objects to support the additional cache
- * function. These are allocated on-demand. The total size is
- * 32 bytes for a 32-bit architecture.
- *
- * Security:
- * Since this module does not handle any low-level data directly,
- * no security issue specific to this module is anticipated.
- *
- * Standards:
- * None.
- */
-
-/***
- *** Imports
- ***/
-
-#include <isc/mutex.h>
-#include <isc/lang.h>
-#include <isc/refcount.h>
-#include <isc/stdtime.h>
-
-#include <dns/types.h>
-
-/***
- *** Functions
- ***/
-ISC_LANG_BEGINDECLS
-
-isc_result_t
-dns_acache_create(dns_acache_t **acachep, isc_mem_t *mctx,
- isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr);
-/*
- * Create a new DNS additional cache object.
- *
- * Requires:
- *
- * 'mctx' is a valid memory context
- *
- * 'taskmgr' is a valid task manager
- *
- * 'timermgr' is a valid timer or NULL. If NULL, no periodic cleaning of
- * the cache will take place.
- *
- * 'acachep' is a valid pointer, and *acachep == NULL
- *
- * Ensures:
- *
- * '*acachep' is attached to the newly created cache
- *
- * Returns:
- *
- * ISC_R_SUCCESS
- * ISC_R_NOMEMORY
- * ISC_R_UNEXPECTED
- */
-
-void
-dns_acache_attach(dns_acache_t *source, dns_acache_t **targetp);
-/*
- * Attach *targetp to cache.
- *
- * Requires:
- *
- * 'acache' is a valid additional cache.
- *
- * 'targetp' points to a NULL dns_acache_t *.
- *
- * Ensures:
- *
- * *targetp is attached to the 'source' additional cache.
- */
-
-void
-dns_acache_detach(dns_acache_t **acachep);
-/*
- * Detach *acachep from its cache.
- *
- * Requires:
- *
- * '*acachep' points to a valid additional cache.
- *
- * Ensures:
- *
- * *acachep is NULL.
- *
- * If '*acachep' is the last reference to the cache and the additional
- * cache does not have an outstanding task, all resources used by the
- * cache will be freed.
- */
-
-void
-dns_acache_setcleaninginterval(dns_acache_t *acache, unsigned int t);
-/*
- * Set the periodic cleaning interval of an additional cache to 'interval'
- * seconds.
- */
-
-void
-dns_acache_setcachesize(dns_acache_t *acache, size_t size);
-/*
- * Set the maximum additional cache size. 0 means unlimited.
- */
-
-isc_result_t
-dns_acache_setdb(dns_acache_t *acache, dns_db_t *db);
-/*
- * Set 'db' in 'acache' when the db can be referred from acache, in order
- * to provide a hint for resolving the back reference.
- *
- * Requires:
- * 'acache' is a valid acache pointer.
- * 'db' is a valid DNS DB pointer.
- *
- * Ensures:
- * 'acache' will have a reference to 'db'.
- *
- * Returns:
- * ISC_R_SUCCESS
- * ISC_R_EXISTS (which means the specified 'db' is already set)
- * ISC_R_NOMEMORY
- */
-
-isc_result_t
-dns_acache_putdb(dns_acache_t *acache, dns_db_t *db);
-/*
- * Release 'db' from 'acache' if it has been set by dns_acache_setdb().
- *
- * Requires:
- * 'acache' is a valid acache pointer.
- * 'db' is a valid DNS DB pointer.
- *
- * Ensures:
- * 'acache' will release the reference to 'db'. Additionally, the content
- * of each cache entry that is related to the 'db' will be released via
- * the callback function.
- *
- * Returns:
- * ISC_R_SUCCESS
- * ISC_R_NOTFOUND (which means the specified 'db' is not set in 'acache')
- * ISC_R_NOMEMORY
- */
-
-void
-dns_acache_shutdown(dns_acache_t *acache);
-/*
- * Shutdown 'acache'.
- *
- * Requires:
- *
- * '*acache' is a valid additional cache.
- */
-
-isc_result_t
-dns_acache_createentry(dns_acache_t *acache, dns_db_t *origdb,
- void (*callback)(dns_acacheentry_t *, void **),
- void *cbarg, dns_acacheentry_t **entryp);
-/*
- * Create an additional cache entry. A new entry is created and attached to
- * the given additional cache object. A callback function is also associated
- * with the created entry, which will be called when the cache entry is purged
- * for some reason.
- *
- * Requires:
- *
- * 'acache' is a valid additional cache.
- * 'entryp' is a valid pointer, and *entryp == NULL
- * 'origdb' is a valid DNS DB pointer.
- * 'callback' and 'cbarg' can be NULL. In this case, however, the entry
- * is meaningless (and will be cleaned-up in the next periodical
- * cleaning).
- *
- * Ensures:
- * '*entryp' will point to a new additional cache entry.
- *
- * Returns:
- * ISC_R_SUCCESS
- * ISC_R_NOMEMORY
- */
-
-isc_result_t
-dns_acache_getentry(dns_acacheentry_t *entry, dns_zone_t **zonep,
- dns_db_t **dbp, dns_dbversion_t **versionp,
- dns_dbnode_t **nodep, dns_name_t *fname,
- dns_message_t *msg, isc_stdtime_t now);
-/*
- * Get content from a particular additional cache entry.
- *
- * Requires:
- *
- * 'entry' is a valid additional cache entry.
- * 'zonep' is a NULL pointer or '*zonep' == NULL (this is the only
- * optional parameter.)
- * 'dbp' is a valid pointer, and '*dbp' == NULL
- * 'versionp' is a valid pointer, and '*versionp' == NULL
- * 'nodep' is a valid pointer, and '*nodep' == NULL
- * 'fname' is a valid DNS name.
- * 'msg' is a valid DNS message.
- *
- * Ensures:
- * Several possible cases can happen according to the content.
- * 1. For a positive cache entry,
- * '*zonep' will point to the corresponding zone (if zonep is a valid
- * pointer),
- * '*dbp' will point to a DB for the zone,
- * '*versionp' will point to its version, and
- * '*nodep' will point to the corresponding DB node.
- * 'fname' will have the DNS name of the DB node and contain a list of
- * rdataset for the node (which can be an empty list).
- *
- * 2. For a negative cache entry that means no corresponding zone exists,
- * '*zonep' == NULL (if zonep is a valid pointer)
- * '*dbp', '*versionp', and '*nodep' will be NULL.
- *
- * 3. For a negative cache entry that means no corresponding DB node
- * exists, '*zonep' will point to the corresponding zone (if zonep is a
- * valid pointer),
- * '*dbp' will point to a corresponding DB for zone,
- * '*versionp' will point to its version.
- * '*nodep' will be kept as NULL.
- * 'fname' will not change.
- *
- * On failure, no new references will be created.
- *
- * Returns:
- * ISC_R_SUCCESS
- * ISC_R_NOMEMORY
- */
-
-isc_result_t
-dns_acache_setentry(dns_acache_t *acache, dns_acacheentry_t *entry,
- dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
- dns_dbnode_t *node, dns_name_t *fname);
-/*
- * Set content to a particular additional cache entry.
- *
- * Requires:
- * 'acache' is a valid additional cache.
- * 'entry' is a valid additional cache entry.
- * All the others pointers are NULL or a valid pointer of the
- * corresponding type.
- *
- * Returns:
- * ISC_R_SUCCESS
- * ISC_R_NOMEMORY
- * ISC_R_NOTFOUND
- */
-
-isc_boolean_t
-dns_acache_cancelentry(dns_acacheentry_t *entry);
-/*
- * Cancel the use of the cache entry 'entry'. This function is supposed to
- * be called when the node that holds the entry finds the content is not
- * correct any more. This function will try to release as much dependency as
- * possible, and will be ready to be cleaned-up. The registered callback
- * function will be canceled and will never called.
- *
- * Requires:
- * 'entry' is a valid additional cache entry.
- *
- * Returns:
- * ISC_TRUE if the entry was active when canceled
- */
-
-void
-dns_acache_attachentry(dns_acacheentry_t *source, dns_acacheentry_t **targetp);
-/*
- * Attach *targetp to the cache entry 'source'.
- *
- * Requires:
- *
- * 'source' is a valid additional cache entry.
- *
- * 'targetp' points to a NULL dns_acacheentry_t *.
- *
- * Ensures:
- *
- * *targetp is attached to 'source'.
- */
-
-void
-dns_acache_detachentry(dns_acacheentry_t **entryp);
-/*
- * Detach *entryp from its cache.
- *
- * Requires:
- *
- * '*entryp' points to a valid additional cache entry.
- *
- * Ensures:
- *
- * *entryp is NULL.
- *
- * If '*entryp' is the last reference to the entry,
- * cache does not have an outstanding task, all resources used by the
- * entry (including the entry object itself) will be freed.
- */
-
-void
-dns_acache_countquerymiss(dns_acache_t *acache);
-/*
- * Count up a missed acache query. XXXMLG need more docs.
- */
-
-ISC_LANG_ENDDECLS
-
-#endif /* DNS_ACACHE_H */
#include <isc/region.h>
#include <dns/types.h>
+#include <dns/name.h>
ISC_LANG_BEGINDECLS
#define DNS_COMPRESS_CASESENSITIVE 0x02 /*%< case sensitive compression. */
#define DNS_COMPRESS_ENABLED 0x04
-#define DNS_COMPRESS_READY 0x80000000
-
-#define DNS_COMPRESS_TABLESIZE 64
+/*
+ * DNS_COMPRESS_TABLESIZE must be a power of 2. The compress code
+ * utilizes this assumption.
+ */
+#define DNS_COMPRESS_TABLEBITS 6
+#define DNS_COMPRESS_TABLESIZE (1U << DNS_COMPRESS_TABLEBITS)
+#define DNS_COMPRESS_TABLEMASK (DNS_COMPRESS_TABLESIZE - 1)
#define DNS_COMPRESS_INITIALNODES 16
typedef struct dns_compressnode dns_compressnode_t;
struct dns_compressnode {
- isc_region_t r;
+ dns_compressnode_t *next;
isc_uint16_t offset;
isc_uint16_t count;
- isc_uint8_t labels;
- dns_compressnode_t *next;
+ isc_region_t r;
+ dns_name_t name;
};
struct dns_compress {
#define DNS_LOGMODULE_SDB (&dns_modules[22])
#define DNS_LOGMODULE_DIFF (&dns_modules[23])
#define DNS_LOGMODULE_HINTS (&dns_modules[24])
-#define DNS_LOGMODULE_ACACHE (&dns_modules[25])
+#define DNS_LOGMODULE_UNUSED1 (&dns_modules[25])
#define DNS_LOGMODULE_DLZ (&dns_modules[26])
#define DNS_LOGMODULE_DNSSEC (&dns_modules[27])
#define DNS_LOGMODULE_CRYPTO (&dns_modules[28])
dns_name_t *name,
dns_rdataset_t *neg,
dns_rdataset_t *negsig);
- isc_result_t (*getadditional)(dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype,
- dns_acache_t *acache,
- dns_zone_t **zonep,
- dns_db_t **dbp,
- dns_dbversion_t **versionp,
- dns_dbnode_t **nodep,
- dns_name_t *fname,
- dns_message_t *msg,
- isc_stdtime_t now);
- isc_result_t (*setadditional)(dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype,
- dns_acache_t *acache,
- dns_zone_t *zone,
- dns_db_t *db,
- dns_dbversion_t *version,
- dns_dbnode_t *node,
- dns_name_t *fname);
- isc_result_t (*putadditional)(dns_acache_t *acache,
- dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype);
void (*settrust)(dns_rdataset_t *rdataset,
dns_trust_t trust);
void (*expire)(dns_rdataset_t *rdataset);
void (*clearprefetch)(dns_rdataset_t *rdataset);
void (*setownercase)(dns_rdataset_t *rdataset,
const dns_name_t *name);
- void (*getownercase)(const dns_rdataset_t *rdataset, dns_name_t *name);
+ void (*getownercase)(const dns_rdataset_t *rdataset,
+ dns_name_t *name);
+ isc_result_t (*addglue)(dns_rdataset_t *rdataset,
+ dns_dbversion_t *version,
+ unsigned int options,
+ dns_message_t *msg);
} dns_rdatasetmethods_t;
#define DNS_RDATASET_MAGIC ISC_MAGIC('D','N','S','R')
* Output the RRset in load order.
*/
+#define DNS_RDATASETATTR_NONE 0x00000000 /*%< No ordering. */
#define DNS_RDATASETATTR_QUESTION 0x00000001
#define DNS_RDATASETATTR_RENDERED 0x00000002 /*%< Used by message.c */
#define DNS_RDATASETATTR_ANSWERED 0x00000004 /*%< Used by server. */
#define DNS_RDATASETATTR_NCACHE 0x00000080 /*%< Used by resolver. */
#define DNS_RDATASETATTR_CHAINING 0x00000100 /*%< Used by resolver. */
#define DNS_RDATASETATTR_TTLADJUSTED 0x00000200 /*%< Used by message.c */
-#define DNS_RDATASETATTR_FIXEDORDER 0x00000400
-#define DNS_RDATASETATTR_RANDOMIZE 0x00000800
+#define DNS_RDATASETATTR_FIXEDORDER 0x00000400 /*%< Fixed ordering. */
+#define DNS_RDATASETATTR_RANDOMIZE 0x00000800 /*%< Random ordering. */
#define DNS_RDATASETATTR_CHASE 0x00001000 /*%< Used by resolver. */
#define DNS_RDATASETATTR_NXDOMAIN 0x00002000
#define DNS_RDATASETATTR_NOQNAME 0x00004000
#define DNS_RDATASETATTR_OPTOUT 0x00100000 /*%< OPTOUT proof */
#define DNS_RDATASETATTR_NEGATIVE 0x00200000
#define DNS_RDATASETATTR_PREFETCH 0x00400000
+#define DNS_RDATASETATTR_CYCLIC 0x00800000 /*%< Cyclic ordering. */
/*%
* _OMITDNSSEC:
*/
#define DNS_RDATASETTOWIRE_OMITDNSSEC 0x0001
+/*%
+ * _FILTERAAAA
+ * If A records are present, omit AAAA records when adding
+ * glue
+ */
+#define DNS_RDATASETADDGLUE_FILTERAAAA 0x0001
+
void
dns_rdataset_init(dns_rdataset_t *rdataset);
/*%<
*\li 'name' to be valid and have NSEC3 and RRSIG(NSEC3) rdatasets.
*/
-isc_result_t
-dns_rdataset_getadditional(dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype,
- dns_acache_t *acache,
- dns_zone_t **zonep,
- dns_db_t **dbp,
- dns_dbversion_t **versionp,
- dns_dbnode_t **nodep,
- dns_name_t *fname,
- dns_message_t *msg,
- isc_stdtime_t now);
-/*%<
- * Get cached additional information from the DB node for a particular
- * 'rdataset.' 'type' is one of dns_rdatasetadditional_fromauth,
- * dns_rdatasetadditional_fromcache, and dns_rdatasetadditional_fromglue,
- * which specifies the origin of the information. 'qtype' is intended to
- * be used for specifying a particular rdata type in the cached information.
- *
- * Requires:
- * \li 'rdataset' is a valid rdataset.
- * \li 'acache' can be NULL, in which case this function will simply return
- * ISC_R_FAILURE.
- * \li For the other pointers, see dns_acache_getentry().
- *
- * Ensures:
- * \li See dns_acache_getentry().
- *
- * Returns:
- * \li #ISC_R_SUCCESS
- * \li #ISC_R_FAILURE - additional information caching is not supported.
- * \li #ISC_R_NOTFOUND - the corresponding DB node has not cached additional
- * information for 'rdataset.'
- * \li Any error that dns_acache_getentry() can return.
- */
-
-isc_result_t
-dns_rdataset_setadditional(dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype,
- dns_acache_t *acache,
- dns_zone_t *zone,
- dns_db_t *db,
- dns_dbversion_t *version,
- dns_dbnode_t *node,
- dns_name_t *fname);
-/*%<
- * Set cached additional information to the DB node for a particular
- * 'rdataset.' See dns_rdataset_getadditional for the semantics of 'type'
- * and 'qtype'.
- *
- * Requires:
- * \li 'rdataset' is a valid rdataset.
- * \li 'acache' can be NULL, in which case this function will simply return
- * ISC_R_FAILURE.
- * \li For the other pointers, see dns_acache_setentry().
- *
- * Ensures:
- * \li See dns_acache_setentry().
- *
- * Returns:
- * \li #ISC_R_SUCCESS
- * \li #ISC_R_FAILURE - additional information caching is not supported.
- * \li #ISC_R_NOMEMORY
- * \li Any error that dns_acache_setentry() can return.
- */
-
-isc_result_t
-dns_rdataset_putadditional(dns_acache_t *acache,
- dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype);
-/*%<
- * Discard cached additional information stored in the DB node for a particular
- * 'rdataset.' See dns_rdataset_getadditional for the semantics of 'type'
- * and 'qtype'.
- *
- * Requires:
- * \li 'rdataset' is a valid rdataset.
- * \li 'acache' can be NULL, in which case this function will simply return
- * ISC_R_FAILURE.
- *
- * Ensures:
- * \li See dns_acache_cancelentry().
- *
- * Returns:
- * \li #ISC_R_SUCCESS
- * \li #ISC_R_FAILURE - additional information caching is not supported.
- * \li #ISC_R_NOTFOUND - the corresponding DB node has not cached additional
- * information for 'rdataset.'
- */
-
void
dns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
/*%<
* according to it. If CASESET is not set, do nothing.
*/
+isc_result_t
+dns_rdataset_addglue(dns_rdataset_t *rdataset,
+ dns_dbversion_t *version,
+ unsigned int options,
+ dns_message_t *msg);
+/*%<
+ * Add glue records for rdataset to the additional section of message in
+ * 'msg'. 'rdataset' must be of type NS. If DNS_RDATASETADDGLUE_FILTERAAAA
+ * is set in 'options' there is type A glue, type AAAA glue is not added.
+ *
+ * In case a successful result is not returned, the caller should try to
+ * add glue directly to the message by iterating for additional data.
+ *
+ * Requires:
+ * \li 'rdataset' is a valid NS rdataset.
+ * \li 'version' is the DB version.
+ * \li 'options' is options; currently only _FILTERAAAA is defined.
+ * \li 'msg' is the DNS message to which the glue should be added.
+ *
+ * Returns:
+ *\li #ISC_R_SUCCESS
+ *\li #ISC_R_NOTIMPLEMENTED
+ *\li #ISC_R_FAILURE
+ *\li Any error that dns_rdata_additionaldata() can return.
+ */
+
void
dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_rdata_rrsig_t *rrsig, isc_stdtime_t now,
#include <isc/types.h>
-typedef struct dns_acache dns_acache_t;
-typedef struct dns_acacheentry dns_acacheentry_t;
-typedef struct dns_acachestats dns_acachestats_t;
typedef struct dns_acl dns_acl_t;
typedef struct dns_aclelement dns_aclelement_t;
typedef struct dns_aclenv dns_aclenv_t;
dns_resolver_t * resolver;
dns_adb_t * adb;
dns_requestmgr_t * requestmgr;
- dns_acache_t * acache;
dns_cache_t * cache;
dns_db_t * cachedb;
dns_db_t * hints;
dns_fwdtable_t * fwdtable;
isc_boolean_t recursion;
isc_boolean_t auth_nxdomain;
- isc_boolean_t additionalfromcache;
- isc_boolean_t additionalfromauth;
isc_boolean_t minimal_any;
dns_minimaltype_t minimalresponses;
isc_boolean_t enablednssec;
* DNS_R_BADNAME failed rdata checks.
*/
-void
-dns_zone_setacache(dns_zone_t *zone, dns_acache_t *acache);
-/*%<
- * Associate the zone with an additional cache.
- *
- * Require:
- * 'zone' to be a valid zone.
- * 'acache' to be a non NULL pointer.
- *
- * Ensures:
- * 'zone' will have a reference to 'acache'
- */
-
void
dns_zone_setcheckmx(dns_zone_t *zone, dns_checkmxfunc_t checkmx);
/*%<
{ "dns/sdb", 0 },
{ "dns/diff", 0 },
{ "dns/hints", 0 },
- { "dns/acache", 0 },
+ { "dns/unused1", 0 },
{ "dns/dlz", 0 },
{ "dns/dnssec", 0 },
{ "dns/crypto", 0 },
* XXXMLG These should come from a config setting.
*/
#define SCRATCHPAD_SIZE 512
-#define NAME_COUNT 8
+#define NAME_COUNT 64
#define OFFSET_COUNT 4
#define RDATA_COUNT 8
#define RDATALIST_COUNT 8
-#define RDATASET_COUNT RDATALIST_COUNT
+#define RDATASET_COUNT 64
/*%
* Text representation of the different items, for message_totext
result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
if (result != ISC_R_SUCCESS)
goto cleanup;
+ isc_mempool_setfillcount(m->namepool, NAME_COUNT);
isc_mempool_setfreemax(m->namepool, NAME_COUNT);
isc_mempool_setname(m->namepool, "msg:names");
&m->rdspool);
if (result != ISC_R_SUCCESS)
goto cleanup;
- isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
+ isc_mempool_setfillcount(m->rdspool, RDATASET_COUNT);
+ isc_mempool_setfreemax(m->rdspool, RDATASET_COUNT);
isc_mempool_setname(m->rdspool, "msg:rdataset");
dynbuf = NULL;
unsigned int first, unsigned int n,
dns_name_t *target)
{
- unsigned char *offsets;
- dns_offsets_t odata;
+ unsigned char *p, l;
unsigned int firstoffset, endoffset;
+ unsigned int i;
/*
* Make 'target' refer to the 'n' labels including and following
REQUIRE(n <= source->labels - first); /* note first+n could overflow */
REQUIRE(BINDABLE(target));
- SETUP_OFFSETS(source, offsets, odata);
-
- if (first == source->labels)
+ p = source->ndata;
+ if (ISC_UNLIKELY(first == source->labels)) {
firstoffset = source->length;
- else
- firstoffset = offsets[first];
+ } else {
+ for (i = 0; i < first; i++) {
+ l = *p;
+ p += l + 1;
+ }
+ firstoffset = p - source->ndata;
+ }
- if (first + n == source->labels)
+ if (ISC_LIKELY(first + n == source->labels))
endoffset = source->length;
- else
- endoffset = offsets[first + n];
+ else {
+ for (i = 0; i < n; i++) {
+ l = *p;
+ p += l + 1;
+ }
+ endoffset = p - source->ndata;
+ }
target->ndata = &source->ndata[firstoffset];
target->length = endoffset - firstoffset;
offset = 0;
nlabels = 0;
absolute = ISC_FALSE;
- while (offset != length) {
+ while (ISC_LIKELY(offset != length)) {
INSIST(nlabels < 128);
offsets[nlabels++] = offset;
- count = *ndata++;
- offset++;
+ count = *ndata;
INSIST(count <= 63);
- offset += count;
- ndata += count;
+ offset += count + 1;
+ ndata += count + 1;
INSIST(offset <= length);
- if (count == 0) {
+ if (ISC_UNLIKELY(count == 0)) {
absolute = ISC_TRUE;
break;
}
rdataset_current,
rdataset_clone,
rdataset_count,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- rdataset_settrust,
- NULL,
- NULL,
- NULL,
- NULL
+ NULL, /* addnoqname */
+ NULL, /* getnoqname */
+ NULL, /* addclosest */
+ NULL, /* getclosest */
+ rdataset_settrust, /* settrust */
+ NULL, /* expire */
+ NULL, /* clearprefetch */
+ NULL, /* setownercase */
+ NULL, /* getownercase */
+ NULL /* addglue */
};
isc_result_t
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id: order.c,v 1.10 2007/06/19 23:47:16 tbox Exp $ */
-
/*! \file */
#include <config.h>
REQUIRE(DNS_ORDER_VALID(order));
REQUIRE(mode == DNS_RDATASETATTR_RANDOMIZE ||
mode == DNS_RDATASETATTR_FIXEDORDER ||
- mode == 0 /* DNS_RDATASETATTR_CYCLIC */ );
+ mode == DNS_RDATASETATTR_CYCLIC);
ent = isc_mem_get(order->mctx, sizeof(*ent));
if (ent == NULL)
if (match(name, dns_fixedname_name(&ent->name)))
return (ent->mode);
}
- return (DNS_RDATASETATTR_RANDOMIZE);
+ return (DNS_RDATASETATTR_NONE);
}
void
#include <isc/task.h>
#include <isc/time.h>
#include <isc/util.h>
+#include <isc/hash.h>
-#include <dns/acache.h>
#include <dns/callbacks.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
#define slab_methods slab_methods64
#define zone_methods zone_methods64
-#define acache_callback acache_callback64
-#define acache_cancelentry acache_cancelentry64
#define activeempty activeempty64
#define activeemtpynode activeemtpynode64
#define add32 add64
#define findnodeintree findnodeintree64
#define findnsec3node findnsec3node64
#define flush_deletions flush_deletions64
-#define free_acachearray free_acachearray64
+#define free_gluelist free_gluelist64
+#define free_gluetable free_gluetable64
#define free_noqname free_noqname64
#define free_rbtdb free_rbtdb64
#define free_rbtdb_callback free_rbtdb_callback64
#define getoriginnode getoriginnode64
#define getrrsetstats getrrsetstats64
#define getsigningtime getsigningtime64
+#define glue_nsdname_cb glue_nsdname_cb64
#define hashsize hashsize64
#define init_file_version init_file_version64
#define isdnssec isdnssec64
#define prune_tree prune_tree64
#define rbt_datafixer rbt_datafixer64
#define rbt_datawriter rbt_datawriter64
+#define rdataset_addglue rdataset_addglue64
#define rdataset_clearprefetch rdataset_clearprefetch64
#define rdataset_clone rdataset_clone64
#define rdataset_count rdataset_count64
#define rdataset_disassociate rdataset_disassociate64
#define rdataset_expire rdataset_expire64
#define rdataset_first rdataset_first64
-#define rdataset_getadditional rdataset_getadditional64
#define rdataset_getclosest rdataset_getclosest64
#define rdataset_getnoqname rdataset_getnoqname64
#define rdataset_getownercase rdataset_getownercase64
#define rdataset_next rdataset_next64
-#define rdataset_putadditional rdataset_putadditional64
-#define rdataset_setadditional rdataset_setadditional64
#define rdataset_setownercase rdataset_setownercase64
#define rdataset_settrust rdataset_settrust64
#define rdatasetiter_current rdatasetiter_current64
dns_rdatatype_t type;
};
-typedef struct acachectl acachectl_t;
-
typedef struct rdatasetheader {
/*%
* Locked by the owning node's lock.
* performance reasons.
*/
- acachectl_t *additional_auth;
- acachectl_t *additional_glue;
-
dns_rbtnode_t *node;
isc_stdtime_t last_used;
ISC_LINK(struct rdatasetheader) link;
#define RDATASET_ATTR_PREFETCH 0x0200
#define RDATASET_ATTR_CASESET 0x0400
#define RDATASET_ATTR_ZEROTTL 0x0800
-
-typedef struct acache_cbarg {
- dns_rdatasetadditional_t type;
- unsigned int count;
- dns_db_t *db;
- dns_dbnode_t *node;
- rdatasetheader_t *header;
-} acache_cbarg_t;
-
-struct acachectl {
- dns_acacheentry_t *entry;
- acache_cbarg_t *cbarg;
-};
+#define RDATASET_ATTR_CASEFULLYLOWER 0x1000
/*
* XXX
(((header)->attributes & RDATASET_ATTR_CASESET) != 0)
#define ZEROTTL(header) \
(((header)->attributes & RDATASET_ATTR_ZEROTTL) != 0)
+#define CASEFULLYLOWER(header) \
+ (((header)->attributes & RDATASET_ATTR_CASEFULLYLOWER) != 0)
#define ACTIVE(header, now) \
(((header)->rdh_ttl > (now)) || \
((header)->rdh_ttl == (now) && ZEROTTL(header)))
#define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */
+#define RBTDB_GLUE_TABLE_INIT_SIZE 2U
/*%
* Number of buckets for cache DB entries (locks, LRU lists, TTL heaps).
expire_flush
} expire_t;
+typedef struct rbtdb_glue rbtdb_glue_t;
+
+typedef struct rbtdb_glue_table_node {
+ struct rbtdb_glue_table_node *next;
+ dns_rbtnode_t *node;
+ rbtdb_glue_t *glue_list;
+} rbtdb_glue_table_node_t;
+
typedef struct rbtdb_version {
/* Not locked */
rbtdb_serial_t serial;
isc_rwlock_t rwlock;
isc_uint64_t records;
isc_uint64_t bytes;
+
+ isc_rwlock_t glue_rwlock;
+ size_t glue_table_size;
+ size_t glue_table_nodecount;
+ rbtdb_glue_table_node_t **glue_table;
} rbtdb_version_t;
typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t;
dns_name_t *name,
dns_rdataset_t *neg,
dns_rdataset_t *negsig);
-static isc_result_t rdataset_getadditional(dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype,
- dns_acache_t *acache,
- dns_zone_t **zonep,
- dns_db_t **dbp,
- dns_dbversion_t **versionp,
- dns_dbnode_t **nodep,
- dns_name_t *fname,
- dns_message_t *msg,
- isc_stdtime_t now);
-static isc_result_t rdataset_setadditional(dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype,
- dns_acache_t *acache,
- dns_zone_t *zone,
- dns_db_t *db,
- dns_dbversion_t *version,
- dns_dbnode_t *node,
- dns_name_t *fname);
-static isc_result_t rdataset_putadditional(dns_acache_t *acache,
- dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype);
static inline isc_boolean_t need_headerupdate(rdatasetheader_t *header,
isc_stdtime_t now);
static void update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
const dns_name_t *name);
static void rdataset_getownercase(const dns_rdataset_t *rdataset,
dns_name_t *name);
+static isc_result_t rdataset_addglue(dns_rdataset_t *rdataset,
+ dns_dbversion_t *version,
+ unsigned int options,
+ dns_message_t *msg);
+static void free_gluetable(rbtdb_version_t *version);
static dns_rdatasetmethods_t rdataset_methods = {
rdataset_disassociate,
rdataset_current,
rdataset_clone,
rdataset_count,
- NULL,
+ NULL, /* addnoqname */
rdataset_getnoqname,
- NULL,
+ NULL, /* addclosest */
rdataset_getclosest,
- rdataset_getadditional,
- rdataset_setadditional,
- rdataset_putadditional,
rdataset_settrust,
rdataset_expire,
rdataset_clearprefetch,
rdataset_setownercase,
- rdataset_getownercase
+ rdataset_getownercase,
+ rdataset_addglue
};
static dns_rdatasetmethods_t slab_methods = {
rdataset_current,
rdataset_clone,
rdataset_count,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
+ NULL, /* addnoqname */
+ NULL, /* getnoqname */
+ NULL, /* addclosest */
+ NULL, /* getclosest */
+ NULL, /* settrust */
+ NULL, /* expire */
+ NULL, /* clearprefetch */
+ NULL, /* setownercase */
+ NULL, /* getownercase */
+ NULL /* addglue */
};
static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
&refs);
INSIST(refs == 0);
UNLINK(rbtdb->open_versions, rbtdb->current_version, link);
+ isc_rwlock_destroy(&rbtdb->current_version->glue_rwlock);
isc_refcount_destroy(&rbtdb->current_version->references);
isc_rwlock_destroy(&rbtdb->current_version->rwlock);
isc_mem_put(rbtdb->common.mctx, rbtdb->current_version,
if (rbtdb->nsnode != NULL)
dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->nsnode);
+ /*
+ * The current version's glue table needs to be freed early
+ * so the nodes are dereferenced before we check the active
+ * node count below.
+ */
+ if (rbtdb->current_version != NULL) {
+ free_gluetable(rbtdb->current_version);
+ }
+
/*
* Even though there are no external direct references, there still
* may be nodes in use.
NODE_LOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);
rbtdb->node_locks[i].exiting = ISC_TRUE;
NODE_UNLOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write);
- if (isc_refcount_current(&rbtdb->node_locks[i].references)
- == 0) {
+ if (isc_refcount_current(&rbtdb->node_locks[i].references) == 0)
+ {
inactive++;
}
}
if (inactive != 0) {
RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);
rbtdb->active -= inactive;
- if (rbtdb->active == 0)
+ if (rbtdb->active == 0) {
want_free = ISC_TRUE;
+ }
RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
if (want_free) {
char buf[DNS_NAME_FORMATSIZE];
- if (dns_name_dynamic(&rbtdb->common.origin))
+ if (dns_name_dynamic(&rbtdb->common.origin)) {
dns_name_format(&rbtdb->common.origin, buf,
sizeof(buf));
- else
+ } else {
strcpy(buf, "<UNKNOWN>");
+ }
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
"calling free_rbtdb(%s)", buf);
{
isc_result_t result;
rbtdb_version_t *version;
+ size_t i;
version = isc_mem_get(mctx, sizeof(*version));
if (version == NULL)
isc_mem_put(mctx, version, sizeof(*version));
return (NULL);
}
+ result = isc_rwlock_init(&version->glue_rwlock, 0, 0);
+ if (result != ISC_R_SUCCESS) {
+ isc_refcount_destroy(&version->references);
+ isc_mem_put(mctx, version, sizeof(*version));
+ return (NULL);
+ }
+
+ version->glue_table_size = RBTDB_GLUE_TABLE_INIT_SIZE;
+ version->glue_table_nodecount = 0U;
+ version->glue_table = (rbtdb_glue_table_node_t **)
+ isc_mem_get(mctx, (version->glue_table_size *
+ sizeof(*version->glue_table)));
+ if (version->glue_table == NULL) {
+ isc_rwlock_destroy(&version->glue_rwlock);
+ isc_refcount_destroy(&version->references);
+ isc_mem_put(mctx, version, sizeof(*version));
+ return (NULL);
+ }
+
version->writer = writer;
version->commit_ok = ISC_FALSE;
ISC_LIST_INIT(version->changed_list);
ISC_LIST_INIT(version->resigned_list);
ISC_LINK_INIT(version, link);
+ for (i = 0; i < version->glue_table_size; i++)
+ version->glue_table[i] = NULL;
+
return (version);
}
}
result = isc_rwlock_init(&version->rwlock, 0, 0);
if (result != ISC_R_SUCCESS) {
+ free_gluetable(version);
+ isc_rwlock_destroy(&version->glue_rwlock);
isc_refcount_destroy(&version->references);
isc_mem_put(rbtdb->common.mctx, version,
sizeof(*version));
return (changed);
}
-static void
-free_acachearray(isc_mem_t *mctx, rdatasetheader_t *header,
- acachectl_t *array)
-{
- unsigned int count;
- unsigned int i;
- unsigned char *raw; /* RDATASLAB */
-
- /*
- * The caller must be holding the corresponding node lock.
- */
-
- if (array == NULL)
- return;
-
- raw = (unsigned char *)header + sizeof(*header);
- count = raw[0] * 256 + raw[1];
-
- /*
- * Sanity check: since an additional cache entry has a reference to
- * the original DB node (in the callback arg), there should be no
- * acache entries when the node can be freed.
- */
- for (i = 0; i < count; i++)
- INSIST(array[i].entry == NULL && array[i].cbarg == NULL);
-
- isc_mem_put(mctx, array, count * sizeof(acachectl_t));
-}
-
static inline void
free_noqname(isc_mem_t *mctx, struct noqname **noqname) {
new->node = (dns_rbtnode_t *)p;
}
if (CASESET(old)) {
+ uint16_t attr;
+
memmove(new->upper, old->upper, sizeof(old->upper));
- new->attributes |= RDATASET_ATTR_CASESET;
+ attr = old->attributes & (RDATASET_ATTR_CASESET |
+ RDATASET_ATTR_CASEFULLYLOWER);
+ new->attributes |= attr;
}
}
if (rdataset->closest != NULL)
free_noqname(mctx, &rdataset->closest);
- free_acachearray(mctx, rdataset, rdataset->additional_auth);
- free_acachearray(mctx, rdataset, rdataset->additional_glue);
-
if (NONEXISTENT(rdataset))
size = sizeof(*rdataset);
else
if (cleanup_version != NULL) {
INSIST(EMPTY(cleanup_version->changed_list));
+ free_gluetable(cleanup_version);
+ isc_rwlock_destroy(&cleanup_version->glue_rwlock);
isc_rwlock_destroy(&cleanup_version->rwlock);
isc_mem_put(rbtdb->common.mctx, cleanup_version,
sizeof(*cleanup_version));
DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_ZONE, ISC_LOG_ERROR,
"Unable to reinsert header to "
- "re-signing heap: %s\n",
+ "re-signing heap: %s",
dns_result_totext(result));
}
decrement_reference(rbtdb, header->node, least_serial,
newheader->closest = NULL;
newheader->count = init_count++;
newheader->trust = rdataset->trust;
- newheader->additional_auth = NULL;
- newheader->additional_glue = NULL;
newheader->last_used = now;
newheader->node = rbtnode;
if (rbtversion != NULL) {
newheader->noqname = NULL;
newheader->closest = NULL;
newheader->count = init_count++;
- newheader->additional_auth = NULL;
- newheader->additional_glue = NULL;
newheader->last_used = 0;
newheader->node = rbtnode;
if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
* to additional info. We need to clear these fields
* to avoid having duplicated references.
*/
- newheader->additional_auth = NULL;
- newheader->additional_glue = NULL;
rbtversion->records +=
dns_rdataslab_count((unsigned char *)newheader,
sizeof(*newheader));
newheader->noqname = NULL;
newheader->closest = NULL;
newheader->count = 0;
- newheader->additional_auth = NULL;
- newheader->additional_glue = NULL;
newheader->node = rbtnode;
newheader->resign = 0;
newheader->resign_lsb = 0;
newheader->trust = 0;
newheader->noqname = NULL;
newheader->closest = NULL;
- newheader->additional_auth = NULL;
- newheader->additional_glue = NULL;
if (rbtversion != NULL)
newheader->serial = rbtversion->serial;
else
newheader->noqname = NULL;
newheader->closest = NULL;
newheader->count = init_count++;
- newheader->additional_auth = NULL;
- newheader->additional_glue = NULL;
newheader->last_used = 0;
newheader->node = node;
setownercase(newheader, name);
sizeof(rbtdb->current_version->salt));
result = isc_rwlock_init(&rbtdb->current_version->rwlock, 0, 0);
if (result != ISC_R_SUCCESS) {
+ free_gluetable(rbtdb->current_version);
+ isc_rwlock_destroy(&rbtdb->current_version->glue_rwlock);
isc_refcount_destroy(&rbtdb->current_version->references);
isc_mem_put(mctx, rbtdb->current_version,
sizeof(*rbtdb->current_version));
return (dns_name_copy(origin, name, NULL));
}
-/*%
- * Additional cache routines.
- */
-static isc_result_t
-rdataset_getadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype, dns_acache_t *acache,
- dns_zone_t **zonep, dns_db_t **dbp,
- dns_dbversion_t **versionp, dns_dbnode_t **nodep,
- dns_name_t *fname, dns_message_t *msg,
- isc_stdtime_t now)
-{
- dns_rbtdb_t *rbtdb = rdataset->private1;
- dns_rbtnode_t *rbtnode = rdataset->private2;
+static void
+setownercase(rdatasetheader_t *header, const dns_name_t *name) {
+ unsigned int i;
+ isc_boolean_t fully_lower;
+
+ /*
+ * We do not need to worry about label lengths as they are all
+ * less than or equal to 63.
+ */
+ memset(header->upper, 0, sizeof(header->upper));
+ fully_lower = ISC_TRUE;
+ for (i = 0; i < name->length; i++)
+ if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a) {
+ header->upper[i/8] |= 1 << (i%8);
+ fully_lower = ISC_FALSE;
+ }
+ header->attributes |= RDATASET_ATTR_CASESET;
+ if (ISC_LIKELY(fully_lower))
+ header->attributes |= RDATASET_ATTR_CASEFULLYLOWER;
+}
+
+static void
+rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) {
unsigned char *raw = rdataset->private3; /* RDATASLAB */
- unsigned int current_count = rdataset->privateuint4;
- unsigned int count;
rdatasetheader_t *header;
- nodelock_t *nodelock;
- unsigned int total_count;
- acachectl_t *acarray;
- dns_acacheentry_t *entry;
- isc_result_t result;
-
- UNUSED(qtype); /* we do not use this value at least for now */
- UNUSED(acache);
header = (struct rdatasetheader *)(raw - sizeof(*header));
+ setownercase(header, name);
+}
+
+static const unsigned char charmask[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
- total_count = raw[0] * 256 + raw[1];
- INSIST(total_count > current_count);
- count = total_count - current_count - 1;
+static unsigned char maptolower[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
- acarray = NULL;
+static void
+rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
+ const unsigned char *raw = rdataset->private3; /* RDATASLAB */
+ const rdatasetheader_t *header;
+ unsigned int i, j;
+ unsigned char bits;
+ unsigned char c, flip;
- nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
- NODE_LOCK(nodelock, isc_rwlocktype_read);
+ header = (const struct rdatasetheader *)(raw - sizeof(*header));
- switch (type) {
- case dns_rdatasetadditional_fromauth:
- acarray = header->additional_auth;
- break;
- case dns_rdatasetadditional_fromcache:
- acarray = NULL;
- break;
- case dns_rdatasetadditional_fromglue:
- acarray = header->additional_glue;
- break;
- default:
- INSIST(0);
- }
+ if (!CASESET(header))
+ return;
- if (acarray == NULL) {
- if (type != dns_rdatasetadditional_fromcache)
- dns_acache_countquerymiss(acache);
- NODE_UNLOCK(nodelock, isc_rwlocktype_read);
- return (ISC_R_NOTFOUND);
+#if 0
+ /*
+ * This was the original code, and is implemented differently in
+ * the #else block that follows.
+ */
+ for (i = 0; i < name->length; i++) {
+ /*
+ * Set the case bit if it does not match the recorded bit.
+ */
+ if (name->ndata[i] >= 0x61 && name->ndata[i] <= 0x7a &&
+ (header->upper[i/8] & (1 << (i%8))) != 0)
+ name->ndata[i] &= ~0x20; /* clear the lower case bit */
+ else if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a &&
+ (header->upper[i/8] & (1 << (i%8))) == 0)
+ name->ndata[i] |= 0x20; /* set the lower case bit */
}
+#else
- if (acarray[count].entry == NULL) {
- dns_acache_countquerymiss(acache);
- NODE_UNLOCK(nodelock, isc_rwlocktype_read);
- return (ISC_R_NOTFOUND);
+ if (ISC_LIKELY(CASEFULLYLOWER(header))) {
+ unsigned char *bp, *be;
+ bp = name->ndata;
+ be = bp + name->length;
+
+ while (bp <= be - 4) {
+ c = bp[0];
+ bp[0] = maptolower[c];
+ c = bp[1];
+ bp[1] = maptolower[c];
+ c = bp[2];
+ bp[2] = maptolower[c];
+ c = bp[3];
+ bp[3] = maptolower[c];
+ bp += 4;
+ }
+ while (bp < be) {
+ c = *bp;
+ *bp++ = maptolower[c];
+ }
+ return;
}
- entry = NULL;
- dns_acache_attachentry(acarray[count].entry, &entry);
+ i = 0;
+ for (j = 0; j < (name->length >> 3); j++) {
+ unsigned int k;
- NODE_UNLOCK(nodelock, isc_rwlocktype_read);
+ bits = ~(header->upper[j]);
- result = dns_acache_getentry(entry, zonep, dbp, versionp,
- nodep, fname, msg, now);
+ for (k = 0; k < 8; k++) {
+ c = name->ndata[i];
+ flip = (bits & 1) << 5;
+ flip ^= c;
+ flip &= charmask[c];
+ name->ndata[i] ^= flip;
- dns_acache_detachentry(&entry);
+ i++;
+ bits >>= 1;
+ }
+ }
- return (result);
-}
+ if (ISC_UNLIKELY(i == name->length))
+ return;
-static void
-acache_callback(dns_acacheentry_t *entry, void **arg) {
- dns_rbtdb_t *rbtdb;
- dns_rbtnode_t *rbtnode;
- nodelock_t *nodelock;
- acachectl_t *acarray = NULL;
- acache_cbarg_t *cbarg;
- unsigned int count;
+ bits = ~(header->upper[j]);
- REQUIRE(arg != NULL);
- cbarg = *arg;
+ for (; i < name->length; i++) {
+ c = name->ndata[i];
+ flip = (bits & 1) << 5;
+ flip ^= c;
+ flip &= charmask[c];
+ name->ndata[i] ^= flip;
- /*
- * The caller must hold the entry lock.
- */
+ bits >>= 1;
+ }
+#endif
+}
- rbtdb = (dns_rbtdb_t *)cbarg->db;
- rbtnode = (dns_rbtnode_t *)cbarg->node;
+struct rbtdb_glue {
+ struct rbtdb_glue *next;
+ dns_fixedname_t fixedname;
+ dns_rdataset_t rdataset_a;
+ dns_rdataset_t sigrdataset_a;
+ dns_rdataset_t rdataset_aaaa;
+ dns_rdataset_t sigrdataset_aaaa;
+};
- nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
- NODE_LOCK(nodelock, isc_rwlocktype_write);
+typedef struct {
+ rbtdb_glue_t *glue_list;
+ dns_rbtdb_t *rbtdb;
+ rbtdb_version_t *rbtversion;
+} rbtdb_glue_additionaldata_ctx_t;
- switch (cbarg->type) {
- case dns_rdatasetadditional_fromauth:
- acarray = cbarg->header->additional_auth;
- break;
- case dns_rdatasetadditional_fromglue:
- acarray = cbarg->header->additional_glue;
- break;
- default:
- INSIST(0);
- }
+static void
+free_gluelist(rbtdb_glue_t *glue_list, dns_rbtdb_t *rbtdb) {
+ rbtdb_glue_t *cur, *cur_next;
- count = cbarg->count;
- if (acarray != NULL && acarray[count].entry == entry) {
- acarray[count].entry = NULL;
- INSIST(acarray[count].cbarg == cbarg);
- acarray[count].cbarg = NULL;
- isc_mem_put(rbtdb->common.mctx, cbarg, sizeof(acache_cbarg_t));
- dns_acache_detachentry(&entry);
- }
+ if (glue_list == (void *) -1)
+ return;
+
+ cur = glue_list;
+ while (cur != NULL) {
+ cur_next = cur->next;
+
+ if (dns_rdataset_isassociated(&cur->rdataset_a))
+ dns_rdataset_disassociate(&cur->rdataset_a);
+ if (dns_rdataset_isassociated(&cur->sigrdataset_a))
+ dns_rdataset_disassociate(&cur->sigrdataset_a);
- NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+ if (dns_rdataset_isassociated(&cur->rdataset_aaaa))
+ dns_rdataset_disassociate(&cur->rdataset_aaaa);
+ if (dns_rdataset_isassociated(&cur->sigrdataset_aaaa))
+ dns_rdataset_disassociate(&cur->sigrdataset_aaaa);
- dns_db_detachnode((dns_db_t *)rbtdb, (dns_dbnode_t **)(void*)&rbtnode);
- dns_db_detach((dns_db_t **)(void*)&rbtdb);
+ dns_rdataset_invalidate(&cur->rdataset_a);
+ dns_rdataset_invalidate(&cur->sigrdataset_a);
+ dns_rdataset_invalidate(&cur->rdataset_aaaa);
+ dns_rdataset_invalidate(&cur->sigrdataset_aaaa);
- *arg = NULL;
+ isc_mem_put(rbtdb->common.mctx, cur, sizeof(*cur));
+ cur = cur_next;
+ }
}
static void
-acache_cancelentry(isc_mem_t *mctx, dns_acacheentry_t *entry,
- acache_cbarg_t **cbargp)
-{
- acache_cbarg_t *cbarg;
+free_gluetable(rbtdb_version_t *version) {
+ dns_rbtdb_t *rbtdb;
+ size_t i;
+
+ RWLOCK(&version->glue_rwlock, isc_rwlocktype_write);
- REQUIRE(mctx != NULL);
- REQUIRE(entry != NULL);
- REQUIRE(cbargp != NULL && *cbargp != NULL);
+ rbtdb = version->rbtdb;
- cbarg = *cbargp;
+ for (i = 0; i < version->glue_table_size; i++) {
+ rbtdb_glue_table_node_t *cur, *cur_next;
- if (dns_acache_cancelentry(entry)) {
- dns_db_detachnode(cbarg->db, &cbarg->node);
- dns_db_detach(&cbarg->db);
+ cur = version->glue_table[i];
+ while (cur != NULL) {
+ cur_next = cur->next;
+ /* dns_rbtnode_refdecrement(cur->node, NULL); */
+ cur->node = NULL;
+ free_gluelist(cur->glue_list, rbtdb);
+ cur->glue_list = NULL;
+ isc_mem_put(rbtdb->common.mctx, cur, sizeof(*cur));
+ cur = cur_next;
+ }
+ version->glue_table[i] = NULL;
}
- isc_mem_put(mctx, cbarg, sizeof(acache_cbarg_t));
+ isc_mem_put(rbtdb->common.mctx, version->glue_table,
+ (sizeof(*version->glue_table) *
+ version->glue_table_size));
- *cbargp = NULL;
+ RWUNLOCK(&version->glue_rwlock, isc_rwlocktype_write);
}
-static isc_result_t
-rdataset_setadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype, dns_acache_t *acache,
- dns_zone_t *zone, dns_db_t *db,
- dns_dbversion_t *version, dns_dbnode_t *node,
- dns_name_t *fname)
-{
- dns_rbtdb_t *rbtdb = rdataset->private1;
- dns_rbtnode_t *rbtnode = rdataset->private2;
- unsigned char *raw = rdataset->private3; /* RDATASLAB */
- unsigned int current_count = rdataset->privateuint4;
- rdatasetheader_t *header;
- unsigned int total_count, count;
- nodelock_t *nodelock;
- isc_result_t result;
- acachectl_t *acarray;
- dns_acacheentry_t *newentry, *oldentry = NULL;
- acache_cbarg_t *newcbarg, *oldcbarg = NULL;
+static isc_boolean_t
+rehash_gluetable(rbtdb_version_t *version) {
+ size_t oldsize;
+ rbtdb_glue_table_node_t **oldtable;
+ rbtdb_glue_table_node_t *gluenode;
+ rbtdb_glue_table_node_t *nextgluenode;
+ uint32_t hash;
+ size_t i;
+
+ if (ISC_LIKELY(version->glue_table_nodecount <
+ (version->glue_table_size * 3U)))
+ return (ISC_FALSE);
- UNUSED(qtype);
+ oldsize = version->glue_table_size;
+ oldtable = version->glue_table;
+ do {
+ INSIST((version->glue_table_size * 2 + 1) >
+ version->glue_table_size);
+ version->glue_table_size = version->glue_table_size * 2 + 1;
+ } while (version->glue_table_nodecount >=
+ (version->glue_table_size * 3U));
+
+ version->glue_table = (rbtdb_glue_table_node_t **)
+ isc_mem_get(version->rbtdb->common.mctx,
+ (version->glue_table_size *
+ sizeof(*version->glue_table)));
+ if (ISC_UNLIKELY(version->glue_table == NULL)) {
+ version->glue_table = oldtable;
+ version->glue_table_size = oldsize;
+ return (ISC_FALSE);
+ }
- if (type == dns_rdatasetadditional_fromcache)
- return (ISC_R_SUCCESS);
+ for (i = 0; i < version->glue_table_size; i++)
+ version->glue_table[i] = NULL;
- header = (struct rdatasetheader *)(raw - sizeof(*header));
+ for (i = 0; i < oldsize; i++) {
+ for (gluenode = oldtable[i];
+ gluenode != NULL;
+ gluenode = nextgluenode)
+ {
+ hash = isc_hash_function(&gluenode->node,
+ sizeof(gluenode->node),
+ ISC_TRUE, NULL) %
+ version->glue_table_size;
+ nextgluenode = gluenode->next;
+ gluenode->next = version->glue_table[hash];
+ version->glue_table[hash] = gluenode;
+ }
+ }
- total_count = raw[0] * 256 + raw[1];
- INSIST(total_count > current_count);
- count = total_count - current_count - 1; /* should be private data */
+ isc_mem_put(version->rbtdb->common.mctx, oldtable,
+ oldsize * sizeof(*version->glue_table));
- newcbarg = isc_mem_get(rbtdb->common.mctx, sizeof(*newcbarg));
- if (newcbarg == NULL)
- return (ISC_R_NOMEMORY);
- newcbarg->type = type;
- newcbarg->count = count;
- newcbarg->header = header;
- newcbarg->db = NULL;
- dns_db_attach((dns_db_t *)rbtdb, &newcbarg->db);
- newcbarg->node = NULL;
- dns_db_attachnode((dns_db_t *)rbtdb, (dns_dbnode_t *)rbtnode,
- &newcbarg->node);
- newentry = NULL;
- result = dns_acache_createentry(acache, (dns_db_t *)rbtdb,
- acache_callback, newcbarg, &newentry);
- if (result != ISC_R_SUCCESS)
- goto fail;
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3),
+ "rehash_gluetable(): "
+ "resized glue table from %"ISC_PRINT_QUADFORMAT"u to "
+ "%"ISC_PRINT_QUADFORMAT"u",
+ (isc_uint64_t) oldsize,
+ (isc_uint64_t) version->glue_table_size);
- /* Set cache data in the new entry. */
- result = dns_acache_setentry(acache, newentry, zone, db,
- version, node, fname);
- if (result != ISC_R_SUCCESS)
- goto fail;
+ return (ISC_TRUE);
+}
- nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
- NODE_LOCK(nodelock, isc_rwlocktype_write);
+static isc_result_t
+glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) {
+ rbtdb_glue_additionaldata_ctx_t *ctx;
+ isc_result_t result;
+ dns_fixedname_t fixedname_a;
+ dns_name_t *name_a;
+ dns_rdataset_t rdataset_a, sigrdataset_a;
+ dns_rbtnode_t *node_a;
+ dns_fixedname_t fixedname_aaaa;
+ dns_name_t *name_aaaa;
+ dns_rdataset_t rdataset_aaaa, sigrdataset_aaaa;
+ dns_rbtnode_t *node_aaaa;
+ rbtdb_glue_t *glue;
+ dns_name_t *gluename;
- acarray = NULL;
- switch (type) {
- case dns_rdatasetadditional_fromauth:
- acarray = header->additional_auth;
- break;
- case dns_rdatasetadditional_fromglue:
- acarray = header->additional_glue;
- break;
- default:
- INSIST(0);
+ /*
+ * NS records want addresses in additional records.
+ */
+ INSIST(qtype == dns_rdatatype_a);
+
+ ctx = (rbtdb_glue_additionaldata_ctx_t *) arg;
+ result = ISC_R_FAILURE;
+ glue = NULL;
+ node_a = NULL;
+ node_aaaa = NULL;
+
+ dns_fixedname_init(&fixedname_a);
+ name_a = dns_fixedname_name(&fixedname_a);
+ dns_rdataset_init(&rdataset_a);
+ dns_rdataset_init(&sigrdataset_a);
+
+ dns_fixedname_init(&fixedname_aaaa);
+ name_aaaa = dns_fixedname_name(&fixedname_aaaa);
+ dns_rdataset_init(&rdataset_aaaa);
+ dns_rdataset_init(&sigrdataset_aaaa);
+
+ result = zone_find((dns_db_t *) ctx->rbtdb, name, ctx->rbtversion,
+ dns_rdatatype_a, DNS_DBFIND_GLUEOK, 0,
+ (dns_dbnode_t **) &node_a, name_a,
+ &rdataset_a, &sigrdataset_a);
+ if (result == DNS_R_GLUE) {
+ glue = isc_mem_get(ctx->rbtdb->common.mctx, sizeof(*glue));
+ if (glue == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto out;
+ }
+
+ dns_fixedname_init(&glue->fixedname);
+ gluename = dns_fixedname_name(&glue->fixedname);
+ dns_name_copy(name_a, gluename, NULL);
+
+ dns_rdataset_init(&glue->rdataset_a);
+ dns_rdataset_init(&glue->sigrdataset_a);
+ dns_rdataset_init(&glue->rdataset_aaaa);
+ dns_rdataset_init(&glue->sigrdataset_aaaa);
+
+ dns_rdataset_clone(&rdataset_a, &glue->rdataset_a);
+ if (dns_rdataset_isassociated(&sigrdataset_a)) {
+ dns_rdataset_clone(&sigrdataset_a,
+ &glue->sigrdataset_a);
+ }
}
- if (acarray == NULL) {
- unsigned int i;
+ result = zone_find((dns_db_t *) ctx->rbtdb, name, ctx->rbtversion,
+ dns_rdatatype_aaaa, DNS_DBFIND_GLUEOK, 0,
+ (dns_dbnode_t **) &node_aaaa, name_aaaa,
+ &rdataset_aaaa, &sigrdataset_aaaa);
+ if (result == DNS_R_GLUE) {
+ if (glue == NULL) {
+ glue = isc_mem_get(ctx->rbtdb->common.mctx,
+ sizeof(*glue));
+ if (glue == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto out;
+ }
- acarray = isc_mem_get(rbtdb->common.mctx, total_count *
- sizeof(acachectl_t));
+ dns_fixedname_init(&glue->fixedname);
+ gluename = dns_fixedname_name(&glue->fixedname);
+ dns_name_copy(name_aaaa, gluename, NULL);
- if (acarray == NULL) {
- NODE_UNLOCK(nodelock, isc_rwlocktype_write);
- goto fail;
+ dns_rdataset_init(&glue->rdataset_a);
+ dns_rdataset_init(&glue->sigrdataset_a);
+ dns_rdataset_init(&glue->rdataset_aaaa);
+ dns_rdataset_init(&glue->sigrdataset_aaaa);
+ } else {
+ INSIST(node_a == node_aaaa);
+ INSIST(dns_name_equal(name_a, name_aaaa));
}
- for (i = 0; i < total_count; i++) {
- acarray[i].entry = NULL;
- acarray[i].cbarg = NULL;
+ dns_rdataset_clone(&rdataset_aaaa, &glue->rdataset_aaaa);
+ if (dns_rdataset_isassociated(&sigrdataset_aaaa)) {
+ dns_rdataset_clone(&sigrdataset_aaaa,
+ &glue->sigrdataset_aaaa);
}
}
- switch (type) {
- case dns_rdatasetadditional_fromauth:
- header->additional_auth = acarray;
- break;
- case dns_rdatasetadditional_fromglue:
- header->additional_glue = acarray;
- break;
- default:
- INSIST(0);
- }
- if (acarray[count].entry != NULL) {
- /*
- * Swap the entry. Delay cleaning-up the old entry since
- * it would require a node lock.
- */
- oldentry = acarray[count].entry;
- INSIST(acarray[count].cbarg != NULL);
- oldcbarg = acarray[count].cbarg;
+ if (glue != NULL) {
+ glue->next = ctx->glue_list;
+ ctx->glue_list = glue;
}
- acarray[count].entry = newentry;
- acarray[count].cbarg = newcbarg;
- NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+ result = ISC_R_SUCCESS;
- if (oldentry != NULL) {
- acache_cancelentry(rbtdb->common.mctx, oldentry, &oldcbarg);
- dns_acache_detachentry(&oldentry);
- }
+out:
+ if (dns_rdataset_isassociated(&rdataset_a))
+ rdataset_disassociate(&rdataset_a);
+ if (dns_rdataset_isassociated(&sigrdataset_a))
+ rdataset_disassociate(&sigrdataset_a);
- return (ISC_R_SUCCESS);
+ if (dns_rdataset_isassociated(&rdataset_aaaa))
+ rdataset_disassociate(&rdataset_aaaa);
+ if (dns_rdataset_isassociated(&sigrdataset_aaaa))
+ rdataset_disassociate(&sigrdataset_aaaa);
- fail:
- if (newcbarg != NULL) {
- if (newentry != NULL) {
- acache_cancelentry(rbtdb->common.mctx, newentry,
- &newcbarg);
- dns_acache_detachentry(&newentry);
- } else {
- dns_db_detachnode((dns_db_t *)rbtdb, &newcbarg->node);
- dns_db_detach(&newcbarg->db);
- isc_mem_put(rbtdb->common.mctx, newcbarg,
- sizeof(*newcbarg));
- }
- }
+ if (node_a != NULL)
+ detachnode((dns_db_t *) ctx->rbtdb, (dns_dbnode_t *) &node_a);
+ if (node_aaaa != NULL)
+ detachnode((dns_db_t *) ctx->rbtdb,
+ (dns_dbnode_t *) &node_aaaa);
return (result);
}
static isc_result_t
-rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type, dns_rdatatype_t qtype)
+rdataset_addglue(dns_rdataset_t *rdataset,
+ dns_dbversion_t *version,
+ unsigned int options,
+ dns_message_t *msg)
{
dns_rbtdb_t *rbtdb = rdataset->private1;
- dns_rbtnode_t *rbtnode = rdataset->private2;
- unsigned char *raw = rdataset->private3; /* RDATASLAB */
- unsigned int current_count = rdataset->privateuint4;
- rdatasetheader_t *header;
- nodelock_t *nodelock;
- unsigned int total_count, count;
- acachectl_t *acarray;
- dns_acacheentry_t *entry;
- acache_cbarg_t *cbarg;
-
- UNUSED(qtype); /* we do not use this value at least for now */
- UNUSED(acache);
+ dns_rbtnode_t *node = rdataset->private2;
+ rbtdb_version_t *rbtversion = version;
+ isc_uint32_t index;
+ rbtdb_glue_table_node_t *cur;
+ isc_boolean_t found;
+ isc_boolean_t restarted;
+ rbtdb_glue_t *ge;
+ rbtdb_glue_additionaldata_ctx_t ctx;
+ isc_result_t result;
- if (type == dns_rdatasetadditional_fromcache)
- return (ISC_R_SUCCESS);
+ INSIST(rdataset->type == dns_rdatatype_ns);
+ INSIST(rbtdb == rbtversion->rbtdb);
+ INSIST(!IS_CACHE(rbtdb) && !IS_STUB(rbtdb));
- header = (struct rdatasetheader *)(raw - sizeof(*header));
+ found = ISC_FALSE;
+ restarted = ISC_FALSE;
+ result = ISC_R_FAILURE;
- total_count = raw[0] * 256 + raw[1];
- INSIST(total_count > current_count);
- count = total_count - current_count - 1;
+ /*
+ * The glue table cache that forms a part of the DB version
+ * structure is not explicitly bounded and there's no cache
+ * cleaning. The zone data size itself is an implicit bound.
+ *
+ * The key into the glue hashtable is the node pointer. This is
+ * because the glue hashtable is a property of the DB version,
+ * and the glue is keyed for the ownername/NS tuple. We don't
+ * bother with using an expensive dns_name_t comparison here as
+ * the node pointer is a fixed value that won't change for a DB
+ * version and can be compared directly.
+ */
+ index = isc_hash_function(&node, sizeof(node), ISC_TRUE, NULL) %
+ rbtversion->glue_table_size;
- acarray = NULL;
- entry = NULL;
+restart:
+ /*
+ * First, check if we have the additional entries already cached
+ * in the glue table.
+ */
+ RWLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_read);
- nodelock = &rbtdb->node_locks[rbtnode->locknum].lock;
- NODE_LOCK(nodelock, isc_rwlocktype_write);
+ for (cur = rbtversion->glue_table[index]; cur != NULL; cur = cur->next)
+ if (cur->node == node)
+ break;
- switch (type) {
- case dns_rdatasetadditional_fromauth:
- acarray = header->additional_auth;
- break;
- case dns_rdatasetadditional_fromglue:
- acarray = header->additional_glue;
- break;
- default:
- INSIST(0);
+ if (cur == NULL) {
+ goto no_glue;
}
+ /*
+ * We found a cached result. Add it to the message and
+ * return.
+ */
+ found = ISC_TRUE;
+ ge = cur->glue_list;
- if (acarray == NULL) {
- NODE_UNLOCK(nodelock, isc_rwlocktype_write);
- return (ISC_R_NOTFOUND);
- }
+ /*
+ * (void *) -1 is a special value that means no glue is
+ * present in the zone.
+ */
+ if (ge == (void *) -1)
+ goto no_glue;
+
+ for (; ge != NULL; ge = ge->next) {
+ isc_buffer_t *buffer = NULL;
+ dns_name_t *name = NULL;
+ dns_rdataset_t *rdataset_a = NULL;
+ dns_rdataset_t *sigrdataset_a = NULL;
+ dns_rdataset_t *rdataset_aaaa = NULL;
+ dns_rdataset_t *sigrdataset_aaaa = NULL;
+ dns_name_t *gluename = dns_fixedname_name(&ge->fixedname);
+
+ result = isc_buffer_allocate(msg->mctx, &buffer, 512);
+ if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
+ goto no_glue;
+ }
- entry = acarray[count].entry;
- if (entry == NULL) {
- NODE_UNLOCK(nodelock, isc_rwlocktype_write);
- return (ISC_R_NOTFOUND);
- }
+ result = dns_message_gettempname(msg, &name);
+ if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
+ isc_buffer_free(&buffer);
+ goto no_glue;
+ }
- acarray[count].entry = NULL;
- cbarg = acarray[count].cbarg;
- acarray[count].cbarg = NULL;
+ dns_name_copy(gluename, name, buffer);
+ dns_message_takebuffer(msg, &buffer);
- NODE_UNLOCK(nodelock, isc_rwlocktype_write);
+ if (dns_rdataset_isassociated(&ge->rdataset_a)) {
+ result = dns_message_gettemprdataset(msg, &rdataset_a);
+ if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
+ dns_message_puttempname(msg, &name);
+ isc_buffer_free(&buffer);
+ goto no_glue;
+ }
+ }
- if (entry != NULL) {
- if (cbarg != NULL)
- acache_cancelentry(rbtdb->common.mctx, entry, &cbarg);
- dns_acache_detachentry(&entry);
+ if (dns_rdataset_isassociated(&ge->sigrdataset_a)) {
+ result = dns_message_gettemprdataset(msg,
+ &sigrdataset_a);
+ if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
+ if (rdataset_a != NULL) {
+ dns_message_puttemprdataset(msg,
+ &rdataset_a);
+ }
+ dns_message_puttempname(msg, &name);
+ isc_buffer_free(&buffer);
+ goto no_glue;
+ }
+ }
+
+ if (ISC_LIKELY((options & DNS_RDATASETADDGLUE_FILTERAAAA) == 0))
+ {
+ if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
+ result = dns_message_gettemprdataset(msg,
+ &rdataset_aaaa);
+ if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
+ dns_message_puttempname(msg, &name);
+ isc_buffer_free(&buffer);
+ if (rdataset_a != NULL) {
+ dns_message_puttemprdataset(msg,
+ &rdataset_a);
+ }
+ if (sigrdataset_a != NULL) {
+ dns_message_puttemprdataset(msg,
+ &sigrdataset_a);
+ }
+ goto no_glue;
+ }
+ }
+
+ if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
+ result = dns_message_gettemprdataset(msg,
+ &sigrdataset_aaaa);
+ if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) {
+ dns_message_puttempname(msg, &name);
+ isc_buffer_free(&buffer);
+ if (rdataset_a != NULL) {
+ dns_message_puttemprdataset(msg,
+ &rdataset_a);
+ }
+ if (sigrdataset_a != NULL)
+ dns_message_puttemprdataset(msg,
+ &sigrdataset_a);
+ if (rdataset_aaaa != NULL)
+ dns_message_puttemprdataset(msg,
+ &rdataset_aaaa);
+ goto no_glue;
+ }
+ }
+ }
+
+ if (ISC_LIKELY(dns_rdataset_isassociated(&ge->rdataset_a))) {
+ dns_rdataset_clone(&ge->rdataset_a, rdataset_a);
+ ISC_LIST_APPEND(name->list, rdataset_a, link);
+ }
+
+ if (dns_rdataset_isassociated(&ge->sigrdataset_a)) {
+ dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a);
+ ISC_LIST_APPEND(name->list, sigrdataset_a, link);
+ }
+
+ if (ISC_LIKELY((options & DNS_RDATASETADDGLUE_FILTERAAAA) == 0))
+ {
+ if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
+ dns_rdataset_clone(&ge->rdataset_aaaa,
+ rdataset_aaaa);
+ ISC_LIST_APPEND(name->list, rdataset_aaaa,
+ link);
+ }
+ if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
+ dns_rdataset_clone(&ge->sigrdataset_aaaa,
+ sigrdataset_aaaa);
+ ISC_LIST_APPEND(name->list, sigrdataset_aaaa,
+ link);
+ }
+ }
+
+ dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
}
- return (ISC_R_SUCCESS);
-}
+no_glue:
+ RWUNLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_read);
-static void
-setownercase(rdatasetheader_t *header, const dns_name_t *name) {
- unsigned int i;
+ if (found) {
+ return (ISC_R_SUCCESS);
+ }
+
+ if (restarted) {
+ return (ISC_R_FAILURE);
+ }
/*
- * We do not need to worry about label lengths as they are all
- * less than or equal to 63.
+ * No cached glue was found in the table. Cache it and restart
+ * this function.
+ *
+ * Due to the gap between the read lock and the write lock, it's
+ * possible that we may cache a duplicate glue table entry, but
+ * we don't care.
*/
- memset(header->upper, 0, sizeof(header->upper));
- for (i = 0; i < name->length; i++)
- if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a)
- header->upper[i/8] |= 1 << (i%8);
- header->attributes |= RDATASET_ATTR_CASESET;
-}
-static void
-rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) {
- unsigned char *raw = rdataset->private3; /* RDATASLAB */
- rdatasetheader_t *header;
+ ctx.glue_list = NULL;
+ ctx.rbtdb = rbtdb;
+ ctx.rbtversion = rbtversion;
- header = (struct rdatasetheader *)(raw - sizeof(*header));
- setownercase(header, name);
-}
+ RWLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_write);
-static void
-rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
- const unsigned char *raw = rdataset->private3; /* RDATASLAB */
- const rdatasetheader_t *header;
- unsigned int i;
+ if (ISC_UNLIKELY(rehash_gluetable(rbtversion))) {
+ index = isc_hash_function(&node, sizeof(node),
+ ISC_TRUE, NULL) %
+ rbtversion->glue_table_size;
+ }
- header = (const struct rdatasetheader *)(raw - sizeof(*header));
+ (void)dns_rdataset_additionaldata(rdataset, glue_nsdname_cb, &ctx);
- if (!CASESET(header))
- return;
+ cur = isc_mem_get(rbtdb->common.mctx, sizeof(*cur));
+ if (cur == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto out;
+ }
- for (i = 0; i < name->length; i++) {
+ /*
+ * XXXMUKS: it looks like the dns_dbversion is not destroyed
+ * when named is terminated by a keyboard break. This doesn't
+ * cleanup the node reference and keeps the process dangling.
+ */
+ /* dns_rbtnode_refincrement0(node, NULL); */
+ cur->node = node;
+
+ if (ctx.glue_list == NULL) {
/*
- * Set the case bit if it does not match the recorded bit.
+ * No glue was found. Cache it so.
*/
- if (name->ndata[i] >= 0x61 && name->ndata[i] <= 0x7a &&
- (header->upper[i/8] & (1 << (i%8))) != 0)
- name->ndata[i] &= ~0x20; /* clear the lower case bit */
- else if (name->ndata[i] >= 0x41 && name->ndata[i] <= 0x5a &&
- (header->upper[i/8] & (1 << (i%8))) == 0)
- name->ndata[i] |= 0x20; /* set the lower case bit */
+ cur->glue_list = (void *) -1;
+ } else {
+ cur->glue_list = ctx.glue_list;
}
+
+ cur->next = rbtversion->glue_table[index];
+ rbtversion->glue_table[index] = cur;
+ rbtversion->glue_table_nodecount++;
+
+ result = ISC_R_SUCCESS;
+
+ out:
+ RWUNLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_write);
+
+ if (result == ISC_R_SUCCESS) {
+ restarted = ISC_TRUE;
+ goto restart;
+ }
+
+ return (result);
}
/*%
isc__rdatalist_getnoqname,
isc__rdatalist_addclosest,
isc__rdatalist_getclosest,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ NULL, /* settrust */
+ NULL, /* expire */
+ NULL, /* clearprefetch */
isc__rdatalist_setownercase,
- isc__rdatalist_getownercase
+ isc__rdatalist_getownercase,
+ NULL /* addglue */
};
void
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-/* $Id$ */
-
/*! \file */
#include <config.h>
question_current,
question_clone,
question_count,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
+ NULL, /* addnoqname */
+ NULL, /* getnoqname */
+ NULL, /* addclosest */
+ NULL, /* getclosest */
+ NULL, /* settrust */
+ NULL, /* expire */
+ NULL, /* clearprefetch */
+ NULL, /* setownercase */
+ NULL, /* getownercase */
+ NULL /* addglue */
};
void
#define MAX_SHUFFLE 32
#define WANT_FIXED(r) (((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0)
#define WANT_RANDOM(r) (((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0)
+#define WANT_CYCLIC(r) (((r)->attributes & DNS_RDATASETATTR_CYCLIC) != 0)
struct towire_sort {
int key;
isc_buffer_t savedbuffer, rdlen, rrbuffer;
unsigned int headlen;
isc_boolean_t question = ISC_FALSE;
- isc_boolean_t shuffle = ISC_FALSE;
- dns_rdata_t *shuffled = NULL, shuffled_fixed[MAX_SHUFFLE];
- struct towire_sort *sorted = NULL, sorted_fixed[MAX_SHUFFLE];
+ isc_boolean_t shuffle = ISC_FALSE, sort = ISC_FALSE;
+ dns_rdata_t orig_fixed[MAX_SHUFFLE];
+ dns_rdata_t *orig = orig_fixed;
+ struct towire_sort new_fixed[MAX_SHUFFLE];
+ struct towire_sort *new = new_fixed;
dns_fixedname_t fixed;
dns_name_t *name;
}
/*
- * Do we want to shuffle this answer?
+ * Do we want to sort and/or shuffle this answer?
*/
- if (!question && count > 1 &&
- (!WANT_FIXED(rdataset) || order != NULL) &&
- rdataset->type != dns_rdatatype_rrsig)
- shuffle = ISC_TRUE;
-
- if (shuffle && count > MAX_SHUFFLE) {
- shuffled = isc_mem_get(cctx->mctx, count * sizeof(*shuffled));
- sorted = isc_mem_get(cctx->mctx, count * sizeof(*sorted));
- if (shuffled == NULL || sorted == NULL)
- shuffle = ISC_FALSE;
- } else {
- shuffled = shuffled_fixed;
- sorted = sorted_fixed;
+ if (!question && count > 1 && rdataset->type != dns_rdatatype_rrsig) {
+ if (order != NULL) {
+ sort = ISC_TRUE;
+ }
+ if (WANT_RANDOM(rdataset) || WANT_CYCLIC(rdataset)) {
+ shuffle = ISC_TRUE;
+ }
}
- if (shuffle) {
+ if ((shuffle || sort) && count > MAX_SHUFFLE) {
+ orig = isc_mem_get(cctx->mctx, count * sizeof(*orig));
+ new = isc_mem_get(cctx->mctx, count * sizeof(*new));
+ if (orig == NULL || new == NULL)
+ shuffle = sort = ISC_FALSE;
+ }
+
+ if (shuffle || sort) {
/*
* First we get handles to all of the rdata.
*/
i = 0;
do {
INSIST(i < count);
- dns_rdata_init(&shuffled[i]);
- dns_rdataset_current(rdataset, &shuffled[i]);
+ dns_rdata_init(&orig[i]);
+ dns_rdataset_current(rdataset, &orig[i]);
i++;
result = dns_rdataset_next(rdataset);
} while (result == ISC_R_SUCCESS);
if (result != ISC_R_NOMORE)
goto cleanup;
INSIST(i == count);
+ }
- /*
- * Now we shuffle.
- */
- if (WANT_FIXED(rdataset)) {
- /*
- * 'Fixed' order.
- */
- INSIST(order != NULL);
- for (i = 0; i < count; i++) {
- sorted[i].key = (*order)(&shuffled[i],
- order_arg);
- sorted[i].rdata = &shuffled[i];
- }
- } else if (WANT_RANDOM(rdataset)) {
+ if (shuffle) {
+ if (WANT_RANDOM(rdataset)) {
/*
* 'Random' order.
*/
isc_random_get(&val);
choice = i + (val % (count - i));
- rdata = shuffled[i];
- shuffled[i] = shuffled[choice];
- shuffled[choice] = rdata;
+ rdata = orig[i];
+ orig[i] = orig[choice];
+ orig[choice] = rdata;
if (order != NULL)
- sorted[i].key = (*order)(&shuffled[i],
+ new[i].key = (*order)(&orig[i],
order_arg);
else
- sorted[i].key = 0; /* Unused */
- sorted[i].rdata = &shuffled[i];
+ new[i].key = 0; /* Unused */
+ new[i].rdata = &orig[i];
}
- } else {
+ } else if (WANT_CYCLIC(rdataset)) {
/*
- * "Cyclic" order.
+ * 'Cyclic' order.
*/
isc_uint32_t val;
unsigned int j;
j = val % count;
for (i = 0; i < count; i++) {
if (order != NULL)
- sorted[i].key = (*order)(&shuffled[j],
+ new[i].key = (*order)(&orig[j],
order_arg);
else
- sorted[i].key = 0; /* Unused */
- sorted[i].rdata = &shuffled[j];
+ new[i].key = 0; /* Unused */
+ new[i].rdata = &orig[j];
j++;
if (j == count)
j = 0; /* Wrap around. */
}
}
+ } else if (sort) {
+ for (i = 0; i < count; i++) {
+ if (order != NULL)
+ new[i].key = (*order)(&orig[i], order_arg);
+ else
+ new[i].key = 0; /* Unused */
+ new[i].rdata = &orig[i];
+ }
+ }
- /*
- * Sorted order.
- */
- if (order != NULL)
- qsort(sorted, count, sizeof(sorted[0]),
- towire_compare);
+ /*
+ * Sortlist order.
+ */
+ if (sort) {
+ qsort(new, count, sizeof(new[0]), towire_compare);
}
savedbuffer = *target;
/*
* Copy out the rdata
*/
- if (shuffle)
- rdata = *(sorted[i].rdata);
- else {
+ if (shuffle || sort) {
+ rdata = *(new[i].rdata);
+ } else {
dns_rdata_reset(&rdata);
dns_rdataset_current(rdataset, &rdata);
}
added++;
}
- if (shuffle) {
+ if (shuffle || sort) {
i++;
if (i == count)
result = ISC_R_NOMORE;
*target = savedbuffer;
cleanup:
- if (sorted != NULL && sorted != sorted_fixed)
- isc_mem_put(cctx->mctx, sorted, count * sizeof(*sorted));
- if (shuffled != NULL && shuffled != shuffled_fixed)
- isc_mem_put(cctx->mctx, shuffled, count * sizeof(*shuffled));
+ if (new != NULL && new != new_fixed)
+ isc_mem_put(cctx->mctx, new, count * sizeof(*new));
+ if (orig != NULL && orig != orig_fixed)
+ isc_mem_put(cctx->mctx, orig, count * sizeof(*orig));
return (result);
}
return((rdataset->methods->getclosest)(rdataset, name, neg, negsig));
}
-/*
- * Additional cache stuff
- */
-isc_result_t
-dns_rdataset_getadditional(dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype,
- dns_acache_t *acache,
- dns_zone_t **zonep,
- dns_db_t **dbp,
- dns_dbversion_t **versionp,
- dns_dbnode_t **nodep,
- dns_name_t *fname,
- dns_message_t *msg,
- isc_stdtime_t now)
-{
- REQUIRE(DNS_RDATASET_VALID(rdataset));
- REQUIRE(rdataset->methods != NULL);
- REQUIRE(zonep == NULL || *zonep == NULL);
- REQUIRE(dbp != NULL && *dbp == NULL);
- REQUIRE(versionp != NULL && *versionp == NULL);
- REQUIRE(nodep != NULL && *nodep == NULL);
- REQUIRE(fname != NULL);
- REQUIRE(msg != NULL);
-
- if (acache != NULL && rdataset->methods->getadditional != NULL) {
- return ((rdataset->methods->getadditional)(rdataset, type,
- qtype, acache,
- zonep, dbp,
- versionp, nodep,
- fname, msg, now));
- }
-
- return (ISC_R_FAILURE);
-}
-
-isc_result_t
-dns_rdataset_setadditional(dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype,
- dns_acache_t *acache,
- dns_zone_t *zone,
- dns_db_t *db,
- dns_dbversion_t *version,
- dns_dbnode_t *node,
- dns_name_t *fname)
-{
- REQUIRE(DNS_RDATASET_VALID(rdataset));
- REQUIRE(rdataset->methods != NULL);
-
- if (acache != NULL && rdataset->methods->setadditional != NULL) {
- return ((rdataset->methods->setadditional)(rdataset, type,
- qtype, acache, zone,
- db, version,
- node, fname));
- }
-
- return (ISC_R_FAILURE);
-}
-
-isc_result_t
-dns_rdataset_putadditional(dns_acache_t *acache,
- dns_rdataset_t *rdataset,
- dns_rdatasetadditional_t type,
- dns_rdatatype_t qtype)
-{
- REQUIRE(DNS_RDATASET_VALID(rdataset));
- REQUIRE(rdataset->methods != NULL);
-
- if (acache != NULL && rdataset->methods->putadditional != NULL) {
- return ((rdataset->methods->putadditional)(acache, rdataset,
- type, qtype));
- }
-
- return (ISC_R_FAILURE);
-}
-
void
dns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
REQUIRE(DNS_RDATASET_VALID(rdataset));
rdataset->ttl = ttl;
sigrdataset->ttl = ttl;
}
+
+isc_result_t
+dns_rdataset_addglue(dns_rdataset_t *rdataset,
+ dns_dbversion_t *version,
+ unsigned int options,
+ dns_message_t *msg)
+{
+ REQUIRE(DNS_RDATASET_VALID(rdataset));
+ REQUIRE(rdataset->methods != NULL);
+ REQUIRE(rdataset->type == dns_rdatatype_ns);
+
+ if (rdataset->methods->addglue == NULL)
+ return (ISC_R_NOTIMPLEMENTED);
+
+ return ((rdataset->methods->addglue)(rdataset, version,
+ options, msg));
+}
rdataset_current,
rdataset_clone,
rdataset_count,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
+ NULL, /* addnoqname */
+ NULL, /* getnoqname */
+ NULL, /* addclosest */
+ NULL, /* getclosest */
+ NULL, /* settrust */
+ NULL, /* expire */
+ NULL, /* clearprefetch */
+ NULL, /* setownercase */
+ NULL, /* getownercase */
+ NULL /* addglue */
};
void
isc__rdatalist_count,
isc__rdatalist_addnoqname,
isc__rdatalist_getnoqname,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
+ NULL, /* addclosest */
+ NULL, /* getclosest */
+ NULL, /* settrust */
+ NULL, /* expire */
+ NULL, /* clearprefetch */
+ NULL, /* setownercase */
+ NULL, /* getownercase */
+ NULL /* addglue */
};
static void
isc__rdatalist_count,
isc__rdatalist_addnoqname,
isc__rdatalist_getnoqname,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
+ NULL, /* addclosest */
+ NULL, /* getclosest */
+ NULL, /* settrust */
+ NULL, /* expire */
+ NULL, /* clearprefetch */
+ NULL, /* setownercase */
+ NULL, /* getownercase */
+ NULL /* addglue */
};
static void
int fd;
const char *sock_path;
unsigned int req_len;
- isc_region_t token_region;
+ isc_region_t token_region = {NULL, 0};
unsigned char *data;
isc_buffer_t buf;
isc_uint32_t token_len = 0;
#include <isc/task.h>
#include <isc/util.h>
-#include <dns/acache.h>
#include <dns/acl.h>
#include <dns/adb.h>
#include <dns/badcache.h>
goto cleanup_zt;
}
- view->acache = NULL;
view->cache = NULL;
view->cachedb = NULL;
ISC_LIST_INIT(view->dlz_searched);
*/
view->recursion = ISC_TRUE;
view->auth_nxdomain = ISC_FALSE; /* Was true in BIND 8 */
- view->additionalfromcache = ISC_TRUE;
- view->additionalfromauth = ISC_TRUE;
view->enablednssec = ISC_TRUE;
view->enablevalidation = ISC_TRUE;
view->acceptexpired = ISC_FALSE;
dns_adb_detach(&view->adb);
if (view->resolver != NULL)
dns_resolver_detach(&view->resolver);
- if (view->acache != NULL) {
- if (view->cachedb != NULL)
- dns_acache_putdb(view->acache, view->cachedb);
- dns_acache_detach(&view->acache);
- }
dns_rrl_view_destroy(view);
if (view->rpzs != NULL)
dns_rpz_detach_rpzs(&view->rpzs);
dns_adb_shutdown(view->adb);
if (!REQSHUTDOWN(view))
dns_requestmgr_shutdown(view->requestmgr);
- if (view->acache != NULL)
- dns_acache_shutdown(view->acache);
if (view->zonetable != NULL) {
if (view->flush)
dns_zt_flushanddetach(&view->zonetable);
view->cacheshared = shared;
if (view->cache != NULL) {
- if (view->acache != NULL)
- dns_acache_putdb(view->acache, view->cachedb);
dns_db_detach(&view->cachedb);
dns_cache_detach(&view->cache);
}
dns_cache_attach(cache, &view->cache);
dns_cache_attachdb(cache, &view->cachedb);
INSIST(DNS_DB_VALID(view->cachedb));
-
- if (view->acache != NULL)
- dns_acache_setdb(view->acache, view->cachedb);
}
isc_boolean_t
if (result != ISC_R_SUCCESS)
return (result);
}
- if (view->acache != NULL)
- dns_acache_putdb(view->acache, view->cachedb);
dns_db_detach(&view->cachedb);
dns_cache_attachdb(view->cache, &view->cachedb);
- if (view->acache != NULL)
- dns_acache_setdb(view->acache, view->cachedb);
if (view->resolver != NULL)
dns_resolver_flushbadcache(view->resolver, NULL);
if (view->failcache != NULL)
; Exported Functions
EXPORTS
-dns_acache_attach
-dns_acache_attachentry
-dns_acache_cancelentry
-dns_acache_countquerymiss
-dns_acache_create
-dns_acache_createentry
-dns_acache_detach
-dns_acache_detachentry
-dns_acache_getentry
-dns_acache_putdb
-dns_acache_setcachesize
-dns_acache_setcleaninginterval
-dns_acache_setdb
-dns_acache_setentry
-dns_acache_shutdown
dns_acl_any
dns_acl_attach
dns_acl_create
dns_rdatalist_init
dns_rdatalist_tordataset
dns_rdataset_addclosest
+dns_rdataset_addglue
dns_rdataset_additionaldata
dns_rdataset_addnoqname
dns_rdataset_clearprefetch
dns_rdataset_disassociate
dns_rdataset_expire
dns_rdataset_first
-dns_rdataset_getadditional
dns_rdataset_getclosest
dns_rdataset_getnoqname
dns_rdataset_getownercase
dns_rdataset_isassociated
dns_rdataset_makequestion
dns_rdataset_next
-dns_rdataset_putadditional
-dns_rdataset_setadditional
dns_rdataset_setownercase
dns_rdataset_settrust
dns_rdataset_totext
dns_zone_rpz_enable
dns_zone_rpz_enable_db
dns_zone_set_parentcatz
-dns_zone_setacache
dns_zone_setadded
dns_zone_setalsonotify
dns_zone_setalsonotifydscpkeys
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
-SOURCE=..\include\dns\acache.h
-# End Source File
-# Begin Source File
-
SOURCE=..\include\dns\acl.h
# End Source File
# Begin Source File
# PROP Default_Filter "c"
# Begin Source File
-SOURCE=..\acache.c
-# End Source File
-# Begin Source File
-
SOURCE=..\acl.c
# End Source File
# Begin Source File
!ELSE
CLEAN :
!ENDIF
- -@erase "$(INTDIR)\acache.obj"
-@erase "$(INTDIR)\acl.obj"
-@erase "$(INTDIR)\adb.obj"
-@erase "$(INTDIR)\badcache.obj"
DEF_FILE= \
".\libdns.def"
LINK32_OBJS= \
- "$(INTDIR)\acache.obj" \
"$(INTDIR)\acl.obj" \
"$(INTDIR)\adb.obj" \
"$(INTDIR)\badcache.obj" \
!ELSE
CLEAN :
!ENDIF
- -@erase "$(INTDIR)\acache.obj"
- -@erase "$(INTDIR)\acache.sbr"
-@erase "$(INTDIR)\acl.obj"
-@erase "$(INTDIR)\acl.sbr"
-@erase "$(INTDIR)\adb.obj"
BSC32=bscmake.exe
BSC32_FLAGS=/nologo /o"$(OUTDIR)\libdns.bsc"
BSC32_SBRS= \
- "$(INTDIR)\acache.sbr" \
"$(INTDIR)\acl.sbr" \
"$(INTDIR)\adb.sbr" \
"$(INTDIR)\badcache.sbr" \
DEF_FILE= \
".\libdns.def"
LINK32_OBJS= \
- "$(INTDIR)\acache.obj" \
"$(INTDIR)\acl.obj" \
"$(INTDIR)\adb.obj" \
"$(INTDIR)\badcache.obj" \
!IF "$(CFG)" == "libdns - @PLATFORM@ Release" || "$(CFG)" == "libdns - @PLATFORM@ Debug"
-SOURCE=..\acache.c
-
-!IF "$(CFG)" == "libdns - @PLATFORM@ Release"
-
-
-"$(INTDIR)\acache.obj" : $(SOURCE) "$(INTDIR)"
- $(CPP) $(CPP_PROJ) $(SOURCE)
-
-
-!ELSEIF "$(CFG)" == "libdns - @PLATFORM@ Debug"
-
-
-"$(INTDIR)\acache.obj" "$(INTDIR)\acache.sbr" : $(SOURCE) "$(INTDIR)"
- $(CPP) $(CPP_PROJ) $(SOURCE)
-
-
-!ENDIF
-
SOURCE=..\acl.c
!IF "$(CFG)" == "libdns - @PLATFORM@ Release"
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Resource Files">
<ClCompile Include="version.c">
<Filter>Library Source Files</Filter>
</ClCompile>
- <ClCompile Include="..\acache.c">
- <Filter>Library Source Files</Filter>
- </ClCompile>
<ClCompile Include="..\acl.c">
<Filter>Library Source Files</Filter>
</ClCompile>
<ClInclude Include="..\rdatalist_p.h">
<Filter>Library Header Files</Filter>
</ClInclude>
- <ClInclude Include="..\include\dns\acache.h">
- <Filter>Library Header Files</Filter>
- </ClInclude>
<ClInclude Include="..\include\dns\acl.h">
<Filter>Library Header Files</Filter>
</ClInclude>
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|@PLATFORM@">
<None Include="libdns.def" />
</ItemGroup>
<ItemGroup>
- <ClCompile Include="..\acache.c" />
<ClCompile Include="..\acl.c" />
<ClCompile Include="..\adb.c" />
<ClCompile Include="..\badcache.c" />
@IF PKCS11
<ClInclude Include="..\dst_pkcs11.h" />
@END PKCS11
- <ClInclude Include="..\include\dns\acache.h" />
<ClInclude Include="..\include\dns\acl.h" />
<ClInclude Include="..\include\dns\adb.h" />
<ClInclude Include="..\include\dns\badcache.h" />
#include <isc/timer.h>
#include <isc/util.h>
-#include <dns/acache.h>
#include <dns/acl.h>
#include <dns/adb.h>
#include <dns/callbacks.h>
isc_uint32_t sigvalidityinterval;
isc_uint32_t sigresigninginterval;
dns_view_t *view;
- dns_acache_t *acache;
dns_checkmxfunc_t checkmx;
dns_checksrvfunc_t checksrv;
dns_checknsfunc_t checkns;
zone->sigvalidityinterval = 30 * 24 * 3600;
zone->sigresigninginterval = 7 * 24 * 3600;
zone->view = NULL;
- zone->acache = NULL;
zone->checkmx = NULL;
zone->checksrv = NULL;
zone->checkns = NULL;
dns_stats_detach(&zone->rcvquerystats);
if (zone->db != NULL)
zone_detachdb(zone);
- if (zone->acache != NULL)
- dns_acache_detach(&zone->acache);
if (zone->rpzs != NULL) {
REQUIRE(zone->rpz_num < zone->rpzs->p.num_zones);
dns_rpz_detach_rpzs(&zone->rpzs);
return (result);
}
-void
-dns_zone_setacache(dns_zone_t *zone, dns_acache_t *acache) {
- REQUIRE(DNS_ZONE_VALID(zone));
- REQUIRE(acache != NULL);
-
- LOCK_ZONE(zone);
- if (zone->acache != NULL)
- dns_acache_detach(&zone->acache);
- dns_acache_attach(acache, &zone->acache);
- ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
- if (zone->db != NULL) {
- isc_result_t result;
-
- /*
- * If the zone reuses an existing DB, the DB needs to be
- * set in the acache explicitly. We can safely ignore the
- * case where the DB is already set. If other error happens,
- * the acache will not work effectively.
- */
- result = dns_acache_setdb(acache, zone->db);
- if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- "dns_acache_setdb() failed: %s",
- isc_result_totext(result));
- }
- }
- ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
- UNLOCK_ZONE(zone);
-}
-
static isc_result_t
dns_zone_setstring(dns_zone_t *zone, char **field, const char *value) {
char *copy;
REQUIRE(zone->db == NULL && db != NULL);
dns_db_attach(db, &zone->db);
- if (zone->acache != NULL) {
- isc_result_t result;
- result = dns_acache_setdb(zone->acache, db);
- if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- "dns_acache_setdb() failed: %s",
- isc_result_totext(result));
- }
- }
}
/* The caller must hold the dblock as a writer. */
zone_detachdb(dns_zone_t *zone) {
REQUIRE(zone->db != NULL);
- if (zone->acache != NULL)
- (void)dns_acache_putdb(zone->acache, zone->db);
dns_db_detach(&zone->db);
}
static isc_uint32_t fnv_offset_basis;
static isc_once_t fnv_once = ISC_ONCE_INIT;
+static isc_boolean_t fnv_initialized = ISC_FALSE;
static void
fnv_initialize(void) {
while (fnv_offset_basis == 0) {
isc_random_get(&fnv_offset_basis);
}
+
+ fnv_initialized = ISC_TRUE;
}
const void *
isc_hash_get_initializer(void) {
- RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
+ if (ISC_UNLIKELY(!fnv_initialized))
+ RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
return (&fnv_offset_basis);
}
* Ensure that fnv_initialize() is not called after
* isc_hash_set_initializer() is called.
*/
- RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
+ if (ISC_UNLIKELY(!fnv_initialized))
+ RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
fnv_offset_basis = *((const unsigned int *) initializer);
}
const unsigned char *be;
REQUIRE(length == 0 || data != NULL);
- RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
+
+ if (ISC_UNLIKELY(!fnv_initialized))
+ RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
hval = ISC_UNLIKELY(previous_hashp != NULL) ?
*previous_hashp : fnv_offset_basis;
*/
if (case_sensitive) {
- while (bp < be - 4) {
- hval ^= (isc_uint32_t) bp[0];
+ while (bp <= be - 4) {
+ hval ^= bp[0];
hval *= 16777619;
- hval ^= (isc_uint32_t) bp[1];
+ hval ^= bp[1];
hval *= 16777619;
- hval ^= (isc_uint32_t) bp[2];
+ hval ^= bp[2];
hval *= 16777619;
- hval ^= (isc_uint32_t) bp[3];
+ hval ^= bp[3];
hval *= 16777619;
bp += 4;
}
while (bp < be) {
- hval ^= (isc_uint32_t) *bp++;
+ hval ^= *bp++;
hval *= 16777619;
}
} else {
- while (bp < be - 4) {
- hval ^= (isc_uint32_t) maptolower[bp[0]];
+ while (bp <= be - 4) {
+ hval ^= maptolower[bp[0]];
hval *= 16777619;
- hval ^= (isc_uint32_t) maptolower[bp[1]];
+ hval ^= maptolower[bp[1]];
hval *= 16777619;
- hval ^= (isc_uint32_t) maptolower[bp[2]];
+ hval ^= maptolower[bp[2]];
hval *= 16777619;
- hval ^= (isc_uint32_t) maptolower[bp[3]];
+ hval ^= maptolower[bp[3]];
hval *= 16777619;
bp += 4;
}
while (bp < be) {
- hval ^= (isc_uint32_t) maptolower[*bp++];
+ hval ^= maptolower[*bp++];
hval *= 16777619;
}
}
const unsigned char *be;
REQUIRE(length == 0 || data != NULL);
- RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
+
+ if (ISC_UNLIKELY(!fnv_initialized))
+ RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
hval = ISC_UNLIKELY(previous_hashp != NULL) ?
*previous_hashp : fnv_offset_basis;
if (case_sensitive) {
while (be >= bp + 4) {
be -= 4;
- hval ^= (isc_uint32_t) be[3];
+ hval ^= be[3];
hval *= 16777619;
- hval ^= (isc_uint32_t) be[2];
+ hval ^= be[2];
hval *= 16777619;
- hval ^= (isc_uint32_t) be[1];
+ hval ^= be[1];
hval *= 16777619;
- hval ^= (isc_uint32_t) be[0];
+ hval ^= be[0];
hval *= 16777619;
}
while (--be >= bp) {
- hval ^= (isc_uint32_t) *be;
+ hval ^= *be;
hval *= 16777619;
}
} else {
while (be >= bp + 4) {
be -= 4;
- hval ^= (isc_uint32_t) maptolower[be[3]];
+ hval ^= maptolower[be[3]];
hval *= 16777619;
- hval ^= (isc_uint32_t) maptolower[be[2]];
+ hval ^= maptolower[be[2]];
hval *= 16777619;
- hval ^= (isc_uint32_t) maptolower[be[1]];
+ hval ^= maptolower[be[1]];
hval *= 16777619;
- hval ^= (isc_uint32_t) maptolower[be[0]];
+ hval ^= maptolower[be[0]];
hval *= 16777619;
}
while (--be >= bp) {
- hval ^= (isc_uint32_t) maptolower[*be];
+ hval ^= maptolower[*be];
hval *= 16777619;
}
}
* To make many functions be inline macros (via \#define) define this.
* If it is undefined, a function will be used.
*/
-/* #define ISC_BUFFER_USEINLINE */
+#define ISC_BUFFER_USEINLINE 1
ISC_LANG_BEGINDECLS
#define ISC__BUFFER_PUTMEM(_b, _base, _length) \
do { \
if (ISC_UNLIKELY((_b)->autore)) { \
- isc_buffer_t *tmpbuf = _b; \
- REQUIRE(isc_buffer_reserve(&tmpbuf, _length) \
+ isc_buffer_t *_tmp = _b; \
+ REQUIRE(isc_buffer_reserve(&_tmp, _length) \
== ISC_R_SUCCESS); \
} \
REQUIRE(isc_buffer_availablelength(_b) >= (unsigned int) _length); \
unsigned char *_cp; \
_length = strlen(_source); \
if (ISC_UNLIKELY((_b)->autore)) { \
- isc_buffer_t *tmpbuf = _b; \
- REQUIRE(isc_buffer_reserve(&tmpbuf, _length) \
+ isc_buffer_t *_tmp = _b; \
+ REQUIRE(isc_buffer_reserve(&_tmp, _length) \
== ISC_R_SUCCESS); \
} \
REQUIRE(isc_buffer_availablelength(_b) >= (unsigned int) _length); \
#define ISC__BUFFER_PUTUINT8(_b, _val) \
do { \
unsigned char *_cp; \
+ /* evaluate (_val) only once */ \
isc_uint8_t _val2 = (_val); \
if (ISC_UNLIKELY((_b)->autore)) { \
- isc_buffer_t *tmpbuf = _b; \
- REQUIRE(isc_buffer_reserve(&tmpbuf, 1) \
+ isc_buffer_t *_tmp = _b; \
+ REQUIRE(isc_buffer_reserve(&_tmp, 1) \
== ISC_R_SUCCESS); \
} \
REQUIRE(isc_buffer_availablelength(_b) >= 1U); \
_cp = isc_buffer_used(_b); \
(_b)->used++; \
- _cp[0] = _val2 & 0x00ff; \
+ _cp[0] = _val2; \
} while (0)
#define ISC__BUFFER_PUTUINT16(_b, _val) \
do { \
unsigned char *_cp; \
+ /* evaluate (_val) only once */ \
isc_uint16_t _val2 = (_val); \
if (ISC_UNLIKELY((_b)->autore)) { \
- isc_buffer_t *tmpbuf = _b; \
- REQUIRE(isc_buffer_reserve(&tmpbuf, 2) \
+ isc_buffer_t *_tmp = _b; \
+ REQUIRE(isc_buffer_reserve(&_tmp, 2) \
== ISC_R_SUCCESS); \
} \
REQUIRE(isc_buffer_availablelength(_b) >= 2U); \
_cp = isc_buffer_used(_b); \
(_b)->used += 2; \
- _cp[0] = (unsigned char)((_val2 & 0xff00U) >> 8); \
- _cp[1] = (unsigned char)(_val2 & 0x00ffU); \
+ _cp[0] = _val2 >> 8; \
+ _cp[1] = _val2; \
} while (0)
#define ISC__BUFFER_PUTUINT24(_b, _val) \
do { \
unsigned char *_cp; \
+ /* evaluate (_val) only once */ \
isc_uint32_t _val2 = (_val); \
if (ISC_UNLIKELY((_b)->autore)) { \
- isc_buffer_t *tmpbuf = _b; \
- REQUIRE(isc_buffer_reserve(&tmpbuf, 3) \
+ isc_buffer_t *_tmp = _b; \
+ REQUIRE(isc_buffer_reserve(&_tmp, 3) \
== ISC_R_SUCCESS); \
} \
REQUIRE(isc_buffer_availablelength(_b) >= 3U); \
_cp = isc_buffer_used(_b); \
(_b)->used += 3; \
- _cp[0] = (unsigned char)((_val2 & 0xff0000U) >> 16); \
- _cp[1] = (unsigned char)((_val2 & 0xff00U) >> 8); \
- _cp[2] = (unsigned char)(_val2 & 0x00ffU); \
+ _cp[0] = _val2 >> 16; \
+ _cp[1] = _val2 >> 8; \
+ _cp[2] = _val2; \
} while (0)
#define ISC__BUFFER_PUTUINT32(_b, _val) \
do { \
unsigned char *_cp; \
+ /* evaluate (_val) only once */ \
isc_uint32_t _val2 = (_val); \
if (ISC_UNLIKELY((_b)->autore)) { \
- isc_buffer_t *tmpbuf = _b; \
- REQUIRE(isc_buffer_reserve(&tmpbuf, 4) \
+ isc_buffer_t *_tmp = _b; \
+ REQUIRE(isc_buffer_reserve(&_tmp, 4) \
== ISC_R_SUCCESS); \
} \
REQUIRE(isc_buffer_availablelength(_b) >= 4U); \
_cp = isc_buffer_used(_b); \
(_b)->used += 4; \
- _cp[0] = (unsigned char)((_val2 & 0xff000000) >> 24); \
- _cp[1] = (unsigned char)((_val2 & 0x00ff0000) >> 16); \
- _cp[2] = (unsigned char)((_val2 & 0x0000ff00) >> 8); \
- _cp[3] = (unsigned char)((_val2 & 0x000000ff)); \
+ _cp[0] = _val2 >> 24; \
+ _cp[1] = _val2 >> 16; \
+ _cp[2] = _val2 >> 8; \
+ _cp[3] = _val2; \
} while (0)
#if defined(ISC_BUFFER_USEINLINE)
#define ISC_MSG_POSTLOCK 1207 /*%< "postlock" */
#define ISC_MSG_PREUNLOCK 1208 /*%< "preunlock" */
#define ISC_MSG_POSTUNLOCK 1209 /*%< "postunlock" */
+#define ISC_MSG_PRINTLOCK2 1210 /*%< "rwlock %p thread %lu ..." w/ atomic */
#define ISC_MSG_UNKNOWNFAMILY 1301 /*%< "unknown address family: %d" */
#define DELETE_TRACE(a, b, c, d, e)
#define ISC_MEMFUNC_SCOPE
#else
+#define TRACE_OR_RECORD (ISC_MEM_DEBUGTRACE|ISC_MEM_DEBUGRECORD)
#define ADD_TRACE(a, b, c, d, e) \
do { \
- if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \
- ISC_MEM_DEBUGRECORD)) != 0 && \
+ if ((isc_mem_debugging & TRACE_OR_RECORD) != 0 && \
b != NULL) \
add_trace_entry(a, b, c, d, e); \
} while (0)
-#define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e)
+#define DELETE_TRACE(a, b, c, d, e) \
+ do { \
+ if ((isc_mem_debugging & TRACE_OR_RECORD) != 0 && \
+ b != NULL) \
+ delete_trace_entry(a, b, c, d, e); \
+ } while(0)
static void
print_active(isc__mem_t *ctx, FILE *out);
if (((ctx->flags & ISC_MEMFLAG_INTERNAL) == 0) && (si != NULL))
mem_getstats(ctx, si[-1].u.size);
-#if ISC_MEM_TRACKLINES
ADD_TRACE(ctx, si, si[-1].u.size, file, line);
-#endif
if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
!ctx->is_overmem) {
ctx->is_overmem = ISC_TRUE;
UNLOCK(mpctx->lock);
#if ISC_MEM_TRACKLINES
- if (item != NULL) {
+ if (((isc_mem_debugging & TRACE_OR_RECORD) != 0) && item != NULL) {
MCTXLOCK(mctx, &mctx->lock);
ADD_TRACE(mctx, item, mpctx->size, file, line);
MCTXUNLOCK(mctx, &mctx->lock);
mpctx->allocated--;
#if ISC_MEM_TRACKLINES
- MCTXLOCK(mctx, &mctx->lock);
- DELETE_TRACE(mctx, mem, mpctx->size, file, line);
- MCTXUNLOCK(mctx, &mctx->lock);
+ if ((isc_mem_debugging & TRACE_OR_RECORD) != 0) {
+ MCTXLOCK(mctx, &mctx->lock);
+ DELETE_TRACE(mctx, mem, mpctx->size, file, line);
+ MCTXUNLOCK(mctx, &mctx->lock);
+ }
#endif /* ISC_MEM_TRACKLINES */
/*
RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
LOCK(&contextslock);
- if (!ISC_LIST_EMPTY(contexts)) {
+ if (!ISC_LIST_EMPTY(contexts)) {
#if ISC_MEM_TRACKLINES
- isc__mem_t *ctx;
-
- for (ctx = ISC_LIST_HEAD(contexts);
- ctx != NULL;
- ctx = ISC_LIST_NEXT(ctx, link)) {
- fprintf(file, "context: %p\n", ctx);
- print_active(ctx, file);
+ if ((isc_mem_debugging & TRACE_OR_RECORD) != 0) {
+ isc__mem_t *ctx;
+
+ for (ctx = ISC_LIST_HEAD(contexts);
+ ctx != NULL;
+ ctx = ISC_LIST_NEXT(ctx, link)) {
+ fprintf(file, "context: %p\n", ctx);
+ print_active(ctx, file);
+ }
+ fflush(file);
}
- fflush(file);
#endif
INSIST(0);
}
static void
print_lock(const char *operation, isc_rwlock_t *rwl, isc_rwlocktype_t type) {
+#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG)
+ fprintf(stderr,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_PRINTLOCK2,
+ "rwlock %p thread %lu %s(%s): "
+ "write_requests=%u, write_completions=%u, "
+ "cnt_and_flag=0x%x, readers_waiting=%u, "
+ "write_granted=%u, write_quota=%u\n"),
+ rwl, isc_thread_self(), operation,
+ (type == isc_rwlocktype_read ?
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_READ, "read") :
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
+ ISC_MSG_WRITE, "write")),
+ rwl->write_requests, rwl->write_completions,
+ rwl->cnt_and_flag, rwl->readers_waiting,
+ rwl->write_granted, rwl->write_quota);
+#else
fprintf(stderr,
isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
ISC_MSG_PRINTLOCK,
ISC_MSG_READING, "reading") :
isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK,
ISC_MSG_WRITING, "writing")),
- rwl->active, rwl->granted, rwl->readers_waiting,
- rwl->writers_waiting);
-}
+ rwl->active, rwl->granted,
+ rwl->readers_waiting, rwl->writers_waiting);
#endif
+}
+#endif /* ISC_RWLOCK_TRACE */
isc_result_t
isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
static cfg_clausedef_t
view_clauses[] = {
- { "acache-cleaning-interval", &cfg_type_uint32, 0 },
- { "acache-enable", &cfg_type_boolean, 0 },
- { "additional-from-auth", &cfg_type_boolean, 0 },
- { "additional-from-cache", &cfg_type_boolean, 0 },
+ { "acache-cleaning-interval", &cfg_type_uint32,
+ CFG_CLAUSEFLAG_OBSOLETE },
+ { "acache-enable", &cfg_type_boolean,
+ CFG_CLAUSEFLAG_OBSOLETE },
+ { "additional-from-auth", &cfg_type_boolean,
+ CFG_CLAUSEFLAG_OBSOLETE },
+ { "additional-from-cache", &cfg_type_boolean,
+ CFG_CLAUSEFLAG_OBSOLETE },
{ "allow-new-zones", &cfg_type_boolean, 0 },
{ "allow-query-cache", &cfg_type_bracketed_aml, 0 },
{ "allow-query-cache-on", &cfg_type_bracketed_aml, 0 },
{ "lame-ttl", &cfg_type_ttlval, 0 },
{ "nocookie-udp-size", &cfg_type_uint32, 0 },
{ "nosit-udp-size", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
- { "max-acache-size", &cfg_type_sizenodefault, 0 },
+ { "max-acache-size", &cfg_type_sizenodefault,
+ CFG_CLAUSEFLAG_OBSOLETE },
{ "max-cache-size", &cfg_type_sizeorpercent, 0 },
{ "max-cache-ttl", &cfg_type_uint32, 0 },
{ "max-clients-per-query", &cfg_type_uint32, 0 },
./lib/dns/.gitignore X 2012,2013,2016
./lib/dns/Atffile X 2011
./lib/dns/Makefile.in MAKE 1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017
-./lib/dns/acache.c C 2004,2005,2006,2007,2008,2012,2013,2015,2016
./lib/dns/acl.c C 1999,2000,2001,2002,2004,2005,2006,2007,2008,2009,2011,2013,2014,2016
./lib/dns/adb.c C 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016
./lib/dns/api X 1999,2000,2001,2006,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017
./lib/dns/hmac_link.c C.NAI 1999,2000,2001,2002,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016
./lib/dns/include/Makefile.in MAKE 1998,1999,2000,2001,2004,2007,2012,2016
./lib/dns/include/dns/Makefile.in MAKE 1998,1999,2000,2001,2002,2003,2004,2007,2008,2009,2011,2012,2013,2014,2015,2016,2017
-./lib/dns/include/dns/acache.h C 2004,2006,2007,2013,2016
./lib/dns/include/dns/acl.h C 1999,2000,2001,2002,2004,2005,2006,2007,2009,2011,2013,2014,2016
./lib/dns/include/dns/adb.h C 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2011,2013,2014,2015,2016
./lib/dns/include/dns/badcache.h C 2014,2016