diff --git a/bin/delv/delv.c b/bin/delv/delv.c index d1ba814be1..2ecaeb3ed7 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -94,6 +94,7 @@ #define MAXNAME (DNS_NAME_MAXTEXT + 1) #define MAX_QUERIES 32 +#define MAX_TOTAL 200 #define MAX_RESTARTS 11 /* Variables used internally by delv. */ @@ -138,6 +139,7 @@ static bool showcomments = true, showdnssec = true, showtrust = true, yaml = false, fulltrace = false; static uint32_t maxqueries = MAX_QUERIES; +static uint32_t maxtotal = MAX_TOTAL; static uint32_t restarts = MAX_RESTARTS; static bool resolve_trace = false, validator_trace = false, @@ -1168,22 +1170,46 @@ plus_option(char *option) { break; case 'm': switch (cmd[1]) { - case 'a': /* maxqueries */ - FULLCHECK("maxqueries"); - if (value == NULL) { - goto need_value; - } - if (!state) { + case 'a': + switch (cmd[3]) { + case 'q': /* maxqueries */ + FULLCHECK("maxqueries"); + if (value == NULL) { + goto need_value; + } + if (!state) { + goto invalid_option; + } + result = parse_uint(&maxqueries, value, + UINT_MAX, "maxqueries"); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse maxqueries"); + } + if (maxqueries == 0) { + fatal("maxqueries must be nonzero"); + } + break; + case 't': /* maxtotalqueries */ + FULLCHECK("maxtotalqueries"); + if (value == NULL) { + goto need_value; + } + if (!state) { + goto invalid_option; + } + result = parse_uint(&maxtotal, value, UINT_MAX, + "maxtotalqueries"); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse maxtotalqueries"); + } + if (maxtotal == 0) { + fatal("maxtotalqueries must be " + "nonzero"); + } + break; + default: goto invalid_option; } - result = parse_uint(&maxqueries, value, UINT_MAX, - "maxqueries"); - if (result != ISC_R_SUCCESS) { - fatal("Couldn't parse maxqueries"); - } - if (maxqueries == 0) { - fatal("maxqueries must be nonzero"); - } break; case 't': /* mtrace */ FULLCHECK("mtrace"); @@ -1931,6 +1957,7 @@ run_resolve(void *arg) { CHECK(dns_client_create(mctx, loopmgr, netmgr, 0, tlsctx_client_cache, &client, srcaddr4, srcaddr6)); dns_client_setmaxrestarts(client, restarts); + dns_client_setmaxqueries(client, maxtotal); /* Set the nameserver */ if (server != NULL) { @@ -2196,6 +2223,7 @@ run_server(void *arg) { dns_cache_detach(&cache); dns_view_setdstport(view, destport); dns_view_setmaxrestarts(view, restarts); + dns_view_setmaxqueries(view, maxtotal); CHECK(dns_rootns_create(mctx, dns_rdataclass_in, hintfile, &roothints)); dns_view_sethints(view, roothints); diff --git a/bin/delv/delv.rst b/bin/delv/delv.rst index c32601e8b4..f8c2da6806 100644 --- a/bin/delv/delv.rst +++ b/bin/delv/delv.rst @@ -353,6 +353,11 @@ assign values to options like the timeout interval. They have the form This option specifies the maximum number of queries to send to resolve a name before giving up. The default is 32. +.. option:: +maxtotalqueries + + This option specifies the maximum number of queries to send to resolve + a client request before giving up. The default is 200. + .. option:: +trust, +notrust This option controls whether to display the trust level when printing a record. diff --git a/lib/dns/client.c b/lib/dns/client.c index 26c7acf8d4..fa4ba6ee84 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -81,6 +82,7 @@ struct dns_client { unsigned int find_timeout; unsigned int find_udpretries; uint8_t max_restarts; + uint8_t max_queries; isc_refcount_t references; @@ -91,6 +93,7 @@ struct dns_client { #define DEF_FIND_TIMEOUT 5 #define DEF_FIND_UDPRETRIES 3 #define DEF_MAX_RESTARTS 11 +#define DEF_MAX_QUERIES 200 /*% * Internal state for a single name resolution procedure @@ -111,6 +114,7 @@ typedef struct resctx { dns_fetch_t *fetch; dns_namelist_t namelist; isc_result_t result; + isc_counter_t *qc; dns_clientresume_t *rev; dns_rdataset_t *rdataset; dns_rdataset_t *sigrdataset; @@ -252,6 +256,7 @@ dns_client_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, isc_nm_t *nm, .loop = isc_loop_get(loopmgr, 0), .nm = nm, .max_restarts = DEF_MAX_RESTARTS, + .max_queries = DEF_MAX_QUERIES, }; result = dns_dispatchmgr_create(mctx, loopmgr, nm, @@ -395,6 +400,14 @@ dns_client_setmaxrestarts(dns_client_t *client, uint8_t max_restarts) { client->max_restarts = max_restarts; } +void +dns_client_setmaxqueries(dns_client_t *client, uint8_t max_queries) { + REQUIRE(DNS_CLIENT_VALID(client)); + REQUIRE(max_queries > 0); + + client->max_queries = max_queries; +} + static isc_result_t getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) { dns_rdataset_t *rdataset; @@ -456,7 +469,7 @@ start_fetch(resctx_t *rctx) { result = dns_resolver_createfetch( rctx->view->resolver, dns_fixedname_name(&rctx->name), - rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL, NULL, + rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL, rctx->qc, rctx->client->loop, fetch_done, rctx, rctx->rdataset, rctx->sigrdataset, &rctx->fetch); @@ -935,6 +948,11 @@ startresolve(dns_client_t *client, const dns_name_t *name, rctx->magic = RCTX_MAGIC; isc_refcount_increment(&client->references); + result = isc_counter_create(mctx, client->max_queries, &rctx->qc); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + ISC_LIST_APPEND(client->resctxs, rctx, link); *transp = (dns_clientrestrans_t *)rctx; @@ -949,6 +967,9 @@ cleanup: if (sigrdataset != NULL) { putrdataset(client->mctx, &sigrdataset); } + if (rctx->qc != NULL) { + isc_counter_detach(&rctx->qc); + } isc_mem_put(mctx, rctx, sizeof(*rctx)); isc_mem_put(mctx, rev, sizeof(*rev)); @@ -1042,6 +1063,9 @@ destroyrestrans(dns_clientrestrans_t **transp) { rctx->magic = 0; + if (rctx->qc != NULL) { + isc_counter_detach(&rctx->qc); + } isc_mem_put(mctx, rctx, sizeof(*rctx)); } diff --git a/lib/dns/include/dns/client.h b/lib/dns/include/dns/client.h index c065c0c705..75cbf89250 100644 --- a/lib/dns/include/dns/client.h +++ b/lib/dns/include/dns/client.h @@ -187,6 +187,19 @@ dns_client_setmaxrestarts(dns_client_t *client, uint8_t max_restarts); *\li 'max_restarts' is greater than 0. */ +void +dns_client_setmaxqueries(dns_client_t *client, uint8_t max_queries); +/*%< + * Set the number of permissible outgoing queries before we give up, + * This defaults to 200. + * + * Requires: + * + *\li 'client' is a valid client. + + *\li 'max_queries' is greater than 0. + */ + typedef void (*dns_client_resolve_cb)(dns_client_t *client, const dns_name_t *name, dns_namelist_t *namelist,