From 5581cf9b765fae22d602a2b488a47822597656c4 Mon Sep 17 00:00:00 2001 From: Grigorii Demidov Date: Thu, 30 Mar 2017 13:38:40 +0200 Subject: [PATCH] lib/nsrep: don't treat servers with NOIP4 + NOIP6 flags as timeouted --- lib/cache.h | 3 +++ lib/layer/iterate.c | 10 +++++++++- lib/layer/rrcache.c | 11 +++++++++-- lib/nsrep.c | 12 +++++++++--- lib/resolve.c | 36 ++++++++++++++++++++++++++++-------- lib/zonecut.c | 13 +++++++++---- 6 files changed, 67 insertions(+), 18 deletions(-) diff --git a/lib/cache.h b/lib/cache.h index b9f8f84b7..7a6f2af40 100644 --- a/lib/cache.h +++ b/lib/cache.h @@ -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. + */ }; diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index ebb709aa2..539d6c3c4 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -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); diff --git a/lib/layer/rrcache.c b/lib/layer/rrcache.c index 9cf0497df..e7f3a0f85 100644 --- a/lib/layer/rrcache.c +++ b/lib/layer/rrcache.c @@ -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); } diff --git a/lib/nsrep.c b/lib/nsrep.c index f3dd405af..1bf27048d 100644 --- a/lib/nsrep.c +++ b/lib/nsrep.c @@ -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 { diff --git a/lib/resolve.c b/lib/resolve.c index 0352179d9..dd3c35df2 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -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); diff --git a/lib/zonecut.c b/lib/zonecut.c index f5b4cfb37..d8220e156 100644 --- a/lib/zonecut.c +++ b/lib/zonecut.c @@ -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); -- 2.47.2