*/
dns_name_t *name;
dns_rdatatype_t type;
+
+ /*
+ * Original query type (may differ from type in the case
+ * of CNAME responses).
+ */
+ dns_rdatatype_t origtype;
+
/*
* Rdata and RRSIG (if any) for positive responses.
*/
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_task_t *task, isc_taskaction_t action, void *arg,
+ dns_rdatatype_t origtype, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset, dns_message_t *message,
+ unsigned int options, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
dns_validator_t **validatorp);
/*%<
* Start a DNSSEC validation.
*
- * This validates a response to the question given by
- * 'name' and 'type'.
+ * This validates a response RRset matching owner 'name' and type 'type'.
*
- * To validate a positive response, the response data is
+ * When validating a positive response, the response data is
* given by 'rdataset' and 'sigrdataset'. If 'sigrdataset'
* is NULL, the data is presumed insecure and an attempt
* is made to prove its insecurity by finding the appropriate
* is implemented yet). If the complete response message
* is not available, 'message' is NULL.
*
- * To validate a negative response, the complete negative response
- * message is given in 'message'. The 'rdataset', and
+ * When validating a negative response, the complete negative
+ * response message is given in 'message'. The 'rdataset', and
* 'sigrdataset' arguments must be NULL, but the 'name' and 'type'
* arguments must be provided.
*
+ * 'origtype' is the original query type that generated this
+ * response. This may differ from 'type', if 'type' is CNAME.
+ * This is used for loop detection, to prevent a case in
+ * which a validator attempts to restart the same fetch that was
+ * already waiting for the validator.
+ *
* The validation is performed in the context of 'view'.
*
* When the validation finishes, a dns_validatorevent_t with
dns_name_t *name, dns_rdatatype_t type, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset, unsigned int valoptions,
isc_task_t *task) {
- dns_validator_t *validator = NULL;
- dns_valarg_t *valarg;
isc_result_t result;
+ dns_validator_t *validator = NULL;
+ dns_valarg_t *valarg = NULL;
+ dns_rdatatype_t origtype = dns_rdatatype_none;
valarg = isc_mem_get(fctx->mctx, sizeof(*valarg));
valoptions &= ~DNS_VALIDATOR_DEFER;
}
- result = dns_validator_create(fctx->res->view, name, type, rdataset,
- sigrdataset, message, valoptions, task,
- validated, valarg, &validator);
+ if (type == dns_rdatatype_cname) {
+ origtype = fctx->type;
+ }
+ result = dns_validator_create(
+ fctx->res->view, name, type, origtype, rdataset, sigrdataset,
+ message, valoptions, task, validated, valarg, &validator);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
if (result == ISC_R_SUCCESS) {
inc_stats(fctx->res, dns_resstatscounter_val);
static inline bool
check_deadlock(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
- dns_validator_t *parent;
+ dns_validator_t *parent = NULL;
for (parent = val; parent != NULL; parent = parent->parent) {
- if (parent->event != NULL && parent->event->type == type &&
+ if (parent->event == NULL) {
+ continue;
+ }
+
+ if ((parent->event->type == type ||
+ (parent->event->type == dns_rdatatype_cname &&
+ parent->event->origtype == type)) &&
dns_name_equal(parent->event->name, name) &&
/*
* As NSEC3 records are meta data you sometimes
* need to prove a NSEC3 record which says that
* itself doesn't exist.
*/
- (parent->event->type != dns_rdatatype_nsec3 ||
- rdataset == NULL || sigrdataset == NULL ||
- parent->event->message == NULL ||
+ (type != dns_rdatatype_nsec3 || rdataset == NULL ||
+ sigrdataset == NULL || parent->event->message == NULL ||
parent->event->rdataset != NULL ||
parent->event->sigrdataset != NULL))
{
(DNS_VALIDATOR_NOCDFLAG | DNS_VALIDATOR_NONTA));
validator_logcreate(val, name, type, caller, "validator");
- result = dns_validator_create(val->view, name, type, rdataset, sig,
- NULL, vopts, val->task, action, val,
- &val->subvalidator);
+ result = dns_validator_create(val->view, name, type, dns_rdatatype_none,
+ rdataset, sig, NULL, vopts, val->task,
+ action, val, &val->subvalidator);
if (result == ISC_R_SUCCESS) {
val->subvalidator->parent = val;
val->subvalidator->depth = val->depth + 1;
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_task_t *task, isc_taskaction_t action, void *arg,
+ dns_rdatatype_t origtype, dns_rdataset_t *rdataset,
+ dns_rdataset_t *sigrdataset, dns_message_t *message,
+ unsigned int options, isc_task_t *task,
+ isc_taskaction_t action, void *arg,
dns_validator_t **validatorp) {
isc_result_t result = ISC_R_FAILURE;
dns_validator_t *val;
event->result = ISC_R_FAILURE;
event->name = name;
event->type = type;
+ event->origtype = origtype;
event->rdataset = rdataset;
event->sigrdataset = sigrdataset;
event->message = message;