diff options
author | Michele Guerini Rocco <rnhmjoj@users.noreply.github.com> | 2020-07-07 10:58:55 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-07 10:58:55 +0200 |
commit | fc553c0bc5411478e2448a707f74369ae9351e96 (patch) | |
tree | 1d43e1bb3802d53983615a73fe716b7a9513585a /nixos | |
parent | 01c4a388ee49f3df5c71fb2886c926beda660577 (diff) | |
parent | 8ff681a7caeec1b6138f03242823ec95983a066c (diff) | |
download | nixpkgs-fc553c0bc5411478e2448a707f74369ae9351e96.tar nixpkgs-fc553c0bc5411478e2448a707f74369ae9351e96.tar.gz nixpkgs-fc553c0bc5411478e2448a707f74369ae9351e96.tar.bz2 nixpkgs-fc553c0bc5411478e2448a707f74369ae9351e96.tar.lz nixpkgs-fc553c0bc5411478e2448a707f74369ae9351e96.tar.xz nixpkgs-fc553c0bc5411478e2448a707f74369ae9351e96.tar.zst nixpkgs-fc553c0bc5411478e2448a707f74369ae9351e96.zip |
Merge pull request #89773 from rnhmjoj/ncdns
ncdns: init at 0.0.10.3
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/modules/module-list.nix | 1 | ||||
-rw-r--r-- | nixos/modules/services/networking/ncdns.nix | 278 | ||||
-rw-r--r-- | nixos/tests/all-tests.nix | 1 | ||||
-rw-r--r-- | nixos/tests/ncdns.nix | 77 |
4 files changed, 357 insertions, 0 deletions
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index fe6da60132d..f361163ca63 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -607,6 +607,7 @@ ./services/networking/dnscrypt-wrapper.nix ./services/networking/dnsdist.nix ./services/networking/dnsmasq.nix + ./services/networking/ncdns.nix ./services/networking/ejabberd.nix ./services/networking/epmd.nix ./services/networking/ergo.nix diff --git a/nixos/modules/services/networking/ncdns.nix b/nixos/modules/services/networking/ncdns.nix new file mode 100644 index 00000000000..c1832ad1752 --- /dev/null +++ b/nixos/modules/services/networking/ncdns.nix @@ -0,0 +1,278 @@ +{ 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 ]; + +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 4eb6849cfc6..7f3bb9bcc81 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -221,6 +221,7 @@ in nat.firewall = handleTest ./nat.nix { withFirewall = true; }; nat.firewall-conntrack = handleTest ./nat.nix { withFirewall = true; withConntrackHelpers = true; }; nat.standalone = handleTest ./nat.nix { withFirewall = false; }; + ncdns = handleTest ./ncdns.nix {}; ndppd = handleTest ./ndppd.nix {}; neo4j = handleTest ./neo4j.nix {}; specialisation = handleTest ./specialisation.nix {}; diff --git a/nixos/tests/ncdns.nix b/nixos/tests/ncdns.nix new file mode 100644 index 00000000000..507e20fe7cc --- /dev/null +++ b/nixos/tests/ncdns.nix @@ -0,0 +1,77 @@ +import ./make-test-python.nix ({ pkgs, ... }: +let + fakeReply = pkgs.writeText "namecoin-reply.json" '' + { "error": null, + "id": 1, + "result": { + "address": "T31q8ucJ4dI1xzhxQ5QispfECld5c7Xw", + "expired": false, + "expires_in": 2248, + "height": 438155, + "name": "d/test", + "txid": "db61c0b2540ba0c1a2c8cc92af703a37002e7566ecea4dbf8727c7191421edfb", + "value": "{\"ip\": \"1.2.3.4\", \"email\": \"root@test.bit\",\"info\": \"Fake record\"}", + "vout": 0 + } + } + ''; +in + +{ + name = "ncdns"; + + nodes.server = { ... }: { + networking.nameservers = [ "127.0.0.1" ]; + + services.namecoind.rpc = { + address = "127.0.0.1"; + user = "namecoin"; + password = "secret"; + port = 8332; + }; + + # Fake namecoin RPC server because we can't + # run a full node in a test. + systemd.services.namecoind = { + wantedBy = [ "multi-user.target" ]; + script = '' + while true; do + echo -e "HTTP/1.1 200 OK\n\n $(<${fakeReply})\n" \ + | ${pkgs.netcat}/bin/nc -N -l 127.0.0.1 8332 + done + ''; + }; + + services.ncdns = { + enable = true; + dnssec.enable = true; + }; + + services.pdns-recursor = { + enable = true; + dns.allowFrom = [ "127.0.0.0/8" ]; + settings.loglevel = 8; + resolveNamecoin = true; + }; + + environment.systemPackages = [ pkgs.dnsutils ]; + + }; + + testScript = '' + with subtest("DNSSEC keys have been generated"): + server.wait_for_unit("ncdns") + server.wait_for_file("/var/lib/ncdns/bit.key") + server.wait_for_file("/var/lib/ncdns/bit-zone.key") + + with subtest("DNSKEY bit record is present"): + server.wait_for_unit("pdns-recursor") + server.wait_for_open_port("53") + server.succeed("host -t DNSKEY bit") + + with subtest("can resolve a .bit name"): + server.wait_for_unit("namecoind") + server.wait_for_open_port("8332") + assert "1.2.3.4" in server.succeed("host -t A test.bit") + ''; +}) |