Merge branch '3133-tcp-error-handling-v9_18' into 'v9_18'

correct TCP error handling in dispatch and resolver

See merge request isc-projects/bind9!5857
This commit is contained in:
Ondřej Surý 2022-02-17 15:50:26 +00:00
commit d7bcb0b5b7
4 changed files with 38 additions and 37 deletions

View file

@ -1,3 +1,8 @@
5808. [bug] Certain TCP failures were not caught and handled
correctly by the dispatch manager, causing
connections to time out rather than returning
SERVFAIL. [GL #3133]
5807. [bug] Add a TCP "write" timer, and time out writing
connections after the "tcp-idle-timeout" period
has elapsed. [GL #3132]

View file

@ -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);

View file

@ -1058,7 +1058,7 @@ req_response(isc_result_t result, isc_region_t *region, void *arg) {
req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request,
isc_result_totext(result));
if (result == ISC_R_CANCELED || result == ISC_R_EOF) {
if (result == ISC_R_CANCELED) {
return;
}

View file

@ -7411,7 +7411,7 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
fetchctx_t *fctx = NULL;
respctx_t rctx;
if (eresult == ISC_R_CANCELED || eresult == ISC_R_EOF) {
if (eresult == ISC_R_CANCELED) {
return;
}
@ -7886,45 +7886,40 @@ rctx_answer_init(respctx_t *rctx) {
static isc_result_t
rctx_dispfail(respctx_t *rctx) {
fetchctx_t *fctx = rctx->fctx;
resquery_t *query = rctx->query;
if (rctx->result == ISC_R_SUCCESS) {
return (ISC_R_SUCCESS);
}
if (rctx->result == ISC_R_EOF &&
(rctx->retryopts & DNS_FETCHOPT_NOEDNS0) == 0) {
/*
* The problem might be that they don't understand
* EDNS0. Turn it off and try again.
*/
rctx->retryopts |= DNS_FETCHOPT_NOEDNS0;
rctx->resend = true;
add_bad_edns(fctx, &query->addrinfo->sockaddr);
} else {
/*
* There's no hope for this response.
*/
rctx->next_server = true;
/*
* There's no hope for this response.
*/
rctx->next_server = true;
/*
* If this is a network error, mark the server as bad so
* that we won't try it for this fetch again. Also
* adjust finish and no_response so that we penalize
* this address in SRTT adjustment later.
*/
if (rctx->result == ISC_R_HOSTUNREACH ||
rctx->result == ISC_R_NETUNREACH ||
rctx->result == ISC_R_CONNREFUSED ||
rctx->result == ISC_R_CANCELED ||
rctx->result == ISC_R_SHUTTINGDOWN)
{
rctx->broken_server = rctx->result;
rctx->broken_type = badns_unreachable;
rctx->finish = NULL;
rctx->no_response = true;
}
/*
* If this is a network failure, the operation is cancelled,
* or the network manager is being shut down, we mark the server
* as bad so that we won't try it for this fetch again. Also
* adjust finish and no_response so that we penalize this
* address in SRTT adjustments later.
*/
switch (rctx->result) {
case ISC_R_EOF:
case ISC_R_HOSTUNREACH:
case ISC_R_NETUNREACH:
case ISC_R_CONNREFUSED:
case ISC_R_CONNECTIONRESET:
case ISC_R_CANCELED:
case ISC_R_SHUTTINGDOWN:
rctx->broken_server = rctx->result;
rctx->broken_type = badns_unreachable;
rctx->finish = NULL;
rctx->no_response = true;
break;
default:
break;
}
FCTXTRACE3("dispatcher failure", rctx->result);
rctx_done(rctx, ISC_R_SUCCESS);
return (ISC_R_COMPLETE);