Commit 7dae38f7 authored by Karel Slaný's avatar Karel Slaný Committed by Ondřej Surý

Served cookie queries are handled inside cookie module.

parent ee2ac45a
......@@ -203,6 +203,7 @@ struct kr_zonecut {
};
struct kr_query {
struct kr_query *parent;
uint16_t qdcount;
knot_dname_t *sname;
uint16_t type;
uint16_t class;
......
......@@ -511,6 +511,15 @@ static int begin(knot_layer_t *ctx, void *module_param)
if (ctx->state & (KNOT_STATE_DONE|KNOT_STATE_FAIL)) {
return ctx->state;
}
/*
* Fail if no query section. DNS cookies must be handled before
* this layer.
*/
const struct kr_request *req = ctx->data;
const struct kr_query *qry = req->current_query;
if (qry->qdcount == 0) {
return KNOT_STATE_FAIL;
}
return reset(ctx);
}
......
......@@ -389,62 +389,6 @@ int kr_resolve_begin(struct kr_request *request, struct kr_context *ctx, knot_pk
return KNOT_STATE_CONSUME;
}
#if defined(ENABLE_COOKIES)
/**
* @brief Put cookie into answer packet.
* @param clnt_sockaddr client socket address
* @param srvr_sett settings structure of the server cookie algorithm
* @param cookies obtained cookies
* @param answer answer packet
* @return state
*/
static int cookie_answer(const void *clnt_sockaddr,
const struct kr_cookie_settings *srvr_sett,
struct knot_dns_cookies *cookies, knot_pkt_t *answer)
{
assert(srvr_sett && cookies && answer);
/* Initialise answer. */
knot_wire_set_qr(answer->wire);
knot_wire_clear_aa(answer->wire);
knot_wire_set_ra(answer->wire);
knot_wire_set_rcode(answer->wire, KNOT_RCODE_NOERROR);
struct knot_sc_private srvr_data = {
.clnt_sockaddr = clnt_sockaddr,
.secret_data = srvr_sett->current.secr->data,
.secret_len = srvr_sett->current.secr->size
};
struct timeval tv;
gettimeofday(&tv, NULL);
struct kr_nonce_input nonce = {
.rand = kr_rand_uint(UINT32_MAX),
.time = tv.tv_sec
};
/* Add fres cookie into the answer. */
int ret = kr_answer_write_cookie(&srvr_data,
cookies->cc, cookies->cc_len, &nonce,
kr_sc_algs[srvr_sett->current.alg_id], answer);
if (ret != kr_ok()) {
return KNOT_STATE_FAIL;
}
/* Check server cookie only with current settings. */
ret = knot_sc_check(KR_NONCE_LEN, cookies, &srvr_data,
kr_sc_algs[srvr_sett->current.alg_id]);
if (ret != KNOT_EOK) {
/* RFC7873 5.4 */
kr_pkt_set_ext_rcode(answer, KNOT_RCODE_BADCOOKIE);
return KNOT_STATE_FAIL | KNOT_STATE_DONE;
}
return KNOT_STATE_DONE;
}
#endif /* defined(ENABLE_COOKIES) */
static int resolve_query(struct kr_request *request, const knot_pkt_t *packet)
{
struct kr_rplan *rplan = &request->rplan;
......@@ -453,30 +397,7 @@ static int resolve_query(struct kr_request *request, const knot_pkt_t *packet)
uint16_t qtype = knot_pkt_qtype(packet);
struct kr_query *qry = kr_rplan_push(rplan, NULL, qname, qclass, qtype);
if (!qry) {
#if defined(ENABLE_COOKIES)
/* 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_no_question_cookie_query(packet);
if (cookie_opt && request->ctx->cookie_ctx.clnt.enabled) {
if (kr_ok() != kr_parse_cookie_opt(cookie_opt,
&cookies)) {
/* RFC7873 5.2.2 malformed cookie. */
knot_wire_set_rcode(request->answer->wire,
KNOT_RCODE_FORMERR);
return KNOT_STATE_FAIL;
}
}
return cookie_answer(request->qsource.addr,
&request->ctx->cookie_ctx.srvr,
&cookies, request->answer);
#else /* !defined(ENABLE_COOKIES) */
return KNOT_STATE_FAIL;
#endif /* defined(ENABLE_COOKIES) */
}
/* Deferred zone cut lookup for this query. */
......
......@@ -42,20 +42,19 @@ const knot_lookup_t *kr_query_flag_names(void)
static struct kr_query *query_create(knot_mm_t *pool, const knot_dname_t *name)
{
if (name == NULL) {
return NULL;
}
struct kr_query *qry = mm_alloc(pool, sizeof(struct kr_query));
if (qry == NULL) {
return NULL;
}
memset(qry, 0, sizeof(struct kr_query));
qry->sname = knot_dname_copy(name, pool);
if (qry->sname == NULL) {
mm_free(pool, qry);
return NULL;
if (name != NULL) {
qry->sname = knot_dname_copy(name, pool);
if (qry->sname == NULL) {
mm_free(pool, qry);
return NULL;
}
qry->qdcount = 1;
}
knot_dname_to_lower(qry->sname);
......@@ -112,7 +111,7 @@ bool kr_rplan_empty(struct kr_rplan *rplan)
struct kr_query *kr_rplan_push(struct kr_rplan *rplan, struct kr_query *parent,
const knot_dname_t *name, uint16_t cls, uint16_t type)
{
if (rplan == NULL || name == NULL) {
if (rplan == NULL) {
return NULL;
}
......
......@@ -65,6 +65,7 @@ const knot_lookup_t *kr_query_flag_names(void);
*/
struct kr_query {
struct kr_query *parent;
uint16_t qdcount; /* Can be 0 when querying server cookie. */
knot_dname_t *sname;
uint16_t stype;
uint16_t sclass;
......
......@@ -397,9 +397,14 @@ int check_request(knot_layer_t *ctx, void *module_param)
.time = req->current_query->timestamp.tv_sec
};
const struct kr_query *qry = req->current_query;
if (!cookies.sc) {
/* Request has no server cookie. TODO -- Silently discard? */
if (!ignore_badcookie) {
/* Request has no server cookie. */
if (qry->qdcount == 0) {
/* RFC7873 5.4 */
return_state = KNOT_STATE_DONE;
} else if (!ignore_badcookie) { /* TODO -- Silently discard? */
/* Generate BADCOOKIE response. */
DEBUG_MSG(NULL, "%s\n",
"request is missing server cookie");
......@@ -431,8 +436,12 @@ int check_request(knot_layer_t *ctx, void *module_param)
kr_sc_algs[srvr_sett->recent.alg_id]);
}
if (ret != KNOT_EOK) {
/* TODO -- Silently discard? */
if (!ignore_badcookie) {
/* Invalid server cookie. */
if (qry->qdcount == 0) {
/* RFC7873 5.4 */
kr_pkt_set_ext_rcode(req->answer, KNOT_RCODE_BADCOOKIE);
return_state = KNOT_STATE_DONE | KNOT_STATE_FAIL;
} else if (!ignore_badcookie) { /* TODO -- Silently discard? */
/* Generate BADCOOKIE response. */
DEBUG_MSG(NULL, "%s\n",
"request has invalid server cookie");
......
......@@ -32,7 +32,8 @@ static void test_rplan_params(void **state)
struct kr_rplan rplan;
assert_int_equal(kr_rplan_init(&rplan, NULL, NULL), KNOT_EOK);
assert_null((void *)kr_rplan_push(&rplan, NULL, NULL, 0, 0));
// TODO: add test for empty dname
// assert_null((void *)kr_rplan_push(&rplan, NULL, NULL, 0, 0));
assert_int_equal(kr_rplan_pop(&rplan, NULL), KNOT_EINVAL);
assert_true(kr_rplan_empty(&rplan) == true);
kr_rplan_deinit(&rplan);
......
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