{ pkgs, lib, config, info, ... }: let inherit (lib) types; inherit (config.services) knot; inherit (config.users) users groups; in { imports = [ knot/autogeree.net.nix knot/sourcephile.fr.nix ]; options.services.knot = { zones = lib.mkOption { default = { }; type = types.attrsOf (types.submodule ({ ... }: { #config.domain = lib.mkDefault name; options = { conf = lib.mkOption { type = types.lines; }; data = lib.mkOption { type = types.nullOr types.lines; }; }; })); }; }; config = { systemd.services.knot.serviceConfig.ExecStartPre = lib.mapAttrsToList (domain: { data, ... }: '' +${pkgs.coreutils}/bin/install -D -o ${users.knot.name} -g ${groups."knot".name} -m 700 \ ${pkgs.writeText "${domain}.zone" data} \ /var/lib/knot/zones/${domain}.zone '') knot.zones; /* systemd.services.knot.postStart = lib.mkAfter '' PATH="/run/current-system/sw/bin:$PATH" knotc zone-freeze ${domain}. while ! knotc zone-status ${domain}. +freeze | grep -q 'freeze: yes'; do sleep 1; done knotc zone-flush ${domain}. install -o knot -g knot -m 700 ${zone} /var/lib/knot/signed/${domain}.zone knotc zone-reload ${domain}. knotc zone-thaw ${domain}. ''; */ networking.nftables.ruleset = '' table inet filter { chain input-net { meta l4proto { udp, tcp } th dport domain counter accept comment "knot: DNS" } set output-net-knot-ipv4 { type ipv4_addr; } set output-net-knot-ipv6 { type ipv6_addr; } chain output-net { skuid ${users.knot.name} \ meta l4proto { udp, tcp } th dport domain \ ip daddr @output-net-knot-ipv4 \ counter accept \ comment "knot: DNS notify" skuid ${users.knot.name} \ meta l4proto { udp, tcp } th dport domain \ ip6 daddr @output-net-knot-ipv6 \ counter accept \ comment "knot: DNS notify" } } ''; services.knot = { enable = true; extraArgs = [ "-v" ]; # https://www.knot-dns.cz/docs/2.6/html/reference.html extraConfig = '' server : # Listen on localhost to allow only there # dynamic updates for ACME challenges. listen: 127.0.0.1@5353 mod-rrl: - id: default rate-limit: 200 slip: 2 template: - id: default dnssec-signing: off # move databases below the state directory, because they need to be writable storage: /var/lib/knot/zones # 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 global-module: mod-rrl/default database: journal-db: /var/lib/knot/journal kasp-db: /var/lib/knot/kasp timer-db: /var/lib/knot/timer log: - target: syslog any: info remote: - id: local_resolver address: 127.0.0.1@53 - id: secondary_gandi address: ${info.gandi.dns.secondary.axfr.ipv4}@53 - id: secondary_muarf address: 78.192.65.63@53 submission: - id: dnssec_validating_resolver parent: local_resolver policy: - id: rsa single-type-signing: false ksk-shared: false algorithm: RSASHA256 ksk-size: 4096 zsk-size: 2048 zsk-lifetime: 30d ksk-lifetime: 365d ksk-submission: dnssec_validating_resolver - id: ed25519 single-type-signing: false ksk-shared: false algorithm: ED25519 ksk-size: 256 zsk-size: 256 zsk-lifetime: 30d ksk-lifetime: 365d cds-cdnskey-publish: always ksk-submission: dnssec_validating_resolver acl: - id: acl_gandi address: ${info.gandi.dns.secondary.axfr.ipv4} action: transfer - id: acl_muarf address: 78.192.65.63 action: transfer '' + lib.concatStringsSep "\n" (lib.mapAttrsToList (_domain: { conf, ... }: conf) knot.zones); }; }; }