]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/zonecut: use SBELT only when necessary, prefer cached information
authorMarek Vavruša <marek.vavrusa@nic.cz>
Thu, 1 Oct 2015 14:55:22 +0000 (16:55 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Fri, 2 Oct 2015 11:28:01 +0000 (13:28 +0200)
before the algorithm was happy with root hints for all queries starting
at root, however they're often overloaded and result in timeouts
the updated code provides SBELT only for root NS query lookup and tries
to use cached information as much as possible

lib/resolve.c
lib/zonecut.c
lib/zonecut.h
tests/kresd.j2

index 40c62b4615bae66c8cc8be6cda531942af0b23ce..cc031b12e4b9b811e1ca709987c7c92ba19d34fe 100644 (file)
@@ -77,7 +77,7 @@ static int invalidate_ns(struct kr_rplan *rplan, struct kr_query *qry)
 
 static int ns_fetch_cut(struct kr_query *qry, struct kr_request *req, bool secured)
 {
-       int ret = 0;
+       int ret = kr_error(ENOENT);
 
        /* Find closest zone cut from cache */
        struct kr_cache_txn txn;
@@ -92,8 +92,6 @@ static int ns_fetch_cut(struct kr_query *qry, struct kr_request *req, bool secur
                        ret = kr_zonecut_find_cached(req->ctx, &qry->zone_cut, qry->sname, &txn, qry->timestamp.tv_sec, secured);
                }
                kr_cache_txn_abort(&txn);
-       } else {
-               ret = kr_zonecut_set_sbelt(req->ctx, &qry->zone_cut);
        }
        return ret;
 }
@@ -122,6 +120,12 @@ static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
        }
        /* Bail out if the query is already pending or dependency loop. */
        if (!next_type || kr_rplan_satisfies(qry->parent, qry->ns.name, KNOT_CLASS_IN, next_type)) {
+               /* Fall back to SBELT if root server query fails. */
+               if (!next_type && qry->zone_cut.name[0] == '\0') {
+                       DEBUG_MSG("=> fallback to root hints\n");
+                       kr_zonecut_set_sbelt(ctx, &qry->zone_cut);
+                       return kr_error(EAGAIN);
+               }
                /* No IPv4 nor IPv6, flag server as unuseable. */
                DEBUG_MSG("=> unresolvable NS address, bailing out\n");
                qry->ns.reputation |= KR_NS_NOIP4 | KR_NS_NOIP6;
@@ -134,9 +138,14 @@ static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
        if (!next) {
                return kr_error(ENOMEM);
        }
-
-       next->flags |= QUERY_AWAIT_CUT;
-       return kr_ok();
+       /* At the root level with no NS addresses, revert to SBELT. */
+       int ret = 0;
+       if (qry->zone_cut.name[0] == '\0') {
+               ret = kr_zonecut_set_sbelt(ctx, &qry->zone_cut);
+       } else {
+               next->flags |= QUERY_AWAIT_CUT;
+       }
+       return ret;
 }
 
 static int edns_put(knot_pkt_t *pkt)
@@ -378,7 +387,19 @@ static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot
                }
                int ret = ns_fetch_cut(qry, request, (qry->flags & QUERY_DNSSEC_WANT));
                if (ret != 0) {
-                       return KNOT_STATE_FAIL;
+                       /* No cached cut found, start from SBELT and issue priming query. */
+                       if (ret == kr_error(ENOENT)) {
+                               DEBUG_MSG("=> root priming query\n");
+                               ret = kr_zonecut_set_sbelt(request->ctx, &qry->zone_cut);
+                               if (ret != 0) {
+                                       return KNOT_STATE_FAIL;
+                               }
+                               zone_cut_subreq(rplan, qry, qry->zone_cut.name, KNOT_RRTYPE_NS);
+                               qry->flags &= ~QUERY_AWAIT_CUT;
+                               return KNOT_STATE_DONE;
+                       } else {
+                               return KNOT_STATE_FAIL;
+                       }
                }
                /* Update minimized QNAME if zone cut changed */
                if (qry->zone_cut.name[0] != '\0' && !(qry->flags & QUERY_NO_MINIMIZE)) {
@@ -494,7 +515,8 @@ ns_election:
 
        /* Resolve address records */
        if (qry->ns.addr[0].ip.sa_family == AF_UNSPEC) {
-               if (ns_resolve_addr(qry, request) != 0) {
+               int ret = ns_resolve_addr(qry, request);
+               if (ret != 0) {
                        qry->flags &= ~(QUERY_AWAIT_IPV6|QUERY_AWAIT_IPV4|QUERY_TCP);
                        goto ns_election; /* Must try different NS */
                }
index 1bd0e1a599a0881e7e29a05c1d88260e53a4f2b0..36046c391d772f845b31de834db38b81aad70bdd 100644 (file)
@@ -257,32 +257,29 @@ int kr_zonecut_set_sbelt(struct kr_context *ctx, struct kr_zonecut *cut)
        }
 
        update_cut_name(cut, U8(""));
+       map_walk(&cut->nsset, free_addr_set, cut->pool);
+       map_clear(&cut->nsset);
 
        /* Copy root hints from resolution context. */
+       int ret = 0;
        if (ctx->root_hints.nsset.root) {
-               int ret = kr_zonecut_copy(cut, &ctx->root_hints);
-               if (ret == 0) {
-                       ret = kr_zonecut_copy_trust(cut, &ctx->root_hints);
-               }
-               if (ret == 0) {
-                       return ret;
-               }
-       }
-
-       /* Copy compiled-in root hints */
-       for (unsigned i = 0; i < HINT_COUNT; ++i) {
-               const struct hint_info *hint = &SBELT[i];
-               knot_rdata_t rdata[knot_rdata_array_size(HINT_ADDRLEN)];
-               knot_rdata_init(rdata, HINT_ADDRLEN, hint->addr, 0);
-               int ret = kr_zonecut_add(cut, hint->name, rdata);
-               if (ret != 0) {
-                       return ret;
+               ret = kr_zonecut_copy(cut, &ctx->root_hints);
+       } else {
+               /* Copy compiled-in root hints */
+               for (unsigned i = 0; i < HINT_COUNT; ++i) {
+                       const struct hint_info *hint = &SBELT[i];
+                       knot_rdata_t rdata[knot_rdata_array_size(HINT_ADDRLEN)];
+                       knot_rdata_init(rdata, HINT_ADDRLEN, hint->addr, 0);
+                       ret = kr_zonecut_add(cut, hint->name, rdata);
+                       if (ret != 0) {
+                               break;
+                       }
                }
        }
 
        /* Set trust anchor. */
        knot_rrset_free(&cut->trust_anchor, cut->pool);
-       return kr_ok();
+       return ret;
 }
 
 /** Fetch address for zone cut. */
@@ -330,11 +327,6 @@ static int fetch_ns(struct kr_context *ctx, struct kr_zonecut *cut, const knot_d
                }
        }
 
-       /* Always keep SBELT as a backup for root */
-       if (name[0] == '\0') {
-               kr_zonecut_set_sbelt(ctx, cut);
-       }
-
        return kr_ok();
 }
 
@@ -411,6 +403,5 @@ int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut, const
                name = knot_wire_next_label(name, NULL);
        }
 
-       /* Name server not found, start with SBELT. */
-       return kr_zonecut_set_sbelt(ctx, cut);
+       return kr_error(ENOENT);
 }
index 5ea58d2ca943787c3133d0f12023ba88213f8a76..91b95154430fc8009939f49eee8f38a51e5bf889 100644 (file)
@@ -126,7 +126,7 @@ int kr_zonecut_set_sbelt(struct kr_context *ctx, struct kr_zonecut *cut);
  * @param txn       cache transaction (read)
  * @param timestamp transaction timestamp
  * @param secured   search nearest containing a DNSKEY
- * @return 0 or error code
+ * @return 0 or error code (ENOENT if it doesn't find anything)
  */
 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, bool secured);
index 2f787b5cf5da8a90ee5170d3391c6434430530f0..7ddcccee9e415b505f7be61a229fe6ea35ac0786 100644 (file)
@@ -1,9 +1,10 @@
 net = { '{{SELF_ADDR}}' }
 modules = {'stats', 'policy', 'hints'}
 cache.size = 1*MB
-hints.root({['k.root-servers.net'] = '{{ROOT_ADDR}}'})
 option('NO_MINIMIZE', {{NO_MINIMIZE}})
 option('ALLOW_LOCAL', true)
+hints.config('/dev/null')
+hints.root({['k.root-servers.net'] = '{{ROOT_ADDR}}'})
 trust_anchors.add('{{TRUST_ANCHOR}}')
 verbose(true)