diff --git a/Makefile b/Makefile index 3a69c9aab4d9a76daaa19d49c8c501407954c41e..93e16e43c64c11cfcf2e9dde08ff23765995f121 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ include platform.mk all: info lib daemon modules install: lib-install daemon-install modules-install etc-install check: all tests -clean: lib-clean daemon-clean modules-clean tests-clean doc-clean +clean: contrib-clean lib-clean daemon-clean modules-clean tests-clean doc-clean doc: doc-html .PHONY: all install check clean doc info @@ -49,7 +49,9 @@ BUILD_CFLAGS += $(addprefix -I,$(wildcard contrib/ccan/*) contrib/murmurhash3) info: $(info Target: Knot DNS Resolver $(MAJOR).$(MINOR).$(PATCH)-$(PLATFORM)) $(info Compiler: $(CC) $(BUILD_CFLAGS)) - $(info Linker: $(LD) $(BUILD_LDFLAGS)) + $(info HARDENING: $(HARDENING)) + $(info BUILDMODE: $(BUILDMODE)) + $(info PREFIX: $(PREFIX)) $(info PREFIX: $(PREFIX)) $(info DESTDIR: $(DESTDIR)) $(info BINDIR: $(BINDIR)) @@ -72,7 +74,6 @@ info: $(info [$(HAS_libmemcached)] libmemcached (modules/memcached)) $(info [$(HAS_hiredis)] hiredis (modules/redis)) $(info [$(HAS_cmocka)] cmocka (tests/unit)) - $(info [$(HAS_socket_wrapper)] socket_wrapper (lib)) $(info ) # Installation directories @@ -82,6 +83,7 @@ $(DESTDIR)$(ETCDIR): $(INSTALL) -m 0750 -d $@ # Sub-targets +include contrib/contrib.mk include lib/lib.mk include daemon/daemon.mk include modules/modules.mk diff --git a/config.mk b/config.mk index 5b99b347854e1be330a335e49d1bd0f60d2f7726..33117bd6c61996ecc766fb49ab51c23c4a7c98d1 100644 --- a/config.mk +++ b/config.mk @@ -2,6 +2,9 @@ MAJOR := 1 MINOR := 0 PATCH := 0-beta2 +ABIVER := 1 +BUILDMODE := dynamic +HARDENING := yes # Paths PREFIX := /usr/local @@ -13,10 +16,12 @@ ETCDIR := $(PREFIX)/etc/kresd # Tools CC ?= cc -BUILD_LDFLAGS += $(LDFLAGS) -BUILD_CFLAGS := $(CFLAGS) -std=c99 -D_GNU_SOURCE -fPIC -Wtype-limits -Wall -I$(abspath .) -I$(abspath lib/generic) -I$(abspath contrib) -BUILD_CFLAGS += -DPACKAGE_VERSION="\"$(MAJOR).$(MINOR).$(PATCH)\"" -DPREFIX="\"$(PREFIX)\"" -DMODULEDIR="\"$(MODULEDIR)\"" -DETCDIR="\"$(ETCDIR)\"" RM := rm -f LN := ln -s XXD := ./scripts/embed.sh INSTALL := install + +# Flags +BUILD_LDFLAGS += $(LDFLAGS) +BUILD_CFLAGS := $(CFLAGS) -std=c99 -D_GNU_SOURCE -D_FORTIFY_SOURCE=2 -Wno-unused -Wtype-limits -Wformat -Wformat-security -Wall -I$(abspath .) -I$(abspath lib/generic) -I$(abspath contrib) +BUILD_CFLAGS += -DPACKAGE_VERSION="\"$(MAJOR).$(MINOR).$(PATCH)\"" -DPREFIX="\"$(PREFIX)\"" -DMODULEDIR="\"$(MODULEDIR)\"" -DETCDIR="\"$(ETCDIR)\"" diff --git a/contrib/cleanup.h b/contrib/cleanup.h new file mode 100644 index 0000000000000000000000000000000000000000..7dcd750b0f3ce9844510945f98fb49a43ae7f122 --- /dev/null +++ b/contrib/cleanup.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2015 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 <http://www.gnu.org/licenses/>. +*/ +/** + * Cleanup attributes. + * @cond internal + */ +#pragma once +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> + +#define auto_free __attribute__((cleanup(_cleanup_free))) +static inline void _cleanup_free(char **p) { + free(*p); +} +#define auto_close __attribute__((cleanup(_cleanup_close))) +static inline void _cleanup_close(int *p) { + if (*p > 0) close(*p); +} +#define auto_fclose __attribute__((cleanup(_cleanup_fclose))) +static inline void _cleanup_fclose(FILE **p) { + if (*p) fclose(*p); +} +/* @endcond */ \ No newline at end of file diff --git a/contrib/contrib.mk b/contrib/contrib.mk new file mode 100644 index 0000000000000000000000000000000000000000..3daf43df53f5eeb163856ea91867c9330df1c1e6 --- /dev/null +++ b/contrib/contrib.mk @@ -0,0 +1,10 @@ +contrib_SOURCES := \ + contrib/ccan/asprintf/asprintf.c \ + contrib/ccan/ilog/ilog.c \ + contrib/ccan/isaac/isaac.c \ + contrib/ccan/json/json.c \ + contrib/ucw/mempool.c \ + contrib/murmurhash3/murmurhash3.c +contrib_CFLAGS := -fPIC +contrib_TARGET := $(abspath contrib)/contrib$(AREXT) +$(eval $(call make_static,contrib,contrib)) diff --git a/daemon/README.rst b/daemon/README.rst index 4fccf6f66eac9c06efe7fa08f2224d29d398fec5..a93dbd7b71fbfedc171d35472eba1041fee6d3c7 100644 --- a/daemon/README.rst +++ b/daemon/README.rst @@ -155,6 +155,8 @@ Configuration example -- 10MB cache cache.size = 10*MB +.. tip:: There are more configuration examples in `etc/` directory for personal, ISP, company internal and resolver cluster use cases. + Configuration syntax -------------------- diff --git a/daemon/bindings.c b/daemon/bindings.c index 9c751146a1ad73fb072828d746cf353363554cbb..e97230c91af78593f598024f9f298fc97b28ca85 100644 --- a/daemon/bindings.c +++ b/daemon/bindings.c @@ -15,6 +15,7 @@ */ #include <uv.h> +#include <contrib/cleanup.h> #include <libknot/descriptor.h> #include "lib/cache.h" diff --git a/daemon/daemon.mk b/daemon/daemon.mk index e56fad1f79e121ccb2c7575548be74e7bbd53588..c96c1e46de7eecebdc3bf84da6087084e0be5a06 100644 --- a/daemon/daemon.mk +++ b/daemon/daemon.mk @@ -1,7 +1,4 @@ -kresd_EMBED := \ - contrib/ccan/asprintf/asprintf.c kresd_SOURCES := \ - $(kresd_EMBED) \ daemon/io.c \ daemon/network.c \ daemon/engine.c \ @@ -9,6 +6,7 @@ kresd_SOURCES := \ daemon/bindings.c \ daemon/ffimodule.c \ daemon/main.c + kresd_DIST := daemon/lua/kres.lua daemon/lua/trust_anchors.lua # Embedded resources @@ -24,8 +22,9 @@ endif bindings-install: $(kresd_DIST) $(DESTDIR)$(MODULEDIR) $(INSTALL) -m 0644 $(kresd_DIST) $(DESTDIR)$(MODULEDIR) -kresd_DEPEND := $(libkres) -kresd_LIBS := $(libkres_TARGET) $(libknot_LIBS) $(libdnssec_LIBS) $(libuv_LIBS) $(lua_LIBS) +kresd_CFLAGS := -fPIE +kresd_DEPEND := $(libkres) $(contrib) +kresd_LIBS := $(libkres_TARGET) $(contrib_TARGET) $(libknot_LIBS) $(libdnssec_LIBS) $(libuv_LIBS) $(lua_LIBS) # Make binary ifeq ($(HAS_lua)|$(HAS_libuv), yes|yes) diff --git a/daemon/engine.c b/daemon/engine.c index ac52ba0593fb557069f7110a42c8352c1dae2b8c..fcdca1aad89837f6154bde5f3efcaa59fca1dfe2 100644 --- a/daemon/engine.c +++ b/daemon/engine.c @@ -14,6 +14,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <contrib/cleanup.h> #include <ccan/json/json.h> #include <ccan/asprintf/asprintf.h> #include <uv.h> @@ -153,9 +154,9 @@ static int l_quit(lua_State *L) static int l_verbose(lua_State *L) { if (lua_isboolean(L, 1) || lua_isnumber(L, 1)) { - log_debug_enable(lua_toboolean(L, 1)); + kr_debug_set(lua_toboolean(L, 1)); } - lua_pushboolean(L, log_debug_status()); + lua_pushboolean(L, kr_debug_status()); return 1; } @@ -176,7 +177,7 @@ static int l_option(lua_State *L) unsigned opt_code = 0; if (lua_isstring(L, 1)) { const char *opt = lua_tostring(L, 1); - for (const lookup_table_t *it = query_flag_names; it->name; ++it) { + for (const lookup_table_t *it = kr_query_flag_names(); it->name; ++it) { if (strcmp(it->name, opt) == 0) { opt_code = it->id; break; diff --git a/daemon/main.c b/daemon/main.c index ba653431e93b9c905b4bd724c76d055ddca2c194..62375a40e30bdd8d1a7bd090e729703fb62e731d 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -18,9 +18,10 @@ #include <string.h> #include <getopt.h> #include <uv.h> +#include <contrib/cleanup.h> +#include <contrib/ucw/mempool.h> +#include <contrib/ccan/asprintf/asprintf.h> -#include "contrib/ucw/mempool.h" -#include "contrib/ccan/asprintf/asprintf.h" #include "lib/defines.h" #include "lib/resolve.h" #include "lib/dnssec.h" @@ -235,12 +236,12 @@ int main(int argc, char **argv) g_interactive = 0; forks = atoi(optarg); if (forks == 0) { - log_error("[system] error '-f' requires number, not '%s'\n", optarg); + kr_log_error("[system] error '-f' requires number, not '%s'\n", optarg); return EXIT_FAILURE; } #if (!defined(UV_VERSION_HEX)) || (!defined(SO_REUSEPORT)) if (forks > 1) { - log_error("[system] libuv 1.7+ is required for SO_REUSEPORT support, multiple forks not supported\n"); + kr_log_error("[system] libuv 1.7+ is required for SO_REUSEPORT support, multiple forks not supported\n"); return EXIT_FAILURE; } #endif @@ -268,15 +269,15 @@ int main(int argc, char **argv) } free(keyfile_buf); if (!keyfile) { - log_error("[system] keyfile '%s': not writeable\n", optarg); + kr_log_error("[system] keyfile '%s': not writeable\n", optarg); return EXIT_FAILURE; } break; case 'v': - log_debug_enable(true); + kr_debug_set(true); break; case 'V': - log_info("%s, version %s\n", "Knot DNS Resolver", PACKAGE_VERSION); + kr_log_info("%s, version %s\n", "Knot DNS Resolver", PACKAGE_VERSION); return EXIT_SUCCESS; case 'h': case '?': @@ -292,17 +293,17 @@ int main(int argc, char **argv) if (optind < argc) { const char *rundir = argv[optind]; if (access(rundir, W_OK) != 0) { - log_error("[system] rundir '%s': %s\n", rundir, strerror(errno)); + kr_log_error("[system] rundir '%s': %s\n", rundir, strerror(errno)); return EXIT_FAILURE; } ret = chdir(rundir); if (ret != 0) { - log_error("[system] rundir '%s': %s\n", rundir, strerror(errno)); + kr_log_error("[system] rundir '%s': %s\n", rundir, strerror(errno)); return EXIT_FAILURE; } if(config && access(config, R_OK) != 0) { - log_error("[system] rundir '%s'\n", rundir); - log_error("[system] config '%s': %s\n", config, strerror(errno)); + kr_log_error("[system] rundir '%s'\n", rundir); + kr_log_error("[system] config '%s': %s\n", config, strerror(errno)); return EXIT_FAILURE; } } @@ -339,13 +340,13 @@ int main(int argc, char **argv) struct engine engine; ret = engine_init(&engine, &pool); if (ret != 0) { - log_error("[system] failed to initialize engine: %s\n", kr_strerror(ret)); + kr_log_error("[system] failed to initialize engine: %s\n", kr_strerror(ret)); return EXIT_FAILURE; } /* Create worker */ struct worker_ctx *worker = init_worker(loop, &engine, &pool, forks, fork_count); if (!worker) { - log_error("[system] not enough memory\n"); + kr_log_error("[system] not enough memory\n"); return EXIT_FAILURE; } /* Bind to sockets and run */ @@ -354,7 +355,7 @@ int main(int argc, char **argv) const char *addr = set_addr(addr_set.at[i], &port); ret = network_listen(&engine.net, addr, (uint16_t)port, NET_UDP|NET_TCP); if (ret != 0) { - log_error("[system] bind to '%s#%d' %s\n", addr, port, knot_strerror(ret)); + kr_log_error("[system] bind to '%s#%d' %s\n", addr, port, knot_strerror(ret)); ret = EXIT_FAILURE; } } @@ -365,7 +366,7 @@ int main(int argc, char **argv) if (keyfile) { auto_free char *cmd = afmt("trust_anchors.file = '%s'", keyfile); if (!cmd) { - log_error("[system] not enough memory\n"); + kr_log_error("[system] not enough memory\n"); return EXIT_FAILURE; } engine_cmd(&engine, cmd); diff --git a/daemon/worker.c b/daemon/worker.c index cb5dd83b9dc493b3f35483a4451f06b6897dbca8..b05643a2726f2a99ad4137d704eed1fa25631e83 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -484,7 +484,7 @@ static int subreq_key(char *dst, struct qr_task *task) assert(task); knot_pkt_t *pkt = task->pktbuf; assert(knot_wire_get_qr(pkt->wire) == false); - return kr_rrmap_key(dst, knot_pkt_qname(pkt), knot_pkt_qtype(pkt), knot_pkt_qclass(pkt)); + return kr_rrkey(dst, knot_pkt_qname(pkt), knot_pkt_qtype(pkt), knot_pkt_qclass(pkt)); } static void subreq_finalize(struct qr_task *task, const struct sockaddr *packet_source, knot_pkt_t *pkt) @@ -498,7 +498,7 @@ static void subreq_finalize(struct qr_task *task, const struct sockaddr *packet_ /* Clear from outstanding table. */ if (!task->leading) return; - char key[RRMAP_KEYSIZE]; + char key[KR_RRKEY_LEN]; int ret = subreq_key(key, task); if (ret > 0) { assert(map_get(&task->worker->outstanding, key) == task); @@ -525,7 +525,7 @@ static void subreq_finalize(struct qr_task *task, const struct sockaddr *packet_ static void subreq_lead(struct qr_task *task) { assert(task); - char key[RRMAP_KEYSIZE]; + char key[KR_RRKEY_LEN]; if (subreq_key(key, task) > 0) { assert(map_contains(&task->worker->outstanding, key) == false); map_set(&task->worker->outstanding, key, task); @@ -536,12 +536,12 @@ static void subreq_lead(struct qr_task *task) static bool subreq_enqueue(struct qr_task *task) { assert(task); - char key[RRMAP_KEYSIZE]; + char key[KR_RRKEY_LEN]; if (subreq_key(key, task) > 0) { struct qr_task *leader = map_get(&task->worker->outstanding, key); if (leader) { /* Enqueue itself to leader for this subrequest. */ - int ret = array_reserve_mm(leader->waiting, leader->waiting.len + 1, mm_reserve, &leader->req.pool); + int ret = array_reserve_mm(leader->waiting, leader->waiting.len + 1, kr_memreserve, &leader->req.pool); if (ret == 0) { array_push(leader->waiting, task); qr_task_ref(task); diff --git a/doc/build.rst b/doc/build.rst index 55d93032b6852077e6d9d5f488d27d853cdbbe27..9d0dccb882254649f0762e37b27fc6c19c689049 100644 --- a/doc/build.rst +++ b/doc/build.rst @@ -78,24 +78,6 @@ Most of the dependencies can be resolved from packages, here's an overview for s brew install pkg-config libuv luajit cmocka -Getting Docker image --------------------- - -Docker images require only either Linux or a Linux VM (see boot2docker_ on OS X). - -.. code-block:: bash - - $ docker run cznic/knot-resolver - -See the `Docker images`_ page for more information and options. -You can hack on the container by changing the container entrypoint to shell like: - -.. code-block:: bash - - $ docker run -it --entrypoint=/bin/bash cznic/knot-resolver - -.. tip:: You can build the Docker image yourself with ``docker build -t knot-resolver scripts``. - Building from sources --------------------- @@ -123,6 +105,24 @@ Alternatively you can build only specific parts of the project, i.e. ``library`` .. note:: Documentation is not built by default, run ``make doc`` to build it. +Building with security compiler flags +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Knot DNS Resolver enables certain `security compile-time flags <https://wiki.debian.org/Hardening#Notes_on_Memory_Corruption_Mitigation_Methods>`_ that do not affect performance. +You can add more flags to the build by appending them to `CFLAGS` variable, e.g. ``make CFLAGS="-fstack-protector"``. + + .. csv-table:: + :header: "Method", "Status", "Notes" + + "-fstack-protector", "*disabled*", "(must be specifically enabled in CFLAGS)" + "-D_FORTIFY_SOURCE=2", "**enabled**", "" + "-pie", "**enabled**", "enables ASLR for kresd (disable with ``make HARDENING=no``)" + "RELRO", "**enabled**", "full [#]_" + +You can also disable linker hardening when it's unsupported with ``make HARDENING=no``. + +.. [#] See `checksec.sh <http://www.trapkit.de/tools/checksec.html>`_ + Building for packages ~~~~~~~~~~~~~~~~~~~~~ @@ -133,7 +133,41 @@ The build system supports both DESTDIR_ and `amalgamated builds <https://www.sql $ make install DESTDIR=/tmp/stage # Staged install $ make all install AMALG=yes # Amalgamated build -.. note:: Amalgamated build assembles everything in one source file and compiles it. It is useful for packages, as the compiler sees the whole program and is able to produce a smaller and faster binary. On the other hand, it complicates debugging. +Amalgamated build assembles everything in one source file and compiles it. It is useful for packages, as the compiler sees the whole program and is able to produce a smaller and faster binary. On the other hand, it complicates debugging. + +.. tip:: There is a template for service file and AppArmor profile to help you kickstart the package. + +Default paths +~~~~~~~~~~~~~ + +The default installation follows FHS with several custom paths for configuration and modules. +All paths are prefixed with ``PREFIX`` variable by default if not specified otherwise. + + .. csv-table:: + :header: "Component", "Variable", "Default", "Notes" + + "library", "``LIBDIR``", "``$(PREFIX)/lib``", "pkg-config is auto-generated [#]_" + "daemon", "``BINDIR``", "``$(PREFIX)/bin``", "" + "configuration", "``ETCDIR``", "``$(PREFIX)/etc/kresd``", "Configuration file, templates." + "modules", "``MODULEDIR``", "``$(LIBDIR)/kdns_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. + +.. note:: Each module is self-contained and may install additional bundled files within ``$(MODULEDIR)/$(modulename)``. These files should be read-only, non-executable. + +Static or dynamic? +~~~~~~~~~~~~~~~~~~ + +By default the resolver library is built as a dynamic library with versioned ABI. You can revert to static build with ``BUILDMODE`` variable. + +.. code-block:: bash + + $ make BUILDMODE=dynamic # Default, create dynamic library + $ make BUILDMODE=static # Create static library + +When the library is linked statically, it usually produces a smaller binary. However linking it to various C modules might violate ODR and increase the size. Building dependencies ~~~~~~~~~~~~~~~~~~~~~ @@ -181,6 +215,24 @@ is otherwise unable to find and load modules. Read the `documentation <deckard_doc>`_ for more information about requirements, how to run it and extend it. +Getting Docker image +-------------------- + +Docker images require only either Linux or a Linux VM (see boot2docker_ on OS X). + +.. code-block:: bash + + $ docker run cznic/knot-resolver + +See the `Docker images`_ page for more information and options. +You can hack on the container by changing the container entrypoint to shell like: + +.. code-block:: bash + + $ docker run -it --entrypoint=/bin/bash cznic/knot-resolver + +.. tip:: You can build the Docker image yourself with ``docker build -t knot-resolver scripts``. + .. _Docker images: https://registry.hub.docker.com/u/cznic/knot-resolver .. _libuv: https://github.com/libuv/libuv .. _MSVC: https://msdn.microsoft.com/en-us/vstudio/hh386302.aspx diff --git a/etc/config.cluster b/etc/config.cluster new file mode 100644 index 0000000000000000000000000000000000000000..5be5c923ca4ca4f07058aee4bb254703191366f0 --- /dev/null +++ b/etc/config.cluster @@ -0,0 +1,46 @@ +-- Config file example useable for larger resolver farms +-- In this case cache should be made as large as possible, and prefetching turned off +-- as the resolver is busy most of the time. +-- Alternative is using `etcd` as a configuration backend. +-- Refer to manual: http://knot-resolver.readthedocs.org/en/latest/daemon.html#configuration + +-- Listen on localhost and external interface +net = { '127.0.0.1', '::1', '192.168.1.1' } + +-- Drop root privileges +user('kresd', 'kresd') + +-- Auto-maintain root TA +trust_anchors.file = 'root.keys' + +-- Large cache size, so we don't need to flush ever +-- This can be larger than available RAM, least frequently accessed +-- records will be paged out as long as there's enough disk space to back it +cache.size = 100 * GB + +-- Load Useful modules +modules = { + 'policy', -- Block queries to local zones/bad sites + 'cachectl', -- Cache control interface + 'hints', -- Load /etc/hosts and allow custom root hints + 'stats', -- Track internal statistics + graphite = { -- Send statistics to local InfluxDB + -- `worker.id` allows us to keep per-fork statistics + prefix = hostname()..worker.id, + -- Address of the Graphite/InfluxDB server + host = '192.168.1.2', + }, + 'redis', -- Allow to use Redis as a cache backend +} + +-- Use local root server copy for performance reasons +hints.root({ + ['j.root-servers.net.'] = { '192.168.1.4', '2001:503:c27::2:30', '192.58.128.30' } +}) + +-- Apply RPZ for all clients, default rule is DENY +policy:add(policy.rpz(policy.DENY, 'blacklist.rpz')) + +-- Optional: use Redis/Memcached as a cache backend which may be distributed between nodes +-- cache.storage = 'redis://127.0.0.1:6398' + diff --git a/etc/config.isp b/etc/config.isp new file mode 100644 index 0000000000000000000000000000000000000000..4d6e9910bb9ed4986f2c7e4afa17b4bdbe0ff7b1 --- /dev/null +++ b/etc/config.isp @@ -0,0 +1,39 @@ +-- Config file example useable for multi-user ISP resolver +-- Refer to manual: http://knot-resolver.readthedocs.org/en/latest/daemon.html#configuration + +-- Listen on localhost and external interface +net = { '127.0.0.1', '::1', '192.168.1.1' } + +-- Drop root privileges +user('kresd', 'kresd') + +-- Auto-maintain root TA +trust_anchors.file = 'root.keys' + +-- Large cache size, so we don't need to flush often +-- This can be larger than available RAM, least frequently accessed +-- records will be paged out +cache.size = 4 * GB + +-- Load Useful modules +modules = { + 'policy', -- Block queries to local zones/bad sites + 'view', -- Views for certain clients + 'cachectl', -- Cache control interface + 'hints', -- Load /etc/hosts and allow custom root hints + 'stats', -- Track internal statistics + graphite = { -- Send statistics to local InfluxDB + -- `worker.id` allows us to keep per-fork statistics + prefix = hostname()..worker.id, + -- Address of the Graphite/InfluxDB server + host = '192.168.1.2', + } +} + +-- Block all `site.nl` for `10.0.0.0/24` subnet +view:addr('10.0.0.0/24', policy.suffix(policy.DROP, {todname('site.nl')})) +-- Force all clients from `192.168.2.0/24` to TCP +view:addr('192.168.2.0/24', policy.all(policy.TC)) +-- Apply RPZ for all clients, default rule is DENY +policy:add(policy.rpz(policy.DENY, 'blacklist.rpz')) + diff --git a/etc/config.personal b/etc/config.personal new file mode 100644 index 0000000000000000000000000000000000000000..12881b13df33d318b8ab71891bd5f53d692534e8 --- /dev/null +++ b/etc/config.personal @@ -0,0 +1,25 @@ +-- Config file example useable for personal resolver. +-- The goal is to have a validating resolver with tiny memory footprint, +-- while actively tracking and refreshing frequent records to lower user latency. +-- Refer to manual: http://knot-resolver.readthedocs.org/en/latest/daemon.html#configuration + +-- Listen on localhost (default) +-- net = { '127.0.0.1', '::1' } + +-- Drop root privileges +user('kresd', 'kresd') + +-- Auto-maintain root TA +trust_anchors.file = 'root.keys' + +-- Load Useful modules +modules = { + 'policy', -- Block queries to local zones/bad sites + 'cachectl', -- Cache control interface + 'hints', -- Load /etc/hosts and allow custom root hints + 'stats', -- Track internal statistics + 'predict', -- Prefetch expiring/frequent records +} + +-- Smaller cache size +cache.size = 10 * MB diff --git a/etc/config.splitview b/etc/config.splitview new file mode 100644 index 0000000000000000000000000000000000000000..ff26a09ad3aa4167b0abd4be95383bc91e526d28 --- /dev/null +++ b/etc/config.splitview @@ -0,0 +1,35 @@ +-- Config file with split-view for internal zone +-- Refer to manual: http://knot-resolver.readthedocs.org/en/latest/daemon.html#configuration + +-- Listen on localhost and external interface +net = { '127.0.0.1', '::1', '192.168.1.1' } + +-- Drop root privileges +user('kresd', 'kresd') + +-- Auto-maintain root TA +trust_anchors.file = 'root.keys' + +-- Load Useful modules +modules = { + 'policy', -- Block queries to local zones/bad sites + 'cachectl', -- Cache control interface + 'hints', -- Load /etc/hosts and allow custom root hints + 'stats', -- Track internal statistics + graphite = { -- Send statistics to local InfluxDB + -- `worker.id` allows us to keep per-fork statistics + prefix = hostname()..worker.id, + -- Address of the Graphite/InfluxDB server + host = '192.168.1.2', + }, + -- Use DNS64 with specified NAT64 address + dns64 = 'fe80::21b:77ff:0:0', +} + +-- Large cache size, so we don't need to flush often +-- This can be larger than available RAM, least frequently accessed +-- records will be paged out +cache.size = 4 * GB + +-- Forward everything below `company.cz` to `192.168.1.3` +policy:add(policy.suffix(policy.FORWARD('192.168.1.3'), {todname('company.cz')})) diff --git a/etc/etc.mk b/etc/etc.mk index 18ee2a0fc5ff1b060552e3d43acd13d1977ccf30..9c5b446eb93781c785ad15b5d9b7641302b0025c 100644 --- a/etc/etc.mk +++ b/etc/etc.mk @@ -1,4 +1,8 @@ -etc_SOURCES := icann-ca.pem +etc_SOURCES := icann-ca.pem \ + config.cluster \ + config.isp \ + config.personal \ + config.splitview etc-install: $(DESTDIR)$(ETCDIR) $(INSTALL) -m 0640 $(addprefix etc/,$(etc_SOURCES)) $(DESTDIR)$(ETCDIR) diff --git a/lib/cache.c b/lib/cache.c index 64394bd3ed6e8e0fb4e4dd679e69b819353f4b67..50347f7220d796f20bb6e2a01bd1813aca96bf4e 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -58,7 +58,7 @@ static void assert_right_version(struct kr_cache *cache) /* Recreate cache and write version key */ ret = txn_api(&txn)->count(&txn.t); if (ret > 0) { /* Non-empty cache, purge it. */ - log_info("[cache] purging cache\n"); + kr_log_info("[cache] purging cache\n"); kr_cache_clear(&txn); kr_cache_txn_commit(&txn); ret = kr_cache_txn_begin(cache, &txn, 0); diff --git a/lib/cache.h b/lib/cache.h index 211eb20cf5754112083a43b611409610fec8e8cb..3fabea7ced0d18e8764e2af1434a56d308d10607 100644 --- a/lib/cache.h +++ b/lib/cache.h @@ -18,6 +18,7 @@ #include <libknot/rrset.h> #include <libknot/internal/namedb/namedb.h> +#include "lib/defines.h" /** Cache entry tag */ enum kr_cache_tag { @@ -86,6 +87,7 @@ struct kr_cache_txn { * @param mm memory context. * @return 0 or an error code */ +KR_EXPORT int kr_cache_open(struct kr_cache *cache, const namedb_api_t *api, void *opts, mm_ctx_t *mm); /** @@ -93,6 +95,7 @@ int kr_cache_open(struct kr_cache *cache, const namedb_api_t *api, void *opts, m * @note This doesn't clear the data, just closes the connection to the database. * @param cache database instance */ +KR_EXPORT void kr_cache_close(struct kr_cache *cache); /** @@ -103,6 +106,7 @@ void kr_cache_close(struct kr_cache *cache); * @param flags transaction flags (see namedb.h in libknot) * @return 0 or an errcode */ +KR_EXPORT int kr_cache_txn_begin(struct kr_cache *cache, struct kr_cache_txn *txn, unsigned flags); /** @@ -110,12 +114,14 @@ int kr_cache_txn_begin(struct kr_cache *cache, struct kr_cache_txn *txn, unsigne * @param txn transaction instance * @return 0 or an errcode */ +KR_EXPORT int kr_cache_txn_commit(struct kr_cache_txn *txn); /** * Abort existing transaction instance. * @param txn transaction instance */ +KR_EXPORT void kr_cache_txn_abort(struct kr_cache_txn *txn); /** @@ -129,6 +135,7 @@ void kr_cache_txn_abort(struct kr_cache_txn *txn); * @param timestamp current time (will be replaced with drift if successful) * @return 0 or an errcode */ +KR_EXPORT int kr_cache_peek(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type, struct kr_cache_entry **entry, uint32_t *timestamp); @@ -144,6 +151,7 @@ int kr_cache_peek(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *nam * @param data inserted data * @return 0 or an errcode */ +KR_EXPORT int kr_cache_insert(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type, struct kr_cache_entry *header, namedb_val_t data); @@ -155,6 +163,7 @@ int kr_cache_insert(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *n * @param type record type * @return 0 or an errcode */ +KR_EXPORT int kr_cache_remove(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type); /** @@ -162,6 +171,7 @@ int kr_cache_remove(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *n * @param txn transaction instance * @return 0 or an errcode */ +KR_EXPORT int kr_cache_clear(struct kr_cache_txn *txn); /** @@ -173,6 +183,7 @@ int kr_cache_clear(struct kr_cache_txn *txn); * @param timestamp current time * @return rank (0 or positive), or an error (negative number) */ +KR_EXPORT int kr_cache_peek_rank(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t *name, uint16_t type, uint32_t timestamp); /** @@ -184,6 +195,7 @@ int kr_cache_peek_rank(struct kr_cache_txn *txn, uint8_t tag, const knot_dname_t * @param timestamp current time (will be replaced with drift if successful) * @return 0 or an errcode */ +KR_EXPORT int kr_cache_peek_rr(struct kr_cache_txn *txn, knot_rrset_t *rr, uint16_t *rank, uint32_t *timestamp); /** @@ -194,6 +206,7 @@ int kr_cache_peek_rr(struct kr_cache_txn *txn, knot_rrset_t *rr, uint16_t *rank, * @param mm memory context * @return 0 or an errcode */ +KR_EXPORT int kr_cache_materialize(knot_rrset_t *dst, const knot_rrset_t *src, uint32_t drift, mm_ctx_t *mm); /** @@ -204,6 +217,7 @@ int kr_cache_materialize(knot_rrset_t *dst, const knot_rrset_t *src, uint32_t dr * @param timestamp current time * @return 0 or an errcode */ +KR_EXPORT int kr_cache_insert_rr(struct kr_cache_txn *txn, const knot_rrset_t *rr, uint16_t rank, uint32_t timestamp); /** @@ -215,6 +229,7 @@ int kr_cache_insert_rr(struct kr_cache_txn *txn, const knot_rrset_t *rr, uint16_ * @param timestamp current time (will be replaced with drift if successful) * @return 0 or an errcode */ +KR_EXPORT int kr_cache_peek_rrsig(struct kr_cache_txn *txn, knot_rrset_t *rr, uint16_t *rank, uint32_t *timestamp); /** @@ -226,4 +241,5 @@ int kr_cache_peek_rrsig(struct kr_cache_txn *txn, knot_rrset_t *rr, uint16_t *ra * @param timestamp current time * @return 0 or an errcode */ +KR_EXPORT int kr_cache_insert_rrsig(struct kr_cache_txn *txn, const knot_rrset_t *rr, uint16_t rank, uint32_t timestamp); diff --git a/lib/defines.h b/lib/defines.h index c70c279f980c1657884cb8d0a05ce40162e8d7ae..7031f7ddb5fe8d9fc270ae0d1ee6e7f73a9620c2 100644 --- a/lib/defines.h +++ b/lib/defines.h @@ -27,11 +27,13 @@ #define KR_CONST __attribute__((__const__)) #define KR_PURE __attribute__((__pure__)) #define KR_NORETURN __attribute__((__noreturn__)) +#define KR_COLD __attribute__((__cold__)) #else #define KR_EXPORT #define KR_CONST #define KR_PURE #define KR_NORETURN +#define KR_COLD #endif /* diff --git a/lib/dnssec.h b/lib/dnssec.h index 7679f730a2a41d7a410248687b09b376bda29d3f..82ea7bccfa290a0e2970ed3091ea8b05c8d0072d 100644 --- a/lib/dnssec.h +++ b/lib/dnssec.h @@ -16,23 +16,27 @@ #pragma once +#include "lib/defines.h" #include <libknot/internal/consts.h> #include <libknot/packet/pkt.h> /** * Initialise cryptographic back-end. */ +KR_EXPORT void kr_crypto_init(void); /** * De-initialise cryptographic back-end. */ +KR_EXPORT void kr_crypto_cleanup(void); /** * Re-initialise cryptographic back-end. * @note Must be called after fork() in the child. */ +KR_EXPORT void kr_crypto_reinit(void); /** Opaque DNSSEC key pointer. */ @@ -89,12 +93,15 @@ int kr_dnskeys_trusted(const knot_pkt_t *pkt, knot_section_t section_id, const k bool has_nsec3); /** Return true if the DNSKEY can be used as a ZSK. */ +KR_EXPORT KR_PURE bool kr_dnssec_key_zsk(const uint8_t *dnskey_rdata); /** Return true if the DNSKEY indicates being KSK (=> has SEP). */ +KR_EXPORT KR_PURE bool kr_dnssec_key_ksk(const uint8_t *dnskey_rdata); /** Return true if the DNSKEY is revoked. */ +KR_EXPORT KR_PURE bool kr_dnssec_key_revoked(const uint8_t *dnskey_rdata); /** Return DNSKEY tag. @@ -103,6 +110,7 @@ bool kr_dnssec_key_revoked(const uint8_t *dnskey_rdata); * @param rdlen RDATA length. * @return Key tag (positive number), or an error code */ +KR_EXPORT KR_PURE int kr_dnssec_key_tag(uint16_t rrtype, const uint8_t *rdata, size_t rdlen); /** Return 0 if the two keys are identical. @@ -113,6 +121,7 @@ int kr_dnssec_key_tag(uint16_t rrtype, const uint8_t *rdata, size_t rdlen); * @param key_b_rdlen Second key RDATA length * @return 0 if they match or an error code */ +KR_EXPORT KR_PURE int kr_dnssec_key_match(const uint8_t *key_a_rdata, size_t key_a_rdlen, const uint8_t *key_b_rdata, size_t key_b_rdlen); diff --git a/lib/dnssec/ta.h b/lib/dnssec/ta.h index 6c712a0db162205b985d01c66d837ea8e77f8a4d..3541c4ac4e4ab275f6c307f0751e9b45344682da 100644 --- a/lib/dnssec/ta.h +++ b/lib/dnssec/ta.h @@ -25,6 +25,7 @@ * @param name name of the TA * @return non-empty RRSet or NULL */ +KR_EXPORT knot_rrset_t *kr_ta_get(map_t *trust_anchors, const knot_dname_t *name); /** @@ -37,6 +38,7 @@ knot_rrset_t *kr_ta_get(map_t *trust_anchors, const knot_dname_t *name); * @param rdlen * @return 0 or an error */ +KR_EXPORT int kr_ta_add(map_t *trust_anchors, const knot_dname_t *name, uint16_t type, uint32_t ttl, const uint8_t *rdata, uint16_t rdlen); @@ -47,6 +49,7 @@ int kr_ta_add(map_t *trust_anchors, const knot_dname_t *name, uint16_t type, * @param name name of the TA * @return boolean */ +KR_EXPORT KR_PURE int kr_ta_covers(map_t *trust_anchors, const knot_dname_t *name); /** @@ -55,10 +58,12 @@ int kr_ta_covers(map_t *trust_anchors, const knot_dname_t *name); * @param name name of the TA * @return 0 or an error */ +KR_EXPORT int kr_ta_del(map_t *trust_anchors, const knot_dname_t *name); /** * Clear trust store. * @param trust_anchors trust store */ +KR_EXPORT void kr_ta_clear(map_t *trust_anchors); diff --git a/lib/generic/map.c b/lib/generic/map.c index a6a12911a2b6bd8546dfa15b04327690ef89f45f..81a283dc5c900411875a3f9e8f622d37609ae7c8 100644 --- a/lib/generic/map.c +++ b/lib/generic/map.c @@ -17,6 +17,13 @@ #include "map.h" + /* Exports */ +#if defined _WIN32 || defined __CYGWIN__ + #define EXPORT __attribute__ ((dllexport)) +#else + #define EXPORT __attribute__ ((visibility ("default"))) +#endif + #ifdef _MSC_VER /* MSVC */ typedef unsigned __int8 uint8_t; typedef unsigned __int32 uint32_t; @@ -112,7 +119,7 @@ static cb_data_t *cbt_make_data(map_t *map, const uint8_t *str, size_t len, void } /*! Creates a new, empty critbit map */ -map_t map_make(void) +EXPORT map_t map_make(void) { map_t map; map.root = NULL; @@ -123,12 +130,12 @@ map_t map_make(void) } /*! Returns non-zero if map contains str */ -int map_contains(map_t *map, const char *str) +EXPORT int map_contains(map_t *map, const char *str) { return map_get(map, str) != NULL; } -void *map_get(map_t *map, const char *str) +EXPORT void *map_get(map_t *map, const char *str) { const uint8_t *ubytes = (void *)str; const size_t ulen = strlen(str); @@ -161,7 +168,7 @@ void *map_get(map_t *map, const char *str) } /*! Inserts str into map, returns 0 on success */ -int map_set(map_t *map, const char *str, void *value) +EXPORT int map_set(map_t *map, const char *str, void *value) { const uint8_t *const ubytes = (void *)str; const size_t ulen = strlen(str); @@ -262,7 +269,7 @@ different_byte_found: } /*! Deletes str from the map, returns 0 on success */ -int map_del(map_t *map, const char *str) +EXPORT int map_del(map_t *map, const char *str) { const uint8_t *ubytes = (void *)str; const size_t ulen = strlen(str); @@ -307,7 +314,7 @@ int map_del(map_t *map, const char *str) } /*! Clears the given map */ -void map_clear(map_t *map) +EXPORT void map_clear(map_t *map) { if (map->root) { cbt_traverse_delete(map, map->root); @@ -316,7 +323,7 @@ void map_clear(map_t *map) } /*! Calls callback for all strings in map with the given prefix */ -int map_walk_prefixed(map_t *map, const char *prefix, +EXPORT int map_walk_prefixed(map_t *map, const char *prefix, int (*callback)(const char *, void *, void *), void *baton) { const uint8_t *ubytes = (void *)prefix; diff --git a/lib/layer.h b/lib/layer.h index 335edadef26939727af6a77e9a6174d7e9bbaf01..3d1d536a3e602e7b9b626f64d0252edd3966d383 100644 --- a/lib/layer.h +++ b/lib/layer.h @@ -25,7 +25,7 @@ #define QRDEBUG(query, cls, fmt, ...) do { \ unsigned _ind = 0; \ for (struct kr_query *q = (query); q; q = q->parent, _ind += 2); \ - log_debug("[%s] %*s" fmt, cls, _ind, "", ## __VA_ARGS__); \ + kr_log_debug("[%s] %*s" fmt, cls, _ind, "", ## __VA_ARGS__); \ } while (0) #else #define QRDEBUG(query, cls, fmt, ...) diff --git a/lib/lib.mk b/lib/lib.mk index 9f09c58fcbada9273619af89f3c8b53d394b8bb8..822af51f78f356b1d02227c56a64caf4c8259e84 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -1,12 +1,4 @@ -ccan_EMBED := \ - contrib/ccan/ilog/ilog.c \ - contrib/ccan/isaac/isaac.c \ - contrib/ccan/json/json.c \ - contrib/ucw/mempool.c \ - contrib/murmurhash3/murmurhash3.c - libkres_SOURCES := \ - $(ccan_EMBED) \ lib/generic/map.c \ lib/layer/iterate.c \ lib/layer/validate.c \ @@ -47,17 +39,36 @@ libkres_HEADERS := \ lib/cache.h # Dependencies -libkres_DEPEND := -libkres_CFLAGS := -fvisibility=hidden -libkres_LIBS := $(libknot_LIBS) $(libdnssec_LIBS) +libkres_DEPEND := $(contrib) +libkres_CFLAGS := -fvisibility=hidden -fPIC +libkres_LIBS := $(contrib_TARGET) $(libknot_LIBS) $(libdnssec_LIBS) libkres_TARGET := -L$(abspath lib) -lkres # Make library +ifeq ($(BUILDMODE), static) $(eval $(call make_static,libkres,lib,yes)) +else +$(eval $(call make_lib,libkres,lib,yes,$(ABIVER))) +endif + +# Generate pkg-config file +libkres.pc: + @echo 'prefix='$(PREFIX) > $@ + @echo 'exec_prefix=$${prefix}' >> $@ + @echo 'libdir='$(LIBDIR) >> $@ + @echo 'includedir='$(INCLUDEDIR) >> $@ + @echo 'Name: libkres' >> $@ + @echo 'Description: Knot DNS Resolver library' >> $@ + @echo 'URL: https://www.knot-dns.cz' >> $@ + @echo 'Version: $(MAJOR).$(MINOR).$(PATCH)' >> $@ + @echo 'Libs: -L$${libdir} -lkres' >> $@ + @echo 'Cflags: -I$${includedir}' >> $@ +libkres-pcinstall: libkres.pc libkres-install + $(INSTALL) -m 644 $< $(DESTDIR)$(LIBDIR)/pkgconfig # Targets lib: $(libkres) -lib-install: libkres-install +lib-install: libkres-install libkres-pcinstall lib-clean: libkres-clean -.PHONY: lib lib-install lib-clean +.PHONY: lib lib-install lib-clean libkres.pc diff --git a/lib/module.c b/lib/module.c index 369be3aa26513d4615eb0ef9c303e82f3423a2dd..cd075a8eee0c83682564e3da0378be912f64b3be 100644 --- a/lib/module.c +++ b/lib/module.c @@ -17,7 +17,7 @@ #include <stdlib.h> #include <dlfcn.h> #include <pthread.h> -#include <unistd.h> +#include <contrib/cleanup.h> #include "lib/defines.h" #include "lib/utils.h" diff --git a/lib/module.h b/lib/module.h index d3d2c7b307421b5d38a70085b68f4909462ca45e..4b9ec2b95cbc0939834ae60a04020471b02e57cf 100644 --- a/lib/module.h +++ b/lib/module.h @@ -72,6 +72,7 @@ struct kr_module { * @param path module search path * @return 0 or an error */ +KR_EXPORT int kr_module_load(struct kr_module *module, const char *name, const char *path); /** @@ -79,6 +80,7 @@ int kr_module_load(struct kr_module *module, const char *name, const char *path) * * @param module module structure */ +KR_EXPORT void kr_module_unload(struct kr_module *module); /** diff --git a/lib/nsrep.h b/lib/nsrep.h index dbeca487645af7be80d99bbcf28e1dda30473f61..848b28f0b542be9886ddd3c62be7f773a6997776 100644 --- a/lib/nsrep.h +++ b/lib/nsrep.h @@ -87,6 +87,7 @@ struct kr_nsrep * @param addr_len address bytes length (type will be derived from this) * @return 0 or an error code */ +KR_EXPORT int kr_nsrep_set(struct kr_query *qry, uint8_t *addr, size_t addr_len); /** @@ -95,6 +96,7 @@ int kr_nsrep_set(struct kr_query *qry, uint8_t *addr, size_t addr_len); * @param ctx resolution context * @return 0 or an error code */ +KR_EXPORT int kr_nsrep_elect(struct kr_query *qry, struct kr_context *ctx); /** @@ -103,6 +105,7 @@ int kr_nsrep_elect(struct kr_query *qry, struct kr_context *ctx); * @param ctx resolution context * @return 0 or an error code */ +KR_EXPORT int kr_nsrep_elect_addr(struct kr_query *qry, struct kr_context *ctx); /** @@ -116,6 +119,7 @@ int kr_nsrep_elect_addr(struct kr_query *qry, struct kr_context *ctx); * @param cache LRU cache * @return 0 on success, error code on failure */ +KR_EXPORT int kr_nsrep_update_rtt(struct kr_nsrep *ns, const struct sockaddr *addr, unsigned score, kr_nsrep_lru_t *cache); /** @@ -126,4 +130,5 @@ int kr_nsrep_update_rtt(struct kr_nsrep *ns, const struct sockaddr *addr, unsign * @param cache LRU cache * @return 0 on success, error code on failure */ +KR_EXPORT int kr_nsrep_update_rep(struct kr_nsrep *ns, unsigned reputation, kr_nsrep_lru_t *cache); diff --git a/lib/resolve.c b/lib/resolve.c index b665345ee082ad0be907ae750f70965619380c74..df7c91ff9d427e4cdd8f6fb59e0ae78df1850d56 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -111,9 +111,10 @@ static int invalidate_ns(struct kr_rplan *rplan, struct kr_query *qry) if (qry->ns.addr[0].ip.sa_family != AF_UNSPEC) { uint8_t *addr = kr_nsrep_inaddr(qry->ns.addr[0]); size_t addr_len = kr_nsrep_inaddr_len(qry->ns.addr[0]); - knot_rdata_t rdata[knot_rdata_array_size(addr_len)]; - knot_rdata_init(rdata, addr_len, addr, 0); - return kr_zonecut_del(&qry->zone_cut, qry->ns.name, rdata); + /* @warning _NOT_ thread-safe */ + static knot_rdata_t rdata_arr[RDATA_ARR_MAX]; + knot_rdata_init(rdata_arr, addr_len, addr, 0); + return kr_zonecut_del(&qry->zone_cut, qry->ns.name, rdata_arr); } else { return kr_zonecut_del(&qry->zone_cut, qry->ns.name, NULL); } diff --git a/lib/resolve.h b/lib/resolve.h index 20d589d5bb7c0c68a45211665232902681f0afb7..905e134e003c123b5cd613871f6e695e8304219a 100644 --- a/lib/resolve.h +++ b/lib/resolve.h @@ -132,6 +132,7 @@ struct kr_request { * @param answer allocated packet for final answer * @return CONSUME (expecting query) */ +KR_EXPORT int kr_resolve_begin(struct kr_request *request, struct kr_context *ctx, knot_pkt_t *answer); /** @@ -144,6 +145,7 @@ int kr_resolve_begin(struct kr_request *request, struct kr_context *ctx, knot_pk * @param packet [in] input packet * @return any state */ +KR_EXPORT int kr_resolve_consume(struct kr_request *request, const struct sockaddr *src, knot_pkt_t *packet); /** @@ -159,6 +161,7 @@ int kr_resolve_consume(struct kr_request *request, const struct sockaddr *src, k * @param packet [out] packet to be filled with additional query * @return any state */ +KR_EXPORT int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *type, knot_pkt_t *packet); /** @@ -171,6 +174,7 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t * @param state either DONE or FAIL state * @return DONE */ +KR_EXPORT int kr_resolve_finish(struct kr_request *request, int state); /** @@ -178,6 +182,7 @@ int kr_resolve_finish(struct kr_request *request, int state); * @param request request state * @return pointer to rplan */ +KR_EXPORT KR_PURE struct kr_rplan *kr_resolve_plan(struct kr_request *request); /** @@ -185,5 +190,6 @@ struct kr_rplan *kr_resolve_plan(struct kr_request *request); * @param request request state * @return mempool */ +KR_EXPORT KR_PURE mm_ctx_t *kr_resolve_pool(struct kr_request *request); diff --git a/lib/rplan.c b/lib/rplan.c index db6bad1646a7e69018d2debe865fe2e53789c1dc..8bae41cd1dab5e67bfab02c9b43c5a30db12ffbd 100644 --- a/lib/rplan.c +++ b/lib/rplan.c @@ -36,6 +36,11 @@ const lookup_table_t query_flag_names[] = { { 0, NULL } }; +const lookup_table_t *kr_query_flag_names(void) +{ + return query_flag_names; +} + static struct kr_query *query_create(mm_ctx_t *pool, const knot_dname_t *name) { if (name == NULL) { diff --git a/lib/rplan.h b/lib/rplan.h index 86fd061dbeed5791a5827ea965e5a24fde706f81..0d05269c755d4c7e1140675489af4a1a7ddd866a 100644 --- a/lib/rplan.h +++ b/lib/rplan.h @@ -54,7 +54,8 @@ enum kr_query_flag { }; /** Query flag names table */ -extern const lookup_table_t query_flag_names[]; +KR_EXPORT KR_CONST +const lookup_table_t *kr_query_flag_names(void); /** * Single query representation. @@ -94,12 +95,14 @@ struct kr_rplan { * @param request resolution request * @param pool ephemeral memory pool for whole resolution */ +KR_EXPORT int kr_rplan_init(struct kr_rplan *rplan, struct kr_request *request, mm_ctx_t *pool); /** * Deinitialize resolution plan, aborting any uncommited transactions. * @param rplan plan instance */ +KR_EXPORT void kr_rplan_deinit(struct kr_rplan *rplan); /** @@ -107,6 +110,7 @@ void kr_rplan_deinit(struct kr_rplan *rplan); * @param rplan plan instance * @return true or false */ +KR_EXPORT KR_PURE bool kr_rplan_empty(struct kr_rplan *rplan); /** @@ -119,6 +123,7 @@ bool kr_rplan_empty(struct kr_rplan *rplan); * @param type resolved type * @return query instance or NULL */ +KR_EXPORT struct kr_query *kr_rplan_push(struct kr_rplan *rplan, struct kr_query *parent, const knot_dname_t *name, uint16_t cls, uint16_t type); @@ -129,15 +134,19 @@ struct kr_query *kr_rplan_push(struct kr_rplan *rplan, struct kr_query *parent, * @param qry resolved query * @return 0 or an error */ +KR_EXPORT int kr_rplan_pop(struct kr_rplan *rplan, struct kr_query *qry); /** * Return true if resolution chain satisfies given query. */ +KR_EXPORT KR_PURE bool kr_rplan_satisfies(struct kr_query *closure, const knot_dname_t *name, uint16_t cls, uint16_t type); /** Return last resolved query. */ +KR_EXPORT KR_PURE struct kr_query *kr_rplan_resolved(struct kr_rplan *rplan); /** Return query predecessor. */ +KR_EXPORT KR_PURE struct kr_query *kr_rplan_next(struct kr_query *qry); \ No newline at end of file diff --git a/lib/utils.c b/lib/utils.c index 75cd81a080613a2a79df45115936da4dc991ff55..b2511754411bc79cd4cee7136a2355624392c05c 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -17,15 +17,15 @@ #include <stdarg.h> #include <string.h> #include <stdlib.h> -#include <unistd.h> #include <stdio.h> #include <arpa/inet.h> #include <sys/time.h> +#include <contrib/cleanup.h> +#include <ccan/isaac/isaac.h> #include <libknot/descriptor.h> #include <libknot/dname.h> #include <libknot/rrtype/rrsig.h> -#include "ccan/isaac/isaac.h" #include "lib/defines.h" #include "lib/utils.h" #include "lib/generic/array.h" @@ -34,7 +34,7 @@ #include "lib/resolve.h" /* Logging & debugging */ -bool _env_debug = false; +static bool _env_debug = false; /** @internal CSPRNG context */ static isaac_ctx ISAAC; @@ -64,19 +64,26 @@ static inline int u16tostr(uint8_t *dst, uint16_t num) /* * Cleanup callbacks. */ -void _cleanup_free(char **p) + +bool kr_debug_set(bool status) { - free(*p); + return _env_debug = status; } -void _cleanup_close(int *p) +bool kr_debug_status(void) { - if (*p > 0) close(*p); + return _env_debug; } -void _cleanup_fclose(FILE **p) +void kr_log_debug(const char *fmt, ...) { - if (*p) fclose(*p); + if (_env_debug) { + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + fflush(stdout); + } } char* kr_strcatdup(unsigned n, ...) @@ -163,7 +170,7 @@ unsigned kr_rand_uint(unsigned max) return isaac_next_uint(&ISAAC, max); } -int mm_reserve(void *baton, char **mem, size_t elm_size, size_t want, size_t *have) +int kr_memreserve(void *baton, char **mem, size_t elm_size, size_t want, size_t *have) { if (*have >= want) { return 0; @@ -205,8 +212,10 @@ int kr_pkt_put(knot_pkt_t *pkt, const knot_dname_t *name, uint32_t ttl, /* Create empty RR */ knot_rrset_t rr; knot_rrset_init(&rr, knot_dname_copy(name, &pkt->mm), rtype, rclass); - /* Create RDATA */ - knot_rdata_t rdata_arr[knot_rdata_array_size(rdlen)]; + /* Create RDATA + * @warning _NOT_ thread safe. + */ + static knot_rdata_t rdata_arr[RDATA_ARR_MAX]; knot_rdata_init(rdata_arr, rdlen, rdata, ttl); knot_rdataset_add(&rr.rrs, rdata_arr, &pkt->mm); /* Append RR */ @@ -304,7 +313,7 @@ int kr_bitcmp(const char *a, const char *b, int bits) return ret; } -int kr_rrmap_key(char *key, const knot_dname_t *owner, uint16_t type, uint8_t rank) +int kr_rrkey(char *key, const knot_dname_t *owner, uint16_t type, uint8_t rank) { if (!key || !owner) { return kr_error(EINVAL); @@ -330,7 +339,7 @@ int kr_rrmap_add(map_t *stash, const knot_rrset_t *rr, uint8_t rank, mm_ctx_t *p } /* Stash key = {[1] flags, [1-255] owner, [5] type, [1] \x00 } */ - char key[RRMAP_KEYSIZE]; + char key[KR_RRKEY_LEN]; uint8_t extra_flags = 0; uint16_t rrtype = rr->type; /* Stash RRSIGs in a special cache, flag them and set type to its covering RR. @@ -339,7 +348,7 @@ int kr_rrmap_add(map_t *stash, const knot_rrset_t *rr, uint8_t rank, mm_ctx_t *p rrtype = knot_rrsig_type_covered(&rr->rrs, 0); extra_flags |= KEY_FLAG_RRSIG; } - int ret = kr_rrmap_key(key, rr->owner, rrtype, rank); + int ret = kr_rrkey(key, rr->owner, rrtype, rank); if (ret <= 0) { return kr_error(EILSEQ); } @@ -360,7 +369,7 @@ int kr_rrmap_add(map_t *stash, const knot_rrset_t *rr, uint8_t rank, mm_ctx_t *p int kr_rrarray_add(rr_array_t *array, const knot_rrset_t *rr, mm_ctx_t *pool) { - int ret = array_reserve_mm(*array, array->len + 1, mm_reserve, pool); + int ret = array_reserve_mm(*array, array->len + 1, kr_memreserve, pool); if (ret != 0) { return kr_error(ENOMEM); } diff --git a/lib/utils.h b/lib/utils.h index cfa789cedc6a44b01bf8bd4fee38113909a71857..d47dce3b6cec0814b9baf1610ce44abf7cd0ffa0 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -23,38 +23,22 @@ #include "lib/generic/map.h" #include "lib/generic/array.h" -/* - * General-purpose attributes. - * @cond internal - */ -#define auto_free __attribute__((cleanup(_cleanup_free))) -extern void _cleanup_free(char **p); -#define auto_close __attribute__((cleanup(_cleanup_close))) -extern void _cleanup_close(int *p); -#define auto_fclose __attribute__((cleanup(_cleanup_fclose))) -extern void _cleanup_fclose(FILE **p); -/* @endcond */ - /* * Logging and debugging. */ -#define log_info(fmt, ...) printf((fmt), ## __VA_ARGS__) -#define log_error(fmt, ...) fprintf(stderr, (fmt), ## __VA_ARGS__) +#define kr_log_info(fmt, ...) printf((fmt), ## __VA_ARGS__) +#define kr_log_error(fmt, ...) fprintf(stderr, (fmt), ## __VA_ARGS__) #ifndef NDEBUG -extern bool _env_debug; /* @internal cond variable */ /* Toggle debug messages */ -#define log_debug_enable(x) _env_debug = (x) -#define log_debug_status() _env_debug -/* Message logging */ -#define log_debug(fmt, ...) do { \ - if (_env_debug) { printf((fmt), ## __VA_ARGS__); fflush(stdout); } \ - } while (0) +KR_EXPORT bool kr_debug_set(bool status); +KR_EXPORT KR_PURE bool kr_debug_status(void); +KR_EXPORT void kr_log_debug(const char *fmt, ...); /* Debug block */ -#define WITH_DEBUG if(__builtin_expect(_env_debug, 0)) +#define WITH_DEBUG if(__builtin_expect(kr_debug_status(), 0)) #else -#define log_debug_status() false -#define log_debug_enable(x) -#define log_debug(fmt, ...) +#define kr_debug_status() false +#define kr_debug_set(x) +#define kr_log_debug(fmt, ...) #define WITH_DEBUG if(0) #endif @@ -77,51 +61,71 @@ struct kr_context; typedef array_t(knot_rrset_t *) rr_array_t; /* @endcond */ +/** @internal RDATA array maximum size. */ +#define RDATA_ARR_MAX (UINT16_MAX + sizeof(uint64_t)) /** @internal Next RDATA shortcut. */ #define kr_rdataset_next(rd) (rd + knot_rdata_array_size(knot_rdata_rdlen(rd))) /** Concatenate N strings. */ +KR_EXPORT char* kr_strcatdup(unsigned n, ...); /** Reseed CSPRNG context. */ int kr_rand_reseed(void); /** Get pseudo-random value. */ +KR_EXPORT unsigned kr_rand_uint(unsigned max); /** Memory reservation routine for mm_ctx_t */ -int mm_reserve(void *baton, char **mem, size_t elm_size, size_t want, size_t *have); +KR_EXPORT +int kr_memreserve(void *baton, char **mem, size_t elm_size, size_t want, size_t *have); /** @internal Fast packet reset. */ +KR_EXPORT int kr_pkt_recycle(knot_pkt_t *pkt); /** Construct and put record to packet. */ +KR_EXPORT int kr_pkt_put(knot_pkt_t *pkt, const knot_dname_t *name, uint32_t ttl, uint16_t rclass, uint16_t rtype, const uint8_t *rdata, uint16_t rdlen); /** Address bytes for given family. */ +KR_EXPORT KR_PURE const char *kr_inaddr(const struct sockaddr *addr); /** Address length for given family. */ +KR_EXPORT KR_PURE int kr_inaddr_len(const struct sockaddr *addr); /** Return address type for string. */ +KR_EXPORT KR_PURE int kr_straddr_family(const char *addr); /** Return address length in given family. */ +KR_EXPORT KR_CONST int kr_family_len(int family); /** Parse address and return subnet length (bits). * @warning 'dst' must be at least `sizeof(struct in6_addr)` long. */ +KR_EXPORT int kr_straddr_subnet(void *dst, const char *addr); /** Compare memory bitwise. */ +KR_EXPORT KR_PURE int kr_bitcmp(const char *a, const char *b, int bits); /** @internal RR map flags. */ #define KEY_FLAG_RRSIG 0x02 #define KEY_FLAG_RANK(key) (key[0] >> 2) #define KEY_COVERING_RRSIG(key) (key[0] & KEY_FLAG_RRSIG) -/* Stash key = {[1] flags, [1-255] owner, [5] type, [1] \x00 } */ -#define RRMAP_KEYSIZE (9 + KNOT_DNAME_MAXLEN) -/** @internal Create unique string key for RR. */ -int kr_rrmap_key(char *key, const knot_dname_t *owner, uint16_t type, uint8_t rank); +/* Stash key = {[1] flags, [1-255] owner, [5] type, [1] \x00 } */ +#define KR_RRKEY_LEN (9 + KNOT_DNAME_MAXLEN) +/** Create unique null-terminated string key for RR. + * @param key Destination buffer for key size, MUST be KR_RRKEY_LEN or larger. + * @param owner RR owner domain name. + * @param type RR type. + * @param rank RR rank (8 bit tag usable for anything). + * @return key length if successful or an error + * */ +KR_EXPORT +int kr_rrkey(char *key, const knot_dname_t *owner, uint16_t type, uint8_t rank); /** @internal Merges RRSets with matching owner name and type together. * @note RRSIG RRSets are merged according the type covered fields. @@ -135,4 +139,5 @@ int kr_rrarray_add(rr_array_t *array, const knot_rrset_t *rr, mm_ctx_t *pool); /** * Call module property. */ +KR_EXPORT char *kr_module_call(struct kr_context *ctx, const char *module, const char *prop, const char *input); diff --git a/lib/zonecut.c b/lib/zonecut.c index ca120b7e52ac741b1b5e16481de115e7aab40a2f..05e18a9cf8eab42977541409152c211bb3fd3990 100644 --- a/lib/zonecut.c +++ b/lib/zonecut.c @@ -223,7 +223,7 @@ int kr_zonecut_add(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rd return kr_ok(); } /* Push new address */ - int ret = pack_reserve_mm(*pack, 1, rdlen, mm_reserve, cut->pool); + int ret = pack_reserve_mm(*pack, 1, rdlen, kr_memreserve, cut->pool); if (ret != 0) { return kr_error(ENOMEM); } @@ -271,6 +271,8 @@ int kr_zonecut_set_sbelt(struct kr_context *ctx, struct kr_zonecut *cut) if (!ctx || !cut) { return kr_error(EINVAL); } + /* @warning _NOT_ thread-safe */ + static knot_rdata_t rdata_arr[RDATA_ARR_MAX]; update_cut_name(cut, U8("")); map_walk(&cut->nsset, free_addr_set, cut->pool); @@ -284,9 +286,8 @@ int kr_zonecut_set_sbelt(struct kr_context *ctx, struct kr_zonecut *cut) /* Copy compiled-in root hints */ for (unsigned i = 0; i < HINT_COUNT; ++i) { const struct hint_info *hint = &SBELT[i]; - knot_rdata_t rdata[knot_rdata_array_size(hint->len)]; - knot_rdata_init(rdata, hint->len, hint->addr, 0); - ret = kr_zonecut_add(cut, hint->name, rdata); + knot_rdata_init(rdata_arr, hint->len, hint->addr, 0); + ret = kr_zonecut_add(cut, hint->name, rdata_arr); if (ret != 0) { break; } diff --git a/lib/zonecut.h b/lib/zonecut.h index a3eca008225a287cc1a4e46fae13ba8852e979f0..64ebd7b5b998b325171ef1faa2f416138ed0e570 100644 --- a/lib/zonecut.h +++ b/lib/zonecut.h @@ -18,6 +18,7 @@ #include "lib/generic/map.h" #include "lib/generic/pack.h" +#include "lib/defines.h" #include "lib/cache.h" struct kr_rplan; @@ -42,12 +43,14 @@ struct kr_zonecut { * @param pool * @return 0 or error code */ +KR_EXPORT int kr_zonecut_init(struct kr_zonecut *cut, const knot_dname_t *name, mm_ctx_t *pool); /** * Clear the structure and free the address set. * @param cut zone cut */ +KR_EXPORT void kr_zonecut_deinit(struct kr_zonecut *cut); /** @@ -56,6 +59,7 @@ void kr_zonecut_deinit(struct kr_zonecut *cut); * @param cut zone cut to be set * @param name new zone cut name */ +KR_EXPORT void kr_zonecut_set(struct kr_zonecut *cut, const knot_dname_t *name); /** @@ -64,6 +68,7 @@ void kr_zonecut_set(struct kr_zonecut *cut, const knot_dname_t *name); * @param src source zone cut * @return 0 or an error code */ +KR_EXPORT int kr_zonecut_copy(struct kr_zonecut *dst, const struct kr_zonecut *src); /** @@ -72,6 +77,7 @@ int kr_zonecut_copy(struct kr_zonecut *dst, const struct kr_zonecut *src); * @param src source zone cut * @return 0 or an error code */ +KR_EXPORT int kr_zonecut_copy_trust(struct kr_zonecut *dst, const struct kr_zonecut *src); /** @@ -85,6 +91,7 @@ int kr_zonecut_copy_trust(struct kr_zonecut *dst, const struct kr_zonecut *src); * @param rdata nameserver address (as rdata) * @return 0 or error code */ +KR_EXPORT int kr_zonecut_add(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rdata_t *rdata); /** @@ -94,6 +101,7 @@ int kr_zonecut_add(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rd * @param rdata name server address * @return 0 or error code */ +KR_EXPORT int kr_zonecut_del(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rdata_t *rdata); /** @@ -106,6 +114,7 @@ int kr_zonecut_del(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rd * @param ns name server name * @return pack of addresses or NULL */ +KR_EXPORT KR_PURE pack_t *kr_zonecut_find(struct kr_zonecut *cut, const knot_dname_t *ns); /** @@ -115,6 +124,7 @@ pack_t *kr_zonecut_find(struct kr_zonecut *cut, const knot_dname_t *ns); * @param cut zone cut to be populated * @return 0 or error code */ +KR_EXPORT int kr_zonecut_set_sbelt(struct kr_context *ctx, struct kr_zonecut *cut); /** @@ -128,5 +138,6 @@ int kr_zonecut_set_sbelt(struct kr_context *ctx, struct kr_zonecut *cut); * @param secured set to true if want secured zone cut, will return false if it is provably insecure * @return 0 or error code (ENOENT if it doesn't find anything) */ +KR_EXPORT int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name, struct kr_cache_txn *txn, uint32_t timestamp, bool * restrict secured); diff --git a/modules/cachectl/cachectl.mk b/modules/cachectl/cachectl.mk index 6707dbdca13ee5258270c1956ac8d7cdd63f6b88..f39cfa60a3c06df82872424c01e515cc7d8c0674 100644 --- a/modules/cachectl/cachectl.mk +++ b/modules/cachectl/cachectl.mk @@ -1,5 +1,5 @@ -cachectl_CFLAGS := -fvisibility=hidden +cachectl_CFLAGS := -fvisibility=hidden -fPIC cachectl_SOURCES := modules/cachectl/cachectl.c cachectl_DEPEND := $(libkres) -cachectl_LIBS := $(libkres_TARGET) $(libkres_LIBS) +cachectl_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS) $(call make_c_module,cachectl) \ No newline at end of file diff --git a/modules/hints/hints.c b/modules/hints/hints.c index 99667e9bfd2dbd91498c25fc9fcfb99624082ff3..03c13ce0699e6bea705f9731d815ad9bab4866bb 100644 --- a/modules/hints/hints.c +++ b/modules/hints/hints.c @@ -26,6 +26,7 @@ #include <libknot/rrtype/aaaa.h> #include <ccan/json/json.h> #include <ucw/mempool.h> +#include <contrib/cleanup.h> #include "daemon/engine.h" #include "lib/zonecut.h" @@ -230,13 +231,13 @@ static int add_pair(struct kr_zonecut *hints, const char *name, const char *addr return kr_error(EINVAL); } - /* Build rdata */ - size_t addr_len = 0; - uint8_t *raw_addr = sockaddr_raw(&ss, &addr_len); - knot_rdata_t rdata[knot_rdata_array_size(addr_len)]; - knot_rdata_init(rdata, addr_len, raw_addr, 0); - - return kr_zonecut_add(hints, key, rdata); + /* Build RDATA */ + size_t addr_len = kr_inaddr_len((struct sockaddr *)&ss); + const uint8_t *raw_addr = (const uint8_t *)kr_inaddr((struct sockaddr *)&ss); + /* @warning _NOT_ thread-safe */ + static knot_rdata_t rdata_arr[RDATA_ARR_MAX]; + knot_rdata_init(rdata_arr, addr_len, raw_addr, 0); + return kr_zonecut_add(hints, key, rdata_arr); } static int load_map(struct kr_zonecut *hints, FILE *fp) diff --git a/modules/hints/hints.mk b/modules/hints/hints.mk index c726391189068189237c857bc720e533971f73af..c7bb521be5536c35e76ab7e3ea3e43966dd405e4 100644 --- a/modules/hints/hints.mk +++ b/modules/hints/hints.mk @@ -1,5 +1,5 @@ -hints_CFLAGS := -fvisibility=hidden +hints_CFLAGS := -fvisibility=hidden -fPIC hints_SOURCES := modules/hints/hints.c hints_DEPEND := $(libkres) -hints_LIBS := $(libkres_TARGET) $(libkres_LIBS) +hints_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS) $(call make_c_module,hints) \ No newline at end of file diff --git a/modules/kmemcached/kmemcached.mk b/modules/kmemcached/kmemcached.mk index 87462a707135922d59cb6220a16f276ee09ba85e..148bd5952918d8bf227f1f510cb0860941143673 100644 --- a/modules/kmemcached/kmemcached.mk +++ b/modules/kmemcached/kmemcached.mk @@ -1,4 +1,4 @@ -kmemcached_CFLAGS := -fvisibility=hidden +kmemcached_CFLAGS := -fvisibility=hidden -fPIC kmemcached_SOURCES := modules/kmemcached/kmemcached.c modules/kmemcached/namedb_memcached.c kmemcached_LIBS := $(libkres_TARGET) $(libkres_LIBS) $(libmemcached_LIBS) $(call make_c_module,kmemcached) diff --git a/modules/redis/redis.mk b/modules/redis/redis.mk index 765f231aeef5060980edbad8ac45d3c47ca54b8a..2cb4463a7e0fd2a2cdcf7e85ca62945056858133 100644 --- a/modules/redis/redis.mk +++ b/modules/redis/redis.mk @@ -1,4 +1,4 @@ -redis_CFLAGS := -fvisibility=hidden +redis_CFLAGS := -fvisibility=hidden -fPIC redis_SOURCES := modules/redis/redis.c modules/redis/namedb_redis.c redis_LIBS := $(libkres_TARGET) $(libkres_LIBS) $(hiredis_LIBS) $(libuv_LIBS) $(call make_c_module,redis) diff --git a/modules/stats/stats.c b/modules/stats/stats.c index 11c1c8a33edccb3f52cfc12edb78c0564c9b0911..2b3e6219e7a4f25747a18cddbd3c0793a6528184 100644 --- a/modules/stats/stats.c +++ b/modules/stats/stats.c @@ -24,6 +24,7 @@ #include <libknot/packet/pkt.h> #include <ccan/json/json.h> +#include <contrib/cleanup.h> #include "lib/layer/iterate.h" #include "lib/rplan.h" diff --git a/modules/stats/stats.mk b/modules/stats/stats.mk index ef8a55e8304701625f5fed1a9205c9959f04eaf3..17e462472787a02baaaf19007af1b8f7e647b213 100644 --- a/modules/stats/stats.mk +++ b/modules/stats/stats.mk @@ -1,5 +1,5 @@ -stats_CFLAGS := -fvisibility=hidden +stats_CFLAGS := -fvisibility=hidden -fPIC stats_SOURCES := modules/stats/stats.c -stats_DEPEND := $(libkres) -stats_LIBS := $(libkres_TARGET) $(libkres_LIBS) +stats_DEPEND := $(libkres) $(contrib) +stats_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS) $(call make_c_module,stats) diff --git a/platform.mk b/platform.mk index 182755389ea68cd0dc7ad4a0bbdfbf237690e2f1..dd01c96841f3469dfc9ec549758f52e1ee86ce1c 100644 --- a/platform.mk +++ b/platform.mk @@ -2,6 +2,7 @@ # Don't touch this unless you're changing the way targets are compiled # You have been warned +# Platform-dependent stuff checks CCLD := $(CC) CGO := go tool cgo GO := go @@ -15,6 +16,10 @@ ARTYPE := static BINEXT := PLATFORM = Linux ARCH := $(word 1, $(subst -, ,$(shell $(CC) -dumpmachine))) +# Library versioning flags (platform-specific) +SOVER = +# Library versioned extension (platform-specific) +SOVER_EXT = $(LIBEXT).$(1) ifeq ($(OS),Windows_NT) PLATFORM := Windows RM := del @@ -27,9 +32,21 @@ else PLATFORM := Darwin LIBEXT := .dylib MODTYPE := dynamiclib + # OS X specific hardening since -pie doesn't work + ifneq ($(HARDENING),no) + BINFLAGS += -Wl,-pie + endif + # Version is prepended to dylib + SOVER_EXT = .$(1)$(LIBEXT) + SOVER = $(if $(1), -compatibility_version $(2) -current_version $(1),) else PLATFORM := POSIX LDFLAGS += -pthread -lm -Wl,-E + # ELF hardening options + ifneq ($(HARDENING),no) + BINFLAGS += -pie + LDFLAGS += -Wl,-z,relro,-z,now + endif ifeq (,$(findstring BSD,$(UNAME))) LDFLAGS += -ldl endif @@ -41,16 +58,12 @@ ifeq ($(V),1) quiet = $($1) else quiet = @echo " $1 $2"; $($1) -endif - -%.o: %.c - $(call quiet,CC,$<) $(BUILD_CFLAGS) -MMD -MP -c $< -o $@ +endif # Make objects and depends (name) define make_objs $(1)_OBJ := $$($(1)_SOURCES:.c=.o) $(1)_DEP := $$($(1)_SOURCES:.c=.d) - -include $$($(1)_DEP) endef @@ -67,23 +80,34 @@ endif else $$(eval $$(call make_objs,$(1))) endif +# Rules to generate objects with custom CFLAGS and binary/library +$$($(1)_OBJ): $$($(1)_SOURCES) + $(call quiet,CC,$$(@:%.o=%.c)) $(BUILD_CFLAGS) $$($(1)_CFLAGS) -MMD -MP -c $$(@:%.o=%.c) -o $$@ $(1) := $(2)/$(1)$(3) $(2)/$(1)$(3): $$($(1)_OBJ) $$($(1)_DEPEND) ifeq ($(4),-$(ARTYPE)) $(call quiet,AR,$$@) rcs $$@ $$($(1)_OBJ) else - $(call quiet,CCLD,$$@) $(BUILD_CFLAGS) $$($(1)_CFLAGS) $$($(1)_OBJ) -o $$@ $(4) $$($(1)_LIBS) $(BUILD_LDFLAGS) + $(call quiet,CCLD,$$@) $$($(1)_CFLAGS) $(BUILD_CFLAGS) $$($(1)_OBJ) $(call SOVER,$(7),$(7)) -o $$@ $(4) $$($(1)_LIBS) $(BUILD_LDFLAGS) $$($(1)_LDFLAGS) endif +# Additional rules $(1)-clean: $(RM) $$($(1)_OBJ) $$($(1)_DEP) $(2)/$(1)$(3) ifeq ($(6), yes) $(RM) $(1).amalg.c $(1).amalg.o endif $(1)-install: $(2)/$(1)$(3) +# Modules install to special path ifneq ($(5),$(MODULEDIR)) $(INSTALL) -d $(DESTDIR)$(5) endif +# Versioned library install +ifneq ($(strip $(7)),) + $(INSTALL) $(2)/$(1)$(3) $(DESTDIR)$(5)/$(1)$(call SOVER_EXT,$(7)) + $(LN) -f $(1)$(call SOVER_EXT,$(7)) $(DESTDIR)$(5)/$(1)$(3) +else $(INSTALL) $(2)/$(1)$(3) $(DESTDIR)$(5) +endif ifneq ($$(strip $$($(1)_HEADERS)),) $(INSTALL) -d $(DESTDIR)$(INCLUDEDIR)/$(1) $(INSTALL) -m 644 $$($(1)_HEADERS) $(DESTDIR)$(INCLUDEDIR)/$(1) @@ -91,9 +115,9 @@ endif .PHONY: $(1)-clean $(1)-install endef -# Make targets (name,path,amalgable yes|no) +# Make targets (name,path,amalgable yes|no,abiver) make_bin = $(call make_target,$(1),$(2),$(BINEXT),$(BINFLAGS),$(BINDIR),$(3)) -make_lib = $(call make_target,$(1),$(2),$(LIBEXT),-$(LIBTYPE),$(LIBDIR),$(3)) +make_lib = $(call make_target,$(1),$(2),$(LIBEXT),-$(LIBTYPE),$(LIBDIR),$(3),$(4)) make_module = $(call make_target,$(1),$(2),$(LIBEXT),-$(LIBTYPE),$(MODULEDIR),$(3)) make_shared = $(call make_target,$(1),$(2),$(MODEXT),-$(MODTYPE),$(LIBDIR),$(3)) make_static = $(call make_target,$(1),$(2),$(AREXT),-$(ARTYPE),$(LIBDIR),$(3)) diff --git a/scripts/kresd.apparmor b/scripts/kresd.apparmor new file mode 100644 index 0000000000000000000000000000000000000000..81fa5a1e3b73908c1fce9d2c51c89a739c6be4a8 --- /dev/null +++ b/scripts/kresd.apparmor @@ -0,0 +1,30 @@ +#include <tunables/global> + +/usr/bin/kresd { + #include <abstractions/base> + #include <abstractions/nameservice> + capability net_bind_service, + capability setgid, + capability setuid, + # seems to be needed during start to read /var/lib/kresd + # while we still run as root. + capability dac_override, + + network tcp, + network udp, + + /proc/sys/net/core/somaxconn r, + /etc/kresd/* r, + /var/lib/kresd/ r, + /var/lib/kresd/** rwlk, + + # modules + /usr/lib{,64}/kdns_modules/*.lua r, + /usr/lib{,64}/kdns_modules/*.so rm, + + # for tinyweb + /usr/lib{,64}/kdns_modules/tinyweb/ r, + /usr/lib{,64}/kdns_modules/tinyweb/* r, + /var/lib/GeoIP/* r, +} + diff --git a/scripts/kresd.service b/scripts/kresd.service new file mode 100644 index 0000000000000000000000000000000000000000..b6a00ad5cda1c208c4bf94ec5066584c699eecaf --- /dev/null +++ b/scripts/kresd.service @@ -0,0 +1,12 @@ +[Unit] +Description=Knot DNS Resolver daemon +After=syslog.target network.target auditd.service + +[Service] +Type=simple +EnvironmentFile=-/etc/sysconfig/kresd +ExecStart=/usr/bin/kresd -c /etc/kresd/config -f $KRESD_WORKERS $KRESD_OPTIONS /var/lib/kresd/ +Restart=on-abort + +[Install] +WantedBy=multi-user.target diff --git a/scripts/kresd.sysconfig b/scripts/kresd.sysconfig new file mode 100644 index 0000000000000000000000000000000000000000..ceb5e3068a44d38161979ab78e4e8ff2f26d7aa4 --- /dev/null +++ b/scripts/kresd.sysconfig @@ -0,0 +1,14 @@ +## Path: System/DNS +## Description: Number of worker processes to spawn +## Type: integer +## Default: 1 +## ServiceRestart: kresd +## +# +# Number of workers to spawn for kresd. +# If you get start up failures with "already in use" your libuv is too +# old and you have to stick to 1. +# +KRESD_WORKERS=1 +# Additional options +KRESD_OPTIONS= diff --git a/tests/test_utils.c b/tests/test_utils.c index f4e1b582eb1c7edfaba1b546fb6bbe3685a465aa..c874ef8d68649103235b2fd0e84534db4725acd8 100644 --- a/tests/test_utils.c +++ b/tests/test_utils.c @@ -16,6 +16,7 @@ #include <sys/socket.h> #include <stdio.h> +#include <contrib/cleanup.h> #include "tests/test.h" #include "lib/utils.h" diff --git a/tests/unit.mk b/tests/unit.mk index 98967130bee91537a5a98a8b24ea05c710fa3bc8..9e16890957a31c79f127c5e5956a439efa25f170 100644 --- a/tests/unit.mk +++ b/tests/unit.mk @@ -14,6 +14,7 @@ tests_BIN := \ test_zonecut \ test_rplan +mock_cmodule_CFLAGS := -fPIC mock_cmodule_SOURCES := tests/mock_cmodule.c $(eval $(call make_lib,mock_cmodule,tests)) @@ -21,14 +22,22 @@ $(eval $(call make_lib,mock_cmodule,tests)) tests_DEPEND := $(libkres) $(mock_cmodule) $(mock_gomodule) tests_LIBS := $(libkres_TARGET) $(libkres_LIBS) $(cmocka_LIBS) +# Platform-specific library injection +ifeq ($(PLATFORM),Darwin) + preload_syms := DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_LIBRARY_PATH="$(DYLD_LIBRARY_PATH):$(abspath lib)" +else + preload_syms := LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):$(abspath lib)" +endif + # Make test binaries define make_test +$(1)_CFLAGS := -fPIE $(1)_SOURCES := tests/$(1).c $(1)_LIBS := $(tests_LIBS) $(1)_DEPEND := $(tests_DEPEND) $(call make_bin,$(1),tests) $(1): $$($(1)) - @$$< + @$(preload_syms) $$< .PHONY: $(1) endef