{ 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 # Function to generate domain-specific configurations generateDomainConfig = domain: conf: ifaceName: let iface = config.pepe.core.network.interfaces.${ifaceName}; serverIP = iface.devices.server.address or "127.0.0.1"; interfaceNet = iface.net; 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 } ''; # Function to generate device views for an interface generateDeviceViews = ifaceName: let iface = config.pepe.core.network.interfaces.${ifaceName}; in 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 ); # Collect all interfaces used across all domains allInterfaces = lib.unique (lib.flatten (lib.mapAttrsToList (_: conf: conf.dnsInterfaces) (config.pepe.core.vhost.hosts // cfg.extraDomains) )); # Generate all device views once allDeviceViews = concatMapStrings generateDeviceViews allInterfaces; # Function to generate configurations for all domains generateCoreDNSConfig = domains: let generateForDomain = domain: conf: concatMapStrings (ifaceName: generateDomainConfig domain conf ifaceName) conf.dnsInterfaces; in concatStrings (mapAttrsToList generateForDomain domains); allDomains = config.pepe.core.vhost.hosts // cfg.extraDomains; in '' ${generateCoreDNSConfig allDomains} ${allDeviceViews} . { forward . tls://45.90.28.77 tls://45.90.30.77 { tls_servername lan-${cfg.nextDNSId}.dns.nextdns.io health_check 5s } } ''; }; }; }