at 24.11-pre 8.5 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 `services.namecoind.enable = true;` 56 and an RPC username/password 57 ''; 58 59 address = mkOption { 60 type = types.str; 61 default = "[::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 defaultText = literalExpression "config.networking.hostName"; 80 example = "example.com"; 81 description = '' 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 84 the zone apex: 85 ``` 86 bit. IN NS ns1.example.com. 87 ``` 88 If unset ncdns will generate an internal pseudo-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. 92 ''; 93 }; 94 95 identity.hostmaster = mkOption { 96 type = types.str; 97 default = ""; 98 example = "root@example.com"; 99 description = '' 100 An email address for the SOA record at the bit zone. 101 If you are only using ncdns locally you can ignore this. 102 ''; 103 }; 104 105 identity.address = mkOption { 106 type = types.str; 107 default = "127.127.127.127"; 108 description = '' 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. 112 ''; 113 }; 114 115 dnssec.enable = mkEnableOption '' 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 121 ''; 122 123 dnssec.keys.public = mkOption { 124 type = types.path; 125 default = defaultFiles.public; 126 description = '' 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: 130 ``` 131 $ dnssec-keygen -a RSASHA256 -3 -b 2048 -f KSK bit 132 ``` 133 ''; 134 }; 135 136 dnssec.keys.private = mkOption { 137 type = types.path; 138 default = defaultFiles.private; 139 description = '' 140 Path to the file containing the KSK private key. 141 ''; 142 }; 143 144 dnssec.keys.zonePublic = mkOption { 145 type = types.path; 146 default = defaultFiles.zonePublic; 147 description = '' 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: 151 ``` 152 $ dnssec-keygen -a RSASHA256 -3 -b 2048 bit 153 ``` 154 ''; 155 }; 156 157 dnssec.keys.zonePrivate = mkOption { 158 type = types.path; 159 default = defaultFiles.zonePrivate; 160 description = '' 161 Path to the file containing the ZSK private key. 162 ''; 163 }; 164 165 settings = mkOption { 166 type = configType; 167 default = { }; 168 example = literalExpression '' 169 { # enable webserver 170 ncdns.httplistenaddr = ":8202"; 171 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"; 177 } 178 ''; 179 description = '' 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. 184 ''; 185 }; 186 187 }; 188 189 services.pdns-recursor.resolveNamecoin = mkOption { 190 type = types.bool; 191 default = false; 192 description = '' 193 Resolve `.bit` top-level domains using ncdns and namecoin. 194 ''; 195 }; 196 197 }; 198 199 200 ###### implementation 201 202 config = mkIf cfg.enable { 203 204 services.pdns-recursor = mkIf cfgs.pdns-recursor.resolveNamecoin { 205 forwardZonesRecurse.bit = "${cfg.address}:${toString cfg.port}"; 206 luaConfig = 207 if cfg.dnssec.enable 208 then ''readTrustAnchorsFromFile("${cfg.dnssec.keys.public}")'' 209 else ''addNTA("bit", "namecoin DNSSEC disabled")''; 210 }; 211 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" ]; 216 }; 217 218 services.ncdns.settings = mkDefaultAttrs { 219 ncdns = 220 { # Namecoin RPC 221 namecoinrpcaddress = 222 "${cfgs.namecoind.rpc.address}:${toString cfgs.namecoind.rpc.port}"; 223 namecoinrpcusername = cfgs.namecoind.rpc.user; 224 namecoinrpcpassword = cfgs.namecoind.rpc.password; 225 226 # Identity 227 selfname = cfg.identity.hostname; 228 hostmaster = cfg.identity.hostmaster; 229 selfip = cfg.identity.address; 230 231 # Other 232 bind = "${cfg.address}:${toString cfg.port}"; 233 } 234 // optionalAttrs cfg.dnssec.enable 235 { # DNSSEC 236 publickey = "../.." + cfg.dnssec.keys.public; 237 privatekey = "../.." + cfg.dnssec.keys.private; 238 zonepublickey = "../.." + cfg.dnssec.keys.zonePublic; 239 zoneprivatekey = "../.." + cfg.dnssec.keys.zonePrivate; 240 }; 241 242 # Daemon 243 service.daemon = true; 244 xlog.journal = true; 245 }; 246 247 users.users.ncdns = { 248 isSystemUser = true; 249 group = "ncdns"; 250 description = "ncdns daemon user"; 251 }; 252 users.groups.ncdns = {}; 253 254 systemd.services.ncdns = { 255 description = "ncdns daemon"; 256 after = [ "namecoind.service" ]; 257 wantedBy = [ "multi-user.target" ]; 258 259 serviceConfig = { 260 User = "ncdns"; 261 StateDirectory = "ncdns"; 262 Restart = "on-failure"; 263 ExecStart = "${pkgs.ncdns}/bin/ncdns -conf=${configFile}"; 264 }; 265 266 preStart = optionalString (cfg.dnssec.enable && needsKeygen) '' 267 cd ${dataDir} 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 275 fi 276 ''; 277 }; 278 279 }; 280 281 meta.maintainers = with lib.maintainers; [ rnhmjoj ]; 282 283}