{ config, inputs, lib, pkgs, this, ... }: with lib; let cfg = config.nixfiles.modules.unbound; in { options.nixfiles.modules.unbound = { enable = mkEnableOption "Unbound"; domain = mkOption { description = "Domain name sans protocol scheme."; type = with types; str; default = config.networking.domain; }; }; config = mkIf cfg.enable { ark.directories = [ config.services.unbound.stateDir ]; nixfiles.modules.redis.enable = true; services = { unbound = { enable = true; package = pkgs.unbound-with-systemd.override { withRedis = true; withTFO = true; }; checkconf = true; settings = { server = { module-config = ''"respip validator iterator"''; interface = with this.wireguard; [ "127.0.0.1" "::1" ipv4.address ipv6.address ]; local-zone = concatLists ( mapAttrsToList (h: _: [ "\"${h}.${cfg.domain}\" redirect" ]) my.configurations ); local-data = concatLists ( mapAttrsToList ( hostname: let domain = "${hostname}.${cfg.domain}"; in attr: (optionals (hasAttr "wireguard" attr) ( with attr.wireguard; [ "\"${domain} 604800 IN A ${ipv4.address}\"" "\"${domain} 604800 IN AAAA ${ipv6.address}\"" "\"${domain}. A ${ipv4.address}\"" "\"${domain}. AAAA ${ipv6.address}\"" ] ++ concatMap (domain: [ "\"${domain}. A ${ipv4.address}\"" "\"${domain}. AAAA ${ipv6.address}\"" ]) attr.domains )) ) my.configurations ); local-data-ptr = concatLists ( mapAttrsToList ( hostname: let domain = "${hostname}.${cfg.domain}"; in attr: (optionals (hasAttr "wireguard" attr) ( with attr.wireguard; [ "\"${ipv4.address} ${domain}\"" "\"${ipv6.address} ${domain}\"" ] ++ concatMap (domain: [ "\"${ipv4.address} ${domain}\"" "\"${ipv6.address} ${domain}\"" ]) attr.domains )) ) my.configurations ); private-domain = map (domain: "${domain}.") [ cfg.domain "local" ]; private-address = with config.nixfiles.modules.wireguard; [ ipv4.subnet ipv6.subnet ]; access-control = with config.nixfiles.modules.wireguard; [ "0.0.0.0/0 refuse" "::/0 refuse" "127.0.0.0/8 allow" "::1/128 allow" "${ipv4.subnet} allow" "${ipv6.subnet} allow" ]; cache-min-ttl = 0; serve-expired = true; serve-expired-reply-ttl = 0; prefetch = true; prefetch-key = true; hide-identity = true; hide-version = true; extended-statistics = true; log-replies = false; log-tag-queryreply = false; log-local-actions = false; verbosity = 0; }; forward-zone = [ { name = "."; forward-tls-upstream = true; forward-addr = let mkDnsOverTls = ips: auth: map ( ip: concatStrings [ ip "@" auth ] ) ips; in mkDnsOverTls dns.const.quad9.default "853#dns.quad9.net"; } ]; cachedb = with config.services.redis.servers.default; { backend = "redis"; redis-server-host = bind; redis-server-port = port; }; rpz = { name = "hagezi.pro"; zonefile = "hagezi.pro"; url = "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/pro.txt"; }; }; enableRootTrustAnchor = true; localControlSocketPath = "/run/unbound/unbound.socket"; }; prometheus.exporters.unbound = { enable = true; listenAddress = mkDefault this.wireguard.ipv4.address; port = 9167; inherit (config.services.unbound) group user; unbound.host = "unix://${config.services.unbound.localControlSocketPath}"; }; }; boot.kernel.sysctl."net.ipv4.tcp_fastopen" = mkOverride 200 3; topology = with cfg; { nodes.${this.hostname}.services.unbound = { name = "Unbound"; icon = "${inputs.homelab-svg-assets}/assets/unbound.svg"; details.listen.text = concatMapStringsSep "\n" (i: "${i}:53") ( filter (i: i != "127.0.0.1" && i != "::1") config.services.unbound.settings.server.interface ); }; }; }; }