{ config, lib, pkgs, ... }: with lib; let inherit (pkgs) stdenv; cfg = config.networking.nextdns; identifyingPrefix = if cfg.identifyDevice then "${config.networking.hostName}-" else ""; kresdConfig = { enable = true; extraConfig = '' modules = { 'hints > iterate' } localTrees = policy.todnames({ 'lan.', 'home.', '10.in-addr.arpa.', '172.in-addr.arpa.', '192.in-addr.arpa.' }) hints.add_hosts() policy.add(policy.suffix(policy.FLAGS({'NO_CACHE'}), localTrees)) policy.add(policy.suffix(policy.STUB({ '192.168.0.1', '192.168.1.1', '172.30.42.1', '10.0.0.1' }), localTrees)) policy.add(policy.all(policy.TLS_FORWARD({ {'45.90.28.0', hostname='${identifyingPrefix}${cfg.configID}.dns1.nextdns.io'}, {'2a07:a8c0::', hostname='${identifyingPrefix}${cfg.configID}.dns1.nextdns.io'}, {'45.90.30.0', hostname='${identifyingPrefix}${cfg.configID}.dns2.nextdns.io'}, {'2a07:a8c1::', hostname='${identifyingPrefix}${cfg.configID}.dns2.nextdns.io'} }))) ''; }; in { options = { networking.nextdns.enable = mkOption { type = types.bool; default = false; description = "Whether to enable DNS resolution via NextDNS"; }; networking.nextdns.configID = mkOption { type = types.str; default = ""; example = literalExample "abcdef"; description = "NextDNS configuration ID"; }; networking.nextdns.identifyDevice = mkOption { type = types.bool; default = false; description = "Whether to send hostname for identifying in your logs"; }; }; config = mkIf cfg.enable { assertions = [ { assertion = !(stdenv.isDarwin); message = "NextDNS module is not supported on Darwin"; } ]; networking = { networkmanager.dns = "none"; resolvconf.useLocalResolver = true; }; services.kresd = kresdConfig; }; }