$(eval $(call find_lib,lmdb))
$(eval $(call find_lib,libzscanner,2.1))
$(eval $(call find_lib,libuv,1.0))
+$(eval $(call find_lib,libcrypto))
$(eval $(call find_alt,lua,luajit))
$(eval $(call find_lib,cmocka))
$(eval $(call find_bin,doxygen))
BUILD_CFLAGS += $(addprefix -I,$(wildcard contrib/ccan/*) contrib/murmurhash3)
ifeq ($(ENABLE_cookies),yes)
-BUILD_CFLAGS += -DENABLE_COOKIES
+BUILD_CFLAGS += -DENABLE_COOKIES $(libcrypto_CFLAGS)
endif
# Overview
$(info [$(HAS_lua)] luajit (daemon))
$(info [$(HAS_libuv)] libuv (daemon))
$(info [$(HAS_gnutls)] libgnutls (daemon))
+ $(info [$(HAS_libcrypto)] crypto (DNS cookies))
$(info )
$(info Optional)
$(info --------)
#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 <libknot/error.h>
#include "contrib/fnv/fnv.h"
#include "lib/cookies/cache.h"
# 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}
+ .data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
struct kr_cookie_ctx kr_glob_cookie_ctx = {
WITH_DEBUG {
char ns_str[INET6_ADDRSTRLEN];
inet_ntop(addr_family, *addr, ns_str, sizeof(ns_str));
- DEBUG_MSG(NULL, "obtaned IP address '%s'\n", ns_str);
+ DEBUG_MSG(NULL, "obtained IP address '%s'\n", ns_str);
}
return kr_ok();
}
-int kr_client_cokie_fnv64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT],
- const void *clnt_sockaddr, const void *srvr_sockaddr,
- const struct kr_cookie_secret *secret)
+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 &&
+ if ((!clnt_sockaddr && !srvr_sockaddr) ||
!(secret && secret->size && secret->data)) {
return kr_error(EINVAL);
}
const uint8_t *addr = NULL;
- size_t size = 0;
+ size_t alen = 0; /* Address length. */
Fnv64_t hash_val = FNV1A_64_INIT;
- /* Client address currently always ignored. */
-#if 0
+#if defined(CC_HASH_USE_CLIENT_ADDRESS)
if (clnt_sockaddr) {
- if (kr_ok() == kr_address_bytes(clnt_sockaddr, &addr, &size)) {
- assert(addr && size);
- hash_val = fnv_64a_buf(addr, size, hash_val);
+ if (kr_ok() == kr_address_bytes(clnt_sockaddr, &addr, &alen)) {
+ assert(addr && alen);
+ hash_val = fnv_64a_buf(addr, alen, hash_val);
}
}
-#endif
+#endif /* defined(CC_HASH_USE_CLIENT_ADDRESS) */
if (srvr_sockaddr) {
- if (kr_ok() == kr_address_bytes(srvr_sockaddr, &addr, &size)) {
- assert(addr && size);
- hash_val = fnv_64a_buf((void *) addr, size, hash_val);
+ if (kr_ok() == kr_address_bytes(srvr_sockaddr, &addr, &alen)) {
+ assert(addr && alen);
+ hash_val = fnv_64a_buf((void *) addr, alen, hash_val);
}
}
- if (secret && secret->size && secret->data) {
- DEBUG_MSG(NULL, "%s\n", "adding client secret into cookie");
- hash_val = fnv_64a_buf((void *) addr, size, hash_val);
- }
+ hash_val = fnv_64a_buf((void *) secret->data, secret->size, hash_val);
assert(KNOT_OPT_COOKIE_CLNT == sizeof(hash_val));
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.
* TODO -- generate client cookie from client address, server address
* and secret quantity. */
uint8_t cc[KNOT_OPT_COOKIE_CLNT];
- int ret = kr_client_cokie_fnv64(cc, clnt_sockaddr, srvr_sockaddr,
- cntrl->current_cs);
+ assert(cntrl->cc_compute_func);
+ int ret = cntrl->cc_compute_func(cc, clnt_sockaddr, srvr_sockaddr,
+ cntrl->current_cs);
if (ret != kr_ok()) {
return ret;
}
/** 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 *);
+
/** DNS cookies controlling structure. */
struct kr_cookie_ctx {
bool enabled; /**< Enabled/disables DNS cookies functionality. */
uint32_t cache_ttl; /**< TTL used when caching cookies */
-// struct kr_cache cache; /*!< Server cookies cache. */
+ /**< Client cookie computation callback. */
+ cc_compute_func_t *cc_compute_func;
};
/** Global cookie control context. */
int kr_address_bytes(const void *sockaddr, const uint8_t **addr, size_t *len);
/**
- * Compute client cookie.
- * @not At least one of the arguments must be non-null.
+ * 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_client_cokie_fnv64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT],
- const void *clnt_sockaddr, const void *srvr_sockaddr,
- const struct kr_cookie_secret *secret);
+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.
* @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
* @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)
+ const struct kr_cookie_secret *csecr,
+ cc_compute_func_t *cc_compute_func)
{
uint8_t generated_cc[KNOT_OPT_COOKIE_CLNT] = {0, };
- int ret = kr_client_cokie_fnv64(generated_cc, clnt_sockaddr,
- srvr_sockaddr, csecr);
+ int ret = cc_compute_func(generated_cc, clnt_sockaddr,
+ srvr_sockaddr, csecr);
if (ret != kr_ok()) {
return ret;
}
* @param nsrep name server reputation context
* @param cc client cookie data
* @param csecr client secret
+ * @param cc_compute_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)
+ const struct kr_cookie_secret *csecr,
+ cc_compute_func_t *cc_compute_func)
{
- assert(nsrep && cc && csecr);
+ assert(nsrep && cc && csecr && cc_compute_func);
const struct sockaddr *sockaddr = NULL;
if (nsrep->addr[i].ip.sa_family == AF_UNSPEC) {
break;
}
- int ret = check_client_cookie(cc, NULL, &nsrep->addr[i], csecr);
+ int ret = check_client_cookie(cc, NULL, &nsrep->addr[i], csecr,
+ cc_compute_func);
if (ret == kr_ok()) {
sockaddr = (struct sockaddr *) &nsrep->addr[i];
break;
* @param cntr cookie control structure
* @return kr_ok() if matching address found, error code else
*/
-static int srvr_sockaddr_cc_check(const struct sockaddr **sockaddr, bool *is_current,
- const struct kr_query *qry,
+static int srvr_sockaddr_cc_check(const struct sockaddr **sockaddr,
+ bool *is_current, const struct kr_query *qry,
const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
const struct kr_cookie_ctx *cntrl)
{
/* The address must correspond with the client cookie. */
if (tmp_sockaddr) {
int ret = check_client_cookie(cc, NULL, tmp_sockaddr,
- cntrl->current_cs);
+ cntrl->current_cs,
+ cntrl->cc_compute_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->recent_cs,
+ cntrl->cc_compute_func);
}
if (ret == kr_ok()) {
*sockaddr = tmp_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);
+ tmp_sockaddr = guess_server_addr(ns, cc, cntrl->current_cs,
+ cntrl->cc_compute_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);
+ tmp_sockaddr = guess_server_addr(ns, cc, cntrl->recent_cs,
+ cntrl->cc_compute_func);
}
if (tmp_sockaddr) {
*sockaddr = tmp_sockaddr;
libkres_HEADERS += \
lib/cookies/cache.h \
lib/cookies/control.h
+
+libkres_LIBS += $(libcrypto_LIBS)
endif
# Make library
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;
+
// cookies_cache_init(&kr_glob_cookie_ctx.cache, engine);
module->data = NULL;