summaryrefslogtreecommitdiff
path: root/lib/dns/resolver.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dns/resolver.c')
-rw-r--r--lib/dns/resolver.c251
1 files changed, 198 insertions, 53 deletions
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index 2e60cd84cca24..befe3cafe0f2e 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -21,6 +21,7 @@
#include <config.h>
+#include <isc/counter.h>
#include <isc/log.h>
#include <isc/platform.h>
#include <isc/print.h>
@@ -131,11 +132,20 @@
#define MAXIMUM_QUERY_TIMEOUT 30 /* The maximum time in seconds for the whole query to live. */
#endif
+/* The default maximum number of recursions to follow before giving up. */
+#ifndef DEFAULT_RECURSION_DEPTH
+#define DEFAULT_RECURSION_DEPTH 7
+#endif
+
+/* The default maximum number of iterative queries to allow before giving up. */
+#ifndef DEFAULT_MAX_QUERIES
+#define DEFAULT_MAX_QUERIES 50
+#endif
+
/*%
* Maximum EDNS0 input packet size.
*/
#define RECV_BUFFER_SIZE 4096 /* XXXRTH Constant. */
-#define EDNSOPTS 2
/*%
* This defines the maximum number of timeouts we will permit before we
@@ -163,6 +173,7 @@ typedef struct query {
isc_buffer_t *tsig;
dns_tsigkey_t *tsigkey;
isc_socketevent_t sendevent;
+ int ednsversion;
unsigned int options;
unsigned int attributes;
unsigned int sends;
@@ -234,12 +245,13 @@ struct fetchctx {
isc_sockaddrlist_t edns;
isc_sockaddrlist_t edns512;
isc_sockaddrlist_t bad_edns;
- dns_validator_t *validator;
+ dns_validator_t * validator;
ISC_LIST(dns_validator_t) validators;
dns_db_t * cache;
dns_adb_t * adb;
isc_boolean_t ns_ttl_ok;
isc_uint32_t ns_ttl;
+ isc_counter_t * qc;
/*%
* The number of events we're waiting for.
@@ -307,6 +319,7 @@ struct fetchctx {
isc_boolean_t timeout;
dns_adbaddrinfo_t *addrinfo;
isc_sockaddr_t *client;
+ unsigned int depth;
};
#define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!')
@@ -343,6 +356,7 @@ typedef struct {
struct dns_fetch {
unsigned int magic;
+ isc_mem_t * mctx;
fetchctx_t * private;
};
@@ -418,6 +432,8 @@ struct dns_resolver {
isc_timer_t * spillattimer;
isc_boolean_t zero_no_soa_ttl;
unsigned int query_timeout;
+ unsigned int maxdepth;
+ unsigned int maxqueries;
/* Locked by lock. */
unsigned int references;
@@ -449,12 +465,16 @@ struct dns_resolver {
#define FCTX_ADDRINFO_MARK 0x0001
#define FCTX_ADDRINFO_FORWARDER 0x1000
#define FCTX_ADDRINFO_TRIED 0x2000
+#define FCTX_ADDRINFO_EDNSOK 0x4000
+
#define UNMARKED(a) (((a)->flags & FCTX_ADDRINFO_MARK) \
== 0)
#define ISFORWARDER(a) (((a)->flags & \
FCTX_ADDRINFO_FORWARDER) != 0)
#define TRIED(a) (((a)->flags & \
FCTX_ADDRINFO_TRIED) != 0)
+#define EDNSOK(a) (((a)->flags & \
+ FCTX_ADDRINFO_EDNSOK) != 0)
#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
#define NEGATIVE(r) (((r)->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
@@ -792,6 +812,7 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
dns_adbfind_t *find;
dns_adbaddrinfo_t *addrinfo;
isc_socket_t *socket;
+ isc_stdtime_t now;
query = *queryp;
fctx = query->fctx;
@@ -862,14 +883,13 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
/*
* Age RTTs of servers not tried.
*/
- factor = DNS_ADB_RTTADJAGE;
+ isc_stdtime_get(&now);
if (finish != NULL)
for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs);
addrinfo != NULL;
addrinfo = ISC_LIST_NEXT(addrinfo, publink))
if (UNMARKED(addrinfo))
- dns_adb_adjustsrtt(fctx->adb, addrinfo,
- 0, factor);
+ dns_adb_agesrtt(fctx->adb, addrinfo, now);
if (finish != NULL && TRIEDFIND(fctx))
for (find = ISC_LIST_HEAD(fctx->finds);
@@ -879,16 +899,15 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
addrinfo != NULL;
addrinfo = ISC_LIST_NEXT(addrinfo, publink))
if (UNMARKED(addrinfo))
- dns_adb_adjustsrtt(fctx->adb, addrinfo,
- 0, factor);
+ dns_adb_agesrtt(fctx->adb, addrinfo,
+ now);
if (finish != NULL && TRIEDALT(fctx)) {
for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs);
addrinfo != NULL;
addrinfo = ISC_LIST_NEXT(addrinfo, publink))
if (UNMARKED(addrinfo))
- dns_adb_adjustsrtt(fctx->adb, addrinfo,
- 0, factor);
+ dns_adb_agesrtt(fctx->adb, addrinfo, now);
for (find = ISC_LIST_HEAD(fctx->altfinds);
find != NULL;
find = ISC_LIST_NEXT(find, publink))
@@ -896,8 +915,8 @@ fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp,
addrinfo != NULL;
addrinfo = ISC_LIST_NEXT(addrinfo, publink))
if (UNMARKED(addrinfo))
- dns_adb_adjustsrtt(fctx->adb, addrinfo,
- 0, factor);
+ dns_adb_agesrtt(fctx->adb, addrinfo,
+ now);
}
/*
@@ -1533,6 +1552,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
if (result != ISC_R_SUCCESS)
goto cleanup_dispatch;
}
+
fctx->querysent++;
ISC_LIST_APPEND(fctx->queries, query, link);
@@ -1674,7 +1694,7 @@ resquery_send(resquery_t *query) {
isc_boolean_t cleanup_cctx = ISC_FALSE;
isc_boolean_t secure_domain;
isc_boolean_t connecting = ISC_FALSE;
- dns_ednsopt_t ednsopts[EDNSOPTS];
+ dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS];
unsigned ednsopt = 0;
fctx = query->fctx;
@@ -1821,12 +1841,12 @@ resquery_send(resquery_t *query) {
if (fctx->timeout) {
if ((triededns512(fctx, &query->addrinfo->sockaddr) ||
fctx->timeouts >= (MAX_EDNS0_TIMEOUTS * 2)) &&
- (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
- query->options |= DNS_FETCHOPT_NOEDNS0;
- fctx->reason = "disabling EDNS";
+ (query->options & DNS_FETCHOPT_NOEDNS0) == 0 &&
+ !EDNSOK(query->addrinfo)) {
} else if ((triededns(fctx, &query->addrinfo->sockaddr) ||
fctx->timeouts >= MAX_EDNS0_TIMEOUTS) &&
- (query->options & DNS_FETCHOPT_NOEDNS0) == 0) {
+ (query->options & DNS_FETCHOPT_NOEDNS0) == 0 &&
+ !EDNSOK(query->addrinfo)) {
query->options |= DNS_FETCHOPT_EDNS512;
fctx->reason = "reducing the advertised EDNS UDP "
"packet size to 512 octets";
@@ -1859,12 +1879,13 @@ resquery_send(resquery_t *query) {
if (peer != NULL)
(void) dns_peer_getrequestnsid(peer, &reqnsid);
if (reqnsid) {
- INSIST(ednsopt < EDNSOPTS);
+ INSIST(ednsopt < DNS_EDNSOPTIONS);
ednsopts[ednsopt].code = DNS_OPT_NSID;
ednsopts[ednsopt].length = 0;
ednsopts[ednsopt].value = NULL;
ednsopt++;
}
+ query->ednsversion = version;
result = fctx_addopt(fctx->qmessage, version,
udpsize, ednsopts, ednsopt);
if (reqnsid && result == ISC_R_SUCCESS) {
@@ -1876,6 +1897,7 @@ resquery_send(resquery_t *query) {
* bit.
*/
query->options |= DNS_FETCHOPT_NOEDNS0;
+ query->ednsversion = -1;
}
} else {
/*
@@ -1884,8 +1906,10 @@ resquery_send(resquery_t *query) {
* not using EDNS0.
*/
query->options |= DNS_FETCHOPT_NOEDNS0;
+ query->ednsversion = -1;
}
- }
+ } else
+ query->ednsversion = -1;
/*
* If we need EDNS0 to do this query and aren't using it, we lose.
@@ -2186,9 +2210,9 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
*/
INSIST(!SHUTTINGDOWN(fctx));
fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
- if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES)
+ if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES) {
want_try = ISC_TRUE;
- else {
+ } else {
fctx->findfail++;
if (fctx->pending == 0) {
/*
@@ -2217,7 +2241,7 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
else if (want_done)
fctx_done(fctx, ISC_R_FAILURE, __LINE__);
else if (destroy) {
- fctx_destroy(fctx);
+ fctx_destroy(fctx);
if (bucket_empty)
empty_bucket(res);
}
@@ -2471,12 +2495,13 @@ findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port,
* See what we know about this address.
*/
find = NULL;
- result = dns_adb_createfind(fctx->adb,
- res->buckets[fctx->bucketnum].task,
- fctx_finddone, fctx, name,
- &fctx->name, fctx->type,
- options, now, NULL,
- res->view->dstport, &find);
+ result = dns_adb_createfind2(fctx->adb,
+ res->buckets[fctx->bucketnum].task,
+ fctx_finddone, fctx, name,
+ &fctx->name, fctx->type,
+ options, now, NULL,
+ res->view->dstport,
+ fctx->depth + 1, fctx->qc, &find);
if (result != ISC_R_SUCCESS) {
if (result == DNS_R_ALIAS) {
/*
@@ -2584,6 +2609,14 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) {
res = fctx->res;
+ if (fctx->depth > res->maxdepth) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
+ "too much NS indirection resolving '%s'",
+ fctx->info);
+ return (DNS_R_SERVFAIL);
+ }
+
/*
* Forwarders.
*/
@@ -3059,6 +3092,16 @@ fctx_try(fetchctx_t *fctx, isc_boolean_t retrying, isc_boolean_t badcache) {
}
}
+ result = isc_counter_increment(fctx->qc);
+ if (result != ISC_R_SUCCESS) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
+ "exceeded max queries resolving '%s'",
+ fctx->info);
+ fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
+ return;
+ }
+
result = fctx_query(fctx, addrinfo, fctx->options);
if (result != ISC_R_SUCCESS)
fctx_done(fctx, result, __LINE__);
@@ -3157,6 +3200,7 @@ fctx_destroy(fetchctx_t *fctx) {
isc_mem_put(fctx->mctx, sa, sizeof(*sa));
}
+ isc_counter_detach(&fctx->qc);
isc_timer_detach(&fctx->timer);
dns_message_destroy(&fctx->rmessage);
dns_message_destroy(&fctx->qmessage);
@@ -3485,7 +3529,8 @@ log_ns_ttl(fetchctx_t *fctx, const char *where) {
static isc_result_t
fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
dns_name_t *domain, dns_rdataset_t *nameservers,
- unsigned int options, unsigned int bucketnum, fetchctx_t **fctxp)
+ unsigned int options, unsigned int bucketnum, unsigned int depth,
+ isc_counter_t *qc, fetchctx_t **fctxp)
{
fetchctx_t *fctx;
isc_result_t result;
@@ -3507,6 +3552,21 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
fctx = isc_mem_get(mctx, sizeof(*fctx));
if (fctx == NULL)
return (ISC_R_NOMEMORY);
+
+ fctx->qc = NULL;
+ if (qc != NULL) {
+ isc_counter_attach(qc, &fctx->qc);
+ } else {
+ result = isc_counter_create(res->mctx,
+ res->maxqueries, &fctx->qc);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_fetch;
+ }
+
+ /*
+ * Make fctx->info point to a copy of a formatted string
+ * "name/type".
+ */
dns_name_format(name, buf, sizeof(buf));
dns_rdatatype_format(type, typebuf, sizeof(typebuf));
strcat(buf, "/"); /* checked */
@@ -3514,7 +3574,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
fctx->info = isc_mem_strdup(mctx, buf);
if (fctx->info == NULL) {
result = ISC_R_NOMEMORY;
- goto cleanup_fetch;
+ goto cleanup_counter;
}
FCTXTRACE("create");
dns_name_init(&fctx->name, NULL);
@@ -3537,6 +3597,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
fctx->state = fetchstate_init;
fctx->want_shutdown = ISC_FALSE;
fctx->cloned = ISC_FALSE;
+ fctx->depth = depth;
ISC_LIST_INIT(fctx->queries);
ISC_LIST_INIT(fctx->finds);
ISC_LIST_INIT(fctx->altfinds);
@@ -3615,7 +3676,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
*/
if (dns_rdatatype_atparent(fctx->type))
findoptions |= DNS_DBFIND_NOEXACT;
- result = dns_view_findzonecut(res->view, fwdname,
+ result = dns_view_findzonecut(res->view, name,
domain, 0, findoptions,
ISC_TRUE,
&fctx->nameservers,
@@ -3744,6 +3805,9 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
cleanup_info:
isc_mem_free(mctx, fctx->info);
+ cleanup_counter:
+ isc_counter_detach(&fctx->qc);
+
cleanup_fetch:
isc_mem_put(mctx, fctx, sizeof(*fctx));
@@ -4008,6 +4072,7 @@ validated(isc_task_t *task, isc_event_t *event) {
isc_result_t result = ISC_R_SUCCESS;
isc_stdtime_t now;
isc_uint32_t ttl;
+ isc_uint32_t bucketnum;
UNUSED(task); /* for now */
@@ -4024,7 +4089,8 @@ validated(isc_task_t *task, isc_event_t *event) {
FCTXTRACE("received validation completion event");
- LOCK(&res->buckets[fctx->bucketnum].lock);
+ bucketnum = fctx->bucketnum;
+ LOCK(&res->buckets[bucketnum].lock);
ISC_LIST_UNLINK(fctx->validators, vevent->validator, link);
fctx->validator = NULL;
@@ -4046,7 +4112,6 @@ validated(isc_task_t *task, isc_event_t *event) {
* so, destroy the fctx.
*/
if (SHUTTINGDOWN(fctx) && !sentresponse) {
- isc_uint32_t bucketnum = fctx->bucketnum;
isc_boolean_t bucket_empty;
bucket_empty = maybe_destroy(fctx, ISC_TRUE);
UNLOCK(&res->buckets[bucketnum].lock);
@@ -4149,7 +4214,7 @@ validated(isc_task_t *task, isc_event_t *event) {
result = fctx->vresult;
add_bad(fctx, addrinfo, result, badns_validation);
isc_event_free(&event);
- UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&res->buckets[bucketnum].lock);
INSIST(fctx->validator == NULL);
fctx->validator = ISC_LIST_HEAD(fctx->validators);
if (fctx->validator != NULL)
@@ -4277,7 +4342,7 @@ validated(isc_task_t *task, isc_event_t *event) {
dns_db_detachnode(fctx->cache, &node);
if (SHUTTINGDOWN(fctx))
bucket_empty = maybe_destroy(fctx, ISC_TRUE);
- UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&res->buckets[bucketnum].lock);
if (bucket_empty)
empty_bucket(res);
goto cleanup_event;
@@ -4294,7 +4359,7 @@ validated(isc_task_t *task, isc_event_t *event) {
* be validated.
*/
dns_db_detachnode(fctx->cache, &node);
- UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&res->buckets[bucketnum].lock);
dns_validator_send(ISC_LIST_HEAD(fctx->validators));
goto cleanup_event;
}
@@ -4377,7 +4442,7 @@ validated(isc_task_t *task, isc_event_t *event) {
if (node != NULL)
dns_db_detachnode(fctx->cache, &node);
- UNLOCK(&res->buckets[fctx->bucketnum].lock);
+ UNLOCK(&res->buckets[bucketnum].lock);
fctx_done(fctx, result, __LINE__); /* Locks bucket. */
cleanup_event:
@@ -4913,10 +4978,17 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
}
}
- if (valrdataset != NULL)
- result = valcreate(fctx, addrinfo, name, fctx->type,
- valrdataset, valsigrdataset, valoptions,
- task);
+ if (valrdataset != NULL) {
+ dns_rdatatype_t vtype = fctx->type;
+ if (CHAINING(valrdataset)) {
+ if (valrdataset->type == dns_rdatatype_cname)
+ vtype = dns_rdatatype_cname;
+ else
+ vtype = dns_rdatatype_dname;
+ }
+ result = valcreate(fctx, addrinfo, name, vtype, valrdataset,
+ valsigrdataset, valoptions, task);
+ }
if (result == ISC_R_SUCCESS && have_answer) {
fctx->attributes |= FCTX_ATTR_HAVEANSWER;
@@ -5657,7 +5729,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
char qbuf[DNS_NAME_FORMATSIZE];
char nbuf[DNS_NAME_FORMATSIZE];
char tbuf[DNS_RDATATYPE_FORMATSIZE];
- dns_rdatatype_format(fctx->type, tbuf,
+ dns_rdatatype_format(type, tbuf,
sizeof(tbuf));
dns_name_format(name, nbuf,
sizeof(nbuf));
@@ -5666,8 +5738,8 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
log_formerr(fctx,
"unrelated %s %s in "
"%s authority section",
- tbuf, qbuf, nbuf);
- return (DNS_R_FORMERR);
+ tbuf, nbuf, qbuf);
+ goto nextname;
}
if (type == dns_rdatatype_ns) {
/*
@@ -5730,6 +5802,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
}
}
}
+ nextname:
result = dns_message_nextname(message, section);
if (result == ISC_R_NOMORE)
break;
@@ -7015,21 +7088,33 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
* EDNS may not be supported so we can now cache the lack of
* EDNS support.
*/
- if (opt == NULL &&
+ if (opt == NULL && !EDNSOK(query->addrinfo) &&
(message->rcode == dns_rcode_noerror ||
message->rcode == dns_rcode_nxdomain ||
message->rcode == dns_rcode_refused ||
message->rcode == dns_rcode_yxdomain) &&
bad_edns(fctx, &query->addrinfo->sockaddr)) {
- char addrbuf[ISC_SOCKADDR_FORMATSIZE];
- isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf,
- sizeof(addrbuf));
dns_adb_changeflags(fctx->adb, query->addrinfo,
DNS_FETCHOPT_NOEDNS0,
DNS_FETCHOPT_NOEDNS0);
}
/*
+ * If we get a non error EDNS response record the fact so we
+ * won't fallback to plain DNS in the future for this server.
+ */
+ if (opt != NULL && !EDNSOK(query->addrinfo) &&
+ (query->options & DNS_FETCHOPT_NOEDNS0) == 0 &&
+ (message->rcode == dns_rcode_noerror ||
+ message->rcode == dns_rcode_nxdomain ||
+ message->rcode == dns_rcode_refused ||
+ message->rcode == dns_rcode_yxdomain)) {
+ dns_adb_changeflags(fctx->adb, query->addrinfo,
+ FCTX_ADDRINFO_EDNSOK,
+ FCTX_ADDRINFO_EDNSOK);
+ }
+
+ /*
* Deal with truncated responses by retrying using TCP.
*/
if ((message->flags & DNS_MESSAGEFLAG_TC) != 0)
@@ -7143,6 +7228,18 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
DNS_FETCHOPT_EDNSVERSIONSET;
mask = DNS_FETCHOPT_EDNSVERSIONMASK |
DNS_FETCHOPT_EDNSVERSIONSET;
+ /*
+ * Record that we got a good EDNS response.
+ */
+ if (query->ednsversion > (int)version &&
+ !EDNSOK(query->addrinfo)) {
+ dns_adb_changeflags(fctx->adb, query->addrinfo,
+ FCTX_ADDRINFO_EDNSOK,
+ FCTX_ADDRINFO_EDNSOK);
+ }
+ /*
+ * Record the supported EDNS version.
+ */
switch (version) {
case 0:
dns_adb_changeflags(fctx->adb, query->addrinfo,
@@ -7731,6 +7828,8 @@ dns_resolver_create(dns_view_t *view,
res->spillattimer = NULL;
res->zero_no_soa_ttl = ISC_FALSE;
res->query_timeout = DEFAULT_QUERY_TIMEOUT;
+ res->maxdepth = DEFAULT_RECURSION_DEPTH;
+ res->maxqueries = DEFAULT_MAX_QUERIES;
res->nbuckets = ntasks;
res->activebuckets = ntasks;
res->buckets = isc_mem_get(view->mctx,
@@ -8169,9 +8268,9 @@ dns_resolver_createfetch(dns_resolver_t *res, dns_name_t *name,
dns_rdataset_t *sigrdataset,
dns_fetch_t **fetchp)
{
- return (dns_resolver_createfetch2(res, name, type, domain,
+ return (dns_resolver_createfetch3(res, name, type, domain,
nameservers, forwarders, NULL, 0,
- options, task, action, arg,
+ options, 0, NULL, task, action, arg,
rdataset, sigrdataset, fetchp));
}
@@ -8187,6 +8286,25 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
dns_rdataset_t *sigrdataset,
dns_fetch_t **fetchp)
{
+ return (dns_resolver_createfetch3(res, name, type, domain,
+ nameservers, forwarders, client, id,
+ options, 0, NULL, task, action, arg,
+ rdataset, sigrdataset, fetchp));
+}
+
+isc_result_t
+dns_resolver_createfetch3(dns_resolver_t *res, dns_name_t *name,
+ dns_rdatatype_t type,
+ dns_name_t *domain, dns_rdataset_t *nameservers,
+ dns_forwarders_t *forwarders,
+ isc_sockaddr_t *client, dns_messageid_t id,
+ unsigned int options, unsigned int depth,
+ isc_counter_t *qc, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
+ dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset,
+ dns_fetch_t **fetchp)
+{
dns_fetch_t *fetch;
fetchctx_t *fctx = NULL;
isc_result_t result = ISC_R_SUCCESS;
@@ -8222,6 +8340,8 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
fetch = isc_mem_get(res->mctx, sizeof(*fetch));
if (fetch == NULL)
return (ISC_R_NOMEMORY);
+ fetch->mctx = NULL;
+ isc_mem_attach(res->mctx, &fetch->mctx);
bucketnum = dns_name_fullhash(name, ISC_FALSE) % res->nbuckets;
@@ -8273,11 +8393,12 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
if (fctx == NULL) {
result = fctx_create(res, name, type, domain, nameservers,
- options, bucketnum, &fctx);
+ options, bucketnum, depth, qc, &fctx);
if (result != ISC_R_SUCCESS)
goto unlock;
new_fctx = ISC_TRUE;
- }
+ } else if (fctx->depth > depth)
+ fctx->depth = depth;
result = fctx_join(fctx, task, client, id, action, arg,
rdataset, sigrdataset, fetch);
@@ -8312,7 +8433,7 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
FTRACE("created");
*fetchp = fetch;
} else
- isc_mem_put(res->mctx, fetch, sizeof(*fetch));
+ isc_mem_putanddetach(&fetch->mctx, fetch, sizeof(*fetch));
return (result);
}
@@ -8403,7 +8524,7 @@ dns_resolver_destroyfetch(dns_fetch_t **fetchp) {
UNLOCK(&res->buckets[bucketnum].lock);
- isc_mem_put(res->mctx, fetch, sizeof(*fetch));
+ isc_mem_putanddetach(&fetch->mctx, fetch, sizeof(*fetch));
*fetchp = NULL;
if (bucket_empty)
@@ -9049,3 +9170,27 @@ dns_resolver_settimeout(dns_resolver_t *resolver, unsigned int seconds) {
resolver->query_timeout = seconds;
}
+
+void
+dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ resolver->maxdepth = maxdepth;
+}
+
+unsigned int
+dns_resolver_getmaxdepth(dns_resolver_t *resolver) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ return (resolver->maxdepth);
+}
+
+void
+dns_resolver_setmaxqueries(dns_resolver_t *resolver, unsigned int queries) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ resolver->maxqueries = queries;
+}
+
+unsigned int
+dns_resolver_getmaxqueries(dns_resolver_t *resolver) {
+ REQUIRE(VALID_RESOLVER(resolver));
+ return (resolver->maxqueries);
+}