at 23.11-pre 8.7 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 (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 57 ''); 58 59 address = mkOption { 60 type = types.str; 61 default = "[::1]"; 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. 65 ''; 66 }; 67 68 port = mkOption { 69 type = types.port; 70 default = 5333; 71 description = lib.mdDoc '' 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 = 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 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 = 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. 102 ''; 103 }; 104 105 identity.address = mkOption { 106 type = types.str; 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. 112 ''; 113 }; 114 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 121 ''); 122 123 dnssec.keys.public = mkOption { 124 type = types.path; 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: 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 = lib.mdDoc '' 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 = 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: 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 = lib.mdDoc '' 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 = 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. 184 ''; 185 }; 186 187 }; 188 189 services.pdns-recursor.resolveNamecoin = mkOption { 190 type = types.bool; 191 default = false; 192 description = lib.mdDoc '' 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}