2024-12-10 20:26:33 +01:00
|
|
|
{
|
|
|
|
config,
|
|
|
|
lib,
|
|
|
|
pkgs,
|
|
|
|
...
|
|
|
|
}:
|
2017-01-25 18:41:52 +01:00
|
|
|
let
|
2020-02-05 19:18:11 +01:00
|
|
|
cfg = config.services.kresd;
|
2020-02-05 19:27:16 +01:00
|
|
|
|
|
|
|
# Convert systemd-style address specification to kresd config line(s).
|
|
|
|
# On Nix level we don't attempt to precisely validate the address specifications.
|
2022-01-05 15:58:27 +01:00
|
|
|
# The optional IPv6 scope spec comes *after* port, perhaps surprisingly.
|
2024-12-10 20:26:33 +01:00
|
|
|
mkListen =
|
|
|
|
kind: addr:
|
|
|
|
let
|
|
|
|
al_v4 = builtins.match "([0-9.]+):([0-9]+)($)" addr;
|
|
|
|
al_v6 = builtins.match "\\[(.+)]:([0-9]+)(%.*|$)" addr;
|
|
|
|
al_portOnly = builtins.match "(^)([0-9]+)" addr;
|
|
|
|
al =
|
|
|
|
lib.findFirst (a: a != null) (throw "services.kresd.*: incorrect address specification '${addr}'")
|
|
|
|
[
|
|
|
|
al_v4
|
|
|
|
al_v6
|
|
|
|
al_portOnly
|
|
|
|
];
|
|
|
|
port = lib.elemAt al 1;
|
|
|
|
addrSpec =
|
|
|
|
if al_portOnly == null then "'${lib.head al}${lib.elemAt al 2}'" else "{'::', '0.0.0.0'}";
|
|
|
|
in
|
|
|
|
# freebind is set for compatibility with earlier kresd services;
|
|
|
|
# it could be configurable, for example.
|
|
|
|
''
|
|
|
|
net.listen(${addrSpec}, ${port}, { kind = '${kind}', freebind = true })
|
|
|
|
'';
|
2020-02-05 19:27:16 +01:00
|
|
|
|
|
|
|
configFile = pkgs.writeText "kresd.conf" (
|
2020-11-12 19:04:12 +01:00
|
|
|
""
|
2024-08-24 22:05:53 +02:00
|
|
|
+ lib.concatMapStrings (mkListen "dns") cfg.listenPlain
|
|
|
|
+ lib.concatMapStrings (mkListen "tls") cfg.listenTLS
|
|
|
|
+ lib.concatMapStrings (mkListen "doh2") cfg.listenDoH
|
2020-02-05 19:27:16 +01:00
|
|
|
+ cfg.extraConfig
|
|
|
|
);
|
2024-12-10 20:26:33 +01:00
|
|
|
in
|
|
|
|
{
|
|
|
|
meta.maintainers = [
|
|
|
|
lib.maintainers.vcunat # upstream developer
|
|
|
|
];
|
2017-01-25 18:41:52 +01:00
|
|
|
|
2019-12-16 23:06:27 +01:00
|
|
|
imports = [
|
2024-08-24 22:05:53 +02:00
|
|
|
(lib.mkChangedOptionModule [ "services" "kresd" "interfaces" ] [ "services" "kresd" "listenPlain" ]
|
2024-12-10 20:26:33 +01:00
|
|
|
(
|
|
|
|
config:
|
|
|
|
let
|
|
|
|
value = lib.getAttrFromPath [ "services" "kresd" "interfaces" ] config;
|
|
|
|
in
|
|
|
|
map (iface: if lib.elem ":" (lib.stringToCharacters iface) then "[${iface}]:53" else "${iface}:53") # Syntax depends on being IPv6 or IPv4.
|
2019-12-16 23:06:27 +01:00
|
|
|
value
|
|
|
|
)
|
|
|
|
)
|
2024-08-24 22:05:53 +02:00
|
|
|
(lib.mkRemovedOptionModule [ "services" "kresd" "cacheDir" ] "Please use (bind-)mounting instead.")
|
2019-12-16 23:06:27 +01:00
|
|
|
];
|
|
|
|
|
2017-01-25 18:41:52 +01:00
|
|
|
###### interface
|
|
|
|
options.services.kresd = {
|
2024-08-24 22:05:53 +02:00
|
|
|
enable = lib.mkOption {
|
|
|
|
type = lib.types.bool;
|
2017-01-25 18:41:52 +01:00
|
|
|
default = false;
|
2024-04-13 14:54:15 +02:00
|
|
|
description = ''
|
2017-01-25 18:41:52 +01:00
|
|
|
Whether to enable knot-resolver domain name server.
|
|
|
|
DNSSEC validation is turned on by default.
|
2022-07-28 23:19:15 +02:00
|
|
|
You can run `sudo nc -U /run/knot-resolver/control/1`
|
2020-02-05 19:27:16 +01:00
|
|
|
and give commands interactively to kresd@1.service.
|
2017-01-25 18:41:52 +01:00
|
|
|
'';
|
|
|
|
};
|
2024-08-24 22:05:53 +02:00
|
|
|
package = lib.mkPackageOption pkgs "knot-resolver" {
|
2023-11-27 01:19:27 +01:00
|
|
|
example = "knot-resolver.override { extraFeatures = true; }";
|
2021-04-24 09:11:00 +02:00
|
|
|
};
|
2024-08-24 22:05:53 +02:00
|
|
|
extraConfig = lib.mkOption {
|
|
|
|
type = lib.types.lines;
|
2017-01-25 18:41:52 +01:00
|
|
|
default = "";
|
2024-04-13 14:54:15 +02:00
|
|
|
description = ''
|
2017-01-25 18:41:52 +01:00
|
|
|
Extra lines to be added verbatim to the generated configuration file.
|
2024-04-18 19:42:01 +02:00
|
|
|
See upstream documentation <https://www.knot-resolver.cz/documentation/stable/config-overview.html> for more details.
|
2017-01-25 18:41:52 +01:00
|
|
|
'';
|
|
|
|
};
|
2024-08-24 22:05:53 +02:00
|
|
|
listenPlain = lib.mkOption {
|
|
|
|
type = with lib.types; listOf str;
|
2024-12-10 20:26:33 +01:00
|
|
|
default = [
|
|
|
|
"[::1]:53"
|
|
|
|
"127.0.0.1:53"
|
|
|
|
];
|
2020-02-05 19:27:16 +01:00
|
|
|
example = [ "53" ];
|
2024-04-13 14:54:15 +02:00
|
|
|
description = ''
|
2019-12-16 23:06:27 +01:00
|
|
|
What addresses and ports the server should listen on.
|
2022-12-31 12:19:48 +01:00
|
|
|
For detailed syntax see ListenStream in {manpage}`systemd.socket(5)`.
|
2017-01-25 18:41:52 +01:00
|
|
|
'';
|
|
|
|
};
|
2024-08-24 22:05:53 +02:00
|
|
|
listenTLS = lib.mkOption {
|
|
|
|
type = with lib.types; listOf str;
|
2024-12-10 20:26:33 +01:00
|
|
|
default = [ ];
|
|
|
|
example = [
|
|
|
|
"198.51.100.1:853"
|
|
|
|
"[2001:db8::1]:853"
|
|
|
|
"853"
|
|
|
|
];
|
2024-04-13 14:54:15 +02:00
|
|
|
description = ''
|
2019-12-16 23:06:27 +01:00
|
|
|
Addresses and ports on which kresd should provide DNS over TLS (see RFC 7858).
|
2022-12-31 12:19:48 +01:00
|
|
|
For detailed syntax see ListenStream in {manpage}`systemd.socket(5)`.
|
2018-02-12 20:48:25 +01:00
|
|
|
'';
|
|
|
|
};
|
2024-08-24 22:05:53 +02:00
|
|
|
listenDoH = lib.mkOption {
|
|
|
|
type = with lib.types; listOf str;
|
2024-12-10 20:26:33 +01:00
|
|
|
default = [ ];
|
|
|
|
example = [
|
|
|
|
"198.51.100.1:443"
|
|
|
|
"[2001:db8::1]:443"
|
|
|
|
"443"
|
|
|
|
];
|
2024-04-13 14:54:15 +02:00
|
|
|
description = ''
|
2020-11-12 19:04:12 +01:00
|
|
|
Addresses and ports on which kresd should provide DNS over HTTPS/2 (see RFC 8484).
|
2022-12-31 12:19:48 +01:00
|
|
|
For detailed syntax see ListenStream in {manpage}`systemd.socket(5)`.
|
2020-01-23 19:19:14 +00:00
|
|
|
'';
|
|
|
|
};
|
2024-08-24 22:05:53 +02:00
|
|
|
instances = lib.mkOption {
|
|
|
|
type = lib.types.ints.unsigned;
|
2020-02-05 19:27:16 +01:00
|
|
|
default = 1;
|
2024-04-13 14:54:15 +02:00
|
|
|
description = ''
|
2020-02-05 19:27:16 +01:00
|
|
|
The number of instances to start. They will be called kresd@{1,2,...}.service.
|
|
|
|
Knot Resolver uses no threads, so this is the way to scale.
|
|
|
|
You can dynamically start/stop them at will, so this is just system default.
|
|
|
|
'';
|
|
|
|
};
|
2017-01-25 18:41:52 +01:00
|
|
|
# TODO: perhaps options for more common stuff like cache size or forwarding
|
|
|
|
};
|
|
|
|
|
|
|
|
###### implementation
|
2024-08-24 22:05:53 +02:00
|
|
|
config = lib.mkIf cfg.enable {
|
2020-02-05 19:27:16 +01:00
|
|
|
environment.etc."knot-resolver/kresd.conf".source = configFile; # not required
|
2017-01-25 18:41:52 +01:00
|
|
|
|
2024-08-24 22:05:53 +02:00
|
|
|
networking.resolvconf.useLocalResolver = lib.mkDefault true;
|
2021-04-24 09:25:07 +02:00
|
|
|
|
2024-12-10 20:26:33 +01:00
|
|
|
users.users.knot-resolver = {
|
|
|
|
isSystemUser = true;
|
|
|
|
group = "knot-resolver";
|
|
|
|
description = "Knot-resolver daemon user";
|
|
|
|
};
|
2020-02-05 19:27:16 +01:00
|
|
|
users.groups.knot-resolver.gid = null;
|
2017-01-25 18:41:52 +01:00
|
|
|
|
2021-04-24 09:11:00 +02:00
|
|
|
systemd.packages = [ cfg.package ]; # the units are patched inside the package a bit
|
2017-01-25 18:41:52 +01:00
|
|
|
|
2024-12-10 20:26:33 +01:00
|
|
|
systemd.targets.kresd = {
|
|
|
|
# configure units started by default
|
2020-02-05 19:27:16 +01:00
|
|
|
wantedBy = [ "multi-user.target" ];
|
2024-12-10 20:26:33 +01:00
|
|
|
wants = [
|
|
|
|
"kres-cache-gc.service"
|
|
|
|
] ++ map (i: "kresd@${toString i}.service") (lib.range 1 cfg.instances);
|
2018-02-12 20:48:25 +01:00
|
|
|
};
|
2020-02-05 19:27:16 +01:00
|
|
|
systemd.services."kresd@".serviceConfig = {
|
2024-12-10 20:26:33 +01:00
|
|
|
ExecStart =
|
|
|
|
"${cfg.package}/bin/kresd --noninteractive "
|
2021-04-24 09:11:00 +02:00
|
|
|
+ "-c ${cfg.package}/lib/knot-resolver/distro-preconfig.lua -c ${configFile}";
|
2020-08-10 14:21:49 -04:00
|
|
|
# Ensure /run/knot-resolver exists
|
|
|
|
RuntimeDirectory = "knot-resolver";
|
|
|
|
RuntimeDirectoryMode = "0770";
|
2020-08-10 14:11:27 -04:00
|
|
|
# Ensure /var/lib/knot-resolver exists
|
|
|
|
StateDirectory = "knot-resolver";
|
|
|
|
StateDirectoryMode = "0770";
|
2020-08-16 12:16:30 -04:00
|
|
|
# Ensure /var/cache/knot-resolver exists
|
2020-02-05 19:27:16 +01:00
|
|
|
CacheDirectory = "knot-resolver";
|
2020-08-16 12:16:30 -04:00
|
|
|
CacheDirectoryMode = "0770";
|
2020-01-23 19:19:14 +00:00
|
|
|
};
|
2020-12-25 09:46:30 +01:00
|
|
|
# We don't mind running stop phase from wrong version. It seems less racy.
|
|
|
|
systemd.services."kresd@".stopIfChanged = false;
|
2017-01-25 18:41:52 +01:00
|
|
|
};
|
|
|
|
}
|