diff options
Diffstat (limited to 'bin/named/query.c')
-rw-r--r-- | bin/named/query.c | 192 |
1 files changed, 117 insertions, 75 deletions
diff --git a/bin/named/query.c b/bin/named/query.c index 3992d6e92269..363c95fa670b 100644 --- a/bin/named/query.c +++ b/bin/named/query.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: query.c,v 1.257.18.46.2.1 2009/11/19 00:25:17 marka Exp $ */ +/* $Id: query.c,v 1.257.18.53 2009/12/30 08:55:48 jinmei Exp $ */ /*! \file */ @@ -116,13 +116,16 @@ typedef struct client_additionalctx { dns_rdataset_t *rdataset; } client_additionalctx_t; -static void +static isc_result_t query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype); static isc_boolean_t validate(ns_client_t *client, dns_db_t *db, dns_name_t *name, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset); +static inline void +log_queryerror(ns_client_t *client, isc_result_t result, int line, int level); + /*% * Increment query statistics counters. */ @@ -165,8 +168,14 @@ query_send(ns_client_t *client) { } static void -query_error(ns_client_t *client, isc_result_t result) { +query_error(ns_client_t *client, isc_result_t result, int line) { + int loglevel = ISC_LOG_DEBUG(3); + + if (result == DNS_R_SERVFAIL) + loglevel = ISC_LOG_DEBUG(1); + inc_stats(client, dns_statscounter_failure); + log_queryerror(client, result, line, loglevel); ns_client_error(client, result); } @@ -942,7 +951,7 @@ query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype, zonep, dbp, versionp); #endif - /* If successfull, Transfer ownership of zone. */ + /* If successful, Transfer ownership of zone. */ if (result == ISC_R_SUCCESS) { #ifdef DLZ *zonep = zone; @@ -1159,7 +1168,7 @@ query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { goto cleanup; /* - * Don't poision caches using the bailiwick protection model. + * Don't poison caches using the bailiwick protection model. */ if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) goto cleanup; @@ -1633,7 +1642,7 @@ query_addadditional2(void *arg, dns_name_t *name, dns_rdatatype_t qtype) { goto cleanup; /* - * Don't poision caches using the bailiwick protection model. + * Don't poison caches using the bailiwick protection model. */ if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) goto cleanup; @@ -2293,7 +2302,7 @@ mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name, /* * Find the secure key that corresponds to rrsig. - * Note: 'keyrdataset' maintains state between sucessive calls, + * Note: 'keyrdataset' maintains state between successive calls, * there may be multiple keys with the same keyid. * Return ISC_FALSE if we have exhausted all the possible keys. */ @@ -2685,7 +2694,7 @@ query_addwildcardproof(ns_client_t *client, dns_db_t *db, node = NULL; /* - * Get the NOQNAME proof then if !ispositve + * Get the NOQNAME proof then if !ispositive * get the NOWILDCARD proof. * * DNS_DBFIND_NOWILD finds the NSEC records that covers the @@ -2864,8 +2873,12 @@ query_addnxrrsetnsec(ns_client_t *client, dns_db_t *db, static void query_resume(isc_task_t *task, isc_event_t *event) { dns_fetchevent_t *devent = (dns_fetchevent_t *)event; + dns_fetch_t *fetch; ns_client_t *client; - isc_boolean_t fetch_cancelled, client_shuttingdown; + isc_boolean_t fetch_canceled, client_shuttingdown; + isc_result_t result; + isc_logcategory_t *logcategory = NS_LOGCATEGORY_QUERY_EERRORS; + int errorloglevel; /* * Resume a query after recursion. @@ -2886,30 +2899,31 @@ query_resume(isc_task_t *task, isc_event_t *event) { */ INSIST(devent->fetch == client->query.fetch); client->query.fetch = NULL; - fetch_cancelled = ISC_FALSE; + fetch_canceled = ISC_FALSE; /* * Update client->now. */ isc_stdtime_get(&client->now); } else { /* - * This is a fetch completion event for a cancelled fetch. + * This is a fetch completion event for a canceled fetch. * Clean up and don't resume the find. */ - fetch_cancelled = ISC_TRUE; + fetch_canceled = ISC_TRUE; } UNLOCK(&client->query.fetchlock); INSIST(client->query.fetch == NULL); client->query.attributes &= ~NS_QUERYATTR_RECURSING; - dns_resolver_destroyfetch(&devent->fetch); + fetch = devent->fetch; + devent->fetch = NULL; /* * If this client is shutting down, or this transaction * has timed out, do not resume the find. */ client_shuttingdown = ns_client_shuttingdown(client); - if (fetch_cancelled || client_shuttingdown) { + if (fetch_canceled || client_shuttingdown) { if (devent->node != NULL) dns_db_detachnode(devent->db, &devent->node); if (devent->db != NULL) @@ -2918,8 +2932,8 @@ query_resume(isc_task_t *task, isc_event_t *event) { if (devent->sigrdataset != NULL) query_putrdataset(client, &devent->sigrdataset); isc_event_free(&event); - if (fetch_cancelled) - query_error(client, DNS_R_SERVFAIL); + if (fetch_canceled) + query_error(client, DNS_R_SERVFAIL, __LINE__); else query_next(client, ISC_R_CANCELED); /* @@ -2927,8 +2941,22 @@ query_resume(isc_task_t *task, isc_event_t *event) { */ ns_client_detach(&client); } else { - query_find(client, devent, 0); + result = query_find(client, devent, 0); + if (result != ISC_R_SUCCESS) { + if (result == DNS_R_SERVFAIL) + errorloglevel = ISC_LOG_DEBUG(2); + else + errorloglevel = ISC_LOG_DEBUG(4); + if (isc_log_wouldlog(ns_g_lctx, errorloglevel)) { + dns_resolver_logfetch(fetch, ns_g_lctx, + logcategory, + NS_LOGMODULE_QUERY, + errorloglevel, ISC_FALSE); + } + } } + + dns_resolver_destroyfetch(&fetch); } static isc_result_t @@ -3055,6 +3083,7 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain, do { \ eresult = r; \ want_restart = ISC_FALSE; \ + line = __LINE__; \ } while (0) /* @@ -3294,8 +3323,7 @@ warn_rfc1918(ns_client_t *client, dns_name_t *fname, dns_rdataset_t *rdataset) { RUNTIME_CHECK(result == ISC_R_SUCCESS); dns_rdataset_current(&found, &rdata); result = dns_rdata_tostruct(&rdata, &soa, NULL); - if (result != ISC_R_SUCCESS) - return; + RUNTIME_CHECK(result == ISC_R_SUCCESS); if (dns_name_equal(&soa.origin, &prisoner) && dns_name_equal(&soa.contact, &hostmaster)) { char buf[DNS_NAME_FORMATSIZE]; @@ -3317,7 +3345,7 @@ warn_rfc1918(ns_client_t *client, dns_name_t *fname, dns_rdataset_t *rdataset) { * If 'event' is non-NULL, we are returning from recursion and 'qtype' * is ignored. Otherwise, 'qtype' is the query type. */ -static void +static isc_result_t query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) { dns_db_t *db, *zdb; @@ -3346,8 +3374,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) isc_boolean_t empty_wild; dns_rdataset_t *noqname; isc_boolean_t resuming; - dns_rdataset_t tmprdataset; - unsigned int dboptions; + int line = -1; CTRACE("query_find"); @@ -3559,49 +3586,9 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) /* * Now look for an answer in the database. */ - dboptions = client->query.dboptions; - if (sigrdataset == NULL && client->view->enablednssec) { - /* - * If the client doesn't want DNSSEC we still want to - * look for any data pending validation to save a remote - * lookup if possible. - */ - dns_rdataset_init(&tmprdataset); - sigrdataset = &tmprdataset; - dboptions |= DNS_DBFIND_PENDINGOK; - } - refind: result = dns_db_find(db, client->query.qname, version, type, - dboptions, client->now, &node, fname, - rdataset, sigrdataset); - /* - * If we have found pending data try to validate it. - * If the data does not validate as secure and we can't - * use the unvalidated data requery the database with - * pending disabled to prevent infinite looping. - */ - if (result != ISC_R_SUCCESS || !DNS_TRUST_PENDING(rdataset->trust)) - goto validation_done; - if (validate(client, db, fname, rdataset, sigrdataset)) - goto validation_done; - if (rdataset->trust != dns_trust_pending_answer || - !PENDINGOK(client->query.dboptions)) { - dns_rdataset_disassociate(rdataset); - if (sigrdataset != NULL && - dns_rdataset_isassociated(sigrdataset)) - dns_rdataset_disassociate(sigrdataset); - if (sigrdataset == &tmprdataset) - sigrdataset = NULL; - dns_db_detachnode(db, &node); - dboptions &= ~DNS_DBFIND_PENDINGOK; - goto refind; - } - validation_done: - if (sigrdataset == &tmprdataset) { - if (dns_rdataset_isassociated(sigrdataset)) - dns_rdataset_disassociate(sigrdataset); - sigrdataset = NULL; - } + client->query.dboptions, client->now, + &node, fname, rdataset, sigrdataset); resume: CTRACE("query_find: resume"); @@ -4432,7 +4419,8 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) * or if the client requested recursion and thus wanted * the complete answer, send an error response. */ - query_error(client, eresult); + INSIST(line >= 0); + query_error(client, eresult, line); } ns_client_detach(&client); } else if (!RECURSING(client)) { @@ -4449,7 +4437,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) * is in the glue sort it to the start of the additional * section. */ - if (client->message->counts[DNS_SECTION_ANSWER] == 0 && + if (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER]) && client->message->rcode == dns_rcode_noerror && (qtype == dns_rdatatype_a || qtype == dns_rdatatype_aaaa)) answer_in_glue(client, qtype); @@ -4458,10 +4446,22 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) client->view->auth_nxdomain == ISC_TRUE) client->message->flags |= DNS_MESSAGEFLAG_AA; + /* + * If the response is somehow unexpected for the client and this + * is a result of recursion, return an error to the caller + * to indicate it may need to be logged. + */ + if (resuming && + (ISC_LIST_EMPTY(client->message->sections[DNS_SECTION_ANSWER]) || + client->message->rcode != dns_rcode_noerror)) + eresult = ISC_R_FAILURE; + query_send(client); ns_client_detach(&client); } CTRACE("query_find: done"); + + return (eresult); } static inline void @@ -4488,6 +4488,48 @@ log_query(ns_client_t *client) { (client->opt != NULL) ? "E" : ""); } +static inline void +log_queryerror(ns_client_t *client, isc_result_t result, int line, int level) { + char namebuf[DNS_NAME_FORMATSIZE]; + char typename[DNS_RDATATYPE_FORMATSIZE]; + char classname[DNS_RDATACLASS_FORMATSIZE]; + const char *namep, *typep, *classp, *sep1, *sep2; + dns_rdataset_t *rdataset; + + if (!isc_log_wouldlog(ns_g_lctx, level)) + return; + + namep = typep = classp = sep1 = sep2 = ""; + + /* + * Query errors can happen for various reasons. In some cases we cannot + * even assume the query contains a valid question section, so we should + * expect exceptional cases. + */ + if (client->query.origqname != NULL) { + dns_name_format(client->query.origqname, namebuf, + sizeof(namebuf)); + namep = namebuf; + sep1 = " for "; + + rdataset = ISC_LIST_HEAD(client->query.origqname->list); + if (rdataset != NULL) { + dns_rdataclass_format(rdataset->rdclass, classname, + sizeof(classname)); + classp = classname; + dns_rdatatype_format(rdataset->type, typename, + sizeof(typename)); + typep = typename; + sep2 = "/"; + } + } + + ns_client_log(client, NS_LOGCATEGORY_QUERY_EERRORS, NS_LOGMODULE_QUERY, + level, "query failed (%s)%s%s%s%s%s%s at %s:%d", + isc_result_totext(result), sep1, namep, sep2, + classp, sep2, typep, __FILE__, line); +} + void ns_query_start(ns_client_t *client) { isc_result_t result; @@ -4548,7 +4590,7 @@ ns_query_start(ns_client_t *client) { */ result = dns_message_firstname(message, DNS_SECTION_QUESTION); if (result != ISC_R_SUCCESS) { - query_error(client, result); + query_error(client, result, __LINE__); return; } dns_message_currentname(message, DNS_SECTION_QUESTION, @@ -4561,9 +4603,9 @@ ns_query_start(ns_client_t *client) { * There's more than one QNAME in the question * section. */ - query_error(client, DNS_R_FORMERR); + query_error(client, DNS_R_FORMERR, __LINE__); } else - query_error(client, result); + query_error(client, result, __LINE__); return; } @@ -4574,7 +4616,7 @@ ns_query_start(ns_client_t *client) { * Check for multiple question queries, since edns1 is dead. */ if (message->counts[DNS_SECTION_QUESTION] > 1) { - query_error(client, DNS_R_FORMERR); + query_error(client, DNS_R_FORMERR, __LINE__); return; } @@ -4594,7 +4636,7 @@ ns_query_start(ns_client_t *client) { return; case dns_rdatatype_maila: case dns_rdatatype_mailb: - query_error(client, DNS_R_NOTIMP); + query_error(client, DNS_R_NOTIMP, __LINE__); return; case dns_rdatatype_tkey: result = dns_tkey_processquery(client->message, @@ -4603,10 +4645,10 @@ ns_query_start(ns_client_t *client) { if (result == ISC_R_SUCCESS) query_send(client); else - query_error(client, result); + query_error(client, result, __LINE__); return; default: /* TSIG, etc. */ - query_error(client, DNS_R_FORMERR); + query_error(client, DNS_R_FORMERR, __LINE__); return; } } @@ -4667,5 +4709,5 @@ ns_query_start(ns_client_t *client) { qclient = NULL; ns_client_attach(client, &qclient); - query_find(qclient, NULL, qtype); + (void)query_find(qclient, NULL, qtype); } |