diff options
author | azahi <azat@bahawi.net> | 2025-03-12 20:17:13 +0300 |
---|---|---|
committer | azahi <azat@bahawi.net> | 2025-03-12 20:17:13 +0300 |
commit | c81dc5a13b469c511fac6fa2390b70422d1b4da5 (patch) | |
tree | 4dab5909006ab5c25da6bd9fde6a714c7719ded7 /modules/unbound.nix | |
parent | 2025-02-17 (diff) |
Diffstat (limited to 'modules/unbound.nix')
-rw-r--r-- | modules/unbound.nix | 209 |
1 files changed, 150 insertions, 59 deletions
diff --git a/modules/unbound.nix b/modules/unbound.nix index c38c25b..10807a9 100644 --- a/modules/unbound.nix +++ b/modules/unbound.nix @@ -18,6 +18,20 @@ in type = lib.types.str; default = config.networking.domain; }; + + zone = { + whitelist = lib.mkOption { + description = "List of domains that always will be allowed."; + type = with lib.types; listOf str; + default = [ ]; + }; + + blacklist = lib.mkOption { + description = "List of domains that always will be denied."; + type = with lib.types; listOf str; + default = [ ]; + }; + }; }; config = lib.mkIf cfg.enable { @@ -48,55 +62,70 @@ in ]; local-zone = + let + mapAs = t: map (x: ''"${x}" ${t}''); + in + ( + lib.my.configurations + |> lib.mapAttrsToList (x: _: [ ''"${x}.${cfg.domain}" redirect'' ]) + |> lib.concatLists + ) + ++ mapAs "always_transparent" cfg.zone.whitelist + ++ mapAs "always_nxdomain" cfg.zone.blacklist; + local-data = lib.my.configurations - |> lib.mapAttrsToList (x: _: [ ''"${x}.${cfg.domain}" redirect'' ]) - |> lib.concatLists; - local-data = lib.concatLists ( - lib.mapAttrsToList ( + |> lib.mapAttrsToList ( hostname: let domain = "${hostname}.${cfg.domain}"; in attr: (lib.optionals (lib.hasAttr "wireguard" attr) ( - with attr.wireguard; + let + inherit (attr.wireguard) ipv4 ipv6; + in [ - "\"${domain} 604800 IN A ${ipv4.address}\"" - "\"${domain} 604800 IN AAAA ${ipv6.address}\"" - "\"${domain}. A ${ipv4.address}\"" - "\"${domain}. AAAA ${ipv6.address}\"" + ''"${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 + attr.domains + |> lib.concatMap (domain: [ + ''"${domain}. A ${ipv4.address}"'' + ''"${domain}. AAAA ${ipv6.address}"'' + ]) )) )) - ) lib.my.configurations - ); - local-data-ptr = lib.concatLists ( - lib.mapAttrsToList ( + ) + |> lib.concatLists; + local-data-ptr = + lib.my.configurations + |> lib.mapAttrsToList ( hostname: let domain = "${hostname}.${cfg.domain}"; in attr: (lib.optionals (lib.hasAttr "wireguard" attr) ( - with attr.wireguard; + let + inherit (attr.wireguard) ipv4 ipv6; + in [ - "\"${ipv4.address} ${domain}\"" - "\"${ipv6.address} ${domain}\"" + ''"${ipv4.address} ${domain}"'' + ''"${ipv6.address} ${domain}"'' ] ++ (lib.optionals (lib.hasAttr "domains" attr) ( - lib.concatMap (domain: [ - "\"${ipv4.address} ${domain}\"" - "\"${ipv6.address} ${domain}\"" - ]) attr.domains + attr.domains + |> lib.concatMap (domain: [ + ''"${ipv4.address} ${domain}"'' + ''"${ipv6.address} ${domain}"'' + ]) )) )) - ) lib.my.configurations - ); + ) + |> lib.concatLists; private-domain = map (domain: "${domain}.") [ cfg.domain @@ -137,13 +166,11 @@ in verbosity = 1; }; - forward-zone = [ - { - name = "."; - forward-tls-upstream = true; - forward-addr = lib.dns.mkDoT lib.dns.const.quad9.ecs; - } - ]; + 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"; @@ -154,33 +181,83 @@ in 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-send-identity = false; + dnstap-send-version = false; + dnstap-log-resolver-query-messages = false; + dnstap-log-resolver-response-messages = false; + dnstap-log-forwarder-query-messages = false; + dnstap-log-forwarder-response-messages = false; + dnstap-log-client-query-messages = false; dnstap-log-client-response-messages = true; - dnstap-log-forwarder-query-messages = true; - dnstap-log-forwarder-response-messages = true; }; - rpz = [ - { - name = "hagezi-ultimate"; - zonefile = "hagezi-ultimate"; - url = "https://raw.githubusercontent.com/hagezi/dns-blocklists/main/rpz/ultimate.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"; - } - ]; + rpz = + let + # https://unbound.docs.nlnetlabs.nl/en/latest/topics/filtering/rpz.html + mkRpz = + { + name, + url ? null, + zonefile ? null, + }: + { + inherit name; + zonefile = lib.mkIf (zonefile != null) zonefile; + url = lib.mkIf (url != null) url; + rpz-log = true; + rpz-log-name = name; + }; + + # https://unbound.docs.nlnetlabs.nl/en/latest/manpages/unbound.conf.html#response-policy-zone-options + mkLocalZonefile = + { + name, + action, + list, + }: + [ + '' + $TTL 30 + @ SOA localhost. root.localhost. 1 43200 3600 86400 300 + NS localhost. + '' + ] + ++ (cfg.zone.${name} |> map (x: "${x} CNAME ${action}")) + |> lib.concatLines + |> pkgs.writeText "${name}.zone" + |> toString; + in + [ + { + name = "whitelist"; + zonefile = mkLocalZonefile { + name = "whitelist"; + action = "rpz-passthru."; + list = cfg.zone.whitelist; + }; + } + { + name = "blacklist"; + zonefile = mkLocalZonefile { + name = "blacklist"; + action = "."; + list = cfg.zone.whitelist; + }; + } + { + name = "hagezi-ultimate"; + url = "https://raw.githubusercontent.com/hagezi/dns-blocklists/main/rpz/ultimate.txt"; + } + { + name = "big-osid"; + url = "https://big.oisd.nl/rpz"; + } + { + name = "nsfw-osid"; + url = "https://nsfw.oisd.nl/rpz"; + } + ] + |> map mkRpz; }; enableRootTrustAnchor = true; @@ -190,7 +267,7 @@ in prometheus.exporters.unbound = { enable = true; - listenAddress = lib.mkDefault this.wireguard.ipv4.address; + listenAddress = "127.0.0.1"; port = 9167; inherit (config.services.unbound) group user; unbound.host = "unix://${config.services.unbound.localControlSocketPath}"; @@ -209,16 +286,30 @@ in dnstap-unbound = { serviceConfig = { - ExecStart = "${lib.getExe pkgs.dnstap} -u ${config.services.unbound.settings.dnstap.dnstap-socket-path}"; + ExecStart = "${lib.getExe pkgs.dnstap} -j -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" ]; }; + + alloy.reloadTriggers = [ config.environment.etc."alloy/unbound.alloy".source ]; }; }; + environment.etc."alloy/unbound.alloy".text = with config.services.prometheus.exporters.unbound; '' + prometheus.scrape "unbound" { + targets = [ + { + __address__ = "${listenAddress}:${toString port}", + instance = "${config.networking.hostName}", + }, + ] + forward_to = [prometheus.relabel.default.receiver] + } + ''; + boot.kernel.sysctl."net.ipv4.tcp_fastopen" = lib.mkOverride 200 3; topology.nodes.${this.hostname}.services.unbound = { |