query.c revision 03e200df5dc283f24a6a349f0b31d3eab26da893
"query %p: %s",
query, (m))
* 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 * 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, if necessary. */ * Find a zone database to answer the query. /* 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. */ /* Calculate how many labels are in name. */ /* Try to find name in bind's standard database. */ /* See how many labels are in the zone's name. */ * If # zone labels < # name labels, try to find an even better match * Only try if a DLZ driver is loaded for this view /* If we successful, we found a better match. */ * If the previous search returned a zone, detach it. * If the previous search returned a database, * If the previous search returned a version, clear it. * Get our database version. * Be sure to return our database. * We return a null zone, No stats for DLZ zones. /* If successfull, Transfer ownership of zone. */ * If neither attempt above succeeded, return the cache instead * 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). * Don't poision caches using the bailiwick protection model. * 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 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 * If we're adding SRV records to the additional data * section, it's helpful if we add the SRV additional data CTRACE(
"query_addadditional: cleanup");
CTRACE(
"query_addadditional: done");
* This function is optimized for "address" types. For other * types, use a generic routine. * XXX: ideally, this function should be generic enough. 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 /* Check additional cache */ CTRACE(
"query_addadditional2: auth zone not found");
/* Is the cached DB up-to-date? */ CTRACE(
"query_addadditional2: old auth additional cache");
* 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");
/* We've got an active cache. */ CTRACE(
"query_addadditional2: auth additional cache");
* Look for a zone database that might contain authoritative /* Cache the negative result */ 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. /* Cache the negative result */ * 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). * Don't poision caches using the bailiwick protection model. /* Check additional cache */ CTRACE(
"query_addadditional2: old glue additional cache");
/* We have a negative cache. */ CTRACE(
"query_addadditional2: negative glue additional cache");
CTRACE(
"query_addadditional2: glue additional cache");
/* cache the negative result */ * 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. * 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. * Negative cache entries don't have sigrdatasets. /* Remember the result as a cache */ /* do not cache incomplete information */ /* Find AAAA RRset with sig RRset */ /* The NXDOMAIN case should be covered above */ * Negative cache entries don't have sigrdatasets. * Set the new result in the cache if required. We do not support * caching additional data from a cache DB. * 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 CTRACE(
"query_addadditional2: 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. CTRACE(
"query_addadditional2: cleanup");
CTRACE(
"query_addadditional2: done");
* Add 'rdataset' and any pertinent additional data to * 'fname', a name in the response message for 'client'. * We don't care if dns_rdataset_additionaldata() fails. 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");
"dns_db_findrdataset or 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 NSEC. */ * 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");
* Get the NOQNAME proof then if !ispositve * get the NOWILDCARD proof. * DNS_DBFIND_NOWILD finds the NSEC records that covers the * name ignoring any wildcard. From the owner and next names * of this record you can compute which wildcard (if it exists) * will match by finding the longest common suffix of the * owner name and next names with the qname and prefixing that * with the wildcard label. * b.example NSEC a.d.example * a.d.example NSEC g.f.example * g.f.example NSEC z.i.example * z.i.example NSEC example * a.example -> example NSEC b.example * d.b.example -> b.example NSEC a.d.example * a.f.example -> a.d.example NSEC g.f.example * j.example -> z.i.example NSEC example * We'll need some resources... * We'll need some resources... /* This will succeed, since we've stripped labels. */ * 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 soft limit exceeded, " "aborting oldest query");
"no more recursive clients: %s",
"ns_client_replace() failed: %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. CTRACE(
"query_addnoqnameproof");
A,
sizeof(A),
sizeof(B), \
B,
NULL, { (
void *)-
1, (
void *)-
1}, \
static unsigned char inaddr10[] =
"\00210\007IN-ADDR\004ARPA";
static unsigned char inaddr16172[] =
"\00216\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr17172[] =
"\00217\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr18172[] =
"\00218\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr19172[] =
"\00219\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr20172[] =
"\00220\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr21172[] =
"\00221\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr22172[] =
"\00222\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr23172[] =
"\00223\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr24172[] =
"\00224\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr25172[] =
"\00225\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr26172[] =
"\00226\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr27172[] =
"\00227\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr28172[] =
"\00228\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr29172[] =
"\00229\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr30172[] =
"\00230\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr31172[] =
"\00231\003172\007IN-ADDR\004ARPA";
static unsigned char inaddr168192[] =
"\003168\003192\007IN-ADDR\004ARPA";
static unsigned char prisoner_data[] =
"\010prisoner\004iana\003org";
static unsigned char hostmaster_data[] =
"\012hostmaster\014root-servers\003org";
"RFC 1918 response from " * 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");
"check-names failure %s/%s/%s",
namebuf,
* First we must find the right database. * Look to see if we are authoritative for the * child zone if the query type is DS. * if is_zone = true, zone = NULL then this is * a DLZ zone. Don't attempt to attach zone. 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. * Look to see if we are authoritative for the * child zone if the query type is DS. * 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 NSEC 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 NSEC record if we found one. * If we've got a NSEC 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 an arbitrary name with a stub * resolver and not have it cached. * Add NSEC record if we found one. * Set message rcode, if required. * Look for RFC 1918 leakage from Internet. * 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. * RFC2672, 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 NSEC 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 * This was a duplicate query that we are * recursing on. Don't send a response now. * The original query will still cause a response. * 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 * If this is a referral and the answer to the question * is in the glue sort it to the start of the additional * Ensure that appropriate cleanups occur. * Behave as if we don't support DNSSEC if not enabled. * 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. * Allow glue NS records to be added to the authority section * if the answer is secure. * 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