Commit b4a88628 authored by Karel Slaný's avatar Karel Slaný Committed by Ondřej Surý
Browse files

Checking cookies in inbound requests.

parent 639a486f
......@@ -349,6 +349,13 @@ static int qr_task_start(struct qr_task *task, knot_pkt_t *query)
task->req.qsource.key = knot_rrset_copy(query->tsig_rr, &task->req.pool);
}
#if defined(ENABLE_COOKIES)
/* Remember query source EDNS data */
if (query->opt_rr) {
task->req.qsource.opt = knot_rrset_copy(query->opt_rr, &task->req.pool);
}
#endif /* defined(ENABLE_COOKIES) */
/* Start resolution */
struct worker_ctx *worker = task->worker;
struct engine *engine = worker->engine;
......
......@@ -160,7 +160,7 @@ fail:
}
const struct kr_clnt_cookie_alg_descr kr_clnt_cookie_algs[] = {
{ "FNV-64", kr_clnt_cookie_alg_fnv64 },
{ "FNV-64", kr_clnt_cookie_alg_fnv64 },
{ "HMAC-SHA256-64", kr_clnt_cookie_alg_hmac_sha256_64 },
{ NULL, NULL }
};
......
......@@ -18,6 +18,7 @@
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
......@@ -29,24 +30,14 @@
* @brief Server cookie contains only hash value.
* @note DNS Cookies -- Appendix B.1
*/
static int srvr_cookie_parse_simple(const uint8_t *cookie_data, uint16_t data_len,
static int srvr_cookie_parse_simple(const uint8_t *sc, uint16_t sc_len,
struct kr_srvr_cookie_inbound *inbound)
{
if (!cookie_data || !inbound) {
if (!sc || !sc_len || !inbound) {
return kr_error(EINVAL);
}
const uint8_t *cc = NULL, *sc = NULL;
uint16_t cc_len = 0, sc_len = 0;
int ret = knot_edns_opt_cookie_parse(cookie_data, data_len,
&cc, &cc_len, &sc, &sc_len);
if (ret != KNOT_EOK || !sc) {
kr_error(EINVAL); /* Server cookie missing. */
}
assert(cc_len == KNOT_OPT_COOKIE_CLNT);
//memset(inbound, 0, sizeof(*inbound));
inbound->clnt_cookie = cc;
inbound->hash_data = sc; /* Entire server cookie contains data. */
inbound->hash_len = sc_len;
......@@ -57,29 +48,19 @@ static int srvr_cookie_parse_simple(const uint8_t *cookie_data, uint16_t data_le
* @brief Server cookie contains also additional values.
* @note DNS Cookies -- Appendix B.2
*/
static int srvr_cookie_parse(const uint8_t *cookie_data, uint16_t data_len,
static int srvr_cookie_parse(const uint8_t *sc, uint16_t sc_len,
struct kr_srvr_cookie_inbound *inbound)
{
if (!cookie_data || !inbound) {
if (!sc || !sc_len || !inbound) {
return kr_error(EINVAL);
}
const uint8_t *cc = NULL, *sc = NULL;
uint16_t cc_len = 0, sc_len = 0;
int ret = knot_edns_opt_cookie_parse(cookie_data, data_len,
&cc, &cc_len, &sc, &sc_len);
if (ret != KNOT_EOK || !sc) {
kr_error(EINVAL); /* Server cookie missing. */
}
assert(cc_len == KNOT_OPT_COOKIE_CLNT);
if (sc_len <= (2 * sizeof(uint32_t))) { /* nonce + time */
return kr_error(EINVAL);
}
uint32_t aux;
inbound->clnt_cookie = cc;
memcpy(&aux, sc, sizeof(aux));
inbound->nonce = ntohl(aux);
memcpy(&aux, sc + sizeof(aux), sizeof(aux));
......@@ -105,8 +86,8 @@ static int kr_srvr_cookie_alg_fnv64_simple(const struct kr_srvr_cookie_input *in
return kr_error(EINVAL);
}
if (!input->clnt_cookie ||
!input->srvr_data.secret_data || !input->srvr_data.secret_len) {
if (!input->clnt_cookie || !input->srvr_data ||
!input->srvr_data->secret_data || !input->srvr_data->secret_len) {
return kr_error(EINVAL);
}
......@@ -115,7 +96,7 @@ static int kr_srvr_cookie_alg_fnv64_simple(const struct kr_srvr_cookie_input *in
Fnv64_t hash_val = FNV1A_64_INIT;
if (kr_ok() == kr_address_bytes(input->srvr_data.clnt_sockaddr, &addr,
if (kr_ok() == kr_address_bytes(input->srvr_data->clnt_sockaddr, &addr,
&alen)) {
assert(addr && alen);
hash_val = fnv_64a_buf((void *) addr, alen, hash_val);
......@@ -124,8 +105,8 @@ static int kr_srvr_cookie_alg_fnv64_simple(const struct kr_srvr_cookie_input *in
hash_val = fnv_64a_buf((void *) input->clnt_cookie,
KNOT_OPT_COOKIE_CLNT, hash_val);
hash_val = fnv_64a_buf((void *) input->srvr_data.secret_data,
input->srvr_data.secret_len, hash_val);
hash_val = fnv_64a_buf((void *) input->srvr_data->secret_data,
input->srvr_data->secret_len, hash_val);
memcpy(sc_out, &hash_val, sizeof(hash_val));
*sc_size = sizeof(hash_val);
......@@ -149,8 +130,8 @@ static int kr_srvr_cookie_alg_fnv64(const struct kr_srvr_cookie_input *input,
return kr_error(EINVAL);
}
if (!input->clnt_cookie ||
!input->srvr_data.secret_data || !input->srvr_data.secret_len) {
if (!input->clnt_cookie || !input->srvr_data ||
!input->srvr_data->secret_data || !input->srvr_data->secret_len) {
return kr_error(EINVAL);
}
......@@ -159,8 +140,8 @@ static int kr_srvr_cookie_alg_fnv64(const struct kr_srvr_cookie_input *input,
Fnv64_t hash_val = FNV1A_64_INIT;
if (input->srvr_data.clnt_sockaddr) {
if (kr_ok() == kr_address_bytes(input->srvr_data.clnt_sockaddr,
if (input->srvr_data->clnt_sockaddr) {
if (kr_ok() == kr_address_bytes(input->srvr_data->clnt_sockaddr,
&addr, &alen)) {
assert(addr && alen);
hash_val = fnv_64a_buf((void *) addr, alen, hash_val);
......@@ -176,8 +157,8 @@ static int kr_srvr_cookie_alg_fnv64(const struct kr_srvr_cookie_input *input,
hash_val = fnv_64a_buf((void *) input->clnt_cookie,
KNOT_OPT_COOKIE_CLNT, hash_val);
hash_val = fnv_64a_buf((void *) input->srvr_data.secret_data,
input->srvr_data.secret_len, hash_val);
hash_val = fnv_64a_buf((void *) input->srvr_data->secret_data,
input->srvr_data->secret_len, hash_val);
uint32_t aux = htonl(input->nonce);
memcpy(sc_out, &aux, sizeof(aux));
......@@ -206,8 +187,8 @@ static int kr_srvr_cookie_alg_hmac_sha256_64_simple(const struct kr_srvr_cookie_
return kr_error(EINVAL);
}
if (!input->clnt_cookie ||
!input->srvr_data.secret_data || !input->srvr_data.secret_len) {
if (!input->clnt_cookie || !input->srvr_data ||
!input->srvr_data->secret_data || !input->srvr_data->secret_len) {
return kr_error(EINVAL);
}
......@@ -220,8 +201,8 @@ static int kr_srvr_cookie_alg_hmac_sha256_64_simple(const struct kr_srvr_cookie_
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
int ret = HMAC_Init_ex(&ctx, input->srvr_data.secret_data,
input->srvr_data.secret_len,
int ret = HMAC_Init_ex(&ctx, input->srvr_data->secret_data,
input->srvr_data->secret_len,
EVP_sha256(), NULL);
if (ret != 1) {
ret = kr_error(EINVAL);
......@@ -234,8 +215,8 @@ static int kr_srvr_cookie_alg_hmac_sha256_64_simple(const struct kr_srvr_cookie_
goto fail;
}
if (input->srvr_data.clnt_sockaddr) {
if (kr_ok() == kr_address_bytes(input->srvr_data.clnt_sockaddr,
if (input->srvr_data->clnt_sockaddr) {
if (kr_ok() == kr_address_bytes(input->srvr_data->clnt_sockaddr,
&addr, &alen)) {
assert(addr && alen);
ret = HMAC_Update(&ctx, addr, alen);
......@@ -278,8 +259,8 @@ static int kr_srvr_cookie_alg_hmac_sha256_64(const struct kr_srvr_cookie_input *
return kr_error(EINVAL);
}
if (!input->clnt_cookie ||
!input->srvr_data.secret_data || !input->srvr_data.secret_len) {
if (!input->clnt_cookie || !input->srvr_data ||
!input->srvr_data->secret_data || !input->srvr_data->secret_len) {
return kr_error(EINVAL);
}
......@@ -292,8 +273,8 @@ static int kr_srvr_cookie_alg_hmac_sha256_64(const struct kr_srvr_cookie_input *
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
int ret = HMAC_Init_ex(&ctx, input->srvr_data.secret_data,
input->srvr_data.secret_len,
int ret = HMAC_Init_ex(&ctx, input->srvr_data->secret_data,
input->srvr_data->secret_len,
EVP_sha256(), NULL);
if (ret != 1) {
ret = kr_error(EINVAL);
......@@ -318,8 +299,8 @@ static int kr_srvr_cookie_alg_hmac_sha256_64(const struct kr_srvr_cookie_input *
goto fail;
}
if (input->srvr_data.clnt_sockaddr) {
if (kr_ok() == kr_address_bytes(input->srvr_data.clnt_sockaddr,
if (input->srvr_data->clnt_sockaddr) {
if (kr_ok() == kr_address_bytes(input->srvr_data->clnt_sockaddr,
&addr, &alen)) {
assert(addr && alen);
ret = HMAC_Update(&ctx, addr, alen);
......@@ -353,3 +334,84 @@ fail:
HMAC_CTX_cleanup(&ctx);
return ret;
}
const struct kr_srvr_cookie_alg_descr kr_srvr_cookie_algs[] = {
{ "FNV-64-SIMPLE", SRVR_FNV64_SIMPLE_HASH_SIZE, srvr_cookie_parse_simple, kr_srvr_cookie_alg_fnv64_simple },
{ "FNV-64", SRVR_FNV64_SIZE, srvr_cookie_parse, kr_srvr_cookie_alg_fnv64 },
{ "HMAC-SHA256-64-SIMPLE", SRVR_HMAC_SHA256_64_SIMPLE_HASH_SIZE, srvr_cookie_parse_simple, kr_srvr_cookie_alg_hmac_sha256_64_simple },
{ "HMAC-SHA256-64", SRVR_HMAC_SHA256_64_SIZE, srvr_cookie_parse, kr_srvr_cookie_alg_hmac_sha256_64 },
{ NULL, 0, NULL, NULL }
};
const struct kr_srvr_cookie_alg_descr *kr_srvr_cookie_alg(const struct kr_srvr_cookie_alg_descr sc_algs[],
const char *name)
{
if (!sc_algs || !name) {
return NULL;
}
const struct kr_srvr_cookie_alg_descr *aux_ptr = sc_algs;
while (aux_ptr && aux_ptr->gen_func) {
assert(aux_ptr->name);
if (strcmp(aux_ptr->name, name) == 0) {
return aux_ptr;
}
++aux_ptr;
}
return NULL;
}
int kr_srvr_cookie_check(const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
const uint8_t *sc, uint16_t sc_len,
const struct kr_srvr_cookie_check_ctx *check_ctx,
const struct kr_srvr_cookie_alg_descr *sc_alg)
{
if (!cc || !sc || !sc_len || !check_ctx || !sc_alg) {
return kr_error(EINVAL);
}
if (!check_ctx->clnt_sockaddr ||
!check_ctx->secret_data || !check_ctx->secret_len) {
return kr_error(EINVAL);
}
if (!sc_alg->srvr_cookie_size ||
!sc_alg->opt_parse_func || !sc_alg->gen_func) {
return kr_error(EINVAL);
}
if (sc_len != sc_alg->srvr_cookie_size) {
/* Cookie size does to match. */
return kr_error(EBADMSG);
}
struct kr_srvr_cookie_inbound inbound_sc = { 0, };
/* Obtain data from received server cookie. */
int ret = sc_alg->opt_parse_func(sc, sc_len, &inbound_sc);
if (ret != kr_ok()) {
return ret;
}
uint8_t generated_sc[KNOT_OPT_COOKIE_SRVR_MAX] = { 0, };
size_t generated_sc_len = KNOT_OPT_COOKIE_SRVR_MAX;
struct kr_srvr_cookie_input sc_input = {
.clnt_cookie = cc,
.nonce = inbound_sc.nonce,
.time = inbound_sc.time,
.srvr_data = check_ctx
};
/* Generate a new server cookie. */
ret = sc_alg->gen_func(&sc_input, generated_sc, &generated_sc_len);
if (ret != kr_ok()) {
return ret;
}
assert(generated_sc_len == sc_alg->srvr_cookie_size);
ret = (memcmp(sc, generated_sc, generated_sc_len) == 0) ?
kr_ok() : kr_error(EBADMSG);
return ret;
}
......@@ -29,7 +29,6 @@ struct kr_srvr_cookie_check_ctx {
/** Inbound server cookie content structure. */
struct kr_srvr_cookie_inbound {
const uint8_t *clnt_cookie; /**< Client cookie, `KNOT_OPT_COOKIE_CLNT` bytes long. */
uint32_t nonce; /**< Some value. */
uint32_t time; /**< Time stamp. */
const uint8_t *hash_data; /**< Hash data. */
......@@ -41,17 +40,17 @@ struct kr_srvr_cookie_input {
const uint8_t *clnt_cookie; /**< Client cookie, must be `KNOT_OPT_COOKIE_CLNT` bytes long. */
uint32_t nonce; /**< Some generated value. */
uint32_t time; /**< Cookie time stamp. */
struct kr_srvr_cookie_check_ctx srvr_data; /**< Data known to the server. */
const struct kr_srvr_cookie_check_ctx *srvr_data; /**< Data known to the server. */
};
/**
* @brief Server cookie parser function type.
* @param cookie_data Entire cookie option data (without option header).
* @param data_len Cookie data length.
* @param inbound Inbound cookie structure to be set.
* @param sc Server cookie data.
* @param data_len Server cookie data length.
* @param inbound Inbound cookie structure to be set.
* @return kr_ok() or error code.
*/
typedef int (srvr_cookie_parse_t)(const uint8_t *cookie_data, uint16_t data_len,
typedef int (srvr_cookie_parse_t)(const uint8_t *sc, uint16_t sc_len,
struct kr_srvr_cookie_inbound *inbound);
/**
* @brief Server cookie generator function type.
......@@ -65,10 +64,10 @@ typedef int (srvr_cookie_gen_t)(const struct kr_srvr_cookie_input *input,
/** Holds description of server cookie hashing algorithms. */
struct kr_srvr_cookie_alg_descr {
const char *name; /** Server cookie algorithm name. */
const char *name; /**< Server cookie algorithm name. */
const uint16_t srvr_cookie_size; /**< Size of the generated server cookie. */
const srvr_cookie_parse_t *opt_parse_func; /**< Cookie option parser function. */
const srvr_cookie_gen_t *gen_func; /*< Cookie generator function. */
srvr_cookie_parse_t *opt_parse_func; /**< Cookie option parser function. */
srvr_cookie_gen_t *gen_func; /**< Cookie generator function. */
};
/**
......@@ -79,14 +78,27 @@ struct kr_srvr_cookie_alg_descr {
KR_EXPORT
extern const struct kr_srvr_cookie_alg_descr kr_srvr_cookie_algs[];
/**
* @brief Return pointer to server cookie algorithm with given name.
* @param sc_algs List of available algorithms.
* @param name Algorithm name.
* @return pointer to algorithm or NULL if not found.
*/
KR_EXPORT
const struct kr_srvr_cookie_alg_descr *kr_srvr_cookie_alg(const struct kr_srvr_cookie_alg_descr sc_algs[],
const char *name);
/**
* @brief Check whether supplied client and server cookie match.
* @param cookie_opt Entire cookie option, must contain server cookie.
* @param cc Client cookie.
* @param sc Server cookie that should be checked.
* @param sc_len Server cookie length.
* @param check_ctx Data known to the server needed for cookie validation.
* @param sc_alg Server cookie algorithm.
* @return kr_ok() if check OK, error code else.
*/
KR_EXPORT
int kr_srvr_cookie_check(const uint8_t *cookie_opt,
int kr_srvr_cookie_check(const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
const uint8_t *sc, uint16_t sc_len,
const struct kr_srvr_cookie_check_ctx *check_ctx,
const struct kr_srvr_cookie_alg_descr *sc_alg);
......@@ -38,9 +38,16 @@ struct kr_cookie_secret dflt_cs = {
.data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
/* Default srver secret. */
struct kr_cookie_secret dflt_ss = {
.size = KNOT_OPT_COOKIE_CLNT,
.data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
struct kr_cookie_ctx kr_glob_cookie_ctx = {
.enabled = false,
.current_cs = &dflt_cs
.current_cs = &dflt_cs,
.current_ss = &dflt_ss
};
static int opt_rr_add_cookies(knot_rrset_t *opt_rr,
......
......@@ -34,6 +34,10 @@ struct kr_cookie_secret {
KR_EXPORT
extern struct kr_cookie_secret dflt_cs;
/** Default server secret. */
KR_EXPORT
extern struct kr_cookie_secret dflt_ss;
/** Default cookie TTL. */
#define DFLT_COOKIE_TTL 72000
......@@ -46,7 +50,11 @@ struct kr_cookie_ctx {
uint32_t cache_ttl; /**< TTL used when caching cookies */
struct kr_cookie_secret *current_ss; /**< current server secret */
struct kr_cookie_secret *recent_ss; /**< recent server secret */
const struct kr_clnt_cookie_alg_descr *cc_alg; /**< Client cookie algorithm. */
const struct kr_srvr_cookie_alg_descr *sc_alg; /**< Server cookie algorithm. */
};
/** Global cookie control context. */
......
......@@ -26,6 +26,7 @@
#include "daemon/engine.h"
#include "lib/cookies/alg_clnt.h"
#include "lib/cookies/alg_srvr.h"
#include "lib/cookies/cache.h"
#include "lib/cookies/control.h"
#include "lib/module.h"
......@@ -366,12 +367,85 @@ static int check_response(knot_layer_t *ctx, knot_pkt_t *pkt)
return ctx->state;
}
static int check_request(knot_layer_t *ctx, void *module_param)
{
if (!kr_glob_cookie_ctx.enabled) {
/* TODO -- IS there a way how to determine whether the original
* request came via TCP? */
return ctx->state;
}
struct kr_request *req = ctx->data;
const knot_rrset_t *req_opt_rr = req->qsource.opt;
if (!req_opt_rr) {
return ctx->state;
}
uint8_t *req_cookie_opt = knot_edns_get_option(req_opt_rr,
KNOT_EDNS_OPTION_COOKIE);
if (!req_cookie_opt) {
return ctx->state;
}
const uint8_t *req_cookie_data = knot_edns_opt_get_data(req_cookie_opt);
uint16_t req_cookie_len = knot_edns_opt_get_length(req_cookie_opt);
assert(req_cookie_data && req_cookie_len);
const uint8_t *req_cc = NULL, *req_sc = NULL;
uint16_t req_cc_len = 0, req_sc_len = 0;
int ret = knot_edns_opt_cookie_parse(req_cookie_data, req_cookie_len,
&req_cc, &req_cc_len,
&req_sc, &req_sc_len);
if (ret != KNOT_EOK) {
/* TODO -- Generate BADCOOKIE response. */
DEBUG_MSG(NULL, "%s\n", "got malformed DNS cookie in request");
return ctx->state;
}
assert(req_cc_len == KNOT_OPT_COOKIE_CLNT);
if (!req_sc) {
/* TODO -- BADCOOKIE? Occasionally ignore? */
DEBUG_MSG(NULL, "%s\n", "no server cookie in request");
return ctx->state;
}
/* Check server cookie obtained in request. */
const struct kr_cookie_ctx *cntrl = &kr_glob_cookie_ctx;
if (!req->qsource.addr || !cntrl->current_ss) {
/* TODO -- SERVFAIL? */
DEBUG_MSG(NULL, "%s\n", "no server DNS cookie context data");
return ctx->state;
}
struct kr_srvr_cookie_check_ctx check_ctx = {
.clnt_sockaddr = req->qsource.addr,
.secret_data = cntrl->current_ss->data,
.secret_len = cntrl->current_ss->size
};
ret = kr_srvr_cookie_check(req_cc, req_sc, req_sc_len, &check_ctx,
cntrl->sc_alg);
if (ret != kr_ok()) {
/* TODO -- BADCOOKIE? Occasionally ignore? */
DEBUG_MSG(NULL, "%s\n", "invalid server DNS cookie data");
return ctx->state;
}
/* Server cookie OK. */
return ctx->state;
}
/** Module implementation. */
KR_EXPORT
const knot_layer_api_t *cookiemonster_layer(struct kr_module *module)
{
static knot_layer_api_t _layer = {
.begin = &check_request,
.consume = &check_response
};
/* Store module reference */
......
......@@ -114,6 +114,9 @@ struct kr_request {
const struct sockaddr *addr;
const struct sockaddr *dst_addr;
const knot_pkt_t *packet;
#if defined(ENABLE_COOKIES)
const knot_rrset_t *opt;
#endif /* defined(ENABLE_COOKIES) */
} qsource;
struct {
unsigned rtt; /**< Current upstream RTT */
......
......@@ -22,6 +22,7 @@
#include "daemon/engine.h"
#include "lib/cookies/alg_clnt.h"
#include "lib/cookies/alg_srvr.h"
#include "lib/cookies/control.h"
#include "lib/layer.h"
......@@ -291,7 +292,9 @@ 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.current_ss = &dflt_ss;
kr_glob_cookie_ctx.cc_alg = kr_clnt_cookie_alg(kr_clnt_cookie_algs, "FNV-64");
kr_glob_cookie_ctx.sc_alg = kr_srvr_cookie_alg(kr_srvr_cookie_algs, "HMAC-SHA256-64");
module->data = NULL;
......@@ -315,6 +318,18 @@ int cookiectl_deinit(struct kr_module *module)
}
kr_glob_cookie_ctx.current_cs = &dflt_cs;
if (kr_glob_cookie_ctx.recent_ss &&
kr_glob_cookie_ctx.recent_ss != &dflt_ss) {
free(kr_glob_cookie_ctx.recent_ss);
}
kr_glob_cookie_ctx.recent_ss = NULL;
if (kr_glob_cookie_ctx.current_ss &&
kr_glob_cookie_ctx.current_ss != &dflt_ss) {
free(kr_glob_cookie_ctx.current_ss);
}
kr_glob_cookie_ctx.current_ss = &dflt_ss;
return kr_ok();
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment