Some TCP error conditions are handled incorrectly
In lib/dns/dispatch.c:tcp_recv()
, the default
case in the second
switch
statement is overly broad and causes some result codes provided
by netmgr to be incorrectly overridden with ISC_R_SHUTTINGDOWN
. This
enables e.g. shutting down resolving ...
messages to be logged in the
middle of normal resolver operation (which is confusing as such messages
are only supposed to be logged when the netmgr is being shut down
entirely) and causes some error conditions to be mishandled by resolver
code (resquery_response()
).
As an example, consider what happens if tcp_recv()
gets invoked with
the ISC_R_EOF
result code:
-
The first
switch
statement callstcp_recv_shutdown()
to prepare the dispatch for cleanup. -
The
result
variable remains untouched. -
The second
switch
statement matchesISC_R_EOF
to thedefault
case. -
tcp_recv_cancelall()
gets called, which causes the higher-level dispatch callback (resquery_response()
) to be invoked with theISC_R_SHUTTINGDOWN
result code. -
Instead of returning early (which should happen for
ISC_R_EOF
),resquery_response()
continues to process theISC_R_SHUTTINGDOWN
result code, eventually reachingrctx_dispfail()
and marking the server as bad.
At least two other error conditions (ISC_R_CANCELED
and
ISC_R_CONNECTIONRESET
) can be similarly overridden with
ISC_R_SHUTTINGDOWN
.
AIUI, the original netmgr error code should be propagated to the resolver code so that it can be handled accordingly. Perhaps something like this could work?
diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c
index c13d91d0642..81e2f0658d7 100644
--- a/lib/dns/dispatch.c
+++ b/lib/dns/dispatch.c
@@ -713,13 +713,14 @@ tcp_recv_done(dns_dispentry_t *resp, isc_result_t eresult,
}
static void
-tcp_recv_cancelall(dns_displist_t *resps, isc_region_t *region) {
+tcp_recv_cancelall(dns_displist_t *resps, isc_region_t *region,
+ isc_result_t result) {
dns_dispentry_t *resp = NULL, *next = NULL;
for (resp = ISC_LIST_HEAD(*resps); resp != NULL; resp = next) {
next = ISC_LIST_NEXT(resp, rlink);
ISC_LIST_UNLINK(*resps, resp, rlink);
- resp->response(ISC_R_SHUTTINGDOWN, region, resp->arg);
+ resp->response(result, region, resp->arg);
dispentry_detach(&resp);
}
}
@@ -831,7 +832,7 @@ tcp_recv(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
break;
default:
/* We're being shut down; cancel all outstanding resps. */
- tcp_recv_cancelall(&resps, region);
+ tcp_recv_cancelall(&resps, region, result);
}
dns_dispatch_detach(&disp);