diff options
Diffstat (limited to 'usr.sbin/bind/lib/dns/resolver.c')
-rw-r--r-- | usr.sbin/bind/lib/dns/resolver.c | 163 |
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) { |