query.c revision 95d24aa0d0c34529438d67424dcabad9b8cd9810
* Increment query statistics counters. /* We end up here in case of YXDOMAIN, and maybe others */ * client->query.qname was dynamically allocated. * If we're not freeing everything, we keep the first three * dbversions structures around. * Reset the query state of a client to its default state. * Cancel the fetch if it's running. * Cleanup any active versions. * Allocate a name buffer. CTRACE(
"query_newnamebuf: isc_buffer_allocate failed: done");
CTRACE(
"query_newnamebuf: done");
* Return a name buffer with space for a maximal name, allocating * a new one if necessary. CTRACE(
"query_getnamebuf: query_newnamebuf failed: done");
CTRACE(
"query_getnamebuf: query_newnamebuf failed: done");
CTRACE(
"query_getnamebuf: done");
* 'name' is using space in 'dbuf', but 'dbuf' has not yet been * adjusted to take account of that. We do the adjustment. * 'name' is no longer needed. Return it to our pool of temporary * names. If it is using a name buffer, relinquish its exclusive CTRACE(
"query_releasename: done");
CTRACE(
"query_newname: dns_message_gettempname failed: done");
CTRACE(
"query_newname: done");
"dns_message_gettemprdataset failed: done");
CTRACE(
"query_newrdataset: done");
CTRACE(
"query_putrdataset: done");
for (i = 0; i < n; i++) {
* We only return ISC_R_NOMEMORY if we couldn't * We may already have done a query related to this * database. If so, we must be sure to make subsequent * queries from the same version. * This is a new zone for this query. Add it to * Find a zone database to answer the query. * This limits our searching to the zone where the first name * (the query target) was looked for. This prevents following * CNAMES or DNAMES into other zones and prevents returning * additional data from other zones. * If the zone has an ACL, we'll check it, otherwise * we use the view's "allow-query" ACL. Each ACL is only checked * Also, get the database version to use. * Get the current version of this database. * We've evaluated the view's queryacl already. If * NS_QUERYATTR_QUERYOK is set, then the client is * allowed to make queries, otherwise the query should * We haven't evaluated the view's queryacl yet. * We were allowed by the default * "allow-query" ACL. Remember this so we * don't have to check again. * We've now evaluated the view's query ACL, and * the NS_QUERYATTR_QUERYOK attribute is now valid. * Remember the result of the ACL check so we * don't have to check again. /* Transfer ownership. */ * Find a cache database to answer the query. * This may fail with DNS_R_REFUSED if the client * is not allowed to use the cache. * We've evaluated the view's queryacl already. If * NS_QUERYATTR_QUERYOK is set, then the client is * allowed to make queries, otherwise the query should * We haven't evaluated the view's queryacl yet. * We were allowed by the default * "allow-query" ACL. Remember this so we * don't have to check again. * We've now evaluated the view's query ACL, and * the NS_QUERYATTR_QUERYOK attribute is now valid. /* Transfer ownership. */ * Find a database to answer the query. * Now look for an answer in the database. * Either the answer is in the cache, or we * We don't have the data in the cache. If we've got * glue from the zone, use it. * We don't know the answer. * We found an answer, but the cache may be better. * Remember what we've got and go look in the cache. * Otherwise, the glue is the best answer. * If we get here, the result is ISC_R_SUCCESS, and we found the * answer we were looking for in the zone. * We've already got this RRset in the response. CTRACE(
"query_isduplicate: true: done");
* The name exists, but the rdataset does not. * If the dns_name_t we're looking up is already in the message, * we don't want to trigger the caller's name replacement logic. CTRACE(
"query_isduplicate: false: done");
CTRACE(
"query_addadditional");
* 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. * Look for a zone database that might contain authoritative 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. * No authoritative data was found. The cache is our next best bet. * Most likely the client isn't allowed to query the cache. * No cached data was found. Glue is our last chance. * 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). * We have found a potential additional data rdataset, or * at least a node to iterate over. * If we have an rdataset, add it to the additional data * 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 * We now go looking for A, A6, and AAAA records, along with * XXXRTH This code could be more efficient. * Negative cache entries don't have sigrdatasets. CTRACE(
"query_addadditional: addname");
* If we haven't added anything, then we're done. * 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. * 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 * 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 * XXXRTH We should lower the priority here. Alternatively, * we could raise the priority of glue records. * If we're adding SRV records to the additional data * section, it's helpful if we add the SRV additional data * 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. CTRACE(
"query_addadditional: cleanup");
CTRACE(
"query_addadditional: done");
* Add an rrset to the additional data section. * 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 * 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. * Add 'rdataset' and any pertinent additional data to * 'fname', a name in the response message for 'client'. * We don't care if dns_a6_foreach or dns_rdataset_additionaldata() * RFC 2535 section 3.5 says that when NS, SOA, A, or AAAA records * are retrieved, any KEY RRs for the owner name should be added * to the additional data section. We treat A6 records the same way. * We don't care if query_addadditional() fails. * XXXRTH We should lower the priority here. Alternatively, * we could raise the priority of glue records. CTRACE(
"query_addrdataset: done");
* 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. * We've already got an RRset of the given name and type. * There's nothing else to do; CTRACE(
"query_addrrset: dns_message_findname succeeded: done");
* The name doesn't exist. * 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 * We have a signature. Add it to the response. CTRACE(
"query_addrrset: done");
* Get resources and make 'name' be the database origin. * This is bad. We tried to get the SOA RR at the zone top * Extract the SOA MINIMUM. * Add the SOA and its SIG to the response, with the * TTLs adjusted per RFC2308 section 3. * Get resources and make 'name' be the database origin. CTRACE(
"query_addns: dns_message_gettempname failed: done");
CTRACE(
"query_addns: query_newrdataset failed");
CTRACE(
"query_addns: query_newrdataset failed");
CTRACE(
"query_addns: calling dns_db_find");
CTRACE(
"query_addns: dns_db_find complete");
CTRACE(
"query_addns: dns_db_find failed");
* This is bad. We tried to get the NS rdataset at the zone * top and it didn't work! CTRACE(
"query_addns: cleanup");
* We assume the name data referred to by tname won't go away. * Find the right database. * We'll need some resources... * Now look for the zonecut. * We found a zonecut in the cache, but our * zone delegation is better. * We didn't find anything in the cache, but we * have a zone delegation, so use it. * We've already done query_keepname() on * zfname, so we must set dbuf to NULL to * prevent query_addrrset() from trying to * call query_keepname() again. * We'll need some resources... * Look for the DS record, which may or may not be present. * If we didn't find it, look for an NXT. */ * We've already added the NS record, so if the name's not there, * we have other problems. Use this name rather than calling CTRACE(
"query_addwildcardproof");
* We'll need some resources... * We'll need some resources... * If this returns success, we've found the wildcard for a * successful answer, so we're done. * Resume a query after recursion. * This is the fetch we've been waiting for. * This is a fetch completion event for a cancelled fetch. * Clean up and don't resume the find. * If this client is shutting down, or this transaction * has timed out, do not resume the find. * This may destroy the client. * We are about to recurse, which means that this client will * be unavailable for serving new requests for an indeterminate * amount of time. If this client is currently responsible * for handling incoming queries, set up a new client * object to handle them while we are waiting for a * response. There is no need to replace TCP clients * because those have already been replaced when the * connection was accepted (if allowed by the TCP quota). "recursive-clients limit exceeded, " "aborting oldest query");
"no more recursive clients: %s",
* Record that we're waiting for an event. A client which * is shutting down will not be destroyed until all the * events have been received. * Extract a network address from the RDATA of an A or AAAA * ISC_R_NOTIMPLEMENTED The rdata is not a known address type. * Find the sort order of 'rdata' in the topology-like * ACL forming the second element in a 2-element top-level * Find the sort order of 'rdata' in the matching element * of a 1-element top-level sortlist statement. * Find the sortlist statement that applies to 'client' and set up * the sortlist info in in client->message appropriately. * Do the bulk of query processing for the current query of 'client'. * If 'event' is non-NULL, we are returning from recursion and 'qtype' * is ignored. Otherwise, 'qtype' is the query type. * One-time initialization. * It's especially important to initialize anything that the cleanup * We're returning from recursion. Restore the query context * We'll need some resources... * Not returning from recursion. * If it's a SIG query, we'll iterate the node. CTRACE(
"query_find: restart");
* First we must find the right database. CTRACE(
"query_find: db_find");
* We'll need some resources... * Now look for an answer in the database. * This case is handled in the main line below. * These cases are handled in the main line below. * The cache doesn't even have the root NS. Get them from * Nonsensical root hints may require cleanup. * We don't have any root server hints, but * we may have working forwarders, so try to /* Unable to give root server referral. */ * XXXRTH We should trigger root server priming here. * We're authoritative for an ancestor of QNAME. * If we don't have a cache, this is the best * If the client is making a nonrecursive * query we always give out the authoritative * delegation. This way even if we get * junk in our cache, we won't fail in our * role as the delegating authority if another * nameserver asks us about a delegated * We enable the retrieval of glue for this * database by setting client->query.gluedb. * We must ensure NOADDITIONAL is off, * because the generation of * additional data is required in * We might have a better answer or delegation * in the cache. We'll remember the current * values of fname, rdataset, and sigrdataset. * We'll then go looking for QNAME in the * cache. If we find something better, we'll * We've already got a delegation from * authoritative data, and it is better * than what we found in the cache. Use * it instead of the cache delegation. * We've already done query_keepname() on * zfname, so we must set dbuf to NULL to * prevent query_addrrset() from trying to * call query_keepname() again. * We don't clean up zdb here because we * may still need it. It will get cleaned * up by the main cleanup code. * This is the best answer. * We must ensure NOADDITIONAL is off, * because the generation of * additional data is required in * If we've got a NXT record, we need to save the * name now because we're going call query_addsoa() * below, and it needs to use the name buffer. * We're not going to use fname, and need to release * our hold on the name buffer so query_addsoa() * Add NXT record if we found one. * If we've got a NXT record, we need to save the * name now because we're going call query_addsoa() * below, and it needs to use the name buffer. * We're not going to use fname, and need to release * our hold on the name buffer so query_addsoa() * Add SOA. If the query was for a SOA record force the * ttl to zero so that it is possible for clients to find * the containing zone of a arbitary name with a stub * resolver and not have it cached. * Add NXT record if we found one. * Set message rcode, if required. * We don't call query_addrrset() because we don't need any * of its extra features (and things would probably break!). * Keep a copy of the rdataset. We have to do this because * query_addrrset may clear 'rdataset' (to prevent the * cleanup code from cleaning it up). * Add the CNAME to the answer section. * We set the PARTIALANSWER attribute so that if anything goes * wrong later on, we'll return what we've got so far. * Reset qname to be the target name of the CNAME and restart * Compare the current qname to the found name. We need * to know how many labels and bits are in common because * we're going to have to split qname later on. * Keep a copy of the rdataset. We have to do this because * query_addrrset may clear 'rdataset' (to prevent the * cleanup code from cleaning it up). * Add the DNAME to the answer section. * We set the PARTIALANSWER attribute so that if anything goes * wrong later on, we'll return what we've got so far. * Get the target name of the DNAME. * Construct the new qname. * RFC 2672, section 4.1, subsection 3c says * we should return YXDOMAIN if the constructed * name would be too long. * Synthesize a CNAME for this DNAME. * We want to synthesize a CNAME since if we don't * then older software that doesn't understand DNAME * will not chain like it should. * We do not try to synthesize a signature because we hope * that security aware servers will understand DNAME. Also, * even if we had an online key, making a signature * on-the-fly is costly, and not really legitimate anyway * since the synthesized CNAME is NOT in the zone. * Switch to the new qname and restart. * Something has gone wrong. * XXXRTH Need to handle zonecuts with special case * Calling query_addrrset() with a non-NULL dbuf is going * to either keep or release the name. We don't want it to * release fname, since we may have to call query_addrrset() * more than once. That means we have to call query_keepname() * now, and pass a NULL dbuf to query_addrrset(). * If we do a query_addrrset() below, we must set fname to * NULL before leaving this block, otherwise we might try to * cleanup fname even though we're using it! * rdataset is non-NULL only in certain pathological * cases involving DNAMEs. * We're not interested in this rdataset. * We didn't match any rdatasets. * XXXRTH If this is a secure zone and we * didn't find any SIGs, we should generate * an error unless we were searching for * We were searching for SIG records in * a nonsecure zone. Send a "no error, * This is the "normal" case -- an ordinary question to which * We shouldn't ever fail to add 'rdataset' * because it's already in the answer. CTRACE(
"query_find: addauth");
* Add NS records to the authority section (if we haven't already * added them to the answer section). * Add NXT records to the authority section if they're needed for * DNSSEC wildcard proofs. CTRACE(
"query_find: cleanup");
* We're not authoritative, so we must ensure the AA bit * If we don't have any answer to give the client, * or if the client requested recursion and thus wanted * the complete answer, send an error response. * We are done. Set up sortlist data for the message * rendering code, make a final tweak to the AA bit if the * auth-nxdomain config option says so, then render and * Ensure that appropriate cleanups occur. * We don't have a cache. Turn off cache support and * If the client isn't allowed to recurse (due to * "recursion no", the allow-recursion ACL, or the * lack of a resolver in this view), or if it * doesn't want recursion, turn recursion off. * There's more than one QNAME in the question * Check for multiple question queries, since edns1 is dead. * Check for meta-queries like IXFR and AXFR. break;
/* Let query_find handle it. */ default:
/* TSIG, etc. */ * If the client has requested that DNSSEC checking be disabled, * allow lookups to return pending data and instruct the resolver * to return data before validation has completed. * This is an ordinary query. * Assume authoritative response until it is known to be * Set AD. We must clear it if we add non-validated data to a * Synthesize IPv6 responses if appropriate. /* Must be 32 nibbles + "ip6" + "int" + root */ /* bitstring label + "ip6" + "arpa" + root */ * Generate a synthetic IPv6 forward mapping response for the current * Start an ADB find to get addresses, or more addresses, for * a synthetic IPv6 forward mapping response. * Make a persistent copy of the 'target' name data in 'ptarget'; * it will become the new query name. * Get another temporary name 'tname' for insertion into the * Probably a CNAME loop. Reply with partial * Handle an ADB finddone event generated as part of synthetic IPv6 * forward mapping processing. * Generate a synthetic IPv6 forward mapping response based on * a completed ADB lookup. * Could it be useful to return IPv4 addresses as A records? * Finish synthetic IPv6 forward mapping processing. -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9, -
1, -
1, -
1, -
1, -
1, -
1,
-
1,
10,
11,
12,
13,
14,
15, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1,
10,
11,
12,
13,
14,
15, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1,
-
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1, -
1 * Convert label 'i' of 'name' into its hexadecimal value, storing it * in '*hexp'. If the label is not a valid hex nibble, return ISC_R_FAILURE. * Convert the ip6.int name 'name' into the corresponding IPv6 address for (i = 0; i <
16; i++) {
* Generate a synthetic IPv6 reverse mapping response for the current /* Try IP6.ARPA nibble style first. */ return;
/* Wait for completion event. */ /* Try IP6.INT nibble next. */ /* Try IP6.ARPA bitstring next. */ * in some cases, but since there may be any combination * of NXDOMAIN and NXRRSET results from the IP6.INT * and IP6.ARPA lookups, it could still be wrong with * respect to one or the other. * Get a temporary name 'tname' for insertion into the