]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/nsrep: don't treat servers with NOIP4 + NOIP6 flags as timeouted
authorGrigorii Demidov <grigorii.demidov@nic.cz>
Thu, 30 Mar 2017 11:38:40 +0000 (13:38 +0200)
committerGrigorii Demidov <grigorii.demidov@nic.cz>
Thu, 30 Mar 2017 11:38:40 +0000 (13:38 +0200)
lib/cache.h
lib/layer/iterate.c
lib/layer/rrcache.c
lib/nsrep.c
lib/resolve.c
lib/zonecut.c

index b9f8f84b77fa7f0f0fdb781aa17fbf342b9e946c..7a6f2af40f6d98021ff198721ab189e83a3c74d5 100644 (file)
@@ -59,6 +59,9 @@ enum kr_cache_flag {
                                        * that covers the "next closer" name
                                        * has the Opt-Out bit set
                                        */
+       KR_CACHE_FLAG_NODS        = 4, /* Entry contains NS rrset
+                                       * for which DS nonexistence is proven.
+                                       */
 };
 
 
index ebb709aa2e6fca4258a31c03c5bf28755b47b8ae..539d6c3c45c0fb68b5a2fb1eab8e022573a4c09b 100644 (file)
@@ -178,6 +178,14 @@ static void fetch_glue(knot_pkt_t *pkt, const knot_dname_t *ns, struct kr_reques
                            (rr->type != KNOT_RRTYPE_AAAA)) {
                                continue;
                        }
+                       if ((rr->type == KNOT_RRTYPE_A) &&
+                           (req->ctx->options & QUERY_NO_IPV4)) {
+                               continue;
+                       }
+                       if ((rr->type == KNOT_RRTYPE_AAAA) &&
+                           (req->ctx->options & QUERY_NO_IPV6)) {
+                               continue;
+                       }
                        (void) update_nsaddr(rr, req->current_query);
                }
        }
@@ -344,6 +352,7 @@ static int process_authority(knot_pkt_t *pkt, struct kr_request *req)
                }
        }
 
+
        if ((qry->flags & QUERY_DNSSEC_WANT) && (result == KR_STATE_CONSUME)) {
                if (knot_wire_get_aa(pkt->wire) == 0 &&
                    knot_wire_get_ancount(pkt->wire) == 0 &&
@@ -636,7 +645,6 @@ static int process_stub(knot_pkt_t *pkt, struct kr_request *req)
 
        knot_wire_set_aa(pkt->wire);
        query->flags |= QUERY_RESOLVED;
-
        /* Pick authority RRs. */
        int pkt_class = kr_response_classify(pkt);
        const bool to_wire = ((pkt_class & (PKT_NXDOMAIN|PKT_NODATA)) != 0);
index 9cf0497dfa85fb54d3311700f870b69d4b55c3cb..e7f3a0f853d9c12f55d7c5518ec725e5a5ddbf43 100644 (file)
@@ -221,9 +221,16 @@ static int commit_rr(const char *key, void *val, void *data)
        }
 
        uint8_t flags = KR_CACHE_FLAG_NONE;
-       if ((rank & KR_RANK_AUTH) && (baton->qry->flags & QUERY_DNSSEC_WEXPAND)) {
-               flags |= KR_CACHE_FLAG_WCARD_PROOF;
+       if (rank & KR_RANK_AUTH) {
+               if (baton->qry->flags & QUERY_DNSSEC_WEXPAND) {
+                       flags |= KR_CACHE_FLAG_WCARD_PROOF;
+               }
+               if ((rr->type == KNOT_RRTYPE_NS) &&
+                   (baton->qry->flags & QUERY_DNSSEC_NODS)) {
+                       flags |= KR_CACHE_FLAG_NODS;
+               }
        }
+
        return kr_cache_insert_rr(baton->cache, rr, rank, flags, baton->timestamp);
 }
 
index f3dd405afbcfce2397c2e9eb7856f166191e3180..1bf27048d7bca453cd70e9c58607ca7c5cd24908 100644 (file)
@@ -139,10 +139,16 @@ static int eval_nsrep(const char *k, void *v, void *baton)
                /* If the server doesn't have IPv6, give it disadvantage. */
                if (reputation & KR_NS_NOIP6) {
                        score += FAVOUR_IPV6;
-                       /* If the server is unknown but has rep record, treat it as timeouted */
                        if (reputation & KR_NS_NOIP4) {
-                               score = KR_NS_UNKNOWN;
-                               reputation = 0; /* Start with clean slate */
+                               /* Server is unknown but has rep record.
+                                * We can not distinguish if it happens either
+                                * due to timeout or due to other circumstances
+                                * (for example, we have ipv6-only network and
+                                * we are dealing with ipv4-only NS).
+                                * Don't use it for now.
+                                * TODO -
+                                * add explicit flag for timeouted servers */
+                               score = KR_NS_MAX_SCORE + 1;
                        }
                }
        } else {
index 0352179d9f4fcef342d67ce497db623e5b305243..dd3c35df2ed0d2a6d88ac9c88ae358f0ec691d4c 100644 (file)
@@ -138,7 +138,7 @@ static int invalidate_ns(struct kr_rplan *rplan, struct kr_query *qry)
                knot_rdata_init(rdata_arr, addr_len, addr, 0);
                return kr_zonecut_del(&qry->zone_cut, qry->ns.name, rdata_arr);
        } else {
-               return kr_zonecut_del(&qry->zone_cut, qry->ns.name, NULL);
+               return kr_zonecut_del_all(&qry->zone_cut, qry->ns.name);
        }
 }
 
@@ -250,7 +250,7 @@ static int ns_fetch_cut(struct kr_query *qry, const knot_dname_t *requested_name
            (cut_found.key == NULL)) {
                /* No DNSKEY was found for cached cut.
                 * If no glue were fetched for this cut,
-                * we have got circular dependance - must fetch A\AAAA
+                * we have got circular dependancy - must fetch A\AAAA
                 * from authoritative, but we have no key to verify it.
                 * TODO - try to refetch cut only if no glue were fetched */
                kr_zonecut_deinit(&cut_found);
@@ -292,10 +292,12 @@ static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
         * Prefer IPv6 and continue with IPv4 if not available.
         */
        uint16_t next_type = 0;
-       if (!(qry->flags & QUERY_AWAIT_IPV6)) {
+       if (!(qry->flags & QUERY_AWAIT_IPV6) &&
+           !(ctx->options & QUERY_NO_IPV6)) {
                next_type = KNOT_RRTYPE_AAAA;
                qry->flags |= QUERY_AWAIT_IPV6;
-       } else if (!(qry->flags & QUERY_AWAIT_IPV4)) {
+       } else if (!(qry->flags & QUERY_AWAIT_IPV4) &&
+                  !(ctx->options & QUERY_NO_IPV4)) {
                next_type = KNOT_RRTYPE_A;
                qry->flags |= QUERY_AWAIT_IPV4;
                /* Hmm, no useable IPv6 then. */
@@ -318,10 +320,27 @@ static int ns_resolve_addr(struct kr_query *qry, struct kr_request *param)
                invalidate_ns(rplan, qry);
                return kr_error(EHOSTUNREACH);
        }
-       /* Push new query to the resolution plan */
-       struct kr_query *next = kr_rplan_push(rplan, qry, qry->ns.name, KNOT_CLASS_IN, next_type);
-       if (!next) {
-               return kr_error(ENOMEM);
+       struct kr_query *next = qry;
+       if (knot_dname_is_equal(qry->ns.name, qry->sname) &&
+           qry->stype == next_type) {
+               if (!(qry->flags & QUERY_NO_MINIMIZE)) {
+                       qry->flags |= QUERY_NO_MINIMIZE;
+                       qry->flags &= ~QUERY_AWAIT_IPV6;
+                       qry->flags &= ~QUERY_AWAIT_IPV4;
+                       VERBOSE_MSG(qry, "=> circular dependepcy, retrying with non-minimized name\n");
+               } else {
+                       qry->ns.reputation |= KR_NS_NOIP4 | KR_NS_NOIP6;
+                       kr_nsrep_update_rep(&qry->ns, qry->ns.reputation, ctx->cache_rep);
+                       invalidate_ns(rplan, qry);
+                       VERBOSE_MSG(qry, "=> unresolvable NS address, bailing out\n");
+                       return kr_error(EHOSTUNREACH);
+               }
+       } else {
+               /* Push new query to the resolution plan */
+               next = kr_rplan_push(rplan, qry, qry->ns.name, KNOT_CLASS_IN, next_type);
+               if (!next) {
+                       return kr_error(ENOMEM);
+               }
        }
        /* At the root level with no NS addresses, add SBELT subrequest. */
        int ret = 0;
@@ -1071,6 +1090,7 @@ ns_election:
                int ret = ns_resolve_addr(qry, request);
                if (ret != 0) {
                        qry->flags &= ~(QUERY_AWAIT_IPV6|QUERY_AWAIT_IPV4|QUERY_TCP);
+                       qry->ns.name = NULL;
                        goto ns_election; /* Must try different NS */
                }
                ITERATE_LAYERS(request, qry, reset);
index f5b4cfb3746734d3f85df88880688ee31ad1e7a9..d8220e1565cc3c0db50630d14a0aef5dd26e71a0 100644 (file)
@@ -343,12 +343,14 @@ static void fetch_addr(struct kr_zonecut *cut, struct kr_cache *cache, const kno
 }
 
 /** Fetch best NS for zone cut. */
-static int fetch_ns(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name, uint32_t timestamp, uint8_t * restrict rank)
+static int fetch_ns(struct kr_context *ctx, struct kr_zonecut *cut,
+                   const knot_dname_t *name, uint32_t timestamp,
+                   uint8_t * restrict rank, uint8_t * restrict flags)
 {
        uint32_t drift = timestamp;
        knot_rrset_t cached_rr;
        knot_rrset_init(&cached_rr, (knot_dname_t *)name, KNOT_RRTYPE_NS, KNOT_CLASS_IN);
-       int ret = kr_cache_peek_rr(&ctx->cache, &cached_rr, rank, NULL, &drift);
+       int ret = kr_cache_peek_rr(&ctx->cache, &cached_rr, rank, flags, &drift);
        if (ret != 0) {
                return ret;
        }
@@ -446,11 +448,14 @@ int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut, const
        while (true) {
                /* Fetch NS first and see if it's insecure. */
                uint8_t rank = 0;
+               uint8_t flags = 0;
                const bool is_root = (label[0] == '\0');
-               if (fetch_ns(ctx, cut, label, timestamp, &rank) == 0) {
+               if (fetch_ns(ctx, cut, label, timestamp, &rank, &flags) == 0) {
                        /* Flag as insecure if cached as this */
-                       if (rank & KR_RANK_INSECURE)
+                       if ((rank & KR_RANK_INSECURE) ||
+                           (flags & KR_CACHE_FLAG_NODS)) {
                                *secured = false;
+                       }
                        /* Fetch DS if caller wants secure zone cut */
                        if (*secured || is_root) {
                                fetch_ta(cut, &ctx->cache, label, timestamp);