1 { config, lib, pkgs, ... }:
6 cfgs = config.services;
9 dataDir = "/var/lib/ncdns";
12 valueType = with types; oneOf [ int str bool path ]
13 // { description = "setting type (integer, string, bool or path)"; };
15 configType = with types; attrsOf (nullOr (either valueType configType))
17 ncdns.conf configuration type. The format consists of an
18 attribute set of settings. Each setting can be either `null`,
19 a value or an attribute set. The allowed values are integers,
20 strings, booleans or paths.
24 configFile = pkgs.runCommand "ncdns.conf"
25 { json = builtins.toJSON cfg.settings;
26 passAsFile = [ "json" ];
28 "${pkgs.remarshal}/bin/json2toml < $jsonPath > $out";
31 public = "${dataDir}/bit.key";
32 private = "${dataDir}/bit.private";
33 zonePublic = "${dataDir}/bit-zone.key";
34 zonePrivate = "${dataDir}/bit-zone.private";
37 # if all keys are the default value
38 needsKeygen = all id (flip mapAttrsToList cfg.dnssec.keys
39 (n: v: v == getAttr n defaultFiles));
41 mkDefaultAttrs = mapAttrs (n: v: mkDefault v);
53 enable = mkEnableOption (lib.mdDoc ''
54 ncdns, a Go daemon to bridge Namecoin to DNS.
55 To resolve .bit domains set `services.namecoind.enable = true;`
56 and an RPC username/password
62 description = lib.mdDoc ''
63 The IP address the ncdns resolver will bind to. Leave this unchanged
64 if you do not wish to directly expose the resolver.
71 description = lib.mdDoc ''
72 The port the ncdns resolver will bind to.
76 identity.hostname = mkOption {
78 default = config.networking.hostName;
79 defaultText = literalExpression "config.networking.hostName";
80 example = "example.com";
81 description = lib.mdDoc ''
82 The hostname of this ncdns instance, which defaults to the machine
83 hostname. If specified, ncdns lists the hostname as an NS record at
86 bit. IN NS ns1.example.com.
88 If unset ncdns will generate an internal psuedo-hostname under the
89 zone, which will resolve to the value of
90 {option}`services.ncdns.identity.address`.
91 If you are only using ncdns locally you can ignore this.
95 identity.hostmaster = mkOption {
98 example = "root@example.com";
99 description = lib.mdDoc ''
100 An email address for the SOA record at the bit zone.
101 If you are only using ncdns locally you can ignore this.
105 identity.address = mkOption {
107 default = "127.127.127.127";
108 description = lib.mdDoc ''
109 The IP address the hostname specified in
110 {option}`services.ncdns.identity.hostname` should resolve to.
111 If you are only using ncdns locally you can ignore this.
115 dnssec.enable = mkEnableOption (lib.mdDoc ''
116 DNSSEC support in ncdns. This will generate KSK and ZSK keypairs
117 (unless provided via the options
118 {option}`services.ncdns.dnssec.publicKey`,
119 {option}`services.ncdns.dnssec.privateKey` etc.) and add a trust
120 anchor to recursive resolvers
123 dnssec.keys.public = mkOption {
125 default = defaultFiles.public;
126 description = lib.mdDoc ''
127 Path to the file containing the KSK public key.
128 The key can be generated using the `dnssec-keygen`
129 command, provided by the package `bind` as follows:
131 $ dnssec-keygen -a RSASHA256 -3 -b 2048 -f KSK bit
136 dnssec.keys.private = mkOption {
138 default = defaultFiles.private;
139 description = lib.mdDoc ''
140 Path to the file containing the KSK private key.
144 dnssec.keys.zonePublic = mkOption {
146 default = defaultFiles.zonePublic;
147 description = lib.mdDoc ''
148 Path to the file containing the ZSK public key.
149 The key can be generated using the `dnssec-keygen`
150 command, provided by the package `bind` as follows:
152 $ dnssec-keygen -a RSASHA256 -3 -b 2048 bit
157 dnssec.keys.zonePrivate = mkOption {
159 default = defaultFiles.zonePrivate;
160 description = lib.mdDoc ''
161 Path to the file containing the ZSK private key.
165 settings = mkOption {
168 example = literalExpression ''
170 ncdns.httplistenaddr = ":8202";
172 # synchronize TLS certs
173 certstore.nss = true;
174 # note: all paths are relative to the config file
175 certstore.nsscertdir = "../../var/lib/ncdns";
176 certstore.nssdbdir = "../../home/alice/.pki/nssdb";
179 description = lib.mdDoc ''
180 ncdns settings. Use this option to configure ncds
181 settings not exposed in a NixOS option or to bypass one.
182 See the example ncdns.conf file at <https://github.com/namecoin/ncdns/blob/master/_doc/ncdns.conf.example>
183 for the available options.
189 services.pdns-recursor.resolveNamecoin = mkOption {
192 description = lib.mdDoc ''
193 Resolve `.bit` top-level domains using ncdns and namecoin.
200 ###### implementation
202 config = mkIf cfg.enable {
204 services.pdns-recursor = mkIf cfgs.pdns-recursor.resolveNamecoin {
205 forwardZonesRecurse.bit = "${cfg.address}:${toString cfg.port}";
208 then ''readTrustAnchorsFromFile("${cfg.dnssec.keys.public}")''
209 else ''addNTA("bit", "namecoin DNSSEC disabled")'';
212 # Avoid pdns-recursor not finding the DNSSEC keys
213 systemd.services.pdns-recursor = mkIf cfgs.pdns-recursor.resolveNamecoin {
214 after = [ "ncdns.service" ];
215 wants = [ "ncdns.service" ];
218 services.ncdns.settings = mkDefaultAttrs {
222 "${cfgs.namecoind.rpc.address}:${toString cfgs.namecoind.rpc.port}";
223 namecoinrpcusername = cfgs.namecoind.rpc.user;
224 namecoinrpcpassword = cfgs.namecoind.rpc.password;
227 selfname = cfg.identity.hostname;
228 hostmaster = cfg.identity.hostmaster;
229 selfip = cfg.identity.address;
232 bind = "${cfg.address}:${toString cfg.port}";
234 // optionalAttrs cfg.dnssec.enable
236 publickey = "../.." + cfg.dnssec.keys.public;
237 privatekey = "../.." + cfg.dnssec.keys.private;
238 zonepublickey = "../.." + cfg.dnssec.keys.zonePublic;
239 zoneprivatekey = "../.." + cfg.dnssec.keys.zonePrivate;
243 service.daemon = true;
247 users.users.ncdns = {
250 description = "ncdns daemon user";
252 users.groups.ncdns = {};
254 systemd.services.ncdns = {
255 description = "ncdns daemon";
256 after = [ "namecoind.service" ];
257 wantedBy = [ "multi-user.target" ];
261 StateDirectory = "ncdns";
262 Restart = "on-failure";
263 ExecStart = "${pkgs.ncdns}/bin/ncdns -conf=${configFile}";
266 preStart = optionalString (cfg.dnssec.enable && needsKeygen) ''
268 if [ ! -e bit.key ]; then
269 ${pkgs.bind}/bin/dnssec-keygen -a RSASHA256 -3 -b 2048 bit
270 mv Kbit.*.key bit-zone.key
271 mv Kbit.*.private bit-zone.private
272 ${pkgs.bind}/bin/dnssec-keygen -a RSASHA256 -3 -b 2048 -f KSK bit
273 mv Kbit.*.key bit.key
274 mv Kbit.*.private bit.private
281 meta.maintainers = with lib.maintainers; [ rnhmjoj ];