📄 query.c
字号:
CTRACE("query_isduplicate: false: done"); return (ISC_FALSE);}static isc_result_tquery_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { ns_client_t *client = arg; isc_result_t result, eresult; dns_dbnode_t *node; dns_db_t *db; dns_name_t *fname, *mname; dns_rdataset_t *rdataset, *sigrdataset, *a6rdataset, *trdataset; isc_buffer_t *dbuf; isc_buffer_t b; dns_dbversion_t *version; isc_boolean_t added_something, need_addname; dns_zone_t *zone; dns_rdatatype_t type; REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(qtype != dns_rdatatype_any); if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype)) return (ISC_R_SUCCESS); CTRACE("query_addadditional"); /* * Initialization. */ eresult = ISC_R_SUCCESS; fname = NULL; rdataset = NULL; sigrdataset = NULL; a6rdataset = NULL; trdataset = NULL; db = NULL; version = NULL; node = NULL; added_something = ISC_FALSE; need_addname = ISC_FALSE; zone = NULL; /* * 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. */ if (qtype == dns_rdatatype_a) type = dns_rdatatype_any; else type = qtype; /* * Get some resources. */ dbuf = query_getnamebuf(client); if (dbuf == NULL) goto cleanup; fname = query_newname(client, dbuf, &b); rdataset = query_newrdataset(client); if (fname == NULL || rdataset == NULL) goto cleanup; if (WANTDNSSEC(client)) { sigrdataset = query_newrdataset(client); if (sigrdataset == NULL) goto cleanup; } /* * Look for a zone database that might contain authoritative * additional data. */ result = query_getzonedb(client, name, DNS_GETDB_NOLOG, &zone, &db, &version); if (result != ISC_R_SUCCESS) goto try_cache; CTRACE("query_addadditional: 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, rdataset, sigrdataset); if (result == ISC_R_SUCCESS) goto found; if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) dns_rdataset_disassociate(sigrdataset); 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: result = query_getcachedb(client, &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, client->now, &node, fname, rdataset, sigrdataset); if (result == ISC_R_SUCCESS) goto found; if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) dns_rdataset_disassociate(sigrdataset); 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; 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, rdataset, sigrdataset); if (!(result == ISC_R_SUCCESS || result == DNS_R_ZONECUT || result == DNS_R_GLUE)) goto cleanup; found: /* * We have found a potential additional data rdataset, or * at least a node to iterate over. */ query_keepname(client, fname, dbuf); /* * If we have an rdataset, add it to the additional data * section. */ mname = NULL; if (dns_rdataset_isassociated(rdataset) && !query_isduplicate(client, fname, type, &mname)) { if (mname != NULL) { query_releasename(client, &fname); fname = mname; } else need_addname = ISC_TRUE; ISC_LIST_APPEND(fname->list, rdataset, link); trdataset = rdataset; rdataset = NULL; added_something = ISC_TRUE; /* * Note: we only add SIGs if we've added the type they cover, * so we do not need to check if the SIG rdataset is already * in the response. */ if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { ISC_LIST_APPEND(fname->list, sigrdataset, link); sigrdataset = NULL; } } if (qtype == dns_rdatatype_a) { /* * We now go looking for A, A6, and AAAA records, along with * their signatures. * * XXXRTH This code could be more efficient. */ if (rdataset != NULL) { if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); } else { rdataset = query_newrdataset(client); if (rdataset == NULL) goto addname; } if (sigrdataset != NULL) { if (dns_rdataset_isassociated(sigrdataset)) dns_rdataset_disassociate(sigrdataset); } else if (WANTDNSSEC(client)) { sigrdataset = query_newrdataset(client); if (sigrdataset == NULL) goto addname; } result = dns_db_findrdataset(db, node, version, dns_rdatatype_a, 0, client->now, rdataset, sigrdataset); if (result == DNS_R_NCACHENXDOMAIN) goto addname; if (result == DNS_R_NCACHENXRRSET) { dns_rdataset_disassociate(rdataset); /* * Negative cache entries don't have sigrdatasets. */ INSIST(sigrdataset == NULL || ! dns_rdataset_isassociated(sigrdataset)); } if (result == ISC_R_SUCCESS) { mname = NULL; if (!query_isduplicate(client, fname, dns_rdatatype_a, &mname)) { if (mname != NULL) { query_releasename(client, &fname); fname = mname; } else need_addname = ISC_TRUE; ISC_LIST_APPEND(fname->list, rdataset, link); added_something = ISC_TRUE; if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { ISC_LIST_APPEND(fname->list, sigrdataset, link); sigrdataset = query_newrdataset(client); } rdataset = query_newrdataset(client); if (rdataset == NULL) goto addname; if (WANTDNSSEC(client) && sigrdataset == NULL) goto addname; } else { dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) dns_rdataset_disassociate(sigrdataset); } } result = dns_db_findrdataset(db, node, version, dns_rdatatype_a6, 0, client->now, rdataset, sigrdataset); if (result == DNS_R_NCACHENXDOMAIN) goto addname; if (result == DNS_R_NCACHENXRRSET) { dns_rdataset_disassociate(rdataset); INSIST(sigrdataset == NULL || ! dns_rdataset_isassociated(sigrdataset)); } if (result == ISC_R_SUCCESS) { mname = NULL; if (!query_isduplicate(client, fname, dns_rdatatype_a6, &mname)) { if (mname != NULL) { query_releasename(client, &fname); fname = mname; } else need_addname = ISC_TRUE; a6rdataset = rdataset; ISC_LIST_APPEND(fname->list, rdataset, link); added_something = ISC_TRUE; if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { ISC_LIST_APPEND(fname->list, sigrdataset, link); sigrdataset = query_newrdataset(client); } rdataset = query_newrdataset(client); if (rdataset == NULL) goto addname; if (WANTDNSSEC(client) && sigrdataset == NULL) goto addname; } else { dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) dns_rdataset_disassociate(sigrdataset); } } result = dns_db_findrdataset(db, node, version, dns_rdatatype_aaaa, 0, client->now, rdataset, sigrdataset); if (result == DNS_R_NCACHENXDOMAIN) goto addname; if (result == DNS_R_NCACHENXRRSET) { dns_rdataset_disassociate(rdataset); INSIST(sigrdataset == NULL || ! dns_rdataset_isassociated(sigrdataset)); } if (result == ISC_R_SUCCESS) { mname = NULL; if (!query_isduplicate(client, fname, dns_rdatatype_aaaa, &mname)) { if (mname != NULL) { query_releasename(client, &fname); fname = mname; } else need_addname = ISC_TRUE; ISC_LIST_APPEND(fname->list, rdataset, link); added_something = ISC_TRUE; if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { ISC_LIST_APPEND(fname->list, sigrdataset, link); sigrdataset = NULL; } rdataset = NULL; } } } addname: CTRACE("query_addadditional: 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; /* * In a few cases, we want to add additional data for additional * data. It's simpler to just deal with special cases here than * to try to create a general purpose mechanism and allow the * rdata implementations to do it themselves. * * This involves recursion, but the depth is limited. The * most complex case is adding a SRV rdataset, which involves * recursing to add address records, which in turn can cause * recursion to add KEYs. */ if (type == dns_rdatatype_a || type == dns_rdatatype_aaaa) { /* * RFC 2535 section 3.5 says that when A or AAAA records are * retrieved as additional data, any KEY RRs for the owner name * should be added to the additional data section. Note: we * do NOT include A6 in the list of types with such treatment * in additional data because we'd have to do it for each A6 * in the A6 chain. * * XXXRTH We should lower the priority here. Alternatively, * we could raise the priority of glue records. */ eresult = query_addadditional(client, name, dns_rdatatype_key); } else if (type == dns_rdatatype_srv && trdataset != NULL) { /* * If we're adding SRV records to the additional data * section, it's helpful if we add the SRV additional data * as well. */ eresult = dns_rdataset_additionaldata(trdataset, query_addadditional, client); } /* * If we added an A6 rdataset, we should also add everything we * know about the A6 chains. We wait until now to do this so that * they'll come after any additional data added above. */ if (a6rdataset != NULL) { dns_a6_reset(&client->query.a6ctx); dns_a6_foreach(&client->query.a6ctx, a6rdataset, client->now); } cleanup: CTRACE("query_addadditional: cleanup"); query_putrdataset(client, &rdataset); if (sigrdataset != NULL) query_putrdataset(client, &sigrdataset); 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_addadditional: done"); return (eresult);}static voidquery_adda6rrset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset){ ns_client_t *client = arg; dns_rdataset_t *crdataset, *csigrdataset; isc_buffer_t b, *dbuf; dns_name_t *fname, *mname; /* * Add an rrset to the additional data section. */ REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(rdataset->type == dns_rdatatype_a6); /* * Get some resources... */ fname = NULL; crdataset = NULL; csigrdataset = NULL; dbuf = query_getnamebuf(client); if (dbuf == NULL) goto cleanup; fname = query_newname(client, dbuf, &b); crdataset = query_newrdataset(client); if (fname == NULL || crdataset == NULL) goto cleanup; if (sigrdataset != NULL) { csigrdataset = query_newrdataset(client); if (csigrdataset == NULL) goto cleanup; } if (dns_name_copy(name, fname, NULL) != ISC_R_SUCCESS) goto cleanup; dns_rdataset_clone(rdataset, crdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) dns_rdataset_clone(sigrdataset, csigrdataset); mname = NULL; if (query_isduplicate(client, fname, crdataset->type, &mname)) goto cleanup; if (mname != NULL) { query_releasename(client, &fname); fname = mname; } else { query_keepname(client, fname, dbuf); dns_message_addname(client->message, fname, DNS_SECTION_ADDITIONAL); } ISC_LIST_APPEND(fname->list, crdataset, link); crdataset = NULL; /* * Note: we only add SIGs if we've added the type they cover, so * we do not need to check if the SIG rdataset is already in the * response. */ if (sigrdataset != NULL && dns_rdataset_isassociated(csigrdataset)) { ISC_LIST_APPEND(fname->list, csigrdataset, link); csigrdataset = NULL; } fname = NULL; /* * In spite of RFC 2535 section 3.5, we don't currently try to add * KEY RRs for the A6 records. It's just too much work. */ cleanup: query_putrdataset(client, &crdataset); if (sigrdataset != NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -