1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfgs = config.services;
7 cfg = cfgs.dnschain;
8
9 dataDir = "/var/lib/dnschain";
10 username = "dnschain";
11
12 configFile = pkgs.writeText "dnschain.conf" ''
13 [log]
14 level = info
15
16 [dns]
17 host = ${cfg.dns.address}
18 port = ${toString cfg.dns.port}
19 oldDNSMethod = NO_OLD_DNS
20 externalIP = ${cfg.dns.externalAddress}
21
22 [http]
23 host = ${cfg.api.hostname}
24 port = ${toString cfg.api.port}
25 tlsPort = ${toString cfg.api.tlsPort}
26
27 ${cfg.extraConfig}
28 '';
29
30in
31
32{
33
34 ###### interface
35
36 options = {
37
38 services.dnschain = {
39
40 enable = mkEnableOption ''
41 DNSChain, a blockchain based DNS + HTTP server.
42 To resolve .bit domains set <literal>services.namecoind.enable = true;</literal>
43 and an RPC username/password.
44 '';
45
46 dns.address = mkOption {
47 type = types.str;
48 default = "127.0.0.1";
49 description = ''
50 The IP address the DNSChain resolver will bind to.
51 Leave this unchanged if you do not wish to directly expose the resolver.
52 '';
53 };
54
55 dns.externalAddress = mkOption {
56 type = types.str;
57 default = cfg.dns.address;
58 description = ''
59 The IP address used by clients to reach the resolver and the value of
60 the <literal>namecoin.dns</literal> record. Set this in case the bind address
61 is not the actual IP address (e.g. the machine is behind a NAT).
62 '';
63 };
64
65 dns.port = mkOption {
66 type = types.int;
67 default = 5333;
68 description = ''
69 The port the DNSChain resolver will bind to.
70 '';
71 };
72
73 api.hostname = mkOption {
74 type = types.str;
75 default = "0.0.0.0";
76 description = ''
77 The hostname (or IP address) the DNSChain API server will bind to.
78 '';
79 };
80
81 api.port = mkOption {
82 type = types.int;
83 default = 8080;
84 description = ''
85 The port the DNSChain API server (HTTP) will bind to.
86 '';
87 };
88
89 api.tlsPort = mkOption {
90 type = types.int;
91 default = 4433;
92 description = ''
93 The port the DNSChain API server (HTTPS) will bind to.
94 '';
95 };
96
97 extraConfig = mkOption {
98 type = types.lines;
99 default = "";
100 example = ''
101 [log]
102 level = debug
103 '';
104 description = ''
105 Additional options that will be appended to the configuration file.
106 '';
107 };
108
109 };
110
111 services.dnsmasq.resolveDNSChainQueries = mkOption {
112 type = types.bool;
113 default = false;
114 description = ''
115 Resolve <literal>.bit</literal> top-level domains using DNSChain and namecoin.
116 '';
117 };
118
119 services.pdns-recursor.resolveDNSChainQueries = mkOption {
120 type = types.bool;
121 default = false;
122 description = ''
123 Resolve <literal>.bit</literal> top-level domains using DNSChain and namecoin.
124 '';
125 };
126
127 };
128
129
130 ###### implementation
131
132 config = mkIf cfg.enable {
133
134 services.dnsmasq.servers = optionals cfgs.dnsmasq.resolveDNSChainQueries
135 [ "/.bit/127.0.0.1#${toString cfg.dns.port}"
136 "/.dns/127.0.0.1#${toString cfg.dns.port}"
137 ];
138
139 services.pdns-recursor.forwardZones = mkIf cfgs.pdns-recursor.resolveDNSChainQueries
140 { bit = "127.0.0.1:${toString cfg.dns.port}";
141 dns = "127.0.0.1:${toString cfg.dns.port}";
142 };
143
144 users.extraUsers = singleton {
145 name = username;
146 description = "DNSChain daemon user";
147 home = dataDir;
148 createHome = true;
149 uid = config.ids.uids.dnschain;
150 extraGroups = optional cfgs.namecoind.enable "namecoin";
151 };
152
153 systemd.services.dnschain = {
154 description = "DNSChain daemon";
155 after = optional cfgs.namecoind.enable "namecoind.target";
156 wantedBy = [ "multi-user.target" ];
157
158 serviceConfig = {
159 User = "dnschain";
160 Restart = "on-failure";
161 ExecStart = "${pkgs.dnschain}/bin/dnschain";
162 };
163
164 preStart = ''
165 # Link configuration file into dnschain home directory
166 configPath=${dataDir}/.dnschain/dnschain.conf
167 mkdir -p ${dataDir}/.dnschain
168 if [ "$(realpath $configPath)" != "${configFile}" ]; then
169 rm -f $configPath
170 ln -s ${configFile} $configPath
171 fi
172 '';
173 };
174
175 };
176
177}