nixpkgs/nixos/modules/services/networking/bind.nix
pennae 2e751c0772 treewide: automatically md-convert option descriptions
the conversion procedure is simple:

 - find all things that look like options, ie calls to either `mkOption`
   or `lib.mkOption` that take an attrset. remember the attrset as the
   option
 - for all options, find a `description` attribute who's value is not a
   call to `mdDoc` or `lib.mdDoc`
 - textually convert the entire value of the attribute to MD with a few
   simple regexes (the set from mdize-module.sh)
 - if the change produced a change in the manual output, discard
 - if the change kept the manual unchanged, add some text to the
   description to make sure we've actually found an option. if the
   manual changes this time, keep the converted description

this procedure converts 80% of nixos options to markdown. around 2000
options remain to be inspected, but most of those fail the "does not
change the manual output check": currently the MD conversion process
does not faithfully convert docbook tags like <code> and <package>, so
any option using such tags will not be converted at all.
2022-07-30 15:16:34 +02:00

275 lines
7.6 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.bind;
bindPkg = config.services.bind.package;
bindUser = "named";
bindZoneCoerce = list: builtins.listToAttrs (lib.forEach list (zone: { name = zone.name; value = zone; }));
bindZoneOptions = { name, config, ... }: {
options = {
name = mkOption {
type = types.str;
default = name;
description = lib.mdDoc "Name of the zone.";
};
master = mkOption {
description = lib.mdDoc "Master=false means slave server";
type = types.bool;
};
file = mkOption {
type = types.either types.str types.path;
description = lib.mdDoc "Zone file resource records contain columns of data, separated by whitespace, that define the record.";
};
masters = mkOption {
type = types.listOf types.str;
description = lib.mdDoc "List of servers for inclusion in stub and secondary zones.";
};
slaves = mkOption {
type = types.listOf types.str;
description = lib.mdDoc "Addresses who may request zone transfers.";
default = [ ];
};
extraConfig = mkOption {
type = types.str;
description = lib.mdDoc "Extra zone config to be appended at the end of the zone section.";
default = "";
};
};
};
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; };
forward ${cfg.forward};
forwarders { ${concatMapStrings (entry: " ${entry}; ") cfg.forwarders} };
directory "${cfg.directory}";
pid-file "/run/named/named.pid";
${cfg.extraOptions}
};
${cfg.extraConfig}
${ concatMapStrings
({ name, file, master ? true, slaves ? [], masters ? [], extraConfig ? "" }:
''
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}
};
''
}
allow-query { any; };
${extraConfig}
};
'')
(attrValues cfg.zones) }
'';
in
{
###### interface
options = {
services.bind = {
enable = mkEnableOption "BIND domain name server";
package = mkOption {
type = types.package;
default = pkgs.bind;
defaultText = literalExpression "pkgs.bind";
description = lib.mdDoc "The BIND package to use.";
};
cacheNetworks = mkOption {
default = [ "127.0.0.0/24" ];
type = types.listOf types.str;
description = "
What networks are allowed to use us as a resolver. Note
that this is for recursive queries -- all networks are
allowed to query zones configured with the `zones` option.
It is recommended that you limit cacheNetworks to avoid your
server being used for DNS amplification attacks.
";
};
blockedNetworks = mkOption {
default = [ ];
type = types.listOf types.str;
description = "
What networks are just blocked.
";
};
ipv4Only = mkOption {
default = false;
type = types.bool;
description = "
Only use ipv4, even if the host supports ipv6.
";
};
forwarders = mkOption {
default = config.networking.nameservers;
defaultText = literalExpression "config.networking.nameservers";
type = types.listOf types.str;
description = "
List of servers we should forward requests to.
";
};
forward = mkOption {
default = "first";
type = types.enum ["first" "only"];
description = "
Whether to forward 'first' (try forwarding but lookup directly if forwarding fails) or 'only'.
";
};
listenOn = mkOption {
default = [ "any" ];
type = types.listOf types.str;
description = "
Interfaces to listen on.
";
};
listenOnIpv6 = mkOption {
default = [ "any" ];
type = types.listOf types.str;
description = "
Ipv6 interfaces to listen on.
";
};
directory = mkOption {
type = types.str;
default = "/run/named";
description = lib.mdDoc "Working directory of BIND.";
};
zones = mkOption {
default = [ ];
type = with types; coercedTo (listOf attrs) bindZoneCoerce (attrsOf (types.submodule bindZoneOptions));
description = "
List of zones we claim authority over.
";
example = {
"example.com" = {
master = false;
file = "/var/dns/example.com";
masters = [ "192.168.0.1" ];
slaves = [ ];
extraConfig = "";
};
};
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = "
Extra lines to be added verbatim to the generated named configuration file.
";
};
extraOptions = mkOption {
type = types.lines;
default = "";
description = lib.mdDoc ''
Extra lines to be added verbatim to the options section of the
generated named configuration file.
'';
};
configFile = mkOption {
type = types.path;
default = confFile;
defaultText = literalExpression "confFile";
description = "
Overridable config file to use for named. By default, that
generated by nixos.
";
};
};
};
###### implementation
config = mkIf cfg.enable {
networking.resolvconf.useLocalResolver = mkDefault true;
users.users.${bindUser} =
{
group = bindUser;
description = "BIND daemon user";
isSystemUser = true;
};
users.groups.${bindUser} = {};
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
${bindPkg.out}/sbin/rndc-confgen -c /etc/bind/rndc.key -u ${bindUser} -a -A hmac-sha256 2>/dev/null
fi
${pkgs.coreutils}/bin/mkdir -p /run/named
chown ${bindUser} /run/named
${pkgs.coreutils}/bin/mkdir -p ${cfg.directory}
chown ${bindUser} ${cfg.directory}
'';
serviceConfig = {
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";
};
unitConfig.Documentation = "man:named(8)";
};
};
}