Commit 5581cf9b authored by Grigorii Demidov's avatar Grigorii Demidov

lib/nsrep: don't treat servers with NOIP4 + NOIP6 flags as timeouted

parent b7141688
......@@ -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.
*/
};
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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 {
......
......@@ -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 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t
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);
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment