break;
case KNOT_RRTYPE_DS:
VERBOSE_MSG(qry, "<= parent: updating DS\n");
- if (qry->flags & (QUERY_DNSSEC_NODS | QUERY_DNSSEC_INSECURE)) { /* DS non-existence proven. */
+ 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) {
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);
return ((an->count != 0) && (num_entries == 0)) ? false : true;
}
-static void unsigned_forward(kr_layer_t *ctx, knot_pkt_t *pkt)
+static int unsigned_forward(kr_layer_t *ctx, knot_pkt_t *pkt)
{
struct kr_request *req = ctx->req;
struct kr_query *qry = req->current_query;
const uint16_t qtype = knot_pkt_qtype(pkt);
+ printf("unsigned forward\n");
+
+/*
if (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);
return;
}
return;
-
-
- /* We are in forwarding mode and have got unsigned answer.
- * Check if answer is empty or not */
- if ((qtype == KNOT_RRTYPE_DS) || (qtype == KNOT_RRTYPE_RRSIG)) {
- /* We are already trying to detect zone security status.
- * Answer for DS \ RRSIG query can contains
- * CNAME instead of target qtype.
- * Ask for DS for parent zone in this case */
- if ((knot_pkt_section(pkt, KNOT_ANSWER)->count != 0) &&
- !(qry->flags & QUERY_CNAME)) {
- /* Answer isn't empty and doesn't contain CNAME.
- * Do nothing */
- return;
+*/
+// if (qtype == KNOT_RRTYPE_NS) {
+ printf("KNOT_RRTYPE_NS\n");
+ bool nods = false;
+ bool ds_req = false;
+ for (int i = 0; i < req->rplan.resolved.len; ++i) {
+ struct kr_query *q = req->rplan.resolved.at[i];
+ kr_dname_print(q->sname, "q: ", " ");
+ kr_dname_print(qry->sname, "qry: ", " ");
+ kr_rrtype_print(q->stype, "type: ", "\n");
+ if (/* q->parent == qry && */
+ q->sclass == qry->sclass &&
+ q->stype == KNOT_RRTYPE_DS &&
+ knot_dname_is_equal(q->sname, qry->sname)) {
+ ds_req = true;
+ printf("DSREQ\n");
+ if (q->flags & QUERY_DNSSEC_NODS) {
+ printf("NODS\n");
+ nods = true;
+ }
+ }
}
- } else if ((knot_pkt_section(pkt, KNOT_ANSWER)->count != 0) &&
- !(qry->flags & QUERY_CNAME)) {
- /* Answer isn't empty. */
- return;
- }
-
- /* AUTHORITY can contain SOA */
- if (knot_pkt_section(pkt, KNOT_AUTHORITY)->count > 1) {
- return;
- }
- const knot_dname_t *qname = NULL;
- bool has_soa = false;
- if (knot_pkt_section(pkt, KNOT_AUTHORITY)->count == 1) {
- const knot_pktsection_t *sec = knot_pkt_section(pkt, KNOT_AUTHORITY);
- const knot_rrset_t *rr = knot_pkt_rr(sec, 0);
- if (rr->type != KNOT_RRTYPE_SOA) {
- return;
+ if (nods) {
+ printf("NODS return\n");
+ 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;
+ }
+ return KR_STATE_DONE;
}
- qname = rr->owner;
- has_soa = true;
- }
+// }
- /* check_signer() is going to return KR_STATE_YIELD.
- * This will cause refetching DS for current zone name by check_trust_chain()
- * (i.e. - we do not receive RRSIG at all and
- * want to figure out with zone security status).
- * Here we set current zone name. When qtype is :
- * 1) RRSIG + SOA - use SOA owner
- * 2) RRSIG - use qname
- * 3) DS + SOA - next-label(SOA owner)
- * 4) DS - use next-label(qname) */
if (qtype != KNOT_RRTYPE_DS) {
- /* We have got empty answer.
- * It is necessary to figure out with zone security status.
- * If there is SOA. use SOA owner since it is exact zone name.
- * If no, try the owner of packet qname. */
- if (!has_soa) {
- qname = knot_pkt_qname(pkt);
- }
- } else {
- /* We already trying to figure out with security status.
- * In previous steps DS query was spawned.
- * Here we have got empty answer for DS query.
- * If there is SOA. use next-label (SOA owner),
- * otherwise use next-label (packet qname) */
- if (has_soa) {
- if (knot_dname_is_equal(qname, knot_pkt_qname(pkt)) && qname[0] != '\0') {
- qname = knot_wire_next_label(qname, NULL);
- }
- } else {
- qname = knot_pkt_qname(pkt);
- if (qname[0] != '\0') {
- qname = knot_wire_next_label(qname, NULL);
- }
+ 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;
}
- if (qname[0] != '\0') {
- qry->zone_cut.name = knot_dname_copy(qname, &req->pool);
- }
-
- return;
+ return KR_STATE_YIELD;
}
static int check_signer(kr_layer_t *ctx, knot_pkt_t *pkt)
if (ta_name && (!signer || !knot_dname_is_equal(ta_name, signer))) {
/* check all newly added RRSIGs */
if (!signer) {
+ if (qry->flags & QUERY_FORWARD) {
+ return unsigned_forward(ctx, pkt);
+ }
/* Not a DNSSEC-signed response. */
if (ctx->state == KR_STATE_YIELD) {
/* Already yielded for revalidation.
* It means that trust chain is OK and
* transition to INSECURE hasn't occured.
* Let the validation logic ask about RRSIG. */
+ printf("already yielded\n");
return KR_STATE_DONE;
}
/* Ask parent for DS
* for both parent and child,
* and child zone is not signed. */
qry->zone_cut.name = knot_dname_copy(qname, &req->pool);
- } else if (qry->flags & QUERY_FORWARD) {
- unsigned_forward(ctx, pkt);
- return KR_STATE_YIELD;
}
} else if (knot_dname_is_sub(signer, qry->zone_cut.name)) {
/* Key signer is below current cut, advance and refetch keys. */
- qry->zone_cut.name = knot_dname_copy(signer, &req->pool);
+ if (!(qry->flags & QUERY_FORWARD)) {
+ qry->zone_cut.name = knot_dname_copy(signer, &req->pool);
+ } else {
+ for (int i = 0; i < req->rplan.resolved.len; ++i) {
+ struct kr_query *q = req->rplan.resolved.at[i];
+ if (/* q->parent == qry && */
+ q->sclass == qry->sclass &&
+ q->stype == KNOT_RRTYPE_DS &&
+ knot_dname_is_equal(q->sname, signer)) {
+ printf("DSREQQQQ\n");
+ if (q->flags & QUERY_DNSSEC_NODS) {
+ 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;
+ }
+ }
+ }
+ }
+ }
} else if (!knot_dname_is_equal(signer, qry->zone_cut.name)) {
/* Key signer is above the current cut, so we can't validate it. This happens when
a server is authoritative for both grandparent, parent and child zone.
} /* else zone cut matches, but DS/DNSKEY doesn't => refetch. */
if (qry->stype != KNOT_RRTYPE_DS) {
/* zone cut matches, but DS/DNSKEY doesn't => refetch. */
+ printf("sheck_signer\n");
VERBOSE_MSG(qry, ">< cut changed, needs revalidation\n");
return KR_STATE_YIELD;
}
if (ret != KR_STATE_DONE) {
return ret;
}
+ if ((qry->flags & (QUERY_FORWARD | QUERY_DNSSEC_INSECURE)) ==
+ (QUERY_FORWARD | QUERY_DNSSEC_INSECURE)) {
+ return KR_STATE_DONE;
+ }
}
if (knot_wire_get_aa(pkt->wire) && qtype == KNOT_RRTYPE_DNSKEY) {
ret = validate_keyset(req, pkt, has_nsec3);
if (ret == kr_error(EAGAIN)) {
+ printf("validate\n");
VERBOSE_MSG(qry, ">< cut changed, needs revalidation\n");
return KR_STATE_YIELD;
} else if (ret != 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;
+ }
+ }
+ }
VERBOSE_MSG(qry, "<= answer valid, OK\n");
return KR_STATE_DONE;
}
return next;
}
-static int forward_trust_chain_check(struct kr_request *request, struct kr_query *qry, bool resume)
+static int forward_trust_chain_check(struct kr_request *request, struct kr_query *qry, bool resume, knot_pkt_t *packet)
{
struct kr_rplan *rplan = &request->rplan;
map_t *trust_anchors = &request->ctx->trust_anchors;
return KR_STATE_PRODUCE;
}
- const knot_dname_t* wanted_name = qry->zone_cut.name;
+// if (qry->parent != NULL) {
+// return KR_STATE_PRODUCE;
+// }
+
bool nods = false;
- if (qry->parent == NULL && !resume) {
- wanted_name = qry->sname;
+ bool ds_req = false;
+ bool ns_req = false;
+ bool minimized = false;
+// const knot_dname_t* wanted_name = qry->zone_cut.name;
+ const knot_dname_t* wanted_name = NULL;
+ int name_offset = 1;
+ while (1) {
+ wanted_name = qry->sname;
+ nods = false;
+ ds_req = false;
+ ns_req = false;
+ minimized = false;
+ kr_dname_print(qry->zone_cut.name, "cut_name: ", " ");
+ kr_dname_print(qry->sname, "sname: ", " ");
+ kr_rrtype_print(qry->stype, "type: ", "\n");
+ if (qry->parent == NULL /* && !resume */) {
+// 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 + 1) {
+ while(wanted_name[0] && wanted_name_labels > cut_labels + name_offset) {
wanted_name = knot_wire_next_label(wanted_name, NULL);
wanted_name_labels -= 1;
}
- nods = (wanted_name == qry->sname);
- }
+ 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 (q->parent == qry &&
+ q->sclass == qry->sclass &&
+ (q->stype == KNOT_RRTYPE_DS || q->stype == KNOT_RRTYPE_NS) &&
+ knot_dname_is_equal(q->sname, wanted_name)) {
+ if (q->stype == KNOT_RRTYPE_DS) {
+ ds_req = true;
+ if (qry->flags & QUERY_DNSSEC_NODS) {
+ nods = true;
+ }
+ } else {
+ ns_req = true;
+ }
+ }
+ }
- for (int i = 0; i < request->rplan.resolved.len; ++i) {
- struct kr_query *q = request->rplan.resolved.at[i];
- if (q->parent == qry &&
- q->sclass == qry->sclass &&
- q->stype == KNOT_RRTYPE_DS &&
- (q->flags & QUERY_DNSSEC_NODS) &&
- knot_dname_is_equal(q->sname, wanted_name)) {
- nods = true;
- VERBOSE_MSG(qry, "stop chasing trust chain\n");
+ if (qry->parent == NULL /* && !resume */) {
+ printf("initial request ds_req %i ns_req %i\n", ds_req, ns_req);
+
+ if (ds_req && !ns_req && minimized) {
+ struct kr_query *next = kr_rplan_push(rplan, qry, wanted_name, qry->sclass, KNOT_RRTYPE_NS);
+ if (!next) {
+ return KR_STATE_FAIL;
+ }
+ 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;
+ return KR_STATE_DONE;
+ }
+ }
+ kr_dname_print(wanted_name, "wanted_name: ", " ");
+ printf("resume? %i\n", resume);
+
+ if ((qry->stype == KNOT_RRTYPE_DS) &&
+ knot_dname_is_equal(wanted_name, qry->sname)) {
+ printf("if1\n");
+ nods = true;
+ } else if (resume && !ds_req) {
+ printf("if2\n");
+ nods = false;
+ } else if (!minimized) {
+ printf("if3\n");
+ nods = true;
+ } else {
+ printf("if4\n");
+ nods = ds_req;
+ }
+ if (ds_req && ns_req) {
+ name_offset += 1;
+ } else {
break;
}
}
-
- nods = nods ||
- ((qry->stype == KNOT_RRTYPE_DS) &&
- knot_dname_is_equal(wanted_name, qry->sname));
+ printf("ds_req %i ns_req %i nods? %i\n", ds_req, ns_req, nods);
/* Disable DNSSEC if it enters NTA. */
if (kr_ta_get(negative_anchors, wanted_name)){
* Since forwarding targets already are in qry->ns -
* cut fetching is not needed. */
if (qry->flags & QUERY_FORWARD) {
- return forward_trust_chain_check(request, qry, false);
+ return forward_trust_chain_check(request, qry, false, packet);
}
if (!(qry->flags & QUERY_AWAIT_CUT)) {
/* The query was resolved from cache.
if (qry->deferred != NULL) {
/* @todo: Refactoring validator, check trust chain before resuming. */
int state = (qry->flags & QUERY_FORWARD) ?
- forward_trust_chain_check(request, qry, true) :
+ forward_trust_chain_check(request, qry, true, packet) :
trust_chain_check(request, qry);
switch(state) {
case KR_STATE_FAIL: return KR_STATE_FAIL;