#include "lib/dnssec/nsec3.h"
#include "lib/dnssec/signature.h"
#include "lib/dnssec.h"
+#include "lib/resolve.h"
void kr_crypto_init(void)
{
dnssec_key_free((dnssec_key_t *) *key);
*key = NULL;
}
+
+int kr_dnssec_matches_name_and_type(const ranked_rr_array_t *rrs, uint32_t qry_uid,
+ const knot_dname_t *name, uint16_t type)
+{
+ int ret = kr_error(ENOENT);
+ for (size_t i = 0; i < rrs->len; ++i) {
+ const ranked_rr_array_entry_t *entry = rrs->at[i];
+ const knot_rrset_t *nsec = entry->rr;
+ if (entry->qry_uid != qry_uid || entry->yielded) {
+ continue;
+ }
+ if (nsec->type != KNOT_RRTYPE_NSEC &&
+ nsec->type != KNOT_RRTYPE_NSEC3) {
+ continue;
+ }
+ if (!kr_rank_test(entry->rank, KR_RANK_SECURE)) {
+ continue;
+ }
+ if (nsec->type == KNOT_RRTYPE_NSEC) {
+ ret = kr_nsec_matches_name_and_type(nsec, name, type);
+ } else {
+ ret = kr_nsec3_matches_name_and_type(nsec, name, type);
+ }
+ if (ret == kr_ok()) {
+ return kr_ok();
+ } else if (ret != kr_error(ENOENT)) {
+ return ret;
+ }
+ }
+ return ret;
+}
* @param key Pointer to freed key.
*/
void kr_dnssec_key_free(struct dseckey **key);
+
+/**
+ * Checks whether NSEC\NSEC3 RR selected by iterator matches the supplied name and type.
+ * @param request Records selected by iterator.
+ * @param qry_uid Query unique identifier where NSEC\NSEC3 belongs to.
+ * @param name Name to be checked.
+ * @param type Type to be checked.
+ * @return 0 or error code.
+ */
+int kr_dnssec_matches_name_and_type(const ranked_rr_array_t *rrs, uint32_t qry_uid,
+ const knot_dname_t *name, uint16_t type);
return kr_error(EINVAL);
}
+
+int kr_nsec_matches_name_and_type(const knot_rrset_t *nsec,
+ const knot_dname_t *name, uint16_t type)
+{
+ if (!nsec || !name) {
+ return (EINVAL);
+ }
+ if (!knot_dname_is_equal(nsec->owner, name)) {
+ return (ENOENT);
+ }
+ uint8_t *bm = NULL;
+ uint16_t bm_size = 0;
+ knot_nsec_bitmap(&nsec->rrs, &bm, &bm_size);
+ if (!bm) {
+ return kr_error(EINVAL);
+ }
+ if (!kr_nsec_bitmap_contains_type(bm, bm_size, type)) {
+ return (ENOENT);
+ }
+ return kr_ok();
+}
* EINVAL - bogus.
*/
int kr_nsec_ref_to_unsigned(const knot_pkt_t *pkt);
+
+/**
+ * Checks whether supplied NSEC RR matches the supplied name and type.
+ * @param nsec NSEC RR.
+ * @param name Name to be checked.
+ * @param type Type to be checked.
+ * @return 0 or error code.
+ */
+int kr_nsec_matches_name_and_type(const knot_rrset_t *nsec,
+ const knot_dname_t *name, uint16_t type);
return kr_error(EINVAL);
}
+int kr_nsec3_matches_name_and_type(const knot_rrset_t *nsec3,
+ const knot_dname_t *name, uint16_t type)
+{
+ int flags = 0;
+ int ret = matches_name_and_type(&flags, nsec3, name, type);
+ if (ret != kr_ok()) {
+ return ret;
+ }
+ return ((flags & (FLG_NAME_MATCHED | FLG_TYPE_BIT_MISSING)) != FLG_NAME_MATCHED) ?
+ kr_error(ENOENT) : kr_ok();
+}
* EINVAL - bogus.
*/
int kr_nsec3_ref_to_unsigned(const knot_pkt_t *pkt);
+
+/**
+ * Checks whether supplied NSEC3 RR matches the supplied name and type.
+ * @param nsec3 NSEC3 RR.
+ * @param name Name to be checked.
+ * @param type Type to be checked.
+ * @return 0 or error code.
+ */
+int kr_nsec3_matches_name_and_type(const knot_rrset_t *nsec3,
+ const knot_dname_t *name, uint16_t type);
}
}
-static int update_parent_keys(struct kr_query *qry, uint16_t answer_type)
+static int update_parent_keys(struct kr_request *req, uint16_t answer_type)
{
+ struct kr_query *qry = req->current_query;
struct kr_query *parent = qry->parent;
assert(parent);
switch(answer_type) {
if (qry->flags & (QUERY_DNSSEC_INSECURE)) { /* DS non-existence proven. */
mark_insecure_parents(qry);
} else if ((qry->flags & (QUERY_DNSSEC_NODS | QUERY_FORWARD)) == QUERY_DNSSEC_NODS) {
- mark_insecure_parents(qry);
+ if (qry->flags & QUERY_DNSSEC_OPTOUT) {
+ mark_insecure_parents(qry);
+ } else {
+ int ret = kr_dnssec_matches_name_and_type(&req->auth_selected, qry->uid,
+ qry->sname, KNOT_RRTYPE_NS);
+ if (ret == kr_ok()) {
+ mark_insecure_parents(qry);
+ }
+ }
+ } else if ((qry->flags & (QUERY_DNSSEC_NODS | QUERY_FORWARD | QUERY_DNSSEC_OPTOUT)) ==
+ (QUERY_DNSSEC_NODS | QUERY_FORWARD)) {
+ int ret = kr_dnssec_matches_name_and_type(&req->auth_selected, qry->uid,
+ qry->sname, KNOT_RRTYPE_NS);
+ if (ret == kr_ok()) {
+ 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);
if (!parent->zone_cut.trust_anchor) {
const uint16_t qtype = knot_pkt_qtype(pkt);
const uint8_t pkt_rcode = knot_wire_get_rcode(pkt->wire);
bool nods = false;
+ bool ns_exist = true;
for (int i = 0; i < req->rplan.resolved.len; ++i) {
struct kr_query *q = req->rplan.resolved.at[i];
if (q->sclass == qry->sclass &&
q->stype == KNOT_RRTYPE_DS &&
knot_dname_is_equal(q->sname, qry->sname)) {
nods = true;
+ if (!(q->flags & QUERY_DNSSEC_OPTOUT)) {
+ int ret = kr_dnssec_matches_name_and_type(&req->auth_selected, q->uid,
+ qry->sname, KNOT_RRTYPE_NS);
+ ns_exist = (ret == kr_ok());
+ }
}
}
- if (nods && qtype == KNOT_RRTYPE_NS && !(qry->flags & QUERY_CNAME)) {
+ if (nods && ns_exist && qtype == KNOT_RRTYPE_NS && !(qry->flags & QUERY_CNAME)) {
qry->flags &= ~QUERY_DNSSEC_WANT;
qry->flags |= QUERY_DNSSEC_INSECURE;
if (qry->forward_flags & QUERY_CNAME) {
return KR_STATE_DONE;
}
+ if (ctx->state == KR_STATE_YIELD) {
+ return KR_STATE_DONE;
+ }
+
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 ret = 0;
struct kr_request *req = ctx->req;
struct kr_query *qry = req->current_query;
+
/* Ignore faulty or unprocessed responses. */
if (ctx->state & (KR_STATE_FAIL|KR_STATE_CONSUME)) {
return ctx->state;
}
/* Update parent query zone cut */
if (qry->parent) {
- if (update_parent_keys(qry, qtype) != 0) {
+ if (update_parent_keys(req, qtype) != 0) {
return KR_STATE_FAIL;
}
}
#include "lib/rplan.h"
#include "lib/layer/iterate.h"
#include "lib/dnssec/ta.h"
+#include "lib/dnssec.h"
#if defined(ENABLE_COOKIES)
#include "lib/cookies/control.h"
#include "lib/cookies/helper.h"
bool nods = false;
bool ds_req = false;
bool ns_req = false;
+ bool ns_exist = true;
bool minimized = false;
int name_offset = 1;
do {
ds_req = false;
ns_req = false;
minimized = false;
+ ns_exist = true;
int cut_labels = knot_dname_labels(qry->zone_cut.name, NULL);
int wanted_name_labels = knot_dname_labels(wanted_name, NULL);
if (qry->flags & QUERY_DNSSEC_NODS) {
nods = true;
}
+ if (!(q->flags & QUERY_DNSSEC_OPTOUT)) {
+ int ret = kr_dnssec_matches_name_and_type(&request->auth_selected, q->uid,
+ wanted_name, KNOT_RRTYPE_NS);
+ ns_exist = (ret == kr_ok());
+ }
} else {
ns_req = true;
}
}
}
- if (ds_req && !ns_req && (minimized || resume)) {
+ if (ds_req && ns_exist && !ns_req && (minimized || resume)) {
struct kr_query *next = zone_cut_subreq(rplan, qry, wanted_name,
KNOT_RRTYPE_NS);
if (!next) {
nods = ds_req;
}
name_offset += 1;
- } while (ds_req && ns_req && minimized);
+ } while (ds_req && (ns_req || !ns_exist) && minimized);
/* Disable DNSSEC if it enters NTA. */
if (kr_ta_get(negative_anchors, wanted_name)){