diff --git a/nix/nixos-module/container/dnscache.nix b/nix/nixos-module/container/dnscache.nix index 738ca99..8354b2c 100644 --- a/nix/nixos-module/container/dnscache.nix +++ b/nix/nixos-module/container/dnscache.nix @@ -1,124 +1,95 @@ { hostName, config, lib, pkgs, ... }: lib.mkIf config.site.hosts.${hostName}.services.dnscache.enable { - services.unbound = { + services.kresd = { enable = true; - settings = { - remote-control = { - control-enable = true; - control-use-cert = false; - }; - server = { - num-threads = 4; - verbosity = 1; - prefetch = true; - prefetch-key = true; - serve-expired = true; - cache-min-ttl = 60; - cache-max-ttl = 3600; - infra-cache-slabs = "8"; - key-cache-slabs = "8"; - msg-cache-slabs = "8"; - rrset-cache-slabs = "8"; - msg-cache-size = "256m"; # half again 128m? - rrset-cache-size = "512m"; # half again 256m? + instances = 4; + listenPlain = [ "0.0.0.0:53" "[::0]:53" ]; + extraConfig = /* lua */ '' + modules = { + 'http', + 'predict', + 'prefill', + 'serve_stale < cache', -- servce stail records while refreshing the record + 'workarounds < iterate', -- solve problems around specific broken subdomains, mainly disables case randomization + 'view' + } - interface = [ "0.0.0.0" "'::0'" ]; - # TODO: generate - access-control = builtins.concatLists [ - [ # localhost - "::1/128 allow" - "127.0.0.0/8 allow" - ] - [ # mgmt - "${config.site.net.mgmt.subnet4} allow" - ] - [ # dn42 - "fd23:42:c3d2:500::/56 allow" - "::172.20.72.0/117 allow" - "::172.22.99.0/120 allow" - "172.20.72.0/21 allow" - "172.22.99.0/24 allow" - ] - [ # freifunk - "10.200.0.0/15 allow" - ] - [ # DSI - "2a00:8180:2000:37::1/128 allow" - "2a00:8180:2c00:200::/56 allow" - ] - [ # flpk - "${config.site.net.flpk.subnet4} allow" - "2a0f:5382:acab:1400::/56 allow" - ] - [ # default - "0.0.0.0/0 deny" - "::/0 deny" - ] - ]; - # For DNS over TLS - tls-cert-bundle = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; + cache.size = 500 * MB + cache.min_ttl(60) - # allow reverse lookup of rfc1918 space, which includes the DN42 address space - unblock-lan-zones = true; - insecure-lan-zones = true; + net.listen('127.0.0.1', 8453, { kind = 'webmgmt' }) + http.prometheus.namespace = 'resolver_' - domain-insecure = [ - "dn42" - "d.f.ip6.arpa" - "ffdd" - ]; - }; + -- dns42 + policy.add(policy.suffix( + policy.STUB({'fd42:d42:d42:54::1', 'fd42:d42:d42:53::1', '172.20.0.53', '172.23.0.53'}), + policy.todnames({'dn42.', 'd.f.ip6.arpa', '20.172.in-addr.arpa', '21.172.in-addr.arpa', '22.172.in-addr.arpa', '23.172.in-addr.arpa'}) + )) - forward-zone = let - mkFfddZone = name: { - inherit name; - forward-addr = [ "10.200.0.4" "10.200.0.16" ]; - }; - in [ { - name = "."; - forward-tls-upstream = true; - forward-addr = [ - # Quad9 - "2620:fe::fe@853#dns.quad9.net" - "9.9.9.9@853#dns.quad9.net" - "2620:fe::9@853#dns.quad9.net" - "149.112.112.112@853#dns.quad9.net" - # Cloudflare DNS - "2606:4700:4700::1111@853#cloudflare-dns.com" - "1.1.1.1@853#cloudflare-dns.com" - "2606:4700:4700::1001@853#cloudflare-dns.com" - "1.0.0.1@853#cloudflare-dns.com" - ]; - } ] ++ - # Local networks - map ({ name, ... }: { - name = "${name}"; - forward-addr = [ "${config.site.net.serv.hosts4.dns}" ] ++ - map (hosts6: hosts6.dns) - (builtins.attrValues config.site.net.serv.hosts6); - }) config.site.dns.localZones - # Freifunk - ++ (map mkFfddZone [ - "ffdd" - "200.10.in-addr.arpa" - "201.10.in-addr.arpa" - ]); - # DN42 - stub-zone = let - mkDn42Zone = name: { - inherit name; - stub-prime = true; - stub-addr = [ - "172.20.0.53" "fd42:d42:d42:54::1" - "172.23.0.53" "fd42:d42:d42:53::1" - ]; - }; - in map mkDn42Zone [ - "dn42" "d.f.ip6.arpa" - "20.172.in-addr.arpa" "21.172.in-addr.arpa" - "22.172.in-addr.arpa" "23.172.in-addr.arpa" - ]; - }; + -- freifunk + policy.add(policy.suffix( + policy.STUB({'10.200.0.4', '10.200.0.16'}), + policy.todnames({'ffdd.', '200.10.in-addr.arpa', '201.10.in-addr.arpa'}) + )) + + -- size.dns.localZones + policy.add(policy.suffix( + policy.STUB({'${config.site.net.serv.hosts4.dns}', ${lib.concatStringsSep ", " (map (hosts6: "'${hosts6.dns}'") (builtins.attrValues config.site.net.serv.hosts6))}}) + policy.todnames({${lib.concatStringsSep ", " (map (zone: "'${zone.name}'") config.site.dns.localZones)}}) + )) + + -- forward to dns caches + policy.add(policy.slice( + policy.slice_randomize_psl(), + -- quad9 + policy.TLS_FORWARD({ + {'2620:fe::fe', hostname='dns.quad9.net'}, + {'2620:fe::9', hostname='dns.quad9.net'}, + {'9.9.9.9', hostname='dns.quad9.net'} + }) + -- cloudflare + policy.TLS_FORWARD({ + {'2606:4700:4700::1111', hostname='cloudflare-dns.com'}, + {'2606:4700:4700::1001', hostname='cloudflare-dns.com'}, + {'1.1.1.1', hostname='cloudflare-dns.com'}, + {'1.0.0.1', hostname='cloudflare-dns.com'} + }) + }))) + + -- allow access from our networks + '' + lib.concatMapStringsSep "\n" (cidr: "view:addr('${cidr}', policy.all(policy.PASS))") [ + # localhost + "::1/128" "127.0.0.0/8" + # mgmt + "${config.site.net.mgmt.subnet4}" + # dn42 + "fd23:42:c3d2:500::/56" "::172.20.72.0/117" "::172.22.99.0/120" + "172.20.72.0/21" "172.22.99.0/24" + # freifunk + "10.200.0.0/15" + # DSI + "2a00:8180:2000:37::1/128" "2a00:8180:2c00:200::/56" + # flpk + "${config.site.net.flpk.subnet4}" "2a0f:5382:acab:1400::/56 allow" + ] + /* lua */ '' + + + -- drop everything that hasn't matched + view:addr('0.0.0.0/0', policy.all(policy.DROP)) + view:addr('::/0', policy.all(policy.DROP)) + + predict = { + window = 15, -- sampling window + period = 24*(60/15) -- track last X hours, divide through sampling window + }, + + prefill.config({ + ['.'] = { + url = 'https://www.internic.net/domain/root.zone', + interval = 86400, -- seconds + } + }) + ''; }; }