at 21.11-pre 8.6 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfgs = config.services; 7 cfg = cfgs.ncdns; 8 9 dataDir = "/var/lib/ncdns"; 10 username = "ncdns"; 11 12 valueType = with types; oneOf [ int str bool path ] 13 // { description = "setting type (integer, string, bool or path)"; }; 14 15 configType = with types; attrsOf (nullOr (either valueType configType)) 16 // { description = '' 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. 21 ''; 22 }; 23 24 configFile = pkgs.runCommand "ncdns.conf" 25 { json = builtins.toJSON cfg.settings; 26 passAsFile = [ "json" ]; 27 } 28 "${pkgs.remarshal}/bin/json2toml < $jsonPath > $out"; 29 30 defaultFiles = { 31 public = "${dataDir}/bit.key"; 32 private = "${dataDir}/bit.private"; 33 zonePublic = "${dataDir}/bit-zone.key"; 34 zonePrivate = "${dataDir}/bit-zone.private"; 35 }; 36 37 # if all keys are the default value 38 needsKeygen = all id (flip mapAttrsToList cfg.dnssec.keys 39 (n: v: v == getAttr n defaultFiles)); 40 41 mkDefaultAttrs = mapAttrs (n: v: mkDefault v); 42 43in 44 45{ 46 47 ###### interface 48 49 options = { 50 51 services.ncdns = { 52 53 enable = mkEnableOption '' 54 ncdns, a Go daemon to bridge Namecoin to DNS. 55 To resolve .bit domains set <literal>services.namecoind.enable = true;</literal> 56 and an RPC username/password 57 ''; 58 59 address = mkOption { 60 type = types.str; 61 default = "127.0.0.1"; 62 description = '' 63 The IP address the ncdns resolver will bind to. Leave this unchanged 64 if you do not wish to directly expose the resolver. 65 ''; 66 }; 67 68 port = mkOption { 69 type = types.port; 70 default = 5333; 71 description = '' 72 The port the ncdns resolver will bind to. 73 ''; 74 }; 75 76 identity.hostname = mkOption { 77 type = types.str; 78 default = config.networking.hostName; 79 example = "example.com"; 80 description = '' 81 The hostname of this ncdns instance, which defaults to the machine 82 hostname. If specified, ncdns lists the hostname as an NS record at 83 the zone apex: 84 <programlisting> 85 bit. IN NS ns1.example.com. 86 </programlisting> 87 If unset ncdns will generate an internal psuedo-hostname under the 88 zone, which will resolve to the value of 89 <option>services.ncdns.identity.address</option>. 90 If you are only using ncdns locally you can ignore this. 91 ''; 92 }; 93 94 identity.hostmaster = mkOption { 95 type = types.str; 96 default = ""; 97 example = "root@example.com"; 98 description = '' 99 An email address for the SOA record at the bit zone. 100 If you are only using ncdns locally you can ignore this. 101 ''; 102 }; 103 104 identity.address = mkOption { 105 type = types.str; 106 default = "127.127.127.127"; 107 description = '' 108 The IP address the hostname specified in 109 <option>services.ncdns.identity.hostname</option> should resolve to. 110 If you are only using ncdns locally you can ignore this. 111 ''; 112 }; 113 114 dnssec.enable = mkEnableOption '' 115 DNSSEC support in ncdns. This will generate KSK and ZSK keypairs 116 (unless provided via the options 117 <option>services.ncdns.dnssec.publicKey</option>, 118 <option>services.ncdns.dnssec.privateKey</option> etc.) and add a trust 119 anchor to recursive resolvers 120 ''; 121 122 dnssec.keys.public = mkOption { 123 type = types.path; 124 default = defaultFiles.public; 125 description = '' 126 Path to the file containing the KSK public key. 127 The key can be generated using the <literal>dnssec-keygen</literal> 128 command, provided by the package <package>bind</package> as follows: 129 <programlisting> 130 $ dnssec-keygen -a RSASHA256 -3 -b 2048 -f KSK bit 131 </programlisting> 132 ''; 133 }; 134 135 dnssec.keys.private = mkOption { 136 type = types.path; 137 default = defaultFiles.private; 138 description = '' 139 Path to the file containing the KSK private key. 140 ''; 141 }; 142 143 dnssec.keys.zonePublic = mkOption { 144 type = types.path; 145 default = defaultFiles.zonePublic; 146 description = '' 147 Path to the file containing the ZSK public key. 148 The key can be generated using the <literal>dnssec-keygen</literal> 149 command, provided by the package <package>bind</package> as follows: 150 <programlisting> 151 $ dnssec-keygen -a RSASHA256 -3 -b 2048 bit 152 </programlisting> 153 ''; 154 }; 155 156 dnssec.keys.zonePrivate = mkOption { 157 type = types.path; 158 default = defaultFiles.zonePrivate; 159 description = '' 160 Path to the file containing the ZSK private key. 161 ''; 162 }; 163 164 settings = mkOption { 165 type = configType; 166 default = { }; 167 example = literalExample '' 168 { # enable webserver 169 ncdns.httplistenaddr = ":8202"; 170 171 # synchronize TLS certs 172 certstore.nss = true; 173 # note: all paths are relative to the config file 174 certstore.nsscertdir = "../../var/lib/ncdns"; 175 certstore.nssdbdir = "../../home/alice/.pki/nssdb"; 176 } 177 ''; 178 description = '' 179 ncdns settings. Use this option to configure ncds 180 settings not exposed in a NixOS option or to bypass one. 181 See the example ncdns.conf file at <link xlink:href=" 182 https://git.io/JfX7g"/> for the available options. 183 ''; 184 }; 185 186 }; 187 188 services.pdns-recursor.resolveNamecoin = mkOption { 189 type = types.bool; 190 default = false; 191 description = '' 192 Resolve <literal>.bit</literal> top-level domains using ncdns and namecoin. 193 ''; 194 }; 195 196 }; 197 198 199 ###### implementation 200 201 config = mkIf cfg.enable { 202 203 services.pdns-recursor = mkIf cfgs.pdns-recursor.resolveNamecoin { 204 forwardZonesRecurse.bit = "127.0.0.1:${toString cfg.port}"; 205 luaConfig = 206 if cfg.dnssec.enable 207 then ''readTrustAnchorsFromFile("${cfg.dnssec.keys.public}")'' 208 else ''addNTA("bit", "namecoin DNSSEC disabled")''; 209 }; 210 211 # Avoid pdns-recursor not finding the DNSSEC keys 212 systemd.services.pdns-recursor = mkIf cfgs.pdns-recursor.resolveNamecoin { 213 after = [ "ncdns.service" ]; 214 wants = [ "ncdns.service" ]; 215 }; 216 217 services.ncdns.settings = mkDefaultAttrs { 218 ncdns = 219 { # Namecoin RPC 220 namecoinrpcaddress = 221 "${cfgs.namecoind.rpc.address}:${toString cfgs.namecoind.rpc.port}"; 222 namecoinrpcusername = cfgs.namecoind.rpc.user; 223 namecoinrpcpassword = cfgs.namecoind.rpc.password; 224 225 # Identity 226 selfname = cfg.identity.hostname; 227 hostmaster = cfg.identity.hostmaster; 228 selfip = cfg.identity.address; 229 230 # Other 231 bind = "${cfg.address}:${toString cfg.port}"; 232 } 233 // optionalAttrs cfg.dnssec.enable 234 { # DNSSEC 235 publickey = "../.." + cfg.dnssec.keys.public; 236 privatekey = "../.." + cfg.dnssec.keys.private; 237 zonepublickey = "../.." + cfg.dnssec.keys.zonePublic; 238 zoneprivatekey = "../.." + cfg.dnssec.keys.zonePrivate; 239 }; 240 241 # Daemon 242 service.daemon = true; 243 xlog.journal = true; 244 }; 245 246 users.users.ncdns = { 247 isSystemUser = true; 248 description = "ncdns daemon user"; 249 }; 250 251 systemd.services.ncdns = { 252 description = "ncdns daemon"; 253 after = [ "namecoind.service" ]; 254 wantedBy = [ "multi-user.target" ]; 255 256 serviceConfig = { 257 User = "ncdns"; 258 StateDirectory = "ncdns"; 259 Restart = "on-failure"; 260 ExecStart = "${pkgs.ncdns}/bin/ncdns -conf=${configFile}"; 261 }; 262 263 preStart = optionalString (cfg.dnssec.enable && needsKeygen) '' 264 cd ${dataDir} 265 if [ ! -e bit.key ]; then 266 ${pkgs.bind}/bin/dnssec-keygen -a RSASHA256 -3 -b 2048 bit 267 mv Kbit.*.key bit-zone.key 268 mv Kbit.*.private bit-zone.private 269 ${pkgs.bind}/bin/dnssec-keygen -a RSASHA256 -3 -b 2048 -f KSK bit 270 mv Kbit.*.key bit.key 271 mv Kbit.*.private bit.private 272 fi 273 ''; 274 }; 275 276 }; 277 278 meta.maintainers = with lib.maintainers; [ rnhmjoj ]; 279 280}