📄 rbtdb.c
字号:
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))) maybe_zonecut = ISC_TRUE; } /* * Certain DNSSEC types are not subject to CNAME matching * (RFC 2535, section 2.3.5). * * We don't check for SIG, because we don't store SIG records * directly. */ if (type == dns_rdatatype_key || type == dns_rdatatype_nxt) 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_sig, type); nxtheader = NULL; nxtsig = 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 ((header->attributes & RDATASET_ATTR_NONEXISTENT) != 0) 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_nxt && type != dns_rdatatype_key) { /* * 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 SIG, * 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 SIG 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_nxt) { /* * Remember a NXT rdataset even if we're * not specifically looking for it, because * we might need it later. */ nxtheader = header; } else if (header->type == RBTDB_RDATATYPE_SIGNXT) { /* * If we need the NXT rdataset, we'll also * need its signature. */ nxtsig = 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 && (nxtheader == NULL || nxtsig == NULL)) { /* * The zone is secure but there's no NXT, * or the NXT has no signature! */ if (!wild) { result = DNS_R_BADDB; goto node_exit; } UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock)); result = find_closest_nxt(&search, nodep, foundname, rdataset, sigrdataset); if (result == ISC_R_SUCCESS) result = DNS_R_EMPTYWILD; goto tree_exit; } if (nodep != NULL) { new_reference(search.rbtdb, node); *nodep = node; } if (search.rbtdb->secure) { bind_rdataset(search.rbtdb, node, nxtheader, 0, rdataset); bind_rdataset(search.rbtdb, node, nxtsig, 0, sigrdataset); } 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 NXT or KEY. */ if (search.zonecut == node) { if (type == dns_rdatatype_nxt || type == dns_rdatatype_key) 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); } 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->references--; if (node->references == 0) no_references(search.rbtdb, node, 0, isc_rwlocktype_none); UNLOCK(lock); } if (close_version) closeversion(db, &version, ISC_FALSE); dns_rbtnodechain_reset(&search.chain); return (result);}static isc_result_tzone_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options, isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset){ UNUSED(db); UNUSED(name); UNUSED(options); UNUSED(now); UNUSED(nodep); UNUSED(foundname); UNUSED(rdataset); UNUSED(sigrdataset); FATAL_ERROR(__FILE__, __LINE__, "zone_findzonecut() called!"); return (ISC_R_NOTIMPLEMENTED);}static isc_result_tcache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { rbtdb_search_t *search = arg; rdatasetheader_t *header, *header_prev, *header_next; rdatasetheader_t *dname_header, *sigdname_header; isc_result_t result; /* XXX comment */ REQUIRE(search->zonecut == NULL); /* * Keep compiler silent. */ UNUSED(name); LOCK(&(search->rbtdb->node_locks[node->locknum].lock)); /* * Look for a DNAME or SIG DNAME rdataset. */ dname_header = NULL; sigdname_header = NULL; header_prev = NULL; for (header = node->data; header != NULL; header = header_next) { header_next = header->next; if (header->ttl <= search->now) { /* * This rdataset is stale. If no one else is * using the node, we can clean it up right * now, otherwise we mark it as stale, and * the node as dirty, so it will get cleaned * up later. */ if (node->references == 0) { INSIST(header->down == NULL); if (header_prev != NULL) header_prev->next = header->next; else node->data = header->next; free_rdataset(search->rbtdb->common.mctx, header); } else { header->attributes |= RDATASET_ATTR_STALE; node->dirty = 1; header_prev = header; } } else if (header->type == dns_rdatatype_dname && EXISTS(header)) { dname_header = header; header_prev = header; } else if (header->type == RBTDB_RDATATYPE_SIGDNAME && EXISTS(header)) { sigdname_header = header; header_prev = header; } else header_prev = header; } if (dname_header != NULL && (dname_header->trust != dns_trust_pending || (search->options & DNS_DBFIND_PENDINGOK) != 0)) { /* * 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 = dname_header; search->zonecut_sigrdataset = sigdname_header; search->need_cleanup = ISC_TRUE; result = DNS_R_PARTIALMATCH; } else result = DNS_R_CONTINUE; UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock)); return (result);}static inline isc_result_tfind_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset){ unsigned int i; dns_rbtnode_t *level_node; rdatasetheader_t *header, *header_prev, *header_next; rdatasetheader_t *found, *foundsig; isc_result_t result = ISC_R_NOTFOUND; dns_name_t name; dns_rbtdb_t *rbtdb; isc_boolean_t done; /* * Caller must be holding the tree lock. */ rbtdb = search->rbtdb; i = search->chain.level_matches; done = ISC_FALSE; do { LOCK(&(rbtdb->node_locks[node->locknum].lock)); /* * Look for NS and SIG NS rdatasets. */ found = NULL; foundsig = NULL; header_prev = NULL; for (header = node->data; header != NULL; header = header_next) { header_next = header->next; if (header->ttl <= search->now) { /* * This rdataset is stale. If no one else is * using the node, we can clean it up right * now, otherwise we mark it as stale, and * the node as dirty, so it will get cleaned * up later. */ if (node->references == 0) { INSIST(header->down == NULL); if (header_prev != NULL) header_prev->next = header->next; else node->data = header->next; free_rdataset(rbtdb->common.mctx, header); } else { header->attributes |= RDATASET_ATTR_STALE; node->dirty = 1; header_prev = header; } } else if ((header->attributes & RDATASET_ATTR_NONEXISTENT) == 0) { /* * We've found an extant rdataset. See if * we're interested in it. */ if (header->type == dns_rdatatype_ns) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -