From 37a8da0a828e9161684eecf1b66d395e9efd6ac7 Mon Sep 17 00:00:00 2001 From: Tim Keller Date: Wed, 31 Dec 2025 09:36:22 -0600 Subject: dns dhcp rm debug config --- nixos/default.nix | 2 +- nixos/services/router/dns-dhcp.nix | 157 ++++++++++++++++++++++++++++++++++ nixos/services/router/dns.nix | 171 ------------------------------------- 3 files changed, 158 insertions(+), 172 deletions(-) create mode 100644 nixos/services/router/dns-dhcp.nix delete mode 100644 nixos/services/router/dns.nix diff --git a/nixos/default.nix b/nixos/default.nix index 76b5d6f..5ba5f5b 100644 --- a/nixos/default.nix +++ b/nixos/default.nix @@ -7,7 +7,7 @@ ./services/cgit.nix ./services/gitea.nix ./services/searxng.nix - ./services/router/dns.nix + ./services/router/dns-dhcp.nix ./services/router/unbound-blocklist.nix ./bootloader.nix diff --git a/nixos/services/router/dns-dhcp.nix b/nixos/services/router/dns-dhcp.nix new file mode 100644 index 0000000..557cbda --- /dev/null +++ b/nixos/services/router/dns-dhcp.nix @@ -0,0 +1,157 @@ +{ config, lib, ... }: let + cfg = config.services._router.dnsDhcpConfig; +in { + options.services._router.dnsDhcpConfig = { + enable = lib.mkEnableOption "enable pre-configured unbound(outbound) + dnsmasq(local) dns(+dhcp) server"; + # TODO + defaultGateway = lib.mkOption { + }; + localIPSubnet = lib.mkOption { + }; + dhcp = { + rangeStart = lib.mkOption { + }; + rangeEnd = lib.mkOption { + }; + rangeSubnetMask = lib.mkOption { + }; + leaseTime = lib.mkOption { + }; + staticLeases = lib.mkOption { + }; + }; + localDomain = lib.mkOption { + type = lib.types.str; + default = "home.lan"; + description = ""; + }; + #ipv6 = lib.mkEnableOption "enable ipv6"; # TODO + }; + + config = lib.mkIf cfg.enable { + # Unbound as a recursive DNS resolver. + # Preferred for its security/privacy features + performance + services.unbound = { + enable = true; + settings = { + server = { + # Listen on all interfaces (or specify specific IPs) + interface = [ "0.0.0.0" ]; # ++ lib.optionals cfg.ipv6 [ "::0" ]; + + # Allow queries from local networks + access-control = [ + "127.0.0.0/8 allow" + "192.168.0.0/16 allow" + "10.0.0.0/8 allow" + "172.16.0.0/12 allow" + ]; + + # Cache settings + cache-min-ttl = 300; # 5 min + cache-max-ttl = 60 * 60 * 24; # 1 day + + # Prefetch DNS records for better performance + prefetch-key = true; + prefetch = true; + + # Enable DNSSEC validation (signed DNS, prevents man-in-the-middle attacks) + # `auto-trust-anchor-file` is set by default to "/var/unbound/root.key" + trust-anchor-file = ''""''; + domain-insecure = cfg.localDomain; # Local domain is not DNSSEC-signed + harden-below-nxdomain = true; # Protect against non-existent domain response attacks + harden-glue = true; # Protect against incorrect DNS glue record attacks + harden-dnssec-stripped = true; # Ensures that DNSSEC signatures are not stripped from DNS responses + + # Allow queries to localhost for dnsmasq local domain resolution + do-not-query-localhost = false; + + # Privacy / Security + harden-referral-path = true; # Prevents receiving data from servers that are outside the zone in the DNS referral chain + qname-minimisation = true; # Minimizes the amount of information exposed in DNS queries by only sending the essential parts of the query + hide-identity = true; # Hide software identity in response + hide-version = true; # Hide unbound version in response + use-caps-for-id = false; # Disables using uppercase characters in the DNS transaction ID, for compatibility + edns-buffer-size = 1232; # Sets the EDNS (Extension mechanisms for DNS) buffer size to 1232 bytes, which is the default for many DNS resolvers + + # Logging + #verbosity = 3; + #log-queries = true; + #log-replies = true; + #log-local-actions = true; + }; + # Forward unknown to public resolver via DoT + forward-zone = [ + # Local DNS: forward to dnsmasq + { + name = ''"${cfg.localDomain}."''; # TODO mk config + forward-addr = "127.0.0.1@5353"; # TODO mk config + } + # Local reverse DNS: forward reverse lookups (PTR records) + { + name = ''"1.168.192.in-addr.arpa"''; # NOTE: 192.168.1.0 -> 1.168.192 + forward-addr = "127.0.0.1@5353"; + } + # Upstream DNS + { + name = ''"."''; + forward-addr = [ + "9.9.9.9#dns.quad9.net" + "149.112.112.112#dns.quad9.net" + ]; + forward-tls-upstream = true; # Encrypted DNS + } + ]; + remote-control.control-enable = true; + }; + }; + + # Configure dnsmasq for dhcp and local hostname resolution + services.dnsmasq = { + enable = true; + settings = let + mkDHCPRange = ipRangeStart: ipRangeEnd: subnetMask: leaseTime: "${ipRangeStart},${ipRangeEnd},${subnetMask},${leaseTime}"; + mkDHCPOption = option: value: "option:${option},${value}"; + mkDHCPStaticLease = macAddress: hostname: staticIp: "${macAddress},${hostname},${staticIp},infinite"; + #dhcpStaticLeases = builtins.map (); + in { + # General + no-resolv = true; # Do not read /etc/resolv.conf, resolve only the LAN + no-poll = true; # Do not poll /etc/resolv.conf for changes + # TODO config local domain + local = "/${cfg.localDomain}/"; # Use local-only for the defined domain (prevents upstream leaks) + domain = cfg.localDomain; # Define the local domain name + expand-hosts = true; # Create both fully-qualified and short-name entries from DHCP hostnames + + # DNS Server + port = 5353; # Use port 5353 for DNS server since unbound is the main DNS resolver + + # DHCP Server + # TODO config + #dhcp-range = mkDHCPRange "192.168.1.50" "192.168.1.150" "255.255.255.0" "12h"; # Enable DHCP on the LAN interface + dhcp-range = with cfg.dhcp; mkDHCPRange rangeStart rangeEnd subnetMask leaseTime; # Enable DHCP on the LAN interface + + # TODO config + #dhcp-host = [ mkDHCPStaticLease ... ]; # Setup static leases + #dhcp-host = dhcpStaticLeases; # Setup static leases + + dhcp-option = [ + (mkDHCPOption "router" cfg.defaultGateway) # Set default gateway for clients + #(mkDHCPOption "ntp-server" cfg.defaultGateway) # Set ntp server for clients + (mkDHCPOption "dns-server" cfg.defaultGateway) # Set dns server for clients + (mkDHCPOption "domain-search" cfg.localDomain) # Add search rule to clients so they can resolve hostnames w/o the local domain suffix + ]; + + # Logging + #log-dhcp = true; # Log DHCP events + #log-queries = true; # Log DNS queries + + # Cache + cache-size = 1000; # Small cache limit is fine since Unbound does the heavy caching + }; + }; + + # Search localDomain so host can resolve short names + # This is eq. to dnsmasq's dhcp-option "domain-search" for clients, it just adds a search rule to resolv.conf + networking.search = [ cfg.localDomain ]; + }; +} diff --git a/nixos/services/router/dns.nix b/nixos/services/router/dns.nix deleted file mode 100644 index 2772a27..0000000 --- a/nixos/services/router/dns.nix +++ /dev/null @@ -1,171 +0,0 @@ -{ config, lib, ... }: let - #cfg = config.services._routing; - cfg = { - localDomain = "home.lan"; - defaultGateway = "127.0.0.1"; - dhcp = { - rangeStart = "192.168.1.50"; - rangeEnd = "192.168.1.150"; - subnetMask = "255.255.255.0"; - leaseTime = "12h"; - }; - log = { - dhcp = false; - dns = false; - }; - }; -in { - options.services._router.dnsDhcpConfig = { - enable = lib.mkEnableOption "enable pre-configured unbound(outbound) + dnsmasq(local) dns(+dhcp) server"; - # TODO - defaultGateway = lib.mkOption { - }; - localIPSubnet = lib.mkOption { - }; - dhcp = { - rangeStart = lib.mkOption { - }; - rangeEnd = lib.mkOption { - }; - rangeSubnetMask = lib.mkOption { - }; - leaseTime = lib.mkOption { - }; - staticLeases = lib.mkOption { - }; - }; - localDomain = lib.mkOption { - type = lib.types.str; - default = "home.lan"; - description = ""; - }; - #ipv6 = lib.mkEnableOption "enable ipv6"; # TODO - }; - - config = lib.mkIf cfg.enable { - # Unbound as a recursive DNS resolver. - # Preferred for its security/privacy features + performance - services.unbound = { - enable = true; - settings = { - server = { - # Listen on all interfaces (or specify specific IPs) - interface = [ "0.0.0.0" ]; # ++ lib.optionals cfg.ipv6 [ "::0" ]; - - # Allow queries from local networks - access-control = [ - "127.0.0.0/8 allow" - "192.168.0.0/16 allow" - "10.0.0.0/8 allow" - "172.16.0.0/12 allow" - ]; - - # Cache settings - cache-min-ttl = 300; # 5 min - cache-max-ttl = 60 * 60 * 24; # 1 day - - # Prefetch DNS records for better performance - prefetch-key = true; - prefetch = true; - - # Enable DNSSEC validation (signed DNS, prevents man-in-the-middle attacks) - # `auto-trust-anchor-file` is set by default to "/var/unbound/root.key" - trust-anchor-file = ''""''; - domain-insecure = cfg.localDomain; # Local domain is not DNSSEC-signed - harden-below-nxdomain = true; # Protect against non-existent domain response attacks - harden-glue = true; # Protect against incorrect DNS glue record attacks - harden-dnssec-stripped = true; # Ensures that DNSSEC signatures are not stripped from DNS responses - - # Allow queries to localhost for dnsmasq local domain resolution - do-not-query-localhost = false; - - # Privacy / Security - harden-referral-path = true; # Prevents receiving data from servers that are outside the zone in the DNS referral chain - qname-minimisation = true; # Minimizes the amount of information exposed in DNS queries by only sending the essential parts of the query - hide-identity = true; # Hide software identity in response - hide-version = true; # Hide unbound version in response - use-caps-for-id = false; # Disables using uppercase characters in the DNS transaction ID, for compatibility - edns-buffer-size = 1232; # Sets the EDNS (Extension mechanisms for DNS) buffer size to 1232 bytes, which is the default for many DNS resolvers - - # Logging - #verbosity = 3; - #log-queries = true; - #log-replies = true; - #log-local-actions = true; - }; - # Forward unknown to public resolver via DoT - forward-zone = [ - # Local DNS: forward to dnsmasq - { - name = ''"${cfg.localDomain}."''; # TODO mk config - forward-addr = "127.0.0.1@5353"; # TODO mk config - } - # Local reverse DNS: forward reverse lookups (PTR records) - { - name = ''"1.168.192.in-addr.arpa"''; # NOTE: 192.168.1.0 -> 1.168.192 - forward-addr = "127.0.0.1@5353"; - } - # Upstream DNS - { - name = ''"."''; - forward-addr = [ - "9.9.9.9#dns.quad9.net" - "149.112.112.112#dns.quad9.net" - ]; - forward-tls-upstream = true; # Encrypted DNS - } - ]; - remote-control.control-enable = true; - }; - }; - - # Configure dnsmasq for dhcp and local hostname resolution - services.dnsmasq = { - enable = true; - settings = let - mkDHCPRange = ipRangeStart: ipRangeEnd: subnetMask: leaseTime: "${ipRangeStart},${ipRangeEnd},${subnetMask},${leaseTime}"; - mkDHCPOption = option: value: "option:${option},${value}"; - mkDHCPStaticLease = macAddress: hostname: staticIp: "${macAddress},${hostname},${staticIp},infinite"; - #dhcpStaticLeases = builtins.map (); - in { - # General - no-resolv = true; # Do not read /etc/resolv.conf, resolve only the LAN - no-poll = true; # Do not poll /etc/resolv.conf for changes - # TODO config local domain - local = "/${cfg.localDomain}/"; # Use local-only for the defined domain (prevents upstream leaks) - domain = cfg.localDomain; # Define the local domain name - expand-hosts = true; # Create both fully-qualified and short-name entries from DHCP hostnames - - # DNS Server - port = 5353; # Use port 5353 for DNS server since unbound is the main DNS resolver - - # DHCP Server - # TODO config - #dhcp-range = mkDHCPRange "192.168.1.50" "192.168.1.150" "255.255.255.0" "12h"; # Enable DHCP on the LAN interface - dhcp-range = with cfg.dhcp; mkDHCPRange rangeStart rangeEnd subnetMask leaseTime; # Enable DHCP on the LAN interface - - # TODO config - #dhcp-host = [ mkDHCPStaticLease ... ]; # Setup static leases - #dhcp-host = dhcpStaticLeases; # Setup static leases - - dhcp-option = [ - (mkDHCPOption "router" cfg.defaultGateway) # Set default gateway for clients - #(mkDHCPOption "ntp-server" cfg.defaultGateway) # Set ntp server for clients - (mkDHCPOption "dns-server" cfg.defaultGateway) # Set dns server for clients - (mkDHCPOption "domain-search" cfg.localDomain) # Add search rule to clients so they can resolve hostnames w/o the local domain suffix - ]; - - # Logging - #log-dhcp = true; # Log DHCP events - #log-queries = true; # Log DNS queries - - # Cache - cache-size = 1000; # Small cache limit is fine since Unbound does the heavy caching - }; - }; - - # Search localDomain so host can resolve short names - # This is eq. to dnsmasq's dhcp-option "domain-search" for clients, it just adds a search rule to resolv.conf - networking.search = [ cfg.localDomain ]; - }; -} -- cgit v1.2.3