summaryrefslogtreecommitdiffstats
path: root/contrib/bind9/lib/dns/resolver.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind9/lib/dns/resolver.c')
-rw-r--r--contrib/bind9/lib/dns/resolver.c224
1 files changed, 167 insertions, 57 deletions
diff --git a/contrib/bind9/lib/dns/resolver.c b/contrib/bind9/lib/dns/resolver.c
index 717c932..3084dd8 100644
--- a/contrib/bind9/lib/dns/resolver.c
+++ b/contrib/bind9/lib/dns/resolver.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2012 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: resolver.c,v 1.428.6.7 2011-06-08 23:02:43 each Exp $ */
+/* $Id$ */
/*! \file */
@@ -216,6 +216,8 @@ struct fetchctx {
ISC_LIST(dns_validator_t) validators;
dns_db_t * cache;
dns_adb_t * adb;
+ isc_boolean_t ns_ttl_ok;
+ isc_uint32_t ns_ttl;
/*%
* The number of events we're waiting for.
@@ -453,7 +455,7 @@ static isc_result_t ncache_adderesult(dns_message_t *message,
dns_rdataset_t *ardataset,
isc_result_t *eresultp);
static void validated(isc_task_t *task, isc_event_t *event);
-static void maybe_destroy(fetchctx_t *fctx);
+static isc_boolean_t maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked);
static void add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
isc_result_t reason, badnstype_t badtype);
@@ -746,8 +748,11 @@ resquery_destroy(resquery_t **queryp) {
INSIST(query->tcpsocket == NULL);
query->fctx->nqueries--;
- if (SHUTTINGDOWN(query->fctx))
- maybe_destroy(query->fctx); /* Locks bucket. */
+ if (SHUTTINGDOWN(query->fctx)) {
+ dns_resolver_t *res = query->fctx->res;
+ if (maybe_destroy(query->fctx, ISC_FALSE))
+ empty_bucket(res);
+ }
query->magic = 0;
isc_mem_put(query->mctx, query, sizeof(*query));
*queryp = NULL;
@@ -1562,9 +1567,11 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
dns_dispatch_detach(&query->dispatch);
cleanup_query:
- query->magic = 0;
- isc_mem_put(res->buckets[fctx->bucketnum].mctx,
- query, sizeof(*query));
+ if (query->connects == 0) {
+ query->magic = 0;
+ isc_mem_put(res->buckets[fctx->bucketnum].mctx,
+ query, sizeof(*query));
+ }
stop_idle_timer:
RUNTIME_CHECK(fctx_stopidletimer(fctx) == ISC_R_SUCCESS);
@@ -1682,6 +1689,7 @@ resquery_send(resquery_t *query) {
dns_compress_t cctx;
isc_boolean_t cleanup_cctx = ISC_FALSE;
isc_boolean_t secure_domain;
+ isc_boolean_t connecting = ISC_FALSE;
fctx = query->fctx;
QTRACE("send");
@@ -1972,6 +1980,7 @@ resquery_send(resquery_t *query) {
query);
if (result != ISC_R_SUCCESS)
goto cleanup_message;
+ connecting = ISC_TRUE;
query->connects++;
}
}
@@ -1983,8 +1992,19 @@ resquery_send(resquery_t *query) {
*/
result = isc_socket_sendto(socket, &r, task, resquery_senddone,
query, address, NULL);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS) {
+ if (connecting) {
+ /*
+ * This query is still connecting.
+ * Mark it as canceled so that it will just be
+ * cleaned up when the connected event is received.
+ * Keep fctx around until the event is processed.
+ */
+ query->fctx->nqueries++;
+ query->attributes |= RESQUERY_ATTR_CANCELED;
+ }
goto cleanup_message;
+ }
query->sends++;
@@ -2146,6 +2166,7 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
isc_boolean_t want_try = ISC_FALSE;
isc_boolean_t want_done = ISC_FALSE;
isc_boolean_t bucket_empty = ISC_FALSE;
+ isc_boolean_t destroy = ISC_FALSE;
unsigned int bucketnum;
find = event->ev_sender;
@@ -2157,6 +2178,9 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
FCTXTRACE("finddone");
+ bucketnum = fctx->bucketnum;
+ LOCK(&res->buckets[bucketnum].lock);
+
INSIST(fctx->pending > 0);
fctx->pending--;
@@ -2181,17 +2205,17 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
}
} else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 &&
fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) {
- bucketnum = fctx->bucketnum;
- LOCK(&res->buckets[bucketnum].lock);
/*
* Note that we had to wait until we had the lock before
* looking at fctx->references.
*/
if (fctx->references == 0)
- bucket_empty = fctx_destroy(fctx);
- UNLOCK(&res->buckets[bucketnum].lock);
+ destroy = ISC_TRUE;
}
+ UNLOCK(&res->buckets[bucketnum].lock);
+ if (destroy)
+ bucket_empty = fctx_destroy(fctx);
isc_event_free(&event);
dns_adb_destroyfind(&find);
@@ -3421,6 +3445,20 @@ fctx_join(fetchctx_t *fctx, isc_task_t *task, isc_sockaddr_t *client,
return (ISC_R_SUCCESS);
}
+static inline void
+log_ns_ttl(fetchctx_t *fctx, const char *where) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char domainbuf[DNS_NAME_FORMATSIZE];
+
+ dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
+ dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf));
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(10),
+ "log_ns_ttl: fctx %p: %s: %s (in '%s'?): %u %u",
+ fctx, where, namebuf, domainbuf,
+ fctx->ns_ttl_ok, fctx->ns_ttl);
+}
+
static isc_result_t
fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
dns_name_t *domain, dns_rdataset_t *nameservers,
@@ -3514,6 +3552,8 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
fctx->timeout = ISC_FALSE;
fctx->addrinfo = NULL;
fctx->client = NULL;
+ fctx->ns_ttl = 0;
+ fctx->ns_ttl_ok = ISC_FALSE;
dns_name_init(&fctx->nsname, NULL);
fctx->nsfetch = NULL;
@@ -3563,6 +3603,8 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
dns_rdataset_disassociate(&fctx->nameservers);
goto cleanup_name;
}
+ fctx->ns_ttl = fctx->nameservers.ttl;
+ fctx->ns_ttl_ok = ISC_TRUE;
} else {
/*
* We're in forward-only mode. Set the query domain.
@@ -3580,8 +3622,12 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
if (result != ISC_R_SUCCESS)
goto cleanup_name;
dns_rdataset_clone(nameservers, &fctx->nameservers);
+ fctx->ns_ttl = fctx->nameservers.ttl;
+ fctx->ns_ttl_ok = ISC_TRUE;
}
+ log_ns_ttl(fctx, "fctx_create");
+
INSIST(dns_name_issubdomain(&fctx->name, &fctx->domain));
fctx->qmessage = NULL;
@@ -3874,14 +3920,16 @@ clone_results(fetchctx_t *fctx) {
/*
* Destroy '*fctx' if it is ready to be destroyed (i.e., if it has
- * no references and is no longer waiting for any events). If this
- * was the last fctx in the resolver, destroy the resolver.
+ * no references and is no longer waiting for any events).
*
* Requires:
* '*fctx' is shutting down.
+ *
+ * Returns:
+ * true if the resolver is exiting and this is the last fctx in the bucket.
*/
-static void
-maybe_destroy(fetchctx_t *fctx) {
+static isc_boolean_t
+maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked) {
unsigned int bucketnum;
isc_boolean_t bucket_empty = ISC_FALSE;
dns_resolver_t *res = fctx->res;
@@ -3889,8 +3937,11 @@ maybe_destroy(fetchctx_t *fctx) {
REQUIRE(SHUTTINGDOWN(fctx));
+ bucketnum = fctx->bucketnum;
+ if (!locked)
+ LOCK(&res->buckets[bucketnum].lock);
if (fctx->pending != 0 || fctx->nqueries != 0)
- return;
+ goto unlock;
for (validator = ISC_LIST_HEAD(fctx->validators);
validator != NULL; validator = next_validator) {
@@ -3898,14 +3949,12 @@ maybe_destroy(fetchctx_t *fctx) {
dns_validator_cancel(validator);
}
- bucketnum = fctx->bucketnum;
- LOCK(&res->buckets[bucketnum].lock);
if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators))
bucket_empty = fctx_destroy(fctx);
- UNLOCK(&res->buckets[bucketnum].lock);
-
- if (bucket_empty)
- empty_bucket(res);
+ unlock:
+ if (!locked)
+ UNLOCK(&res->buckets[bucketnum].lock);
+ return (bucket_empty);
}
/*
@@ -3913,31 +3962,33 @@ maybe_destroy(fetchctx_t *fctx) {
*/
static void
validated(isc_task_t *task, isc_event_t *event) {
- isc_result_t result = ISC_R_SUCCESS;
- isc_result_t eresult = ISC_R_SUCCESS;
- isc_stdtime_t now;
- fetchctx_t *fctx;
- dns_validatorevent_t *vevent;
- dns_fetchevent_t *hevent;
- dns_rdataset_t *ardataset = NULL;
- dns_rdataset_t *asigrdataset = NULL;
+ dns_adbaddrinfo_t *addrinfo;
dns_dbnode_t *node = NULL;
- isc_boolean_t negative;
- isc_boolean_t chaining;
- isc_boolean_t sentresponse;
- isc_uint32_t ttl;
dns_dbnode_t *nsnode = NULL;
+ dns_fetchevent_t *hevent;
dns_name_t *name;
+ dns_rdataset_t *ardataset = NULL;
+ dns_rdataset_t *asigrdataset = NULL;
dns_rdataset_t *rdataset;
dns_rdataset_t *sigrdataset;
+ dns_resolver_t *res;
dns_valarg_t *valarg;
- dns_adbaddrinfo_t *addrinfo;
+ dns_validatorevent_t *vevent;
+ fetchctx_t *fctx;
+ isc_boolean_t chaining;
+ isc_boolean_t negative;
+ isc_boolean_t sentresponse;
+ isc_result_t eresult = ISC_R_SUCCESS;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_stdtime_t now;
+ isc_uint32_t ttl;
UNUSED(task); /* for now */
REQUIRE(event->ev_type == DNS_EVENT_VALIDATORDONE);
valarg = event->ev_arg;
fctx = valarg->fctx;
+ res = fctx->res;
addrinfo = valarg->addrinfo;
REQUIRE(VALID_FCTX(fctx));
REQUIRE(!ISC_LIST_EMPTY(fctx->validators));
@@ -3947,6 +3998,8 @@ validated(isc_task_t *task, isc_event_t *event) {
FCTXTRACE("received validation completion event");
+ LOCK(&res->buckets[fctx->bucketnum].lock);
+
ISC_LIST_UNLINK(fctx->validators, vevent->validator, link);
fctx->validator = NULL;
@@ -3955,7 +4008,7 @@ validated(isc_task_t *task, isc_event_t *event) {
* destroy the fctx if necessary.
*/
dns_validator_destroy(&vevent->validator);
- isc_mem_put(fctx->res->buckets[fctx->bucketnum].mctx,
+ isc_mem_put(res->buckets[fctx->bucketnum].mctx,
valarg, sizeof(*valarg));
negative = ISC_TF(vevent->rdataset == NULL);
@@ -3968,12 +4021,15 @@ validated(isc_task_t *task, isc_event_t *event) {
* so, destroy the fctx.
*/
if (SHUTTINGDOWN(fctx) && !sentresponse) {
- maybe_destroy(fctx); /* Locks bucket. */
+ isc_uint32_t bucketnum = fctx->bucketnum;
+ isc_boolean_t bucket_empty;
+ bucket_empty = maybe_destroy(fctx, ISC_TRUE);
+ UNLOCK(&res->buckets[bucketnum].lock);
+ if (bucket_empty)
+ empty_bucket(res);
goto cleanup_event;
}
- LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
-
isc_stdtime_get(&now);
/*
@@ -4019,7 +4075,7 @@ validated(isc_task_t *task, isc_event_t *event) {
if (vevent->result != ISC_R_SUCCESS) {
FCTXTRACE("validation failed");
- inc_stats(fctx->res, dns_resstatscounter_valfail);
+ inc_stats(res, dns_resstatscounter_valfail);
fctx->valfail++;
fctx->vresult = vevent->result;
if (fctx->vresult != DNS_R_BROKENCHAIN) {
@@ -4068,7 +4124,7 @@ validated(isc_task_t *task, isc_event_t *event) {
result = fctx->vresult;
add_bad(fctx, addrinfo, result, badns_validation);
isc_event_free(&event);
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&res->buckets[fctx->bucketnum].lock);
INSIST(fctx->validator == NULL);
fctx->validator = ISC_LIST_HEAD(fctx->validators);
if (fctx->validator != NULL)
@@ -4087,8 +4143,7 @@ validated(isc_task_t *task, isc_event_t *event) {
fctx->type == dns_rdatatype_dlv ||
fctx->type == dns_rdatatype_ds) &&
tresult == ISC_R_SUCCESS)
- dns_resolver_addbadcache(fctx->res,
- &fctx->name,
+ dns_resolver_addbadcache(res, &fctx->name,
fctx->type, &expire);
fctx_done(fctx, result, __LINE__); /* Locks bucket. */
} else
@@ -4101,7 +4156,7 @@ validated(isc_task_t *task, isc_event_t *event) {
dns_rdatatype_t covers;
FCTXTRACE("nonexistence validation OK");
- inc_stats(fctx->res, dns_resstatscounter_valnegsuccess);
+ inc_stats(res, dns_resstatscounter_valnegsuccess);
if (fctx->rmessage->rcode == dns_rcode_nxdomain)
covers = dns_rdatatype_any;
@@ -4118,10 +4173,9 @@ validated(isc_task_t *task, isc_event_t *event) {
* to zero to facilitate locating the containing zone of
* a arbitrary zone.
*/
- ttl = fctx->res->view->maxncachettl;
+ ttl = res->view->maxncachettl;
if (fctx->type == dns_rdatatype_soa &&
- covers == dns_rdatatype_any &&
- fctx->res->zero_no_soa_ttl)
+ covers == dns_rdatatype_any && res->zero_no_soa_ttl)
ttl = 0;
result = ncache_adderesult(fctx->rmessage, fctx->cache, node,
@@ -4131,7 +4185,7 @@ validated(isc_task_t *task, isc_event_t *event) {
goto noanswer_response;
goto answer_response;
} else
- inc_stats(fctx->res, dns_resstatscounter_valsuccess);
+ inc_stats(res, dns_resstatscounter_valsuccess);
FCTXTRACE("validation OK");
@@ -4179,14 +4233,17 @@ validated(isc_task_t *task, isc_event_t *event) {
}
if (sentresponse) {
+ isc_boolean_t bucket_empty = ISC_FALSE;
/*
* If we only deferred the destroy because we wanted to cache
* the data, destroy now.
*/
dns_db_detachnode(fctx->cache, &node);
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
if (SHUTTINGDOWN(fctx))
- maybe_destroy(fctx); /* Locks bucket. */
+ bucket_empty = maybe_destroy(fctx, ISC_TRUE);
+ UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ if (bucket_empty)
+ empty_bucket(res);
goto cleanup_event;
}
@@ -4201,7 +4258,7 @@ validated(isc_task_t *task, isc_event_t *event) {
* be validated.
*/
dns_db_detachnode(fctx->cache, &node);
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&res->buckets[fctx->bucketnum].lock);
dns_validator_send(ISC_LIST_HEAD(fctx->validators));
goto cleanup_event;
}
@@ -4276,8 +4333,7 @@ validated(isc_task_t *task, isc_event_t *event) {
if (node != NULL)
dns_db_detachnode(fctx->cache, &node);
- UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
-
+ UNLOCK(&res->buckets[fctx->bucketnum].lock);
fctx_done(fctx, result, __LINE__); /* Locks bucket. */
cleanup_event:
@@ -5248,6 +5304,26 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name,
return (ISC_TRUE);
}
+static void
+trim_ns_ttl(fetchctx_t *fctx, dns_name_t *name, dns_rdataset_t *rdataset) {
+ char ns_namebuf[DNS_NAME_FORMATSIZE];
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char tbuf[DNS_RDATATYPE_FORMATSIZE];
+
+ if (fctx->ns_ttl_ok && rdataset->ttl > fctx->ns_ttl) {
+ dns_name_format(name, ns_namebuf, sizeof(ns_namebuf));
+ dns_name_format(&fctx->name, namebuf, sizeof(namebuf));
+ dns_rdatatype_format(fctx->type, tbuf, sizeof(tbuf));
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(10),
+ "fctx %p: trimming ttl of %s/NS for %s/%s: "
+ "%u -> %u", fctx, ns_namebuf, namebuf, tbuf,
+ rdataset->ttl, fctx->ns_ttl);
+ rdataset->ttl = fctx->ns_ttl;
+ }
+}
+
/*
* Handle a no-answer response (NXDOMAIN, NXRRSET, or referral).
* If look_in_options has LOOK_FOR_NS_IN_ANSWER then we look in the answer
@@ -5418,6 +5494,9 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
if (aa)
rdataset->trust =
dns_trust_authauthority;
+ else if (ISFORWARDER(fctx->addrinfo))
+ rdataset->trust =
+ dns_trust_answer;
else
rdataset->trust =
dns_trust_additional;
@@ -5431,6 +5510,12 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
return (result);
}
+ log_ns_ttl(fctx, "noanswer_response");
+
+ if (ns_rdataset != NULL && dns_name_equal(&fctx->domain, ns_name) &&
+ !dns_name_equal(ns_name, dns_rootname))
+ trim_ns_ttl(fctx, ns_name, ns_rdataset);
+
/*
* A negative response has a SOA record (Type 2)
* and a optional NS RRset (Type 1) or it has neither
@@ -5471,6 +5556,9 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
if (aa)
rdataset->trust =
dns_trust_authauthority;
+ else if (ISFORWARDER(fctx->addrinfo))
+ rdataset->trust =
+ dns_trust_answer;
else
rdataset->trust =
dns_trust_additional;
@@ -5512,6 +5600,9 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
if (aa)
rdataset->trust =
dns_trust_authauthority;
+ else if (ISFORWARDER(fctx->addrinfo))
+ rdataset->trust =
+ dns_trust_answer;
else
rdataset->trust =
dns_trust_additional;
@@ -5643,6 +5734,8 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
if (result != ISC_R_SUCCESS)
return (result);
fctx->attributes |= FCTX_ATTR_WANTCACHE;
+ fctx->ns_ttl_ok = ISC_FALSE;
+ log_ns_ttl(fctx, "DELEGATION");
return (DNS_R_DELEGATION);
}
@@ -5663,8 +5756,8 @@ static isc_result_t
answer_response(fetchctx_t *fctx) {
isc_result_t result;
dns_message_t *message;
- dns_name_t *name, *qname, tname;
- dns_rdataset_t *rdataset;
+ dns_name_t *name, *qname, tname, *ns_name;
+ dns_rdataset_t *rdataset, *ns_rdataset;
isc_boolean_t done, external, chaining, aa, found, want_chaining;
isc_boolean_t have_answer, found_cname, found_type, wanted_chaining;
unsigned int aflag;
@@ -6064,6 +6157,8 @@ answer_response(fetchctx_t *fctx) {
* in this section, and we expect that it is not external.
*/
done = ISC_FALSE;
+ ns_name = NULL;
+ ns_rdataset = NULL;
result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
while (!done && result == ISC_R_SUCCESS) {
name = NULL;
@@ -6091,6 +6186,10 @@ answer_response(fetchctx_t *fctx) {
rdataset->trust =
dns_trust_additional;
+ if (rdataset->type == dns_rdatatype_ns) {
+ ns_name = name;
+ ns_rdataset = rdataset;
+ }
/*
* Mark any additional data related
* to this rdataset.
@@ -6108,6 +6207,12 @@ answer_response(fetchctx_t *fctx) {
if (result == ISC_R_NOMORE)
result = ISC_R_SUCCESS;
+ log_ns_ttl(fctx, "answer_response");
+
+ if (ns_rdataset != NULL && dns_name_equal(&fctx->domain, ns_name) &&
+ !dns_name_equal(ns_name, dns_rootname))
+ trim_ns_ttl(fctx, ns_name, ns_rdataset);
+
return (result);
}
@@ -6179,6 +6284,9 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) {
if (dns_rdataset_isassociated(&fctx->nameservers))
dns_rdataset_disassociate(&fctx->nameservers);
dns_rdataset_clone(fevent->rdataset, &fctx->nameservers);
+ fctx->ns_ttl = fctx->nameservers.ttl;
+ fctx->ns_ttl_ok = ISC_TRUE;
+ log_ns_ttl(fctx, "resume_dslookup");
dns_name_free(&fctx->domain,
fctx->res->buckets[bucketnum].mctx);
dns_name_init(&fctx->domain, NULL);
@@ -7112,6 +7220,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
return;
}
+ fctx->ns_ttl = fctx->nameservers.ttl;
+ fctx->ns_ttl_ok = ISC_TRUE;
fctx_cancelqueries(fctx, ISC_TRUE);
fctx_cleanupfinds(fctx);
fctx_cleanupaltfinds(fctx);
OpenPOWER on IntegriCloud