summaryrefslogtreecommitdiffstats
path: root/src/knot/nameserver/query_module.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/knot/nameserver/query_module.c')
-rw-r--r--src/knot/nameserver/query_module.c791
1 files changed, 791 insertions, 0 deletions
diff --git a/src/knot/nameserver/query_module.c b/src/knot/nameserver/query_module.c
new file mode 100644
index 0000000..2837135
--- /dev/null
+++ b/src/knot/nameserver/query_module.c
@@ -0,0 +1,791 @@
+/* Copyright (C) 2022 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "contrib/sockaddr.h"
+#include "libknot/attribute.h"
+#include "libknot/probe/data.h"
+#include "libknot/xdp.h"
+#include "knot/common/log.h"
+#include "knot/conf/module.h"
+#include "knot/conf/tools.h"
+#include "knot/dnssec/rrset-sign.h"
+#include "knot/dnssec/zone-sign.h"
+#include "knot/nameserver/query_module.h"
+#include "knot/nameserver/process_query.h"
+
+#ifdef HAVE_ATOMIC
+ #define ATOMIC_ADD(dst, val) __atomic_add_fetch(&(dst), (val), __ATOMIC_RELAXED)
+ #define ATOMIC_SUB(dst, val) __atomic_sub_fetch(&(dst), (val), __ATOMIC_RELAXED)
+ #define ATOMIC_SET(dst, val) __atomic_store_n(&(dst), (val), __ATOMIC_RELAXED)
+#else
+ #warning "Statistics data can be inaccurate"
+ #define ATOMIC_ADD(dst, val) ((dst) += (val))
+ #define ATOMIC_SUB(dst, val) ((dst) -= (val))
+ #define ATOMIC_SET(dst, val) ((dst) = (val))
+#endif
+
+_public_
+int knotd_conf_check_ref(knotd_conf_check_args_t *args)
+{
+ return check_ref(args);
+}
+
+struct query_plan *query_plan_create(void)
+{
+ struct query_plan *plan = malloc(sizeof(struct query_plan));
+ if (plan == NULL) {
+ return NULL;
+ }
+
+ for (unsigned i = 0; i < KNOTD_STAGES; ++i) {
+ init_list(&plan->stage[i]);
+ }
+
+ return plan;
+}
+
+void query_plan_free(struct query_plan *plan)
+{
+ if (plan == NULL) {
+ return;
+ }
+
+ for (unsigned i = 0; i < KNOTD_STAGES; ++i) {
+ struct query_step *step, *next;
+ WALK_LIST_DELSAFE(step, next, plan->stage[i]) {
+ free(step);
+ }
+ }
+
+ free(plan);
+}
+
+static struct query_step *make_step(query_step_process_f process, void *ctx)
+{
+ struct query_step *step = calloc(1, sizeof(struct query_step));
+ if (step == NULL) {
+ return NULL;
+ }
+
+ step->process = process;
+ step->ctx = ctx;
+
+ return step;
+}
+
+int query_plan_step(struct query_plan *plan, knotd_stage_t stage,
+ query_step_process_f process, void *ctx)
+{
+ struct query_step *step = make_step(process, ctx);
+ if (step == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ add_tail(&plan->stage[stage], &step->node);
+
+ return KNOT_EOK;
+}
+
+_public_
+int knotd_mod_hook(knotd_mod_t *mod, knotd_stage_t stage, knotd_mod_hook_f hook)
+{
+ if (stage != KNOTD_STAGE_BEGIN && stage != KNOTD_STAGE_END) {
+ return KNOT_EINVAL;
+ }
+
+ return query_plan_step(mod->plan, stage, hook, mod);
+}
+
+_public_
+int knotd_mod_in_hook(knotd_mod_t *mod, knotd_stage_t stage, knotd_mod_in_hook_f hook)
+{
+ if (stage == KNOTD_STAGE_BEGIN || stage == KNOTD_STAGE_END) {
+ return KNOT_EINVAL;
+ }
+
+ return query_plan_step(mod->plan, stage, hook, mod);
+}
+
+knotd_mod_t *query_module_open(conf_t *conf, server_t *server, conf_mod_id_t *mod_id,
+ struct query_plan *plan, const knot_dname_t *zone)
+{
+ if (conf == NULL || server == NULL || mod_id == NULL || plan == NULL) {
+ return NULL;
+ }
+
+ /* Locate the module. */
+ const module_t *mod = conf_mod_find(conf, mod_id->name + 1,
+ mod_id->name[0], false);
+ if (mod == NULL) {
+ return NULL;
+ }
+
+ /* Create query module. */
+ knotd_mod_t *module = calloc(1, sizeof(knotd_mod_t));
+ if (module == NULL) {
+ return NULL;
+ }
+
+ module->plan = plan;
+ module->config = conf;
+ module->server = server;
+ module->zone = zone;
+ module->id = mod_id;
+ module->api = mod->api;
+
+ return module;
+}
+
+static void module_reset(conf_t *conf, knotd_mod_t *module, struct query_plan *new_plan)
+{
+ // Keep ->node
+ module->config = conf;
+ // Keep ->server
+ // Keep ->id
+ module->plan = new_plan;
+ // Keep ->zone
+ // Keep ->api
+
+ // Reset DNSSEC
+ zone_sign_ctx_free(module->sign_ctx);
+ free_zone_keys(module->keyset);
+ free(module->keyset);
+ if (module->dnssec != NULL) {
+ kdnssec_ctx_deinit(module->dnssec);
+ free(module->dnssec);
+ }
+ module->dnssec = NULL;
+ module->keyset = NULL;
+ module->sign_ctx = NULL;
+
+ // Reset statistics
+ knotd_mod_stats_free(module);
+ module->stats_info = NULL;
+ module->stats_vals = NULL;
+ module->stats_count = 0;
+
+ // Keep ->ctx
+}
+
+void query_module_close(knotd_mod_t *module)
+{
+ if (module == NULL) {
+ return;
+ }
+
+ module_reset(NULL, module, NULL);
+ conf_free_mod_id(module->id);
+ free(module);
+}
+
+void query_module_reset(conf_t *conf, knotd_mod_t *module, struct query_plan *new_plan)
+{
+ if (module == NULL) {
+ return;
+ }
+
+ module_reset(conf, module, new_plan);
+}
+
+_public_
+void *knotd_mod_ctx(knotd_mod_t *mod)
+{
+ return (mod != NULL) ? mod->ctx : NULL;
+}
+
+_public_
+void knotd_mod_ctx_set(knotd_mod_t *mod, void *ctx)
+{
+ if (mod != NULL) mod->ctx = ctx;
+}
+
+_public_
+const knot_dname_t *knotd_mod_zone(knotd_mod_t *mod)
+{
+ return (mod != NULL) ? mod->zone : NULL;
+}
+
+_public_
+void knotd_mod_log(knotd_mod_t *mod, int priority, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ knotd_mod_vlog(mod, priority, fmt, args);
+ va_end(args);
+}
+
+_public_
+void knotd_mod_vlog(knotd_mod_t *mod, int priority, const char *fmt, va_list args)
+{
+ if (mod == NULL || fmt == NULL) {
+ return;
+ }
+
+ char msg[512];
+
+ if (vsnprintf(msg, sizeof(msg), fmt, args) < 0) {
+ msg[0] = '\0';
+ }
+
+ #define LOG_ARGS(mod_id, msg) "module '%s%s%.*s', %s", \
+ mod_id->name + 1, (mod_id->len > 0) ? "/" : "", (int)mod_id->len, \
+ mod_id->data, msg
+
+ if (mod->zone == NULL) {
+ log_fmt(priority, LOG_SOURCE_SERVER, LOG_ARGS(mod->id, msg));
+ } else {
+ log_fmt_zone(priority, LOG_SOURCE_ZONE, mod->zone, NULL,
+ LOG_ARGS(mod->id, msg));
+ }
+
+ #undef LOG_ARGS
+}
+
+_public_
+int knotd_mod_stats_add(knotd_mod_t *mod, const char *ctr_name, uint32_t idx_count,
+ knotd_mod_idx_to_str_f idx_to_str)
+{
+ if (mod == NULL || idx_count == 0) {
+ return KNOT_EINVAL;
+ }
+
+ unsigned threads = knotd_mod_threads(mod);
+
+ mod_ctr_t *stats = NULL;
+ uint32_t offset = 0;
+ if (mod->stats_info == NULL) {
+ assert(mod->stats_count == 0);
+ stats = malloc(sizeof(*stats));
+ if (stats == NULL) {
+ return KNOT_ENOMEM;
+ }
+ mod->stats_info = stats;
+
+ assert(mod->stats_vals == NULL);
+ mod->stats_vals = calloc(threads, sizeof(*mod->stats_vals));
+ if (mod->stats_vals == NULL) {
+ knotd_mod_stats_free(mod);
+ return KNOT_ENOMEM;
+ }
+
+ for (unsigned i = 0; i < threads; i++) {
+ mod->stats_vals[i] = calloc(idx_count, sizeof(**mod->stats_vals));
+ if (mod->stats_vals[i] == NULL) {
+ knotd_mod_stats_free(mod);
+ return KNOT_ENOMEM;
+ }
+ }
+ } else {
+ for (uint32_t i = 0; i < mod->stats_count; i++) {
+ offset += mod->stats_info[i].count;
+ }
+ assert(offset == mod->stats_info[mod->stats_count - 1].offset +
+ mod->stats_info[mod->stats_count - 1].count);
+
+ assert(mod->stats_count > 0);
+ size_t old_size = mod->stats_count * sizeof(*stats);
+ size_t new_size = old_size + sizeof(*stats);
+ stats = realloc(mod->stats_info, new_size);
+ if (stats == NULL) {
+ knotd_mod_stats_free(mod);
+ return KNOT_ENOMEM;
+ }
+ mod->stats_info = stats;
+ stats += mod->stats_count;
+
+ for (unsigned i = 0; i < threads; i++) {
+ uint64_t *new_vals = realloc(mod->stats_vals[i],
+ (offset + idx_count) * sizeof(*new_vals));
+ if (new_vals == NULL) {
+ knotd_mod_stats_free(mod);
+ return KNOT_ENOMEM;
+ }
+ mod->stats_vals[i] = new_vals;
+ new_vals += offset;
+ for (uint32_t j = 0; j < idx_count; j++) {
+ *new_vals++ = 0;
+ }
+ }
+ }
+
+ stats->name = ctr_name;
+ stats->count = idx_count;
+ stats->idx_to_str = idx_to_str;
+ stats->offset = offset;
+
+ mod->stats_count++;
+
+ return KNOT_EOK;
+}
+
+_public_
+void knotd_mod_stats_free(knotd_mod_t *mod)
+{
+ if (mod == NULL || mod->stats_info == NULL) {
+ return;
+ }
+
+ if (mod->stats_vals != NULL) {
+ unsigned threads = knotd_mod_threads(mod);
+ for (unsigned i = 0; i < threads; i++) {
+ free(mod->stats_vals[i]);
+ }
+ }
+
+ free(mod->stats_vals);
+ free(mod->stats_info);
+}
+
+#define STATS_BODY(OPERATION) { \
+ if (mod == NULL) return; \
+ \
+ mod_ctr_t *ctr = mod->stats_info + ctr_id; \
+ assert(idx < ctr->count); \
+ OPERATION(mod->stats_vals[thr_id][ctr->offset + idx], val); \
+}
+
+_public_
+void knotd_mod_stats_incr(knotd_mod_t *mod, unsigned thr_id, uint32_t ctr_id,
+ uint32_t idx, uint64_t val)
+{
+ STATS_BODY(ATOMIC_ADD)
+}
+
+_public_
+void knotd_mod_stats_decr(knotd_mod_t *mod, unsigned thr_id, uint32_t ctr_id,
+ uint32_t idx, uint64_t val)
+{
+ STATS_BODY(ATOMIC_SUB)
+}
+
+_public_
+void knotd_mod_stats_store(knotd_mod_t *mod, unsigned thr_id, uint32_t ctr_id,
+ uint32_t idx, uint64_t val)
+{
+ STATS_BODY(ATOMIC_SET)
+}
+
+_public_
+knotd_conf_t knotd_conf_env(knotd_mod_t *mod, knotd_conf_env_t env)
+{
+ static const char *version = "Knot DNS " PACKAGE_VERSION;
+
+ knotd_conf_t out = { { 0 } };
+
+ if (mod == NULL) {
+ return out;
+ }
+
+ conf_t *config = (mod->config != NULL) ? mod->config : conf();
+
+ switch (env) {
+ case KNOTD_CONF_ENV_VERSION:
+ out.single.string = version;
+ break;
+ case KNOTD_CONF_ENV_HOSTNAME:
+ out.single.string = config->hostname;
+ break;
+ case KNOTD_CONF_ENV_WORKERS_UDP:
+ out.single.integer = config->cache.srv_udp_threads;
+ break;
+ case KNOTD_CONF_ENV_WORKERS_TCP:
+ out.single.integer = config->cache.srv_tcp_threads;
+ break;
+ case KNOTD_CONF_ENV_WORKERS_XDP:
+ out.single.integer = config->cache.srv_xdp_threads;
+ break;
+ default:
+ return out;
+ }
+
+ out.count = 1;
+
+ return out;
+}
+
+_public_
+unsigned knotd_mod_threads(knotd_mod_t *mod)
+{
+ knotd_conf_t udp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_UDP);
+ knotd_conf_t xdp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_XDP);
+ knotd_conf_t tcp = knotd_conf_env(mod, KNOTD_CONF_ENV_WORKERS_TCP);
+ return udp.single.integer + xdp.single.integer + tcp.single.integer;
+}
+
+static void set_val(yp_type_t type, knotd_conf_val_t *item, conf_val_t *val)
+{
+ switch (type) {
+ case YP_TINT:
+ item->integer = conf_int(val);
+ break;
+ case YP_TBOOL:
+ item->boolean = conf_bool(val);
+ break;
+ case YP_TOPT:
+ item->option = conf_opt(val);
+ break;
+ case YP_TSTR:
+ item->string = conf_str(val);
+ break;
+ case YP_TDNAME:
+ item->dname = conf_dname(val);
+ break;
+ case YP_TADDR:
+ item->addr = conf_addr(val, NULL);
+ break;
+ case YP_TNET:
+ item->addr = conf_addr_range(val, &item->addr_max,
+ &item->addr_mask);
+ break;
+ case YP_TREF:
+ if (val->code == KNOT_EOK) {
+ conf_val(val);
+ item->data_len = val->len;
+ item->data = val->data;
+ }
+ break;
+ case YP_THEX:
+ case YP_TB64:
+ item->data = conf_bin(val, &item->data_len);
+ break;
+ case YP_TDATA:
+ item->data = conf_data(val, &item->data_len);
+ break;
+ default:
+ return;
+ }
+}
+
+static void set_conf_out(knotd_conf_t *out, conf_val_t *val)
+{
+ if (!(val->item->flags & YP_FMULTI)) {
+ out->count = (val->code == KNOT_EOK) ? 1 : 0;
+ set_val(val->item->type, &out->single, val);
+ } else {
+ size_t count = conf_val_count(val);
+ if (count == 0) {
+ return;
+ }
+
+ out->multi = malloc(count * sizeof(*out->multi));
+ if (out->multi == NULL) {
+ return;
+ }
+ memset(out->multi, 0, count * sizeof(*out->multi));
+
+ for (size_t i = 0; i < count; i++) {
+ set_val(val->item->type, &out->multi[i], val);
+ conf_val_next(val);
+ }
+ out->count = count;
+ }
+}
+
+_public_
+knotd_conf_t knotd_conf(knotd_mod_t *mod, const yp_name_t *section_name,
+ const yp_name_t *item_name, const knotd_conf_t *id)
+{
+ knotd_conf_t out = { { 0 } };
+
+ if (mod == NULL || section_name == NULL || item_name == NULL) {
+ return out;
+ }
+
+ conf_t *config = (mod->config != NULL) ? mod->config : conf();
+
+ conf_val_t val;
+ if (id != NULL) {
+ val = conf_rawid_get(config, section_name, item_name,
+ id->single.data, id->single.data_len);
+ } else {
+ val = conf_get(config, section_name, item_name);
+ }
+
+ set_conf_out(&out, &val);
+
+ return out;
+}
+
+_public_
+knotd_conf_t knotd_conf_mod(knotd_mod_t *mod, const yp_name_t *item_name)
+{
+ knotd_conf_t out = { { 0 } };
+
+ if (mod == NULL || item_name == NULL) {
+ return out;
+ }
+
+ conf_t *config = (mod->config != NULL) ? mod->config : conf();
+
+ conf_val_t val = conf_mod_get(config, item_name, mod->id);
+ if (val.item == NULL) {
+ return out;
+ }
+
+ set_conf_out(&out, &val);
+
+ return out;
+}
+
+_public_
+knotd_conf_t knotd_conf_zone(knotd_mod_t *mod, const yp_name_t *item_name,
+ const knot_dname_t *zone)
+{
+ knotd_conf_t out = { { 0 } };
+
+ if (mod == NULL || item_name == NULL || zone == NULL) {
+ return out;
+ }
+
+ conf_t *config = (mod->config != NULL) ? mod->config : conf();
+
+ conf_val_t val = conf_zone_get(config, item_name, zone);
+
+ set_conf_out(&out, &val);
+
+ return out;
+}
+
+_public_
+knotd_conf_t knotd_conf_check_item(knotd_conf_check_args_t *args,
+ const yp_name_t *item_name)
+{
+ knotd_conf_t out = { { 0 } };
+
+ conf_val_t val = conf_rawid_get_txn(args->extra->conf, args->extra->txn,
+ args->item->name, item_name,
+ args->id, args->id_len);
+
+ set_conf_out(&out, &val);
+
+ return out;
+}
+
+_public_
+bool knotd_conf_addr_range_match(const knotd_conf_t *range,
+ const struct sockaddr_storage *addr)
+{
+ if (range == NULL || addr == NULL) {
+ return false;
+ }
+
+ for (size_t i = 0; i < range->count; i++) {
+ knotd_conf_val_t *val = &range->multi[i];
+ if (val->addr_max.ss_family == AF_UNSPEC) {
+ if (sockaddr_net_match(addr, &val->addr, val->addr_mask)) {
+ return true;
+ }
+ } else {
+ if (sockaddr_range_match(addr, &val->addr, &val->addr_max)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+_public_
+void knotd_conf_free(knotd_conf_t *conf)
+{
+ if (conf == NULL) {
+ return;
+ }
+
+ if (conf->count > 0 && conf->multi != NULL) {
+ memset(conf->multi, 0, conf->count * sizeof(*conf->multi));
+ free(conf->multi);
+ }
+ memset(conf, 0, sizeof(*conf));
+}
+
+_public_
+const struct sockaddr_storage *knotd_qdata_local_addr(knotd_qdata_t *qdata,
+ struct sockaddr_storage *buff)
+{
+ if (qdata == NULL) {
+ return NULL;
+ }
+
+ if (qdata->params->xdp_msg != NULL) {
+#ifdef ENABLE_XDP
+ return (struct sockaddr_storage *)&qdata->params->xdp_msg->ip_to;
+#else
+ assert(0);
+ return NULL;
+#endif
+ } else {
+ socklen_t buff_len = sizeof(*buff);
+ if (getsockname(qdata->params->socket, (struct sockaddr *)buff,
+ &buff_len) != 0) {
+ return NULL;
+ }
+ return buff;
+ }
+}
+
+_public_
+const struct sockaddr_storage *knotd_qdata_remote_addr(knotd_qdata_t *qdata)
+{
+ if (qdata == NULL) {
+ return NULL;
+ }
+
+ if (qdata->params->xdp_msg != NULL) {
+#ifdef ENABLE_XDP
+ return (struct sockaddr_storage *)&qdata->params->xdp_msg->ip_from;
+#else
+ assert(0);
+ return NULL;
+#endif
+ } else {
+ return qdata->params->remote;
+ }
+}
+
+_public_
+uint32_t knotd_qdata_rtt(knotd_qdata_t *qdata)
+{
+ if (qdata == NULL) {
+ return 0;
+ }
+
+ switch (qdata->params->proto) {
+ case KNOTD_QUERY_PROTO_TCP:
+ if (qdata->params->xdp_msg != NULL) {
+#ifdef ENABLE_XDP
+ return qdata->params->measured_rtt;
+#else
+ assert(0);
+ return 0;
+#endif
+ } else {
+ return knot_probe_tcp_rtt(qdata->params->socket);
+ }
+ case KNOTD_QUERY_PROTO_QUIC:
+ return qdata->params->measured_rtt;
+ case KNOTD_QUERY_PROTO_UDP:
+ default:
+ return 0;
+ }
+}
+
+_public_
+const knot_dname_t *knotd_qdata_zone_name(knotd_qdata_t *qdata)
+{
+ if (qdata == NULL || qdata->extra->zone == NULL) {
+ return NULL;
+ }
+
+ return qdata->extra->zone->name;
+}
+
+_public_
+knot_rrset_t knotd_qdata_zone_apex_rrset(knotd_qdata_t *qdata, uint16_t type)
+{
+ if (qdata == NULL || qdata->extra->contents == NULL) {
+ return node_rrset(NULL, type);
+ }
+
+ return node_rrset(qdata->extra->contents->apex, type);
+}
+
+_public_
+int knotd_mod_dnssec_init(knotd_mod_t *mod)
+{
+ if (mod == NULL || mod->dnssec != NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_lmdb_db_t *kaspdb = &mod->server->kaspdb;
+ kasp_db_ensure_init(kaspdb, mod->config); // probably redundant
+
+ mod->dnssec = calloc(1, sizeof(*(mod->dnssec)));
+ if (mod->dnssec == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ conf_val_t conf = conf_zone_get(mod->config, C_DNSSEC_SIGNING, mod->zone);
+ int ret = kdnssec_ctx_init(mod->config, mod->dnssec, mod->zone, kaspdb,
+ conf_bool(&conf) ? NULL : mod->id);
+ if (ret != KNOT_EOK) {
+ free(mod->dnssec);
+ mod->dnssec = NULL;
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+int knotd_mod_dnssec_load_keyset(knotd_mod_t *mod, bool verbose)
+{
+ if (mod == NULL || mod->dnssec == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ mod->keyset = calloc(1, sizeof(*(mod->keyset)));
+ if (mod->keyset == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ int ret = load_zone_keys(mod->dnssec, mod->keyset, verbose);
+ if (ret != KNOT_EOK) {
+ free(mod->keyset);
+ mod->keyset = NULL;
+ return ret;
+ }
+
+ mod->sign_ctx = zone_sign_ctx(mod->keyset, mod->dnssec);
+ if (mod->sign_ctx == NULL) {
+ free_zone_keys(mod->keyset);
+ free(mod->keyset);
+ mod->keyset = NULL;
+ return KNOT_ENOMEM;
+ }
+
+ return KNOT_EOK;
+}
+
+_public_
+void knotd_mod_dnssec_unload_keyset(knotd_mod_t *mod)
+{
+ if (mod != NULL && mod->keyset != NULL) {
+ zone_sign_ctx_free(mod->sign_ctx);
+ mod->sign_ctx = NULL;
+
+ free_zone_keys(mod->keyset);
+ free(mod->keyset);
+ mod->keyset = NULL;
+ }
+}
+
+_public_
+int knotd_mod_dnssec_sign_rrset(knotd_mod_t *mod, knot_rrset_t *rrsigs,
+ const knot_rrset_t *rrset, knot_mm_t *mm)
+{
+ if (mod == NULL || rrsigs == NULL || rrset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ return knot_sign_rrset2(rrsigs, rrset, mod->sign_ctx, mm);
+}