diff --git a/lib/context.c b/lib/context.c
index b25eae14fc8e3ea26f32e6e09350b58975a29278..b6b4293253369aa49ae8d8661a07dffac9523c71 100644
--- a/lib/context.c
+++ b/lib/context.c
@@ -1,16 +1,129 @@
 #include <string.h>
+#include <sys/time.h>
 
+#include <common/sockaddr.h>
 #include "context.h"
 
-int kresolve_ctx_init(struct kresolve_ctx *ctx, mm_ctx_t *mm)
+/*! \brief Initialize NS descriptor. */
+static struct kr_ns *init_ns(mm_ctx_t *mm, const knot_dname_t *name,
+                             const struct sockaddr *addr, unsigned closeness)
 {
-	memset(ctx, 0, sizeof(struct kresolve_ctx));
+	struct kr_ns *ns = mm_alloc(mm, sizeof(struct kr_ns));
+	if (ns == NULL) {
+		return NULL;
+	}
+
+	memset(ns, 0, sizeof(struct kr_ns));
+	ns->name = knot_dname_copy(name, mm);
+	if (ns->name == NULL) {
+		mm_free(mm, ns);
+		return NULL;
+	}
+
+	memcpy(&ns->addr, addr, sockaddr_len(addr));
+	ns->closeness = closeness;
+
+	return ns;
+}
+
+/*! \brief Insert NS before an item. */
+static void insert_ns(struct kr_ns *cur, struct kr_ns *inserted)
+{
+	insert_node((node_t *)inserted, (node_t *)cur);
+	rem_node((node_t *)cur);
+	insert_node((node_t *)cur, (node_t *)inserted);
+}
+
+/*! \brief Remove NS descriptor. */
+static void remove_ns(mm_ctx_t *mm, struct kr_ns *ns)
+{
+	mm_free(mm, ns->name);
+	mm_free(mm, ns);
+}
+
+int kr_context_init(struct kr_context *ctx, mm_ctx_t *mm)
+{
+	memset(ctx, 0, sizeof(struct kr_context));
+
 	ctx->mm = mm;
+	init_list(&ctx->slist);
+
 	return 0;
 }
 
-int kresolve_ctx_close(struct kresolve_ctx *ctx)
+int kr_context_close(struct kr_context *ctx)
 {
-	/* free requestor, pending queries. */
+	/* TODO: free slist, pending queries. */
 	return -1;
 }
+
+int kr_result_init(struct kr_context *ctx, struct kr_result *result)
+{
+	memset(result, 0, sizeof(struct kr_result));
+
+	knot_pkt_t *ans = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, ctx->mm);
+	if (ans == NULL) {
+		return -1;
+	}
+
+	knot_pkt_put_question(ans, ctx->sname, ctx->sclass, ctx->stype);
+	knot_wire_set_rcode(ans->wire, KNOT_RCODE_SERVFAIL);
+	knot_wire_set_qr(ans->wire);
+
+	result->ans = ans;
+	result->cname = ctx->sname;
+	gettimeofday(&result->t_start, NULL);
+
+	return 0;
+}
+
+int kr_result_clear(struct kr_result *result)
+{
+	knot_pkt_free(&result->ans);
+
+	return 0;
+}
+
+int kr_slist_add(struct kr_context *ctx, const knot_dname_t *name, const struct sockaddr *addr)
+{
+	/* Closeness is represented by a number of common labels. */
+	int closeness = knot_dname_matched_labels(name, ctx->sname);
+
+	struct kr_ns *ns = init_ns(ctx->mm, name, addr, closeness);
+	if (ns == NULL) {
+		return -1;
+	}
+
+	struct kr_ns *iter = NULL;
+	WALK_LIST(iter, ctx->slist) {
+		if (iter->closeness < closeness) {
+			insert_ns(iter, ns);
+			return 0;
+		}
+	}
+
+	/* No closer match found. */
+	add_tail(&ctx->slist, (node_t *)ns);
+	return 0;
+}
+
+struct kr_ns *kr_slist_top(struct kr_context *ctx)
+{
+	if (EMPTY_LIST(ctx->slist)) {
+		return NULL;
+	}
+
+	return (struct kr_ns *)HEAD(ctx->slist);
+}
+
+int kr_slist_pop(struct kr_context *ctx)
+{
+	struct kr_ns *top = kr_slist_top(ctx);
+	if (top) {
+		return -1;
+	}
+
+	rem_node((node_t *)top);
+	remove_ns(ctx->mm, top);
+	return 0;
+}
diff --git a/lib/context.h b/lib/context.h
index 551deaa441e2cf43b63ee36dd05d9ffdfec986b4..40571805a6ec01e5f3ddee5bb5bc197df9997580 100644
--- a/lib/context.h
+++ b/lib/context.h
@@ -19,31 +19,47 @@ limitations under the License.
 #include <libknot/mempattern.h>
 #include <libknot/packet/pkt.h>
 
+#warning TODO: this is private define
+#include <common/lists.h>
+#include <common/sockaddr.h>
+
+/*! \brief Name server information. */
+struct kr_ns {
+	node_t node;
+	knot_dname_t *name;
+	struct sockaddr_storage addr;
+	unsigned mean_rtt;
+	unsigned closeness;
+};
+
 /*! \brief Name resolution result. */
-struct kresolve_result {
-	/* Nameserver. */
-	struct {
-		const knot_dname_t *name;
-		struct sockaddr_storage addr;
-	} ns;
-	/* Query */
-	const knot_dname_t *qname;
-	uint16_t qtype;
-	uint16_t qclass;
-	/* Result */
+struct kr_result {
 	const knot_dname_t *cname;
-	uint16_t rcode;
-	knot_rrset_t *data[32];
-	unsigned count;
+	knot_pkt_t *ans;
 	unsigned flags;
+	struct timeval t_start, t_end;
+	unsigned nr_queries;
 };
 
 /*! \brief Name resolution context. */
-struct kresolve_ctx {
+struct kr_context
+{
+	const knot_dname_t *sname;
+	uint16_t stype;
+	uint16_t sclass;
+	uint16_t next_id;
+	list_t slist;
 	mm_ctx_t *mm;
 	unsigned state;
 	unsigned options;
 };
 
-int kresolve_ctx_init(struct kresolve_ctx *ctx, mm_ctx_t *mm);
-int kresolve_ctx_close(struct kresolve_ctx *ctx);
+int kr_context_init(struct kr_context *ctx, mm_ctx_t *mm);
+int kr_context_close(struct kr_context *ctx);
+
+int kr_result_init(struct kr_context *ctx, struct kr_result *result);
+int kr_result_clear(struct kr_result *result);
+
+int kr_slist_add(struct kr_context *ctx, const knot_dname_t *name, const struct sockaddr *addr);
+struct kr_ns *kr_slist_top(struct kr_context *ctx);
+int kr_slist_pop(struct kr_context *ctx);
\ No newline at end of file