From: Marek VavruĊĦa Date: Sat, 18 Apr 2015 21:42:15 +0000 (+0200) Subject: lib: basic nameserver election X-Git-Tag: v1.0.0-beta1~237^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=140e028c5c7da5abf6a8dfbb406700f802e24542;p=thirdparty%2Fknot-resolver.git lib: basic nameserver election nameservers with addresses are preferred, the rest has same weight no blacklisting, penalization or rtt scoring yet --- diff --git a/lib/nsrep.c b/lib/nsrep.c index e49e53124..02f9bf9af 100644 --- a/lib/nsrep.c +++ b/lib/nsrep.c @@ -15,9 +15,61 @@ */ #include "lib/nsrep.h" +#include "lib/generic/pack.h" -int kr_nsrep_score(const knot_dname_t *ns, struct kr_layer_param *param) +/** @internal Macro to set address structure. */ +#define ADDR_SET(sa, family, addr, len) do {\ + memcpy(&sa ## _addr, (addr), (len)); \ + sa ## _family = (family); \ + sa ## _port = htons(KR_DNS_PORT); \ +} while (0) + +/** Update nameserver representation with current name/address pair. */ +static void update_nsrep(struct kr_nsrep *ns, const knot_dname_t *name, uint8_t *addr, unsigned score) +{ + ns->name = name; + ns->score = score; + if (addr == NULL) { + return; + } + + size_t len = pack_obj_len(addr); + void *addr_val = pack_obj_val(addr); + switch(len) { + case sizeof(struct in_addr): + ADDR_SET(ns->addr.ip4.sin, AF_INET, addr_val, len); break; + case sizeof(struct in6_addr): + ADDR_SET(ns->addr.ip6.sin6, AF_INET6, addr_val, len); break; + default: assert(0); break; + } +} + +#undef ADDR_SET + +static int eval_nsrep(const char *k, void *v, void *baton) +{ + unsigned score = KR_NS_VALID; + struct kr_nsrep *ns = baton; + pack_t *addr_set = v; + uint8_t *addr = NULL; + + /* Name server is better candidate if it has address record. */ + if (addr_set->len > 0) { + addr = pack_head(*addr_set); + score += 1; + } + + /* Update best scoring nameserver. */ + if (ns->score < score) { + update_nsrep(ns, (const knot_dname_t *)k, addr, score); + } + + return kr_ok(); +} + +int kr_nsrep_elect(struct kr_nsrep *ns, map_t *nsset) { - /* TODO: stub, always returns valid */ - return KR_NS_VALID; + ns->addr.ip.sa_family = AF_UNSPEC; + ns->score = KR_NS_INVALID; + return map_walk(nsset, eval_nsrep, ns); } diff --git a/lib/nsrep.h b/lib/nsrep.h index 922912a8d..e61f063f2 100644 --- a/lib/nsrep.h +++ b/lib/nsrep.h @@ -20,18 +20,40 @@ #pragma once +#include + +#include "lib/generic/map.h" #include "lib/layer.h" enum kr_ns_score { - KR_NS_INVALID = -1, - KR_NS_VALID = 0 + KR_NS_INVALID = 0, + KR_NS_VALID = 1 +}; + +struct kr_nsrep +{ + unsigned score; + const knot_dname_t *name; + union { + struct sockaddr ip; + struct sockaddr_in ip4; + struct sockaddr_in6 ip6; + } addr; }; -/** Return name server score (KR_NS_VALID is baseline, the higher the better). - * @param ns evaluated NS name - * @param param layer parameters - * @return enum kr_ns_score or higher positive value +/** @internal Address bytes for given family. */ +#define kr_nsrep_inaddr(addr) \ + ((addr).ip.sa_family == AF_INET ? (void *)&((addr).ip4.sin_addr) : (void *)&((addr).ip6.sin6_addr)) +/** @internal Address length for given family. */ +#define kr_nsrep_inaddr_len(addr) \ + ((addr).ip.sa_family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr)) + +/** + * Elect best nameserver/address pair from the nsset. + * @param ns updated NS representation + * @param nsset NS set to choose from + * @return 0 if success (ns is updated), error otherwise */ -int kr_nsrep_score(const knot_dname_t *ns, struct kr_layer_param *param); +int kr_nsrep_elect(struct kr_nsrep *ns, map_t *nsset); /** @} */ diff --git a/lib/resolve.c b/lib/resolve.c index 3f76aa61f..47d84133a 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -70,10 +70,17 @@ static int iterate(struct knot_requestor *requestor, struct kr_layer_param *para DEBUG_MSG("query '%s %s'\n", name_str, type_str); #endif - /* Invalid address for current zone cut. */ - if (sockaddr_len((struct sockaddr *)&cur->zone_cut.addr) < 1) { - DEBUG_MSG("=> ns missing A/AAAA, fetching\n"); - return ns_resolve_addr(cur, param); + /* Elect best nameserver candidate. */ + kr_nsrep_elect(&cur->ns, &cur->zone_cut.nsset); + if (cur->ns.score < KR_NS_VALID) { + DEBUG_MSG("=> no valid NS left\n"); + kr_rplan_pop(param->rplan, cur); + return KNOT_EOK; + } else { + if (cur->ns.addr.ip.sa_family == AF_UNSPEC) { + DEBUG_MSG("=> ns missing A/AAAA, fetching\n"); + return ns_resolve_addr(cur, param); + } } /* Prepare query resolution. */ @@ -120,7 +127,7 @@ static void prepare_layers(struct knot_requestor *req, struct kr_layer_param *pa static int resolve_iterative(struct kr_layer_param *param, mm_ctx_t *pool) { - /* Initialize requestor. */ +/* Initialize requestor. */ struct knot_requestor requestor; knot_requestor_init(&requestor, pool); prepare_layers(&requestor, param); @@ -143,6 +150,7 @@ static int resolve_iterative(struct kr_layer_param *param, mm_ctx_t *pool) } } + DEBUG_MSG("finished: %s, mempool: %llu B\n", knot_strerror(ret), mp_total_size(pool->ctx)); knot_requestor_clear(&requestor); return ret; }