Commit 632ace75 authored by Ondřej Surý's avatar Ondřej Surý

Add EDNS(0) padding support

parent df46cad9
......@@ -594,6 +594,13 @@ For when listening on ``localhost`` just doesn't cut it.
> net.listen("::", 853)
> net.listen("::", 443, {tls = true})
.. function:: net.tls_padding([padding])
Get/set EDNS(0) padding. If set to value >= 2 it will pad the answers
to nearest *padding* boundary, e.g. if set to `64`, the answer will
have size of multiplies of 64 (64, 128, 192, ...). Setting padding to
value < 2 will disable it.
Trust anchors and DNSSEC
^^^^^^^^^^^^^^^^^^^^^^^^
......
......@@ -394,6 +394,33 @@ static int net_tls(lua_State *L)
return 1;
}
static int net_tls_padding(lua_State *L)
{
struct engine *engine = engine_luaget(L);
/* Only return current padding. */
if (lua_gettop(L) == 0) {
if (engine->resolver.tls_padding == 0) {
return -1;
}
lua_pushinteger(L, engine->resolver.tls_padding);
return 1;
}
if ((lua_gettop(L) != 1) || !lua_isnumber(L, 1)) {
lua_pushstring(L, "net.tls_padding takes one numeric parameter: (\"padding\")");
lua_error(L);
}
int padding = lua_tointeger(L, 1);
if ((padding < 0) || (padding > MAX_TLS_PADDING)) {
lua_pushstring(L, "net.tls_padding parameter has to be a number between <0, 4096>");
lua_error(L);
}
engine->resolver.tls_padding = padding;
lua_pushboolean(L, true);
return 1;
}
int lib_net(lua_State *L)
{
static const luaL_Reg lib[] = {
......@@ -404,6 +431,7 @@ int lib_net(lua_State *L)
{ "bufsize", net_bufsize },
{ "tcp_pipeline", net_pipeline },
{ "tls", net_tls },
{ "tls_padding", net_tls_padding },
{ NULL, NULL }
};
register_lib(L, "net", lib);
......
......@@ -483,6 +483,8 @@ static int init_resolver(struct engine *engine)
return kr_error(ENOMEM);
}
knot_edns_init(engine->resolver.opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, engine->pool);
/* Set default TLS padding */
engine->resolver.tls_padding = KR_DEFAULT_TLS_PADDING;
/* Set default root hints */
kr_zonecut_init(&engine->resolver.root_hints, (const uint8_t *)"", engine->pool);
kr_zonecut_set_sbelt(&engine->resolver, &engine->resolver.root_hints);
......
......@@ -112,6 +112,7 @@ struct query_flag {
static const int BADCOOKIE_AGAIN = 1 << 22;
static const int CNAME = 1 << 23;
static const int REORDER_RR = 1 << 24;
static const int TLS = 1 << 25;
};
/*
......
......@@ -19,6 +19,9 @@
#include <uv.h>
#include <gnutls/gnutls.h>
#include <libknot/packet/pkt.h>
#include "lib/defines.h"
#define MAX_TLS_PADDING KR_EDNS_PAYLOAD
struct tls_ctx_t;
struct tls_credentials;
......
......@@ -721,6 +721,7 @@ static int qr_task_step(struct qr_task *task, const struct sockaddr *packet_sour
task->addrlist = NULL;
task->addrlist_count = 0;
task->addrlist_turn = 0;
task->req.has_tls = (task->session && task->session->has_tls) ? true : false;
int state = kr_resolve_consume(&task->req, packet_source, packet);
while (state == KNOT_STATE_PRODUCE) {
state = kr_resolve_produce(&task->req, &task->addrlist, &sock_type, task->pktbuf);
......@@ -881,7 +882,7 @@ int worker_end_tcp(struct worker_ctx *worker, uv_handle_t *handle)
* borrowed the task from parent session. */
struct session *session = handle->data;
if (session->outgoing) {
worker_submit(worker, (uv_handle_t *)handle, NULL, NULL);
worker_submit(worker, (uv_handle_t *)handle, NULL, NULL);
} else {
discard_buffered(session);
}
......
......@@ -64,6 +64,7 @@ static inline int __attribute__((__cold__)) kr_error(int x) {
#define KR_DNS_TLS_PORT 853
#define KR_EDNS_VERSION 0
#define KR_EDNS_PAYLOAD 4096 /* Default UDP payload (max unfragmented UDP is 1452B) */
#define KR_DEFAULT_TLS_PADDING 128 /* Default EDNS(0) Padding is 128 */
/*
* Address sanitizer hints.
......
......@@ -308,6 +308,9 @@ static int edns_create(knot_pkt_t *pkt, knot_pkt_t *template, struct kr_request
wire_size += KR_COOKIE_OPT_MAX_LEN;
}
#endif /* defined(ENABLE_COOKIES) */
if (req->has_tls && req->ctx->tls_padding >= 2) {
wire_size += KNOT_EDNS_OPTION_HDRLEN + req->ctx->tls_padding;
}
return knot_pkt_reserve(pkt, wire_size);
}
......@@ -337,8 +340,36 @@ static void write_extra_records(rr_array_t *arr, knot_pkt_t *answer)
}
}
static int answer_fail(knot_pkt_t *answer)
static int answer_padding(struct kr_request *request)
{
uint16_t padding = request->ctx->tls_padding;
knot_pkt_t *answer = request->answer;
knot_rrset_t *opt_rr = answer->opt_rr;
if (padding < 2) {
return true;
}
int32_t max_pad_bytes = knot_edns_get_payload(opt_rr) - (answer->size + knot_rrset_size(opt_rr));
int32_t pad_bytes = MIN(knot_edns_alignment_size(answer->size, knot_rrset_size(opt_rr), padding),
max_pad_bytes);
if (pad_bytes > 0) {
uint8_t zeros[pad_bytes];
memset(zeros, 0, sizeof(zeros));
int r = knot_edns_add_option(opt_rr, KNOT_EDNS_OPTION_PADDING,
pad_bytes, zeros, &answer->mm);
if (r != KNOT_EOK) {
knot_rrset_clear(opt_rr, &answer->mm);
return false;
}
}
return true;
}
static int answer_fail(struct kr_request *request)
{
knot_pkt_t *answer = request->answer;
int ret = kr_pkt_clear_payload(answer);
knot_wire_clear_ad(answer->wire);
knot_wire_clear_aa(answer->wire);
......@@ -346,6 +377,7 @@ static int answer_fail(knot_pkt_t *answer)
if (ret == 0 && answer->opt_rr) {
/* OPT in SERVFAIL response is still useful for cookies/additional info. */
knot_pkt_begin(answer, KNOT_ADDITIONAL);
answer_padding(request); /* Ignore failed padding in SERVFAIL answer a*/
ret = edns_put(answer);
}
return ret;
......@@ -360,7 +392,7 @@ static int answer_finalize(struct kr_request *request, int state)
if (state == KNOT_STATE_FAIL && rplan->pending.len > 0) {
struct kr_query *last = array_tail(rplan->pending);
if ((last->flags & QUERY_DNSSEC_WANT) && (last->flags & QUERY_DNSSEC_BOGUS)) {
return answer_fail(answer);
return answer_fail(request);
}
}
......@@ -375,6 +407,11 @@ static int answer_finalize(struct kr_request *request, int state)
/* Write EDNS information */
int ret = 0;
if (answer->opt_rr) {
if (request->has_tls) {
if (!answer_padding(request)) {
return answer_fail(request);
}
}
knot_pkt_begin(answer, KNOT_ADDITIONAL);
ret = edns_put(answer);
}
......
......@@ -99,6 +99,7 @@ struct kr_context
* module because of better access. */
struct kr_cookie_ctx cookie_ctx;
kr_cookie_lru_t *cache_cookie;
uint32_t tls_padding;
knot_mm_t *pool;
};
......@@ -132,6 +133,7 @@ struct kr_request {
rr_array_t authority;
rr_array_t additional;
struct kr_rplan rplan;
int has_tls;
knot_mm_t pool;
};
......
......@@ -49,7 +49,8 @@
X(STRICT, 1 << 21) /**< Strict resolver mode. */ \
X(BADCOOKIE_AGAIN, 1 << 22) /**< Query again because bad cookie returned. */ \
X(CNAME, 1 << 23) /**< Query response contains CNAME in answer section. */ \
X(REORDER_RR, 1 << 24) /**< Reorder cached RRs. */
X(REORDER_RR, 1 << 24) /**< Reorder cached RRs. */ \
X(TLS, 1 << 25) /**< Use TLS for this query. */
/** Query flags */
enum kr_query_flag {
......
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