diff --git a/lib/cookies/algorithm.c b/lib/cookies/algorithm.c new file mode 100644 index 0000000000000000000000000000000000000000..5724c9b17e72cdc9042cc9eb0a8fc1e84de199e5 --- /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 0000000000000000000000000000000000000000..e3fc53138d7317d82d878e2591b76cc5723068c3 --- /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 5be9a2261714e67e47b7c6ff36e1c694711016e1..778c51f27a91e07caf602a9aba3ec0ddd9950dbf 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 520ae6b54ef7c44eec8564ab19c88222c98caa58..98727d99e1295a6291a4d171c6998aec5ef77926 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 d5b546a73e7b19d8f0f03d1dbb9a09e6e43b3de2..4bed370b1233e7e77c6c8a10a7b81c806ae7a774 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 5783e9a932916c1dfcf1cdd60dac5db44017b33a..ac5e538276249a3cb20bc82692ff13b297214bb8 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 c178487197866e0740fad8d416c609368caf5d4f..ce7fda084f3484d6bb609d0362fffa1d0d13ba8b 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 4962ec80bbfa7d2d8311fb61249aba24731a025e..f495577d414be71c7ee0acaf2d8426d9abce6b37 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)