*/
#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);
}
#pragma once
+#include <netinet/in.h>
+
+#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);
/** @} */
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. */
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);
}
}
+ DEBUG_MSG("finished: %s, mempool: %llu B\n", knot_strerror(ret), mp_total_size(pool->ctx));
knot_requestor_clear(&requestor);
return ret;
}