#define KR_ITER_LIMIT 50 /* Built-in iterator limit */
#define KR_CNAME_CHAIN_LIMIT 40 /* Built-in maximum CNAME chain length */
#define KR_TIMEOUT_LIMIT 4 /* Maximum number of retries after timeout. */
-#define KR_QUERY_FAIL_LIMIT 40 /* Limit to the number of SERVFAIL\REFUSED
- * responses per query
- */
-#define KR_QUERY_NSRETRY_LIMIT 3 /* Maximum number of retries for single ns */
+#define KR_QUERY_NSRETRY_LIMIT 4 /* Maximum number of retries per query. */
/*
* Defines.
case KNOT_RCODE_SERVFAIL: {
DEBUG_MSG("<= rcode: %s\n", rcode ? rcode->name : "??");
query->fails += 1;
- query->ns.fails += 1;
- if (query->fails >= KR_QUERY_FAIL_LIMIT ||
- query->ns.fails >= KR_QUERY_NSRETRY_LIMIT) {
+ if (query->fails >= KR_QUERY_NSRETRY_LIMIT) {
+ query->fails = 0; /* Reset per-query counter. */
return resolve_error(pkt, req);
} else {
- query->flags |= QUERY_SERVFAIL;
return KNOT_STATE_CONSUME;
}
}
#include "lib/resolve.h"
#include "lib/defines.h"
#include "lib/generic/pack.h"
+#include "contrib/ucw/lib.h"
/** Some built-in unfairness ... */
#define FAVOUR_IPV6 20 /* 20ms bonus for v6 */
qry->ns.name = (const uint8_t *)"";
qry->ns.score = KR_NS_UNKNOWN;
qry->ns.reputation = 0;
- qry->ns.fails = 0;
update_nsrep(&qry->ns, 0, addr, addr_len);
update_nsrep(&qry->ns, 1, NULL, 0);
return kr_ok();
(ns)->ctx = (ctx_); \
(ns)->addr[0].ip.sa_family = AF_UNSPEC; \
(ns)->reputation = 0; \
- (ns)->fails = 0; \
(ns)->score = KR_NS_MAX_SCORE + 1; \
} while (0)
if (score <= KR_NS_GLUED) {
score = KR_NS_GLUED + 1;
}
-
- if ((*cur != 0) && (umode == KR_NS_UPDATE)) {
- /* In KR_NS_UPDATE mode, calculate smooth over last two measurements */
- *cur = (*cur + score) / 2;
- } else {
- /* First measurement or KR_NS_RESET mode, reset */
- *cur = score;
+ /* First update is always set. */
+ if (*cur == 0) {
+ umode = KR_NS_RESET;
+ }
+ /* Update score, by default smooth over last two measurements. */
+ switch (umode) {
+ case KR_NS_UPDATE: *cur = (*cur + score) / 2; break;
+ case KR_NS_RESET: *cur = score; break;
+ case KR_NS_ADD: *cur = MIN(KR_NS_MAX_SCORE - 1, *cur + score); break;
+ default: break;
}
-
return kr_ok();
}
KR_NS_TIMEOUT = (95 * KR_NS_MAX_SCORE) / 100,
KR_NS_LONG = (3 * KR_NS_TIMEOUT) / 4,
KR_NS_UNKNOWN = KR_NS_TIMEOUT / 2,
+ KR_NS_PENALTY = 100,
KR_NS_GLUED = 10
};
* NS RTT update modes.
*/
enum kr_ns_update_mode {
- KR_NS_UPDATE = 0, /**< Update as smooth over last two measurements */
- KR_NS_RESET /**< Set to given value */
+ KR_NS_UPDATE = 0, /**< Update as smooth over last two measurements */
+ KR_NS_RESET, /**< Set to given value */
+ KR_NS_ADD /**< Increment current value */
};
/**
{
unsigned score; /**< NS score */
unsigned reputation; /**< NS reputation */
- unsigned fails; /**< NS fail counter */
const knot_dname_t *name; /**< NS name */
struct kr_context *ctx; /**< Resolution context */
union {
* @param addr chosen address (NULL for first)
* @param score new score (i.e. RTT), see enum kr_ns_score
* @param cache LRU cache
- * @param umode update mode (KR_NS_UPDATE or KR_NS_RESET)
+ * @param umode update mode (KR_NS_UPDATE or KR_NS_RESET or KR_NS_ADD)
* @return 0 on success, error code on failure
*/
KR_EXPORT
DEBUG_MSG(qry, "<= server: '%s' rtt: %ld ms\n", addr_str, time_diff(&qry->timestamp, &now));
}
}
- if (!(qry->flags & QUERY_SERVFAIL)) {
+ /* Do not complete NS address resolution on soft-fail. */
+ const int rcode = knot_wire_get_rcode(packet->wire);
+ if (rcode != KNOT_RCODE_SERVFAIL && rcode != KNOT_RCODE_REFUSED) {
qry->flags &= ~(QUERY_AWAIT_IPV6|QUERY_AWAIT_IPV4);
+ } else { /* Penalize SERVFAILs. */
+ kr_nsrep_update_rtt(&qry->ns, src, KR_NS_PENALTY, ctx->cache_rtt, KR_NS_ADD);
}
/* Do not penalize validation timeouts. */
} else if (!(qry->flags & QUERY_DNSSEC_BOGUS)) {
return KNOT_STATE_FAIL;
}
- if (qry->flags & QUERY_SERVFAIL) {
- qry->flags &= ~QUERY_SERVFAIL;
- } else if (qry->flags & (QUERY_AWAIT_IPV4|QUERY_AWAIT_IPV6)) {
+ if (qry->flags & (QUERY_AWAIT_IPV4|QUERY_AWAIT_IPV6)) {
kr_nsrep_elect_addr(qry, request->ctx);
} else if (!qry->ns.name || !(qry->flags & (QUERY_TCP|QUERY_STUB))) { /* Keep NS when requerying/stub. */
/* Root DNSKEY must be fetched from the hints to avoid chicken and egg problem. */
X(DNSSEC_WEXPAND, 1 << 19) /**< Query response has wildcard expansion. */ \
X(PERMISSIVE, 1 << 20) /**< Permissive resolver mode. */ \
X(STRICT, 1 << 21) /**< Strict resolver mode. */ \
- X(SERVFAIL, 1 << 22) /**< Query response is SERVFAIL or REFUSED. */
/** Query flags */
enum kr_query_flag {