#if defined(ENABLE_COOKIES)
#include <arpa/inet.h> /* inet_ntop() */
#include "lib/cookies/control.h"
+#include "lib/cookies/helper.h"
#endif /* defined(ENABLE_COOKIES) */
#include "lib/utils.h"
#include "lib/layer.h"
return true;
}
+ struct sockaddr_storage *sockaddr_ptr = NULL; /* Not supported yet. */
+#if 0
/* Libuv does not offer a convenient way how to obtain a source IP
* address from a UDP handle that has been initialised using
* uv_udp_init(). The uv_udp_getsockname() fails because of the lazy
* TODO -- A solution might be opening a separate socket and trying
* to obtain the IP address from it.
*/
-
struct sockaddr_storage sockaddr = {0, };
struct sockaddr_storage *sockaddr_ptr = &sockaddr;
int sockaddr_len = sizeof(sockaddr);
if (ret != 0) {
sockaddr_ptr = NULL;
}
+#endif /* 0 */
kr_request_put_cookie(&kr_glob_cookie_ctx.clnt.current, cookie_cache,
(struct sockaddr*) sockaddr_ptr, srvr_addr, pkt);
}
if (handle->type == UV_UDP) {
#if defined(ENABLE_COOKIES)
+ /* The actual server IP address is needed before generating the
+ * actual cookie. Also the resolver somehow mangles the query
+ * packets before building the query i.e. the space needed for
+ * the cookie cannot be allocated in the cookie layer. */
if (knot_wire_get_qr(pkt->wire) == 0) {
/* Update DNS cookies data in query. */
subreq_update_cookies((uv_udp_t *) handle, addr,
}
const struct kr_sc_alg_descr kr_sc_algs[] = {
- { "FNV-64-SIMPLE", &knot_sc_alg_fnv64_simple },
{ "FNV-64", &knot_sc_alg_fnv64 },
- { "HMAC-SHA256-64-SIMPLE", &knot_sc_alg_hmac_sha256_64_simple },
{ "HMAC-SHA256-64", &knot_sc_alg_hmac_sha256_64 },
{ NULL, NULL }
};
}
const struct kr_sc_alg_descr *aux_ptr = sc_algs;
- while (aux_ptr && aux_ptr->alg && aux_ptr->alg->gen_func) {
+ while (aux_ptr && aux_ptr->alg && aux_ptr->alg->hash_func) {
assert(aux_ptr->name);
if (strcmp(aux_ptr->name, name) == 0) {
return aux_ptr;
--- /dev/null
+/* 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> /* htonl(), ... */
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+#include <libknot/errcode.h>
+#include <libknot/rrtype/opt-cookie.h>
+
+#include "lib/cookies/alg_sha.h"
+#include "lib/utils.h"
+
+/**
+ * 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.
+ * @param cc_len Size of buffer/written data.
+ * @return KNOT_EOK on success, error code else.
+ */
+static int cc_gen_hmac_sha256_64(const struct knot_cc_input *input,
+ uint8_t *cc_out, uint16_t *cc_len)
+{
+ if (!input || !cc_out || !cc_len) {
+ return KNOT_EINVAL;
+ }
+
+ if ((!input->clnt_sockaddr && !input->srvr_sockaddr) ||
+ !(input->secret_data && input->secret_len)) {
+ return KNOT_EINVAL;
+ }
+
+ const uint8_t *addr = NULL;
+ int addr_len = 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 = KNOT_EINVAL;
+ goto fail;
+ }
+
+ if (input->clnt_sockaddr) {
+ addr = (uint8_t *)kr_inaddr(input->clnt_sockaddr);
+ addr_len = kr_inaddr_len(input->clnt_sockaddr);
+ if (addr && addr_len > 0) {
+ ret = HMAC_Update(&ctx, addr, addr_len);
+ if (ret != 1) {
+ ret = KNOT_EINVAL;
+ goto fail;
+ }
+ }
+ }
+
+ if (input->srvr_sockaddr) {
+ addr = (uint8_t *)kr_inaddr(input->srvr_sockaddr);
+ addr_len = kr_inaddr_len(input->srvr_sockaddr);
+ if (addr && addr_len > 0) {
+ ret = HMAC_Update(&ctx, addr, addr_len);
+ if (ret != 1) {
+ ret = KNOT_EINVAL;
+ goto fail;
+ }
+ }
+ }
+
+ if (1 != HMAC_Final(&ctx, digest, &digest_len)) {
+ ret = KNOT_EINVAL;
+ goto fail;
+ }
+
+ assert(KNOT_OPT_COOKIE_CLNT <= SHA256_DIGEST_LENGTH);
+ if (*cc_len < KNOT_OPT_COOKIE_CLNT) {
+ return KNOT_ESPACE;
+ }
+
+ *cc_len = KNOT_OPT_COOKIE_CLNT;
+ memcpy(cc_out, digest, *cc_len);
+ ret = KNOT_EOK;
+
+fail:
+ HMAC_CTX_cleanup(&ctx);
+ return ret;
+}
+
+#define SRVR_HMAC_SHA256_64_HASH_SIZE 8
+
+/**
+ * @brief Compute server cookie using HMAC-SHA256-64).
+ * @note Server cookie = nonce | time | HMAC-SHA256-64( server secret, client cookie | nonce| time | client IP )
+ * @param input data to compute cookie from
+ * @param hash_out hash cookie output buffer
+ * @param hash_len buffer size / written data size
+ * @return KNOT_EOK or error code.
+ */
+static int sc_gen_hmac_sha256_64(const struct knot_sc_input *input,
+ uint8_t *hash_out, uint16_t *hash_len)
+{
+ if (!input || !hash_out ||
+ !hash_len || (*hash_len < SRVR_HMAC_SHA256_64_HASH_SIZE)) {
+ return KNOT_EINVAL;
+ }
+
+ if (!input->cc || !input->cc_len || !input->srvr_data ||
+ !input->srvr_data->secret_data || !input->srvr_data->secret_len) {
+ return KNOT_EINVAL;
+ }
+
+ const uint8_t *addr = NULL;
+ size_t addr_len = 0; /* Address length. */
+
+ uint8_t digest[SHA256_DIGEST_LENGTH];
+ unsigned int digest_len = SHA256_DIGEST_LENGTH;
+
+ HMAC_CTX ctx;
+ HMAC_CTX_init(&ctx);
+
+ int ret = HMAC_Init_ex(&ctx, input->srvr_data->secret_data,
+ input->srvr_data->secret_len,
+ EVP_sha256(), NULL);
+ if (ret != 1) {
+ ret = KNOT_EINVAL;
+ goto fail;
+ }
+
+ ret = HMAC_Update(&ctx, input->cc, input->cc_len);
+ if (ret != 1) {
+ ret = KNOT_EINVAL;
+ goto fail;
+ }
+
+ if (input->nonce && input->nonce_len) {
+ ret = HMAC_Update(&ctx, (void *)input->nonce, input->nonce_len);
+ if (ret != 1) {
+ ret = KNOT_EINVAL;
+ goto fail;
+ }
+ }
+
+ if (input->srvr_data->clnt_sockaddr) {
+ addr = (uint8_t *)kr_inaddr(input->srvr_data->clnt_sockaddr);
+ addr_len = kr_inaddr_len(input->srvr_data->clnt_sockaddr);
+ if (addr && addr_len > 0) {
+ ret = HMAC_Update(&ctx, addr, addr_len);
+ if (ret != 1) {
+ ret = KNOT_EINVAL;
+ goto fail;
+ }
+ }
+ }
+
+ if (1 != HMAC_Final(&ctx, digest, &digest_len)) {
+ ret = KNOT_EINVAL;
+ goto fail;
+ }
+
+ assert(SRVR_HMAC_SHA256_64_HASH_SIZE <= SHA256_DIGEST_LENGTH);
+
+ *hash_len = SRVR_HMAC_SHA256_64_HASH_SIZE;
+ memcpy(hash_out, digest, *hash_len);
+
+ ret = KNOT_EOK;
+
+fail:
+ HMAC_CTX_cleanup(&ctx);
+ return ret;
+}
+
+const struct knot_cc_alg knot_cc_alg_hmac_sha256_64 = { KNOT_OPT_COOKIE_CLNT, cc_gen_hmac_sha256_64 };
+
+const struct knot_sc_alg knot_sc_alg_hmac_sha256_64 = { SRVR_HMAC_SHA256_64_HASH_SIZE, sc_gen_hmac_sha256_64 };
--- /dev/null
+/* 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/cookies/client.h>
+#include <libknot/cookies/server.h>
+
+#include "lib/defines.h"
+
+/** FNV-64 client cookie algorithm. */
+KR_EXPORT
+extern const struct knot_cc_alg knot_cc_alg_hmac_sha256_64;
+
+/** FNV-64 server cookie algorithm. */
+KR_EXPORT
+extern const struct knot_sc_alg knot_sc_alg_hmac_sha256_64;
#include "lib/cdb_lmdb.h"
#include "lib/cookies/cache.h"
#include "lib/cookies/control.h"
+#include "lib/utils.h"
/* Key size */
#define KEY_HSIZE (sizeof(uint8_t))
/**
* @internal Composed key as { u8 tag, u8[4,16] IP address }
*/
-static size_t cache_key(uint8_t *buf, uint8_t tag, const void *sockaddr)
+static size_t cache_key(uint8_t *buf, uint8_t tag, const struct sockaddr *sa)
{
- assert(buf && sockaddr);
+ assert(buf && sa);
- const uint8_t *addr = NULL;
- size_t addr_len = 0;
+ const char *addr = kr_inaddr(sa);
+ int addr_len = kr_inaddr_len(sa);
- if (kr_ok() != knot_sockaddr_bytes(sockaddr, &addr, &addr_len)) {
+ if (!addr || (addr_len <= 0)) {
return 0;
}
- assert(addr_len > 0);
buf[0] = tag;
memcpy(buf + sizeof(uint8_t), addr, addr_len);
}
static struct kr_cache_entry *lookup(struct kr_cache *cache, uint8_t tag,
- const void *sockaddr)
+ const struct sockaddr *sa)
{
- if (!cache || !sockaddr) {
+ if (!cache || !sa) {
return NULL;
}
uint8_t keybuf[KEY_SIZE];
- size_t key_len = cache_key(keybuf, tag, sockaddr);
+ size_t key_len = cache_key(keybuf, tag, sa);
/* Look up and return value */
knot_db_val_t key = { keybuf, key_len };
}
int kr_cookie_cache_peek(struct kr_cache *cache, uint8_t tag,
- const void *sockaddr, struct kr_cache_entry **entry,
+ const struct sockaddr *sa, struct kr_cache_entry **entry,
uint32_t *timestamp)
{
- if (!cache_isvalid(cache) || !sockaddr || !entry) {
+ if (!cache_isvalid(cache) || !sa || !entry) {
return kr_error(EINVAL);
}
- struct kr_cache_entry *found = lookup(cache, tag, sockaddr);
+ struct kr_cache_entry *found = lookup(cache, tag, sa);
if (!found) {
cache->stats.miss += 1;
return kr_error(ENOENT);
}
int kr_cookie_cache_insert(struct kr_cache *cache,
- uint8_t tag, const void *sockaddr,
+ uint8_t tag, const struct sockaddr *sa,
struct kr_cache_entry *header, knot_db_val_t data)
{
- if (!cache_isvalid(cache) || !sockaddr || !header) {
+ if (!cache_isvalid(cache) || !sa || !header) {
return kr_error(EINVAL);
}
/* Insert key */
uint8_t keybuf[KEY_SIZE];
- size_t key_len = cache_key(keybuf, tag, sockaddr);
+ size_t key_len = cache_key(keybuf, tag, sa);
if (key_len == 0) {
return kr_error(EILSEQ);
}
}
int kr_cookie_cache_remove(struct kr_cache *cache,
- uint8_t tag, const void *sockaddr)
+ uint8_t tag, const struct sockaddr *sa)
{
- if (!cache_isvalid(cache) || !sockaddr) {
+ if (!cache_isvalid(cache) || !sa) {
return kr_error(EINVAL);
}
uint8_t keybuf[KEY_SIZE];
- size_t key_len = cache_key(keybuf, tag, sockaddr);
+ size_t key_len = cache_key(keybuf, tag, sa);
if (key_len == 0) {
return kr_error(EILSEQ);
}
return cache_op(cache, remove, &key, 1);
}
-int kr_cookie_cache_peek_cookie(struct kr_cache *cache, const void *sockaddr,
+int kr_cookie_cache_peek_cookie(struct kr_cache *cache, const struct sockaddr *sa,
struct timed_cookie *cookie, uint32_t *timestamp)
{
- if (!cache_isvalid(cache) || !sockaddr || !cookie || !timestamp) {
+ if (!cache_isvalid(cache) || !sa || !cookie || !timestamp) {
return kr_error(EINVAL);
}
/* Check if the RRSet is in the cache. */
struct kr_cache_entry *entry = NULL;
- int ret = kr_cookie_cache_peek(cache, KR_CACHE_COOKIE, sockaddr,
+ int ret = kr_cookie_cache_peek(cache, KR_CACHE_COOKIE, sa,
&entry, timestamp);
if (ret != 0) {
return ret;
return kr_ok();
}
-int kr_cookie_cache_insert_cookie(struct kr_cache *cache, const void *sockaddr,
+int kr_cookie_cache_insert_cookie(struct kr_cache *cache, const struct sockaddr *sa,
const struct timed_cookie *cookie,
uint32_t timestamp)
{
- if (!cache_isvalid(cache) || !sockaddr) {
+ if (!cache_isvalid(cache) || !sa) {
return kr_error(EINVAL);
}
knot_edns_opt_get_length(cookie->cookie_opt);
knot_db_val_t data = { (uint8_t *) cookie->cookie_opt, cookie_opt_size };
- return kr_cookie_cache_insert(cache, KR_CACHE_COOKIE, sockaddr,
+ return kr_cookie_cache_insert(cache, KR_CACHE_COOKIE, sa,
&header, data);
}
#pragma once
+#include <netinet/in.h>
+
#include "lib/cache.h"
/** DNS cookie cache entry tag. */
* @note The 'drift' is the time passed between the inception time and now (in seconds).
* @param cache cache structure
* @param tag asset tag
- * @param sockaddr asset socket address
+ * @param sa asset socket address
* @param entry cache entry, will be set to valid pointer or NULL
* @param timestamp current time (will be replaced with drift if successful)
* @return 0 or an error code
*/
KR_EXPORT
int kr_cookie_cache_peek(struct kr_cache *cache,
- uint8_t tag, const void *sockaddr,
+ uint8_t tag, const struct sockaddr *sa,
struct kr_cache_entry **entry, uint32_t *timestamp);
/**
* Insert asset into cache, replacing any existing data.
* @param cache cache structure
* @param tag asset tag
- * @param sockaddr asset socket address
+ * @param sa asset socket address
* @param header filled entry header (ttl and time stamp)
* @param data inserted data
* @return 0 or an error code
*/
KR_EXPORT
int kr_cookie_cache_insert(struct kr_cache *cache,
- uint8_t tag, const void *sockaddr,
+ uint8_t tag, const struct sockaddr *sa,
struct kr_cache_entry *header, knot_db_val_t data);
/**
* Remove asset from cache.
* @param cache cache structure
* @param tag asset tag
- * @param sockaddr asset socket address
+ * @param sa asset socket address
* @return 0 or an error code
*/
KR_EXPORT
int kr_cookie_cache_remove(struct kr_cache *cache,
- uint8_t tag, const void *sockaddr);
+ uint8_t tag, const struct sockaddr *sa);
/**
* Structure used for cookie cache interface.
* Peek the cache for given cookie (socket address)
* @note The 'drift' is the time passed between the cache time of the cookie and now (in seconds).
* @param cache cache structure
- * @param sockaddr socket address
+ * @param sa socket address
* @param cookie asset
* @param timestamp current time (will be replaced with drift if successful)
* @return 0 or an error code
*/
KR_EXPORT
-int kr_cookie_cache_peek_cookie(struct kr_cache *cache, const void *sockaddr,
+int kr_cookie_cache_peek_cookie(struct kr_cache *cache, const struct sockaddr *sa,
struct timed_cookie *cookie, uint32_t *timestamp);
/**
* Insert a DNS cookie (client and server) entry for the given server signature (IP address).
* @param cache cache structure
- * @param sockaddr server IP address
+ * @param sa server IP address
* @param cookie ttl and whole EDNS cookie option (header, client and server cookies)
* @param timestamp current time
* @return 0 or an error code
*/
KR_EXPORT
-int kr_cookie_cache_insert_cookie(struct kr_cache *cache, const void *sockaddr,
+int kr_cookie_cache_insert_cookie(struct kr_cache *cache, const struct sockaddr *sa,
const struct timed_cookie *cookie,
uint32_t timestamp);
/**
* Remove asset from cache.
* @param txn transaction instance
- * @param sockaddr socket address
+ * @param sa socket address
* @return 0 or an error code
*/
-#define kr_cookie_cache_remove_cookie(cache, sockaddr) \
- kr_cookie_cache_remove((cache), KR_CACHE_COOKIE, (sockaddr))
+#define kr_cookie_cache_remove_cookie(cache, sa) \
+ kr_cookie_cache_remove((cache), KR_CACHE_COOKIE, (sa))
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-//#define MODULE_DEBUG_MSGS 1 /* Comment out if debug messages are not desired. */
-
-#include <assert.h>
-#include <libknot/error.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "lib/cookies/cache.h"
#include "lib/cookies/control.h"
-#include "lib/layer.h"
-#include "lib/utils.h"
-
-#if defined(MODULE_DEBUG_MSGS)
-# define DEBUG_MSG(qry, fmt...) QRDEBUG(qry, "cookies_control", fmt)
-#else /* !defined(MODULE_DEBUG_MSGS) */
-# define DEBUG_MSG(qry, fmt...) do { } while (0)
-#endif /* defined(MODULE_DEBUG_MSGS) */
struct kr_cookie_ctx kr_glob_cookie_ctx = {
.clnt = { false, { NULL, NULL }, { NULL, NULL}, DFLT_COOKIE_TTL },
.srvr = { false, { NULL, NULL }, { NULL, NULL} }
};
-
-static int opt_rr_add_cookies(knot_rrset_t *opt_rr,
- uint8_t *cc, uint16_t cc_len,
- uint8_t *sc, uint16_t sc_len,
- knot_mm_t *mm)
-{
- uint16_t cookies_size = 0;
- uint8_t *cookies_data = NULL;
-
- cookies_size = knot_edns_opt_cookie_data_len(cc_len, sc_len);
-
- int ret = knot_edns_reserve_option(opt_rr, KNOT_EDNS_OPTION_COOKIE,
- cookies_size, &cookies_data, mm);
- if (ret != KNOT_EOK) {
- return ret;
- }
- assert(cookies_data != NULL);
-
- ret = knot_edns_opt_cookie_write(cc, cc_len, sc, sc_len,
- cookies_data, &cookies_size);
- if (ret != KNOT_EOK) {
- return ret;
- }
-
- assert(cookies_size == knot_edns_opt_cookie_data_len(cc_len, sc_len));
-
- return KNOT_EOK;
-}
-
-static int opt_rr_add_option(knot_rrset_t *opt_rr, uint8_t *option,
- knot_mm_t *mm)
-{
- assert(opt_rr && option);
-
- uint8_t *reserved_data = NULL;
- uint16_t opt_code = knot_edns_opt_get_code(option);
- uint16_t opt_len = knot_edns_opt_get_length(option);
- uint8_t *opt_data = knot_edns_opt_get_data(option);
-
- int ret = knot_edns_reserve_option(opt_rr, opt_code,
- opt_len, &reserved_data, mm);
- if (ret != KNOT_EOK) {
- return ret;
- }
- assert(reserved_data);
-
- memcpy(reserved_data, opt_data, opt_len);
- return KNOT_EOK;
-}
-
-/**
- * Check whether there is a cached cookie that matches the current client
- * cookie.
- */
-static const uint8_t *peek_and_check_cc(struct kr_cache *cache,
- const void *sockaddr,
- const uint8_t *cc, uint16_t cc_len)
-{
- assert(cache && sockaddr && cc && cc_len);
-
- uint32_t timestamp = 0;
- struct timed_cookie timed_cookie = { 0, };
-
- int ret = kr_cookie_cache_peek_cookie(cache, sockaddr, &timed_cookie,
- ×tamp);
- if (ret != kr_ok()) {
- return NULL;
- }
- assert(timed_cookie.cookie_opt);
-
- /* Ignore the timestamp and time to leave. If the cookie is in cache
- * then just use it. The cookie control should be prerformed in the
- * cookie module/layer. */
-
- const uint8_t *cached_cc = knot_edns_opt_get_data((uint8_t *) timed_cookie.cookie_opt);
-
- if (cc_len == KNOT_OPT_COOKIE_CLNT &&
- 0 == memcmp(cc, cached_cc, cc_len)) {
- return timed_cookie.cookie_opt;
- }
-
- return NULL;
-}
-
-int kr_request_put_cookie(const struct kr_clnt_cookie_settings *clnt_cntrl,
- struct kr_cache *cookie_cache,
- const void *clnt_sockaddr, const void *srvr_sockaddr,
- knot_pkt_t *pkt)
-{
- if (!clnt_cntrl || !pkt) {
- return kr_error(EINVAL);
- }
-
- if (!pkt->opt_rr) {
- return kr_ok();
- }
-
- if (!clnt_cntrl->csec || !clnt_cntrl->calg ||
- !cookie_cache) {
- return kr_error(EINVAL);
- }
-
- /* Generate client cookie.
- * TODO -- generate client cookie from client address, server address
- * and secret quantity. */
- struct knot_ccookie_input input = {
- .clnt_sockaddr = clnt_sockaddr,
- .srvr_sockaddr = srvr_sockaddr,
- .secret_data = clnt_cntrl->csec->data,
- .secret_len = clnt_cntrl->csec->size
- };
- uint8_t cc[KNOT_OPT_COOKIE_CLNT];
- uint16_t cc_len = KNOT_OPT_COOKIE_CLNT;
- assert(clnt_cntrl->calg && clnt_cntrl->calg->alg &&
- clnt_cntrl->calg->alg->gen_func);
- int ret = clnt_cntrl->calg->alg->gen_func(&input, cc, &cc_len);
- if (ret != kr_ok()) {
- return ret;
- }
- assert(cc_len == KNOT_OPT_COOKIE_CLNT);
-
- const uint8_t *cached_cookie = peek_and_check_cc(cookie_cache,
- srvr_sockaddr,
- cc, cc_len);
-
- /* This is a very nasty hack that prevents the packet to be corrupted
- * when using contemporary 'Cookie interface'. */
- assert(pkt->current == KNOT_ADDITIONAL);
- pkt->sections[KNOT_ADDITIONAL].count -= 1;
- pkt->rrset_count -= 1;
- pkt->size -= knot_edns_wire_size(pkt->opt_rr);
- knot_wire_set_arcount(pkt->wire, knot_wire_get_arcount(pkt->wire) - 1);
-#if 0
- /* Reclaim reserved size -- does not work as intended.. */
- ret = knot_pkt_reclaim(pkt, knot_edns_wire_size(pkt->opt_rr));
- if (ret != KNOT_EOK) {
- return ret;
- }
-#endif
-
- if (cached_cookie) {
- ret = opt_rr_add_option(pkt->opt_rr, (uint8_t *) cached_cookie,
- &pkt->mm);
- } else {
- ret = opt_rr_add_cookies(pkt->opt_rr, cc, cc_len,
- NULL, 0, &pkt->mm);
- }
-
- /* Write to packet. */
- assert(pkt->current == KNOT_ADDITIONAL);
- return knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, pkt->opt_rr, KNOT_PF_FREE);
-}
-
-int kr_answer_opt_rr_add_cookies(const struct knot_scookie_input *input,
- const struct kr_sc_alg_descr *sc_alg,
- knot_pkt_t *pkt)
-{
- if (!input || !sc_alg || !sc_alg->alg || pkt) {
- kr_error(EINVAL);
- }
-
- uint16_t cookie_size = input->cc_len + sc_alg->alg->sc_size;
- uint8_t *data = NULL;
-
- if (!pkt->opt_rr) {
- kr_error(EINVAL);
- }
- int ret = knot_edns_reserve_option(pkt->opt_rr,
- KNOT_EDNS_OPTION_COOKIE,
- cookie_size, &data, &pkt->mm);
- if (ret != KNOT_EOK) {
- return kr_error(ret);
- }
-
- memcpy(data, input->cc, input->cc_len);
- cookie_size = sc_alg->alg->sc_size;
- ret = sc_alg->alg->gen_func(input, data + input->cc_len, &cookie_size);
- if (ret != kr_ok()) {
- /* TODO -- Delete COOKIE option. */
- return ret;
- }
-
- return ret;
-}
-
-int kr_pkt_set_ext_rcode(knot_pkt_t *pkt, uint16_t whole_rcode)
-{
- if (!pkt || !knot_pkt_has_edns(pkt)) {
- return kr_error(EINVAL);
- }
-
- uint8_t rcode = whole_rcode & 0x0f;
- uint8_t ext_rcode = whole_rcode >> 4;
- knot_wire_set_rcode(pkt->wire, rcode);
- knot_edns_set_ext_rcode(pkt->opt_rr, ext_rcode);
-
- return kr_ok();
-}
-
-uint8_t *kr_is_cookie_query(const knot_pkt_t *pkt)
-{
- if (!pkt || knot_wire_get_qdcount(pkt->wire) > 0) {
- return false;
- }
-
- if (knot_wire_get_qr(pkt->wire) != 0 || !pkt->opt_rr) {
- return false;
- }
-
- return knot_edns_get_option(pkt->opt_rr, KNOT_EDNS_OPTION_COOKIE);
-}
-
-int kr_parse_cookie_opt(uint8_t *cookie_opt, struct knot_dns_cookies *cookies)
-{
- if (!cookie_opt || !cookies) {
- kr_error(EINVAL);
- }
-
- const uint8_t *cookie_data = knot_edns_opt_get_data(cookie_opt);
- uint16_t cookie_len = knot_edns_opt_get_length(cookie_opt);
- assert(cookie_data && cookie_len);
-
- int ret = knot_edns_opt_cookie_parse(cookie_data, cookie_len,
- &cookies->cc, &cookies->cc_len,
- &cookies->sc, &cookies->sc_len);
-
- return (ret == KNOT_EOK) ? kr_ok() : kr_error(EINVAL);
-}
#pragma once
-#include <libknot/packet/pkt.h>
#include <libknot/rrtype/opt-cookie.h>
#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
#include "lib/cookies/alg_containers.h"
#include "lib/cache.h"
/** Global cookie control context. */
KR_EXPORT
extern struct kr_cookie_ctx kr_glob_cookie_ctx;
-
-/**
- * @brief Insert a DNS cookie into query packet.
- * @note The packet must already contain ENDS section.
- * @param clnt_cntrl Client cookie control structure.
- * @param cookie_cache Cookie cache.
- * @param clnt_sockaddr Client address.
- * @param srvr_sockaddr Server address.
- * @param pkt DNS request packet.
- */
-KR_EXPORT
-int kr_request_put_cookie(const struct kr_clnt_cookie_settings *clnt_cntrl,
- struct kr_cache *cookie_cache,
- const void *clnt_sockaddr, const void *srvr_sockaddr,
- knot_pkt_t *pkt);
-
-/**
- * @brief Add cookies into answer.
- * @note Data are only added into the OPT RR.
- * @param input input data to generate server cookie from
- * @param sc_alg algorithm to use
- * @param pkt packet which to put cookie into
- * @return kr_ok() or error code
- */
-KR_EXPORT
-int kr_answer_opt_rr_add_cookies(const struct knot_scookie_input *input,
- const struct kr_sc_alg_descr *sc_alg,
- knot_pkt_t *pkt);
-
-/**
- * @brief Set RCODE and extended RCODE.
- * @param pkt DNS packet
- * @param whole_rcode RCODE value
- * @return kr_ok() or error code
- */
-KR_EXPORT
-int kr_pkt_set_ext_rcode(knot_pkt_t *pkt, uint16_t whole_rcode);
-
-/**
- * @brief Check whether packet is a server cookie request.
- * @param pkt Packet to be examined.
- * @param cookies Received cookies.
- * @return Pointer to entire cookie option if is a cookie query, NULL else.
- */
-KR_EXPORT
-uint8_t *kr_is_cookie_query(const knot_pkt_t *pkt);
-
-/**
- * @brief Parse cookies from cookie option.
- * @param cookie_opt Cookie option.
- * @param cookies Cookie structure to be set.
- * @return kr_ok() on success, error if cookies are malformed.
- */
-KR_EXPORT
-int kr_parse_cookie_opt(uint8_t *cookie_opt, struct knot_dns_cookies *cookies);
--- /dev/null
+/* 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 <assert.h>
+#include <libknot/rrtype/opt-cookie.h>
+
+#include "lib/cookies/cache.h"
+#include "lib/cookies/helper.h"
+#include "lib/defines.h"
+
+/**
+ * @brief Check whether there is a cached cookie that matches the current
+ * client cookie.
+ */
+static const uint8_t *peek_and_check_cc(struct kr_cache *cache,
+ const void *sockaddr,
+ const uint8_t *cc, uint16_t cc_len)
+{
+ assert(cache && sockaddr && cc && cc_len);
+
+ uint32_t timestamp = 0;
+ struct timed_cookie timed_cookie = { 0, };
+
+ int ret = kr_cookie_cache_peek_cookie(cache, sockaddr, &timed_cookie,
+ ×tamp);
+ if (ret != kr_ok()) {
+ return NULL;
+ }
+ assert(timed_cookie.cookie_opt);
+
+ /* Ignore the time stamp and time to leave. If the cookie is in cache
+ * then just use it. The cookie control should be performed in the
+ * cookie module/layer. */
+
+ const uint8_t *cached_cc = knot_edns_opt_get_data((uint8_t *) timed_cookie.cookie_opt);
+
+ if (cc_len == KNOT_OPT_COOKIE_CLNT &&
+ 0 == memcmp(cc, cached_cc, cc_len)) {
+ return timed_cookie.cookie_opt;
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief Adds entire EDNS option into the RR Set.
+ */
+static int opt_rr_add_opt(knot_rrset_t *opt_rr, uint8_t *option, knot_mm_t *mm)
+{
+ assert(opt_rr && option);
+
+ uint8_t *reserved_data = NULL;
+ uint16_t opt_code = knot_edns_opt_get_code(option);
+ uint16_t opt_len = knot_edns_opt_get_length(option);
+ uint8_t *opt_data = knot_edns_opt_get_data(option);
+
+ int ret = knot_edns_reserve_option(opt_rr, opt_code,
+ opt_len, &reserved_data, mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ assert(reserved_data);
+
+ memcpy(reserved_data, opt_data, opt_len);
+ return KNOT_EOK;
+}
+
+/**
+ * @brief Add a client cookie option into the RR Set.
+ */
+static int opt_rr_add_cc(knot_rrset_t *opt_rr, uint8_t *cc, uint16_t cc_len,
+ knot_mm_t *mm)
+{
+#define SC NULL
+#define SC_LEN 0
+ uint16_t cookies_size = 0;
+ uint8_t *cookies_data = NULL;
+
+ cookies_size = knot_edns_opt_cookie_data_len(cc_len, SC_LEN);
+
+ int ret = knot_edns_reserve_option(opt_rr, KNOT_EDNS_OPTION_COOKIE,
+ cookies_size, &cookies_data, mm);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ assert(cookies_data != NULL);
+
+ ret = knot_edns_opt_cookie_write(cc, cc_len, SC, SC_LEN,
+ cookies_data, &cookies_size);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ assert(cookies_size == knot_edns_opt_cookie_data_len(cc_len, SC_LEN));
+
+ return KNOT_EOK;
+#undef SC
+#undef SC_LEN
+}
+
+int kr_request_put_cookie(const struct kr_clnt_cookie_settings *clnt_cntrl,
+ struct kr_cache *cookie_cache,
+ const struct sockaddr *clnt_sa,
+ const struct sockaddr *srvr_sa,
+ knot_pkt_t *pkt)
+{
+ if (!clnt_cntrl || !pkt) {
+ return kr_error(EINVAL);
+ }
+
+ if (!pkt->opt_rr) {
+ return kr_ok();
+ }
+
+ if (!clnt_cntrl->csec || !clnt_cntrl->calg ||
+ !cookie_cache) {
+ return kr_error(EINVAL);
+ }
+
+ /* Generate client cookie.
+ * TODO -- generate client cookie from client address, server address
+ * and secret quantity. */
+ struct knot_cc_input input = {
+ .clnt_sockaddr = clnt_sa,
+ .srvr_sockaddr = srvr_sa,
+ .secret_data = clnt_cntrl->csec->data,
+ .secret_len = clnt_cntrl->csec->size
+ };
+ uint8_t cc[KNOT_OPT_COOKIE_CLNT];
+ uint16_t cc_len = KNOT_OPT_COOKIE_CLNT;
+ assert(clnt_cntrl->calg && clnt_cntrl->calg->alg &&
+ clnt_cntrl->calg->alg->gen_func);
+ int ret = clnt_cntrl->calg->alg->gen_func(&input, cc, &cc_len);
+ if (ret != kr_ok()) {
+ return ret;
+ }
+ assert(cc_len == KNOT_OPT_COOKIE_CLNT);
+
+ const uint8_t *cached_cookie = peek_and_check_cc(cookie_cache,
+ srvr_sa, cc, cc_len);
+
+ /* This is a very nasty hack that prevents the packet to be corrupted
+ * when using contemporary 'Cookie interface'. */
+ assert(pkt->current == KNOT_ADDITIONAL);
+ pkt->sections[KNOT_ADDITIONAL].count -= 1;
+ pkt->rrset_count -= 1;
+ pkt->size -= knot_edns_wire_size(pkt->opt_rr);
+ knot_wire_set_arcount(pkt->wire, knot_wire_get_arcount(pkt->wire) - 1);
+#if 0
+ /* Reclaim reserved size -- does not work as intended.. */
+ ret = knot_pkt_reclaim(pkt, knot_edns_wire_size(pkt->opt_rr));
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+#endif
+
+ if (cached_cookie) {
+ ret = opt_rr_add_opt(pkt->opt_rr, (uint8_t *)cached_cookie,
+ &pkt->mm);
+ } else {
+ ret = opt_rr_add_cc(pkt->opt_rr, cc, cc_len, &pkt->mm);
+ }
+
+ /* Write to packet. */
+ assert(pkt->current == KNOT_ADDITIONAL);
+ return knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, pkt->opt_rr, KNOT_PF_FREE);
+}
+
+int kr_answer_write_cookie(const struct knot_sc_private *srvr_data,
+ const uint8_t *cc, uint16_t cc_len,
+ struct kr_nonce_input *nonce,
+ const struct knot_sc_alg *alg,
+ knot_pkt_t *pkt)
+{
+ if (!srvr_data || !srvr_data->clnt_sockaddr ||
+ !srvr_data->secret_data|| !srvr_data->secret_len) {
+ return kr_error(EINVAL);
+ }
+
+ if (!cc || !cc_len || !nonce) {
+ return kr_error(EINVAL);
+ }
+
+ if (!alg || !alg->hash_size || !alg->hash_func) {
+ return kr_error(EINVAL);
+ }
+
+ if (!pkt && !pkt->opt_rr) {
+ return kr_error(EINVAL);
+ }
+
+ uint16_t nonce_len = NONCE_LEN;
+ uint16_t hash_len = alg->hash_size;
+
+ uint8_t *cookie = NULL;
+ uint16_t cookie_len = knot_edns_opt_cookie_data_len(cc_len,
+ nonce_len + hash_len);
+ if (cookie_len == 0) {
+ return kr_error(EINVAL);
+ }
+
+ int ret = knot_edns_reserve_option(pkt->opt_rr, KNOT_EDNS_OPTION_COOKIE,
+ cookie_len, &cookie, &pkt->mm);
+ if (ret != KNOT_EOK) {
+ return kr_error(ENOMEM);
+ }
+
+ struct knot_sc_input input = {
+ .cc = cookie,
+ .cc_len = cc_len,
+ .srvr_data = srvr_data
+ };
+ memcpy(cookie, cc, cc_len);
+
+ if (nonce_len) {
+ kr_nonce_write_wire(cookie + cc_len, &nonce_len, nonce);
+
+ input.nonce = cookie + cc_len;
+ input.nonce_len = nonce_len;
+ }
+
+ ret = alg->hash_func(&input, cookie + cc_len + nonce_len, &hash_len);
+ if (ret != KNOT_EOK) {
+ return kr_error(EINVAL);
+ }
+
+ return kr_ok();
+}
+
+int kr_pkt_set_ext_rcode(knot_pkt_t *pkt, uint16_t whole_rcode)
+{
+ if (!pkt || !knot_pkt_has_edns(pkt)) {
+ return kr_error(EINVAL);
+ }
+
+ uint8_t rcode = whole_rcode & 0x0f;
+ uint8_t ext_rcode = whole_rcode >> 4;
+ knot_wire_set_rcode(pkt->wire, rcode);
+ knot_edns_set_ext_rcode(pkt->opt_rr, ext_rcode);
+
+ return kr_ok();
+}
+
+uint8_t *kr_is_cookie_query(const knot_pkt_t *pkt)
+{
+ if (!pkt || knot_wire_get_qdcount(pkt->wire) > 0) {
+ return false;
+ }
+
+ if (knot_wire_get_qr(pkt->wire) != 0 || !pkt->opt_rr) {
+ return false;
+ }
+
+ return knot_edns_get_option(pkt->opt_rr, KNOT_EDNS_OPTION_COOKIE);
+}
+
+int kr_parse_cookie_opt(uint8_t *cookie_opt, struct knot_dns_cookies *cookies)
+{
+ if (!cookie_opt || !cookies) {
+ kr_error(EINVAL);
+ }
+
+ const uint8_t *cookie_data = knot_edns_opt_get_data(cookie_opt);
+ uint16_t cookie_len = knot_edns_opt_get_length(cookie_opt);
+ assert(cookie_data && cookie_len);
+
+ int ret = knot_edns_opt_cookie_parse(cookie_data, cookie_len,
+ &cookies->cc, &cookies->cc_len,
+ &cookies->sc, &cookies->sc_len);
+
+ return (ret == KNOT_EOK) ? kr_ok() : kr_error(EINVAL);
+}
--- /dev/null
+/* 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/packet/pkt.h>
+
+#include "lib/cookies/control.h"
+#include "lib/cookies/nonce.h"
+#include "lib/defines.h"
+
+/**
+ * @brief Insert a DNS cookie into query packet.
+ * @note The packet must already contain ENDS section.
+ * @param clnt_cntrl client cookie control structure
+ * @param cookie_cache cookie cache
+ * @param clnt_sa client socket address
+ * @param srvr_sa server socket address
+ * @param pkt DNS request packet
+ * @return kr_ok() or error code
+ */
+KR_EXPORT
+int kr_request_put_cookie(const struct kr_clnt_cookie_settings *clnt_cntrl,
+ struct kr_cache *cookie_cache,
+ const struct sockaddr *clnt_sa,
+ const struct sockaddr *srvr_sa,
+ knot_pkt_t *pkt);
+
+/**
+ * @brief Inserts a cookie option into the OPT RR. It does not write any
+ * wire data.
+ * @param srvr_data server knowledge
+ * @param cc client cookie
+ * @param cc_len client cookie length
+ * @param nonce nonce value
+ * @param alg hash algorithm
+ * @param pkt DNS response packet
+ */
+KR_EXPORT
+int kr_answer_write_cookie(const struct knot_sc_private *srvr_data,
+ const uint8_t *cc, uint16_t cc_len,
+ struct kr_nonce_input *nonce,
+ const struct knot_sc_alg *alg,
+ knot_pkt_t *pkt);
+
+/**
+ * @brief Set RCODE and extended RCODE.
+ * @param pkt DNS packet
+ * @param whole_rcode RCODE value
+ * @return kr_ok() or error code
+ */
+KR_EXPORT
+int kr_pkt_set_ext_rcode(knot_pkt_t *pkt, uint16_t whole_rcode);
+
+/**
+ * @brief Check whether packet is a server cookie request.
+ * @param pkt Packet to be examined.
+ * @param cookies Received cookies.
+ * @return Pointer to entire cookie option if is a cookie query, NULL else.
+ */
+KR_EXPORT
+uint8_t *kr_is_cookie_query(const knot_pkt_t *pkt);
+
+/**
+ * @brief Parse cookies from cookie option.
+ * @param cookie_opt Cookie option.
+ * @param cookies Cookie structure to be set.
+ * @return kr_ok() on success, error if cookies are malformed.
+ */
+KR_EXPORT
+int kr_parse_cookie_opt(uint8_t *cookie_opt, struct knot_dns_cookies *cookies);
--- /dev/null
+/* 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>
+#include <assert.h>
+
+#include "lib/cookies/nonce.h"
+
+int kr_nonce_write_wire(uint8_t *buf, uint16_t *buf_len,
+ struct kr_nonce_input *input)
+{
+ if (!buf || !buf_len || !input) {;
+ return kr_error(EINVAL);
+ }
+
+ if (*buf_len < NONCE_LEN) {
+ kr_error(EINVAL);
+ }
+
+ uint32_t aux = htonl(input->rand);
+ memcpy(buf, &aux, sizeof(aux));
+ aux = htonl(input->time);
+ memcpy(buf + sizeof(aux), &aux, sizeof(aux));
+ *buf_len = 2 * sizeof(aux);
+ assert(NONCE_LEN == *buf_len);
+
+ return kr_ok();
+}
--- /dev/null
+/* 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 "lib/defines.h"
+
+/* RFC7873 Appendix B.2 mentions an algorithm using two values before the
+ * actual server cookie hash. */
+
+/** Nonce value length. */
+#define NONCE_LEN 8
+
+/** Input data to generate nonce from. */
+struct kr_nonce_input {
+ uint32_t rand; /**< some random value */
+ uint32_t time; /**< time stamp */
+};
+
+/**
+ * @brief Writes server cookie nonce balue into given buffer.
+ *
+ * @param buf buffer to write nonce data in wire format into
+ * @param buf_len on input contains nonce buffer size, on output contains
+ * size of actual written data
+ * @param input data to generate wire data from
+ * @return kr_ok() on success, error code else
+ */
+KR_EXPORT
+int kr_nonce_write_wire(uint8_t *buf, uint16_t *buf_len,
+ struct kr_nonce_input *input);
#include "lib/cookies/alg_containers.h"
#include "lib/cookies/cache.h"
#include "lib/cookies/control.h"
+#include "lib/cookies/helper.h"
+#include "lib/cookies/nonce.h"
#include "lib/module.h"
#include "lib/layer.h"
const struct sockaddr *sockaddr = NULL;
- struct knot_ccookie_input input = {
- .clnt_sockaddr = NULL,
+ struct knot_cc_input input = {
+ .clnt_sockaddr = NULL, /* Not supported yet. */
.srvr_sockaddr = NULL,
.secret_data = csecr->data,
.secret_len = csecr->size
break;
}
- input.srvr_sockaddr = &nsrep->addr[i];
- int ret = knot_ccookie_check(cc, cc_len, &input, cc_alg->alg);
+ input.srvr_sockaddr = (struct sockaddr *)&nsrep->addr[i];
+ int ret = knot_cc_check(cc, cc_len, &input, cc_alg->alg);
if (ret == KNOT_EOK) {
- sockaddr = (struct sockaddr *) &nsrep->addr[i];
+ sockaddr = (struct sockaddr *)&nsrep->addr[i];
break;
}
}
if (tmp_sockaddr) {
assert(clnt_cntrl->current.csec);
- struct knot_ccookie_input input = {
- .clnt_sockaddr = NULL,
+ struct knot_cc_input input = {
+ .clnt_sockaddr = NULL, /* Not supported yet. */
.srvr_sockaddr = tmp_sockaddr,
.secret_data = clnt_cntrl->current.csec->data,
.secret_len = clnt_cntrl->current.csec->size
};
- int ret = knot_ccookie_check(cc, cc_len, &input,
+ int ret = knot_cc_check(cc, cc_len, &input,
clnt_cntrl->current.calg->alg);
bool have_current = (ret == KNOT_EOK);
if ((ret != KNOT_EOK) &&
clnt_cntrl->recent.csec && clnt_cntrl->recent.calg) {
input.secret_data = clnt_cntrl->recent.csec->data;
input.secret_len = clnt_cntrl->recent.csec->size;
- ret = knot_ccookie_check(cc, cc_len, &input,
- clnt_cntrl->recent.calg->alg);
+ ret = knot_cc_check(cc, cc_len, &input,
+ clnt_cntrl->recent.calg->alg);
}
if (ret == KNOT_EOK) {
*sockaddr = tmp_sockaddr;
return knot_edns_get_option(req->qsource.opt, KNOT_EDNS_OPTION_COOKIE);
}
-/* TODO -- DNS cookie request. */
-
static int check_request(knot_layer_t *ctx, void *module_param)
{
if (!kr_glob_cookie_ctx.srvr.enabled) {
int return_state = ctx->state;
- struct knot_scookie_check_ctx check_ctx = {
+ struct knot_sc_private srvr_data = {
.clnt_sockaddr = req->qsource.addr,
.secret_data = srvr_cntrl->current.ssec->data,
.secret_len = srvr_cntrl->current.ssec->size
};
- struct knot_scookie_input input = {
- .cc = cookies.cc,
- .cc_len = cookies.cc_len,
- .nonce = kr_rand_uint(UINT32_MAX),
- .time = req->current_query->timestamp.tv_sec,
- .srvr_data = &check_ctx
+ struct kr_nonce_input nonce = {
+ .rand = kr_rand_uint(UINT32_MAX),
+ .time = req->current_query->timestamp.tv_sec
};
if (!cookies.sc) {
/* Check server cookie obtained in request. */
- ret = knot_scookie_check(&cookies, &check_ctx,
- srvr_cntrl->current.salg->alg);
+ ret = knot_sc_check(NONCE_LEN, &cookies, &srvr_data,
+ srvr_cntrl->current.salg->alg);
if (ret == KNOT_EINVAL &&
srvr_cntrl->recent.ssec && srvr_cntrl->recent.salg->alg) {
/* Try recent algorithm. */
- struct knot_scookie_check_ctx recent_ctx = {
+ struct knot_sc_private recent_srvr_data = {
.clnt_sockaddr = req->qsource.addr,
.secret_data = srvr_cntrl->recent.ssec->data,
.secret_len = srvr_cntrl->recent.ssec->size
};
- ret = knot_scookie_check(&cookies, &recent_ctx,
- srvr_cntrl->recent.salg->alg);
+ ret = knot_sc_check(NONCE_LEN, &cookies, &recent_srvr_data,
+ srvr_cntrl->recent.salg->alg);
}
if (ret != KNOT_EOK) {
/* TODO -- Silently discard? */
answer_add_cookies:
/* Add server cookie into response. */
- kr_answer_opt_rr_add_cookies(&input, srvr_cntrl->current.salg,
+ ret = kr_answer_write_cookie(&srvr_data, cookies.cc, cookies.cc_len,
+ &nonce, srvr_cntrl->current.salg->alg,
req->answer);
+ if (ret != kr_ok()) {
+ return_state = KNOT_STATE_FAIL;
+ }
return return_state;
}
libkres_SOURCES += \
lib/layer/cookiemonster.c \
lib/cookies/alg_containers.c \
- lib/cookies/alg_sha.c \
- lib/cookies/cache.c \
- lib/cookies/control.c
+ lib/cookies/alg_sha.c \
+ lib/cookies/cache.c \
+ lib/cookies/control.c \
+ lib/cookies/helper.c \
+ lib/cookies/nonce.c
libkres_HEADERS += \
- lib/cookies/alg_containers..h \
- lib/cookies/alg_sha.h \
- lib/cookies/cache.h \
- lib/cookies/control.h
+ lib/cookies/alg_containers.h \
+ lib/cookies/alg_sha.h \
+ lib/cookies/cache.h \
+ lib/cookies/control.h \
+ lib/cookies/helper.h \
+ lib/cookies/nonce.h
libkres_LIBS += $(libcrypto_LIBS)
endif
#include "lib/dnssec/ta.h"
#if defined(ENABLE_COOKIES)
#include "lib/cookies/control.h"
+#include "lib/cookies/helper.h"
+#include "lib/cookies/nonce.h"
#endif /* defined(ENABLE_COOKIES) */
#define DEBUG_MSG(qry, fmt...) QRDEBUG((qry), "resl", fmt)
knot_wire_set_ra(answer->wire);
knot_wire_set_rcode(answer->wire, KNOT_RCODE_NOERROR);
- struct knot_scookie_check_ctx check_ctx = {
+ struct knot_sc_private srvr_data = {
.clnt_sockaddr = clnt_sockaddr,
.secret_data = srvr_cntrl->current.ssec->data,
.secret_len = srvr_cntrl->current.ssec->size
struct timeval tv;
gettimeofday(&tv, NULL);
- struct knot_scookie_input input = {
- .cc = cookies->cc,
- .cc_len = cookies->cc_len,
- .nonce = kr_rand_uint(UINT32_MAX),
- .time = tv.tv_sec,
- .srvr_data = &check_ctx
+ struct kr_nonce_input nonce = {
+ .rand = kr_rand_uint(UINT32_MAX),
+ .time = tv.tv_sec
};
- int ret = kr_answer_opt_rr_add_cookies(&input,
- srvr_cntrl->current.salg,
- answer);
+ /* Add fres cookie into the answer. */
+ int ret = kr_answer_write_cookie(&srvr_data,
+ cookies->cc, cookies->cc_len, &nonce,
+ srvr_cntrl->current.salg->alg, answer);
if (ret != kr_ok()) {
return KNOT_STATE_FAIL;
}
- if (!cookies->sc) {
- return KNOT_STATE_DONE;
- }
-
/* Check server cookie only with current settings. */
- ret = knot_scookie_check(cookies, &check_ctx,
- srvr_cntrl->current.salg->alg);
+ ret = knot_sc_check(NONCE_LEN, cookies, &srvr_data,
+ srvr_cntrl->current.salg->alg);
if (ret != KNOT_EOK) {
kr_pkt_set_ext_rcode(answer, KNOT_RCODE_BADCOOKIE);
return KNOT_STATE_FAIL | KNOT_STATE_DONE;
struct kr_query *qry = kr_rplan_push(rplan, NULL, qname, qclass, qtype);
if (!qry) {
#if defined(ENABLE_COOKIES)
- /* May be a DNS cookies query. */
+ /* RFC7873 5.4 specifies a query for server cookie. Such query
+ * has QDCOUNT == 0 and contains a cookie option.
+ *
+ * The layers don't expect to handle queries with QDCOUNT != 1
+ * so such queries are handled directly here. */
struct knot_dns_cookies cookies = { 0, };
uint8_t *cookie_opt = kr_is_cookie_query(packet);
if (cookie_opt && kr_glob_cookie_ctx.clnt.enabled) {
}
const struct kr_sc_alg_descr *aux_ptr = kr_sc_algs;
- while (aux_ptr && aux_ptr->alg && aux_ptr->alg->gen_func) {
+ while (aux_ptr && aux_ptr->alg && aux_ptr->alg->hash_func) {
assert(aux_ptr->name);
JsonNode *element = json_mkstring(aux_ptr->name);
if (!element) {
kr_glob_cookie_ctx.srvr.enabled = false;
kr_glob_cookie_ctx.srvr.current.ssec = ss;
- kr_glob_cookie_ctx.srvr.current.salg = kr_sc_alg(kr_sc_algs,
- "HMAC-SHA256-64");
+ kr_glob_cookie_ctx.srvr.current.salg = kr_sc_alg(kr_sc_algs, "FNV-64");
module->data = NULL;