summaryrefslogtreecommitdiff
path: root/usr.sbin/bind/lib/dns/resolver.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bind/lib/dns/resolver.c')
-rw-r--r--usr.sbin/bind/lib/dns/resolver.c163
1 files changed, 130 insertions, 33 deletions
diff --git a/usr.sbin/bind/lib/dns/resolver.c b/usr.sbin/bind/lib/dns/resolver.c
index c72f269c1b8..c199c12a542 100644
--- a/usr.sbin/bind/lib/dns/resolver.c
+++ b/usr.sbin/bind/lib/dns/resolver.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $ISC: resolver.c,v 1.218.2.18.4.43 2004/08/28 06:25:19 marka Exp $ */
+/* $ISC: resolver.c,v 1.218.2.18.4.51 2005/02/08 23:59:44 marka Exp $ */
#include <config.h>
@@ -762,6 +762,9 @@ static void
resquery_senddone(isc_task_t *task, isc_event_t *event) {
isc_socketevent_t *sevent = (isc_socketevent_t *)event;
resquery_t *query = event->ev_arg;
+ isc_boolean_t retry = ISC_FALSE;
+ isc_result_t result;
+ fetchctx_t *fctx;
REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
@@ -780,6 +783,7 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) {
INSIST(RESQUERY_SENDING(query));
query->sends--;
+ fctx = query->fctx;
if (RESQUERY_CANCELED(query)) {
if (query->sends == 0) {
@@ -791,13 +795,43 @@ resquery_senddone(isc_task_t *task, isc_event_t *event) {
isc_socket_detach(&query->tcpsocket);
resquery_destroy(&query);
}
- } else if (sevent->result == ISC_R_HOSTUNREACH ||
- sevent->result == ISC_R_NETUNREACH)
- fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
- else if (sevent->result != ISC_R_SUCCESS)
- fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
+ } else
+ switch (sevent->result) {
+ case ISC_R_SUCCESS:
+ break;
+
+ case ISC_R_HOSTUNREACH:
+ case ISC_R_NETUNREACH:
+ case ISC_R_NOPERM:
+ case ISC_R_ADDRNOTAVAIL:
+ case ISC_R_CONNREFUSED:
+
+ /*
+ * No route to remote.
+ */
+ fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
+ retry = ISC_TRUE;
+ break;
+
+ default:
+ fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
+ break;
+ }
isc_event_free(&event);
+
+ if (retry) {
+ /*
+ * Behave as if the idle timer has expired. For TCP
+ * this may not actually reflect the latest timer.
+ */
+ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+ result = fctx_stopidletimer(fctx);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ else
+ fctx_try(fctx);
+ }
}
static inline isc_result_t
@@ -1314,7 +1348,10 @@ static void
resquery_connected(isc_task_t *task, isc_event_t *event) {
isc_socketevent_t *sevent = (isc_socketevent_t *)event;
resquery_t *query = event->ev_arg;
+ isc_boolean_t retry = ISC_FALSE;
isc_result_t result;
+ unsigned int attrs;
+ fetchctx_t *fctx;
REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
REQUIRE(VALID_QUERY(query));
@@ -1332,6 +1369,7 @@ resquery_connected(isc_task_t *task, isc_event_t *event) {
*/
query->connects--;
+ fctx = query->fctx;
if (RESQUERY_CANCELED(query)) {
/*
@@ -1341,9 +1379,8 @@ resquery_connected(isc_task_t *task, isc_event_t *event) {
isc_socket_detach(&query->tcpsocket);
resquery_destroy(&query);
} else {
- if (sevent->result == ISC_R_SUCCESS) {
- unsigned int attrs;
-
+ switch (sevent->result) {
+ case ISC_R_SUCCESS:
/*
* We are connected. Create a dispatcher and
* send the query.
@@ -1376,26 +1413,48 @@ resquery_connected(isc_task_t *task, isc_event_t *event) {
result = resquery_send(query);
if (result != ISC_R_SUCCESS) {
- fetchctx_t *fctx = query->fctx;
fctx_cancelquery(&query, NULL, NULL,
ISC_FALSE);
fctx_done(fctx, result);
}
- } else if (sevent->result == ISC_R_HOSTUNREACH ||
- sevent->result == ISC_R_NETUNREACH) {
+ break;
+
+ case ISC_R_NETUNREACH:
+ case ISC_R_HOSTUNREACH:
+ case ISC_R_CONNREFUSED:
+ case ISC_R_NOPERM:
+ case ISC_R_ADDRNOTAVAIL:
+ /*
+ * No route to remote.
+ */
isc_socket_detach(&query->tcpsocket);
fctx_cancelquery(&query, NULL, NULL, ISC_TRUE);
- } else {
+ retry = ISC_TRUE;
+ break;
+
+ default:
isc_socket_detach(&query->tcpsocket);
fctx_cancelquery(&query, NULL, NULL, ISC_FALSE);
+ break;
}
}
isc_event_free(&event);
+
+ if (retry) {
+ /*
+ * Behave as if the idle timer has expired. For TCP
+ * connections this may not actually reflect the latest timer.
+ */
+ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
+ result = fctx_stopidletimer(fctx);
+ if (result != ISC_R_SUCCESS)
+ fctx_done(fctx, result);
+ else
+ fctx_try(fctx);
+ }
}
-
-
static void
fctx_finddone(isc_task_t *task, isc_event_t *event) {
fetchctx_t *fctx;
@@ -3526,6 +3585,14 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, isc_stdtime_t now) {
fctx->validators,
validator, link);
}
+ } else if (CHAINING(rdataset)) {
+ if (rdataset->type == dns_rdatatype_cname)
+ eresult = DNS_R_CNAME;
+ else {
+ INSIST(rdataset->type ==
+ dns_rdatatype_dname);
+ eresult = DNS_R_DNAME;
+ }
}
} else if (!EXTERNAL(rdataset)) {
/*
@@ -4134,7 +4201,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
dns_message_currentname(message, section, &name);
if (dns_name_issubdomain(name, &fctx->domain)) {
/*
- * Look for NS RRset first.
+ * Look for NS/SOA RRsets first.
*/
for (rdataset = ISC_LIST_HEAD(name->list);
rdataset != NULL;
@@ -4148,7 +4215,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
return (DNS_R_FORMERR);
if (type == dns_rdatatype_ns) {
/*
- * NS or SIG NS.
+ * NS or RRSIG NS.
*
* Only one set of NS RRs is allowed.
*/
@@ -4166,17 +4233,9 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
DNS_RDATASETATTR_CACHE;
rdataset->trust = dns_trust_glue;
}
- }
- for (rdataset = ISC_LIST_HEAD(name->list);
- rdataset != NULL;
- rdataset = ISC_LIST_NEXT(rdataset, link)) {
- type = rdataset->type;
- if (type == dns_rdatatype_rrsig)
- type = rdataset->covers;
- if (type == dns_rdatatype_soa ||
- type == dns_rdatatype_nsec) {
+ if (type == dns_rdatatype_soa) {
/*
- * SOA, RRSIG SOA, NSEC, or RRSIG NSEC.
+ * SOA, or RRSIG SOA.
*
* Only one SOA is allowed.
*/
@@ -4187,8 +4246,38 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
return (DNS_R_FORMERR);
soa_name = name;
}
- if (ns_name == NULL) {
- negative_response = ISC_TRUE;
+ name->attributes |=
+ DNS_NAMEATTR_NCACHE;
+ rdataset->attributes |=
+ DNS_RDATASETATTR_NCACHE;
+ if (aa)
+ rdataset->trust =
+ dns_trust_authauthority;
+ else
+ rdataset->trust =
+ dns_trust_additional;
+ }
+ }
+ /*
+ * A negative response has a SOA record (Type 2)
+ * and a optional NS RRset (Type 1) or it has neither
+ * a SOA or a NS RRset (Type 3, handled above) or
+ * rcode is NXDOMAIN (handled above) in which case
+ * the NS RRset is allowed (Type 4).
+ */
+ if (soa_name != NULL)
+ negative_response = ISC_TRUE;
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link)) {
+ type = rdataset->type;
+ if (type == dns_rdatatype_rrsig)
+ type = rdataset->covers;
+ if (type == dns_rdatatype_nsec) {
+ /*
+ * NSEC or RRSIG NSEC.
+ */
+ if (negative_response) {
name->attributes |=
DNS_NAMEATTR_NCACHE;
rdataset->attributes |=
@@ -4217,7 +4306,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
* this is a referral, and there
* should only be one DS.
*/
- if (negative_response)
+ if (ns_name == NULL)
return (DNS_R_FORMERR);
if (rdataset->type ==
dns_rdatatype_ds) {
@@ -5236,10 +5325,15 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
domainbuf, namebuf, typebuf, classbuf, addrbuf);
}
- if ((fctx->res->options | DNS_RESOLVER_CHECKNAMES) != 0)
+ if ((fctx->res->options & DNS_RESOLVER_CHECKNAMES) != 0)
checknames(message);
/*
+ * Clear cache bits.
+ */
+ fctx->attributes &= ~(FCTX_ATTR_WANTNCACHE | FCTX_ATTR_WANTCACHE);
+
+ /*
* Did we get any answers?
*/
if (message->counts[DNS_SECTION_ANSWER] > 0 &&
@@ -5387,13 +5481,16 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
return;
}
findoptions = 0;
+ if (dns_rdatatype_atparent(fctx->type))
+ findoptions |= DNS_DBFIND_NOEXACT;
if ((options & DNS_FETCHOPT_UNSHARED) == 0)
name = &fctx->name;
else
name = &fctx->domain;
result = dns_view_findzonecut(fctx->res->view,
name, fname,
- now, 0, ISC_TRUE,
+ now, findoptions,
+ ISC_TRUE,
&fctx->nameservers,
NULL);
if (result != ISC_R_SUCCESS) {