279 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
		
		
			
		
	
	
			279 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
| 
								 | 
							
								{ config, lib, pkgs, ... }:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								with lib;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								let
							 | 
						||
| 
								 | 
							
								  cfgs = config.services;
							 | 
						||
| 
								 | 
							
								  cfg  = cfgs.ncdns;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  dataDir  = "/var/lib/ncdns";
							 | 
						||
| 
								 | 
							
								  username = "ncdns";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  valueType = with types; oneOf [ int str bool path ]
							 | 
						||
| 
								 | 
							
								    // { description = "setting type (integer, string, bool or path)"; };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  configType = with types; attrsOf (nullOr (either valueType configType))
							 | 
						||
| 
								 | 
							
								    // { description = ''
							 | 
						||
| 
								 | 
							
								          ncdns.conf configuration type. The format consists of an
							 | 
						||
| 
								 | 
							
								          attribute set of settings. Each setting can be either `null`,
							 | 
						||
| 
								 | 
							
								          a value or an attribute set. The allowed values are integers,
							 | 
						||
| 
								 | 
							
								          strings, booleans or paths.
							 | 
						||
| 
								 | 
							
								         '';
							 | 
						||
| 
								 | 
							
								       };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  configFile = pkgs.runCommand "ncdns.conf"
							 | 
						||
| 
								 | 
							
								    { json = builtins.toJSON cfg.settings;
							 | 
						||
| 
								 | 
							
								      passAsFile = [ "json" ];
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    "${pkgs.remarshal}/bin/json2toml < $jsonPath > $out";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  defaultFiles = {
							 | 
						||
| 
								 | 
							
								    public  = "${dataDir}/bit.key";
							 | 
						||
| 
								 | 
							
								    private = "${dataDir}/bit.private";
							 | 
						||
| 
								 | 
							
								    zonePublic  = "${dataDir}/bit-zone.key";
							 | 
						||
| 
								 | 
							
								    zonePrivate = "${dataDir}/bit-zone.private";
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  # if all keys are the default value
							 | 
						||
| 
								 | 
							
								  needsKeygen = all id (flip mapAttrsToList cfg.dnssec.keys
							 | 
						||
| 
								 | 
							
								    (n: v: v == getAttr n defaultFiles));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  mkDefaultAttrs = mapAttrs (n: v: mkDefault v);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								in
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ###### interface
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  options = {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    services.ncdns = {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      enable = mkEnableOption ''
							 | 
						||
| 
								 | 
							
								        ncdns, a Go daemon to bridge Namecoin to DNS.
							 | 
						||
| 
								 | 
							
								        To resolve .bit domains set <literal>services.namecoind.enable = true;</literal>
							 | 
						||
| 
								 | 
							
								        and an RPC username/password
							 | 
						||
| 
								 | 
							
								      '';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      address = mkOption {
							 | 
						||
| 
								 | 
							
								        type = types.str;
							 | 
						||
| 
								 | 
							
								        default = "127.0.0.1";
							 | 
						||
| 
								 | 
							
								        description = ''
							 | 
						||
| 
								 | 
							
								          The IP address the ncdns resolver will bind to.  Leave this unchanged
							 | 
						||
| 
								 | 
							
								          if you do not wish to directly expose the resolver.
							 | 
						||
| 
								 | 
							
								        '';
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      port = mkOption {
							 | 
						||
| 
								 | 
							
								        type = types.port;
							 | 
						||
| 
								 | 
							
								        default = 5333;
							 | 
						||
| 
								 | 
							
								        description = ''
							 | 
						||
| 
								 | 
							
								          The port the ncdns resolver will bind to.
							 | 
						||
| 
								 | 
							
								        '';
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      identity.hostname = mkOption {
							 | 
						||
| 
								 | 
							
								        type = types.str;
							 | 
						||
| 
								 | 
							
								        default = config.networking.hostName;
							 | 
						||
| 
								 | 
							
								        example = "example.com";
							 | 
						||
| 
								 | 
							
								        description = ''
							 | 
						||
| 
								 | 
							
								          The hostname of this ncdns instance, which defaults to the machine
							 | 
						||
| 
								 | 
							
								          hostname. If specified, ncdns lists the hostname as an NS record at
							 | 
						||
| 
								 | 
							
								          the zone apex:
							 | 
						||
| 
								 | 
							
								          <programlisting>
							 | 
						||
| 
								 | 
							
								          bit. IN NS ns1.example.com.
							 | 
						||
| 
								 | 
							
								          </programlisting>
							 | 
						||
| 
								 | 
							
								          If unset ncdns will generate an internal psuedo-hostname under the
							 | 
						||
| 
								 | 
							
								          zone, which will resolve to the value of
							 | 
						||
| 
								 | 
							
								          <option>services.ncdns.identity.address</option>.
							 | 
						||
| 
								 | 
							
								          If you are only using ncdns locally you can ignore this.
							 | 
						||
| 
								 | 
							
								        '';
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      identity.hostmaster = mkOption {
							 | 
						||
| 
								 | 
							
								        type = types.str;
							 | 
						||
| 
								 | 
							
								        default = "";
							 | 
						||
| 
								 | 
							
								        example = "root@example.com";
							 | 
						||
| 
								 | 
							
								        description = ''
							 | 
						||
| 
								 | 
							
								          An email address for the SOA record at the bit zone.
							 | 
						||
| 
								 | 
							
								          If you are only using ncdns locally you can ignore this.
							 | 
						||
| 
								 | 
							
								        '';
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      identity.address = mkOption {
							 | 
						||
| 
								 | 
							
								        type = types.str;
							 | 
						||
| 
								 | 
							
								        default = "127.127.127.127";
							 | 
						||
| 
								 | 
							
								        description = ''
							 | 
						||
| 
								 | 
							
								          The IP address the hostname specified in
							 | 
						||
| 
								 | 
							
								          <option>services.ncdns.identity.hostname</option> should resolve to.
							 | 
						||
| 
								 | 
							
								          If you are only using ncdns locally you can ignore this.
							 | 
						||
| 
								 | 
							
								        '';
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      dnssec.enable = mkEnableOption ''
							 | 
						||
| 
								 | 
							
								        DNSSEC support in ncdns. This will generate KSK and ZSK keypairs
							 | 
						||
| 
								 | 
							
								        (unless provided via the options
							 | 
						||
| 
								 | 
							
								        <option>services.ncdns.dnssec.publicKey</option>,
							 | 
						||
| 
								 | 
							
								        <option>services.ncdns.dnssec.privateKey</option> etc.) and add a trust
							 | 
						||
| 
								 | 
							
								        anchor to recursive resolvers
							 | 
						||
| 
								 | 
							
								      '';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      dnssec.keys.public = mkOption {
							 | 
						||
| 
								 | 
							
								        type = types.path;
							 | 
						||
| 
								 | 
							
								        default = defaultFiles.public;
							 | 
						||
| 
								 | 
							
								        description = ''
							 | 
						||
| 
								 | 
							
								          Path to the file containing the KSK public key.
							 | 
						||
| 
								 | 
							
								          The key can be generated using the <literal>dnssec-keygen</literal>
							 | 
						||
| 
								 | 
							
								          command, provided by the package <package>bind</package> as follows:
							 | 
						||
| 
								 | 
							
								          <programlisting>
							 | 
						||
| 
								 | 
							
								          $ dnssec-keygen -a RSASHA256 -3 -b 2048 -f KSK bit
							 | 
						||
| 
								 | 
							
								          </programlisting>
							 | 
						||
| 
								 | 
							
								        '';
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      dnssec.keys.private = mkOption {
							 | 
						||
| 
								 | 
							
								        type = types.path;
							 | 
						||
| 
								 | 
							
								        default = defaultFiles.private;
							 | 
						||
| 
								 | 
							
								        description = ''
							 | 
						||
| 
								 | 
							
								          Path to the file containing the KSK private key.
							 | 
						||
| 
								 | 
							
								        '';
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      dnssec.keys.zonePublic = mkOption {
							 | 
						||
| 
								 | 
							
								        type = types.path;
							 | 
						||
| 
								 | 
							
								        default = defaultFiles.zonePublic;
							 | 
						||
| 
								 | 
							
								        description = ''
							 | 
						||
| 
								 | 
							
								          Path to the file containing the ZSK public key.
							 | 
						||
| 
								 | 
							
								          The key can be generated using the <literal>dnssec-keygen</literal>
							 | 
						||
| 
								 | 
							
								          command, provided by the package <package>bind</package> as follows:
							 | 
						||
| 
								 | 
							
								          <programlisting>
							 | 
						||
| 
								 | 
							
								          $ dnssec-keygen -a RSASHA256 -3 -b 2048 bit
							 | 
						||
| 
								 | 
							
								          </programlisting>
							 | 
						||
| 
								 | 
							
								        '';
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      dnssec.keys.zonePrivate = mkOption {
							 | 
						||
| 
								 | 
							
								        type = types.path;
							 | 
						||
| 
								 | 
							
								        default = defaultFiles.zonePrivate;
							 | 
						||
| 
								 | 
							
								        description = ''
							 | 
						||
| 
								 | 
							
								          Path to the file containing the ZSK private key.
							 | 
						||
| 
								 | 
							
								        '';
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      settings = mkOption {
							 | 
						||
| 
								 | 
							
								        type = configType;
							 | 
						||
| 
								 | 
							
								        default = { };
							 | 
						||
| 
								 | 
							
								        example = literalExample ''
							 | 
						||
| 
								 | 
							
								          { # enable webserver
							 | 
						||
| 
								 | 
							
								            ncdns.httplistenaddr = ":8202";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            # synchronize TLS certs
							 | 
						||
| 
								 | 
							
								            certstore.nss = true;
							 | 
						||
| 
								 | 
							
								            # note: all paths are relative to the config file
							 | 
						||
| 
								 | 
							
								            certstore.nsscertdir =  "../../var/lib/ncdns";
							 | 
						||
| 
								 | 
							
								            certstore.nssdbdir = "../../home/alice/.pki/nssdb";
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        '';
							 | 
						||
| 
								 | 
							
								        description = ''
							 | 
						||
| 
								 | 
							
								          ncdns settings. Use this option to configure ncds
							 | 
						||
| 
								 | 
							
								          settings not exposed in a NixOS option or to bypass one.
							 | 
						||
| 
								 | 
							
								          See the example ncdns.conf file at <link xlink:href="
							 | 
						||
| 
								 | 
							
								          https://git.io/JfX7g"/> for the available options.
							 | 
						||
| 
								 | 
							
								        '';
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    services.pdns-recursor.resolveNamecoin = mkOption {
							 | 
						||
| 
								 | 
							
								      type = types.bool;
							 | 
						||
| 
								 | 
							
								      default = false;
							 | 
						||
| 
								 | 
							
								      description = ''
							 | 
						||
| 
								 | 
							
								        Resolve <literal>.bit</literal> top-level domains using ncdns and namecoin.
							 | 
						||
| 
								 | 
							
								      '';
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ###### implementation
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  config = mkIf cfg.enable {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    services.pdns-recursor = mkIf cfgs.pdns-recursor.resolveNamecoin {
							 | 
						||
| 
								 | 
							
								      forwardZonesRecurse.bit = "127.0.0.1:${toString cfg.port}";
							 | 
						||
| 
								 | 
							
								      luaConfig =
							 | 
						||
| 
								 | 
							
								        if cfg.dnssec.enable
							 | 
						||
| 
								 | 
							
								          then ''readTrustAnchorsFromFile("${cfg.dnssec.keys.public}")''
							 | 
						||
| 
								 | 
							
								          else ''addNTA("bit", "namecoin DNSSEC disabled")'';
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Avoid pdns-recursor not finding the DNSSEC keys
							 | 
						||
| 
								 | 
							
								    systemd.services.pdns-recursor = mkIf cfgs.pdns-recursor.resolveNamecoin {
							 | 
						||
| 
								 | 
							
								      after = [ "ncdns.service" ];
							 | 
						||
| 
								 | 
							
								      wants = [ "ncdns.service" ];
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    services.ncdns.settings = mkDefaultAttrs {
							 | 
						||
| 
								 | 
							
								      ncdns =
							 | 
						||
| 
								 | 
							
								        { # Namecoin RPC
							 | 
						||
| 
								 | 
							
								          namecoinrpcaddress =
							 | 
						||
| 
								 | 
							
								            "${cfgs.namecoind.rpc.address}:${toString cfgs.namecoind.rpc.port}";
							 | 
						||
| 
								 | 
							
								          namecoinrpcusername = cfgs.namecoind.rpc.user;
							 | 
						||
| 
								 | 
							
								          namecoinrpcpassword = cfgs.namecoind.rpc.password;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          # Identity
							 | 
						||
| 
								 | 
							
								          selfname = cfg.identity.hostname;
							 | 
						||
| 
								 | 
							
								          hostmaster = cfg.identity.hostmaster;
							 | 
						||
| 
								 | 
							
								          selfip = cfg.identity.address;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          # Other
							 | 
						||
| 
								 | 
							
								          bind = "${cfg.address}:${toString cfg.port}";
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        // optionalAttrs cfg.dnssec.enable
							 | 
						||
| 
								 | 
							
								        { # DNSSEC
							 | 
						||
| 
								 | 
							
								          publickey  = "../.." + cfg.dnssec.keys.public;
							 | 
						||
| 
								 | 
							
								          privatekey = "../.." + cfg.dnssec.keys.private;
							 | 
						||
| 
								 | 
							
								          zonepublickey  = "../.." + cfg.dnssec.keys.zonePublic;
							 | 
						||
| 
								 | 
							
								          zoneprivatekey = "../.." + cfg.dnssec.keys.zonePrivate;
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        # Daemon
							 | 
						||
| 
								 | 
							
								        service.daemon = true;
							 | 
						||
| 
								 | 
							
								        xlog.journal = true;
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    users.users.ncdns =
							 | 
						||
| 
								 | 
							
								      { description = "ncdns daemon user"; };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    systemd.services.ncdns = {
							 | 
						||
| 
								 | 
							
								      description = "ncdns daemon";
							 | 
						||
| 
								 | 
							
								      after    = [ "namecoind.service" ];
							 | 
						||
| 
								 | 
							
								      wantedBy = [ "multi-user.target" ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      serviceConfig = {
							 | 
						||
| 
								 | 
							
								        User = "ncdns";
							 | 
						||
| 
								 | 
							
								        StateDirectory = "ncdns";
							 | 
						||
| 
								 | 
							
								        Restart = "on-failure";
							 | 
						||
| 
								 | 
							
								        ExecStart = "${pkgs.ncdns}/bin/ncdns -conf=${configFile}";
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      preStart = optionalString (cfg.dnssec.enable && needsKeygen) ''
							 | 
						||
| 
								 | 
							
								        cd ${dataDir}
							 | 
						||
| 
								 | 
							
								        if [ ! -e bit.key ]; then
							 | 
						||
| 
								 | 
							
								          ${pkgs.bind}/bin/dnssec-keygen -a RSASHA256 -3 -b 2048 bit
							 | 
						||
| 
								 | 
							
								          mv Kbit.*.key bit-zone.key
							 | 
						||
| 
								 | 
							
								          mv Kbit.*.private bit-zone.private
							 | 
						||
| 
								 | 
							
								          ${pkgs.bind}/bin/dnssec-keygen -a RSASHA256 -3 -b 2048 -f KSK bit
							 | 
						||
| 
								 | 
							
								          mv Kbit.*.key bit.key
							 | 
						||
| 
								 | 
							
								          mv Kbit.*.private bit.private
							 | 
						||
| 
								 | 
							
								        fi
							 | 
						||
| 
								 | 
							
								      '';
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  meta.maintainers = with lib.maintainers; [ rnhmjoj ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 |