diff --git a/bin/delv/delv.c b/bin/delv/delv.c index fba5c4e6e8..29989929e1 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -88,10 +88,7 @@ #define MAXNAME (DNS_NAME_MAXTEXT + 1) -/* - * Default maximum number of chained queries before we give up - * to prevent CNAME loops. - */ +#define MAX_QUERIES 32 #define MAX_RESTARTS 11 /* Variables used internally by delv. */ @@ -136,6 +133,9 @@ static bool showcomments = true, showdnssec = true, showtrust = true, multiline = false, short_form = false, print_unknown_format = false, yaml = false, fulltrace = false; +static uint32_t maxqueries = MAX_QUERIES; +static uint32_t restarts = MAX_RESTARTS; + static bool resolve_trace = false, validator_trace = false, message_trace = false, send_trace = false; @@ -1197,6 +1197,23 @@ plus_option(char *option) { break; case 'm': switch (cmd[1]) { + case 'a': /* 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': /* mtrace */ FULLCHECK("mtrace"); message_trace = state; @@ -1249,6 +1266,22 @@ plus_option(char *option) { break; case 'r': switch (cmd[1]) { + case 'e': /* restarts */ + FULLCHECK("restarts"); + if (value == NULL) { + goto need_value; + } + if (!state) { + goto invalid_option; + } + result = parse_uint(&restarts, value, 255, "restarts"); + if (result != ISC_R_SUCCESS) { + fatal("Couldn't parse restarts"); + } + if (restarts == 0) { + fatal("restarts must be between 1..255"); + } + break; case 'o': /* root */ FULLCHECK("root"); if (state && no_sigs) { @@ -1376,10 +1409,7 @@ plus_option(char *option) { break; default: invalid_option: - /* - * We can also add a "need_value:" case here if we ever - * add a plus-option that requires a specified value - */ + need_value: fprintf(stderr, "Invalid option: +%s\n", option); usage(); } @@ -1904,7 +1934,7 @@ run_resolve(void *arg) { /* Create client */ CHECK(dns_client_create(mctx, loopmgr, netmgr, 0, tlsctx_client_cache, &client, srcaddr4, srcaddr6)); - dns_client_setmaxrestarts(client, MAX_RESTARTS); + dns_client_setmaxrestarts(client, restarts); /* Set the nameserver */ if (server != NULL) { @@ -2169,7 +2199,7 @@ run_server(void *arg) { dns_view_setcache(view, cache, false); dns_cache_detach(&cache); dns_view_setdstport(view, destport); - dns_view_setmaxrestarts(view, MAX_RESTARTS); + dns_view_setmaxrestarts(view, restarts); CHECK(dns_rootns_create(mctx, dns_rdataclass_in, hintfile, &roothints)); dns_view_sethints(view, roothints); @@ -2183,6 +2213,7 @@ run_server(void *arg) { CHECK(dns_view_createresolver(view, netmgr, 0, tlsctx_client_cache, dispatch, NULL)); + dns_resolver_setmaxqueries(view->resolver, maxqueries); isc_stats_create(mctx, &resstats, dns_resstatscounter_max); dns_resolver_setstats(view->resolver, resstats); diff --git a/bin/delv/delv.rst b/bin/delv/delv.rst index 2ab1f897f4..74239c9bc1 100644 --- a/bin/delv/delv.rst +++ b/bin/delv/delv.rst @@ -337,6 +337,18 @@ assign values to options like the timeout interval. They have the form they are replaced by the string ``[omitted]`` or, in the DNSKEY case, the key ID is displayed as the replacement, e.g. ``[ key id = value ]``. +.. option:: +restarts + + When name server mode (``delv +ns``) is in use, this option sets the + maximum number of CNAME queries to follow before terminating resolution. + This prevents ``delv`` from hanging in the event of a CNAME loop. + The default is 11. + +.. option:: +maxqueries + + This option specifies the maximum number of queries to send to resolve + a name before giving up. The default is 32. + .. option:: +trust, +notrust This option controls whether to display the trust level when printing a record.