diff --git a/CHANGES b/CHANGES index 5662dbd7ff..de92dc6647 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4253. [bug] Address fetch context reference count handling error + on socket error. [RT#40945] + 4252. [func] Add support for automating the generation CDS and CDNSKEY rrsets to named and dnssec-signzone. [RT #40424] diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index f73b8d2ad2..25dccd50e8 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -1787,8 +1787,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, } query->dispentry = NULL; - fctx_increference(fctx); - query->fctx = fctx; + query->fctx = fctx; /* reference added by caller */ query->tsig = NULL; query->tsigkey = NULL; ISC_LINK_INIT(query, link); @@ -1842,11 +1841,6 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, if (query->dispatch != NULL) dns_dispatch_detach(&query->dispatch); - LOCK(&res->buckets[fctx->bucketnum].lock); - INSIST(fctx->references > 1); - fctx->references--; - UNLOCK(&res->buckets[fctx->bucketnum].lock); - cleanup_query: if (query->connects == 0) { query->magic = 0; @@ -3661,6 +3655,8 @@ fctx_try(fetchctx_t *fctx, isc_boolean_t retrying, isc_boolean_t badcache) { isc_result_t result; dns_adbaddrinfo_t *addrinfo = NULL; dns_resolver_t *res; + unsigned int bucketnum; + isc_boolean_t bucket_empty; FCTXTRACE("try"); @@ -3733,10 +3729,17 @@ fctx_try(fetchctx_t *fctx, isc_boolean_t retrying, isc_boolean_t badcache) { } } + bucketnum = fctx->bucketnum; + fctx_increference(fctx); result = fctx_query(fctx, addrinfo, fctx->options); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { fctx_done(fctx, result, __LINE__); - else if (retrying) + LOCK(&res->buckets[bucketnum].lock); + bucket_empty = fctx_decreference(fctx); + UNLOCK(&res->buckets[bucketnum].lock); + if (bucket_empty) + empty_bucket(res); + } else if (retrying) inc_stats(res, dns_resstatscounter_retry); } @@ -7612,6 +7615,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) { isc_result_t broken_server; badnstype_t broken_type = badns_response; isc_boolean_t no_response; + unsigned int bucketnum; + dns_resolver_t *res; + isc_boolean_t bucket_empty; #ifdef HAVE_DNSTAP unsigned char zone[DNS_NAME_MAXWIRE]; dns_dtmsgtype_t dtmsgtype; @@ -7628,10 +7634,11 @@ resquery_response(isc_task_t *task, isc_event_t *event) { QTRACE("response"); + res = fctx->res; if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == PF_INET) - inc_stats(fctx->res, dns_resstatscounter_responsev4); + inc_stats(res, dns_resstatscounter_responsev4); else - inc_stats(fctx->res, dns_resstatscounter_responsev6); + inc_stats(res, dns_resstatscounter_responsev6); (void)isc_timer_touch(fctx->timer); @@ -7643,7 +7650,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { finish = NULL; no_response = ISC_FALSE; - if (fctx->res->exiting) { + if (res->exiting) { result = ISC_R_SHUTTINGDOWN; FCTXTRACE("resolver shutting down"); goto done; @@ -7757,7 +7764,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { resend = ISC_TRUE; add_bad_edns(fctx, &query->addrinfo->sockaddr); - inc_stats(fctx->res, + inc_stats(res, dns_resstatscounter_edns0fail); } else { broken_server = result; @@ -7781,8 +7788,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { options |= DNS_FETCHOPT_NOEDNS0; resend = ISC_TRUE; add_bad_edns(fctx, &query->addrinfo->sockaddr); - inc_stats(fctx->res, - dns_resstatscounter_edns0fail); + inc_stats(res, dns_resstatscounter_edns0fail); } else { broken_server = DNS_R_UNEXPECTEDRCODE; keep_trying = ISC_TRUE; @@ -7804,15 +7810,14 @@ resquery_response(isc_task_t *task, isc_event_t *event) { DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_PACKETS, &dns_master_style_comment, - ISC_LOG_DEBUG(10), - fctx->res->mctx); + ISC_LOG_DEBUG(10), res->mctx); #ifdef HAVE_DNSTAP /* * Log the response via dnstap. */ memset(&zr, 0, sizeof(zr)); - result = dns_compress_init(&cctx, -1, fctx->res->mctx); + result = dns_compress_init(&cctx, -1, res->mctx); if (result == ISC_R_SUCCESS) { isc_buffer_init(&zb, zone, sizeof(zone)); dns_compress_setmethods(&cctx, DNS_COMPRESS_NONE); @@ -7827,8 +7832,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { else dtmsgtype = DNS_DTTYPE_RR; - dns_dt_send(fctx->res->view, dtmsgtype, - &query->addrinfo->sockaddr, + dns_dt_send(res->view, dtmsgtype, &query->addrinfo->sockaddr, ISC_TF((query->options & DNS_FETCHOPT_TCP) != 0), &zr, &query->start, NULL, &devent->buffer); #endif /* HAVE_DNSTAP */ @@ -7854,7 +7858,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * If the message is signed, check the signature. If not, this * returns success anyway. */ - result = dns_message_checksig(message, fctx->res->view); + result = dns_message_checksig(message, res->view); if (result != ISC_R_SUCCESS) { FCTXTRACE3("signature check failed", result); goto done; @@ -7890,7 +7894,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), - fctx->res->mctx); + res->mctx); dns_adb_changeflags(fctx->adb, query->addrinfo, DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_NOEDNS0); @@ -7914,8 +7918,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { &query->addrinfo->sockaddr, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, - ISC_LOG_DEBUG(3), - fctx->res->mctx); + ISC_LOG_DEBUG(3), res->mctx); dns_adb_changeflags(fctx->adb, query->addrinfo, DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_NOEDNS0); @@ -7943,7 +7946,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { truncated = ISC_TRUE; if (truncated) { - inc_stats(fctx->res, dns_resstatscounter_truncated); + inc_stats(res, dns_resstatscounter_truncated); if ((options & DNS_FETCHOPT_TCP) != 0) { broken_server = DNS_R_TRUNCATEDTCP; keep_trying = ISC_TRUE; @@ -7972,25 +7975,25 @@ resquery_response(isc_task_t *task, isc_event_t *event) { if (message->rcode != dns_rcode_noerror) { switch (message->rcode) { case dns_rcode_nxdomain: - inc_stats(fctx->res, dns_resstatscounter_nxdomain); + inc_stats(res, dns_resstatscounter_nxdomain); break; case dns_rcode_servfail: - inc_stats(fctx->res, dns_resstatscounter_servfail); + inc_stats(res, dns_resstatscounter_servfail); break; case dns_rcode_formerr: - inc_stats(fctx->res, dns_resstatscounter_formerr); + inc_stats(res, dns_resstatscounter_formerr); break; case dns_rcode_refused: - inc_stats(fctx->res, dns_resstatscounter_refused); + inc_stats(res, dns_resstatscounter_refused); break; case dns_rcode_badvers: - inc_stats(fctx->res, dns_resstatscounter_badvers); + inc_stats(res, dns_resstatscounter_badvers); break; case dns_rcode_badcookie: - inc_stats(fctx->res, dns_resstatscounter_badcookie); + inc_stats(res, dns_resstatscounter_badcookie); break; default: - inc_stats(fctx->res, dns_resstatscounter_othererror); + inc_stats(res, dns_resstatscounter_othererror); break; } } @@ -8039,7 +8042,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * Remember that they may not like EDNS0. */ add_bad_edns(fctx, &query->addrinfo->sockaddr); - inc_stats(fctx->res, dns_resstatscounter_edns0fail); + inc_stats(res, dns_resstatscounter_edns0fail); } else if (message->rcode == dns_rcode_formerr) { if (ISFORWARDER(query->addrinfo)) { /* @@ -8174,13 +8177,13 @@ resquery_response(isc_task_t *task, isc_event_t *event) { /* * Is the server lame? */ - if (fctx->res->lame_ttl != 0 && !ISFORWARDER(query->addrinfo) && + if (res->lame_ttl != 0 && !ISFORWARDER(query->addrinfo) && is_lame(fctx)) { - inc_stats(fctx->res, dns_resstatscounter_lame); + inc_stats(res, dns_resstatscounter_lame); log_lame(fctx, query->addrinfo); result = dns_adb_marklame(fctx->adb, query->addrinfo, &fctx->name, fctx->type, - now + fctx->res->lame_ttl); + now + res->lame_ttl); if (result != ISC_R_SUCCESS) isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR, @@ -8196,7 +8199,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * Enforce delegations only zones like NET and COM. */ if (!ISFORWARDER(query->addrinfo) && - dns_view_isdelegationonly(fctx->res->view, &fctx->domain) && + dns_view_isdelegationonly(res->view, &fctx->domain) && !dns_name_equal(&fctx->domain, &fctx->name) && fix_mustbedelegationornxdomain(message, fctx)) { char namebuf[DNS_NAME_FORMATSIZE]; @@ -8208,7 +8211,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf)); - dns_rdataclass_format(fctx->res->rdclass, classbuf, + dns_rdataclass_format(res->rdclass, classbuf, sizeof(classbuf)); isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf, sizeof(addrbuf)); @@ -8220,7 +8223,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { domainbuf, namebuf, typebuf, classbuf, addrbuf); } - if ((fctx->res->options & DNS_RESOLVER_CHECKNAMES) != 0) + if ((res->options & DNS_RESOLVER_CHECKNAMES) != 0) checknames(message); /* @@ -8462,7 +8465,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { name = &fctx->name; else name = &fctx->domain; - result = dns_view_findzonecut(fctx->res->view, + result = dns_view_findzonecut(res->view, name, fname, now, findoptions, ISC_TRUE, @@ -8513,10 +8516,18 @@ resquery_response(isc_task_t *task, isc_event_t *event) { * Resend (probably with changed options). */ FCTXTRACE("resend"); - inc_stats(fctx->res, dns_resstatscounter_retry); + inc_stats(res, dns_resstatscounter_retry); + bucketnum = fctx->bucketnum; + fctx_increference(fctx); result = fctx_query(fctx, addrinfo, options); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { fctx_done(fctx, result, __LINE__); + LOCK(&res->buckets[bucketnum].lock); + bucket_empty = fctx_decreference(fctx); + UNLOCK(&res->buckets[bucketnum].lock); + if (bucket_empty) + empty_bucket(res); + } } else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) { /* * All has gone well so far, but we are waiting for the @@ -8543,7 +8554,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { FCTXTRACE("suspending DS lookup to find parent's NS records"); - result = dns_resolver_createfetch(fctx->res, &fctx->nsname, + result = dns_resolver_createfetch(res, &fctx->nsname, dns_rdatatype_ns, NULL, NULL, NULL, fctx->options, task,