diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index eac4921025b5b6f31a7d7f966db9ae555814aad6..e653443ea17501020aa3720f729896048fe9cbe5 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -154,8 +154,16 @@ static int resolve_auth(knot_pkt_t *pkt, struct kr_layer_param *param) return KNOT_NS_PROC_FAIL; } + /* Authoritative response for min QNAME => disable and retry */ + bool is_minimized = (knot_pkt_qtype(pkt) != cur->stype && + !knot_dname_is_equal(knot_pkt_qname(pkt), cur->sname)); + if (is_minimized && knot_wire_get_rcode(pkt->wire) == KNOT_RCODE_NOERROR) { + cur->flags |= QUERY_NO_MINIMIZE; + return KNOT_NS_PROC_DONE; + } + /* Is relevant for original query? */ - bool update_orig_answer = (cur == kr_rplan_last(param->rplan)); + bool update_orig_answer = (cur == kr_rplan_last(param->rplan) && !is_minimized); const knot_dname_t *cname = cur->sname; const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER); @@ -200,6 +208,21 @@ static int resolve_error(knot_pkt_t *pkt, struct kr_layer_param *param, int errc return KNOT_NS_PROC_FAIL; } +/*! \brief Return minimized QNAME for current zone cut. */ +static const knot_dname_t *minimized_qname(struct kr_query *query, struct kr_zonecut *cut) +{ + /* Minimize name to contain current zone cut + 1 label. */ + const knot_dname_t *qname = query->sname; + int cut_labels = knot_dname_labels(cut->name, NULL); + int qname_labels = knot_dname_labels(qname, NULL); + while(qname_labels > cut_labels + 1) { + qname = knot_wire_next_label(qname, NULL); + qname_labels -= 1; + } + + return qname; +} + /*! \brief Answer is paired to query. */ static bool is_answer_to_query(const knot_pkt_t *answer, struct kr_rplan *rplan) { @@ -208,10 +231,19 @@ static bool is_answer_to_query(const knot_pkt_t *answer, struct kr_rplan *rplan) return -1; } + uint16_t expect_qtype = expect->stype; + const knot_dname_t *expect_qname = expect->sname; + if (!expect->flags & QUERY_NO_MINIMIZE) { + expect_qname = minimized_qname(expect, &rplan->zone_cut); + if (expect_qname != expect->sname) { + expect_qtype = KNOT_RRTYPE_NS; + } + } + return expect->id == knot_wire_get_id(answer->wire) && expect->sclass == knot_pkt_qclass(answer) && - expect->stype == knot_pkt_qtype(answer) && - knot_dname_is_equal(expect->sname, knot_pkt_qname(answer)); + expect_qtype == knot_pkt_qtype(answer) && + knot_dname_is_equal(expect_qname, knot_pkt_qname(answer)); } /* State-less single resolution iteration step, not needed. */ @@ -234,9 +266,20 @@ static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt) return ctx->state; } + /* Minimize QNAME (if possible). */ + struct kr_zonecut *zone_cut = ¶m->rplan->zone_cut; + const knot_dname_t *qname = cur->sname; + uint16_t qtype = cur->stype; + if (!(cur->flags & QUERY_NO_MINIMIZE)) { + qname = minimized_qname(cur, zone_cut); + if (qname != cur->sname) { + qtype = KNOT_RRTYPE_NS; + } + } + /* Form a query for the authoritative. */ knot_pkt_clear(pkt); - int ret = knot_pkt_put_question(pkt, cur->sname, cur->sclass, cur->stype); + int ret = knot_pkt_put_question(pkt, qname, cur->sclass, qtype); if (ret != KNOT_EOK) { return KNOT_NS_PROC_FAIL; } @@ -245,9 +288,12 @@ static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt) knot_wire_set_id(pkt->wire, cur->id); #ifndef NDEBUG - char name_str[KNOT_DNAME_MAXLEN]; - knot_dname_to_str(name_str, param->rplan->zone_cut.ns, sizeof(name_str)); - DEBUG_MSG("sending query to %s\n", name_str); + char name_str[KNOT_DNAME_MAXLEN], zonecut_str[KNOT_DNAME_MAXLEN], ns_str[KNOT_DNAME_MAXLEN], type_str[16]; + knot_dname_to_str(ns_str, zone_cut->ns, sizeof(ns_str)); + knot_dname_to_str(zonecut_str, zone_cut->name, sizeof(zonecut_str)); + knot_dname_to_str(name_str, qname, sizeof(name_str)); + knot_rrtype_to_string(qtype, type_str, sizeof(type_str)); + DEBUG_MSG("query '%s %s' zone cut '%s' nameserver '%s'\n", name_str, type_str, zonecut_str, ns_str); #endif /* Query built, expect answer. */ diff --git a/lib/resolve.c b/lib/resolve.c index 4c299ecee9c4c6c3a104fb997be6863fe5fc1587..748f110584783b69e9dd6e53b728cc0895dca6a7 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -66,13 +66,6 @@ static int iterate(struct knot_requestor *requestor, struct kr_layer_param *para return invalidate_ns(rplan, cur); } - char name_str[KNOT_DNAME_MAXLEN], zonecut_str[KNOT_DNAME_MAXLEN], ns_str[KNOT_DNAME_MAXLEN], type_str[16]; - knot_dname_to_str(ns_str, rplan->zone_cut.ns, sizeof(ns_str)); - knot_dname_to_str(zonecut_str, rplan->zone_cut.name, sizeof(zonecut_str)); - knot_dname_to_str(name_str, cur->sname, sizeof(name_str)); - knot_rrtype_to_string(cur->stype, type_str, sizeof(type_str)); - DEBUG_MSG("resolve '%s %s' zone cut '%s' nameserver '%s'\n", name_str, type_str, zonecut_str, ns_str); - /* Prepare query resolution. */ struct sockaddr *ns_addr = (struct sockaddr *)&rplan->zone_cut.addr; knot_pkt_t *query = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, requestor->mm); diff --git a/lib/rplan.h b/lib/rplan.h index cbada68d7d3d969bce80150533c61553ca1aabb8..f73231e6e15afba10ee481cc0f68e787300324f7 100644 --- a/lib/rplan.h +++ b/lib/rplan.h @@ -24,6 +24,11 @@ #include "lib/context.h" #include "lib/zonecut.h" +/* Query flags */ +enum { + QUERY_NO_MINIMIZE = 1 << 0 /*!< Don't minimize QNAME. */ +}; + /*! * \brief Single query representation. */ diff --git a/lib/zonecut.c b/lib/zonecut.c index d153968678e681ae1b194b101d81ad598d6f17bf..fb7620255438dae8818dcd11dd2d2d83deb6b01c 100644 --- a/lib/zonecut.c +++ b/lib/zonecut.c @@ -120,7 +120,6 @@ int kr_find_zone_cut(struct kr_zonecut *cut, const knot_dname_t *name, namedb_tx return KNOT_EINVAL; } - /* No cache, start with SBELT. */ if (txn == NULL) { return set_sbelt_zone_cut(cut);