network/nix/nixos-module/container/dhcp-server.nix

179 lines
5.1 KiB
Nix

# ISC DHCP/IPv4 server configuration
{ hostName, config, lib, ... }:
let
dhcpNets =
lib.filterAttrs (_: { dhcp, ... }:
dhcp != null &&
dhcp.server == hostName
) config.site.net;
concatMapDhcpNets = f:
lib.pipe dhcpNets [
(builtins.mapAttrs f)
builtins.attrValues
(map (r: if builtins.isList r then r else [ r ]))
builtins.concatLists
];
enabled = builtins.length (builtins.attrNames dhcpNets) > 0;
in
{
services.kea.dhcp4 = lib.optionalAttrs enabled {
enable = true;
settings = {
interfaces-config.interfaces = builtins.attrNames dhcpNets;
dhcp-ddns.enable-updates = true;
subnet4 = concatMapDhcpNets (net: { vlan, subnet4, dhcp, domainName, ... }: {
id = vlan;
subnet = subnet4;
pools = [ {
pool = "${dhcp.start} - ${dhcp.end}";
} ];
rebind-timer = dhcp.time;
valid-lifetime = dhcp.max-time;
option-data = [ {
space = "dhcp4";
name = "routers";
code = 3;
data = config.site.net.${net}.hosts4.${dhcp.router};
} {
space = "dhcp4";
name = "domain-name";
code = 15;
data = domainName;
} {
space = "dhcp4";
name = "domain-name-servers";
code = 6;
data = "172.20.73.8, 9.9.9.9";
} ];
});
match-client-id = false;
host-reservation-identifiers = [ "hw-address" ];
reservations = concatMapDhcpNets (net: { hosts4, dhcp, ... }:
builtins.attrValues (
builtins.mapAttrs (name: hwaddr: {
hostname = "${name}.${net}.zentralwerk.org";
hw-address = hwaddr;
ip-address = hosts4.${name};
}) dhcp.fixed-hosts
));
# Netbooting
option-def = [ {
name = "PXEDiscoveryControl";
code = 6;
space = "vendor-encapsulated-options-space";
type = "uint8";
array = false;
} {
name = "PXEMenuPrompt";
code = 10;
space = "vendor-encapsulated-options-space";
type = "record";
array = false;
record-types = "uint8,string";
} {
name = "PXEBootMenu";
code = 9;
space = "vendor-encapsulated-options-space";
type = "record";
array = false;
record-types = "uint16,uint8,string";
} ];
client-classes =
let
rpi4Class = {
name = "rpi4-pxe";
test = "option[vendor-class-identifier].text == 'PXEClient:Arch:00000:UNDI:002001'";
option-data = [ {
name = "boot-file-name";
data = "bootcode.bin";
} {
name = "vendor-class-identifier";
data = "PXEClient";
} {
name = "vendor-encapsulated-options";
} {
name = "PXEBootMenu";
csv-format = true;
data = "0,17,Raspberry Pi Boot";
space = "vendor-encapsulated-options-space";
} {
name = "PXEDiscoveryControl";
data = "3";
space = "vendor-encapsulated-options-space";
} {
name = "PXEMenuPrompt";
csv-format = true;
data = "0,PXE";
space = "vendor-encapsulated-options-space";
} ];
};
pxeClassData = {
PXE-Legacy = {
arch = "00000";
boot-file-name = "netboot.xyz.kpxe";
};
PXE-UEFI-32-1.arch = "00002";
PXE-UEFI-32-2.arch = "00006";
PXE-UEFI-64-1.arch = "00007";
PXE-UEFI-64-2.arch = "00008";
PXE-UEFI-64-3.arch = "00009";
};
makePxe = name: { boot-file-name ? "netboot.xyz.efi", arch }: {
inherit name boot-file-name;
test = "substring(option[60].hex,0,20) == 'PXEClient:Arch:${arch}'";
next-server = config.site.net.serv.hosts4.nfsroot;
};
in
[ rpi4Class ]
++
builtins.attrValues (
builtins.mapAttrs makePxe pxeClassData
);
};
};
services.kea.dhcp-ddns = lib.optionalAttrs enabled {
enable = true;
settings = {
tsig-keys = [ {
name = "dyndns";
algorithm = "hmac-sha256";
secret = config.site.dyndnsKey;
} ];
forward-ddns.ddns-domains = concatMapDhcpNets (net: { domainName, ... }: {
name = "${domainName}.";
key-name = "dyndns";
dns-servers = [ {
ip-address = config.site.net.serv.hosts4.dns;
} {
ip-address = config.site.net.serv.hosts6.dn42.dns;
} ];
});
reverse-ddns.ddns-domains = map ({ name, ...}: {
name = "${name}.";
key-name = "dyndns";
dns-servers = [ {
ip-address = config.site.net.serv.hosts4.dns;
} {
ip-address = config.site.net.serv.hosts6.dn42.dns;
} ];
}) (
builtins.filter ({ name, dynamic, ... }:
dynamic &&
lib.hasSuffix ".in-addr.arpa" name
) config.site.dns.localZones
);
};
};
}