forked from zentralwerk/network
nix/nixos-module/container/dhcp-server: migrate from isc-dhcpd to kea-dhcp4
This commit is contained in:
parent
db71886898
commit
9b39803076
|
@ -90,7 +90,7 @@ in
|
||||||
Host "inbert.c3d2.de"
|
Host "inbert.c3d2.de"
|
||||||
Host "heise.de"
|
Host "heise.de"
|
||||||
'';
|
'';
|
||||||
}) (lib.optionalAttrs config.services.dhcpd4.enable {
|
}) (lib.optionalAttrs config.services.kea.dhcp4.enable {
|
||||||
plugins.exec =
|
plugins.exec =
|
||||||
let
|
let
|
||||||
maxTimeout = builtins.foldl' (maxTimeout: net:
|
maxTimeout = builtins.foldl' (maxTimeout: net:
|
||||||
|
@ -117,11 +117,11 @@ in
|
||||||
}) ];
|
}) ];
|
||||||
|
|
||||||
|
|
||||||
systemd.services.collectd = lib.mkIf config.services.dhcpd4.enable {
|
systemd.services.collectd = lib.mkIf config.services.kea.dhcp4.enable {
|
||||||
after = [ "dhcpd4.service" ];
|
after = [ "kea-dhcp4-server.service" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
security.wrappers = lib.mkIf config.services.dhcpd4.enable {
|
security.wrappers = lib.mkIf config.services.kea.dhcp4.enable {
|
||||||
collectd-dhcpcount =
|
collectd-dhcpcount =
|
||||||
let
|
let
|
||||||
dhcpcount = pkgs.runCommand "dhcpcount" {
|
dhcpcount = pkgs.runCommand "dhcpcount" {
|
||||||
|
|
|
@ -1,36 +1,26 @@
|
||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
require 'date'
|
require 'csv'
|
||||||
|
|
||||||
INTERVAL = 300
|
INTERVAL = 60
|
||||||
TIMEOUT = ARGV[0].to_i
|
TIMEOUT = ARGV[0].to_i # TODO: now unused
|
||||||
hostname = IO::readlines("/proc/sys/kernel/hostname").join.strip
|
hostname = CSV::readlines("/proc/sys/kernel/hostname").join.strip
|
||||||
STDOUT.sync = true
|
STDOUT.sync = true
|
||||||
|
|
||||||
loop do
|
loop do
|
||||||
seen = {}
|
seen = {}
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
addr = nil
|
header = nil
|
||||||
starts = nil
|
|
||||||
|
|
||||||
IO::readlines("/var/lib/dhcpd4/dhcpd.leases").each do |line|
|
CSV::readlines("/var/lib/kea/kea-leases4.csv", headers: true).each do |rec|
|
||||||
if line =~ /^lease (.+) \{/
|
h = rec.to_h
|
||||||
addr = $1
|
addr = h["hwaddr"]
|
||||||
|
next unless addr
|
||||||
|
|
||||||
starts = nil
|
unless seen[addr]
|
||||||
elsif line =~ /starts \d+ (.+?);/
|
count += 1
|
||||||
starts = DateTime.parse($1).to_time
|
seen[addr] = true
|
||||||
elsif line =~ /^\}/
|
|
||||||
now = Time.now
|
|
||||||
if starts and
|
|
||||||
now >= starts and now < starts + TIMEOUT
|
|
||||||
|
|
||||||
unless seen[addr]
|
|
||||||
count += 1
|
|
||||||
seen[addr] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
puts "PUTVAL \"#{hostname}/exec-dhcpd/current_sessions-leases\" interval=#{INTERVAL} N:#{count}"
|
puts "PUTVAL \"#{hostname}/exec-dhcpd/current_sessions-leases\" interval=#{INTERVAL} N:#{count}"
|
||||||
|
|
|
@ -8,98 +8,171 @@ let
|
||||||
dhcp.server == hostName
|
dhcp.server == hostName
|
||||||
) config.site.net;
|
) 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;
|
enabled = builtins.length (builtins.attrNames dhcpNets) > 0;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
services.dhcpd4 = lib.optionalAttrs enabled {
|
services.kea.dhcp4 = lib.optionalAttrs enabled {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
interfaces = builtins.attrNames dhcpNets;
|
settings = {
|
||||||
|
interfaces-config.interfaces = builtins.attrNames dhcpNets;
|
||||||
|
dhcp-ddns.enable-updates = true;
|
||||||
|
|
||||||
extraConfig = ''
|
subnet4 = concatMapDhcpNets (net: { vlan, subnet4, dhcp, domainName, ... }: {
|
||||||
${builtins.concatStringsSep "\n" (
|
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.attrValues (
|
||||||
builtins.mapAttrs (net: { dhcp, subnet4Net, subnet4Len, domainName, ...}:
|
builtins.mapAttrs (name: hwaddr: {
|
||||||
''
|
hostname = "${name}.${net}.zentralwerk.org";
|
||||||
ddns-update-style standard;
|
hw-address = hwaddr;
|
||||||
key dyndns {
|
ip-address = hosts4.${name};
|
||||||
algorithm hmac-sha256;
|
}) dhcp.fixed-hosts
|
||||||
secret ${config.site.dyndnsKey};
|
));
|
||||||
};
|
|
||||||
zone ${domainName}. {
|
|
||||||
primary ${config.site.net.serv.hosts4.dns};
|
|
||||||
primary6 ${config.site.net.serv.hosts6.dn42.dns};
|
|
||||||
key dyndns;
|
|
||||||
}
|
|
||||||
${lib.concatMapStrings ({ name, dynamic, ... }:
|
|
||||||
lib.optionalString (
|
|
||||||
dynamic &&
|
|
||||||
lib.hasSuffix ".in-addr.arpa" name
|
|
||||||
) ''
|
|
||||||
zone ${name}. {
|
|
||||||
primary ${config.site.net.serv.hosts4.dns};
|
|
||||||
primary6 ${config.site.net.serv.hosts6.dn42.dns};
|
|
||||||
key dyndns;
|
|
||||||
}
|
|
||||||
''
|
|
||||||
) config.site.dns.localZones}
|
|
||||||
|
|
||||||
option guid code 97 = text;
|
# Netbooting
|
||||||
group {
|
option-def = [ {
|
||||||
default-lease-time ${toString dhcp.time};
|
name = "PXEDiscoveryControl";
|
||||||
max-lease-time ${toString dhcp.max-time};
|
code = 6;
|
||||||
option routers ${config.site.net.${net}.hosts4.${dhcp.router}};
|
space = "vendor-encapsulated-options-space";
|
||||||
option domain-name "${domainName}";
|
type = "uint8";
|
||||||
option domain-name-servers 172.20.73.8, 9.9.9.9;
|
array = false;
|
||||||
ddns-domainname "${domainName}";
|
} {
|
||||||
|
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";
|
||||||
|
} ];
|
||||||
|
};
|
||||||
|
|
||||||
class "pxeclients" {
|
pxeClassData = {
|
||||||
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
|
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";
|
||||||
|
};
|
||||||
|
|
||||||
next-server ${config.site.net.serv.hosts4.nfsroot};
|
makePxe = name: { boot-file-name ? "netboot.xyz.efi", arch }: {
|
||||||
option tftp-server-address ${config.site.net.serv.hosts4.nfsroot};
|
inherit name boot-file-name;
|
||||||
if suffix(reverse(1, option guid), 5) = 34:69:50:52:00 {
|
test = "substring(option[60].hex,0,20) == 'PXEClient:Arch:${arch}'";
|
||||||
# RPi4
|
next-server = config.site.net.serv.hosts4.nfsroot;
|
||||||
option vendor-class-identifier "PXEClient";
|
};
|
||||||
option vendor-encapsulated-options "Raspberry Pi Boot";
|
in
|
||||||
option tftp-server-name "${config.site.net.serv.hosts4.nfsroot}";
|
[ rpi4Class ]
|
||||||
} elsif option pxe-system-type = 00:00 {
|
++
|
||||||
filename "netboot.xyz.kpxe"; # BIOS
|
builtins.attrValues (
|
||||||
} elsif option pxe-system-type = 00:07 {
|
builtins.mapAttrs makePxe pxeClassData
|
||||||
filename "netboot.xyz.efi"; # EFI
|
);
|
||||||
option bootfile-name "netboot.xyz.efi";
|
};
|
||||||
} elsif option pxe-system-type = 00:06 {
|
};
|
||||||
filename "netboot.xyz.efi"; # ia32_EFI
|
services.kea.dhcp-ddns = lib.optionalAttrs enabled {
|
||||||
}
|
enable = true;
|
||||||
}
|
|
||||||
|
|
||||||
subnet ${subnet4Net} netmask ${lib.netmasks.${toString subnet4Len}} {
|
settings = {
|
||||||
range ${dhcp.start} ${dhcp.end};
|
tsig-keys = [ {
|
||||||
|
name = "dyndns";
|
||||||
|
algorithm = "hmac-sha256";
|
||||||
|
secret = config.site.dyndnsKey;
|
||||||
|
} ];
|
||||||
|
|
||||||
# always assign the same IP to the same MAC address.
|
forward-ddns.ddns-domains = concatMapDhcpNets (net: { domainName, ... }: {
|
||||||
# fixes changing IP for PXE clients.
|
name = "${domainName}.";
|
||||||
ignore-client-uids true;
|
key-name = "dyndns";
|
||||||
}
|
dns-servers = [ {
|
||||||
|
ip-address = config.site.net.serv.hosts4.dns;
|
||||||
update-static-leases on;
|
} {
|
||||||
|
ip-address = config.site.net.serv.hosts6.dn42.dns;
|
||||||
${builtins.concatStringsSep "\n" (
|
} ];
|
||||||
builtins.attrValues (
|
});
|
||||||
builtins.mapAttrs (addr: hwaddr:
|
reverse-ddns.ddns-domains = map ({ name, ...}: {
|
||||||
''
|
name = "${name}.";
|
||||||
host ${addr} {
|
key-name = "dyndns";
|
||||||
hardware ethernet ${hwaddr};
|
dns-servers = [ {
|
||||||
fixed-address ${addr};
|
ip-address = config.site.net.serv.hosts4.dns;
|
||||||
}
|
} {
|
||||||
''
|
ip-address = config.site.net.serv.hosts6.dn42.dns;
|
||||||
) dhcp.fixed-hosts
|
} ];
|
||||||
)
|
}) (
|
||||||
)}
|
builtins.filter ({ name, dynamic, ... }:
|
||||||
}
|
dynamic &&
|
||||||
''
|
lib.hasSuffix ".in-addr.arpa" name
|
||||||
) dhcpNets
|
) config.site.dns.localZones
|
||||||
)
|
);
|
||||||
)}
|
};
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user