{ config, lib, pkgs, ... }: let inherit (lib) mkOption types mkIf concatMapStrings concatStrings mapAttrsToList attrsets; cfg = config.pepe.core.dns; in { options.pepe.core.dns = { enable = mkOption { type = types.bool; default = false; description = "Whether to enable the DNS server."; }; nextDNSId = mkOption { type = types.str; default = "d65174"; description = "NextDNS ID for DNS over TLS."; }; extraDomains = mkOption { type = types.attrsOf (types.submodule { options = { dnsInterfaces = mkOption { type = types.listOf types.str; default = []; description = "List of interfaces to add DNS entries for this domain."; }; }; }); default = {}; description = "Additional domains to add to DNS configuration."; }; }; config = mkIf cfg.enable { services.coredns = { enable = true; config = let generateCoreDNSConfig = domains: let generateForDomain = domain: conf: concatMapStrings (ifaceName: let iface = config.pepe.core.network.interfaces.${ifaceName}; serverIP = iface.devices.server.address or "127.0.0.1"; interfaceNet = iface.net; deviceViews = concatMapStrings ({ name, device }: let deviceIP = device.address; in '' . { view ${name} { expr client_ip() == '${deviceIP}' } forward . tls://45.90.28.77 tls://45.90.30.77 { tls_servername ${name}-${cfg.nextDNSId}.dns.nextdns.io health_check 5s } } '' ) (attrsets.mapAttrsToList (name: device: { inherit name device; }) iface.devices ); in '' ${domain} { view ${ifaceName} { expr incidr(client_ip(), '${interfaceNet}') } template IN A ${domain} { answer "${domain}. 60 IN A ${serverIP}" } template IN HTTPS ${domain} { answer "${domain}. 60 IN HTTPS 1 . ipv4hint=\"${serverIP}\"" } cache log } ${deviceViews} '' ) conf.dnsInterfaces; in concatStrings (mapAttrsToList generateForDomain domains); allDomains = config.pepe.core.vhost.hosts // cfg.extraDomains; in '' ${generateCoreDNSConfig allDomains} . { forward . tls://45.90.28.77 tls://45.90.30.77 { tls_servername lan-${cfg.nextDNSId}.dns.nextdns.io health_check 5s } } ''; }; }; }