126 lines
3.5 KiB
Nix
126 lines
3.5 KiB
Nix
{
|
|
lib,
|
|
config,
|
|
pkgs,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.modules.services.dhcp-dns-sync;
|
|
ownAddress = (
|
|
lib.elemAt (lib.splitString "/"
|
|
config.systemd.network.networks."30-${cfg.interface}".networkConfig.Address
|
|
) 0
|
|
);
|
|
|
|
dhcp-leases-to-unbound =
|
|
pkgs.runCommand "dhcp-leases-to-unbound"
|
|
{
|
|
code = ./dhcp-leases-to-unbound.cr;
|
|
nativeBuildInputs = [ pkgs.crystal ];
|
|
meta.mainProgram = "dhcp-leases-to-unbound";
|
|
}
|
|
''
|
|
mkdir -p $out/bin
|
|
crystal build $code --release -o $out/bin/dhcp-leases-to-unbound
|
|
'';
|
|
in
|
|
{
|
|
options.modules.services.dhcp-dns-sync = {
|
|
enable = lib.mkEnableOption "Enable DHCP to DNS synchronization";
|
|
|
|
interface = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "koti";
|
|
description = "Network interface to monitor for DHCP leases";
|
|
};
|
|
|
|
domain = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "home.arpa";
|
|
description = "Domain suffix for DHCP hostnames";
|
|
};
|
|
|
|
unboundConfigPath = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "/var/lib/unbound/dhcp-hosts.conf";
|
|
description = "Path to write Unbound include file";
|
|
};
|
|
|
|
interval = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "30s";
|
|
description = "Interval for checking DHCP lease updates";
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
# Create user and group for the service
|
|
users.users.dhcp-dns-sync = {
|
|
isSystemUser = true;
|
|
group = "dhcp-dns-sync";
|
|
description = "DHCP DNS sync service user";
|
|
};
|
|
|
|
users.groups.dhcp-dns-sync = { };
|
|
|
|
# Ensure directories and files exist with proper permissions
|
|
# Directory needs to be group-writable for unbound group
|
|
systemd.tmpfiles.rules = [
|
|
"d /var/lib/unbound 0775 unbound unbound -"
|
|
"f ${cfg.unboundConfigPath} 0644 dhcp-dns-sync unbound -"
|
|
];
|
|
|
|
# Extend Unbound configuration to include generated file
|
|
services.unbound.settings = {
|
|
server = {
|
|
local-zone = [ "${cfg.domain}. static" ];
|
|
include = cfg.unboundConfigPath;
|
|
local-data = [ ''"apu.home.arpa. IN A ${ownAddress}"'' ];
|
|
local-data-ptr = [ ''"${ownAddress} apu.home.arpa."'' ];
|
|
};
|
|
};
|
|
|
|
# Make sure Unbound control is enabled
|
|
services.unbound.settings.remote-control.control-enable = true;
|
|
|
|
# Systemd service
|
|
systemd.services.dhcp-dns-sync = {
|
|
description = "Sync DHCP leases to Unbound DNS";
|
|
after = [
|
|
"systemd-networkd.service"
|
|
"unbound.service"
|
|
];
|
|
requires = [ "unbound.service" ];
|
|
wants = [ "unbound-control.socket" ];
|
|
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
User = "dhcp-dns-sync";
|
|
Group = "unbound";
|
|
# Allow access to networkctl via D-Bus
|
|
SupplementaryGroups = [ "systemd-network" ];
|
|
# Read/write paths
|
|
ReadWritePaths = [ "/var/lib/unbound" ];
|
|
ExecStart = lib.concatStringsSep " " [
|
|
(lib.getExe dhcp-leases-to-unbound)
|
|
"-i ${cfg.interface}"
|
|
"-d ${cfg.domain}"
|
|
"-o ${cfg.unboundConfigPath}"
|
|
"--networkctl ${lib.getExe' pkgs.systemd "networkctl"}"
|
|
"--unbound-control ${lib.getExe' pkgs.unbound "unbound-control"}"
|
|
];
|
|
};
|
|
};
|
|
|
|
# Systemd timer
|
|
systemd.timers.dhcp-dns-sync = {
|
|
description = "Periodic DHCP to DNS sync";
|
|
wantedBy = [ "timers.target" ];
|
|
timerConfig = {
|
|
OnBootSec = "10s";
|
|
OnUnitActiveSec = cfg.interval;
|
|
};
|
|
};
|
|
};
|
|
}
|