* 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.
+ */
};
(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);
}
}
}
}
+
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 &&
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);
}
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);
}
/* 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 {
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);
}
}
(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);
* 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. */
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;
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);
}
/** 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;
}
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);