return ctx->state;
}
+ if (query->zone_cut.key == NULL) {
+/*
+ query->flags |= QUERY_AWAIT_TRUST;
+
+ DEBUG_MSG("%s() A002 '%s'\n", __func__, knot_pkt_qname(pkt));
+
+ struct knot_rrset *opt_rr = knot_rrset_copy(req->answer->opt_rr, &pkt->mm);
+ if (opt_rr == NULL) {
+ return KNOT_STATE_FAIL;
+ }
+ knot_pkt_clear(pkt);
+ int ret = knot_pkt_put_question(pkt, query->zone_cut.name, query->sclass, KNOT_RRTYPE_DNSKEY);
+ if (ret != KNOT_EOK) {
+ knot_rrset_free(&opt_rr, &pkt->mm);
+ return KNOT_STATE_FAIL;
+ }
+ knot_pkt_begin(pkt, KNOT_ADDITIONAL);
+ knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, opt_rr, KNOT_PF_FREE);
+
+ {
+ char name_str[KNOT_DNAME_MAXLEN], type_str[16];
+ knot_dname_to_str(name_str, knot_pkt_qname(pkt), sizeof(name_str));
+ knot_rrtype_to_string(knot_pkt_qtype(pkt), type_str, sizeof(type_str));
+ DEBUG_MSG("%s() A003 '%s %s'\n", __func__, name_str, type_str);
+ }
+
+ return KNOT_STATE_CONSUME;
+*/
+ }
+
+ DEBUG_MSG("%s() A004\n", __func__);
+
+#if 0
/* Copy query EDNS options and request DNSKEY for current cut. */
pkt->opt_rr = knot_rrset_copy(req->answer->opt_rr, &pkt->mm);
query->flags |= QUERY_AWAIT_TRUST;
knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, pkt->opt_rr, KNOT_PF_FREE);
return KNOT_STATE_CONSUME;
+#endif
+ return ctx->state;
}
static int validate(knot_layer_t *ctx, knot_pkt_t *pkt)
#warning TODO: check if we have DNSKEY in qry->zone_cut and validate RRSIGS/proof, return FAIL if failed
#warning TODO: we must also validate incoming DNSKEY records against the current zone cut TA
#warning FLOW: first answer that comes here must have the DNSKEY that we can validate using TA
+
+ return ctx->state;
}
/** Module implementation. */
}
}
-static int ns_fetch_cut(struct kr_query *qry, struct kr_request *req)
+static int ns_fetch_cut(struct kr_query *qry, struct kr_request *req, bool secured)
{
struct kr_cache_txn txn;
int ret = 0;
if (kr_cache_txn_begin(&req->ctx->cache, &txn, NAMEDB_RDONLY) != 0) {
ret = kr_zonecut_set_sbelt(req->ctx, &qry->zone_cut);
} else {
- ret = kr_zonecut_find_cached(req->ctx, &qry->zone_cut, qry->sname, &txn, qry->timestamp.tv_sec);
+ ret = kr_zonecut_find_cached(req->ctx, &qry->zone_cut, qry->sname, &txn, qry->timestamp.tv_sec, secured);
kr_cache_txn_abort(&txn);
}
return ret;
DEBUG_MSG("query '%s %s'\n", type_str, name_str);
#endif
+ /* The query wasn't resolved from cache,
+ * now it's the time to look up closest zone cut from cache.
+ */
+ if (qry->flags & QUERY_AWAIT_CUT) {
+ int ret = ns_fetch_cut(qry, request, true);
+ if (ret != 0) {
+ return KNOT_STATE_FAIL;
+ }
+
+ if (!qry->zone_cut.key) {
+ /* Try to fetch missing DNSKEY. */
+ /* TODO -- Fetch all missing DNSKEYS and DS records. */
+ /* TODO -- Fetch DS at parent side of a zone cut. Fetch NS at the child side of the zone cut. */
+ /* TODO -- Handle holes (sequences with missing delegation). */
+ struct kr_query *next = kr_rplan_push(rplan, qry, qry->zone_cut.name, KNOT_CLASS_IN, KNOT_RRTYPE_DNSKEY);
+ if (!next) {
+ return kr_error(ENOMEM);
+ }
+ }
+ }
+
/* Resolve current query and produce dependent or finish */
int state = knot_overlay_produce(&request->overlay, packet);
if (state != KNOT_STATE_FAIL && knot_wire_get_qr(packet->wire)) {
* now it's the time to look up closest zone cut from cache.
*/
if (qry->flags & QUERY_AWAIT_CUT) {
- int ret = ns_fetch_cut(qry, request);
- if (ret != 0) {
- return KNOT_STATE_FAIL;
- }
qry->flags &= ~QUERY_AWAIT_CUT;
/* Update minimized QNAME if zone cut changed */
if (qry->zone_cut.name[0] != '\0' && !(qry->flags & QUERY_NO_MINIMIZE)) {
struct sockaddr *addr = &qry->ns.addr.ip;
inet_ntop(addr->sa_family, kr_nsrep_inaddr(qry->ns.addr), ns_str, sizeof(ns_str));
knot_dname_to_str(zonecut_str, qry->zone_cut.name, sizeof(zonecut_str));
- DEBUG_MSG("=> querying: '%s' score: %u zone cut: '%s' m12n: '%s'\n", ns_str, qry->ns.score, zonecut_str, qname_str);
+ knot_rrtype_to_string(knot_pkt_qtype(packet), type_str, sizeof(type_str));
+ DEBUG_MSG("=> querying: '%s' score: %u zone cut: '%s' m12n: '%s' type: '%s'\n", ns_str, qry->ns.score, zonecut_str, qname_str, type_str);
#endif
/* Prepare additional query */
return kr_ok();
}
+/** Fetch DNSKEY for zone cut. */
+static int fetch_dnskey(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name, struct kr_cache_txn *txn, uint32_t timestamp)
+{
+ uint32_t drift = timestamp;
+ knot_rrset_t cached_rr;
+
+ knot_rrset_free(&cut->key, cut->pool);
+
+ knot_rrset_init(&cached_rr, (knot_dname_t *)name, KNOT_RRTYPE_DNSKEY, KNOT_CLASS_IN);
+ int ret = kr_cache_peek_rr(txn, &cached_rr, &drift);
+ if (ret != 0) {
+ return ret;
+ }
+
+ cut->key = knot_rrset_new(name, KNOT_RRTYPE_DNSKEY, KNOT_CLASS_IN, cut->pool);
+ if (cut->key == NULL) {
+ return kr_error(ENOMEM);
+ }
+
+ ret = kr_cache_materialize(cut->key, &cached_rr, timestamp, cut->pool);
+ if (ret != 0) {
+ knot_rrset_free(&cut->key, cut->pool);
+ return ret;
+ }
+
+ return kr_ok();
+}
+
int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name,
- struct kr_cache_txn *txn, uint32_t timestamp)
+ struct kr_cache_txn *txn, uint32_t timestamp, bool secured)
{
if (!ctx || !cut || !name) {
return kr_error(EINVAL);
/* Start at QNAME parent. */
while (txn) {
- if (fetch_ns(ctx, cut, name, txn, timestamp) == 0) {
+ bool has_key = !secured || fetch_dnskey(ctx, cut, name, txn, timestamp) == 0;
+ if (has_key && fetch_ns(ctx, cut, name, txn, timestamp) == 0) {
update_cut_name(cut, name);
return kr_ok();
}
* @param name QNAME to start finding zone cut for
* @param txn cache transaction (read)
* @param timestamp transaction timestamp
+ * @param secured search nearest containing a DNSKEY
* @return 0 or error code
*/
int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name,
- struct kr_cache_txn *txn, uint32_t timestamp);
+ struct kr_cache_txn *txn, uint32_t timestamp, bool secured);