diff --git a/hosts/architect/dns.nix b/hosts/architect/dns.nix index 79fe1bb..d345514 100644 --- a/hosts/architect/dns.nix +++ b/hosts/architect/dns.nix @@ -5,6 +5,7 @@ pepe.core.dns = { enable = true; nextDNSId = "d65174"; + processDomainsFirst = true; extraDomains = { "architect.devs.giugl.io" = { dnsInterfaces = [ "lan" "tailscale" ]; diff --git a/modules/core/dns.nix b/modules/core/dns.nix index 15fd774..2e30384 100644 --- a/modules/core/dns.nix +++ b/modules/core/dns.nix @@ -18,6 +18,12 @@ in description = "NextDNS ID for DNS over TLS."; }; + processDomainsFirst = mkOption { + type = types.bool; + default = false; + description = "Process all domains first, then add device views just once."; + }; + extraDomains = mkOption { type = types.attrsOf (types.submodule { options = { @@ -37,66 +43,104 @@ in 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 = if cfg.processDomainsFirst + then concatMapStrings generateDeviceViews allInterfaces + else ""; + + # Function to generate configurations for all domains 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; + if cfg.processDomainsFirst then + # Just generate domain configs without device views + concatMapStrings + (ifaceName: generateDomainConfig domain conf ifaceName) + conf.dnsInterfaces + else + # Original behavior: interleave domains and device views + concatMapStrings + (ifaceName: + let + domainConfig = generateDomainConfig domain conf ifaceName; + deviceViews = generateDeviceViews ifaceName; + in + '' + ${domainConfig} + + ${deviceViews} + '' + ) + 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 {