#include <stdbool.h>
+#include <isc/job.h>
#include <isc/lang.h>
#include <isc/mutex.h>
+#include <isc/refcount.h>
#include <dns/fixedname.h>
#include <dns/rdataset.h>
* whatever purpose the client desires.
*/
struct dns_validator {
- /* Unlocked. */
- unsigned int magic;
- isc_mutex_t lock;
- dns_view_t *view;
+ /* Unlocked: */
+ unsigned int magic;
+ isc_mutex_t lock;
+ dns_view_t *view;
+ isc_loopmgr_t *loopmgr;
+
+ isc_refcount_t references;
/* Name and type of the response to be validated. */
dns_name_t *name;
dns_rdatatype_t type;
- /* Locked by lock. */
- unsigned int options;
- unsigned int attributes;
- dns_fetch_t *fetch;
- dns_validator_t *subvalidator;
- dns_validator_t *parent;
- dns_keytable_t *keytable;
- dst_key_t *key;
- dns_rdata_rrsig_t *siginfo;
- isc_loop_t *loop;
- isc_job_cb cb;
- void *arg;
- unsigned int labels;
- dns_rdataset_t *nxset;
- dns_rdataset_t *keyset;
- dns_rdataset_t *dsset;
- dns_rdataset_t fdsset;
- dns_rdataset_t frdataset;
- dns_rdataset_t fsigrdataset;
- dns_fixedname_t fname;
- dns_fixedname_t wild;
- dns_fixedname_t closest;
- ISC_LINK(dns_validator_t) link;
- bool mustbesecure;
- unsigned int depth;
- unsigned int authcount;
- unsigned int authfail;
- isc_stdtime_t start;
+ /*
+ * Callback and argument to use to inform the caller
+ * that validation is complete.
+ */
+ isc_job_cb cb;
+ void *arg;
+
+ /* Locked by 'lock': */
+ /* Validation options (_DEFER, _NONTA, etc). */
+ unsigned int options;
/*
* Results of a completed validation.
* Answer is secure.
*/
bool secure;
+
+ /* Internal validator state */
+ unsigned int attributes;
+ dns_fetch_t *fetch;
+ dns_validator_t *subvalidator;
+ dns_validator_t *parent;
+ dns_keytable_t *keytable;
+ dst_key_t *key;
+ dns_rdata_rrsig_t *siginfo;
+ unsigned int labels;
+ dns_rdataset_t *nxset;
+ dns_rdataset_t *keyset;
+ dns_rdataset_t *dsset;
+ dns_rdataset_t fdsset;
+ dns_rdataset_t frdataset;
+ dns_rdataset_t fsigrdataset;
+ dns_fixedname_t fname;
+ dns_fixedname_t wild;
+ dns_fixedname_t closest;
+ ISC_LINK(dns_validator_t) link;
+ bool mustbesecure;
+ unsigned int depth;
+ unsigned int authcount;
+ unsigned int authfail;
+ isc_stdtime_t start;
};
/*%
dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_message_t *message, unsigned int options,
- isc_loop_t *loop, isc_job_cb cb, void *arg,
+ isc_loopmgr_t *loop, isc_job_cb cb, void *arg,
dns_validator_t **validatorp);
/*%<
* Start a DNSSEC validation.
* Requires:
*\li '*validatorp' points to a valid DNSSEC validator.
* \li The validator must have completed and sent its completion
- * event.
+ * event.
*
* Ensures:
*\li All resources used by the validator are freed.
*/
+#if DNS_VALIDATOR_TRACE
+#define dns_validator_ref(ptr) \
+ dns_validator__ref(ptr, __func__, __FILE__, __LINE__)
+#define dns_validator_unref(ptr) \
+ dns_validator__unref(ptr, __func__, __FILE__, __LINE__)
+#define dns_validator_attach(ptr, ptrp) \
+ dns_validator__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
+#define dns_validator_detach(ptrp) \
+ dns_validator__detach(ptrp, __func__, __FILE__, __LINE__)
+ISC_REFCOUNT_TRACE_DECL(dns_validator);
+#else
+ISC_REFCOUNT_DECL(dns_validator);
+#endif
+
ISC_LANG_ENDDECLS
static isc_result_t
valcreate(fetchctx_t *fctx, dns_message_t *message, dns_adbaddrinfo_t *addrinfo,
dns_name_t *name, dns_rdatatype_t type, dns_rdataset_t *rdataset,
- dns_rdataset_t *sigrdataset, unsigned int valoptions,
- isc_loop_t *loop) {
+ dns_rdataset_t *sigrdataset, unsigned int valoptions) {
dns_validator_t *validator = NULL;
dns_valarg_t *valarg = NULL;
isc_result_t result;
valoptions &= ~DNS_VALIDATOR_DEFER;
}
- result = dns_validator_create(fctx->res->view, name, type, rdataset,
- sigrdataset, message, valoptions, loop,
- validated, valarg, &validator);
+ result = dns_validator_create(
+ fctx->res->view, name, type, rdataset, sigrdataset, message,
+ valoptions, fctx->res->loopmgr, validated, valarg, &validator);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
inc_stats(fctx->res, dns_resstatscounter_val);
if ((valoptions & DNS_VALIDATOR_DEFER) == 0) {
result = valcreate(
fctx, message, addrinfo, name,
rdataset->type, rdataset,
- sigrdataset, valoptions,
- fctx->loop);
+ sigrdataset, valoptions);
}
} else if (CHAINING(rdataset)) {
if (rdataset->type == dns_rdatatype_cname) {
}
result = valcreate(fctx, message, addrinfo, name, vtype,
- valrdataset, valsigrdataset, valoptions,
- fctx->loop);
+ valrdataset, valsigrdataset, valoptions);
}
if (result == ISC_R_SUCCESS && have_answer) {
* Do negative response validation.
*/
result = valcreate(fctx, message, addrinfo, name, fctx->type,
- NULL, NULL, valoptions, fctx->loop);
+ NULL, NULL, valoptions);
/*
* If validation is necessary, return now. Otherwise
* continue to process the message, letting the
#include <isc/async.h>
#include <isc/base32.h>
+#include <isc/job.h>
#include <isc/md.h>
#include <isc/mem.h>
+#include <isc/refcount.h>
#include <isc/result.h>
#include <isc/string.h>
#include <isc/util.h>
#define VALIDATOR_MAGIC ISC_MAGIC('V', 'a', 'l', '?')
#define VALID_VALIDATOR(v) ISC_MAGIC_VALID(v, VALIDATOR_MAGIC)
-#define VALATTR_SHUTDOWN 0x0001 /*%< Shutting down. */
#define VALATTR_CANCELED 0x0002 /*%< Canceled. */
#define VALATTR_TRIEDVERIFY \
0x0004 /*%< We have found a key and \
#define FOUNDCLOSEST(val) ((val->attributes & VALATTR_FOUNDCLOSEST) != 0)
#define FOUNDOPTOUT(val) ((val->attributes & VALATTR_FOUNDOPTOUT) != 0)
-#define SHUTDOWN(v) (((v)->attributes & VALATTR_SHUTDOWN) != 0)
#define CANCELED(v) (((v)->attributes & VALATTR_CANCELED) != 0)
#define COMPLETE(v) (((v)->attributes & VALATTR_COMPLETE) != 0)
#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
static void
-destroy(dns_validator_t *val);
+destroy_validator(dns_validator_t *val);
static isc_result_t
select_signing_key(dns_validator_t *val, dns_rdataset_t *rdataset);
val->secure = true;
}
+static void
+validator_done_cb(void *arg) {
+ dns_validator_t *val = arg;
+ val->cb(val);
+ dns_validator_detach(&val);
+}
+
/*
* Validator 'val' is finished; send the completion event to the loop
* that called dns_validator_create(), with result `result`.
val->attributes |= VALATTR_COMPLETE;
val->result = result;
- isc_async_run(val->loop, val->cb, val);
-}
-
-/*
- * Called when deciding whether to destroy validator 'val'.
- */
-static bool
-exit_check(dns_validator_t *val) {
- /*
- * Caller must be holding the lock.
- */
- if (!SHUTDOWN(val)) {
- return (false);
- }
- if (val->fetch != NULL || val->subvalidator != NULL) {
- return (false);
- }
-
- return (true);
+ dns_validator_ref(val);
+ isc_job_run(val->loopmgr, validator_done_cb, val);
}
/*%
isc_result_t result;
isc_result_t saved_result;
dns_fetch_t *fetch = NULL;
- bool want_destroy;
INSIST(resp->type == FETCHDONE);
validator_done(val, DNS_R_BROKENCHAIN);
}
}
-
- want_destroy = exit_check(val);
UNLOCK(&val->lock);
if (fetch != NULL) {
dns_resolver_destroyfetch(&fetch);
}
- if (want_destroy) {
- destroy(val);
- }
+ dns_validator_detach(&val);
}
/*%
isc_result_t eresult = resp->result;
isc_result_t result;
dns_fetch_t *fetch = NULL;
- bool want_destroy, trustchain;
+ bool trustchain;
INSIST(resp->type == FETCHDONE);
done:
isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
- want_destroy = exit_check(val);
UNLOCK(&val->lock);
if (fetch != NULL) {
dns_resolver_destroyfetch(&fetch);
}
- if (want_destroy) {
- destroy(val);
- }
+ dns_validator_detach(&val);
}
/*%
isc_result_t result;
isc_result_t eresult = subvalidator->result;
isc_result_t saved_result;
- bool want_destroy;
val->subvalidator = NULL;
+ subvalidator->parent = NULL;
validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_dnskey");
LOCK(&val->lock);
validator_done(val, DNS_R_BROKENCHAIN);
}
- dns_validator_destroy(&subvalidator);
-
- want_destroy = exit_check(val);
UNLOCK(&val->lock);
- if (want_destroy) {
- destroy(val);
- }
+
+ dns_validator_destroy(&subvalidator);
+ dns_validator_detach(&val);
}
/*%
dns_validator_t *val = subvalidator->parent;
isc_result_t result;
isc_result_t eresult = subvalidator->result;
- bool want_destroy;
val->subvalidator = NULL;
+ subvalidator->parent = NULL;
validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_ds");
LOCK(&val->lock);
isc_result_totext(eresult));
validator_done(val, DNS_R_BROKENCHAIN);
}
+ UNLOCK(&val->lock);
dns_validator_destroy(&subvalidator);
-
- want_destroy = exit_check(val);
- UNLOCK(&val->lock);
- if (want_destroy) {
- destroy(val);
- }
+ dns_validator_detach(&val);
}
/*%
dns_validator_t *val = subvalidator->parent;
isc_result_t result;
isc_result_t eresult = subvalidator->result;
- bool want_destroy;
INSIST((val->attributes & VALATTR_INSECURITY) != 0);
validator_done(val, DNS_R_BROKENCHAIN);
}
- dns_validator_destroy(&subvalidator);
-
- want_destroy = exit_check(val);
UNLOCK(&val->lock);
- if (want_destroy) {
- destroy(val);
- }
+
+ dns_validator_destroy(&subvalidator);
+ dns_validator_detach(&val);
}
/*%
dns_rdataset_t *rdataset = subvalidator->rdataset;
isc_result_t result = subvalidator->result;
bool exists, data;
- bool want_destroy;
val->subvalidator = NULL;
}
}
- dns_validator_destroy(&subvalidator);
-
- want_destroy = exit_check(val);
UNLOCK(&val->lock);
- if (want_destroy) {
- destroy(val);
- }
+
+ dns_validator_destroy(&subvalidator);
+ dns_validator_detach(&val);
}
/*%
}
validator_logcreate(val, name, type, caller, "fetch");
+
+ dns_validator_ref(val);
return (dns_resolver_createfetch(
val->view->resolver, name, type, NULL, NULL, NULL, NULL, 0,
- fopts, 0, NULL, val->loop, callback, val, &val->frdataset,
- &val->fsigrdataset, &val->fetch));
+ fopts, 0, NULL, isc_loop_current(val->loopmgr), callback, val,
+ &val->frdataset, &val->fsigrdataset, &val->fetch));
}
/*%
validator_logcreate(val, name, type, caller, "validator");
result = dns_validator_create(val->view, name, type, rdataset, sig,
- NULL, vopts, val->loop, cb, val,
+ NULL, vopts, val->loopmgr, cb, val,
&val->subvalidator);
if (result == ISC_R_SUCCESS) {
- val->subvalidator->parent = val;
+ dns_validator_attach(val, &val->subvalidator->parent);
val->subvalidator->depth = val->depth + 1;
}
return (result);
dns_rdatatype_dnskey,
fetch_callback_dnskey, "seek_dnskey");
if (result != ISC_R_SUCCESS) {
+ dns_validator_detach(&val);
return (result);
}
return (DNS_R_WAIT);
fetch_callback_ds, "validate_dnskey");
*resp = DNS_R_WAIT;
if (result != ISC_R_SUCCESS) {
+ dns_validator_detach(&val);
*resp = result;
}
return (ISC_R_COMPLETE);
static void
validator_start(void *arg) {
dns_validator_t *val = (dns_validator_t *)arg;
- bool want_destroy = false;
isc_result_t result = ISC_R_FAILURE;
if (CANCELED(val)) {
}
if (result != DNS_R_WAIT) {
- want_destroy = exit_check(val);
validator_done(val, result);
}
UNLOCK(&val->lock);
- if (want_destroy) {
- destroy(val);
- }
+
+ dns_validator_detach(&val);
}
isc_result_t
dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
dns_message_t *message, unsigned int options,
- isc_loop_t *loop, isc_job_cb cb, void *arg,
+ isc_loopmgr_t *loopmgr, isc_job_cb cb, void *arg,
dns_validator_t **validatorp) {
isc_result_t result = ISC_R_FAILURE;
dns_validator_t *val = NULL;
.type = type,
.options = options,
.link = ISC_LINK_INITIALIZER,
- .loop = loop,
+ .loopmgr = loopmgr,
.cb = cb,
.arg = arg };
+
+ isc_refcount_init(&val->references, 1);
+
if (message != NULL) {
dns_message_attach(message, &val->message);
}
val->magic = VALIDATOR_MAGIC;
if ((options & DNS_VALIDATOR_DEFER) == 0) {
- isc_async_run(loop, validator_start, val);
+ dns_validator_ref(val);
+ isc_job_run(val->loopmgr, validator_start, val);
}
*validatorp = val;
validator->options &= ~DNS_VALIDATOR_DEFER;
UNLOCK(&validator->lock);
- isc_async_run(validator->loop, validator_start, validator);
+ dns_validator_ref(validator);
+ isc_job_run(validator->loopmgr, validator_start, validator);
}
void
}
static void
-destroy(dns_validator_t *val) {
+destroy_validator(dns_validator_t *val) {
isc_mem_t *mctx = NULL;
- REQUIRE(SHUTDOWN(val));
REQUIRE(val->fetch == NULL);
+ REQUIRE(val->subvalidator == NULL);
val->magic = 0;
if (val->key != NULL) {
void
dns_validator_destroy(dns_validator_t **validatorp) {
dns_validator_t *val = NULL;
- bool want_destroy = false;
REQUIRE(validatorp != NULL);
REQUIRE(VALID_VALIDATOR(val));
LOCK(&val->lock);
-
- val->attributes |= VALATTR_SHUTDOWN;
validator_log(val, ISC_LOG_DEBUG(4), "dns_validator_destroy");
-
- want_destroy = exit_check(val);
UNLOCK(&val->lock);
- if (want_destroy) {
- destroy(val);
- }
+
+ dns_validator_detach(&val);
}
static void
validator_log(val, ISC_LOG_DEBUG(9), "%s: creating %s for %s %s",
caller, operation, namestr, typestr);
}
+
+#if DNS_VALIDATOR_TRACE
+ISC_REFCOUNT_TRACE_IMPL(dns_validator, destroy_validator);
+#else
+ISC_REFCOUNT_IMPL(dns_validator, destroy_validator);
+#endif