📄 rbtdb.c
字号:
} else if (found == NULL && foundsig == NULL) { /* * 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. */ empty_node = ISC_TRUE; result = dns_rbtnodechain_prev(&search->chain, NULL, NULL); } else { /* * We found an active node, but either the * NSEC or the RRSIG NSEC is missing. This * shouldn't happen. */ result = DNS_R_BADDB; } } else { /* * This node isn't active. We've got to keep * looking. */ result = dns_rbtnodechain_prev(&search->chain, NULL, NULL); } UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock)); } while (empty_node && result == ISC_R_SUCCESS); /* * 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. */ if (result == ISC_R_NOMORE) result = DNS_R_BADDB; return (result);}static isc_result_tzone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset){ dns_rbtnode_t *node = NULL; isc_result_t result; rbtdb_search_t search; isc_boolean_t cname_ok = ISC_TRUE; isc_boolean_t close_version = ISC_FALSE; isc_boolean_t maybe_zonecut = ISC_FALSE; isc_boolean_t at_zonecut = ISC_FALSE; isc_boolean_t wild; isc_boolean_t empty_node; isc_mutex_t *lock; rdatasetheader_t *header, *header_next, *found, *nsecheader; rdatasetheader_t *foundsig, *cnamesig, *nsecsig; rbtdb_rdatatype_t sigtype; isc_boolean_t active; dns_rbtnodechain_t chain; search.rbtdb = (dns_rbtdb_t *)db; REQUIRE(VALID_RBTDB(search.rbtdb)); /* * We don't care about 'now'. */ UNUSED(now); /* * If the caller didn't supply a version, attach to the current * version. */ if (version == NULL) { currentversion(db, &version); close_version = ISC_TRUE; } search.rbtversion = version; search.serial = search.rbtversion->serial; search.options = options; search.copy_name = ISC_FALSE; search.need_cleanup = ISC_FALSE; search.wild = ISC_FALSE; search.zonecut = NULL; dns_fixedname_init(&search.zonecut_name); dns_rbtnodechain_init(&search.chain, search.rbtdb->common.mctx); search.now = 0; /* * 'wild' will be true iff. we've matched a wildcard. */ wild = ISC_FALSE; RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read); /* * Search down from the root of the tree. If, while going down, we * encounter a callback node, zone_zonecut_callback() will search the * rdatasets at the zone cut for active DNAME or NS rdatasets. */ result = dns_rbt_findnode(search.rbtdb->tree, name, foundname, &node, &search.chain, DNS_RBTFIND_EMPTYDATA, zone_zonecut_callback, &search); if (result == DNS_R_PARTIALMATCH) { partial_match: if (search.zonecut != NULL) { result = setup_delegation(&search, nodep, foundname, rdataset, sigrdataset); goto tree_exit; } if (search.wild) { /* * At least one of the levels in the search chain * potentially has a wildcard. For each such level, * we must see if there's a matching wildcard active * in the current version. */ result = find_wildcard(&search, &node, name); if (result == ISC_R_SUCCESS) { result = dns_name_copy(name, foundname, NULL); if (result != ISC_R_SUCCESS) goto tree_exit; wild = ISC_TRUE; goto found; } else if (result != ISC_R_NOTFOUND) goto tree_exit; } chain = search.chain; active = activeempty(&search, &chain, name); /* * If we're here, then the name does not exist, is not * beneath a zonecut, and there's no matching wildcard. */ if (search.rbtdb->secure || (search.options & DNS_DBFIND_FORCENSEC) != 0) { result = find_closest_nsec(&search, nodep, foundname, rdataset, sigrdataset, search.rbtdb->secure); if (result == ISC_R_SUCCESS) result = active ? DNS_R_EMPTYNAME : DNS_R_NXDOMAIN; } else result = active ? DNS_R_EMPTYNAME : DNS_R_NXDOMAIN; goto tree_exit; } else if (result != ISC_R_SUCCESS) goto tree_exit; found: /* * We have found a node whose name is the desired name, or we * have matched a wildcard. */ if (search.zonecut != NULL) { /* * If we're beneath a zone cut, we don't want to look for * CNAMEs because they're not legitimate zone glue. */ cname_ok = ISC_FALSE; } else { /* * The node may be a zone cut itself. If it might be one, * make sure we check for it later. */ if (node->find_callback && (node != search.rbtdb->origin_node || IS_STUB(search.rbtdb)) && !dns_rdatatype_atparent(type)) maybe_zonecut = ISC_TRUE; } /* * Certain DNSSEC types are not subject to CNAME matching * (RFC 2535, section 2.3.5). * * We don't check for RRSIG, because we don't store RRSIG records * directly. */ if (type == dns_rdatatype_dnskey || type == dns_rdatatype_nsec) cname_ok = ISC_FALSE; /* * We now go looking for rdata... */ LOCK(&(search.rbtdb->node_locks[node->locknum].lock)); found = NULL; foundsig = NULL; sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type); nsecheader = NULL; nsecsig = NULL; cnamesig = NULL; empty_node = ISC_TRUE; for (header = node->data; header != NULL; header = header_next) { header_next = header->next; /* * Look for an active, extant rdataset. */ do { if (header->serial <= search.serial && !IGNORE(header)) { /* * Is this a "this rdataset doesn't * exist" record? */ if (NONEXISTENT(header)) header = NULL; break; } else header = header->down; } while (header != NULL); if (header != NULL) { /* * We now know that there is at least one active * rdataset at this node. */ empty_node = ISC_FALSE; /* * Do special zone cut handling, if requested. */ if (maybe_zonecut && header->type == dns_rdatatype_ns) { /* * We increment the reference count on node to * ensure that search->zonecut_rdataset will * still be valid later. */ new_reference(search.rbtdb, node); search.zonecut = node; search.zonecut_rdataset = header; search.zonecut_sigrdataset = NULL; search.need_cleanup = ISC_TRUE; maybe_zonecut = ISC_FALSE; at_zonecut = ISC_TRUE; if ((search.options & DNS_DBFIND_GLUEOK) == 0 && type != dns_rdatatype_nsec && type != dns_rdatatype_dnskey) { /* * Glue is not OK, but any answer we * could return would be glue. Return * the delegation. */ found = NULL; break; } if (found != NULL && foundsig != NULL) break; } /* * If we found a type we were looking for, * remember it. */ if (header->type == type || type == dns_rdatatype_any || (header->type == dns_rdatatype_cname && cname_ok)) { /* * We've found the answer! */ found = header; if (header->type == dns_rdatatype_cname && cname_ok) { /* * We may be finding a CNAME instead * of the desired type. * * If we've already got the CNAME RRSIG, * use it, otherwise change sigtype * so that we find it. */ if (cnamesig != NULL) foundsig = cnamesig; else sigtype = RBTDB_RDATATYPE_SIGCNAME; } /* * If we've got all we need, end the search. */ if (!maybe_zonecut && foundsig != NULL) break; } else if (header->type == sigtype) { /* * We've found the RRSIG rdataset for our * target type. Remember it. */ foundsig = header; /* * If we've got all we need, end the search. */ if (!maybe_zonecut && found != NULL) break; } else if (header->type == dns_rdatatype_nsec) { /* * Remember a NSEC rdataset even if we're * not specifically looking for it, because * we might need it later. */ nsecheader = header; } else if (header->type == RBTDB_RDATATYPE_SIGNSEC) { /* * If we need the NSEC rdataset, we'll also * need its signature. */ nsecsig = header; } else if (cname_ok && header->type == RBTDB_RDATATYPE_SIGCNAME) { /* * If we get a CNAME match, we'll also need * its signature. */ cnamesig = header; } } } if (empty_node) { /* * We have an exact match for the name, but there are no * active rdatasets in the desired version. That means that * this node doesn't exist in the desired version, and that * we really have a partial match. */ if (!wild) { UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock)); goto partial_match; } } /* * If we didn't find what we were looking for... */ if (found == NULL) { if (search.zonecut != NULL) { /* * We were trying to find glue at a node beneath a * zone cut, but didn't. * * Return the delegation. */ UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock)); result = setup_delegation(&search, nodep, foundname, rdataset, sigrdataset); goto tree_exit; } /* * The desired type doesn't exist. */ result = DNS_R_NXRRSET; if (search.rbtdb->secure && (nsecheader == NULL || nsecsig == NULL)) { /* * The zone is secure but there's no NSEC, * or the NSEC has no signature! */ if (!wild) { result = DNS_R_BADDB; goto node_exit; } UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock)); result = find_closest_nsec(&search, nodep, foundname, rdataset, sigrdataset, search.rbtdb->secure); if (result == ISC_R_SUCCESS) result = DNS_R_EMPTYWILD; goto tree_exit; } if ((search.options & DNS_DBFIND_FORCENSEC) != 0 && nsecheader == NULL) { /* * There's no NSEC record, and we were told * to find one. */ result = DNS_R_BADDB; goto node_exit; } if (nodep != NULL) { new_reference(search.rbtdb, node); *nodep = node; } if (search.rbtdb->secure || (search.options & DNS_DBFIND_FORCENSEC) != 0) { bind_rdataset(search.rbtdb, node, nsecheader, 0, rdataset); if (nsecsig != NULL) bind_rdataset(search.rbtdb, node, nsecsig, 0, sigrdataset); } if (wild) foundname->attributes |= DNS_NAMEATTR_WILDCARD; goto node_exit; } /* * We found what we were looking for, or we found a CNAME. */ if (type != found->type && type != dns_rdatatype_any && found->type == dns_rdatatype_cname) { /* * We weren't doing an ANY query and we found a CNAME instead * of the type we were looking for, so we need to indicate * that result to the caller. */ result = DNS_R_CNAME; } else if (search.zonecut != NULL) { /* * If we're beneath a zone cut, we must indicate that the * result is glue, unless we're actually at the zone cut * and the type is NSEC or KEY. */ if (search.zonecut == node) { if (type == dns_rdatatype_nsec || type == dns_rdatatype_dnskey) result = ISC_R_SUCCESS; else if (type == dns_rdatatype_any) result = DNS_R_ZONECUT; else result = DNS_R_GLUE; } else result = DNS_R_GLUE; /* * We might have found data that isn't glue, but was occluded * by a dynamic update. If the caller cares about this, they * will have told us to validate glue. * * XXX We should cache the glue validity state! */ if (result == DNS_R_GLUE && (search.options & DNS_DBFIND_VALIDATEGLUE) != 0 && !valid_glue(&search, foundname, type, node)) { UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock)); result = setup_delegation(&search, nodep, foundname, rdataset, sigrdataset); goto tree_exit; } } else { /* * An ordinary successful query! */ result = ISC_R_SUCCESS; } if (nodep != NULL) { if (!at_zonecut) new_reference(search.rbtdb, node); else search.need_cleanup = ISC_FALSE; *nodep = node; } if (type != dns_rdatatype_any) { bind_rdataset(search.rbtdb, node, found, 0, rdataset); if (foundsig != NULL) bind_rdataset(search.rbtdb, node, foundsig, 0, sigrdataset); } if (wild) foundname->attributes |= DNS_NAMEATTR_WILDCARD; node_exit: UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock)); tree_exit: RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read); /* * If we found a zonecut but aren't going to use it, we have to * let go of it. */ if (search.need_cleanup) { node = search.zonecut; lock = &(search.rbtdb->node_locks[node->locknum].lock); LOCK(lock); INSIST(node->references > 0); node->reference
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -