{ config, inputs, lib, pkgs, this, ... }: let cfg = config.nixfiles.modules.unbound; in { options.nixfiles.modules.unbound = { enable = lib.mkEnableOption "Unbound"; domain = lib.mkOption { description = "Domain name sans protocol scheme."; type = lib.types.str; default = config.networking.domain; }; }; config = lib.mkIf cfg.enable { ark.directories = [ config.services.unbound.stateDir ]; nixfiles.modules.redis.enable = true; services = { unbound = { enable = true; package = pkgs.unbound-with-systemd.override { withDNSTAP = true; 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 = lib.my.configurations |> lib.mapAttrsToList (x: _: [ "\"${x}.${cfg.domain}\" redirect" ]) |> lib.concatLists; local-data = lib.concatLists ( lib.mapAttrsToList ( hostname: let domain = "${hostname}.${cfg.domain}"; in attr: (lib.optionals (lib.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}\"" ] ++ (lib.optionals (lib.hasAttr "domains" attr) ( lib.concatMap (domain: [ "\"${domain}. A ${ipv4.address}\"" "\"${domain}. AAAA ${ipv6.address}\"" ]) attr.domains )) )) ) lib.my.configurations ); local-data-ptr = lib.concatLists ( lib.mapAttrsToList ( hostname: let domain = "${hostname}.${cfg.domain}"; in attr: (lib.optionals (lib.hasAttr "wireguard" attr) ( with attr.wireguard; [ "\"${ipv4.address} ${domain}\"" "\"${ipv6.address} ${domain}\"" ] ++ (lib.optionals (lib.hasAttr "domains" attr) ( lib.concatMap (domain: [ "\"${ipv4.address} ${domain}\"" "\"${ipv6.address} ${domain}\"" ]) attr.domains )) )) ) lib.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; cache-max-ttl = 60 * 60 * 24; serve-expired = true; serve-expired-reply-ttl = 0; prefetch = true; prefetch-key = true; hide-identity = false; hide-version = false; extended-statistics = true; log-replies = false; log-tag-queryreply = false; log-local-actions = false; verbosity = 1; }; forward-zone = [ { name = "."; forward-tls-upstream = true; forward-addr = lib.dns.mkDoT lib.dns.const.quad9.ecs; } ]; cachedb = with config.services.redis.servers.default; { backend = "redis"; redis-server-host = bind; redis-server-port = port; }; dnstap = { dnstap-enable = true; dnstap-socket-path = "/run/dnstap-unbound/read.sock"; dnstap-send-identity = true; dnstap-send-version = true; dnstap-log-resolver-query-messages = true; dnstap-log-resolver-response-messages = true; dnstap-log-client-query-messages = true; dnstap-log-client-response-messages = true; dnstap-log-forwarder-query-messages = true; dnstap-log-forwarder-response-messages = true; }; rpz = [ { name = "hagezi-pro"; zonefile = "hagezi-pro"; url = "https://cdn.jsdelivr.net/gh/hagezi/dns-blocklists@latest/rpz/pro.txt"; } { name = "big-osid"; zonefile = "big-osid"; url = "https://big.oisd.nl/rpz"; } { name = "nsfw-osid"; zonefile = "nsfw-osid"; url = "https://nsfw.oisd.nl/rpz"; } ]; }; enableRootTrustAnchor = true; localControlSocketPath = "/run/unbound/control.sock"; }; prometheus.exporters.unbound = { enable = true; listenAddress = lib.mkDefault this.wireguard.ipv4.address; port = 9167; inherit (config.services.unbound) group user; unbound.host = "unix://${config.services.unbound.localControlSocketPath}"; }; }; systemd = let in { services = { unbound = { after = [ "dnstap-unbound.service" ]; requires = [ "dnstap-unbound.service" ]; }; dnstap-unbound = { serviceConfig = { ExecStart = "${lib.getExe pkgs.dnstap} -u ${config.services.unbound.settings.dnstap.dnstap-socket-path}"; User = config.services.unbound.user; Group = config.services.unbound.group; RuntimeDirectory = "dnstap-unbound"; }; wantedBy = [ "multi-user.target" ]; }; }; }; boot.kernel.sysctl."net.ipv4.tcp_fastopen" = lib.mkOverride 200 3; topology = { nodes.${this.hostname}.services.unbound = { name = "Unbound"; icon = "${inputs.homelab-svg-assets}/assets/unbound.svg"; details.listen.text = config.services.unbound.settings.server.interface |> lib.filter (x: x != "127.0.0.1" && x != "::1") |> map (x: "${x}:53") |> lib.concatLines; }; }; }; }