From: Mark Andrews Date: Wed, 16 Nov 2022 00:40:33 +0000 (+1100) Subject: Add dns_db_allrdatasets options X-Git-Tag: v9.19.8~7^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=85048ddeeeba8414ababfe73ba2651183b056180;p=thirdparty%2Fbind9.git Add dns_db_allrdatasets options 'DNS_DB_STALEOK' returns stale rdatasets as well as current rdatasets. 'DNS_DB_EXPIREDOK' returns expired rdatasets as well as current rdatasets. This option is currently only set when DNS_DB_STALEOK is also set. --- diff --git a/lib/dns/cache.c b/lib/dns/cache.c index 966485b50e7..7aedbb6fb56 100644 --- a/lib/dns/cache.c +++ b/lib/dns/cache.c @@ -392,8 +392,8 @@ clearnode(dns_db_t *db, dns_dbnode_t *node) { isc_result_t result; dns_rdatasetiter_t *iter = NULL; - result = dns_db_allrdatasets(db, node, NULL, 0, (isc_stdtime_t)0, - &iter); + result = dns_db_allrdatasets(db, node, NULL, DNS_DB_STALEOK, + (isc_stdtime_t)0, &iter); if (result != ISC_R_SUCCESS) { return (result); } diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index 9673f967f07..b15279c9eef 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -302,6 +302,9 @@ struct dns_dbonupdatelistener { #define DNS_DB_NONSEC3 0x4 /*@}*/ +#define DNS_DB_STALEOK 0x01 +#define DNS_DB_EXPIREDOK 0x02 + /***** ***** Methods *****/ @@ -1168,6 +1171,9 @@ dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, * * \li 'options' controls which rdatasets are selected when interating over * the node. + * 'DNS_DB_STALEOK' return stale rdatasets as well as current rdatasets. + * 'DNS_DB_EXPIREDOK' return expired rdatasets as well as current + * rdatasets. * * \li The 'now' field is ignored if 'db' is a zone database. If 'db' is a * cache database, an rdataset will not be found unless it expires after diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c index 2fdda1ce8df..0c6aeb18d6a 100644 --- a/lib/dns/masterdump.c +++ b/lib/dns/masterdump.c @@ -1669,6 +1669,11 @@ dumptostream(dns_dumpctx_t *dctx) { char *bufmem; dns_name_t *name; dns_fixedname_t fixname; + unsigned int options = DNS_DB_STALEOK; + + if ((dctx->tctx.style.flags & DNS_STYLEFLAG_EXPIRED) != 0) { + options |= DNS_DB_EXPIREDOK; + } bufmem = isc_mem_get(dctx->mctx, initial_buffer_length); @@ -1707,8 +1712,8 @@ dumptostream(dns_dumpctx_t *dctx) { result = dns_dbiterator_pause(dctx->dbiter); RUNTIME_CHECK(result == ISC_R_SUCCESS); - result = dns_db_allrdatasets(dctx->db, node, dctx->version, 0, - dctx->now, &rdsiter); + result = dns_db_allrdatasets(dctx->db, node, dctx->version, + options, dctx->now, &rdsiter); if (result != ISC_R_SUCCESS) { dns_db_detachnode(dctx->db, &node); goto cleanup; @@ -1916,6 +1921,11 @@ dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db, isc_stdtime_t now; dns_totext_ctx_t ctx; dns_rdatasetiter_t *rdsiter = NULL; + unsigned int options = DNS_DB_STALEOK; + + if ((style->flags & DNS_STYLEFLAG_EXPIRED) != 0) { + options |= DNS_DB_EXPIREDOK; + } result = totext_ctx_init(style, NULL, &ctx); if (result != ISC_R_SUCCESS) { @@ -1929,7 +1939,7 @@ dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db, isc_buffer_init(&buffer, bufmem, initial_buffer_length); - result = dns_db_allrdatasets(db, node, version, 0, now, &rdsiter); + result = dns_db_allrdatasets(db, node, version, options, now, &rdsiter); if (result != ISC_R_SUCCESS) { goto failure; } diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index aae127b6fbc..388e7540376 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -444,6 +444,12 @@ typedef ISC_LIST(dns_rbtnode_t) rbtnodelist_t; #define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */ +#define EXPIREDOK(rbtiterator) \ + (((rbtiterator)->common.options & DNS_DB_EXPIREDOK) != 0) + +#define STALEOK(rbtiterator) \ + (((rbtiterator)->common.options & DNS_DB_STALEOK) != 0) + /*% * Number of buckets for cache DB entries (locks, LRU lists, TTL heaps). * There is a tradeoff issue about configuring this value: if this is too @@ -8858,7 +8864,17 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator) { for (header = rbtnode->data; header != NULL; header = top_next) { top_next = header->next; do { - if (header->serial <= serial && !IGNORE(header)) { + dns_ttl_t stale_ttl = header->rdh_ttl; + if (STALEOK(rbtiterator)) { + stale_ttl += STALE_TTL(header, rbtdb); + } + if (EXPIREDOK(rbtiterator)) { + if (!NONEXISTENT(header)) { + break; + } + header = header->down; + } else if (header->serial <= serial && !IGNORE(header)) + { /* * Is this a "this rdataset doesn't exist" * record? Or is it too old in the cache? @@ -8869,8 +8885,7 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator) { * queries for 0 TTL rdatasets to work. */ if (NONEXISTENT(header) || - (now != 0 && now > header->rdh_ttl)) - { + (now != 0 && now > stale_ttl)) { header = NULL; } break; @@ -8906,6 +8921,7 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator) { rbtdb_rdatatype_t type, negtype; dns_rdatatype_t rdtype, covers; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; + bool expiredok = EXPIREDOK(rbtiterator); header = rbtiterator->current; if (header == NULL) { @@ -8930,37 +8946,69 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator) { } else { negtype = RBTDB_RDATATYPE_VALUE(0, rdtype); } - for (header = header->next; header != NULL; header = top_next) { - top_next = header->next; + + /* + * Find the start of the header chain for the next type + * by walking back up the list. + */ + top_next = header->next; + while (top_next != NULL && + (top_next->type == type || top_next->type == negtype)) + { + top_next = top_next->next; + } + if (expiredok) { /* - * If not walking back up the down list. + * Keep walking down the list if possible or + * start the next type. */ - if (header->type != type && header->type != negtype) { - do { - if (header->serial <= serial && !IGNORE(header)) - { - /* - * Is this a "this rdataset doesn't - * exist" record? - * - * Note: unlike everywhere else, we - * check for now > header->ttl instead - * of ">=". This allows ANY and RRSIG - * queries for 0 TTL rdatasets to work. - */ - if (NONEXISTENT(header) || - (now != 0 && now > header->rdh_ttl)) - { - header = NULL; - } + header = header->down != NULL ? header->down : top_next; + } else { + header = top_next; + } + for (; header != NULL; header = top_next) { + top_next = header->next; + do { + dns_ttl_t stale_ttl = header->rdh_ttl; + if (STALEOK(rbtiterator)) { + stale_ttl += STALE_TTL(header, rbtdb); + } + if (expiredok) { + if (!NONEXISTENT(header)) { break; - } else { - header = header->down; } - } while (header != NULL); - if (header != NULL) { + header = header->down; + } else if (header->serial <= serial && !IGNORE(header)) + { + /* + * Is this a "this rdataset doesn't + * exist" record? + * + * Note: unlike everywhere else, we + * check for now > header->ttl instead + * of ">=". This allows ANY and RRSIG + * queries for 0 TTL rdatasets to work. + */ + if (NONEXISTENT(header) || + (now != 0 && now > stale_ttl)) { + header = NULL; + } break; + } else { + header = header->down; } + } while (header != NULL); + if (header != NULL) { + break; + } + /* + * Find the start of the header chain for the next type + * by walking back up the list. + */ + while (top_next != NULL && + (top_next->type == type || top_next->type == negtype)) + { + top_next = top_next->next; } }