diff --git a/bin/delv/delv.c b/bin/delv/delv.c index d494500675..fba5c4e6e8 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -88,6 +88,12 @@ #define MAXNAME (DNS_NAME_MAXTEXT + 1) +/* + * Default maximum number of chained queries before we give up + * to prevent CNAME loops. + */ +#define MAX_RESTARTS 11 + /* Variables used internally by delv. */ char *progname = NULL; static isc_mem_t *mctx = NULL; @@ -1898,6 +1904,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); /* Set the nameserver */ if (server != NULL) { @@ -2162,6 +2169,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); CHECK(dns_rootns_create(mctx, dns_rdataclass_in, hintfile, &roothints)); dns_view_sethints(view, roothints); diff --git a/lib/dns/client.c b/lib/dns/client.c index a945b93d79..bcd9e4c3e5 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -57,8 +57,6 @@ #define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x') #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC) -#define MAX_RESTARTS 11 - #define CHECK(r) \ do { \ result = (r); \ @@ -81,6 +79,7 @@ struct dns_client { unsigned int find_timeout; unsigned int find_udpretries; + uint8_t max_restarts; isc_refcount_t references; @@ -90,6 +89,7 @@ struct dns_client { #define DEF_FIND_TIMEOUT 5 #define DEF_FIND_UDPRETRIES 3 +#define DEF_MAX_RESTARTS 11 /*% * Internal state for a single name resolution procedure @@ -250,6 +250,7 @@ dns_client_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, isc_nm_t *nm, *client = (dns_client_t){ .loop = isc_loop_get(loopmgr, 0), .nm = nm, + .max_restarts = DEF_MAX_RESTARTS, }; result = dns_dispatchmgr_create(mctx, loopmgr, nm, @@ -384,6 +385,14 @@ dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass, return (result); } +void +dns_client_setmaxrestarts(dns_client_t *client, uint8_t max_restarts) { + REQUIRE(DNS_CLIENT_VALID(client)); + REQUIRE(max_restarts > 0); + + client->max_restarts = max_restarts; +} + static isc_result_t getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) { dns_rdataset_t *rdataset; @@ -778,7 +787,9 @@ client_resfind(resctx_t *rctx, dns_fetchresponse_t *resp) { /* * Limit the number of restarts. */ - if (want_restart && rctx->restarts == MAX_RESTARTS) { + if (want_restart && + rctx->restarts == rctx->client->max_restarts) + { want_restart = false; result = ISC_R_QUOTA; send_event = true; diff --git a/lib/dns/include/dns/client.h b/lib/dns/include/dns/client.h index 148578f4b7..c065c0c705 100644 --- a/lib/dns/include/dns/client.h +++ b/lib/dns/include/dns/client.h @@ -174,6 +174,19 @@ dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass, *\li Anything else Failure. */ +void +dns_client_setmaxrestarts(dns_client_t *client, uint8_t max_restarts); +/*%< + * Set the number of permissible chained queries before we give up, + * to prevent CNAME loops. This defaults to 11. + * + * Requires: + * + *\li 'client' is a valid client. + + *\li 'max_restarts' is greater than 0. + */ + typedef void (*dns_client_resolve_cb)(dns_client_t *client, const dns_name_t *name, dns_namelist_t *namelist, diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index ddba1e7401..02932e8a94 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -185,6 +185,7 @@ struct dns_view { unsigned int udpsize; uint32_t maxrrperset; uint32_t maxtypepername; + uint8_t max_restarts; /* * Configurable data for server use only, @@ -1327,4 +1328,16 @@ dns_view_getadb(dns_view_t *view, dns_adb_t **adbp); *\li 'adbp' is non-NULL and '*adbp' is NULL. */ +void +dns_view_setmaxrestarts(dns_view_t *view, uint8_t max_restarts); +/*%< + * Set the number of permissible chained queries before we give up, + * to prevent CNAME loops. This defaults to 11. + * + * Requires: + * + *\li 'view' is valid; + *\li 'max_restarts' is greater than 0. + */ + ISC_LANG_ENDDECLS diff --git a/lib/dns/view.c b/lib/dns/view.c index 99d8b61b59..bcac41bb80 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -74,6 +74,12 @@ #define DNS_VIEW_DELONLYHASH 111 +/*% + * Default maximum number of chained queries before we give up + * to prevent CNAME loops. + */ +#define DEFAULT_MAX_RESTARTS 11 + /*% * Default EDNS0 buffer size */ @@ -116,6 +122,7 @@ dns_view_create(isc_mem_t *mctx, dns_dispatchmgr_t *dispatchmgr, .trust_anchor_telemetry = true, .root_key_sentinel = true, .udpsize = DEFAULT_EDNS_BUFSIZE, + .max_restarts = DEFAULT_MAX_RESTARTS, }; isc_refcount_init(&view->references, 1); @@ -2455,3 +2462,11 @@ dns_view_getadb(dns_view_t *view, dns_adb_t **adbp) { } rcu_read_unlock(); } + +void +dns_view_setmaxrestarts(dns_view_t *view, uint8_t max_restarts) { + REQUIRE(DNS_VIEW_VALID(view)); + REQUIRE(max_restarts > 0); + + view->max_restarts = max_restarts; +} diff --git a/lib/ns/include/ns/server.h b/lib/ns/include/ns/server.h index fc01ee2c62..ec6636a0fd 100644 --- a/lib/ns/include/ns/server.h +++ b/lib/ns/include/ns/server.h @@ -103,6 +103,7 @@ struct ns_server { uint16_t transfer_tcp_message_size; bool interface_auto; dns_tkeyctx_t *tkeyctx; + uint8_t max_restarts; /*% Server id for NSID */ char *server_id; diff --git a/lib/ns/query.c b/lib/ns/query.c index 4e66f7b736..01b24dcdfa 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -86,12 +86,6 @@ #define dns64_bis_return_excluded_addresses 1 #endif /* if 0 */ -/*% - * Maximum number of chained queries before we give up - * to prevent CNAME loops. - */ -#define MAX_RESTARTS 11 - #define QUERY_ERROR(qctx, r) \ do { \ (qctx)->result = r; \ @@ -2046,10 +2040,10 @@ addname: /* * In some cases, a record that has been added as additional * data may *also* trigger the addition of additional data. - * This cannot go more than MAX_RESTARTS levels deep. + * This cannot go more than 'max-restarts' levels deep. */ if (trdataset != NULL && dns_rdatatype_followadditional(type)) { - if (client->additionaldepth++ < MAX_RESTARTS) { + if (client->additionaldepth++ < client->view->max_restarts) { eresult = dns_rdataset_additionaldata( trdataset, fname, query_additional_cb, qctx); } @@ -11580,7 +11574,9 @@ ns_query_done(query_ctx_t *qctx) { * Do we need to restart the query (e.g. for CNAME chaining)? */ if (qctx->want_restart) { - if (qctx->client->query.restarts < MAX_RESTARTS) { + if (qctx->client->query.restarts < + qctx->client->view->max_restarts) + { query_ctx_t *saved_qctx = NULL; qctx->client->query.restarts++; saved_qctx = isc_mem_get(qctx->client->manager->mctx, diff --git a/lib/ns/server.c b/lib/ns/server.c index ea4a588c18..94ee48b76c 100644 --- a/lib/ns/server.c +++ b/lib/ns/server.c @@ -38,7 +38,7 @@ void ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview, ns_server_t **sctxp) { - ns_server_t *sctx; + ns_server_t *sctx = NULL; REQUIRE(sctxp != NULL && *sctxp == NULL);