{ lib, pkgs, config, ... }: let cfg = config.skynet_dns; # reads that date to a string (will need to be fixed in 2038) current_date = toString builtins.currentTime; get_config_file = (domain: '' $TTL 60 ; 1 minute ; hostmaster@${domain} is an email address that recieves stuff related to dns @ IN SOA ${cfg.own.nameserver}.${domain}. hostmaster.${domain}. ( ; Serial (YYYYMMDDCC) this has to be updated for each time the record is updated ${current_date} 600 ; Refresh (10 minutes) 300 ; Retry (5 minutes) 604800 ; Expire (1 week) 3600 ; Minimum (1 hour) ) @ NS ns1.${domain}. @ NS ns2.${domain}. ; @ stands for teh root domain so teh A record below is where ${domain} points to @ A 193.1.99.76 ;@ MX 5 ${domain}. ; can have multiple mailserves ;@ MX 20 mail2.${domain}. ; ------------------------------------------ ; Server Names ; ------------------------------------------ ; External addresses ; ------------------------------------------ ${lib.strings.concatMapStrings (x: x + "\n") cfg.records.external} ; this is fixed for now wintermute A 193.1.101.148 ; internal addresses ; ------------------------------------------ ; May come back to this idea in teh future ; agentjones.int A 172.20.20.1 ; cname's ; ------------------------------------------ ${lib.strings.concatMapStrings (x: x + "\n") cfg.records.cname} '' ); in { options = { skynet_dns = { enable = lib.mkEnableOption { default = false; example = true; description = "Skynet DNS"; type = lib.types.bool; }; own = { nameserver = lib.mkOption { default = "ns1"; type = lib.types.str; description = '' the hostname of this nameserver, eg ns1, ns2 ''; }; external = lib.mkOption { default = [ ]; type = lib.types.listOf lib.types.str; description = '' External records like: agentjones A 193.1.99.72 ''; }; cname = lib.mkOption { default = [ ]; type = lib.types.listOf lib.types.str; description = '' External records like: ns1 CNAME ns1 ''; }; }; records = { external = lib.mkOption { default = [ ]; type = lib.types.listOf lib.types.str; description = '' External records like: agentjones A 193.1.99.72 ''; }; cname = lib.mkOption { default = [ ]; type = lib.types.listOf lib.types.str; description = '' External records like: ns1 CNAME ns1 ''; }; }; }; }; config = lib.mkIf cfg.enable { # secrets required age.secrets.dns_dnskeys = { file = ../secrets/dns_dnskeys.conf.age; owner = "named"; group = "named"; }; networking.firewall = { allowedTCPPorts = [53]; allowedUDPPorts = [53]; }; services.bind = { enable = true; ipv4Only = true; # need to take a look at https://nixos.org/manual/nixos/unstable/#module-security-acme-config-dns extraConfig = '' include "/run/agenix/dns_dnskeys"; ''; # piles of no valid RRSIG resolving 'com/DS/IN' errors extraOptions = '' dnssec-validation yes; ''; # set the upstream dns servers # overrides the default dns servers forwarders = [ # Cloudflare "1.1.1.1" # Google "8.8.8.8" # Quad9 "9.9.9.9" ]; cacheNetworks = [ # this server itself "127.0.0.0/24" # all of skynet can use this as a resolver /* Origianl idea, however all external traffic had the ip of the router "193.1.99.64/26" So to fix this we need to allow smaller ranges? - Didnt work Fallback is explisitly listing each ip we have */ "193.1.99.71/32" "193.1.99.72/32" "193.1.99.73/32" "193.1.99.71/32" "193.1.99.74/32" "193.1.99.75/32" "193.1.99.76/32" "193.1.99.77/32" "193.1.99.78/32" "193.1.99.79/32" "193.1.99.80/32" "193.1.99.81/32" "193.1.99.82/32" "193.1.99.83/32" "193.1.99.81/32" "193.1.99.84/32" "193.1.99.85/32" "193.1.99.86/32" "193.1.99.87/32" "193.1.99.88/32" "193.1.99.89/32" "193.1.99.90/32" "193.1.99.91/32" "193.1.99.92/32" "193.1.99.93/32" "193.1.99.91/32" "193.1.99.94/32" "193.1.99.95/32" "193.1.99.96/32" "193.1.99.97/32" "193.1.99.98/32" "193.1.99.99/32" "193.1.99.100/32" "193.1.99.101/32" "193.1.99.102/32" "193.1.99.103/32" "193.1.99.101/32" "193.1.99.104/32" "193.1.99.105/32" "193.1.99.106/32" "193.1.99.107/32" "193.1.99.108/32" "193.1.99.109/32" "193.1.99.110/32" "193.1.99.111/32" "193.1.99.112/32" "193.1.99.113/32" "193.1.99.111/32" "193.1.99.114/32" "193.1.99.115/32" "193.1.99.116/32" "193.1.99.117/32" "193.1.99.118/32" "193.1.99.119/32" "193.1.99.120/32" "193.1.99.121/32" "193.1.99.122/32" "193.1.99.123/32" "193.1.99.121/32" "193.1.99.124/32" "193.1.99.125/32" "193.1.99.126/32" ]; zones = { /* put any other zones above skynet and link to their files like so: example.ie = { extraConfig = ""; file = ./dns/example; master = true; masters = []; slaves = [ ]; }; Skynet is handled a bit more dynamically since it is the key one we should focus on */ "skynet.ie" = { extraConfig = '' allow-update { key rfc2136key.skynet.ie.; }; dnssec-policy default; inline-signing yes; // for bumping the config // ${current_date} ''; # really wish teh nixos config didnt use master/slave master = true; slaves = [ ]; # need to write this to a file # using the date in it so it will trigger a restart file = "/etc/dns_custom/dns_zone_skynet"; # no leading whitespace for first line }; "csn.ul.ie" = { extraConfig = '' allow-update { key rfc2136key.skynet.ie.; }; dnssec-policy default; inline-signing yes; // for bumping the config // ${current_date} ''; # really wish teh nixos config didnt use master/slave master = true; slaves = [ ]; # need to write this to a file # using the date in it so it will trigger a restart file = "/etc/dns_custom/dns_zone_csn"; # no leading whitespace for first line }; }; }; # creates a folder in /etc for the dns to use users.users.named = { createHome = true; home = "/etc/dns_custom"; }; environment.etc = { # Creates /etc/dns_custom/dns_zone_skynet "dns_custom/dns_zone_skynet" = { user = "named"; group = "named"; # The UNIX file mode bits mode = "0644"; text = get_config_file "skynet.ie"; }; "dns_custom/dns_zone_csn" = { user = "named"; group = "named"; # The UNIX file mode bits mode = "0644"; text = get_config_file "csn.ul.ie"; }; }; }; }