diff --git a/bin/delv/delv.c b/bin/delv/delv.c index c750629517..650d8cb61b 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -76,6 +76,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; static isc_mem_t *mctx = NULL; @@ -1776,6 +1782,8 @@ main(int argc, char *argv[]) { goto cleanup; } + dns_client_setmaxrestarts(client, MAX_RESTARTS); + /* Set the nameserver */ if (server != NULL) { addserver(client); diff --git a/lib/dns/client.c b/lib/dns/client.c index 7ac358df02..16f1facb91 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -60,8 +60,6 @@ #define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x') #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC) -#define MAX_RESTARTS 11 - #ifdef TUNE_LARGE #define RESOLVER_NTASKS 523 #else /* ifdef TUNE_LARGE */ @@ -95,6 +93,7 @@ struct dns_client { unsigned int find_timeout; unsigned int find_udpretries; + uint8_t max_restarts; isc_refcount_t references; @@ -105,6 +104,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 @@ -281,7 +281,11 @@ dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, client = isc_mem_get(mctx, sizeof(*client)); *client = (dns_client_t){ - .actx = actx, .taskmgr = taskmgr, .timermgr = timermgr, .nm = nm + .actx = actx, + .taskmgr = taskmgr, + .timermgr = timermgr, + .nm = nm, + .max_restarts = DEF_MAX_RESTARTS, }; isc_mutex_init(&client->lock); @@ -474,6 +478,14 @@ dns_client_clearservers(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; @@ -886,7 +898,9 @@ client_resfind(resctx_t *rctx, dns_fetchevent_t *event) { /* * 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 ec70f92d88..e5908973bd 100644 --- a/lib/dns/include/dns/client.h +++ b/lib/dns/include/dns/client.h @@ -189,6 +189,19 @@ dns_client_clearservers(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. + */ + isc_result_t dns_client_resolve(dns_client_t *client, const dns_name_t *name, dns_rdataclass_t rdclass, dns_rdatatype_t type, diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 516c209b92..f5e274ef3d 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -193,6 +193,7 @@ struct dns_view { dns_badcache_t *failcache; uint32_t maxrrperset; uint32_t maxtypepername; + uint8_t max_restarts; /* * Configurable data for server use only, @@ -1427,4 +1428,16 @@ dns_view_setmaxtypepername(dns_view_t *view, uint32_t value); * Set the maximum resource record types per owner name that can be cached. */ +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 231041efab..7b8520acd7 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -88,6 +88,12 @@ adb_shutdown(isc_task_t *task, isc_event_t *event); static void req_shutdown(isc_task_t *task, isc_event_t *event); +/*% + * Default maximum number of chained queries before we give up + * to prevent CNAME loops. + */ +#define DEFAULT_MAX_RESTARTS 11 + isc_result_t dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, const char *name, dns_view_t **viewp) { @@ -266,6 +272,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, const char *name, view->hooktable = NULL; view->hooktable_free = NULL; + view->max_restarts = DEFAULT_MAX_RESTARTS; + isc_mutex_init(&view->new_zone_lock); result = dns_order_create(view->mctx, &view->order); @@ -2780,3 +2788,11 @@ dns_view_setmaxtypepername(dns_view_t *view, uint32_t value) { dns_cache_setmaxtypepername(view->cache, value); } } + +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 206c495dc0..6e4309b000 100644 --- a/lib/ns/include/ns/server.h +++ b/lib/ns/include/ns/server.h @@ -100,6 +100,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 b712fe2fb2..5549e202df 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -85,12 +85,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; \ @@ -2095,10 +2089,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); } @@ -11945,7 +11939,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) + { qctx->client->query.restarts++; return (ns__query_start(qctx)); } else { diff --git a/lib/ns/server.c b/lib/ns/server.c index 7b245c39c7..bea4f36a47 100644 --- a/lib/ns/server.c +++ b/lib/ns/server.c @@ -38,7 +38,7 @@ isc_result_t ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview, ns_server_t **sctxp) { - ns_server_t *sctx; + ns_server_t *sctx = NULL; isc_result_t result; REQUIRE(sctxp != NULL && *sctxp == NULL);