2020-04-24 23:36:52 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
|
|
|
|
cfg = config.services.bind;
|
|
|
|
|
2021-07-14 22:03:04 +00:00
|
|
|
bindPkg = config.services.bind.package;
|
|
|
|
|
2020-04-24 23:36:52 +00:00
|
|
|
bindUser = "named";
|
|
|
|
|
2021-05-03 20:48:10 +00:00
|
|
|
bindZoneCoerce = list: builtins.listToAttrs (lib.forEach list (zone: { name = zone.name; value = zone; }));
|
|
|
|
|
|
|
|
bindZoneOptions = { name, config, ... }: {
|
|
|
|
options = {
|
|
|
|
name = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = name;
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Name of the zone.";
|
2021-05-03 20:48:10 +00:00
|
|
|
};
|
|
|
|
master = mkOption {
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Master=false means slave server";
|
2021-05-03 20:48:10 +00:00
|
|
|
type = types.bool;
|
|
|
|
};
|
|
|
|
file = mkOption {
|
|
|
|
type = types.either types.str types.path;
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Zone file resource records contain columns of data, separated by whitespace, that define the record.";
|
2021-05-03 20:48:10 +00:00
|
|
|
};
|
|
|
|
masters = mkOption {
|
|
|
|
type = types.listOf types.str;
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "List of servers for inclusion in stub and secondary zones.";
|
2021-05-03 20:48:10 +00:00
|
|
|
};
|
|
|
|
slaves = mkOption {
|
|
|
|
type = types.listOf types.str;
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Addresses who may request zone transfers.";
|
2021-05-20 23:08:51 +00:00
|
|
|
default = [ ];
|
2021-05-03 20:48:10 +00:00
|
|
|
};
|
2023-04-12 12:48:02 +00:00
|
|
|
allowQuery = mkOption {
|
|
|
|
type = types.listOf types.str;
|
|
|
|
description = lib.mdDoc ''
|
|
|
|
List of address ranges allowed to query this zone. Instead of the address(es), this may instead
|
|
|
|
contain the single string "any".
|
|
|
|
|
|
|
|
NOTE: This overrides the global-level `allow-query` setting, which is set to the contents
|
|
|
|
of `cachenetworks`.
|
|
|
|
'';
|
|
|
|
default = [ "any" ];
|
|
|
|
};
|
2021-05-03 20:48:10 +00:00
|
|
|
extraConfig = mkOption {
|
|
|
|
type = types.str;
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Extra zone config to be appended at the end of the zone section.";
|
2021-05-03 20:48:10 +00:00
|
|
|
default = "";
|
|
|
|
};
|
2021-02-05 17:12:51 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2020-04-24 23:36:52 +00:00
|
|
|
confFile = pkgs.writeText "named.conf"
|
|
|
|
''
|
|
|
|
include "/etc/bind/rndc.key";
|
|
|
|
controls {
|
|
|
|
inet 127.0.0.1 allow {localhost;} keys {"rndc-key";};
|
|
|
|
};
|
|
|
|
|
|
|
|
acl cachenetworks { ${concatMapStrings (entry: " ${entry}; ") cfg.cacheNetworks} };
|
|
|
|
acl badnetworks { ${concatMapStrings (entry: " ${entry}; ") cfg.blockedNetworks} };
|
|
|
|
|
|
|
|
options {
|
|
|
|
listen-on { ${concatMapStrings (entry: " ${entry}; ") cfg.listenOn} };
|
|
|
|
listen-on-v6 { ${concatMapStrings (entry: " ${entry}; ") cfg.listenOnIpv6} };
|
|
|
|
allow-query { cachenetworks; };
|
|
|
|
blackhole { badnetworks; };
|
2022-01-22 01:22:15 +00:00
|
|
|
forward ${cfg.forward};
|
2020-04-24 23:36:52 +00:00
|
|
|
forwarders { ${concatMapStrings (entry: " ${entry}; ") cfg.forwarders} };
|
2021-07-17 21:14:59 +00:00
|
|
|
directory "${cfg.directory}";
|
2020-04-24 23:36:52 +00:00
|
|
|
pid-file "/run/named/named.pid";
|
|
|
|
${cfg.extraOptions}
|
|
|
|
};
|
|
|
|
|
|
|
|
${cfg.extraConfig}
|
|
|
|
|
|
|
|
${ concatMapStrings
|
2023-04-12 12:48:02 +00:00
|
|
|
({ name, file, master ? true, slaves ? [], masters ? [], allowQuery ? [], extraConfig ? "" }:
|
2020-04-24 23:36:52 +00:00
|
|
|
''
|
|
|
|
zone "${name}" {
|
|
|
|
type ${if master then "master" else "slave"};
|
|
|
|
file "${file}";
|
|
|
|
${ if master then
|
|
|
|
''
|
|
|
|
allow-transfer {
|
|
|
|
${concatMapStrings (ip: "${ip};\n") slaves}
|
|
|
|
};
|
|
|
|
''
|
|
|
|
else
|
|
|
|
''
|
|
|
|
masters {
|
|
|
|
${concatMapStrings (ip: "${ip};\n") masters}
|
|
|
|
};
|
|
|
|
''
|
|
|
|
}
|
2023-04-12 12:48:02 +00:00
|
|
|
allow-query { ${concatMapStrings (ip: "${ip}; ") allowQuery}};
|
2020-04-24 23:36:52 +00:00
|
|
|
${extraConfig}
|
|
|
|
};
|
|
|
|
'')
|
2021-05-03 20:48:10 +00:00
|
|
|
(attrValues cfg.zones) }
|
2020-04-24 23:36:52 +00:00
|
|
|
'';
|
|
|
|
|
|
|
|
in
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
###### interface
|
|
|
|
|
|
|
|
options = {
|
|
|
|
|
|
|
|
services.bind = {
|
|
|
|
|
2022-09-09 14:08:57 +00:00
|
|
|
enable = mkEnableOption (lib.mdDoc "BIND domain name server");
|
2020-04-24 23:36:52 +00:00
|
|
|
|
2021-07-14 22:03:04 +00:00
|
|
|
|
|
|
|
package = mkOption {
|
|
|
|
type = types.package;
|
|
|
|
default = pkgs.bind;
|
2021-10-06 13:57:05 +00:00
|
|
|
defaultText = literalExpression "pkgs.bind";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "The BIND package to use.";
|
2021-07-14 22:03:04 +00:00
|
|
|
};
|
|
|
|
|
2020-04-24 23:36:52 +00:00
|
|
|
cacheNetworks = mkOption {
|
2021-05-20 23:08:51 +00:00
|
|
|
default = [ "127.0.0.0/24" ];
|
2021-02-05 17:12:51 +00:00
|
|
|
type = types.listOf types.str;
|
2022-08-21 13:32:41 +00:00
|
|
|
description = lib.mdDoc ''
|
2020-04-24 23:36:52 +00:00
|
|
|
What networks are allowed to use us as a resolver. Note
|
|
|
|
that this is for recursive queries -- all networks are
|
2023-04-12 12:48:02 +00:00
|
|
|
allowed to query zones configured with the `zones` option
|
|
|
|
by default (although this may be overridden within each
|
|
|
|
zone's configuration, via the `allowQuery` option).
|
2020-04-24 23:36:52 +00:00
|
|
|
It is recommended that you limit cacheNetworks to avoid your
|
|
|
|
server being used for DNS amplification attacks.
|
2022-08-21 13:32:41 +00:00
|
|
|
'';
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
blockedNetworks = mkOption {
|
2021-05-20 23:08:51 +00:00
|
|
|
default = [ ];
|
2021-02-05 17:12:51 +00:00
|
|
|
type = types.listOf types.str;
|
2022-08-21 13:32:41 +00:00
|
|
|
description = lib.mdDoc ''
|
2020-04-24 23:36:52 +00:00
|
|
|
What networks are just blocked.
|
2022-08-21 13:32:41 +00:00
|
|
|
'';
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
ipv4Only = mkOption {
|
|
|
|
default = false;
|
2021-02-05 17:12:51 +00:00
|
|
|
type = types.bool;
|
2022-08-21 13:32:41 +00:00
|
|
|
description = lib.mdDoc ''
|
2020-04-24 23:36:52 +00:00
|
|
|
Only use ipv4, even if the host supports ipv6.
|
2022-08-21 13:32:41 +00:00
|
|
|
'';
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
forwarders = mkOption {
|
|
|
|
default = config.networking.nameservers;
|
2021-12-06 16:07:01 +00:00
|
|
|
defaultText = literalExpression "config.networking.nameservers";
|
2021-02-05 17:12:51 +00:00
|
|
|
type = types.listOf types.str;
|
2022-08-21 13:32:41 +00:00
|
|
|
description = lib.mdDoc ''
|
2020-04-24 23:36:52 +00:00
|
|
|
List of servers we should forward requests to.
|
2022-08-21 13:32:41 +00:00
|
|
|
'';
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
|
2022-01-22 01:22:15 +00:00
|
|
|
forward = mkOption {
|
|
|
|
default = "first";
|
|
|
|
type = types.enum ["first" "only"];
|
2022-08-21 13:32:41 +00:00
|
|
|
description = lib.mdDoc ''
|
2022-01-22 01:22:15 +00:00
|
|
|
Whether to forward 'first' (try forwarding but lookup directly if forwarding fails) or 'only'.
|
2022-08-21 13:32:41 +00:00
|
|
|
'';
|
2022-01-22 01:22:15 +00:00
|
|
|
};
|
|
|
|
|
2020-04-24 23:36:52 +00:00
|
|
|
listenOn = mkOption {
|
2021-05-20 23:08:51 +00:00
|
|
|
default = [ "any" ];
|
2020-04-24 23:36:52 +00:00
|
|
|
type = types.listOf types.str;
|
2022-08-21 13:32:41 +00:00
|
|
|
description = lib.mdDoc ''
|
2020-04-24 23:36:52 +00:00
|
|
|
Interfaces to listen on.
|
2022-08-21 13:32:41 +00:00
|
|
|
'';
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
listenOnIpv6 = mkOption {
|
2021-05-20 23:08:51 +00:00
|
|
|
default = [ "any" ];
|
2020-04-24 23:36:52 +00:00
|
|
|
type = types.listOf types.str;
|
2022-08-21 13:32:41 +00:00
|
|
|
description = lib.mdDoc ''
|
2020-04-24 23:36:52 +00:00
|
|
|
Ipv6 interfaces to listen on.
|
2022-08-21 13:32:41 +00:00
|
|
|
'';
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
|
2021-07-17 21:14:59 +00:00
|
|
|
directory = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
default = "/run/named";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc "Working directory of BIND.";
|
2021-07-17 21:14:59 +00:00
|
|
|
};
|
|
|
|
|
2020-04-24 23:36:52 +00:00
|
|
|
zones = mkOption {
|
2021-05-20 23:08:51 +00:00
|
|
|
default = [ ];
|
2021-05-03 20:48:10 +00:00
|
|
|
type = with types; coercedTo (listOf attrs) bindZoneCoerce (attrsOf (types.submodule bindZoneOptions));
|
2022-08-21 13:32:41 +00:00
|
|
|
description = lib.mdDoc ''
|
2020-04-24 23:36:52 +00:00
|
|
|
List of zones we claim authority over.
|
2022-08-21 13:32:41 +00:00
|
|
|
'';
|
2021-05-03 20:48:10 +00:00
|
|
|
example = {
|
|
|
|
"example.com" = {
|
|
|
|
master = false;
|
|
|
|
file = "/var/dns/example.com";
|
2021-05-20 23:08:51 +00:00
|
|
|
masters = [ "192.168.0.1" ];
|
|
|
|
slaves = [ ];
|
2021-05-03 20:48:10 +00:00
|
|
|
extraConfig = "";
|
|
|
|
};
|
|
|
|
};
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
extraConfig = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
default = "";
|
2022-08-21 13:32:41 +00:00
|
|
|
description = lib.mdDoc ''
|
2020-04-24 23:36:52 +00:00
|
|
|
Extra lines to be added verbatim to the generated named configuration file.
|
2022-08-21 13:32:41 +00:00
|
|
|
'';
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
extraOptions = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
default = "";
|
2022-08-12 12:06:08 +00:00
|
|
|
description = lib.mdDoc ''
|
2020-04-24 23:36:52 +00:00
|
|
|
Extra lines to be added verbatim to the options section of the
|
|
|
|
generated named configuration file.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
configFile = mkOption {
|
|
|
|
type = types.path;
|
|
|
|
default = confFile;
|
2021-10-06 13:57:05 +00:00
|
|
|
defaultText = literalExpression "confFile";
|
2022-08-21 13:32:41 +00:00
|
|
|
description = lib.mdDoc ''
|
2020-04-24 23:36:52 +00:00
|
|
|
Overridable config file to use for named. By default, that
|
|
|
|
generated by nixos.
|
2022-08-21 13:32:41 +00:00
|
|
|
'';
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
###### implementation
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
|
|
|
|
networking.resolvconf.useLocalResolver = mkDefault true;
|
|
|
|
|
|
|
|
users.users.${bindUser} =
|
2021-05-20 23:08:51 +00:00
|
|
|
{
|
2021-09-18 10:52:07 +00:00
|
|
|
group = bindUser;
|
2020-04-24 23:36:52 +00:00
|
|
|
description = "BIND daemon user";
|
2021-09-18 10:52:07 +00:00
|
|
|
isSystemUser = true;
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
2021-09-18 10:52:07 +00:00
|
|
|
users.groups.${bindUser} = {};
|
2020-04-24 23:36:52 +00:00
|
|
|
|
|
|
|
systemd.services.bind = {
|
|
|
|
description = "BIND Domain Name Server";
|
|
|
|
after = [ "network.target" ];
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
|
|
|
|
preStart = ''
|
|
|
|
mkdir -m 0755 -p /etc/bind
|
|
|
|
if ! [ -f "/etc/bind/rndc.key" ]; then
|
2021-07-14 22:03:04 +00:00
|
|
|
${bindPkg.out}/sbin/rndc-confgen -c /etc/bind/rndc.key -u ${bindUser} -a -A hmac-sha256 2>/dev/null
|
2020-04-24 23:36:52 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
${pkgs.coreutils}/bin/mkdir -p /run/named
|
|
|
|
chown ${bindUser} /run/named
|
2021-07-17 21:14:59 +00:00
|
|
|
|
|
|
|
${pkgs.coreutils}/bin/mkdir -p ${cfg.directory}
|
|
|
|
chown ${bindUser} ${cfg.directory}
|
2020-04-24 23:36:52 +00:00
|
|
|
'';
|
|
|
|
|
|
|
|
serviceConfig = {
|
2021-07-14 22:03:04 +00:00
|
|
|
ExecStart = "${bindPkg.out}/sbin/named -u ${bindUser} ${optionalString cfg.ipv4Only "-4"} -c ${cfg.configFile} -f";
|
|
|
|
ExecReload = "${bindPkg.out}/sbin/rndc -k '/etc/bind/rndc.key' reload";
|
|
|
|
ExecStop = "${bindPkg.out}/sbin/rndc -k '/etc/bind/rndc.key' stop";
|
2020-04-24 23:36:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
unitConfig.Documentation = "man:named(8)";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|