return kr_rplan_empty(&request->rplan) ? KNOT_STATE_DONE : KNOT_STATE_PRODUCE;
}
-int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *type, knot_pkt_t *packet)
+/** @internal Spawn subrequest in current zone cut (no minimization or lookup). */
+static int zone_cut_subreq(struct kr_rplan *rplan, struct kr_query *parent,
+ const knot_dname_t *qname, uint16_t qtype)
{
- struct kr_rplan *rplan = &request->rplan;
- struct kr_query *qry = kr_rplan_current(rplan);
- unsigned ns_election_iter = 0;
-
- /* No query left for resolution */
- if (kr_rplan_empty(rplan)) {
- return KNOT_STATE_FAIL;
- }
-
- /* Resolve current query and produce dependent or finish */
- ITERATE_LAYERS(request, produce, packet);
- if (request->state != KNOT_STATE_FAIL && knot_wire_get_qr(packet->wire)) {
- /* Produced an answer, consume it. */
- qry->secret = 0;
- request->state = KNOT_STATE_CONSUME;
- ITERATE_LAYERS(request, consume, packet);
+ struct kr_query *next = kr_rplan_push(rplan, parent, qname, parent->sclass, qtype);
+ if (!next) {
+ return kr_error(ENOMEM);
}
- switch(request->state) {
- case KNOT_STATE_FAIL: return request->state; break;
- case KNOT_STATE_CONSUME: break;
- case KNOT_STATE_DONE:
- default: /* Current query is done */
- if (qry->flags & QUERY_RESOLVED) {
- kr_rplan_pop(rplan, qry);
- }
- ITERATE_LAYERS(request, reset);
- return kr_rplan_empty(rplan) ? KNOT_STATE_DONE : KNOT_STATE_PRODUCE;
+ kr_zonecut_set(&next->zone_cut, parent->zone_cut.name);
+ if (kr_zonecut_copy(&next->zone_cut, &parent->zone_cut) != 0 ||
+ kr_zonecut_copy_trust(&next->zone_cut, &parent->zone_cut) != 0) {
+ return kr_error(ENOMEM);
}
+ next->flags |= QUERY_NO_MINIMIZE;
+ return kr_ok();
+}
- /* The query wasn't resolved from cache,
- * now it's the time to look up closest zone cut from cache.
- */
- /* Always try with DNSSEC if it finds island of trust. */
- /* @todo this interface is going to change */
- if (kr_ta_contains(&global_trust_anchors, qry->zone_cut.name)) {
+/** @internal Check current zone cut status and credibility, spawn subrequests if needed. */
+static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot_pkt_t *packet)
+{
+ struct kr_rplan *rplan = &request->rplan;
+
+ /* Always try with DNSSEC if it finds an island of trust. */
+ if (!(request->options & QUERY_DNSSEC_WANT) &&
+ kr_ta_contains(&global_trust_anchors, qry->zone_cut.name)) {
request->options |= QUERY_DNSSEC_WANT;
DEBUG_MSG(">< entered island of trust\n");
}
+ /* The query wasn't resolved from cache,
+ * now it's the time to look up closest zone cut from cache. */
bool want_secured = (request->options & QUERY_DNSSEC_WANT);
if (qry->flags & QUERY_AWAIT_CUT) {
int ret = ns_fetch_cut(qry, request, want_secured);
qry->flags &= ~QUERY_AWAIT_CUT;
}
- /* fetch missing DS record. */
+ /* Missing delegation signature, fetch it first. */
if ((qry->flags & QUERY_AWAIT_DS) && (qry->zone_cut.missing_name)) {
- struct kr_query *next = kr_rplan_push(rplan, qry, qry->zone_cut.missing_name, KNOT_CLASS_IN, KNOT_RRTYPE_DS);
- if (!next) {
- return KNOT_STATE_FAIL;
- }
- kr_zonecut_set(&next->zone_cut, qry->zone_cut.parent_name);
- int ret = kr_zonecut_copy(&next->zone_cut, &qry->zone_cut);
- if (ret != 0) {
- return KNOT_STATE_FAIL;
- }
- ret = kr_zonecut_copy_trust(&next->zone_cut, &qry->zone_cut);
+ int ret = zone_cut_subreq(rplan, qry, qry->zone_cut.missing_name, KNOT_RRTYPE_DS);
if (ret != 0) {
return KNOT_STATE_FAIL;
}
knot_rrset_free(&qry->zone_cut.key, qry->zone_cut.pool);
knot_rrset_free(&qry->zone_cut.trust_anchor, qry->zone_cut.pool);
qry->flags &= ~QUERY_AWAIT_DS;
- return KNOT_STATE_PRODUCE;
+ return KNOT_STATE_DONE;
}
/* Try to fetch missing DNSKEY. */
if (want_secured && !qry->zone_cut.key && qry->stype != KNOT_RRTYPE_DNSKEY) {
- struct kr_query *next = kr_rplan_push(rplan, qry, qry->zone_cut.name, KNOT_CLASS_IN, KNOT_RRTYPE_DNSKEY);
- if (!next) {
- return KNOT_STATE_FAIL;
- }
- kr_zonecut_set(&next->zone_cut, qry->zone_cut.name);
- int ret = kr_zonecut_copy(&next->zone_cut, &qry->zone_cut);
+ int ret = zone_cut_subreq(rplan, qry, qry->zone_cut.name, KNOT_RRTYPE_DNSKEY);
if (ret != 0) {
return KNOT_STATE_FAIL;
}
- ret = kr_zonecut_copy_trust(&next->zone_cut, &qry->zone_cut);
- if (ret != 0) {
- return KNOT_STATE_FAIL;
+ return KNOT_STATE_DONE;
+ }
+
+ return KNOT_STATE_PRODUCE;
+}
+
+int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *type, knot_pkt_t *packet)
+{
+ struct kr_rplan *rplan = &request->rplan;
+ struct kr_query *qry = kr_rplan_current(rplan);
+ unsigned ns_election_iter = 0;
+
+ /* No query left for resolution */
+ if (kr_rplan_empty(rplan)) {
+ return KNOT_STATE_FAIL;
+ }
+
+ /* Resolve current query and produce dependent or finish */
+ ITERATE_LAYERS(request, produce, packet);
+ if (request->state != KNOT_STATE_FAIL && knot_wire_get_qr(packet->wire)) {
+ /* Produced an answer, consume it. */
+ qry->secret = 0;
+ request->state = KNOT_STATE_CONSUME;
+ ITERATE_LAYERS(request, consume, packet);
+ }
+ switch(request->state) {
+ case KNOT_STATE_FAIL: return request->state;
+ case KNOT_STATE_CONSUME: break;
+ case KNOT_STATE_DONE:
+ default: /* Current query is done */
+ if (qry->flags & QUERY_RESOLVED) {
+ kr_rplan_pop(rplan, qry);
}
- return KNOT_STATE_PRODUCE;
+ ITERATE_LAYERS(request, reset);
+ return kr_rplan_empty(rplan) ? KNOT_STATE_DONE : KNOT_STATE_PRODUCE;
}
+
+ /* Update zone cut, spawn new subrequests. */
+ int state = zone_cut_check(request, qry, packet);
+ switch(state) {
+ case KNOT_STATE_FAIL: return KNOT_STATE_FAIL;
+ case KNOT_STATE_DONE: return KNOT_STATE_PRODUCE;
+ default: break;
+ }
+
ns_election:
/* If the query has already selected a NS and is waiting for IPv4/IPv6 record,
* elect best address only, otherwise elect a completely new NS.
*/
if(++ns_election_iter >= KR_ITER_LIMIT) {
- DEBUG_MSG("=> couldn't agree NS decision, report this\n");
+ DEBUG_MSG("=> couldn't converge NS selection, bail out\n");
return KNOT_STATE_FAIL;
}
if (qry->flags & (QUERY_AWAIT_IPV4|QUERY_AWAIT_IPV6)) {