1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.bind;
8
9 bindUser = "named";
10
11 confFile = pkgs.writeText "named.conf"
12 ''
13 include "/etc/bind/rndc.key";
14 controls {
15 inet 127.0.0.1 allow {localhost;} keys {"rndc-key";};
16 };
17
18 acl cachenetworks { ${concatMapStrings (entry: " ${entry}; ") cfg.cacheNetworks} };
19 acl badnetworks { ${concatMapStrings (entry: " ${entry}; ") cfg.blockedNetworks} };
20
21 options {
22 listen-on { ${concatMapStrings (entry: " ${entry}; ") cfg.listenOn} };
23 listen-on-v6 { ${concatMapStrings (entry: " ${entry}; ") cfg.listenOnIpv6} };
24 allow-query { cachenetworks; };
25 blackhole { badnetworks; };
26 forward first;
27 forwarders { ${concatMapStrings (entry: " ${entry}; ") cfg.forwarders} };
28 directory "/var/run/named";
29 pid-file "/var/run/named/named.pid";
30 };
31
32 ${cfg.extraConfig}
33
34 ${ concatMapStrings
35 ({ name, file, master ? true, slaves ? [], masters ? [] }:
36 ''
37 zone "${name}" {
38 type ${if master then "master" else "slave"};
39 file "${file}";
40 ${ if master then
41 ''
42 allow-transfer {
43 ${concatMapStrings (ip: "${ip};\n") slaves}
44 };
45 ''
46 else
47 ''
48 masters {
49 ${concatMapStrings (ip: "${ip};\n") masters}
50 };
51 ''
52 }
53 allow-query { any; };
54 };
55 '')
56 cfg.zones }
57 '';
58
59in
60
61{
62
63 ###### interface
64
65 options = {
66
67 services.bind = {
68
69 enable = mkOption {
70 default = false;
71 description = "
72 Whether to enable BIND domain name server.
73 ";
74 };
75
76 cacheNetworks = mkOption {
77 default = ["127.0.0.0/24"];
78 description = "
79 What networks are allowed to use us as a resolver.
80 ";
81 };
82
83 blockedNetworks = mkOption {
84 default = [];
85 description = "
86 What networks are just blocked.
87 ";
88 };
89
90 ipv4Only = mkOption {
91 default = false;
92 description = "
93 Only use ipv4, even if the host supports ipv6.
94 ";
95 };
96
97 forwarders = mkOption {
98 default = config.networking.nameservers;
99 description = "
100 List of servers we should forward requests to.
101 ";
102 };
103
104 listenOn = mkOption {
105 default = ["any"];
106 type = types.listOf types.str;
107 description = "
108 Interfaces to listen on.
109 ";
110 };
111
112 listenOnIpv6 = mkOption {
113 default = ["any"];
114 type = types.listOf types.str;
115 description = "
116 Ipv6 interfaces to listen on.
117 ";
118 };
119
120 zones = mkOption {
121 default = [];
122 description = "
123 List of zones we claim authority over.
124 master=false means slave server; slaves means addresses
125 who may request zone transfer.
126 ";
127 example = [{
128 name = "example.com";
129 master = false;
130 file = "/var/dns/example.com";
131 masters = ["192.168.0.1"];
132 slaves = [];
133 }];
134 };
135
136 extraConfig = mkOption {
137 type = types.lines;
138 default = "";
139 description = "
140 Extra lines to be added verbatim to the generated named configuration file.
141 ";
142 };
143
144 configFile = mkOption {
145 type = types.path;
146 default = confFile;
147 defaultText = "confFile";
148 description = "
149 Overridable config file to use for named. By default, that
150 generated by nixos.
151 ";
152 };
153
154 };
155
156 };
157
158
159 ###### implementation
160
161 config = mkIf config.services.bind.enable {
162
163 users.extraUsers = singleton
164 { name = bindUser;
165 uid = config.ids.uids.bind;
166 description = "BIND daemon user";
167 };
168
169 systemd.services.bind = {
170 description = "BIND Domain Name Server";
171 after = [ "network.target" ];
172 wantedBy = [ "multi-user.target" ];
173
174 preStart = ''
175 mkdir -m 0755 -p /etc/bind
176 if ! [ -f "/etc/bind/rndc.key" ]; then
177 ${pkgs.bind.out}/sbin/rndc-confgen -r /dev/urandom -c /etc/bind/rndc.key -u ${bindUser} -a -A hmac-sha256 2>/dev/null
178 fi
179
180 ${pkgs.coreutils}/bin/mkdir -p /var/run/named
181 chown ${bindUser} /var/run/named
182 '';
183
184 serviceConfig = {
185 ExecStart = "${pkgs.bind.out}/sbin/named -u ${bindUser} ${optionalString cfg.ipv4Only "-4"} -c ${cfg.configFile} -f";
186 ExecReload = "${pkgs.bind.out}/sbin/rndc -k '/etc/bind/rndc.key' reload";
187 ExecStop = "${pkgs.bind.out}/sbin/rndc -k '/etc/bind/rndc.key' stop";
188 };
189
190 unitConfig.Documentation = "man:named(8)";
191 };
192 };
193}