Merge #361424: refactor lib.packagesFromDirectoryRecursive (v2)
[NixPkgs.git] / nixos / modules / services / networking / dnsdist.nix
blob761dcea67de5df26d8b998951d5f69789419b1a3
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
7 let
8   cfg = config.services.dnsdist;
10   toLua = lib.generators.toLua { };
12   mkBind = cfg: toLua "${cfg.listenAddress}:${toString cfg.listenPort}";
14   configFile = pkgs.writeText "dnsdist.conf" ''
15     setLocal(${mkBind cfg})
16     ${lib.optionalString cfg.dnscrypt.enable dnscryptSetup}
17     ${cfg.extraConfig}
18   '';
20   dnscryptSetup = ''
21     last_rotation = 0
22     cert_serial = 0
23     provider_key = ${toLua cfg.dnscrypt.providerKey}
24     cert_lifetime = ${toLua cfg.dnscrypt.certLifetime} * 60
26     function file_exists(name)
27        local f = io.open(name, "r")
28        return f ~= nil and io.close(f)
29     end
31     function dnscrypt_setup()
32       -- generate provider keys on first run
33       if provider_key == nil then
34         provider_key = "/var/lib/dnsdist/private.key"
35         if not file_exists(provider_key) then
36           generateDNSCryptProviderKeys("/var/lib/dnsdist/public.key",
37                                        "/var/lib/dnsdist/private.key")
38           print("DNSCrypt: generated provider keypair")
39         end
40       end
42       -- generate resolver certificate
43       local now = os.time()
44       generateDNSCryptCertificate(
45         provider_key, "/run/dnsdist/resolver.cert", "/run/dnsdist/resolver.key",
46         cert_serial, now - 60, now + cert_lifetime)
47       addDNSCryptBind(
48         ${mkBind cfg.dnscrypt}, ${toLua cfg.dnscrypt.providerName},
49         "/run/dnsdist/resolver.cert", "/run/dnsdist/resolver.key")
50     end
52     function maintenance()
53       -- certificate rotation
54       local now = os.time()
55       local dnscrypt = getDNSCryptBind(0)
57       if ((now - last_rotation) > 0.9 * cert_lifetime) then
58         -- generate and start using a new certificate
59         dnscrypt:generateAndLoadInMemoryCertificate(
60           provider_key, cert_serial + 1,
61           now - 60, now + cert_lifetime)
63         -- stop advertising the last certificate
64         dnscrypt:markInactive(cert_serial)
66         -- remove the second to last certificate
67         if (cert_serial > 1)  then
68           dnscrypt:removeInactiveCertificate(cert_serial - 1)
69         end
71         print("DNSCrypt: rotated certificate")
73         -- increment serial number
74         cert_serial = cert_serial + 1
75         last_rotation = now
76       end
77     end
79     dnscrypt_setup()
80   '';
84   options = {
85     services.dnsdist = {
86       enable = lib.mkEnableOption "dnsdist domain name server";
88       listenAddress = lib.mkOption {
89         type = lib.types.str;
90         description = "Listen IP address";
91         default = "0.0.0.0";
92       };
93       listenPort = lib.mkOption {
94         type = lib.types.port;
95         description = "Listen port";
96         default = 53;
97       };
99       dnscrypt = {
100         enable = lib.mkEnableOption "a DNSCrypt endpoint to dnsdist";
102         listenAddress = lib.mkOption {
103           type = lib.types.str;
104           description = "Listen IP address of the endpoint";
105           default = "0.0.0.0";
106         };
108         listenPort = lib.mkOption {
109           type = lib.types.port;
110           description = "Listen port of the endpoint";
111           default = 443;
112         };
114         providerName = lib.mkOption {
115           type = lib.types.str;
116           default = "2.dnscrypt-cert.${config.networking.hostName}";
117           defaultText = lib.literalExpression "2.dnscrypt-cert.\${config.networking.hostName}";
118           example = "2.dnscrypt-cert.myresolver";
119           description = ''
120             The name that will be given to this DNSCrypt resolver.
122             ::: {.note}
123             The provider name must start with `2.dnscrypt-cert.`.
124             :::
125           '';
126         };
128         providerKey = lib.mkOption {
129           type = lib.types.nullOr lib.types.path;
130           default = null;
131           description = ''
132             The filepath to the provider secret key.
133             If not given a new provider key pair will be generated in
134             /var/lib/dnsdist on the first run.
136             ::: {.note}
137             The file must be readable by the dnsdist user/group.
138             :::
139           '';
140         };
142         certLifetime = lib.mkOption {
143           type = lib.types.ints.positive;
144           default = 15;
145           description = ''
146             The lifetime (in minutes) of the resolver certificate.
147             This will be automatically rotated before expiration.
148           '';
149         };
151       };
153       extraConfig = lib.mkOption {
154         type = lib.types.lines;
155         default = "";
156         description = ''
157           Extra lines to be added verbatim to dnsdist.conf.
158         '';
159       };
160     };
161   };
163   config = lib.mkIf cfg.enable {
164     users.users.dnsdist = {
165       description = "dnsdist daemons user";
166       isSystemUser = true;
167       group = "dnsdist";
168     };
170     users.groups.dnsdist = { };
172     systemd.packages = [ pkgs.dnsdist ];
174     systemd.services.dnsdist = {
175       wantedBy = [ "multi-user.target" ];
177       startLimitIntervalSec = 0;
178       serviceConfig = {
179         User = "dnsdist";
180         Group = "dnsdist";
181         RuntimeDirectory = "dnsdist";
182         StateDirectory = "dnsdist";
183         # upstream overrides for better nixos compatibility
184         ExecStartPre = [
185           ""
186           "${pkgs.dnsdist}/bin/dnsdist --check-config --config ${configFile}"
187         ];
188         ExecStart = [
189           ""
190           "${pkgs.dnsdist}/bin/dnsdist --supervised --disable-syslog --config ${configFile}"
191         ];
192       };
193     };
194   };