Merge #361424: refactor lib.packagesFromDirectoryRecursive (v2)
[NixPkgs.git] / nixos / modules / services / networking / inadyn.nix
bloba2684f2aee4d858b81b377225ad968d70b462d2d
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
7 let
8   cfg = config.services.inadyn;
10   # check if a value of an attrset is not null or an empty collection
11   nonEmptyValue = _: v: v != null && v != [ ] && v != { };
13   renderOption =
14     k: v:
15     if
16       builtins.elem k [
17         "provider"
18         "custom"
19       ]
20     then
21       lib.concatStringsSep "\n" (
22         lib.mapAttrsToList (name: config: ''
23           ${k} ${name} {
24               ${lib.concatStringsSep "\n    " (
25                 lib.mapAttrsToList renderOption (lib.filterAttrs nonEmptyValue config)
26               )}
27           }'') v
28       )
29     else if k == "include" then
30       "${k}(\"${v}\")"
31     else if k == "hostname" && builtins.isList v then
32       "${k} = { ${builtins.concatStringsSep ", " (map (s: "\"${s}\"") v)} }"
33     else if builtins.isBool v then
34       "${k} = ${lib.boolToString v}"
35     else if builtins.isString v then
36       "${k} = \"${v}\""
37     else
38       "${k} = ${toString v}";
40   configFile' = pkgs.writeText "inadyn.conf" ''
41     # This file was generated by nix
42     # do not edit
44     ${
45       (lib.concatStringsSep "\n" (
46         lib.mapAttrsToList renderOption (lib.filterAttrs nonEmptyValue cfg.settings)
47       ))
48     }
49   '';
51   configFile = if (cfg.configFile != null) then cfg.configFile else configFile';
54   options.services.inadyn =
55     with lib.types;
56     let
57       providerOptions = {
58         include = lib.mkOption {
59           default = null;
60           description = "File to include additional settings for this provider from.";
61           type = nullOr path;
62         };
63         ssl = lib.mkOption {
64           default = true;
65           description = "Whether to use HTTPS for this DDNS provider.";
66           type = bool;
67         };
68         username = lib.mkOption {
69           default = null;
70           description = "Username for this DDNS provider.";
71           type = nullOr str;
72         };
73         password = lib.mkOption {
74           default = null;
75           description = ''
76             Password for this DDNS provider.
78             WARNING: This will be world-readable in the nix store.
79             To store credentials securely, use the `include` or `configFile` options.
80           '';
81           type = nullOr str;
82         };
83         hostname = lib.mkOption {
84           default = "*";
85           example = "your.cool-domain.com";
86           description = "Hostname alias(es).";
87           type = either str (listOf str);
88         };
89       };
90     in
91     {
92       enable = lib.mkEnableOption (''
93         synchronise your machine's IP address with a dynamic DNS provider using inadyn
94       '');
95       user = lib.mkOption {
96         default = "inadyn";
97         type = lib.types.str;
98         description = ''
99           User account under which inadyn runs.
101           ::: {.note}
102           If left as the default value this user will automatically be created
103           on system activation, otherwise you are responsible for
104           ensuring the user exists before the inadyn service starts.
105           :::
106         '';
107       };
108       group = lib.mkOption {
109         default = "inadyn";
110         type = lib.types.str;
111         description = ''
112           Group account under which inadyn runs.
114           ::: {.note}
115           If left as the default value this user will automatically be created
116           on system activation, otherwise you are responsible for
117           ensuring the user exists before the inadyn service starts.
118           :::
119         '';
120       };
121       interval = lib.mkOption {
122         default = "*-*-* *:*:00";
123         description = ''
124           How often to check the current IP.
125           Uses the format described in {manpage}`systemd.time(7)`";
126         '';
127         type = str;
128       };
129       logLevel = lib.mkOption {
130         type = lib.types.enum [
131           "none"
132           "err"
133           "warning"
134           "info"
135           "notice"
136           "debug"
137         ];
138         default = "notice";
139         description = "Set inadyn's log level.";
140       };
141       settings = lib.mkOption {
142         default = { };
143         description = "See `inadyn.conf (5)`";
144         type = submodule {
145           freeformType = attrs;
146           options = {
147             allow-ipv6 = lib.mkOption {
148               default = config.networking.enableIPv6;
149               defaultText = "`config.networking.enableIPv6`";
150               description = "Whether to get IPv6 addresses from interfaces.";
151               type = bool;
152             };
153             forced-update = lib.mkOption {
154               default = 2592000;
155               description = "Duration (in seconds) after which an update is forced.";
156               type = ints.positive;
157             };
158             provider = lib.mkOption {
159               default = { };
160               description = ''
161                 Settings for DDNS providers built-in to inadyn.
163                 For a list of built-in providers, see `inadyn.conf (5)`.
164               '';
165               type = attrsOf (submodule {
166                 freeformType = attrs;
167                 options = providerOptions;
168               });
169             };
170             custom = lib.mkOption {
171               default = { };
172               description = ''
173                 Settings for custom DNS providers.
174               '';
175               type = attrsOf (submodule {
176                 freeformType = attrs;
177                 options = providerOptions // {
178                   ddns-server = lib.mkOption {
179                     description = "DDNS server name.";
180                     type = str;
181                   };
182                   ddns-path = lib.mkOption {
183                     description = ''
184                       DDNS server path.
186                       See `inadnyn.conf (5)` for a list for format specifiers that can be used.
187                     '';
188                     example = "/update?user=%u&password=%p&domain=%h&myip=%i";
189                     type = str;
190                   };
191                 };
192               });
193             };
194           };
195         };
196       };
197       configFile = lib.mkOption {
198         default = null;
199         description = ''
200           Configuration file for inadyn.
202           Setting this will override all other configuration options.
204           Passed to the inadyn service using LoadCredential.
205         '';
206         type = nullOr path;
207       };
208     };
210   config = lib.mkIf cfg.enable {
211     systemd = {
212       services.inadyn = {
213         description = "Update nameservers using inadyn";
214         documentation = [
215           "man:inadyn"
216           "man:inadyn.conf"
217           "file:${pkgs.inadyn}/share/doc/inadyn/README.md"
218         ];
219         requires = [ "network-online.target" ];
220         wantedBy = [ "multi-user.target" ];
221         startAt = cfg.interval;
222         serviceConfig = {
223           Type = "oneshot";
224           ExecStart = ''${lib.getExe pkgs.inadyn} -f ${configFile} --cache-dir ''${CACHE_DIRECTORY} -1 --foreground -l ${cfg.logLevel}'';
225           LoadCredential = "config:${configFile}";
226           CacheDirectory = "inadyn";
228           User = cfg.user;
229           Group = cfg.group;
230           UMask = "0177";
231           LockPersonality = true;
232           MemoryDenyWriteExecute = true;
233           RestrictAddressFamilies = "AF_INET AF_INET6 AF_NETLINK";
234           NoNewPrivileges = true;
235           PrivateDevices = true;
236           PrivateTmp = true;
237           PrivateUsers = true;
238           ProtectSystem = "strict";
239           ProtectProc = "invisible";
240           ProtectHome = true;
241           ProtectClock = true;
242           ProtectControlGroups = true;
243           ProtectHostname = true;
244           ProtectKernelLogs = true;
245           ProtectKernelModules = true;
246           ProtectKernelTunables = true;
247           RestrictNamespaces = true;
248           RestrictRealtime = true;
249           RestrictSUIDSGID = true;
250           SystemCallArchitectures = "native";
251           SystemCallErrorNumber = "EPERM";
252           SystemCallFilter = "@system-service";
253           CapabilityBoundingSet = "";
254         };
255       };
257       timers.inadyn.timerConfig.Persistent = true;
258     };
260     users.users.inadyn = lib.mkIf (cfg.user == "inadyn") {
261       group = cfg.group;
262       isSystemUser = true;
263     };
265     users.groups = lib.mkIf (cfg.group == "inadyn") {
266       inadyn = { };
267     };
268   };