#endif
}
-static int resolve_notimpl(knot_pkt_t *pkt, struct kr_request *req, struct kr_query *qry)
-{
- if (qry->stype == KNOT_RRTYPE_RRSIG && qry->parent != NULL) {
- /* RRSIG subquery have got NOTIMPL.
- * Possible scenario - same NS is autoritative for child and parent,
- * but child isn't signed.
- * We got delegation to parent,
- * then NS responded as NS for child zone.
- * Answer contained record been requested, but no RRSIGs,
- * Validator issued RRSIG query then. If qname is zone name,
- * we can get NOTIMPL. Ask for DS to find out security status.
- * TODO - maybe it would be better to do this in validator, when
- * RRSIG revalidation occurs.
- */
- struct kr_rplan *rplan = &req->rplan;
- struct kr_query *next = kr_rplan_push(rplan, qry->parent, qry->sname,
- qry->sclass, KNOT_RRTYPE_DS);
- if (!next) {
- return KR_STATE_FAIL;
- }
- kr_zonecut_set(&next->zone_cut, qry->parent->zone_cut.name);
- kr_zonecut_copy(&next->zone_cut, &qry->parent->zone_cut);
- kr_zonecut_copy_trust(&next->zone_cut, &qry->parent->zone_cut);
- next->flags.DNSSEC_WANT = true;
- qry->flags.RESOLVED = true;
- return KR_STATE_DONE;
- }
- return resolve_badmsg(pkt, req, qry);
-}
-
/** Resolve input query or continue resolution with followups.
*
* This roughly corresponds to RFC1034, 5.3.3 4a-d.
}
/* fall through */
case KNOT_RCODE_FORMERR:
- VERBOSE_MSG("<= rcode: %s\n", rcode ? rcode->name : "??");
- return resolve_badmsg(pkt, req, query);
case KNOT_RCODE_NOTIMPL:
VERBOSE_MSG("<= rcode: %s\n", rcode ? rcode->name : "??");
- return resolve_notimpl(pkt, req, query);
+ return resolve_badmsg(pkt, req, query);
default:
VERBOSE_MSG("<= rcode: %s\n", rcode ? rcode->name : "??");
return resolve_error(pkt, req);
return signer_name;
}
-static int rrsig_not_found(kr_layer_t *ctx, const knot_rrset_t *rr)
+static int rrsig_not_found(kr_layer_t *ctx, const knot_pkt_t *pkt, const knot_rrset_t *rr)
{
+ /* Signatures are missing. There might be a zone cut that we've skipped
+ * and transitions to insecure. That can commonly happen when iterating
+ * and both sides of that cut are served by the same IP address(es).
+ * We'll try proving that the name truly is insecure - by spawning
+ * a DS sub-query on a suitable QNAME.
+ */
struct kr_request *req = ctx->req;
struct kr_query *qry = req->current_query;
- /* Parent-side record, so don't ask for RRSIG.
- * We won't receive it anyway. */
- if (qry->stype == KNOT_RRTYPE_DS) {
+ if (qry->flags.FORWARD || qry->flags.STUB) {
+ /* Undiscovered signed cuts can't happen in the current forwarding
+ * algorithm, so this function shouldn't be able to help. */
return KR_STATE_FAIL;
}
- struct kr_zonecut *cut = &qry->zone_cut;
- const knot_dname_t *cut_name_start = qry->zone_cut.name;
- bool use_cut = true;
- if (knot_dname_in_bailiwick(rr->owner, cut_name_start) < 0) {
- int zone_labels = knot_dname_labels(qry->zone_cut.name, NULL);
- int matched_labels = knot_dname_matched_labels(qry->zone_cut.name, rr->owner);
- int skip_labels = zone_labels - matched_labels;
- while (skip_labels--) {
- cut_name_start = knot_wire_next_label(cut_name_start, NULL);
- }
- /* try to find the name wanted among ancestors */
- use_cut = false;
- while (cut->parent) {
- cut = cut->parent;
- if (knot_dname_is_equal(cut_name_start, cut->name)) {
- use_cut = true;
+ /* Find cut_next: the name at which to try finding the "missing" zone cut. */
+ const knot_dname_t *cut_next = rr->owner;
+ const knot_dname_t * const cut_top = qry->zone_cut.name;
+ const int next_depth = knot_dname_in_bailiwick(rr->owner, cut_top);
+ if (next_depth <= 0) {
+ return KR_STATE_FAIL; // shouldn't happen, I think
+ } else if (next_depth > 1) {
+ /* Try finding SOA. That can speed up things in deeper zones. */
+ const knot_pktsection_t *sec = knot_pkt_section(pkt, KNOT_AUTHORITY);
+ for (int i = sec->pos; i < sec->pos + sec->count; ++i) {
+ if (pkt->rr[i].type != KNOT_RRTYPE_SOA) continue;
+ const knot_dname_t *owner = pkt->rr[i].owner;
+ if (knot_dname_in_bailiwick(owner, cut_top) >= 1
+ && knot_dname_in_bailiwick(cut_next, owner) >= 1) {
+ cut_next = owner;
break;
}
- };
+ }
}
- struct kr_rplan *rplan = &req->rplan;
- struct kr_query *next = kr_rplan_push(rplan, qry, rr->owner, rr->rclass, KNOT_RRTYPE_RRSIG);
+
+ /* Spawn that DS sub-query. */
+ struct kr_query *next = kr_rplan_push(&req->rplan, qry, cut_next,
+ rr->rclass, KNOT_RRTYPE_DS);
if (!next) {
return KR_STATE_FAIL;
}
- kr_zonecut_init(&next->zone_cut, cut_name_start, &req->pool);
- if (use_cut) {
- kr_zonecut_copy(&next->zone_cut, cut);
- kr_zonecut_copy_trust(&next->zone_cut, cut);
- } else {
- next->flags.AWAIT_CUT = true;
- }
- if (qry->flags.FORWARD) {
- next->flags.AWAIT_CUT = false;
- }
+ kr_zonecut_init(&next->zone_cut, qry->zone_cut.name, &req->pool);
+ kr_zonecut_copy(&next->zone_cut, &qry->zone_cut);
+ kr_zonecut_copy_trust(&next->zone_cut, &qry->zone_cut);
next->flags.DNSSEC_WANT = true;
return KR_STATE_YIELD;
}
-static int check_validation_result(kr_layer_t *ctx, ranked_rr_array_t *arr)
+static int check_validation_result(kr_layer_t *ctx, const knot_pkt_t *pkt, ranked_rr_array_t *arr)
{
int ret = KR_STATE_DONE;
struct kr_request *req = ctx->req;
VERBOSE_MSG(qry, ">< cut changed (new signer), needs revalidation\n");
ret = KR_STATE_YIELD;
} else if (kr_rank_test(invalid_entry->rank, KR_RANK_MISSING)) {
- ret = rrsig_not_found(ctx, rr);
+ ret = rrsig_not_found(ctx, pkt, rr);
} else if (!kr_rank_test(invalid_entry->rank, KR_RANK_SECURE)) {
qry->flags.DNSSEC_BOGUS = true;
ret = KR_STATE_FAIL;
}
/* check validation state and spawn subrequests */
if (!req->answ_validated) {
- ret = check_validation_result(ctx, &req->answ_selected);
+ ret = check_validation_result(ctx, pkt, &req->answ_selected);
if (ret != KR_STATE_DONE) {
return ret;
}
}
if (!req->auth_validated) {
- ret = check_validation_result(ctx, &req->auth_selected);
+ ret = check_validation_result(ctx, pkt, &req->auth_selected);
if (ret != KR_STATE_DONE) {
return ret;
}