sources/bind9/lib/dns/rbtdb.c
/*
 * Find the NSEC/NSEC3 which is or before the current point on the
 * search chain.  For NSEC3 records only NSEC3 records that match the
 * current NSEC3PARAM record are considered.
 */
Find the NSEC/NSEC3 which is or before the current point on the
search chain.  For NSEC3 records only NSEC3 records that match the
current NSEC3PARAM record are considered.
Find the NSEC / NSEC3 which is or before the current point on the search chain . For NSEC3 records only NSEC3 records that match the current NSEC3PARAM record are considered .
static inline isc_result_t
find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
		  dns_name_t *foundname, dns_rdataset_t *rdataset,
		  dns_rdataset_t *sigrdataset, dns_rbt_t *tree,
		  dns_db_secure_t secure)
{
	dns_rbtnode_t *node, *prevnode;
	rdatasetheader_t *header, *header_next, *found, *foundsig;
	dns_rbtnodechain_t nsecchain;
	isc_boolean_t empty_node;
	isc_result_t result;
	dns_fixedname_t fname, forigin;
	dns_name_t *name, *origin;
	dns_rdatatype_t type;
	rbtdb_rdatatype_t sigtype;
	isc_boolean_t wraps;
	isc_boolean_t first = ISC_TRUE;
	isc_boolean_t need_sig = ISC_TF(secure == dns_db_secure);
	if (tree == search->rbtdb->nsec3) {
		type = dns_rdatatype_nsec3;
		sigtype = RBTDB_RDATATYPE_SIGNSEC3;
		wraps = ISC_TRUE;
	} else {
		type = dns_rdatatype_nsec;
		sigtype = RBTDB_RDATATYPE_SIGNSEC;
		wraps = ISC_FALSE;
	}
	dns_fixedname_init(&fname);
	name = dns_fixedname_name(&fname);
	dns_fixedname_init(&forigin);
	origin = dns_fixedname_name(&forigin);
 again:
	node = NULL;
	prevnode = NULL;
	result = dns_rbtnodechain_current(&search->chain, name, origin, &node);
	if (result != ISC_R_SUCCESS)
		return (result);
	do {
		NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
			  isc_rwlocktype_read);
		found = NULL;
		foundsig = NULL;
		empty_node = ISC_TRUE;
		for (header = node->data;
		     header != NULL;
		     header = header_next) {
			header_next = header->next;
			do {
				if (header->serial <= search->serial &&
				    !IGNORE(header)) {
					if (NONEXISTENT(header))
						header = NULL;
					break;
				} else
					header = header->down;
			} while (header != NULL);
			if (header != NULL) {
				empty_node = ISC_FALSE;
				if (header->type == type) {
					found = header;
					if (foundsig != NULL)
						break;
				} else if (header->type == sigtype) {
					foundsig = header;
					if (found != NULL)
						break;
				}
			}
		}
		if (!empty_node) {
			if (found != NULL && search->rbtversion->havensec3 &&
			    found->type == dns_rdatatype_nsec3 &&
			    !matchparams(found, search)) {
				empty_node = ISC_TRUE;
				found = NULL;
				foundsig = NULL;
				result = previous_closest_nsec(type, search,
							       name, origin,
							       &prevnode, NULL,
							       NULL);
			} else if (found != NULL &&
				   (foundsig != NULL || !need_sig)) {
				result = dns_name_concatenate(name, origin,
							      foundname, NULL);
				if (result == ISC_R_SUCCESS) {
					if (nodep != NULL) {
						new_reference(search->rbtdb,
							      node);
						*nodep = node;
					}
					bind_rdataset(search->rbtdb, node,
						      found, search->now,
						      rdataset);
					if (foundsig != NULL)
						bind_rdataset(search->rbtdb,
							      node,
							      foundsig,
							      search->now,
							      sigrdataset);
				}
			} else if (found == NULL && foundsig == NULL) {
				empty_node = ISC_TRUE;
				result = previous_closest_nsec(type, search,
							       name, origin,
							       &prevnode,
							       &nsecchain,
							       &first);
			} else {
				result = DNS_R_BADDB;
			}
		} else {
			result = previous_closest_nsec(type, search,
						       name, origin, &prevnode,
						       &nsecchain, &first);
		}
		NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
			    isc_rwlocktype_read);
		node = prevnode;
		prevnode = NULL;
	} while (empty_node && result == ISC_R_SUCCESS);
	if (!first)
		dns_rbtnodechain_invalidate(&nsecchain);
	if (result == ISC_R_NOMORE && wraps) {
		result = dns_rbtnodechain_last(&search->chain, tree,
					       NULL, NULL);
		if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
			wraps = ISC_FALSE;
			goto again;
		}
	}
	if (result == ISC_R_NOMORE)
		result = DNS_R_BADDB;
	return (result);
}
static inline isc_result_t find_closest_nsec ( rbtdb_search_t * search , dns_dbnode_t * * nodep , dns_name_t * foundname , dns_rdataset_t * rdataset , dns_rdataset_t * sigrdataset , dns_rbt_t * tree , dns_db_secure_t secure ) { dns_rbtnode_t * node , * prevnode ; rdatasetheader_t * header , * header_next , * found , * foundsig ; dns_rbtnodechain_t nsecchain ; isc_boolean_t empty_node ; isc_result_t result ; dns_fixedname_t fname , forigin ; dns_name_t * name , * origin ; dns_rdatatype_t type ; rbtdb_rdatatype_t sigtype ; isc_boolean_t wraps ; isc_boolean_t first = ISC_TRUE ; isc_boolean_t need_sig = ISC_TF ( secure == dns_db_secure ) ; if ( tree == search -> rbtdb -> nsec3 ) { type = dns_rdatatype_nsec3 ; sigtype = RBTDB_RDATATYPE_SIGNSEC3 ; wraps = ISC_TRUE ; } else { type = dns_rdatatype_nsec ; sigtype = RBTDB_RDATATYPE_SIGNSEC ; wraps = ISC_FALSE ; } dns_fixedname_init ( & fname ) ; name = dns_fixedname_name ( & fname ) ; dns_fixedname_init ( & forigin ) ; origin = dns_fixedname_name ( & forigin ) ; again : node = NULL ; prevnode = NULL ; result = dns_rbtnodechain_current ( & search -> chain , name , origin , & node ) ; if ( result != ISC_R_SUCCESS ) return ( result ) ; do { NODE_LOCK ( & ( search -> rbtdb -> node_locks [ node -> locknum ] . lock ) , isc_rwlocktype_read ) ; found = NULL ; foundsig = NULL ; empty_node = ISC_TRUE ; for ( header = node -> data ; header != NULL ; header = header_next ) { header_next = header -> next ; do { if ( header -> serial <= search -> serial && ! IGNORE ( header ) ) { if ( NONEXISTENT ( header ) ) header = NULL ; break ; } else header = header -> down ; } while ( header != NULL ) ; if ( header != NULL ) { empty_node = ISC_FALSE ; if ( header -> type == type ) { found = header ; if ( foundsig != NULL ) break ; } else if ( header -> type == sigtype ) { foundsig = header ; if ( found != NULL ) break ; } } } if ( ! empty_node ) { if ( found != NULL && search -> rbtversion -> havensec3 && found -> type == dns_rdatatype_nsec3 && ! matchparams ( found , search ) ) { empty_node = ISC_TRUE ; found = NULL ; foundsig = NULL ; result = previous_closest_nsec ( type , search , name , origin , & prevnode , NULL , NULL ) ; } else if ( found != NULL && ( foundsig != NULL || ! need_sig ) ) { result = dns_name_concatenate ( name , origin , foundname , NULL ) ; if ( result == ISC_R_SUCCESS ) { if ( nodep != NULL ) { new_reference ( search -> rbtdb , node ) ; * nodep = node ; } bind_rdataset ( search -> rbtdb , node , found , search -> now , rdataset ) ; if ( foundsig != NULL ) bind_rdataset ( search -> rbtdb , node , foundsig , search -> now , sigrdataset ) ; } } else if ( found == NULL && foundsig == NULL ) { empty_node = ISC_TRUE ; result = previous_closest_nsec ( type , search , name , origin , & prevnode , & nsecchain , & first ) ; } else { result = DNS_R_BADDB ; } } else { result = previous_closest_nsec ( type , search , name , origin , & prevnode , & nsecchain , & first ) ; } NODE_UNLOCK ( & ( search -> rbtdb -> node_locks [ node -> locknum ] . lock ) , isc_rwlocktype_read ) ; node = prevnode ; prevnode = NULL ; } while ( empty_node && result == ISC_R_SUCCESS ) ; if ( ! first ) dns_rbtnodechain_invalidate ( & nsecchain ) ; if ( result == ISC_R_NOMORE && wraps ) { result = dns_rbtnodechain_last ( & search -> chain , tree , NULL , NULL ) ; if ( result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN ) { wraps = ISC_FALSE ; goto again ; } } if ( result == ISC_R_NOMORE ) result = DNS_R_BADDB ; return ( result ) ; }
Find the NSEC/NSEC3 which is or before the current point on the
 search chain.
Find the NSEC / NSEC3 which is or before the current point on the search chain .
/*
	 * Use the auxiliary tree only starting with the second node in the
	 * hope that the original node will be right much of the time.
	 */ /*
			 * Look for an active, extant NSEC or RRSIG NSEC.
			 */ /*
					 * Is this a "this rdataset doesn't
					 * exist" record?
					 */ /*
				 * We now know that there is at least one
				 * active rdataset at this node.
				 */ /*
				 * We've found the right NSEC/NSEC3 record.
				 *
				 * Note: for this to really be the right
				 * NSEC record, it's essential that the NSEC
				 * records of any nodes obscured by a zone
				 * cut have been removed; we assume this is
				 * the case.
				 */ /*
				 * This node is active, but has no NSEC or
				 * RRSIG NSEC.  That means it's glue or
				 * other obscured zone data that isn't
				 * relevant for our search.  Treat the
				 * node as if it were empty and keep looking.
				 */ /*
				 * We found an active node, but either the
				 * NSEC or the RRSIG NSEC is missing.  This
				 * shouldn't happen.
				 */ /*
			 * This node isn't active.  We've got to keep
			 * looking.
			 */ /*
	 * If the result is ISC_R_NOMORE, then we got to the beginning of
	 * the database and didn't find a NSEC record.  This shouldn't
	 * happen.
	 */