diff --git a/bin/tests/system/resolver/tests.sh b/bin/tests/system/resolver/tests.sh index ab94c17c10..c2c2fd4d6f 100755 --- a/bin/tests/system/resolver/tests.sh +++ b/bin/tests/system/resolver/tests.sh @@ -53,16 +53,14 @@ grep -F "no servers could be reached" dig.out.ns1.test${n} >/dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) -# 'resolver-query-timeout' is set to 5 seconds in ns1, which is lower than the -# current single query timeout value MAX_SINGLE_QUERY_TIMEOUT of 9 seconds, so -# the "hung fetch" timer should kick in, interrupt the non-responsive query and -# send a SERVFAIL answer. +# 'resolver-query-timeout' is set to 5 seconds in ns1, so named should +# interrupt the non-responsive query and send a SERVFAIL answer before dig's +# own timeout fires, which is set to 7 seconds. n=$((n + 1)) echo_i "checking no response handling with a longer than resolver-query-timeout timeout ($n)" ret=0 dig_with_opts +tcp +tries=1 +timeout=7 noresponse.example.net @10.53.0.1 a >dig.out.ns1.test${n} || ret=1 grep -F "status: SERVFAIL" dig.out.ns1.test${n} >/dev/null || ret=1 -grep -F "EDE: 22 (No Reachable Authority)" dig.out.ns1.test${n} >/dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 53c8b4b8a4..12f3d9c5a2 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -1871,18 +1871,17 @@ tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) { } } - if (ISC_LIST_EMPTY(disp->active)) { + /* Take the oldest active response. */ + resp = ISC_LIST_HEAD(disp->active); + if (resp == NULL) { /* All responses have been canceled */ disp->state = DNS_DISPATCHSTATE_CANCELED; } else if (eresult == ISC_R_SUCCESS) { disp->state = DNS_DISPATCHSTATE_CONNECTED; isc_nmhandle_attach(handle, &disp->handle); - if (resp != NULL) { - isc_nmhandle_cleartimeout(disp->handle); - if (resp->timeout != 0) { - isc_nmhandle_settimeout(disp->handle, - resp->timeout); - } + isc_nmhandle_cleartimeout(disp->handle); + if (resp->timeout != 0) { + isc_nmhandle_settimeout(disp->handle, resp->timeout); } tcp_startrecv(disp, resp); } else { diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 746fe6d947..80b6cbe388 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -360,7 +360,6 @@ struct fetchctx { atomic_uint_fast32_t attributes; isc_timer_t *timer; isc_time_t expires; - isc_time_t next_timeout; isc_interval_t interval; dns_message_t *qmessage; ISC_LIST(resquery_t) queries; @@ -1875,7 +1874,6 @@ fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { seconds = us / US_PER_SEC; us -= seconds * US_PER_SEC; isc_interval_set(&fctx->interval, seconds, us * NS_PER_US); - isc_time_nowplusinterval(&fctx->next_timeout, &fctx->interval); } static isc_result_t @@ -1911,6 +1909,66 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, } } + /* + * Maybe apply DNS64 mappings to IPv4 addresses. + */ + sockaddr = addrinfo->sockaddr; + dns64 = ISC_LIST_HEAD(fctx->res->view->dns64); + if (isc_sockaddr_pf(&sockaddr) == AF_INET && + fctx->res->view->usedns64 && dns64 != NULL) + { + struct in6_addr aaaa; + + result = dns_dns64_aaaafroma( + dns64, NULL, NULL, fctx->res->view->aclenv, 0, + (unsigned char *)&sockaddr.type.sin.sin_addr.s_addr, + aaaa.s6_addr); + if (result == ISC_R_SUCCESS) { + char sockaddrbuf1[ISC_SOCKADDR_FORMATSIZE]; + char sockaddrbuf2[ISC_SOCKADDR_FORMATSIZE]; + + /* format old address */ + isc_sockaddr_format(&sockaddr, sockaddrbuf1, + sizeof(sockaddrbuf1)); + + /* replace address */ + isc_sockaddr_fromin6(&sockaddr, &aaaa, + ntohs(sockaddr.type.sin.sin_port)); + addrinfo->sockaddr = sockaddr; + + /* format new address */ + isc_sockaddr_format(&sockaddr, sockaddrbuf2, + sizeof(sockaddrbuf2)); + isc_log_write(DNS_LOGCATEGORY_RESOLVER, + DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), + "Using DNS64 address %s to talk to %s\n", + sockaddrbuf2, sockaddrbuf1); + } + } + + /* + * Check if the address is in the peers list and has a special + * confguration. + */ + if (res->view->peers != NULL) { + dns_peer_t *peer = NULL; + isc_netaddr_t dstip; + bool usetcp = false; + isc_netaddr_fromsockaddr(&dstip, &sockaddr); + result = dns_peerlist_peerbyaddr(res->view->peers, &dstip, + &peer); + if (result == ISC_R_SUCCESS) { + result = dns_peer_getquerysource(peer, &addr); + if (result == ISC_R_SUCCESS) { + have_addr = true; + } + result = dns_peer_getforcetcp(peer, &usetcp); + if (result == ISC_R_SUCCESS && usetcp) { + options |= DNS_FETCHOPT_TCP; + } + } + } + /* * Allow an additional second for the kernel to resend the SYN * (or SYN without ECN in the case of stupid firewalls blocking @@ -1960,61 +2018,6 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, DNS_MESSAGE_INTENTPARSE, &query->rmessage); query->start = isc_time_now(); - /* - * Maybe apply DNS64 mappings to IPv4 addresses. - */ - sockaddr = addrinfo->sockaddr; - dns64 = ISC_LIST_HEAD(fctx->res->view->dns64); - if (isc_sockaddr_pf(&sockaddr) == AF_INET && - fctx->res->view->usedns64 && dns64 != NULL) - { - struct in6_addr aaaa; - - result = dns_dns64_aaaafroma( - dns64, NULL, NULL, fctx->res->view->aclenv, 0, - (unsigned char *)&sockaddr.type.sin.sin_addr.s_addr, - aaaa.s6_addr); - if (result == ISC_R_SUCCESS) { - char sockaddrbuf1[ISC_SOCKADDR_FORMATSIZE]; - char sockaddrbuf2[ISC_SOCKADDR_FORMATSIZE]; - - /* format old address */ - isc_sockaddr_format(&sockaddr, sockaddrbuf1, - sizeof(sockaddrbuf1)); - - /* replace address */ - isc_sockaddr_fromin6(&sockaddr, &aaaa, - ntohs(sockaddr.type.sin.sin_port)); - addrinfo->sockaddr = sockaddr; - - /* format new address */ - isc_sockaddr_format(&sockaddr, sockaddrbuf2, - sizeof(sockaddrbuf2)); - isc_log_write(DNS_LOGCATEGORY_RESOLVER, - DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), - "Using DNS64 address %s to talk to %s\n", - sockaddrbuf2, sockaddrbuf1); - } - } - if (res->view->peers != NULL) { - dns_peer_t *peer = NULL; - isc_netaddr_t dstip; - bool usetcp = false; - isc_netaddr_fromsockaddr(&dstip, &sockaddr); - result = dns_peerlist_peerbyaddr(res->view->peers, &dstip, - &peer); - if (result == ISC_R_SUCCESS) { - result = dns_peer_getquerysource(peer, &addr); - if (result == ISC_R_SUCCESS) { - have_addr = true; - } - result = dns_peer_getforcetcp(peer, &usetcp); - if (result == ISC_R_SUCCESS && usetcp) { - query->options |= DNS_FETCHOPT_TCP; - } - } - } - /* * If this is a TCP query, then we need to make a socket and * a dispatch for it here. Otherwise we use the resolver's