{ self, pkgs, lib, config, dns, ... }:
let
  secondary = "185.181.104.96";
  domain = config.networking.domain;
  zonefile = with dns.lib.combinators; pkgs.writeText "rfive.de.zone.txt" (dns.lib.toString domain {
    TTL = 3600;
    SOA =
      let
        modulo = number: mod: (number - ((number / mod) * mod));
      in
      {
        nameServer = "ns.rfive.de.";
        adminEmail = "hostmaster@rfive.de";
        serial = lib.strings.toInt (builtins.substring 0 8 self.sourceInfo.lastModifiedDate + toString ((modulo self.sourceInfo.lastModified 86400) / 864));
        refresh = 10800;
        retry = 3600;
        expire = 604800;
        minimum = 3600;
      };
    NS = [
      "ns.inwx.de."
      "ns2.inwx.de."
      "ns3.inxw.eu."
    ];
    A = [ "23.88.121.184" ];
    AAAA = [ "2a01:4f8:c012:49de::1" ];

    CAA = letsEncrypt "ca@rfive.de";

    MX = [{ preference = 1; exchange = "mail.rfive.de."; }];

    TXT = [
      (spf.soft [ "mx" ])
    ];

    subdomains =
      let
        getVirtualHosts = hostname: map (name: builtins.substring 0 (builtins.stringLength name - (builtins.stringLength domain + 1)) name) (builtins.attrNames self.nixosConfigurations."${hostname}".config.services.caddy.virtualHosts);
        genCNAMEs = hostname: lib.attrsets.genAttrs (getVirtualHosts hostname) (_label: { CNAME = [ "${hostname}.${domain}." ]; });
      in
      lib.attrsets.mergeAttrsList [
        rec {
          nuc = {
            A = [ "141.30.227.6" ];
          };
          avm = {
            A = [ "141.30.30.20" ];
          };
          falkenstein = {
            A = [ "23.88.121.184" ];
            AAAA = [ "2a01:4f8:c012:49de::1" ];
          };
          ns = falkenstein;
          mail = falkenstein;
          _dmarc.TXT = [ "v=DMARC1; p=none; adkim=s; fo=1; rua=mailto:dmarc@rfive.de; ruf=mailto:dmarc@rfive.de" ];
          _domainkey.subdomains.rspamd.TXT = [ "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoirUMubro4nlmY6a8JMwK9QB2agAXiJzexDU/7ba6KCggONfoSTfUHlrM/XeM1GG/9oKpngApxDPP97adJuxc8/EELyo4HjTyYD8GBFZhg0AN7V8IPaJ1o5k6dGDk8ZLh41ZCnlAVWkhVSKs5pYtzkrlJIfUSzyuoe8nuFsVe3QIDAQAB" ];
        }
        (builtins.removeAttrs (genCNAMEs "nuc") [ ":2018" ])
        (builtins.removeAttrs (genCNAMEs "falkenstein") [ "mail" ":2018" ])
      ];
  });
in
{
  services.bind = rec {
    enable = true;
    directory = "/var/lib/bind";
    extraConfig = ''
      dnssec-policy "split-keys" {
        keys {
          ksk lifetime unlimited algorithm ecdsap256sha256;
          zsk lifetime 60d algorithm ecdsap256sha256;
        };
        publish-safety 1d;
        retire-safety 1d;
      };
    '';
    zones = {
      "rfive.de" = {
        master = true;
        slaves = [
          secondary
        ];
        extraConfig = ''
          also-notify {${secondary};};
          dnssec-policy split-keys;
          inline-signing yes;
          serial-update-method date;
        '';
        file = "${directory}/rfive.de.zone.txt";
      };
    };
  };
  systemd.services.bind-zonefile = {
    script = ''      
      # copy the file manually to its destination since signing requires a writable directory
      ${pkgs.coreutils}/bin/cp ${zonefile} ${config.services.bind.directory}/rfive.de.zone.txt
      ${pkgs.coreutils}/bin/chown named:named ${config.services.bind.directory}/rfive.de.zone.txt
    '';
  };
  systemd.services.bind = {
    after = [ "bind-zonefile.service" ];
    requires = [ "bind-zonefile.service" ];
  };
  networking.firewall.extraInputRules = ''
    ip saddr ${secondary}/32 tcp dport 53 accept comment "Allow DNS AXFR access from INWX Servers"
    ip saddr ${secondary}/32 udp dport 53 accept comment "Allow DNS access from INWX Servers"
  '';
  environment.systemPackages = with pkgs; [ dig.out ];
}
