From 2f81b111843005d12e1c7a50d4cfe5b22498c710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@sury.org> Date: Tue, 23 May 2017 17:23:14 +0200 Subject: [PATCH 1/7] Make the moduledir configurable at the runtime --- daemon/engine.c | 85 +++++++++++++++++++++++++++++++++++++++---------- daemon/engine.h | 5 +++ daemon/main.c | 28 ++++++++++------ lib/module.c | 8 ++--- 4 files changed, 94 insertions(+), 32 deletions(-) diff --git a/daemon/engine.c b/daemon/engine.c index 520cd3cd3..f6a6513a2 100644 --- a/daemon/engine.c +++ b/daemon/engine.c @@ -21,6 +21,7 @@ #include <unistd.h> #include <grp.h> #include <pwd.h> +#include <sys/param.h> #include <zscanner/scanner.h> #include "daemon/engine.h" @@ -43,6 +44,13 @@ KR_NORETURN int lua_error (lua_State *L); /* Cleanup engine state every 5 minutes */ const size_t CLEANUP_TIMER = 5*60*1000; +/* Execute byte code */ +#define l_dobytecode(L, arr, len, name) \ + (luaL_loadbuffer((L), (arr), (len), (name)) || lua_pcall((L), 0, LUA_MULTRET, 0)) +/** Load file in a sandbox environment. */ +#define l_dosandboxfile(L, filename) \ + (luaL_loadfile((L), (filename)) || engine_pcall((L), 0)) + /* * Global bindings. */ @@ -201,6 +209,63 @@ static int l_hostname(lua_State *L) return 1; } +char *engine_get_moduledir(struct engine *engine) { + return engine->moduledir; +} + +int engine_set_moduledir(struct engine *engine, const char *moduledir) { + if (!engine || !moduledir) { + return kr_error(EINVAL); + } + + char *new_moduledir = strdup(moduledir); + if (!new_moduledir) { + return kr_error(ENOMEM); + } + if (engine->moduledir) { + free(engine->moduledir); + } + engine->moduledir = new_moduledir; + + /* Use module path for including Lua scripts */ + char l_paths[MAXPATHLEN] = { 0 }; + /* Save original package.path to package._path */ + snprintf(l_paths, MAXPATHLEN - 1, + "if package._path == nil then package._path = package.path end\n" + "package.path = '%s/?.lua;%s/?/init.lua;'..package._path\n", + new_moduledir, + new_moduledir); + + int ret = l_dobytecode(engine->L, l_paths, strlen(l_paths), ""); + if (ret != 0) { + lua_pop(engine->L, 1); + return ret; + } + return 0; +} + +/** Return hostname. */ +static int l_moduledir(lua_State *L) +{ + struct engine *engine = engine_luaget(L); + if (lua_gettop(L) == 0) { + lua_pushstring(L, engine_get_moduledir(engine)); + return 1; + } + if ((lua_gettop(L) != 1) || !lua_isstring(L, 1)) { + lua_pushstring(L, "moduledir takes at most one parameter: (\"directory\")"); + lua_error(L); + } + + if (engine_set_moduledir(engine, lua_tostring(L, 1)) != 0) { + lua_pushstring(L, "setting moduledir failed"); + lua_error(L); + } + + lua_pushstring(L, engine_get_moduledir(engine)); + return 1; +} + /** Get/set context option. */ static int l_option(lua_State *L) { @@ -532,6 +597,8 @@ static int init_state(struct engine *engine) lua_setglobal(engine->L, "quit"); lua_pushcfunction(engine->L, l_hostname); lua_setglobal(engine->L, "hostname"); + lua_pushcfunction(engine->L, l_moduledir); + lua_setglobal(engine->L, "moduledir"); lua_pushcfunction(engine->L, l_verbose); lua_setglobal(engine->L, "verbose"); lua_pushcfunction(engine->L, l_option); @@ -548,8 +615,6 @@ static int init_state(struct engine *engine) lua_setglobal(engine->L, "tojson"); lua_pushcfunction(engine->L, l_map); lua_setglobal(engine->L, "map"); - lua_pushliteral(engine->L, MODULEDIR); - lua_setglobal(engine->L, "moduledir"); lua_pushlightuserdata(engine->L, engine); lua_setglobal(engine->L, "__engine"); return kr_ok(); @@ -685,21 +750,9 @@ int engine_ipc(struct engine *engine, const char *expr) } } -/* Execute byte code */ -#define l_dobytecode(L, arr, len, name) \ - (luaL_loadbuffer((L), (arr), (len), (name)) || lua_pcall((L), 0, LUA_MULTRET, 0)) -/** Load file in a sandbox environment. */ -#define l_dosandboxfile(L, filename) \ - (luaL_loadfile((L), (filename)) || engine_pcall((L), 0)) - static int engine_loadconf(struct engine *engine, const char *config_path) { - /* Use module path for including Lua scripts */ - static const char l_paths[] = "package.path = '" MODULEDIR "/?.lua;'..package.path"; - int ret = l_dobytecode(engine->L, l_paths, sizeof(l_paths) - 1, ""); - if (ret != 0) { - lua_pop(engine->L, 1); - } + int ret = 0; /* Init environment */ static const char sandbox_bytecode[] = { #include "daemon/lua/sandbox.inc" @@ -836,7 +889,7 @@ int engine_register(struct engine *engine, const char *name, const char *precede return kr_error(ENOMEM); } module->data = engine; - int ret = kr_module_load(module, name, NULL); + int ret = kr_module_load(module, name, engine->moduledir); /* Load Lua module if not a binary */ if (ret == kr_error(ENOENT)) { ret = ffimodule_register_lua(engine, module, name); diff --git a/daemon/engine.h b/daemon/engine.h index 409e40982..a4f6ab5f4 100644 --- a/daemon/engine.h +++ b/daemon/engine.h @@ -61,6 +61,7 @@ struct engine { uv_timer_t *updater; char *hostname; struct lua_State *L; + char *moduledir; }; int engine_init(struct engine *engine, knot_mm_t *pool); @@ -89,3 +90,7 @@ struct engine *engine_luaget(struct lua_State *L); /** Set/get the per engine hostname */ char *engine_get_hostname(struct engine *engine); int engine_set_hostname(struct engine *engine, const char *hostname); + +/** Set/get the per engine moduledir */ +char *engine_get_moduledir(struct engine *engine); +int engine_set_moduledir(struct engine *engine, const char *moduledir); diff --git a/daemon/main.c b/daemon/main.c index 2ebbf6ad4..6de5e5cd3 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -341,15 +341,16 @@ static void help(int argc, char *argv[]) { printf("Usage: %s [parameters] [rundir]\n", argv[0]); printf("\nParameters:\n" - " -a, --addr=[addr] Server address (default: localhost@53).\n" - " -t, --tls=[addr] Server address for TLS (default: off).\n" - " -S, --fd=[fd] Listen on given fd (handed out by supervisor).\n" - " -T, --tlsfd=[fd] Listen using TLS on given fd (handed out by supervisor).\n" - " -c, --config=[path] Config file path (relative to [rundir]) (default: config).\n" - " -k, --keyfile=[path] File containing trust anchors (DS or DNSKEY).\n" - " -f, --forks=N Start N forks sharing the configuration.\n" - " -q, --quiet Quiet output, no prompt in interactive mode.\n" - " -v, --verbose Run in verbose mode." + " -a, --addr=[addr] Server address (default: localhost@53).\n" + " -t, --tls=[addr] Server address for TLS (default: off).\n" + " -S, --fd=[fd] Listen on given fd (handed out by supervisor).\n" + " -T, --tlsfd=[fd] Listen using TLS on given fd (handed out by supervisor).\n" + " -c, --config=[path] Config file path (relative to [rundir]) (default: config).\n" + " -k, --keyfile=[path] File containing trust anchors (DS or DNSKEY).\n" + " -m, --moduledir=[path] Override the default module path (" MODULEDIR ").\n" + " -f, --forks=N Start N forks sharing the configuration.\n" + " -q, --quiet Quiet output, no prompt in interactive mode.\n" + " -v, --verbose Run in verbose mode." #ifdef NOVERBOSELOG " (Recompile without -DNOVERBOSELOG to activate.)" #endif @@ -433,6 +434,7 @@ int main(int argc, char **argv) array_t(int) tls_fd_set; array_init(tls_fd_set); char *keyfile = NULL; + char *moduledir = MODULEDIR; const char *config = NULL; int control_fd = -1; @@ -446,13 +448,14 @@ int main(int argc, char **argv) {"config", required_argument, 0, 'c'}, {"keyfile",required_argument, 0, 'k'}, {"forks",required_argument, 0, 'f'}, + {"moduledir", required_argument, 0, 'm'}, {"verbose", no_argument, 0, 'v'}, {"quiet", no_argument, 0, 'q'}, {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; - while ((c = getopt_long(argc, argv, "a:t:S:T:c:f:k:vqVh", opts, &li)) != -1) { + while ((c = getopt_long(argc, argv, "a:t:S:T:c:f:m:k:vqVh", opts, &li)) != -1) { switch (c) { case 'a': @@ -482,6 +485,9 @@ int main(int argc, char **argv) case 'k': keyfile = optarg; break; + case 'm': + moduledir = optarg; + break; case 'v': kr_verbose_set(true); #ifdef NOVERBOSELOG @@ -636,6 +642,8 @@ int main(int argc, char **argv) goto cleanup; } + engine_set_moduledir(&engine, moduledir); + /* Block signals. */ uv_loop_t *loop = uv_default_loop(); uv_signal_t sigint, sigterm; diff --git a/lib/module.c b/lib/module.c index 6cd462365..cea899fe8 100644 --- a/lib/module.c +++ b/lib/module.c @@ -132,12 +132,8 @@ int kr_module_load(struct kr_module *module, const char *name, const char *path) /* Search for module library, use current namespace if not found. */ if (load_library(module, name, path) != 0) { - /* Expand HOME env variable, as the linker may not expand it. */ - auto_free char *local_path = kr_strcatdup(2, getenv("HOME"), "/.local/lib/kdns_modules"); - if (load_library(module, name, local_path) != 0) { - if (load_library(module, name, MODULEDIR) != 0) { - module->lib = RTLD_DEFAULT; - } + if (load_library(module, name, MODULEDIR) != 0) { + module->lib = RTLD_DEFAULT; } } -- GitLab From a5c4724d586517c1e69b79b77bdd963124cd67f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@sury.org> Date: Thu, 25 May 2017 12:23:59 +0200 Subject: [PATCH 2/7] Update the moduledir documentation --- daemon/README.rst | 10 +++++++++- doc/build.rst | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/daemon/README.rst b/daemon/README.rst index 26301b9fc..ba01fb864 100644 --- a/daemon/README.rst +++ b/daemon/README.rst @@ -380,7 +380,15 @@ Environment hostname. If called without a parameter, it will return kresd's internal hostname, or the system's POSIX hostname (see gethostname(2)) if kresd's internal hostname is unset. - + +.. function:: moduledir([dir]) + + :return: Modules directory. + + If called with a parameter, it will change kresd's directory for + looking up the dynamic modules. If called without a parameter, it + will return kresd's modules directory. + .. function:: verbose(true | false) :return: Toggle verbose logging. diff --git a/doc/build.rst b/doc/build.rst index 2b054b5dd..b27ddd7c9 100644 --- a/doc/build.rst +++ b/doc/build.rst @@ -175,11 +175,11 @@ All paths are prefixed with ``PREFIX`` variable by default if not specified othe "library", "``LIBDIR``", "``$(PREFIX)/lib``", "pkg-config is auto-generated [#]_" "daemon", "``SBINDIR``", "``$(PREFIX)/sbin``", "" "configuration", "``ETCDIR``", "``$(PREFIX)/etc/kresd``", "Configuration file, templates." - "modules", "``MODULEDIR``", "``$(LIBDIR)/kdns_modules``", "[#]_" + "modules", "``MODULEDIR``", "``$(LIBDIR)/kdns_modules``", "Runtime directory for loading dynamic modules [#]_." "work directory", "", "``$(PREFIX)/var/run/kresd``", "Run directory for daemon." .. [#] The ``libkres.pc`` is installed in ``$(LIBDIR)/pkgconfig``. -.. [#] Users may install additional modules in ``~/.local/lib/kdns_modules`` or in the rundir of a specific instance. +.. [#] The default moduledir can be changed with `-m` option to `kresd` daemon or by calling `moduledir()` function from lua. .. note:: Each module is self-contained and may install additional bundled files within ``$(MODULEDIR)/$(modulename)``. These files should be read-only, non-executable. -- GitLab From b3ae8bdfd4e01b057300bccbcaa1ec0f6444ece6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20=C4=8Cun=C3=A1t?= <vladimir.cunat@nic.cz> Date: Thu, 25 May 2017 17:23:50 +0200 Subject: [PATCH 3/7] engine: free hostname and moduledir (nitpick) --- daemon/engine.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/daemon/engine.c b/daemon/engine.c index f6a6513a2..08b02c647 100644 --- a/daemon/engine.c +++ b/daemon/engine.c @@ -708,6 +708,8 @@ void engine_deinit(struct engine *engine) array_clear(engine->ipc_set); kr_ta_clear(&engine->resolver.trust_anchors); kr_ta_clear(&engine->resolver.negative_anchors); + free(engine->hostname); + free(engine->moduledir); } int engine_pcall(lua_State *L, int argc) -- GitLab From 352da6ea3c0c03f852206feadfca56ed300787d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20=C4=8Cun=C3=A1t?= <vladimir.cunat@nic.cz> Date: Thu, 25 May 2017 17:30:24 +0200 Subject: [PATCH 4/7] module.c: cleanup unused code Searching the default library path for modules wasn't a good idea anyway. --- lib/module.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/module.c b/lib/module.c index cea899fe8..7d9c91c5b 100644 --- a/lib/module.c +++ b/lib/module.c @@ -54,13 +54,9 @@ static void *load_symbol(void *lib, const char *prefix, const char *name) static int load_library(struct kr_module *module, const char *name, const char *path) { + assert(module && name && path); /* Absolute or relative path (then only library search path is used). */ - auto_free char *lib_path = NULL; - if (path != NULL) { - lib_path = kr_strcatdup(4, path, "/", name, LIBEXT); - } else { - lib_path = kr_strcatdup(2, name, LIBEXT); - } + auto_free char *lib_path = kr_strcatdup(4, path, "/", name, LIBEXT); if (lib_path == NULL) { return kr_error(ENOMEM); } @@ -131,7 +127,7 @@ int kr_module_load(struct kr_module *module, const char *name, const char *path) } /* Search for module library, use current namespace if not found. */ - if (load_library(module, name, path) != 0) { + if (!path || load_library(module, name, path) != 0) { if (load_library(module, name, MODULEDIR) != 0) { module->lib = RTLD_DEFAULT; } -- GitLab From 9ad4f88d656ed96839389c268e1c8e5d568be500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20=C4=8Cun=C3=A1t?= <vladimir.cunat@nic.cz> Date: Thu, 25 May 2017 19:38:58 +0200 Subject: [PATCH 5/7] module.c: don't fall back to MODULEDIR if overridden --- lib/module.c | 6 ++---- lib/module.h | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/module.c b/lib/module.c index 7d9c91c5b..67b6aff15 100644 --- a/lib/module.c +++ b/lib/module.c @@ -126,11 +126,9 @@ int kr_module_load(struct kr_module *module, const char *name, const char *path) return kr_error(ENOMEM); } - /* Search for module library, use current namespace if not found. */ + /* Search for module library. */ if (!path || load_library(module, name, path) != 0) { - if (load_library(module, name, MODULEDIR) != 0) { - module->lib = RTLD_DEFAULT; - } + module->lib = RTLD_DEFAULT; } /* Try to load module ABI. */ diff --git a/lib/module.h b/lib/module.h index 92ab3a197..29afc9884 100644 --- a/lib/module.h +++ b/lib/module.h @@ -84,7 +84,7 @@ struct kr_prop { /** - * Load module instance into memory. + * Load a C module instance into memory. * * @param module module structure * @param name module name -- GitLab From e7baf329f9b175f3cef0116037419e72f93f8149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20=C4=8Cun=C3=A1t?= <vladimir.cunat@nic.cz> Date: Thu, 25 May 2017 18:31:14 +0200 Subject: [PATCH 6/7] NEWS: mention module changes --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index 4a146652b..86fe35980 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,8 @@ Improvements - policy: recognize 100.64.0.0/10 as local addresses - layer/iterate: *do* retry repeatedly if REFUSED, as we can't yet easily retry with other NSs while avoiding retrying with those who REFUSED +- modules: allow changing the directory where modules are found, + and do not search the default library path anymore. Knot Resolver 1.2.6 (2017-04-24) -- GitLab From f37f1ed862b5f2096dd4dfbcc5f6db29272f96e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20=C4=8Cun=C3=A1t?= <vladimir.cunat@nic.cz> Date: Fri, 26 May 2017 10:32:16 +0200 Subject: [PATCH 7/7] man page: do maintenance - add missing CLI options - keep consistent order of options (also with --help output) --- daemon/daemon.mk | 4 +++- doc/kresd.8.in | 21 +++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/daemon/daemon.mk b/daemon/daemon.mk index ac692f775..ed5a10288 100644 --- a/daemon/daemon.mk +++ b/daemon/daemon.mk @@ -51,7 +51,9 @@ date := $(shell date +%F -r NEWS) daemon: $(kresd) $(kresd_DIST) daemon-install: kresd-install bindings-install ifneq ($(SED),) - $(SED) -e "s/@VERSION@/$(VERSION)/" -e "s/@DATE@/$(date)/" doc/kresd.8.in > doc/kresd.8 + $(SED) -e "s/@VERSION@/$(VERSION)/" -e "s/@DATE@/$(date)/" \ + -e "s|@MODULEDIR@|$(MODULEDIR)|" \ + doc/kresd.8.in > doc/kresd.8 $(INSTALL) -d -m 0755 $(DESTDIR)$(MANDIR)/man8/ $(INSTALL) -m 0644 doc/kresd.8 $(DESTDIR)$(MANDIR)/man8/ endif diff --git a/doc/kresd.8.in b/doc/kresd.8.in index a54a26232..a1be6e24e 100644 --- a/doc/kresd.8.in +++ b/doc/kresd.8.in @@ -14,12 +14,18 @@ .B kresd .RB [ \-a | \-\-addr .IR addr[@port] ] +.RB [ \-t | \-\-tls +.IR addr[@port] ] .RB [ \-S | \-\-fd .IR fd ] +.RB [ \-T | \-\-tlsfd +.IR fd ] .RB [ \-c | \-\-config .IR config ] .RB [ \-k | \-\-keyfile .IR keyfile ] +.RB [ \-m | \-\-moduledir +.IR path ] .RB [ \-f | \-\-forks .IR N ] .RB [ \-q | \-\-quiet ] @@ -109,12 +115,20 @@ Option may be passed multiple times to listen on more file descriptors. Listen using TLS on given file descriptor(s), passed by supervisor. Option may be passed multiple times to listen on more file descriptors. .TP +.B \-c\fI config\fR, \fB\-\-config=\fI<config> +Set the config file with settings for kresd to read instead of reading the +file at the default location (\fIconfig\fR). The syntax is +described in \fIdaemon/README.md\fR. +.TP .B \-k\fI keyfile\fR, \fB\-\-keyfile=\fI<keyfile> Use given for keeping root trust anchors. If the file doesn't exist, it will be automatically boostrapped from IANA and warning for you will be issued to check it before trusting it. The file contains DNSKEY/DS records in presentation format, and is compatible with Unbound or BIND9 root key files. .TP +.B \-m\fI path\fR, \fB\-\-moduledir=\fI<path> +Override the directory that is searched for modules. Default: @MODULEDIR@ +.TP .B \-f\fI N\fR, \fB\-\-forks=\fI<N> With this option, the daemon is started in non-interactive mode and instead creates a UNIX socket in \fIrundir\fR that the operator can connect to for interactive session. @@ -132,13 +146,8 @@ Daemon will refrain from printing any informative messages, not even a prompt. Increase verbosity. If given multiple times, more information is logged. This is in addition to the verbosity (if any) from the config file. .TP -.B \-c\fI config\fR, \fB\-\-config=\fI<config> -Set the config file with settings for kresd to read instead of reading the -file at the default location (\fIconfig\fR). The syntax is -described in \fIdaemon/README.md\fR. -.TP .B \-h -Show the version and commandline option help. +Show short commandline option help. .TP .B \-V Show the version. -- GitLab