{ config, lib, pkgs, ... }: let inherit (lib) concatStringsSep mkEnableOption mkIf mkOption types; cfg = config.services.https-dns-proxy; providers = { cloudflare = { ips = [ "1.1.1.1" "1.0.0.1" ]; url = "https://cloudflare-dns.com/dns-query"; }; google = { ips = [ "8.8.8.8" "8.8.4.4" ]; url = "https://dns.google/dns-query"; }; quad9 = { ips = [ "9.9.9.9" "149.112.112.112" ]; url = "https://dns.quad9.net/dns-query"; }; }; defaultProvider = "quad9"; providerCfg = let isCustom = cfg.provider.kind == "custom"; in lib.concatStringsSep " " [ "-b" (concatStringsSep "," (if isCustom then cfg.provider.ips else providers."${cfg.provider.kind}".ips)) "-r" (if isCustom then cfg.provider.url else providers."${cfg.provider.kind}".url) ]; in { meta.maintainers = with lib.maintainers; [ peterhoeg ]; ###### interface options.services.https-dns-proxy = { enable = mkEnableOption "https-dns-proxy daemon"; address = mkOption { description = "The address on which to listen"; type = types.str; default = "127.0.0.1"; }; port = mkOption { description = "The port on which to listen"; type = types.port; default = 5053; }; provider = { kind = mkOption { description = '' The upstream provider to use or custom in case you do not trust any of the predefined providers or just want to use your own. The default is ${defaultProvider} and there are privacy and security trade-offs when using any upstream provider. Please consider that before using any of them. If you pick a custom provider, you will need to provide the bootstrap IP addresses as well as the resolver https URL. ''; type = types.enum ((builtins.attrNames providers) ++ [ "custom" ]); default = defaultProvider; }; ips = mkOption { description = "The custom provider IPs"; type = types.listOf types.str; }; url = mkOption { description = "The custom provider URL"; type = types.str; }; }; preferIPv4 = mkOption { description = '' https_dns_proxy will by default use IPv6 and fail if it is not available. To play it safe, we choose IPv4. ''; type = types.bool; default = true; }; extraArgs = mkOption { description = "Additional arguments to pass to the process."; type = types.listOf types.str; default = [ "-v" ]; }; }; ###### implementation config = lib.mkIf cfg.enable { systemd.services.https-dns-proxy = { description = "DNS to DNS over HTTPS (DoH) proxy"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = rec { Type = "exec"; DynamicUser = true; ExecStart = lib.concatStringsSep " " ( [ "${pkgs.https-dns-proxy}/bin/https_dns_proxy" "-a ${toString cfg.address}" "-p ${toString cfg.port}" "-l -" providerCfg ] ++ lib.optional cfg.preferIPv4 "-4" ++ cfg.extraArgs ); Restart = "on-failure"; }; }; }; }