1{ config, pkgs, lib, ... }:
2
3let
4 cfg = config.services.ddclient;
5 boolToStr = bool: if bool then "yes" else "no";
6 dataDir = "/var/lib/ddclient";
7
8 configText = ''
9 # This file can be used as a template for configFile or is automatically generated by Nix options.
10 cache=${dataDir}/ddclient.cache
11 foreground=YES
12 use=${cfg.use}
13 login=${cfg.username}
14 password=${cfg.password}
15 protocol=${cfg.protocol}
16 ${lib.optionalString (cfg.script != "") "script=${cfg.script}"}
17 ${lib.optionalString (cfg.server != "") "server=${cfg.server}"}
18 ${lib.optionalString (cfg.zone != "") "zone=${cfg.zone}"}
19 ssl=${boolToStr cfg.ssl}
20 wildcard=YES
21 quiet=${boolToStr cfg.quiet}
22 verbose=${boolToStr cfg.verbose}
23 ${lib.concatStringsSep "," cfg.domains}
24 ${cfg.extraConfig}
25 '';
26
27in
28
29with lib;
30
31{
32
33 ###### interface
34
35 options = {
36
37 services.ddclient = with lib.types; {
38
39 enable = mkOption {
40 default = false;
41 type = bool;
42 description = ''
43 Whether to synchronise your machine's IP address with a dynamic DNS provider (e.g. dyndns.org).
44 '';
45 };
46
47 domains = mkOption {
48 default = [ "" ];
49 type = listOf str;
50 description = ''
51 Domain name(s) to synchronize.
52 '';
53 };
54
55 username = mkOption {
56 default = "";
57 type = str;
58 description = ''
59 User name.
60 '';
61 };
62
63 password = mkOption {
64 default = "";
65 type = str;
66 description = ''
67 Password. WARNING: The password becomes world readable in the Nix store.
68 '';
69 };
70
71 interval = mkOption {
72 default = "10min";
73 type = str;
74 description = ''
75 The interval at which to run the check and update.
76 See <command>man 7 systemd.time</command> for the format.
77 '';
78 };
79
80 configFile = mkOption {
81 default = "/etc/ddclient.conf";
82 type = path;
83 description = ''
84 Path to configuration file.
85 When set to the default '/etc/ddclient.conf' it will be populated with the various other options in this module. When it is changed (for example: '/root/nixos/secrets/ddclient.conf') the file read directly to configure ddclient. This is a source of impurity.
86 The purpose of this is to avoid placing secrets into the store.
87 '';
88 example = "/root/nixos/secrets/ddclient.conf";
89 };
90
91 protocol = mkOption {
92 default = "dyndns2";
93 type = str;
94 description = ''
95 Protocol to use with dynamic DNS provider (see https://sourceforge.net/p/ddclient/wiki/protocols).
96 '';
97 };
98
99 server = mkOption {
100 default = "";
101 type = str;
102 description = ''
103 Server address.
104 '';
105 };
106
107 ssl = mkOption {
108 default = true;
109 type = bool;
110 description = ''
111 Whether to use to use SSL/TLS to connect to dynamic DNS provider.
112 '';
113 };
114
115
116 quiet = mkOption {
117 default = false;
118 type = bool;
119 description = ''
120 Print no messages for unnecessary updates.
121 '';
122 };
123
124 script = mkOption {
125 default = "";
126 type = str;
127 description = ''
128 script as required by some providers.
129 '';
130 };
131
132 use = mkOption {
133 default = "web, web=checkip.dyndns.com/, web-skip='Current IP Address: '";
134 type = str;
135 description = ''
136 Method to determine the IP address to send to the dynamic DNS provider.
137 '';
138 };
139
140 verbose = mkOption {
141 default = true;
142 type = bool;
143 description = ''
144 Print verbose information.
145 '';
146 };
147
148 zone = mkOption {
149 default = "";
150 type = str;
151 description = ''
152 zone as required by some providers.
153 '';
154 };
155
156 extraConfig = mkOption {
157 default = "";
158 type = lines;
159 description = ''
160 Extra configuration. Contents will be added verbatim to the configuration file.
161 '';
162 };
163 };
164 };
165
166
167 ###### implementation
168
169 config = mkIf config.services.ddclient.enable {
170 environment.etc."ddclient.conf" = {
171 enable = cfg.configFile == "/etc/ddclient.conf";
172 mode = "0600";
173 text = configText;
174 };
175
176 systemd.services.ddclient = {
177 description = "Dynamic DNS Client";
178 wantedBy = [ "multi-user.target" ];
179 after = [ "network.target" ];
180 restartTriggers = [ config.environment.etc."ddclient.conf".source ];
181
182 serviceConfig = rec {
183 DynamicUser = true;
184 RuntimeDirectory = StateDirectory;
185 StateDirectory = builtins.baseNameOf dataDir;
186 Type = "oneshot";
187 ExecStartPre = "!${lib.getBin pkgs.coreutils}/bin/install -m666 ${cfg.configFile} /run/${RuntimeDirectory}/ddclient.conf";
188 ExecStart = "${lib.getBin pkgs.ddclient}/bin/ddclient -file /run/${RuntimeDirectory}/ddclient.conf";
189 };
190 };
191
192 systemd.timers.ddclient = {
193 description = "Run ddclient";
194 wantedBy = [ "timers.target" ];
195 timerConfig = {
196 OnBootSec = cfg.interval;
197 OnUnitInactiveSec = cfg.interval;
198 };
199 };
200 };
201}