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 ];
 | 
						|
 | 
						|
}
 |