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 services.namecoind.enable = true;
+ 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:
+
+ bit. IN NS ns1.example.com.
+
+ If unset ncdns will generate an internal psuedo-hostname under the
+ zone, which will resolve to the value of
+ .
+ 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
+ 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
+ ,
+ 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 dnssec-keygen
+ command, provided by the package bind as follows:
+
+ $ dnssec-keygen -a RSASHA256 -3 -b 2048 -f KSK bit
+
+ '';
+ };
+
+ 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 dnssec-keygen
+ command, provided by the package bind as follows:
+
+ $ dnssec-keygen -a RSASHA256 -3 -b 2048 bit
+
+ '';
+ };
+
+ 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 for the available options.
+ '';
+ };
+
+ };
+
+ services.pdns-recursor.resolveNamecoin = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Resolve .bit 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")
+ '';
+})
diff --git a/pkgs/servers/dns/ncdns/default.nix b/pkgs/servers/dns/ncdns/default.nix
new file mode 100644
index 00000000000..15e400ebad5
--- /dev/null
+++ b/pkgs/servers/dns/ncdns/default.nix
@@ -0,0 +1,41 @@
+{ lib, nixosTests, git, buildGoPackage, fetchFromGitHub, libcap }:
+
+buildGoPackage rec {
+ pname = "ncdns";
+ version = "0.0.10.3";
+
+ goPackagePath = "github.com/namecoin/ncdns";
+ goDeps = ./deps.nix;
+
+ src = fetchFromGitHub {
+ owner = "namecoin";
+ repo = "ncdns";
+ rev = "v${version}";
+ sha256 = "12q5al48mkjhgyk7z5wyklzzrdbcqhwxl79axa4gh9ld75prghbq";
+ };
+
+ patches = [ ./fix-tpl-path.nix ];
+
+ buildInputs = [ libcap ];
+
+ preBuild = ''
+ go generate github.com/namecoin/x509-signature-splice/...
+ '';
+
+ postInstall = ''
+ mkdir -p "$out/share"
+ cp -r "$src/_doc" "$out/share/doc"
+ cp -r "$src/_tpl" "$out/share/tpl"
+ '';
+
+ meta = with lib; {
+ description = "Namecoin to DNS bridge daemon";
+ homepage = "https://github.com/namecoin/ncdns";
+ license = licenses.gpl3Plus;
+ platforms = platforms.all;
+ maintainers = with maintainers; [ rnhmjoj ];
+ };
+
+ passthru.tests.ncdns = nixosTests.ncdns;
+
+}
diff --git a/pkgs/servers/dns/ncdns/deps.nix b/pkgs/servers/dns/ncdns/deps.nix
new file mode 100644
index 00000000000..7ac3f2897e0
--- /dev/null
+++ b/pkgs/servers/dns/ncdns/deps.nix
@@ -0,0 +1,309 @@
+# This file was generated by https://github.com/kamilchm/go2nix v1.3.0
+[
+ {
+ goPackagePath = "github.com/BurntSushi/toml";
+ fetch = {
+ type = "git";
+ url = "https://github.com/BurntSushi/toml";
+ rev = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005";
+ sha256 = "1fjdwwfzyzllgiwydknf1pwjvy49qxfsczqx5gz3y0izs7as99j6";
+ };
+ }
+ {
+ goPackagePath = "github.com/alecthomas/template";
+ fetch = {
+ type = "git";
+ url = "https://github.com/alecthomas/template";
+ rev = "fb15b899a75114aa79cc930e33c46b577cc664b1";
+ sha256 = "1vlasv4dgycydh5wx6jdcvz40zdv90zz1h7836z7lhsi2ymvii26";
+ };
+ }
+ {
+ goPackagePath = "github.com/alecthomas/units";
+ fetch = {
+ type = "git";
+ url = "https://github.com/alecthomas/units";
+ rev = "f65c72e2690dc4b403c8bd637baf4611cd4c069b";
+ sha256 = "04jyqm7m3m01ppfy1f9xk4qvrwvs78q9zml6llyf2b3v5k6b2bbc";
+ };
+ }
+ {
+ goPackagePath = "github.com/btcsuite/btcd";
+ fetch = {
+ type = "git";
+ url = "https://github.com/btcsuite/btcd";
+ rev = "9f0179fd2c46caba343b6515602cf37172f14d5f";
+ sha256 = "0cvpjsxlyzm04pwzi7nj43k9h5wfxj07jdc49qxsav5323v1nvka";
+ };
+ }
+ {
+ goPackagePath = "github.com/btcsuite/btclog";
+ fetch = {
+ type = "git";
+ url = "https://github.com/btcsuite/btclog";
+ rev = "84c8d2346e9fc8c7b947e243b9c24e6df9fd206a";
+ sha256 = "02dl46wcnfpg9sqvg0ipipkpnd7lrf4fnvb9zy56jqa7mfcwc7wk";
+ };
+ }
+ {
+ goPackagePath = "github.com/btcsuite/btcutil";
+ fetch = {
+ type = "git";
+ url = "https://github.com/btcsuite/btcutil";
+ rev = "b2bf7f89d674a3702182b7e15f52807896051af3";
+ sha256 = "0wwykb4cbq8xj2mls2mxma5vaahdgdy3vqw1r2fi4wyj0yr4kyw9";
+ };
+ }
+ {
+ goPackagePath = "github.com/btcsuite/go-socks";
+ fetch = {
+ type = "git";
+ url = "https://github.com/btcsuite/go-socks";
+ rev = "4720035b7bfd2a9bb130b1c184f8bbe41b6f0d0f";
+ sha256 = "18cv2icj059lq4s99p6yh91hlas5f2gi3f1p4c10sjgwrs933d7b";
+ };
+ }
+ {
+ goPackagePath = "github.com/btcsuite/websocket";
+ fetch = {
+ type = "git";
+ url = "https://github.com/btcsuite/websocket";
+ rev = "31079b6807923eb23992c421b114992b95131b55";
+ sha256 = "0xpkf257ml6fpfdgv7hxxc41n0d5yxxm3njm50qpzp7j71l9cjwa";
+ };
+ }
+ {
+ goPackagePath = "github.com/coreos/go-systemd";
+ fetch = {
+ type = "git";
+ url = "https://github.com/coreos/go-systemd";
+ rev = "b51e752dd1c9c618846f8bc5b95ab524bd7b11c2";
+ sha256 = "127dj1iwp69yj74nwh9ckgc0mkk1mv4yzbxmbdxix1r7j6q35z3j";
+ };
+ }
+ {
+ goPackagePath = "github.com/golang/groupcache";
+ fetch = {
+ type = "git";
+ url = "https://github.com/golang/groupcache";
+ rev = "8c9f03a8e57eb486e42badaed3fb287da51807ba";
+ sha256 = "0vjjr79r32icjzlb05wn02k59av7jx0rn1jijml8r4whlg7dnkfh";
+ };
+ }
+ {
+ goPackagePath = "github.com/hlandau/buildinfo";
+ fetch = {
+ type = "git";
+ url = "https://github.com/hlandau/buildinfo";
+ rev = "337a29b5499734e584d4630ce535af64c5fe7813";
+ sha256 = "1kq3r1i4rr9bcvj5yg8w1l95f6sfc3kn6kgcdmlh5i3j9w2sram8";
+ };
+ }
+ {
+ goPackagePath = "github.com/hlandau/degoutils";
+ fetch = {
+ type = "git";
+ url = "https://github.com/hlandau/degoutils";
+ rev = "8fa2440b63444dad556d76366f1c3ee070c8a577";
+ sha256 = "1yj39jbrk3xx3cyl8f4asakc74lsl0brasi25xjf6219pg69q0iy";
+ };
+ }
+ {
+ goPackagePath = "github.com/hlandau/dexlogconfig";
+ fetch = {
+ type = "git";
+ url = "https://github.com/hlandau/dexlogconfig";
+ rev = "244f29bd260884993b176cd14ef2f7631f6f3c18";
+ sha256 = "1d01ghx6xawj3nk3lpk51wbbpxdnc9vzvijvlayvp7cxgsacslbc";
+ };
+ }
+ {
+ goPackagePath = "github.com/hlandau/xlog";
+ fetch = {
+ type = "git";
+ url = "https://github.com/hlandau/xlog";
+ rev = "197ef798aed28e08ed3e176e678fda81be993a31";
+ sha256 = "08rjlqnjbfgpz5rbjq89l7y5vyhk99ivr928sqdi5gnqznbqs4m8";
+ };
+ }
+ {
+ goPackagePath = "github.com/kr/pretty";
+ fetch = {
+ type = "git";
+ url = "https://github.com/kr/pretty";
+ rev = "4e0886370c3a67530192c6a238cff68f56c141b0";
+ sha256 = "1ywbfzz1h3a3qd8rpkiqwi1dm4w8ls9ijb4x1b7567grns9f0vnp";
+ };
+ }
+ {
+ goPackagePath = "github.com/kr/text";
+ fetch = {
+ type = "git";
+ url = "https://github.com/kr/text";
+ rev = "702c74938df48b97370179f33ce2107bd7ff3b3e";
+ sha256 = "0hf58ypz6rxsw6nx3i856whir9lvy4sdx946wbw1nfaf2rdmr9vx";
+ };
+ }
+ {
+ goPackagePath = "github.com/mattn/go-isatty";
+ fetch = {
+ type = "git";
+ url = "https://github.com/mattn/go-isatty";
+ rev = "cb30d6282491c185f77d9bec5d25de1bb61a06bc";
+ sha256 = "0v59mv94acd2m72q8adhigxkx1vn38l5h0d8hp0nxga2v9f3v8kd";
+ };
+ }
+ {
+ goPackagePath = "github.com/miekg/dns";
+ fetch = {
+ type = "git";
+ url = "https://github.com/miekg/dns";
+ rev = "203ad2480beb9330454efc215d21f16c607e8174";
+ sha256 = "12i2l79whv7a8c27f1dvq4wqikx4d0l30r1ja68zfgrgik6vryxq";
+ };
+ }
+ {
+ goPackagePath = "github.com/namecoin/btcd";
+ fetch = {
+ type = "git";
+ url = "https://github.com/namecoin/btcd";
+ rev = "69a10543311fa68737d0a77b4cd045b0b0abfb75";
+ sha256 = "1zbfigs3hrjhdwp19877lpgivdcz3k80149nxdmxlmp03xcswcqy";
+ };
+ }
+ {
+ goPackagePath = "github.com/namecoin/ncbtcjson";
+ fetch = {
+ type = "git";
+ url = "https://github.com/namecoin/ncbtcjson";
+ rev = "fa221af062c70f802db6ed66e1546cc4a41ec277";
+ sha256 = "1fmz5aylsji27vj5f3f3gg9xj99735gh5prvcfz0gmk68v1mnr4i";
+ };
+ }
+ {
+ goPackagePath = "github.com/namecoin/ncrpcclient";
+ fetch = {
+ type = "git";
+ url = "https://github.com/namecoin/ncrpcclient";
+ rev = "858e1a5acd8b2da56462f50323633cdf2fe80977";
+ sha256 = "0pj951wm6fdkk2yv4bxaxka52i7rb6w3fs9ah3fy7p8wchr4smjx";
+ };
+ }
+ {
+ goPackagePath = "github.com/namecoin/tlsrestrictnss";
+ fetch = {
+ type = "git";
+ url = "https://github.com/namecoin/tlsrestrictnss";
+ rev = "945a9f3d995fcb175fd0b19549e21a3e87ba8c13";
+ sha256 = "18qphkqnjw3bwflkyyrddyzgwscs37j7y6ynm9g78bqb5skviqqy";
+ };
+ }
+ {
+ goPackagePath = "github.com/namecoin/x509-signature-splice";
+ fetch = {
+ type = "git";
+ url = "https://github.com/namecoin/x509-signature-splice";
+ rev = "d8b4bf2df701c55239a9fe82bb1e7bea10e30599";
+ sha256 = "0jlj4gb60s7b69d8yx6ljhxgvqgjz01n0h59fswblw09wfba8c4j";
+ };
+ }
+ {
+ goPackagePath = "github.com/ogier/pflag";
+ fetch = {
+ type = "git";
+ url = "https://github.com/ogier/pflag";
+ rev = "45c278ab3607870051a2ea9040bb85fcb8557481";
+ sha256 = "0620v75wppfd84d95n312wpngcb73cph4q3ivs1h0waljfnsrd5l";
+ };
+ }
+ {
+ goPackagePath = "github.com/shiena/ansicolor";
+ fetch = {
+ type = "git";
+ url = "https://github.com/shiena/ansicolor";
+ rev = "a422bbe96644373c5753384a59d678f7d261ff10";
+ sha256 = "1dcn8a9z6a5dxa2m3fkppnajcls8lanbl38qggkf646yi5qsk1hc";
+ };
+ }
+ {
+ goPackagePath = "golang.org/x/crypto";
+ fetch = {
+ type = "git";
+ url = "https://go.googlesource.com/crypto";
+ rev = "279210d13fedf5be6d476bad5df6a015042bb905";
+ sha256 = "0syi72jba84nn1z89bqpcv94wjvzj71dwg1pj30xrcixcz1zsg26";
+ };
+ }
+ {
+ goPackagePath = "golang.org/x/net";
+ fetch = {
+ type = "git";
+ url = "https://go.googlesource.com/net";
+ rev = "627f9648deb96c27737b83199d44bb5c1010cbcf";
+ sha256 = "0ziz7i9mhz6dy2f58dsa83flkk165w1cnazm7yksql5i9m7x099z";
+ };
+ }
+ {
+ goPackagePath = "golang.org/x/sys";
+ fetch = {
+ type = "git";
+ url = "https://go.googlesource.com/sys";
+ rev = "6fdc65e7d9800cc59998e8ac0d9406a20ff5f399";
+ sha256 = "0al5gzij4qkrp11i1h8j7288pg6y716zyh2v0886pv2knha7gjvj";
+ };
+ }
+ {
+ goPackagePath = "gopkg.in/alecthomas/kingpin.v2";
+ fetch = {
+ type = "git";
+ url = "https://gopkg.in/alecthomas/kingpin.v2";
+ rev = "947dcec5ba9c011838740e680966fd7087a71d0d";
+ sha256 = "0mndnv3hdngr3bxp7yxfd47cas4prv98sqw534mx7vp38gd88n5r";
+ };
+ }
+ {
+ goPackagePath = "gopkg.in/hlandau/configurable.v1";
+ fetch = {
+ type = "git";
+ url = "https://gopkg.in/hlandau/configurable.v1";
+ rev = "41496864a1fe3e0fef2973f22372b755d2897402";
+ sha256 = "0i9jbdvi8rz12xsrzzbfxg5lwsqakjcmccsa5a32asmv26k5byqa";
+ };
+ }
+ {
+ goPackagePath = "gopkg.in/hlandau/easyconfig.v1";
+ fetch = {
+ type = "git";
+ url = "https://gopkg.in/hlandau/easyconfig.v1";
+ rev = "c31249162931b4963bbe6e501cccb60d23271a3f";
+ sha256 = "1v8j1pyzcfj1l4pmb1c6mszci6xzc4agdam2kq79kyvbsvbbw9dc";
+ };
+ }
+ {
+ goPackagePath = "gopkg.in/hlandau/madns.v2";
+ fetch = {
+ type = "git";
+ url = "https://gopkg.in/hlandau/madns.v2";
+ rev = "26979b3e4b5aa3e0bd53cf0a014f9eaf43b578e3";
+ sha256 = "09r4m4mqdgd7hvxyvss9m64lq0kk8nylnq2bgnkrclgzpi87fmmb";
+ };
+ }
+ {
+ goPackagePath = "gopkg.in/hlandau/service.v2";
+ fetch = {
+ type = "git";
+ url = "https://gopkg.in/hlandau/service.v2";
+ rev = "b64b3467ebd16f64faec1640c25e318efc0c0d7b";
+ sha256 = "0lpx88f46ylx9lf6jgwcjgklll1pc1mlakrywpa0wzhjj7a4jinc";
+ };
+ }
+ {
+ goPackagePath = "gopkg.in/hlandau/svcutils.v1";
+ fetch = {
+ type = "git";
+ url = "https://gopkg.in/hlandau/svcutils.v1";
+ rev = "c25dac49e50cbbcbef8c81b089f56156f4067729";
+ sha256 = "12b6p71mk33r44d71xizjq82fls0ykfwfl5gnmckbgpxms4bj2xf";
+ };
+ }
+]
diff --git a/pkgs/servers/dns/ncdns/fix-tpl-path.nix b/pkgs/servers/dns/ncdns/fix-tpl-path.nix
new file mode 100644
index 00000000000..850fb4d1b18
--- /dev/null
+++ b/pkgs/servers/dns/ncdns/fix-tpl-path.nix
@@ -0,0 +1,27 @@
+This sets a default value for the tpl directory that works for Nixpkgs.
+
+diff --git a/server/web.go b/server/web.go
+index d024a42..0522d02 100644
+--- a/server/web.go
++++ b/server/web.go
+@@ -10,6 +10,7 @@ import "path/filepath"
+ import "time"
+ import "strings"
+ import "fmt"
++import "os"
+
+ var layoutTpl *template.Template
+ var mainPageTpl *template.Template
+@@ -44,7 +45,11 @@ func deriveTemplate(filename string) (*template.Template, error) {
+ }
+
+ func (s *Server) tplFilename(filename string) string {
+- td := filepath.Join(s.cfg.ConfigDir, "..", "tpl")
++ ex, err := os.Executable()
++ if err != nil {
++ panic(err)
++ }
++ td := filepath.Join(filepath.Dir(ex), "..", "share", "tpl")
+ if s.cfg.TplPath != "" {
+ td = s.cfg.TplPath
+ }
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 3c55c04cf98..d86b5839667 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -16012,6 +16012,8 @@ in
unit = callPackage ../servers/http/unit { };
+ ncdns = callPackage ../servers/dns/ncdns { };
+
nginx = nginxStable;
nginxStable = callPackage ../servers/http/nginx/stable.nix {