about summary refs log tree commit diff
path: root/nixos/tests/knot.nix
diff options
context:
space:
mode:
authorMartin Weinelt <martin@linuxlounge.net>2019-03-13 01:12:56 +0100
committerMartin Weinelt <hexa@darmstadt.ccc.de>2019-03-14 01:28:53 +0100
commita978d3dcd2aa24d7b82d2e99255d3d2354cf81a0 (patch)
tree185a5ac68dcd58674eca9e1ce9513d9752723e5a /nixos/tests/knot.nix
parent5b0502dc85a413e0ad26f84078492a4271e7f456 (diff)
nixos/knot: init
Diffstat (limited to 'nixos/tests/knot.nix')
-rw-r--r--nixos/tests/knot.nix197
1 files changed, 197 insertions, 0 deletions
diff --git a/nixos/tests/knot.nix b/nixos/tests/knot.nix
new file mode 100644
index 0000000000000..e46159836ccc0
--- /dev/null
+++ b/nixos/tests/knot.nix
@@ -0,0 +1,197 @@
+import ./make-test.nix ({ pkgs, lib, ...} :
+let
+  common = {
+    networking.firewall.enable = false;
+    networking.useDHCP = false;
+  };
+  exampleZone = pkgs.writeTextDir "example.com.zone" ''
+      @ SOA ns.example.com. noc.example.com. 2019031301 86400 7200 3600000 172800
+      @       NS      ns1
+      @       NS      ns2
+      ns1     A       192.168.0.1
+      ns1     AAAA    fd00::1
+      ns2     A       192.168.0.2
+      ns2     AAAA    fd00::2
+      www     A       192.0.2.1
+      www     AAAA    2001:DB8::1
+      sub     NS      ns.example.com.
+  '';
+  delegatedZone = pkgs.writeTextDir "sub.example.com.zone" ''
+      @ SOA ns.example.com. noc.example.com. 2019031301 86400 7200 3600000 172800
+      @       NS      ns1.example.com.
+      @       NS      ns2.example.com.
+      @       A       192.0.2.2
+      @       AAAA    2001:DB8::2
+  '';
+
+  knotZonesEnv = pkgs.buildEnv {
+    name = "knot-zones";
+    paths = [ exampleZone delegatedZone ];
+  };
+in {
+  name = "knot";
+
+  nodes = {
+    master = { lib, ... }: {
+      imports = [ common ];
+      networking.interfaces.eth1 = {
+        ipv4.addresses = lib.mkForce [
+          { address = "192.168.0.1"; prefixLength = 24; }
+        ];
+        ipv6.addresses = lib.mkForce [
+          { address = "fd00::1"; prefixLength = 64; }
+        ];
+      };
+      services.knot.enable = true;
+      services.knot.extraArgs = [ "-v" ];
+      services.knot.extraConfig = ''
+        server:
+            listen: 0.0.0.0@53
+            listen: ::@53
+
+        acl:
+          - id: slave_acl
+            address: 192.168.0.2
+            action: transfer
+
+        remote:
+          - id: slave
+            address: 192.168.0.2@53
+
+        template:
+          - id: default
+            storage: ${knotZonesEnv}
+            notify: [slave]
+            acl: [slave_acl]
+            dnssec-signing: on
+            # Input-only zone files
+            # https://www.knot-dns.cz/docs/2.8/html/operation.html#example-3
+            # prevents modification of the zonefiles, since the zonefiles are immutable
+            zonefile-sync: -1
+            zonefile-load: difference
+            journal-content: changes
+            # move databases below the state directory, because they need to be writable
+            journal-db: /var/lib/knot/journal
+            kasp-db: /var/lib/knot/kasp
+            timer-db: /var/lib/knot/timer
+
+        zone:
+          - domain: example.com
+            file: example.com.zone
+
+          - domain: sub.example.com
+            file: sub.example.com.zone
+
+        log:
+          - target: syslog
+            any: info
+      '';
+    };
+
+    slave = { lib, ... }: {
+      imports = [ common ];
+      networking.interfaces.eth1 = {
+        ipv4.addresses = lib.mkForce [
+          { address = "192.168.0.2"; prefixLength = 24; }
+        ];
+        ipv6.addresses = lib.mkForce [
+          { address = "fd00::2"; prefixLength = 64; }
+        ];
+      };
+      services.knot.enable = true;
+      services.knot.extraArgs = [ "-v" ];
+      services.knot.extraConfig = ''
+        server:
+            listen: 0.0.0.0@53
+            listen: ::@53
+
+        acl:
+          - id: notify_from_master
+            address: 192.168.0.1
+            action: notify
+
+        remote:
+          - id: master
+            address: 192.168.0.1@53
+
+        template:
+          - id: default
+            master: master
+            acl: [notify_from_master]
+            # zonefileless setup
+            # https://www.knot-dns.cz/docs/2.8/html/operation.html#example-2
+            zonefile-sync: -1
+            zonefile-load: none
+            journal-content: all
+            # move databases below the state directory, because they need to be writable
+            journal-db: /var/lib/knot/journal
+            kasp-db: /var/lib/knot/kasp
+            timer-db: /var/lib/knot/timer
+
+        zone:
+          - domain: example.com
+            file: example.com.zone
+
+          - domain: sub.example.com
+            file: sub.example.com.zone
+
+        log:
+          - target: syslog
+            any: info
+      '';
+    };
+    client = { lib, nodes, ... }: {
+      imports = [ common ];
+      networking.interfaces.eth1 = {
+        ipv4.addresses = [
+          { address = "192.168.0.3"; prefixLength = 24; }
+        ];
+        ipv6.addresses = [
+          { address = "fd00::3"; prefixLength = 64; }
+        ];
+      };
+      environment.systemPackages = [ pkgs.knot-dns ];
+    };    
+  };
+
+  testScript = { nodes, ... }: let 
+    master4 = (lib.head nodes.master.config.networking.interfaces.eth1.ipv4.addresses).address;
+    master6 = (lib.head nodes.master.config.networking.interfaces.eth1.ipv6.addresses).address;
+
+    slave4 = (lib.head nodes.slave.config.networking.interfaces.eth1.ipv4.addresses).address;
+    slave6 = (lib.head nodes.slave.config.networking.interfaces.eth1.ipv6.addresses).address;
+  in ''
+    startAll;
+
+    $client->waitForUnit("network.target");
+    $master->waitForUnit("knot.service");
+    $slave->waitForUnit("knot.service");
+
+    sub assertResponse {
+      my ($knot, $query_type, $query, $expected) = @_;
+      my $out = $client->succeed("khost -t $query_type $query $knot");
+      $client->log("$knot replies with: $out");
+      chomp $out;
+      die "DNS query for $query ($query_type) against $knot gave '$out' instead of '$expected'"
+        if ($out !~ $expected);
+    }
+
+    foreach ("${master4}", "${master6}", "${slave4}", "${slave6}") {
+      subtest $_, sub {
+        assertResponse($_, "SOA", "example.com", qr/start of authority.*?noc\.example\.com/);
+        assertResponse($_, "A", "example.com", qr/has no [^ ]+ record/);
+        assertResponse($_, "AAAA", "example.com", qr/has no [^ ]+ record/);
+
+        assertResponse($_, "A", "www.example.com", qr/address 192.0.2.1$/);
+        assertResponse($_, "AAAA", "www.example.com", qr/address 2001:db8::1$/);
+
+        assertResponse($_, "NS", "sub.example.com", qr/nameserver is ns\d\.example\.com.$/);
+        assertResponse($_, "A", "sub.example.com", qr/address 192.0.2.2$/);
+        assertResponse($_, "AAAA", "sub.example.com", qr/address 2001:db8::2$/);
+
+        assertResponse($_, "RRSIG", "www.example.com", qr/RR set signature is/);
+        assertResponse($_, "DNSKEY", "example.com", qr/DNSSEC key is/);
+      };
+    }
+  '';
+})