{ pkgs, lib, config, ... }: let cfg = config.services.dyndns; in { options.services.dyndns = { enable = lib.mkEnableOption "Update DNS AAAA records via dyndns"; interface = lib.mkOption { type = lib.types.str; description = "Identifier of the network interface to use"; }; domain = lib.mkOption { type = lib.types.str; description = "Domain name to update"; }; server = lib.mkOption { type = lib.types.str; description = "DynDNS server name"; }; username = lib.mkOption { type = lib.types.str; description = "Username for DynDNS updates"; }; passwordFile = lib.mkOption { type = lib.types.str; description = "File containing the DynDNS password"; }; }; config = lib.mkIf cfg.enable { systemd.services.dyndns = { enable = true; after = [ "network.target" ]; unitConfig = { Description = "Update AAAA records for ${cfg.domain} via DynDNS"; }; serviceConfig = { DynamicUser = true; PrivateTmp = true; PrivateDevices = true; ProtectSystem = true; ProtectHome = true; NoNewPrivileges = true; }; script = '' #!${pkgs.bash}/bin/bash set -eu host="${cfg.domain}" interface="${cfg.interface}" dyndns_server="${cfg.server}" dyndns_user="${cfg.username}" dyndns_password="$(cat "${cfg.passwordFile}")" new_ip=$(${pkgs.iproute}/bin/ip -6 a show scope global -temporary dev "$interface" | ${pkgs.gnused}/bin/sed -n -E 's/^\ *inet6\ (2001(:[0-9a-f]+)+).*$/\1/p' | head -1) if [ -z "$new_ip" ] ; then echo "Could not determine IP address." exit 1 fi current_ip=$(${pkgs.dig}/bin/dig aaaa +short "$host") if [ -z "$current_ip" ] ; then echo "Could not determine current AAAA record." exit 1 fi if [ "$current_ip" = "$new_ip" ] ; then echo "Current AAAA record is already $current_ip, no update needed." exit 0 fi echo "Updating IP to $new_ip." ${pkgs.curl}/bin/curl "https://$dyndns_user:$dyndns_password@$dyndns_server/?hostname=$host&myip=$new_ip" ''; }; systemd.timers.dyndns = { description = "Timer for triggering DynDNS updates"; wantedBy = [ "timers.target" ]; timerConfig = { OnBootSec = "2min"; OnUnitActiveSec = "20min"; Unit = "dyndns.service"; }; }; }; }