From 9e7ae9fdbcd9a791f17ab1201c347a23e1080ab1 Mon Sep 17 00:00:00 2001
From: Karel Slany <karel.slany@nic.cz>
Date: Mon, 13 Jun 2016 14:29:50 +0200
Subject: [PATCH] Moved cookie hash functions into separate unit.

---
 lib/cookies/algorithm.c        | 218 +++++++++++++++++++++++++++++++++
 lib/cookies/algorithm.h        | 101 +++++++++++++++
 lib/cookies/control.c          | 213 ++------------------------------
 lib/cookies/control.h          |  80 +-----------
 lib/layer/cookiemonster.c      |  63 ++++++----
 lib/lib.mk                     |   4 +-
 modules/cookiectl/cookiectl.c  |  29 ++---
 modules/cookiectl/cookiectl.mk |   5 +
 8 files changed, 392 insertions(+), 321 deletions(-)
 create mode 100644 lib/cookies/algorithm.c
 create mode 100644 lib/cookies/algorithm.h

diff --git a/lib/cookies/algorithm.c b/lib/cookies/algorithm.c
new file mode 100644
index 000000000..5724c9b17
--- /dev/null
+++ b/lib/cookies/algorithm.c
@@ -0,0 +1,218 @@
+/*  Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <arpa/inet.h> /* inet_ntop() */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+#include "contrib/fnv/fnv.h"
+#include "lib/cookies/algorithm.h"
+
+//#define CC_HASH_USE_CLIENT_ADDRESS /* When defined, client address will be used when generating client cookie. */
+
+const struct kr_clnt_cookie_alg_descr kr_clnt_cookie_algs[] = {
+	{ kr_clnt_cookie_alg_fnv64, "FNV-64" },
+	{ kr_clnt_cookie_alg_hmac_sha256_64, "HMAC-SHA256-64" },
+	{ NULL, NULL }
+};
+
+clnt_cookie_alg_t *kr_clnt_cookie_alg_func(const struct kr_clnt_cookie_alg_descr cc_algs[],
+                                           const char *name)
+{
+	if (!cc_algs || !name) {
+		return NULL;
+	}
+
+	const struct kr_clnt_cookie_alg_descr *aux_ptr = cc_algs;
+	while (aux_ptr && aux_ptr->func) {
+		assert(aux_ptr->name);
+		if (strcmp(aux_ptr->name, name) == 0) {
+			return aux_ptr->func;
+		}
+		++aux_ptr;
+	}
+
+	return NULL;
+}
+
+const char *kr_clnt_cookie_alg_name(const struct kr_clnt_cookie_alg_descr cc_algs[],
+                                    clnt_cookie_alg_t *func)
+{
+	if (!cc_algs || !func) {
+		return NULL;
+	}
+
+	const struct kr_clnt_cookie_alg_descr *aux_ptr = cc_algs;
+	while (aux_ptr && aux_ptr->func) {
+		assert(aux_ptr->name);
+		if (aux_ptr->func == func) {
+			return aux_ptr->name;
+		}
+		++aux_ptr;
+	}
+
+	return NULL;
+}
+
+int kr_address_bytes(const void *sockaddr, const uint8_t **addr, size_t *len)
+{
+	if (!sockaddr || !addr || !len) {
+		return kr_error(EINVAL);
+	}
+
+	int addr_family = ((struct sockaddr *) sockaddr)->sa_family;
+
+	switch (addr_family) {
+	case AF_INET:
+		*addr = (uint8_t *) &((struct sockaddr_in *) sockaddr)->sin_addr;
+		*len = 4;
+		break;
+	case AF_INET6:
+		*addr = (uint8_t *) &((struct sockaddr_in6 *) sockaddr)->sin6_addr;
+		*len = 16;
+		break;
+	default:
+		*addr = NULL;
+		*len = 0;
+		addr_family = AF_UNSPEC;
+		return kr_error(EINVAL);
+		break;
+	}
+
+	return kr_ok();
+}
+
+int kr_clnt_cookie_alg_fnv64(const struct kr_clnt_cookie_input *input,
+                             uint8_t cc_out[KNOT_OPT_COOKIE_CLNT])
+{
+	if (!input || !cc_out) {
+		return kr_error(EINVAL);
+	}
+
+	if ((!input->clnt_sockaddr && !input->srvr_sockaddr) ||
+	    !(input->secret_data && input->secret_len)) {
+		return kr_error(EINVAL);
+	}
+
+	const uint8_t *addr = NULL;
+	size_t alen = 0; /* Address length. */
+
+	Fnv64_t hash_val = FNV1A_64_INIT;
+
+#if defined(CC_HASH_USE_CLIENT_ADDRESS)
+	if (input->clnt_sockaddr) {
+		if (kr_ok() == kr_address_bytes(input->clnt_sockaddr, &addr,
+		                                &alen)) {
+			assert(addr && alen);
+			hash_val = fnv_64a_buf(addr, alen, hash_val);
+		}
+	}
+#endif /* defined(CC_HASH_USE_CLIENT_ADDRESS) */
+
+	if (input->srvr_sockaddr) {
+		if (kr_ok() == kr_address_bytes(input->srvr_sockaddr, &addr,
+		                                &alen)) {
+			assert(addr && alen);
+			hash_val = fnv_64a_buf((void *) addr, alen, hash_val);
+		}
+	}
+
+	hash_val = fnv_64a_buf((void *) input->secret_data, input->secret_len,
+	                       hash_val);
+
+	assert(KNOT_OPT_COOKIE_CLNT == sizeof(hash_val));
+
+	memcpy(cc_out, &hash_val, KNOT_OPT_COOKIE_CLNT);
+
+	return kr_ok();
+}
+
+int kr_clnt_cookie_alg_hmac_sha256_64(const struct kr_clnt_cookie_input *input,
+                                      uint8_t cc_out[KNOT_OPT_COOKIE_CLNT])
+{
+	if (!input || !cc_out) {
+		return kr_error(EINVAL);
+	}
+
+	if ((!input->clnt_sockaddr && !input->srvr_sockaddr) ||
+	    !(input->secret_data && input->secret_len)) {
+		return kr_error(EINVAL);
+	}
+
+	const uint8_t *addr = NULL;
+	size_t alen = 0; /* Address length. */
+
+	uint8_t digest[SHA256_DIGEST_LENGTH];
+	unsigned int digest_len = SHA256_DIGEST_LENGTH;
+
+	/* text: (client IP | server IP)
+	 * key: client secret */
+
+	HMAC_CTX ctx;
+	HMAC_CTX_init(&ctx);
+
+	int ret = HMAC_Init_ex(&ctx, input->secret_data, input->secret_len,
+	                       EVP_sha256(), NULL);
+	if (ret != 1) {
+		ret = kr_error(EINVAL);
+		goto fail;
+	}
+
+#if defined(CC_HASH_USE_CLIENT_ADDRESS)
+	if (input->clnt_sockaddr) {
+		if (kr_ok() == kr_address_bytes(input->clnt_sockaddr, &addr,
+		                                &alen)) {
+			assert(addr && alen);
+			ret = HMAC_Update(&ctx, addr, alen);
+			if (ret != 1) {
+				ret = kr_error(EINVAL);
+				goto fail;
+			}
+		}
+	}
+#endif /* defined(CC_HASH_USE_CLIENT_ADDRESS) */
+
+	if (input->srvr_sockaddr) {
+		if (kr_ok() == kr_address_bytes(input->srvr_sockaddr, &addr,
+		                                &alen)) {
+			assert(addr && alen);
+			ret = HMAC_Update(&ctx, addr, alen);
+			if (ret != 1) {
+				ret = kr_error(EINVAL);
+				goto fail;
+			}
+		}
+	}
+
+	if (1 != HMAC_Final(&ctx, digest, &digest_len)) {
+		ret = kr_error(EINVAL);
+		goto fail;
+	}
+
+	assert(KNOT_OPT_COOKIE_CLNT <= SHA256_DIGEST_LENGTH);
+
+	memcpy(cc_out, digest, KNOT_OPT_COOKIE_CLNT);
+	ret = kr_ok();
+
+fail:
+	HMAC_CTX_cleanup(&ctx);
+	return ret;
+}
diff --git a/lib/cookies/algorithm.h b/lib/cookies/algorithm.h
new file mode 100644
index 000000000..e3fc53138
--- /dev/null
+++ b/lib/cookies/algorithm.h
@@ -0,0 +1,101 @@
+/*  Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <libknot/rrtype/opt_cookie.h>
+
+#include "lib/defines.h"
+
+/** Maximal size of a cookie option. */
+#define KR_COOKIE_OPT_MAX_LEN (KNOT_EDNS_OPTION_HDRLEN + KNOT_OPT_COOKIE_CLNT + KNOT_OPT_COOKIE_SRVR_MAX)
+
+/** Client cookie computation context. */
+struct kr_clnt_cookie_input {
+	const void *clnt_sockaddr; /**< Client (local) socket address. */
+	const void *srvr_sockaddr; /**< Server (remote) socket address. */
+	const uint8_t *secret_data; /**< Client secret data. */
+	size_t secret_len;
+};
+
+/** Client cookie algorithm type. */
+typedef int (clnt_cookie_alg_t)(const struct kr_clnt_cookie_input *input,
+                                uint8_t *);
+
+/** Holds description of client cookie hashing algorithms. */
+struct kr_clnt_cookie_alg_descr {
+	clnt_cookie_alg_t *func; /**< Pointer to has function. */
+	const char *name; /**< Hash function name. */
+};
+
+/**
+ * List of available client cookie algorithms.
+ *
+ * Last element contains all null entries.
+ */
+KR_EXPORT
+extern const struct kr_clnt_cookie_alg_descr kr_clnt_cookie_algs[];
+
+/**
+ * @brief Return pointer to client cookie hash function with given name.
+ * @param cc_algs List of available algorithms.
+ * @param name    Algorithm name.
+ * @return pointer to function or NULL if not found.
+ */
+KR_EXPORT
+clnt_cookie_alg_t *kr_clnt_cookie_alg_func(const struct kr_clnt_cookie_alg_descr cc_algs[],
+                                           const char *name);
+
+/**
+ * @brief Return name of given client cookie hash function.
+ * @param cc_algs List of available algorithms.
+ * @param func    Sought algorithm function.
+ * @return pointer to string or NULL if not found.
+ */
+KR_EXPORT
+const char *kr_clnt_cookie_alg_name(const struct kr_clnt_cookie_alg_descr cc_algs[],
+                                    clnt_cookie_alg_t *func);
+
+/**
+ * Get pointers to IP address bytes.
+ * @param sockaddr socket address
+ * @param addr pointer to address
+ * @param len address length
+ * @return kr_ok() on success, error code else.
+ */
+int kr_address_bytes(const void *sockaddr, const uint8_t **addr, size_t *len);
+
+/**
+ * Compute client cookie using FNV-64.
+ * @note At least one of the arguments must be non-null.
+ * @param input  Input parameters.
+ * @param cc_out Buffer for computed client cookie.
+ * @return kr_ok() on success, error code else.
+ */
+KR_EXPORT
+int kr_clnt_cookie_alg_fnv64(const struct kr_clnt_cookie_input *input,
+                             uint8_t cc_out[KNOT_OPT_COOKIE_CLNT]);
+
+/**
+ * Compute client cookie using HMAC_SHA256-64.
+ * @note At least one of the arguments must be non-null.
+ * @param input  Input parameters.
+ * @param cc_out Buffer for computed client cookie.
+ * @return kr_ok() on success, error code else.
+ */
+KR_EXPORT
+int kr_clnt_cookie_alg_hmac_sha256_64(const struct kr_clnt_cookie_input *input,
+                                      uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT]);
diff --git a/lib/cookies/control.c b/lib/cookies/control.c
index 5be9a2261..778c51f27 100644
--- a/lib/cookies/control.c
+++ b/lib/cookies/control.c
@@ -16,17 +16,11 @@
 
 //#define MODULE_DEBUG_MSGS 1 /* Comment out if debug messages are not desired. */
 
-#include <arpa/inet.h> /* inet_ntop() */
-#include <sys/socket.h>
-#include <netinet/in.h>
 #include <assert.h>
 #include <libknot/error.h>
-#include <openssl/hmac.h>
-#include <openssl/sha.h>
 #include <stdint.h>
 #include <string.h>
 
-#include "contrib/fnv/fnv.h"
 #include "lib/cookies/cache.h"
 #include "lib/cookies/control.h"
 #include "lib/layer.h"
@@ -38,20 +32,12 @@
 #  define DEBUG_MSG(qry, fmt...) do { } while (0)
 #endif /* defined(MODULE_DEBUG_MSGS) */
 
-//#define CC_HASH_USE_CLIENT_ADDRESS /* When defined, client address will be used when generating client cookie. */
-
 /* Default client secret. */
 struct kr_cookie_secret dflt_cs = {
 	.size = KNOT_OPT_COOKIE_CLNT,
 	.data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
 };
 
-const struct kr_cc_hash_descr kr_cc_hashes[] = {
-	{ kr_cc_compute_fnv64, "FNV-64" },
-	{ kr_cc_compute_hmac_sha256_64, "HMAC-SHA256-64" },
-	{ NULL, NULL }
-};
-
 struct kr_cookie_ctx kr_glob_cookie_ctx = {
 	.enabled = false,
 	.current_cs = &dflt_cs
@@ -106,194 +92,6 @@ static int opt_rr_add_option(knot_rrset_t *opt_rr, uint8_t *option,
 	return KNOT_EOK;
 }
 
-cc_compute_func_t *kr_cc_hash_func(const struct kr_cc_hash_descr cc_hashes[],
-                                   const char *name)
-{
-	if (!cc_hashes || !name) {
-		return NULL;
-	}
-
-	const struct kr_cc_hash_descr *aux_ptr = cc_hashes;
-
-	while (aux_ptr && aux_ptr->hash_func) {
-		assert(aux_ptr->name);
-		if (strcmp(aux_ptr->name, name) == 0) {
-			return aux_ptr->hash_func;
-		}
-		++aux_ptr;
-	}
-
-	return NULL;
-}
-
-const char *kr_cc_hash_name(const struct kr_cc_hash_descr cc_hashes[],
-                            cc_compute_func_t *func)
-{
-	if (!cc_hashes || !func) {
-		return NULL;
-	}
-
-	const struct kr_cc_hash_descr *aux_ptr = cc_hashes;
-	while (aux_ptr && aux_ptr->hash_func) {
-		assert(aux_ptr->name);
-		if (aux_ptr->hash_func == func) {
-			return aux_ptr->name;
-		}
-		++aux_ptr;
-	}
-
-	return NULL;
-}
-
-int kr_address_bytes(const void *sockaddr, const uint8_t **addr, size_t *len)
-{
-	if (!sockaddr || !addr || !len) {
-		return kr_error(EINVAL);
-	}
-
-	int addr_family = ((struct sockaddr *) sockaddr)->sa_family;
-
-	switch (addr_family) {
-	case AF_INET:
-		*addr = (uint8_t *) &((struct sockaddr_in *) sockaddr)->sin_addr;
-		*len = 4;
-		break;
-	case AF_INET6:
-		*addr = (uint8_t *) &((struct sockaddr_in6 *) sockaddr)->sin6_addr;
-		*len = 16;
-		break;
-	default:
-		*addr = NULL;
-		*len = 0;
-		addr_family = AF_UNSPEC;
-		DEBUG_MSG(NULL, "%s\n", "could obtain IP address");
-		return kr_error(EINVAL);
-		break;
-	}
-
-	WITH_DEBUG {
-		char ns_str[INET6_ADDRSTRLEN];
-		inet_ntop(addr_family, *addr, ns_str, sizeof(ns_str));
-		DEBUG_MSG(NULL, "obtained IP address '%s'\n", ns_str);
-	}
-
-	return kr_ok();
-}
-
-int kr_cc_compute_fnv64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT],
-                        const void *clnt_sockaddr, const void *srvr_sockaddr,
-                        const struct kr_cookie_secret *secret)
-{
-	if (!cc_buf) {
-		return kr_error(EINVAL);
-	}
-
-	if ((!clnt_sockaddr && !srvr_sockaddr) ||
-	    !(secret && secret->size && secret->data)) {
-		return kr_error(EINVAL);
-	}
-
-	const uint8_t *addr = NULL;
-	size_t alen = 0; /* Address length. */
-
-	Fnv64_t hash_val = FNV1A_64_INIT;
-
-#if defined(CC_HASH_USE_CLIENT_ADDRESS)
-	if (clnt_sockaddr) {
-		if (kr_ok() == kr_address_bytes(clnt_sockaddr, &addr, &alen)) {
-			assert(addr && alen);
-			hash_val = fnv_64a_buf(addr, alen, hash_val);
-		}
-	}
-#endif /* defined(CC_HASH_USE_CLIENT_ADDRESS) */
-
-	if (srvr_sockaddr) {
-		if (kr_ok() == kr_address_bytes(srvr_sockaddr, &addr, &alen)) {
-			assert(addr && alen);
-			hash_val = fnv_64a_buf((void *) addr, alen, hash_val);
-		}
-	}
-
-	hash_val = fnv_64a_buf((void *) secret->data, secret->size, hash_val);
-
-	assert(KNOT_OPT_COOKIE_CLNT == sizeof(hash_val));
-
-	memcpy(cc_buf, &hash_val, KNOT_OPT_COOKIE_CLNT);
-
-	return kr_ok();
-}
-
-int kr_cc_compute_hmac_sha256_64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT],
-                                 const void *clnt_sockaddr, const void *srvr_sockaddr,
-                                 const struct kr_cookie_secret *secret)
-{
-	if (!cc_buf) {
-		return kr_error(EINVAL);
-	}
-
-	if ((!clnt_sockaddr && !srvr_sockaddr) ||
-	    !(secret && secret->size && secret->data)) {
-		return kr_error(EINVAL);
-	}
-
-	const uint8_t *addr = NULL;
-	size_t alen = 0; /* Address length. */
-
-	uint8_t digest[SHA256_DIGEST_LENGTH];
-	unsigned int digest_len = SHA256_DIGEST_LENGTH;
-
-	/* text: (client IP | server IP)
-	 * key: client secret */
-
-	HMAC_CTX ctx;
-	HMAC_CTX_init(&ctx);
-
-	int ret = HMAC_Init_ex(&ctx, secret->data, secret->size, EVP_sha256(),
-	                       NULL);
-	if (ret != 1) {
-		ret = kr_error(EINVAL);
-		goto fail;
-	}
-
-#if defined(CC_HASH_USE_CLIENT_ADDRESS)
-	if (clnt_sockaddr) {
-		if (kr_ok() == kr_address_bytes(clnt_sockaddr, &addr, &alen)) {
-			assert(addr && alen);
-			ret = HMAC_Update(&ctx, addr, alen);
-			if (ret != 1) {
-				ret = kr_error(EINVAL);
-				goto fail;
-			}
-		}
-	}
-#endif /* defined(CC_HASH_USE_CLIENT_ADDRESS) */
-
-	if (srvr_sockaddr) {
-		if (kr_ok() == kr_address_bytes(srvr_sockaddr, &addr, &alen)) {
-			assert(addr && alen);
-			ret = HMAC_Update(&ctx, addr, alen);
-			if (ret != 1) {
-				ret = kr_error(EINVAL);
-				goto fail;
-			}
-		}
-	}
-
-	if (1 != HMAC_Final(&ctx, digest, &digest_len)) {
-		ret = kr_error(EINVAL);
-		goto fail;
-	}
-
-	assert(KNOT_OPT_COOKIE_CLNT <= SHA256_DIGEST_LENGTH);
-
-	memcpy(cc_buf, digest, KNOT_OPT_COOKIE_CLNT);
-	ret = kr_ok();
-
-fail:
-	HMAC_CTX_cleanup(&ctx);
-	return ret;
-}
-
 /**
  * Check whether there is a cached cookie that matches the current client
  * cookie.
@@ -347,10 +145,15 @@ int kr_request_put_cookie(const struct kr_cookie_ctx *cntrl,
 	/* Generate client cookie.
 	 * TODO -- generate client cookie from client address, server address
 	 * and secret quantity. */
+	struct kr_clnt_cookie_input input = {
+		.clnt_sockaddr = clnt_sockaddr,
+		.srvr_sockaddr = srvr_sockaddr,
+		.secret_data = cntrl->current_cs->data,
+		.secret_len = cntrl->current_cs->size
+	};
 	uint8_t cc[KNOT_OPT_COOKIE_CLNT];
-	assert(cntrl->cc_compute_func);
-	int ret = cntrl->cc_compute_func(cc, clnt_sockaddr, srvr_sockaddr,
-	                                 cntrl->current_cs);
+	assert(cntrl->cc_alg_func);
+	int ret = cntrl->cc_alg_func(&input, cc);
 	if (ret != kr_ok()) {
 		return ret;
 	}
diff --git a/lib/cookies/control.h b/lib/cookies/control.h
index 520ae6b54..98727d99e 100644
--- a/lib/cookies/control.h
+++ b/lib/cookies/control.h
@@ -20,12 +20,10 @@
 #include <libknot/rrtype/opt_cookie.h>
 #include <stdbool.h>
 
+#include "lib/cookies/algorithm.h"
 #include "lib/cache.h"
 #include "lib/defines.h"
 
-/** Maximal size of a cookie option. */
-#define KR_COOKIE_OPT_MAX_LEN (KNOT_EDNS_OPTION_HDRLEN + KNOT_OPT_COOKIE_CLNT + KNOT_OPT_COOKIE_SRVR_MAX)
-
 /** Holds secret quantity. */
 struct kr_cookie_secret {
 	size_t size; /*!< Secret quantity size. */
@@ -39,24 +37,6 @@ extern struct kr_cookie_secret dflt_cs;
 /** Default cookie TTL. */
 #define DFLT_COOKIE_TTL 72000
 
-/** Client cookie creation function type. */
-typedef int (cc_compute_func_t)(uint8_t *, const void *, const void *,
-                               const struct kr_cookie_secret *);
-
-/** Holds description of client cookie hashing algorithms. */
-struct kr_cc_hash_descr {
-	cc_compute_func_t *hash_func; /**< Pointer to has function. */
-	const char *name; /**< Hash function name. */
-};
-
-/**
- * List of available client cookie hash functions.
- *
- * Last element contains all null entries.
- */
-KR_EXPORT
-extern const struct kr_cc_hash_descr kr_cc_hashes[];
-
 /** DNS cookies controlling structure. */
 struct kr_cookie_ctx {
 	bool enabled; /**< Enabled/disables DNS cookies functionality. */
@@ -66,69 +46,13 @@ struct kr_cookie_ctx {
 
 	uint32_t cache_ttl; /**< TTL used when caching cookies */
 
-	cc_compute_func_t *cc_compute_func; /**< Client cookie hash computation callback. */
+	clnt_cookie_alg_t *cc_alg_func; /**< Client cookie hash computation callback. */
 };
 
 /** Global cookie control context. */
 KR_EXPORT
 extern struct kr_cookie_ctx kr_glob_cookie_ctx;
 
-/**
- * @brief Return pointer to client cookie hash function with given name.
- * @param cc_hashes list of avilable has functions
- * @param name has function name
- * @return pointer to function or NULL if not found
- */
-KR_EXPORT
-cc_compute_func_t *kr_cc_hash_func(const struct kr_cc_hash_descr cc_hashes[],
-                                   const char *name);
-
-/**
- * @brief Return name of given client cookie hash function.
- * @param cc_hashes list of avilable has functions
- * @param func sought function
- * @return pointer to string or NULL if not found
- */
-KR_EXPORT
-const char *kr_cc_hash_name(const struct kr_cc_hash_descr cc_hashes[],
-                            cc_compute_func_t *func);
-
-/**
- * Get pointers to IP address bytes.
- * @param sockaddr socket address
- * @param addr pointer to address
- * @param len address length
- */
-int kr_address_bytes(const void *sockaddr, const uint8_t **addr, size_t *len);
-
-/**
- * Compute client cookie using FNV-64.
- * @note At least one of the arguments must be non-null.
- * @param cc_buf        Buffer to which to write the cookie into.
- * @param clnt_sockaddr Client address.
- * @param srvr_sockaddr Server address.
- * @param secret        Client secret quantity.
- * @return kr_ok() on success, error code else.
- */
-KR_EXPORT
-int kr_cc_compute_fnv64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT],
-                        const void *clnt_sockaddr, const void *srvr_sockaddr,
-                        const struct kr_cookie_secret *secret);
-
-/**
- * Compute client cookie using HMAC_SHA256-64.
- * @note At least one of the arguments must be non-null.
- * @param cc_buf        Buffer to which to write the cookie into.
- * @param clnt_sockaddr Client address.
- * @param srvr_sockaddr Server address.
- * @param secret        Client secret quantity.
- * @return kr_ok() on success, error code else.
- */
-KR_EXPORT
-int kr_cc_compute_hmac_sha256_64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT],
-                                 const void *clnt_sockaddr, const void *srvr_sockaddr,
-                                 const struct kr_cookie_secret *secret);
-
 /**
  * Insert a DNS cookie into query packet.
  * @note The packet must already contain ENDS section.
diff --git a/lib/layer/cookiemonster.c b/lib/layer/cookiemonster.c
index d5b546a73..4bed370b1 100644
--- a/lib/layer/cookiemonster.c
+++ b/lib/layer/cookiemonster.c
@@ -25,11 +25,14 @@
 #include <string.h>
 
 #include "daemon/engine.h"
+#include "lib/cookies/algorithm.h"
 #include "lib/cookies/cache.h"
 #include "lib/cookies/control.h"
 #include "lib/module.h"
 #include "lib/layer.h"
 
+#include "lib/layer/__/print_pkt.h"
+
 #define DEBUG_MSG(qry, fmt...) QRDEBUG(qry, "cookiemonster",  fmt)
 
 /* TODO -- The context must store sent cookies and server addresses in order
@@ -39,22 +42,21 @@
  * Check whether supplied client cookie was generated from given client secret
  * and address.
  * @param cc client cookie
- * @param clnt_sockaddr client socket address (i.e. resolver address)
- * @param srvr_sockaddr server socket address
- * @param csecr client secret
- * @param cc_compute_func function generating client cookie
+ * @param input input cookie algorithm parameters
+ * @param cc_alg_func function generating client cookie
  * @return kr_ok() or error code
  */
 static int check_client_cookie(const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
-                               const void *clnt_sockaddr,
-                               const void *srvr_sockaddr,
-                               const struct kr_cookie_secret *csecr,
-                               cc_compute_func_t *cc_compute_func)
+                               const struct kr_clnt_cookie_input *input,
+                               clnt_cookie_alg_t *cc_alg_func)
 {
+	if (!cc || !input || !cc_alg_func) {
+		return kr_error(EINVAL);
+	}
+
 	uint8_t generated_cc[KNOT_OPT_COOKIE_CLNT] = {0, };
 
-	int ret = cc_compute_func(generated_cc, clnt_sockaddr,
-	                          srvr_sockaddr, csecr);
+	int ret = cc_alg_func(input, generated_cc);
 	if (ret != kr_ok()) {
 		return ret;
 	}
@@ -90,25 +92,33 @@ static const struct sockaddr *passed_server_sockaddr(const struct kr_query *qry)
  * @param nsrep name server reputation context
  * @param cc client cookie data
  * @param csecr client secret
- * @param cc_compute_func function generating client cookie
+ * @param cc_alg_func function generating client cookie
  * @return pointer to address if a matching found, NULL if none matches
  */
 static const struct sockaddr *guess_server_addr(const struct kr_nsrep *nsrep,
                                                 const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
                                                 const struct kr_cookie_secret *csecr,
-                                                cc_compute_func_t *cc_compute_func)
+                                                clnt_cookie_alg_t *cc_alg_func)
 {
-	assert(nsrep && cc && csecr && cc_compute_func);
+	assert(nsrep && cc && csecr && cc_alg_func);
 
 	const struct sockaddr *sockaddr = NULL;
 
+	struct kr_clnt_cookie_input input = {
+		.clnt_sockaddr = NULL,
+		.srvr_sockaddr = NULL,
+		.secret_data = csecr->data,
+		.secret_len = csecr->size
+	};
+
 	/* Abusing name server reputation mechanism to obtain IP addresses. */
 	for (int i = 0; i < KR_NSREP_MAXADDR; ++i) {
 		if (nsrep->addr[i].ip.sa_family == AF_UNSPEC) {
 			break;
 		}
-		int ret = check_client_cookie(cc, NULL, &nsrep->addr[i], csecr,
-		                              cc_compute_func);
+
+		input.srvr_sockaddr = &nsrep->addr[i];
+		int ret = check_client_cookie(cc, &input, cc_alg_func);
 		if (ret == kr_ok()) {
 			sockaddr = (struct sockaddr *) &nsrep->addr[i];
 			break;
@@ -137,14 +147,21 @@ static int srvr_sockaddr_cc_check(const struct sockaddr **sockaddr,
 
 	/* The address must correspond with the client cookie. */
 	if (tmp_sockaddr) {
-		int ret = check_client_cookie(cc, NULL, tmp_sockaddr,
-		                              cntrl->current_cs,
-		                              cntrl->cc_compute_func);
+		assert(cntrl->current_cs);
+
+		struct kr_clnt_cookie_input input = {
+			.clnt_sockaddr = NULL,
+			.srvr_sockaddr = tmp_sockaddr,
+			.secret_data = cntrl->current_cs->data,
+			.secret_len = cntrl->current_cs->size
+		};
+		int ret = check_client_cookie(cc, &input, cntrl->cc_alg_func);
 		bool have_current = (ret == kr_ok());
 		if ((ret != kr_ok()) && cntrl->recent_cs) {
-			ret = check_client_cookie(cc, NULL, tmp_sockaddr,
-			                          cntrl->recent_cs,
-			                          cntrl->cc_compute_func);
+			input.secret_data = cntrl->recent_cs->data;
+			input.secret_len = cntrl->recent_cs->size;
+			ret = check_client_cookie(cc, &input,
+			                          cntrl->cc_alg_func);
 		}
 		if (ret == kr_ok()) {
 			*sockaddr = tmp_sockaddr;
@@ -163,12 +180,12 @@ static int srvr_sockaddr_cc_check(const struct sockaddr **sockaddr,
 	/* Abusing name server reputation mechanism to guess IP addresses. */
 	const struct kr_nsrep *ns = &qry->ns;
 	tmp_sockaddr = guess_server_addr(ns, cc, cntrl->current_cs,
-	                                 cntrl->cc_compute_func);
+	                                 cntrl->cc_alg_func);
 	bool have_current = (tmp_sockaddr != NULL);
 	if (!tmp_sockaddr && cntrl->recent_cs) {
 		/* Try recent client secret to check obtained cookie. */
 		tmp_sockaddr = guess_server_addr(ns, cc, cntrl->recent_cs,
-		                                 cntrl->cc_compute_func);
+		                                 cntrl->cc_alg_func);
 	}
 	if (tmp_sockaddr) {
 		*sockaddr = tmp_sockaddr;
diff --git a/lib/lib.mk b/lib/lib.mk
index 5783e9a93..ac5e53827 100644
--- a/lib/lib.mk
+++ b/lib/lib.mk
@@ -1,5 +1,4 @@
 libkres_SOURCES := \
-	contrib/fnv/hash_64a.c \
 	lib/generic/map.c      \
 	lib/layer/iterate.c    \
 	lib/layer/validate.c   \
@@ -47,11 +46,14 @@ libkres_TARGET := -L$(abspath lib) -lkres
 
 ifeq ($(HAS_libcrypto),yes)
 libkres_SOURCES += \
+	contrib/fnv/hash_64a.c \
 	lib/layer/cookiemonster.c \
+	lib/cookies/algorithm.c \
 	lib/cookies/cache.c    \
 	lib/cookies/control.c
 
 libkres_HEADERS += \
+	lib/cookies/algorithm.h \
 	lib/cookies/cache.h    \
 	lib/cookies/control.h
 
diff --git a/modules/cookiectl/cookiectl.c b/modules/cookiectl/cookiectl.c
index c17848719..ce7fda084 100644
--- a/modules/cookiectl/cookiectl.c
+++ b/modules/cookiectl/cookiectl.c
@@ -21,6 +21,7 @@
 #include <string.h>
 
 #include "daemon/engine.h"
+#include "lib/cookies/algorithm.h"
 #include "lib/cookies/control.h"
 #include "lib/layer.h"
 
@@ -28,8 +29,8 @@
 
 #define NAME_ENABLED "enabled"
 #define NAME_CLIENT_SECRET "client_secret"
-#define NAME_CLIENT_HASH_FUNC "client_hash_func"
-#define NAME_AVAILABLE_CLIENT_HASH_FUNCS "available_client_hash_funcs"
+#define NAME_CLIENT_COOKIE_ALG "client_cookie_alg"
+#define NAME_AVAILABLE_CLIENT_COOKIE_ALGS "available_client_cookie_algs"
 #define NAME_CACHE_TTL "cache_ttl"
 
 static bool aply_enabled(struct kr_cookie_ctx *cntrl, const JsonNode *node)
@@ -132,12 +133,12 @@ static bool apply_client_hash_func(struct kr_cookie_ctx *cntrl,
                                    const JsonNode *node)
 {
 	if (node->tag == JSON_STRING) {
-		cc_compute_func_t *cc_compute_func = kr_cc_hash_func(kr_cc_hashes,
-		                                                     node->string_);
-		if (!cc_compute_func) {
+		clnt_cookie_alg_t *cc_alg_func = kr_clnt_cookie_alg_func(kr_clnt_cookie_algs,
+		                                                         node->string_);
+		if (!cc_alg_func) {
 			return false;
 		}
-		cntrl->cc_compute_func = cc_compute_func;
+		cntrl->cc_alg_func = cc_alg_func;
 		return true;
 	}
 
@@ -167,7 +168,7 @@ static bool apply_configuration(struct kr_cookie_ctx *cntrl, const JsonNode *nod
 		return aply_enabled(cntrl, node);
 	} else if (strcmp(node->key, NAME_CLIENT_SECRET) == 0) {
 		return apply_client_secret(cntrl, node);
-	} else  if (strcmp(node->key, NAME_CLIENT_HASH_FUNC) == 0) {
+	} else  if (strcmp(node->key, NAME_CLIENT_COOKIE_ALG) == 0) {
 		return apply_client_hash_func(cntrl, node);
 	} else if (strcmp(node->key, NAME_CACHE_TTL) == 0) {
 		return apply_cache_ttl(cntrl, node);
@@ -214,8 +215,8 @@ static bool read_available_cc_hashes(JsonNode *root,
 		return false;
 	}
 
-	const struct kr_cc_hash_descr *aux_ptr = kr_cc_hashes;
-	while (aux_ptr && aux_ptr->hash_func) {
+	const struct kr_clnt_cookie_alg_descr *aux_ptr = kr_clnt_cookie_algs;
+	while (aux_ptr && aux_ptr->func) {
 		assert(aux_ptr->name);
 		JsonNode *element = json_mkstring(aux_ptr->name);
 		if (!element) {
@@ -225,7 +226,7 @@ static bool read_available_cc_hashes(JsonNode *root,
 		++aux_ptr;
 	}
 
-	json_append_member(root, NAME_AVAILABLE_CLIENT_HASH_FUNCS, array);
+	json_append_member(root, NAME_AVAILABLE_CLIENT_COOKIE_ALGS, array);
 
 	return true;
 
@@ -262,10 +263,10 @@ static char *cookiectl_config(void *env, struct kr_module *module, const char *a
 
 	read_secret(root_node, &kr_glob_cookie_ctx);
 
-	const char *name = kr_cc_hash_name(kr_cc_hashes,
-	                                   kr_glob_cookie_ctx.cc_compute_func);
+	const char *name = kr_clnt_cookie_alg_name(kr_clnt_cookie_algs,
+	                                           kr_glob_cookie_ctx.cc_alg_func);
 	assert(name);
-	json_append_member(root_node, NAME_CLIENT_HASH_FUNC,
+	json_append_member(root_node, NAME_CLIENT_COOKIE_ALG,
 	                   json_mkstring(name));
 
 	read_available_cc_hashes(root_node, &kr_glob_cookie_ctx);
@@ -292,7 +293,7 @@ int cookiectl_init(struct kr_module *module)
 	kr_glob_cookie_ctx.enabled = false;
 	kr_glob_cookie_ctx.current_cs = &dflt_cs;
 	kr_glob_cookie_ctx.cache_ttl = DFLT_COOKIE_TTL;
-	kr_glob_cookie_ctx.cc_compute_func = kr_cc_compute_fnv64;
+	kr_glob_cookie_ctx.cc_alg_func = kr_clnt_cookie_alg_fnv64;
 
 	module->data = NULL;
 
diff --git a/modules/cookiectl/cookiectl.mk b/modules/cookiectl/cookiectl.mk
index 4962ec80b..f495577d4 100644
--- a/modules/cookiectl/cookiectl.mk
+++ b/modules/cookiectl/cookiectl.mk
@@ -1,5 +1,10 @@
 cookiectl_CFLAGS := -fvisibility=hidden -fPIC
 cookiectl_SOURCES := \
+	modules/cookiectl/contrib/openbsd/strlcat.c \
+	modules/cookiectl/contrib/openbsd/strlcpy.c \
+	modules/cookiectl/contrib/print.c \
+	modules/cookiectl/contrib/sockaddr.c \
+	modules/cookiectl/print_pkt.c \
 	modules/cookiectl/cookiectl.c
 cookiectl_DEPEND := $(libkres)
 cookiectl_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS)
-- 
GitLab