diff --git a/.gitignore b/.gitignore index d5c14f297646180b61e8e01ac9b20448228bdbe7..7579e289674a903ab64b6ef5c118cbf4f8c63377 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,6 @@ .libs .deps _obj -tmp* /autom4te.cache/* /config.log /config.h diff --git a/daemon/main.c b/daemon/main.c index de1c9605dba90c58c513f838777e1eff7ea61620..5bf56c726f28dba5fd09aaa85145c76a36619c81 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -321,7 +321,7 @@ static struct worker_ctx *init_worker(struct engine *engine, knot_mm_t *pool, in return worker; } -static int run_worker(uv_loop_t *loop, struct engine *engine, fd_array_t *ipc_set, bool leader) +static int run_worker(uv_loop_t *loop, struct engine *engine, fd_array_t *ipc_set, bool leader, int control_fd) { /* Control sockets or TTY */ auto_free char *sock_file = NULL; @@ -335,12 +335,18 @@ static int run_worker(uv_loop_t *loop, struct engine *engine, fd_array_t *ipc_se uv_pipe_open(&pipe, 0); uv_read_start((uv_stream_t*) &pipe, tty_alloc, tty_read); } else { - (void) mkdir("tty", S_IRWXU|S_IRWXG); - sock_file = afmt("tty/%ld", getpid()); - if (sock_file) { - uv_pipe_bind(&pipe, sock_file); - uv_listen((uv_stream_t *) &pipe, 16, tty_accept); + int pipe_ret = -1; + if (control_fd != -1) { + pipe_ret = uv_pipe_open(&pipe, control_fd); + } else { + (void) mkdir("tty", S_IRWXU|S_IRWXG); + sock_file = afmt("tty/%ld", getpid()); + if (sock_file) { + pipe_ret = uv_pipe_bind(&pipe, sock_file); + } } + if (!pipe_ret) + uv_listen((uv_stream_t *) &pipe, 16, tty_accept); } /* Watch IPC pipes (or just assign them if leading the pgroup). */ if (!leader) { @@ -364,6 +370,14 @@ static int run_worker(uv_loop_t *loop, struct engine *engine, fd_array_t *ipc_se return kr_ok(); } +void free_sd_socket_names(char **socket_names, int count) +{ + for (int i = 0; i < count; i++) { + free(socket_names[i]); + } + free(socket_names); +} + int main(int argc, char **argv) { int forks = 1; @@ -374,6 +388,7 @@ int main(int argc, char **argv) char *keyfile = NULL; const char *config = NULL; char *keyfile_buf = NULL; + int control_fd = -1; /* Long options. */ int c = 0, li = 0, ret = 0; @@ -457,11 +472,25 @@ int main(int argc, char **argv) #ifdef HAS_SYSTEMD /* Accept passed sockets from systemd supervisor. */ - int sd_nsocks = sd_listen_fds(0); + char **socket_names = NULL; + int sd_nsocks = sd_listen_fds_with_names(0, &socket_names); for (int i = 0; i < sd_nsocks; ++i) { int fd = SD_LISTEN_FDS_START + i; - array_push(fd_set, fd); + /* when run under systemd supervision, do not use interactive mode */ + g_interactive = false; + if (forks != 1) { + kr_log_error("[system] when run under systemd-style supervision, " + "use single-process only (bad: --fork=%d).\n", forks); + free_sd_socket_names(socket_names, sd_nsocks); + return EXIT_FAILURE; + } + if (!strcasecmp("control",socket_names[i])) { + control_fd = fd; + } else { + array_push(fd_set, fd); + } } + free_sd_socket_names(socket_names, sd_nsocks); #endif /* Switch to rundir. */ @@ -563,7 +592,7 @@ int main(int argc, char **argv) lua_settop(engine.L, 0); } /* Run the event loop */ - ret = run_worker(loop, &engine, &ipc_set, fork_id == 0); + ret = run_worker(loop, &engine, &ipc_set, fork_id == 0, control_fd); } } if (ret != 0) { diff --git a/doc/kresd.8.in b/doc/kresd.8.in index bd9e27afe5674f692f21dc1a844f38d865babe27..2fac891904918de28c2b9081e053d6b47b87c3ff 100644 --- a/doc/kresd.8.in +++ b/doc/kresd.8.in @@ -111,6 +111,10 @@ With this option, the daemon is started in non-interactive mode and instead crea UNIX socket in \fIrundir\fR that the operator can connect to for interactive session. A number greater than 1 forks the daemon N times, all forks will bind to same addresses and the kernel will load-balance between them on Linux with \fISO_REUSEPORT\fR support. + +When socket-activated and supervised by systemd or the equivalent, kresd defaults to +--forks=1, and must not be set to any other value. If you want multiple concurrent +processes supervised in this way, they should be supervised independently. .TP .B \-q\fR, \fB\-\-quiet Daemon will refrain from printing any informative messages, not even a prompt. diff --git a/scripts/kresd.service b/scripts/kresd.service deleted file mode 100644 index c28adaa76dea953e153ceb8d7c28e0274268a942..0000000000000000000000000000000000000000 --- a/scripts/kresd.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Knot DNS Resolver daemon -After=network.target - -[Service] -Type=simple -EnvironmentFile=-/etc/sysconfig/kresd -ExecStart=/usr/sbin/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 deleted file mode 100644 index ceb5e3068a44d38161979ab78e4e8ff2f26d7aa4..0000000000000000000000000000000000000000 --- a/scripts/kresd.sysconfig +++ /dev/null @@ -1,14 +0,0 @@ -## 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/systemd/README.md b/systemd/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8ddbdc17d41fb38ca88383f75c006ac5768bd740 --- /dev/null +++ b/systemd/README.md @@ -0,0 +1,23 @@ +Running Knot Resolver under systemd (or equivalent) socket activation +===================================================================== + +You can use the files in this directory to run kresd under supervision +by systemd (or any supervisor that provides equivalent file descriptor +initialization via the interface supported by +sd_listen_fds_with_names(3)). + +When run in this configuration: + + * it will be run under a non-privileged user, which means it will not + be able to open any new non-privileged ports. + + * it will use a single process (implicitly uses --forks=1, and will + fail if that configuration variable is set to a different value). + If you want multiple daemons to listen on these ports publicly + concurrently, you'll need the supervisor to manage them + differently, for example via a systemd generator: + + https://www.freedesktop.org/software/systemd/man/systemd.generator.html + + If you have a useful systemd generator for multiple concurrent + processes, please contribute it upstream! diff --git a/systemd/knot-resolver-control.socket b/systemd/knot-resolver-control.socket new file mode 100644 index 0000000000000000000000000000000000000000..9f1976e8e77c2b3d59b9703e96af7d7454ad3e65 --- /dev/null +++ b/systemd/knot-resolver-control.socket @@ -0,0 +1,13 @@ +[Unit] +Description=Knot DNS Resolver control socket +Documentation=man:kresd(8) +Before=sockets.target + +[Socket] +ListenStream=/run/knot-resolver/control +FileDescriptorName=control +Service=knot-resolver.service +SocketMode=0660 + +[Install] +WantedBy=sockets.target diff --git a/systemd/knot-resolver.service b/systemd/knot-resolver.service new file mode 100644 index 0000000000000000000000000000000000000000..927b06a6ea1991370c1c623d43e2ac96377b9866 --- /dev/null +++ b/systemd/knot-resolver.service @@ -0,0 +1,14 @@ +[Unit] +Description=Knot DNS Resolver daemon +## This is a socket-activated service: +RefuseManualStart=true + +[Service] +Type=notify +WorkingDirectory=/run/knot-resolver/cache +ExecStart=/usr/sbin/kresd +User=knot-resolver +Restart=on-failure + +[Install] +WantedBy=sockets.target diff --git a/systemd/knot-resolver.socket b/systemd/knot-resolver.socket new file mode 100644 index 0000000000000000000000000000000000000000..7d8953c233416474d5a082d78f9541a53cdefa4b --- /dev/null +++ b/systemd/knot-resolver.socket @@ -0,0 +1,13 @@ +[Unit] +Description=Knot DNS Resolver network listeners +Documentation=man:kresd(8) +Before=sockets.target + +[Socket] +ListenStream=[::1]:53 +ListenDatagram=[::1]:53 +ListenStream=127.0.0.1:53 +ListenDatagram=127.0.0.1:53 + +[Install] +WantedBy=sockets.target diff --git a/systemd/tmpfiles/knot-resolver.conf b/systemd/tmpfiles/knot-resolver.conf new file mode 100644 index 0000000000000000000000000000000000000000..6006f030e17fdb465904c997a549203485794c11 --- /dev/null +++ b/systemd/tmpfiles/knot-resolver.conf @@ -0,0 +1,7 @@ +# tmpfiles.d(5) runtime directory for knot-resolver (kresd) +#Type Path Mode UID GID Age Argument + d /run/knot-resolver 0750 root root - - + d /run/knot-resolver/cache 0750 knot-resolver knot-resolver - - + L /run/knot-resolver/cache/config 0750 knot-resolver knot-resolver - /etc/knot-resolver/kresd.conf + +