query.c
来自「非常好的dns解析软件」· C语言 代码 · 共 2,425 行 · 第 1/5 页
C
2,425 行
rdataset_base = additionalctx->rdataset; client = additionalctx->client; REQUIRE(NS_CLIENT_VALID(client)); 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; additionaltype = dns_rdatasetadditional_fromauth; dns_name_init(&cfname, NULL); CTRACE("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("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("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("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("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("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_find(db, name, version, type, client->query.dboptions, client->now, &node, fname, 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_find(db, name, version, type, client->query.dboptions | DNS_DBFIND_GLUEOK, client->now, &node, fname, 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 poision 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("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("query_addadditional2: negative glue additional cache"); dns_db_closeversion(cdb, &cversion, ISC_FALSE); dns_db_detach(&cdb); goto cleanup; } /* Cache hit. */ CTRACE("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_find(db, name, version, type, client->query.dboptions | DNS_DBFIND_GLUEOK, client->now, &node, fname, 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; /* * 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 && (rdataset->trust == dns_trust_pending || rdataset->trust == dns_trust_glue) && !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); /* * Negative cache entries don't have sigrdatasets. */ INSIST(! dns_rdataset_isassociated(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; } } /* 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 && (rdataset->trust == dns_trust_pending || rdataset->trust == dns_trust_glue) && !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 != 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("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("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("query_addadditional2: done"); return (eresult);}static inline voidquery_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'. */ CTRACE("query_addrdataset"); ISC_LIST_APPEND(fname->list, rdataset, link); if (client->view->order != NULL) rdataset->attributes |= dns_order_find(client->view->order, fname, rdataset->type, rdataset->rdclass); rdataset->attributes |= DNS_RDATASETATTR_LOADORDER; if (NOADDITIONAL(client)) return; /* * 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); CTRACE("query_addrdataset: done");}static voidquery_addrrset(ns_client_t *client, dns_name_t **namep, dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp, isc_buffer_t *dbuf, dns_section_t section){ dns_name_t *name, *mname; dns_rdataset_t *rdataset, *mrdataset, *sigrdataset; isc_result_t result; /*% * To the current response for 'client', add the answer RRset * '*rdatasetp' and an optional signature set '*sigrdatasetp', with * owner name '*namep', to section 'section', unless they are * already there. Also add any pertinent additional data. * * If 'dbuf' is not NULL, then '*namep' is the name whose data is * stored in 'dbuf'. In this case, query_addrrset() guarantees that * when it returns the name will either have been kept or released. */ CTRACE("query_addrrset"); name = *namep; rdataset = *rdatasetp;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?