{ config, 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 = let adblock-conf = "${config.services.unbound.stateDir}/adblock.conf"; in mkIf cfg.enable { ark.directories = [config.services.unbound.stateDir]; nixfiles.modules = { redis.enable = true; promtail.filters = [ { match = { # Should be fixed[1] in the next release. # # [1]: https://github.com/NLnetLabs/unbound/commit/d7e776114114c16816570e48ab3a27eedc401a0e selector = ''{syslog_identifier="unbound"} |~ ".*could not SSL_read crypto.*"''; action = "drop"; drop_counter_reason = "noise"; }; } ]; }; services = { unbound = { enable = true; package = pkgs.unbound-with-systemd.override { withRedis = true; withTFO = true; }; settings = { server = { 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); 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" ]; private-domain = "${cfg.domain}."; private-address = with config.nixfiles.modules.wireguard; [ ipv4.subnet ipv6.subnet ]; 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; include = ''"${adblock-conf}"''; }; 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; }; }; enableRootTrustAnchor = true; localControlSocketPath = "/run/unbound/unbound.socket"; }; # TODO Switch to https://github.com/letsencrypt/unbound_exporter. prometheus.exporters.unbound = { enable = true; listenAddress = mkDefault this.wireguard.ipv4.address; port = 9167; fetchType = "uds"; controlInterface = config.services.unbound.localControlSocketPath; inherit (config.services.unbound) group user; }; }; systemd = { services = { unbound.after = ["unbound-adblock-update.service"]; unbound-adblock-update = { serviceConfig = with config.services.unbound; { Type = "oneshot"; User = user; Group = group; ExecStart = let pkg = with pkgs; writeShellApplication { name = "unbound-adblock-update"; runtimeInputs = [curl package]; text = '' curl \ "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=unbound&showintro=0&mimetype=plaintext" \ >${adblock-conf} if [[ -f "${localControlSocketPath}" ]]; then unbound-control reload fi ''; }; in "${pkg}/bin/unbound-adblock-update"; }; }; }; timers.unbound-adblock-update = { requires = ["network-online.target"]; timerConfig = { OnUnitActiveSec = "1d"; Unit = "unbound-adblock-update.service"; }; wantedBy = ["timers.target"]; }; }; boot.kernel.sysctl."net.ipv4.tcp_fastopen" = mkOverride 200 3; }; }