1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.dnscache;
7
8 dnscache-root = pkgs.runCommand "dnscache-root" { preferLocalBuild = true; } ''
9 mkdir -p $out/{servers,ip}
10
11 ${concatMapStrings (ip: ''
12 touch "$out/ip/"${lib.escapeShellArg ip}
13 '') cfg.clientIps}
14
15 ${concatStrings (mapAttrsToList (host: ips: ''
16 ${concatMapStrings (ip: ''
17 echo ${lib.escapeShellArg ip} >> "$out/servers/"${lib.escapeShellArg host}
18 '') ips}
19 '') cfg.domainServers)}
20
21 # if a list of root servers was not provided in config, copy it
22 # over. (this is also done by dnscache-conf, but we 'rm -rf
23 # /var/lib/dnscache/root' below & replace it wholesale with this,
24 # so we have to ensure servers/@ exists ourselves.)
25 if [ ! -e $out/servers/@ ]; then
26 # symlink does not work here, due chroot
27 cp ${pkgs.djbdns}/etc/dnsroots.global $out/servers/@;
28 fi
29 '';
30
31in {
32
33 ###### interface
34
35 options = {
36 services.dnscache = {
37
38 enable = mkOption {
39 default = false;
40 type = types.bool;
41 description = lib.mdDoc "Whether to run the dnscache caching dns server.";
42 };
43
44 ip = mkOption {
45 default = "0.0.0.0";
46 type = types.str;
47 description = lib.mdDoc "IP address on which to listen for connections.";
48 };
49
50 clientIps = mkOption {
51 default = [ "127.0.0.1" ];
52 type = types.listOf types.str;
53 description = lib.mdDoc "Client IP addresses (or prefixes) from which to accept connections.";
54 example = ["192.168" "172.23.75.82"];
55 };
56
57 domainServers = mkOption {
58 default = { };
59 type = types.attrsOf (types.listOf types.str);
60 description = lib.mdDoc ''
61 Table of {hostname: server} pairs to use as authoritative servers for hosts (and subhosts).
62 If entry for @ is not specified predefined list of root servers is used.
63 '';
64 example = literalExpression ''
65 {
66 "@" = ["8.8.8.8" "8.8.4.4"];
67 "example.com" = ["192.168.100.100"];
68 }
69 '';
70 };
71
72 forwardOnly = mkOption {
73 default = false;
74 type = types.bool;
75 description = lib.mdDoc ''
76 Whether to treat root servers (for @) as caching
77 servers, requesting addresses the same way a client does. This is
78 needed if you want to use e.g. Google DNS as your upstream DNS.
79 '';
80 };
81
82 };
83 };
84
85 ###### implementation
86
87 config = mkIf config.services.dnscache.enable {
88 environment.systemPackages = [ pkgs.djbdns ];
89 users.users.dnscache.isSystemUser = true;
90
91 systemd.services.dnscache = {
92 description = "djbdns dnscache server";
93 wantedBy = [ "multi-user.target" ];
94 path = with pkgs; [ bash daemontools djbdns ];
95 preStart = ''
96 rm -rf /var/lib/dnscache
97 dnscache-conf dnscache dnscache /var/lib/dnscache ${config.services.dnscache.ip}
98 rm -rf /var/lib/dnscache/root
99 ln -sf ${dnscache-root} /var/lib/dnscache/root
100 '';
101 script = ''
102 cd /var/lib/dnscache/
103 ${optionalString cfg.forwardOnly "export FORWARDONLY=1"}
104 exec ./run
105 '';
106 };
107 };
108}