diff --git a/tv/3modules/unbound.nix b/tv/3modules/unbound.nix new file mode 100644 index 000000000..6a5102753 --- /dev/null +++ b/tv/3modules/unbound.nix @@ -0,0 +1,84 @@ +{ config, lib, pkgs, ... }: { + options.tv.unbound = { + enable = lib.mkEnableOption "tv.unbound"; + DoH.enable = lib.mkEnableOption "tv.unbound.DoH"; + DoT.enable = lib.mkEnableOption "tv.unbound.DoT"; + host = lib.mkOption { + type = lib.types.str; + }; + useACMEHost = lib.mkOption { + type = lib.types.str; + }; + }; + imports = let + cfg = config.tv.unbound; + in [ + (lib.mkIf cfg.enable { + services.unbound = { + enable = true; + settings.server = { + access-control = [ + "::/0 allow" + "0.0.0.0/0 allow" + ]; + interface = [ + "127.0.0.1@53" + "retiolum@53" + "wiregrill@53" + ]; + prefetch = true; + prefetch-key = true; + }; + }; + # Since we use this for local dns resolving, we don't want to stop/start + # but just restart, so we quickly get it back. + systemd.services.unbound.stopIfChanged = false; + + tv.iptables.input-retiolum-accept-udp = [ "domain" ]; + tv.iptables.input-wiregrill-accept-udp = [ "domain" ]; + }) + (lib.mkIf cfg.DoH.enable (let + http-port = 8053; + http-endpoint = "/query"; + in { + services.unbound.package = pkgs.unbound-with-systemd.override { + withDoH = true; + }; + services.unbound.settings.server.interface = [ + "127.0.0.1@${toString http-port}" + ]; + services.unbound.settings.server = { + https-port = http-port; + http-endpoint = http-endpoint; + http-notls-downstream = true; + }; + services.nginx.virtualHosts.${cfg.host} = { + useACMEHost = cfg.useACMEHost; + forceSSL = true; + http2 = true; + locations."/".return = ''404 "Not Found\n"''; + locations.${http-endpoint}.extraConfig = '' + grpc_pass grpc://127.0.0.1:${toString http-port}; + ''; + }; + + tv.iptables.input-internet-accept-tcp = [ "https" ]; + })) + (lib.mkIf cfg.DoT.enable { + services.unbound.settings.server = { + interface = [ + "::@853" + "0.0.0.0@853" + ]; + tls-service-key = "/run/credentials/unbound.service/tls-service-key"; + tls-service-pem = "/run/credentials/unbound.service/tls-service-pem"; + }; + krebs.systemd.services.unbound.restartIfCredentialsChange = true; + systemd.services.unbound.serviceConfig.LoadCredential = [ + "tls-service-key:/var/lib/acme/${cfg.useACMEHost}/key.pem" + "tls-service-pem:/var/lib/acme/${cfg.useACMEHost}/fullchain.pem" + ]; + tv.iptables.input-internet-accept-tcp = [ "domain-s" ]; + }) + ]; +}