about summary refs log tree commit diff
path: root/nixos/modules/services/networking/inadyn.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services/networking/inadyn.nix')
-rw-r--r--nixos/modules/services/networking/inadyn.nix250
1 files changed, 250 insertions, 0 deletions
diff --git a/nixos/modules/services/networking/inadyn.nix b/nixos/modules/services/networking/inadyn.nix
new file mode 100644
index 0000000000000..baa4302096c2c
--- /dev/null
+++ b/nixos/modules/services/networking/inadyn.nix
@@ -0,0 +1,250 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.inadyn;
+
+  # check if a value of an attrset is not null or an empty collection
+  nonEmptyValue = _: v: v != null && v != [ ] && v != { };
+
+  renderOption = k: v:
+    if builtins.elem k [ "provider" "custom" ] then
+      lib.concatStringsSep "\n"
+        (mapAttrsToList
+          (name: config: ''
+            ${k} ${name} {
+                ${lib.concatStringsSep "\n    " (mapAttrsToList renderOption (filterAttrs nonEmptyValue config))}
+            }'')
+          v)
+    else if k == "include" then
+      "${k}(\"${v}\")"
+    else if k == "hostname" && builtins.isList v then
+      "${k} = { ${builtins.concatStringsSep ", " (map (s: "\"${s}\"") v)} }"
+    else if builtins.isBool v then
+      "${k} = ${boolToString v}"
+    else if builtins.isString v then
+      "${k} = \"${v}\""
+    else
+      "${k} = ${toString v}";
+
+  configFile' = pkgs.writeText "inadyn.conf"
+    ''
+      # This file was generated by nix
+      # do not edit
+
+      ${(lib.concatStringsSep "\n" (mapAttrsToList renderOption (filterAttrs nonEmptyValue cfg.settings)))}
+    '';
+
+  configFile = if (cfg.configFile != null) then cfg.configFile else configFile';
+in
+{
+  options.services.inadyn = with types;
+    let
+      providerOptions =
+        {
+          include = mkOption {
+            default = null;
+            description = "File to include additional settings for this provider from.";
+            type = nullOr path;
+          };
+          ssl = mkOption {
+            default = true;
+            description = "Whether to use HTTPS for this DDNS provider.";
+            type = bool;
+          };
+          username = mkOption {
+            default = null;
+            description = "Username for this DDNS provider.";
+            type = nullOr str;
+          };
+          password = mkOption {
+            default = null;
+            description = ''
+              Password for this DDNS provider.
+
+              WARNING: This will be world-readable in the nix store.
+              To store credentials securely, use the `include` or `configFile` options.
+            '';
+            type = nullOr str;
+          };
+          hostname = mkOption {
+            default = "*";
+            example = "your.cool-domain.com";
+            description = "Hostname alias(es).";
+            type = either str (listOf str);
+          };
+        };
+    in
+    {
+      enable = mkEnableOption (''
+        synchronise your machine's IP address with a dynamic DNS provider using inadyn
+      '');
+      user = mkOption {
+        default = "inadyn";
+        type = types.str;
+        description = ''
+          User account under which inadyn runs.
+
+          ::: {.note}
+          If left as the default value this user will automatically be created
+          on system activation, otherwise you are responsible for
+          ensuring the user exists before the inadyn service starts.
+          :::
+        '';
+      };
+      group = mkOption {
+        default = "inadyn";
+        type = types.str;
+        description = ''
+          Group account under which inadyn runs.
+
+          ::: {.note}
+          If left as the default value this user will automatically be created
+          on system activation, otherwise you are responsible for
+          ensuring the user exists before the inadyn service starts.
+          :::
+        '';
+      };
+      interval = mkOption {
+        default = "*-*-* *:*:00";
+        description = ''
+          How often to check the current IP.
+          Uses the format described in {manpage}`systemd.time(7)`";
+        '';
+        type = str;
+      };
+      logLevel = lib.mkOption {
+        type = lib.types.enum [ "none" "err" "warning" "info" "notice" "debug" ];
+        default = "notice";
+        description = "Set inadyn's log level.";
+      };
+      settings = mkOption {
+        default = { };
+        description = "See `inadyn.conf (5)`";
+        type = submodule {
+          freeformType = attrs;
+          options = {
+            allow-ipv6 = mkOption {
+              default = config.networking.enableIPv6;
+              defaultText = "`config.networking.enableIPv6`";
+              description = "Whether to get IPv6 addresses from interfaces.";
+              type = bool;
+            };
+            forced-update = mkOption {
+              default = 2592000;
+              description = "Duration (in seconds) after which an update is forced.";
+              type = ints.positive;
+            };
+            provider = mkOption {
+              default = { };
+              description = ''
+                Settings for DDNS providers built-in to inadyn.
+
+                For a list of built-in providers, see `inadyn.conf (5)`.
+              '';
+              type = attrsOf (submodule {
+                freeformType = attrs;
+                options = providerOptions;
+              });
+            };
+            custom = mkOption {
+              default = { };
+              description = ''
+                Settings for custom DNS providers.
+              '';
+              type = attrsOf (submodule {
+                freeformType = attrs;
+                options = providerOptions // {
+                  ddns-server = mkOption {
+                    description = "DDNS server name.";
+                    type = str;
+                  };
+                  ddns-path = mkOption {
+                    description = ''
+                      DDNS server path.
+
+                      See `inadnyn.conf (5)` for a list for format specifiers that can be used.
+                    '';
+                    example = "/update?user=%u&password=%p&domain=%h&myip=%i";
+                    type = str;
+                  };
+                };
+              });
+            };
+          };
+        };
+      };
+      configFile = mkOption {
+        default = null;
+        description = ''
+          Configuration file for inadyn.
+
+          Setting this will override all other configuration options.
+
+          Passed to the inadyn service using LoadCredential.
+        '';
+        type = nullOr path;
+      };
+    };
+
+  config = lib.mkIf cfg.enable {
+    systemd = {
+      services.inadyn = {
+        description = "Update nameservers using inadyn";
+        documentation = [
+          "man:inadyn"
+          "man:inadyn.conf"
+          "file:${pkgs.inadyn}/share/doc/inadyn/README.md"
+        ];
+        requires = [ "network-online.target" ];
+        wantedBy = [ "multi-user.target" ];
+        startAt = cfg.interval;
+        serviceConfig = {
+          Type = "oneshot";
+          ExecStart = ''${lib.getExe pkgs.inadyn} -f ${configFile} --cache-dir ''${CACHE_DIRECTORY}/inadyn -1 --foreground -l ${cfg.logLevel}'';
+          LoadCredential = "config:${configFile}";
+          CacheDirectory = "inadyn";
+
+          User = cfg.user;
+          Group = cfg.group;
+          UMask = "0177";
+          LockPersonality = true;
+          MemoryDenyWriteExecute = true;
+          RestrictAddressFamilies = "AF_INET AF_INET6 AF_NETLINK";
+          NoNewPrivileges = true;
+          PrivateDevices = true;
+          PrivateTmp = true;
+          PrivateUsers = true;
+          ProtectSystem = "strict";
+          ProtectProc = "invisible";
+          ProtectHome = true;
+          ProtectClock = true;
+          ProtectControlGroups = true;
+          ProtectHostname = true;
+          ProtectKernelLogs = true;
+          ProtectKernelModules = true;
+          ProtectKernelTunables = true;
+          RestrictNamespaces = true;
+          RestrictRealtime = true;
+          RestrictSUIDSGID = true;
+          SystemCallArchitectures = "native";
+          SystemCallErrorNumber = "EPERM";
+          SystemCallFilter = "@system-service";
+          CapabilityBoundingSet = "";
+        };
+      };
+
+      timers.inadyn.timerConfig.Persistent = true;
+    };
+
+    users.users.inadyn = mkIf (cfg.user == "inadyn") {
+      group = cfg.group;
+      isSystemUser = true;
+    };
+
+    users.groups = mkIf (cfg.group == "inadyn") {
+      inadyn = { };
+    };
+  };
+}