/* Copyright (C) 2018 CZ.NIC, z.s.p.o. 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 . */ /** * @file edns_keepalive.c * @brief Minimalistic EDNS keepalive implementation on server side. * If keepalive option is present in query, * always reply with constant timeout value. * */ #include #include "daemon/worker.h" #include "lib/module.h" #include "lib/layer.h" static int edns_keepalive_finalize(kr_layer_t *ctx) { struct kr_request *req = ctx->req; knot_pkt_t *answer = req->answer; const knot_rrset_t *src_opt = req->qsource.packet->opt_rr; knot_rrset_t *answ_opt = answer->opt_rr; const bool ka_want = req->qsource.flags.tcp && src_opt != NULL && knot_edns_get_option(src_opt, KNOT_EDNS_OPTION_TCP_KEEPALIVE) && answ_opt != NULL; if (!ka_want) { return ctx->state; } const struct worker_ctx *worker = (const struct worker_ctx *)req->daemon_context; assert(worker); const struct network *net = &worker->engine->net; uint64_t timeout = net->tcp.in_idle_timeout / 100; if (timeout > UINT16_MAX) { timeout = UINT16_MAX; } knot_mm_t *pool = &answer->mm; uint16_t ka_size = knot_edns_keepalive_size(timeout); uint8_t ka_buf[ka_size]; int ret = knot_edns_keepalive_write(ka_buf, ka_size, timeout); if (ret == KNOT_EOK) { ret = knot_edns_add_option(answ_opt, KNOT_EDNS_OPTION_TCP_KEEPALIVE, ka_size, ka_buf, pool); } if (ret != KNOT_EOK) { ctx->state = KR_STATE_FAIL; } return ctx->state; } KR_EXPORT const kr_layer_api_t *edns_keepalive_layer(struct kr_module *module) { static kr_layer_api_t _layer = { .answer_finalize = &edns_keepalive_finalize, }; /* Store module reference */ _layer.data = module; return &_layer; } KR_MODULE_EXPORT(edns_keepalive)