]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
modules/nsid: new module for +NSID (server-side)
authorPetr Špaček <petr.spacek@nic.cz>
Thu, 25 Oct 2018 14:08:54 +0000 (16:08 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 13 Nov 2018 11:50:58 +0000 (12:50 +0100)
Minor changes to be blamed on Vladimir.

NEWS
doc/modules.rst
modules/modules.mk
modules/nsid/README.rst [new file with mode: 0644]
modules/nsid/nsid.c [new file with mode: 0644]
modules/nsid/nsid.mk [new file with mode: 0644]
modules/nsid/nsid.test.lua [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index b2e9b342f2715b990293092f9403a6e55d7cae21..0a2e8de5faee6f702fca12dae582cf7542675bba 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ Knot Resolver 3.x.y (201y-mm-dd)
 New features
 ------------
 - module edns_keepalive to implement server side of RFC 7828 (#408)
+- module nsid to implement server side of RFC 5001 (#289)
 
 Module API changes
 ------------------
index cb350b33675eefe248273c0160e0fee3c7e65af9..6a9aa349b5759119855c6b0e220dc86e3d6488d9 100644 (file)
@@ -22,6 +22,7 @@ Knot Resolver modules
 .. include:: ../modules/renumber/README.rst
 .. .. include:: ../modules/cookies/README.rst
 .. include:: ../modules/bogus_log/README.rst
+.. include:: ../modules/nsid/README.rst
 .. include:: ../modules/workarounds/README.rst
 .. include:: ../modules/dnstap/README.rst
 .. include:: ../modules/ta_signal_query/README.rst
index 328c8564f7a7d33293c701fa37f58297196d05d3..c14baf4eedfc1d369c365e469525b3ea469d6886 100644 (file)
@@ -14,6 +14,7 @@ endif
 # List of Lua modules
 ifeq ($(HAS_lua),yes)
 modules_TARGETS += bogus_log \
+                  nsid \
                   etcd \
                    ta_sentinel \
                    graphite \
diff --git a/modules/nsid/README.rst b/modules/nsid/README.rst
new file mode 100644 (file)
index 0000000..ed052c9
--- /dev/null
@@ -0,0 +1,35 @@
+.. _mod-nsid:
+
+Name Server Identifier (NSID)
+-----------------------------
+
+This module provides server-side support for :rfc:`5001`
+and is not enabled by default.
+
+DNS clients can request resolver to send back its NSID along with the reply
+to a DNS request.  This is useful for identification of resolver instances
+in larger services (using anycast or load balancers).
+
+
+This is useful tool for debugging larger services,
+as it reveals which particular resolver instance sent the reply.
+
+NSID value can be configured in the resolver's configuration file:
+
+.. code-block:: lua
+
+   modules.load('nsid')
+   nsid.name('instance 1')
+
+You can also obtain configured NSID value:
+
+.. code-block:: lua
+
+   nsid.name()
+   instance 1
+
+The module can be disabled at run-time:
+
+.. code-block:: lua
+
+   modules.unload('nsid')
diff --git a/modules/nsid/nsid.c b/modules/nsid/nsid.c
new file mode 100644 (file)
index 0000000..7db7eee
--- /dev/null
@@ -0,0 +1,122 @@
+/* Copyright (C) Knot Resolver contributors. Licensed under GNU GPLv3 or
+ * (at your option) any later version. See COPYING for text of the license.
+ *
+ * This module provides NSID support according to RFC 5001. */
+
+#include <libknot/packet/pkt.h>
+#include <contrib/cleanup.h>
+#include <ccan/json/json.h>
+#include <lauxlib.h>
+
+#include "daemon/engine.h"
+#include "lib/layer.h"
+
+struct nsid_config {
+       uint8_t *local_nsid;
+       size_t local_nsid_len;
+};
+
+static int nsid_finalize(kr_layer_t *ctx) {
+       const struct kr_module *module = ctx->api->data;
+       const struct nsid_config *config = module->data;
+       struct kr_request *req = ctx->req;
+
+       /* no local NSID configured, do nothing */
+       if (config->local_nsid == NULL)
+               return ctx->state;
+
+       const knot_rrset_t *src_opt = req->qsource.packet->opt_rr;
+       /* no EDNS in request, do nothing */
+       if (src_opt == NULL)
+               return ctx->state;
+
+       const uint8_t *req_nsid = knot_edns_get_option(src_opt, KNOT_EDNS_OPTION_NSID);
+       /* NSID option must be explicitly requested */
+       if (req_nsid == NULL)
+               return ctx->state;
+
+       /* Check violation of https://tools.ietf.org/html/rfc5001#section-2.1:
+        * The resolver MUST NOT include any NSID payload data in the query */
+       if (knot_edns_opt_get_length(req_nsid) != 0)
+               kr_log_verbose("[%05u.  ][nsid] FORMERR: NSID option in query "
+                              "must not contain payload, continuing\n", req->uid);
+               /* FIXME: actually change RCODE in answer to FORMERR? */
+
+       /* Sanity check, answer should have EDNS as well but who knows ... */
+       if (req->answer->opt_rr == NULL)
+               return ctx->state;
+
+       if (knot_edns_add_option(req->answer->opt_rr, KNOT_EDNS_OPTION_NSID,
+                                config->local_nsid_len, config->local_nsid,
+                                &req->pool) != KNOT_EOK) {
+               /* something went wrong and there is no way to salvage content of OPT RRset */
+               kr_log_verbose("[%05u.  ][nsid] unable to add NSID option\n", req->uid);
+               knot_rrset_clear(req->answer->opt_rr, &req->pool);
+       }
+
+       return ctx->state;
+}
+
+KR_EXPORT
+const kr_layer_api_t *nsid_layer(struct kr_module *module)
+{
+       static kr_layer_api_t _layer = {
+               .answer_finalize = &nsid_finalize,
+       };
+       _layer.data = module;
+       return &_layer;
+}
+
+KR_EXPORT
+int nsid_init(struct kr_module *module) {
+       struct nsid_config *config = calloc(1, sizeof(struct nsid_config));
+       if (config == NULL)
+               return kr_error(ENOMEM);
+
+       module->data = config;
+       return kr_ok();
+}
+
+static char* nsid_name(void *env, struct kr_module *module, const char *args)
+{
+       struct engine *engine = env;
+       struct nsid_config *config = module->data;
+       if (args) {  /* set */
+               /* API is not binary safe, we need to fix this one day */
+               uint8_t *arg_copy = (uint8_t *)strdup(args);
+               if (arg_copy == NULL)
+                       luaL_error(engine->L, "[nsid] error while allocating new NSID value\n");
+               free(config->local_nsid);
+               config->local_nsid = arg_copy;
+               config->local_nsid_len = strlen(args);
+       }
+
+       /* get */
+       if (config->local_nsid != NULL)
+               return json_encode_string((char *)config->local_nsid);
+       else
+               return NULL;
+}
+
+KR_EXPORT
+struct kr_prop *nsid_props(void)
+{
+       static struct kr_prop prop_list[] = {
+           { &nsid_name, "name", "Get or set local NSID value" },
+           { NULL, NULL, NULL }
+       };
+       return prop_list;
+}
+
+KR_EXPORT
+int nsid_deinit(struct kr_module *module) {
+       struct nsid_config *config = module->data;
+       if (config != NULL) {
+               free(config->local_nsid);
+               free(config);
+               module->data = NULL;
+       }
+       return kr_ok();
+}
+
+KR_MODULE_EXPORT(nsid);
diff --git a/modules/nsid/nsid.mk b/modules/nsid/nsid.mk
new file mode 100644 (file)
index 0000000..aa7d16c
--- /dev/null
@@ -0,0 +1,5 @@
+nsid_CFLAGS := -fPIC
+nsid_SOURCES := modules/nsid/nsid.c
+nsid_DEPEND := $(libkres)
+nsid_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS)
+$(call make_c_module,nsid)
diff --git a/modules/nsid/nsid.test.lua b/modules/nsid/nsid.test.lua
new file mode 100644 (file)
index 0000000..ce178f8
--- /dev/null
@@ -0,0 +1,21 @@
+-- disable networking so we can get SERVFAIL immediatelly
+net.ipv4 = false
+net.ipv6 = false
+
+-- test for nsid.name() interface
+local function test_nsid_name()
+       if nsid then
+               modules.unload('nsid')
+       end
+       modules.load('nsid')
+       same(nsid.name(), nil, 'NSID modes not provide default NSID value')
+       same(nsid.name('123456'), '123456', 'NSID value can be changed')
+       same(nsid.name(), '123456', 'NSID module remembers configured NSID value')
+       modules.unload('nsid')
+       modules.load('nsid')
+       same(nsid.name(), nil, 'NSID module reload removes configured value')
+end
+
+return {
+       test_nsid_name,
+}