}
if (query->flags & QUERY_FORWARD) {
next->flags |= (QUERY_FORWARD | QUERY_AWAIT_CUT);
+ next->forward_flags |= QUERY_CNAME;
state = kr_nsrep_copy_set(&next->ns, &query->ns);
if (state != kr_ok()) {
return KR_STATE_FAIL;
} else {
next->flags |= QUERY_AWAIT_CUT;
}
+ next->cname_parent = query;
/* Want DNSSEC if and only if it's posible to secure
* this name (i.e. iff it is covered by a TA) */
if (kr_ta_covers_qry(req->ctx, cname, query->stype)) {
break; /* OK */
case KNOT_RCODE_REFUSED:
case KNOT_RCODE_SERVFAIL: {
- if (query->flags & QUERY_STUB) { break; } /* Pass through in stub mode */
+ if (query->flags & (QUERY_STUB | QUERY_FORWARD)) {
+ /* Pass through in stub mode */
+ break;
+ }
VERBOSE_MSG("<= rcode: %s\n", rcode ? rcode->name : "??");
query->fails += 1;
if (query->fails >= KR_QUERY_NSRETRY_LIMIT) {
VERBOSE_MSG(qry, "<= parent: updating DS\n");
if (qry->flags & (QUERY_DNSSEC_INSECURE)) { /* DS non-existence proven. */
mark_insecure_parents(qry);
- } if ((qry->flags & (QUERY_DNSSEC_NODS | QUERY_FORWARD)) == QUERY_DNSSEC_NODS) {
+ } else if ((qry->flags & (QUERY_DNSSEC_NODS | QUERY_FORWARD)) == QUERY_DNSSEC_NODS) {
mark_insecure_parents(qry);
} else { /* DS existence proven. */
parent->zone_cut.trust_anchor = knot_rrset_copy(qry->zone_cut.trust_anchor, parent->zone_cut.pool);
struct kr_request *req = ctx->req;
struct kr_query *qry = req->current_query;
const uint16_t qtype = knot_pkt_qtype(pkt);
-
+ const uint8_t pkt_rcode = knot_wire_get_rcode(pkt->wire);
bool nods = false;
for (int i = 0; i < req->rplan.resolved.len; ++i) {
struct kr_query *q = req->rplan.resolved.at[i];
}
}
- if (nods) {
+ if (nods && qtype == KNOT_RRTYPE_NS && !(qry->flags & QUERY_CNAME)) {
qry->flags &= ~QUERY_DNSSEC_WANT;
qry->flags |= QUERY_DNSSEC_INSECURE;
- if (qry->parent) {
- qry->parent->flags &= ~QUERY_DNSSEC_WANT;
- qry->parent->flags |= QUERY_DNSSEC_INSECURE;
+ if (qry->forward_flags & QUERY_CNAME) {
+ assert(qry->cname_parent);
+ qry->cname_parent->flags &= ~QUERY_DNSSEC_WANT;
+ qry->cname_parent->flags |= QUERY_DNSSEC_INSECURE;
+ } else if (pkt_rcode == KNOT_RCODE_NOERROR && qry->parent != NULL) {
+ const knot_pktsection_t *sec = knot_pkt_section(pkt, KNOT_ANSWER);
+ const knot_rrset_t *rr = knot_pkt_rr(sec, 0);
+ if (rr->type == KNOT_RRTYPE_NS) {
+ qry->parent->zone_cut.name = knot_dname_copy(rr->owner, &req->pool);
+ qry->parent->flags &= ~QUERY_DNSSEC_WANT;
+ qry->parent->flags |= QUERY_DNSSEC_INSECURE;
+ }
+ }
+ while (qry->parent) {
+ qry = qry->parent;
+ qry->flags &= ~QUERY_DNSSEC_WANT;
+ qry->flags |= QUERY_DNSSEC_INSECURE;
+ if (qry->forward_flags & QUERY_CNAME) {
+ assert(qry->cname_parent);
+ qry->cname_parent->flags &= ~QUERY_DNSSEC_WANT;
+ qry->cname_parent->flags |= QUERY_DNSSEC_INSECURE;
+ }
}
return KR_STATE_DONE;
}
- if (qtype != KNOT_RRTYPE_DS) {
+ if (!nods && qtype != KNOT_RRTYPE_DS) {
struct kr_rplan *rplan = &req->rplan;
struct kr_query *next = kr_rplan_push(rplan, qry, qry->sname, qry->sclass, KNOT_RRTYPE_DS);
int state = kr_nsrep_copy_set(&next->ns, &qry->ns);
qry->parent->flags &= ~QUERY_DNSSEC_WANT;
qry->parent->flags |= QUERY_DNSSEC_INSECURE;
}
- } else {
- qry->zone_cut.name = knot_dname_copy(signer, &req->pool);
+ } else if (qry->stype != KNOT_RRTYPE_DS) {
+ struct kr_rplan *rplan = &req->rplan;
+ struct kr_query *next = kr_rplan_push(rplan, qry, qry->sname, qry->sclass, KNOT_RRTYPE_DS);
+ int state = kr_nsrep_copy_set(&next->ns, &qry->ns);
+ if (state != kr_ok()) {
+ return KR_STATE_FAIL;
+ }
+ kr_zonecut_set(&next->zone_cut, qry->zone_cut.name);
+ kr_zonecut_copy_trust(&next->zone_cut, &qry->zone_cut);
+ next->flags |= QUERY_DNSSEC_WANT;
}
}
} else if (!knot_dname_is_equal(signer, qry->zone_cut.name)) {
rank_records(ctx, KR_RANK_OMIT);
return ctx->state;
}
+ uint8_t pkt_rcode = knot_wire_get_rcode(pkt->wire);
+ if ((qry->flags & QUERY_FORWARD) &&
+ pkt_rcode != KNOT_RCODE_NOERROR &&
+ pkt_rcode != KNOT_RCODE_NXDOMAIN) {
+ do {
+ qry->flags |= QUERY_DNSSEC_BOGUS;
+ if (qry->cname_parent) {
+ qry->cname_parent->flags |= QUERY_DNSSEC_BOGUS;
+ }
+ qry = qry->parent;
+ } while (qry);
+ ctx->state = KR_STATE_DONE;
+ return ctx->state;
+ }
+
if (!(qry->flags & QUERY_DNSSEC_WANT)) {
const uint32_t test_flags = (QUERY_CACHED | QUERY_DNSSEC_INSECURE);
const bool is_insec = ((qry->flags & test_flags) == test_flags);
}
/* Check if this is a DNSKEY answer, check trust chain and store. */
- uint8_t pkt_rcode = knot_wire_get_rcode(pkt->wire);
uint16_t qtype = knot_pkt_qtype(pkt);
bool has_nsec3 = pkt_has_type(pkt, KNOT_RRTYPE_NSEC3);
const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER);
qtype = KNOT_RRTYPE_DS;
}
/* Update parent query zone cut */
- if (qry->parent && pkt_rcode != KNOT_RCODE_NXDOMAIN) {
+ if (qry->parent) {
if (update_parent_keys(qry, qtype) != 0) {
return KR_STATE_FAIL;
}
}
-
- if (qry->flags & QUERY_FORWARD) {
- if (qry->parent &&
- qtype == KNOT_RRTYPE_NS &&
- !no_data &&
- pkt_rcode == KNOT_RCODE_NOERROR) {
- const knot_pktsection_t *sec = knot_pkt_section(pkt, KNOT_ANSWER);
- const knot_rrset_t *rr = knot_pkt_rr(sec, 0);
- if (rr->type == KNOT_RRTYPE_NS) {
- qry->parent->zone_cut.name = knot_dname_copy(rr->owner, &req->pool);
- qry->parent->flags &= ~QUERY_DNSSEC_WANT;
- qry->parent->flags |= QUERY_DNSSEC_INSECURE;
- }
+ if (qry->flags & QUERY_FORWARD && qry->parent) {
+ if (pkt_rcode == KNOT_RCODE_NXDOMAIN) {
+ qry->parent->forward_flags |= QUERY_NO_MINIMIZE;
}
}
VERBOSE_MSG(qry, "<= answer valid, OK\n");
map_t *trust_anchors = &request->ctx->trust_anchors;
map_t *negative_anchors = &request->ctx->negative_anchors;
+ if (qry->parent != NULL &&
+ !(qry->forward_flags & QUERY_CNAME) &&
+ knot_dname_in(qry->parent->zone_cut.name, qry->zone_cut.name)) {
+ return KR_STATE_PRODUCE;
+ }
+
assert(qry->flags & QUERY_FORWARD);
if (!trust_anchors) {
return KR_STATE_PRODUCE;
}
+ if (qry->forward_flags & QUERY_NO_MINIMIZE) {
+ qry->flags &= ~QUERY_AWAIT_CUT;
+ return KR_STATE_PRODUCE;
+ }
+
const knot_dname_t *wanted_name = qry->sname;
const knot_dname_t *start_name = qry->sname;
if ((qry->flags & QUERY_AWAIT_CUT) && !resume) {
+ qry->flags &= ~QUERY_AWAIT_CUT;
const knot_dname_t *longest_ta = kr_ta_get_longest_name(trust_anchors, qry->sname);
if (longest_ta) {
start_name = longest_ta;
qry->zone_cut.name = knot_dname_copy(start_name, qry->zone_cut.pool);
+ qry->flags |= QUERY_DNSSEC_WANT;
+ } else {
+ qry->flags &= ~QUERY_DNSSEC_WANT;
+ return KR_STATE_PRODUCE;
}
- qry->flags &= ~QUERY_AWAIT_CUT;
+ }
+
+ bool has_ta = (qry->zone_cut.trust_anchor != NULL);
+ knot_dname_t *ta_name = (has_ta ? qry->zone_cut.trust_anchor->owner : NULL);
+ bool refetch_ta = (!has_ta || !knot_dname_is_equal(qry->zone_cut.name, ta_name));
+ bool is_dnskey_subreq = kr_rplan_satisfies(qry, ta_name, KNOT_CLASS_IN, KNOT_RRTYPE_DNSKEY);
+ bool refetch_key = has_ta && (!qry->zone_cut.key || !knot_dname_is_equal(ta_name, qry->zone_cut.key->owner));
+ if (refetch_key && !is_dnskey_subreq) {
+ struct kr_query *next = zone_cut_subreq(rplan, qry, ta_name, KNOT_RRTYPE_DNSKEY);
+ if (!next) {
+ return KR_STATE_FAIL;
+ }
+ int state = kr_nsrep_copy_set(&next->ns, &qry->ns);
+ if (state != kr_ok()) {
+ return KR_STATE_FAIL;
+ }
+ return KR_STATE_DONE;
}
bool nods = false;
ns_req = false;
minimized = false;
- if (resume) {
- wanted_name = qry->zone_cut.name;
- } else if (qry->parent == NULL) {
- int cut_labels = knot_dname_labels(qry->zone_cut.name, NULL);
- int wanted_name_labels = knot_dname_labels(wanted_name, NULL);
- while (wanted_name[0] && wanted_name_labels > cut_labels + name_offset) {
- wanted_name = knot_wire_next_label(wanted_name, NULL);
- wanted_name_labels -= 1;
- }
- minimized = (wanted_name != qry->sname);
+ int cut_labels = knot_dname_labels(qry->zone_cut.name, NULL);
+ int wanted_name_labels = knot_dname_labels(wanted_name, NULL);
+ while (wanted_name[0] && wanted_name_labels > cut_labels + name_offset) {
+ wanted_name = knot_wire_next_label(wanted_name, NULL);
+ wanted_name_labels -= 1;
}
+ minimized = (wanted_name != qry->sname);
for (int i = 0; i < request->rplan.resolved.len; ++i) {
struct kr_query *q = request->rplan.resolved.at[i];
}
}
- if (qry->parent == NULL &&
- ds_req && !ns_req && (minimized || resume) &&
- !knot_dname_is_equal(qry->zone_cut.name, wanted_name)) {
+ if (ds_req && !ns_req && (minimized || resume)) {
struct kr_query *next = kr_rplan_push(rplan, qry, wanted_name,
qry->sclass, KNOT_RRTYPE_NS);
if (!next) {
nods = ds_req;
}
name_offset += 1;
- } while (ds_req && ns_req && !resume);
+ } while (ds_req && ns_req /* && !resume */ && minimized);
/* Disable DNSSEC if it enters NTA. */
if (kr_ta_get(negative_anchors, wanted_name)){
}
}
- const bool has_ta = (qry->zone_cut.trust_anchor != NULL);
- const knot_dname_t *ta_name = (has_ta ? qry->zone_cut.trust_anchor->owner : NULL);
- const bool refetch_ta = (!has_ta || !knot_dname_is_equal(wanted_name, ta_name));
+ has_ta = (qry->zone_cut.trust_anchor != NULL);
+ ta_name = (has_ta ? qry->zone_cut.trust_anchor->owner : NULL);
+ refetch_ta = (!has_ta || !knot_dname_is_equal(wanted_name, ta_name));
if (!nods && want_secured && refetch_ta) {
struct kr_query *next = kr_rplan_push(rplan, qry, wanted_name, qry->sclass, KNOT_RRTYPE_DS);
if (!next) {
/* Try to fetch missing DNSKEY.
* Do not fetch if this is a DNSKEY subrequest to avoid circular dependency. */
- const bool is_dnskey_subreq = kr_rplan_satisfies(qry, ta_name, KNOT_CLASS_IN, KNOT_RRTYPE_DNSKEY);
- const bool refetch_key = has_ta && (!qry->zone_cut.key || !knot_dname_is_equal(ta_name, qry->zone_cut.key->owner));
+ is_dnskey_subreq = kr_rplan_satisfies(qry, ta_name, KNOT_CLASS_IN, KNOT_RRTYPE_DNSKEY);
+ refetch_key = has_ta && (!qry->zone_cut.key || !knot_dname_is_equal(ta_name, qry->zone_cut.key->owner));
if (want_secured && refetch_key && !is_dnskey_subreq) {
struct kr_query *next = zone_cut_subreq(rplan, qry, ta_name, KNOT_RRTYPE_DNSKEY);
if (!next) {
}
return KR_STATE_DONE;
}
+
return KR_STATE_PRODUCE;
}
struct kr_nsrep ns;
struct kr_layer_pickle *deferred;
uint32_t uid; /**< Query iteration number, unique within the kr_rplan. */
+ uint32_t forward_flags;
+ struct kr_query *cname_parent;
};
/** @cond internal Array of queries. */