nixos/applications/dns.nix

379 lines
No EOL
10 KiB
Nix

{ 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;
# base config for domains we own (skynet.ie, csn.ul.ie, ulcompsoc.ie)
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}
''
);
# https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/4/html/reference_guide/s2-bind-configuration-zone-reverse
# config for our reverse dnspointers (not properly working)
get_config_file_rev = (domain:
''
$ORIGIN 99.1.193.in-addr.arpa.
$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}.
${lib.strings.concatMapStrings (x: x + "." + domain + ".\n") cfg.records.reverse}
''
);
# domains we dont have proper ownship over, only here to ensure the logs dont get cluttered.
get_config_file_old_domains = (domain:
''
$TTL 60 ; 1 minute
; hostmaster@skynet.ie is an email address that recieves stuff related to dns
@ IN SOA ${cfg.own.nameserver}.skynet.ie. hostmaster.skynet.ie. (
; 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.skynet.ie.
@ NS ns2.skynet.ie.
''
);
# arrys of teh two nameservers
tmp1 = ["193.1.99.109"];
tmp2 = ["193.1.99.120"];
primaries = (if cfg.primary then
# primary servers have no primaries (ones they listen to)
[]
else
if builtins.elem cfg.own.ip tmp1 then
tmp2
else
tmp1
);
secondaries = (if cfg.primary then
if builtins.elem cfg.own.ip tmp1 then
tmp2
else
tmp1
else
[]
);
# small function to tidy up the spam of the cache networks, would use teh subnet except all external traffic has the ip of teh router
create_cache_networks = (map (x: "193.1.99.${toString x}/32" ) (lib.lists.range 71 126) );
# standard function to create the etc file, pass in the text and domain and it makes it
create_entry_etc_sub = domain: text: {
# Creates /etc/skynet/dns/domain
"skynet/dns/${domain}" = {
user = "named";
group = "named";
# The UNIX file mode bits
mode = "0664";
text = text;
};
};
# (text.owned "csn.ul.ie")
# standard function to create the etc file, pass in the text and domain and it makes it
create_entry_etc = domain: type:
if type == "owned" then
create_entry_etc_sub domain (text.owned domain)
else if type == "reverse" then
create_entry_etc_sub domain (text.reverse domain)
else if type == "old" then
create_entry_etc_sub domain (text.old domain)
else
{};
create_entry_zone = (domain: extraConfig: {
"${domain}" = {
extraConfig = ''
${extraConfig}
// for bumping the config
// ${current_date}
'';
# really wish teh nixos config didnt use master/slave
master = cfg.primary;
masters = primaries;
slaves = secondaries;
# need to write this to a file
# using the date in it so it will trigger a restart
file = "/etc/skynet/dns/${domain}";
# no leading whitespace for first line
};
});
text = {
owned = domain: get_config_file domain;
reverse = domain: get_config_file_rev domain;
old = domain: get_config_file_old_domains domain;
};
extraConfig = {
owned =
if cfg.primary then
''
allow-update { key rfc2136key.skynet.ie.; };
dnssec-policy default;
inline-signing yes;
''
else
"";
# no extra config for reverse
reverse = "";
old = "";
};
in {
imports = [
../applications/firewall.nix
];
options = {
skynet_dns = {
enable = lib.mkEnableOption {
default = false;
example = true;
description = "Skynet DNS";
type = lib.types.bool;
};
primary = lib.mkOption {
type = lib.types.bool;
default = false;
};
own = {
ip = lib.mkOption {
type = lib.types.str;
description = ''
ip of this server
'';
};
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
'';
};
reverse = lib.mkOption {
default = [ ];
type = lib.types.listOf lib.types.str;
description = ''
External records like: 20 IN PTR vigil
'';
};
};
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
'';
};
reverse = lib.mkOption {
default = [ ];
type = lib.types.listOf lib.types.str;
description = ''
External records like: 20 IN PTR vigil
'';
};
};
};
};
config = lib.mkIf cfg.enable {
# open the firewall for this
skynet_firewall.forward = [
"ip daddr ${cfg.own.ip} tcp dport 53 counter packets 0 bytes 0 accept"
"ip daddr ${cfg.own.ip} udp dport 53 counter packets 0 bytes 0 accept"
];
services.bind.zones =
(create_entry_zone "csn.ul.ie" extraConfig.owned ) //
(create_entry_zone "skynet.ie" extraConfig.owned ) //
(create_entry_zone "ulcompsoc.ie" extraConfig.owned ) //
(create_entry_zone "99.1.193.in-addr.arpa" extraConfig.reverse )//
(create_entry_zone "conradcollins.net" extraConfig.old )//
(create_entry_zone "edelharty.net" extraConfig.old );
environment.etc =
(create_entry_etc "csn.ul.ie" "owned") //
(create_entry_etc "skynet.ie" "owned") //
(create_entry_etc "ulcompsoc.ie" "owned") //
(create_entry_etc "99.1.193.in-addr.arpa" "reverse") //
(create_entry_etc "conradcollins.net" "old") //
(create_entry_etc "edelharty.net" "old");
# 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
Now have a function for it
*/
] ++ create_cache_networks;
};
# creates a folder in /etc for the dns to use
users.users.named = {
createHome = true;
home = "/etc/skynet/dns";
};
};
}