Commit 348b8d9a292ae45029e2a5b59038dfa7d8a759c4
1 parent
e22945cc
First description on how to install and available parameters, etc.
Showing
1 changed file
with
335 additions
and
0 deletions
README.md
0 → 100644
1 | +dyndns.pl | |
2 | +========= | |
3 | + | |
4 | +Perl CGI-BIN script to handle Dynamic DNS updates through HTTP (e.g. from a | |
5 | +router), updating DNS records through secure DNS update statements. | |
6 | + | |
7 | +**Version 1.0**, latest version, documentation and bugtracker available on my | |
8 | +[GitLab instance](https://gitlab.lindenaar.net/scripts/dyndns) | |
9 | + | |
10 | +Copyright (c) 2013 - 2015 Frederik Lindenaar. free for distribution under the | |
11 | +GNU License, see [below](#license) | |
12 | + | |
13 | + | |
14 | +Introduction | |
15 | +------------ | |
16 | +This script provides a simple interface to allow Dynamic DNS updates for DNS | |
17 | +zones. It is intended to be used for routers and (aDSL) modems to register their | |
18 | +IP address by simply opening a URL (this is supported by many modern devices) | |
19 | +but can also be used by end-users (either directly by using a client). Please | |
20 | +bear in mind that this script suits my setup and still might have glitches, but | |
21 | +so far turned out to be a quite stable solution for my needs and I use it in a | |
22 | +production setup. In case you have any comments / questions or issues, please | |
23 | +raise them through my | |
24 | +[GitLab instance](https://gitlab.lindenaar.net/scripts/dyndns) so that all | |
25 | +users benefit. | |
26 | + | |
27 | +Setup | |
28 | +----- | |
29 | +This script is to be executed as CGI-BIN script by a web server. As it is | |
30 | +written in Perl, it requires that installed (which is pretty standard nowadays | |
31 | +on all *nix platforms). This description covers the installation on Apache 2.4, | |
32 | +which should be similar for other web servers, with ISC Bind v9. For performance | |
33 | +reasons consider using the Apache mod_perl module for highly a volatile domain. | |
34 | + | |
35 | +The setup of this solution consists of the following steps: | |
36 | + | |
37 | + 1. Ensure that the Perl modules CGI and Net::DNS are installed. | |
38 | + * on Debian/Ubunto linux this can be done by: | |
39 | + | |
40 | + ~~~~ | |
41 | + sudo apt-get install libcgi-pm-perl libnet-dns-perl | |
42 | + ~~~~ | |
43 | + | |
44 | + * or if you have cpan installed: | |
45 | + | |
46 | + ~~~ | |
47 | + cpan CGI Net::DNS | |
48 | + ~~~ | |
49 | + | |
50 | + 2. Install the file `dyndns.pl` either in your cgi-bin directory or in a | |
51 | + separate folder | |
52 | + | |
53 | + 3. Update the configuration section at the top of the script to match your | |
54 | + environment (see the section on [configuration](#configuration) below). | |
55 | + The least you need to change `$DNSServer` to point to your DNS server and | |
56 | + you probably want to have a look at the `$AllowDebugKey` (useful for | |
57 | + getting things started but you want to set this to 'off' in production. | |
58 | + | |
59 | + 4. To have a nicer URL (or in case the script is not installed in the web | |
60 | + server's cgi-bin directory) add the following line to your Apache virtual | |
61 | + host configuration (replacing `[INSTALL_DIR]` with the install directory): | |
62 | + | |
63 | + ScriptAlias /dyndns [INSTALL_DIR]/dyndns.pl | |
64 | + | |
65 | + in case you have installed the script in a non-standard folder, you will | |
66 | + also need the following to make this work on Apache 2.4 (again replacing | |
67 | + `[INSTALL_DIR]` with the install directory): | |
68 | + | |
69 | + ~~~ | |
70 | + <Directory [INSTALL_DIR]/> | |
71 | + AllowOverride None | |
72 | + Options +ExecCGI -MultiViews -Indexes | |
73 | + Require all granted | |
74 | + </Directory> | |
75 | + ~~~ | |
76 | + | |
77 | + reload apache with `/etc/init.d/apache reload` to make the script | |
78 | + available at <http://myserver.mydomain.tld/dyndns> | |
79 | + | |
80 | + 5. To setup your Bind nameserver, either update `named.conf` direcly or create | |
81 | + a separate file (e.g. `named.dyndns.conf` in the Bind configuration | |
82 | + directory and include that in your setup with the `include` directive | |
83 | + (e.g. `include "named.dyndns.conf";`). For a basic dynamic DNS setup a | |
84 | + configuration like below is required: | |
85 | + | |
86 | + ~~~ | |
87 | + // Define the keys for DynDNS | |
88 | + key "dyndns.mydomain.tld" { | |
89 | + algorithm hmac-md5; secret "QdDJC7QVYmsCxgWoSAUmBg=="; | |
90 | + }; | |
91 | + | |
92 | + key "siteuser" { | |
93 | + algorithm hmac-md5; secret "R6Xkbn+FP85Hq3EDNmv+GQ=="; | |
94 | + }; | |
95 | + | |
96 | + // Define the DDNS zone | |
97 | + zone "dyndns.mydomain.tld" IN { | |
98 | + type master; | |
99 | + file "dyndns/db.dyndns.mydomain.tld"; | |
100 | + | |
101 | + // enable this for list and expire support | |
102 | + // allow-transfer { 192.168.0.2; }; | |
103 | + | |
104 | + update-policy { | |
105 | + grant dyndns.mydomain.tld zonesub ANY; | |
106 | + grant siteuser name site.dyndns.mydomain.tld ANY; | |
107 | + }; | |
108 | + }; | |
109 | + ~~~ | |
110 | + | |
111 | + The above defines a domain zone file `dyndns/db.dyndns.mydomain.tld` with | |
112 | + two signer/keys. *siteuser* only can update `site.dyndns.mydomain.tld` | |
113 | + while *dyndns.mydomain.tld* can update all entries in the domain (intended | |
114 | + for expiry). If you intend to use expiry or want to be able to retrieve a | |
115 | + list of all entries, comment out the `allow-transfer` statement and update | |
116 | + the IP adres to that of your web server. | |
117 | + | |
118 | + To seed these entries with fresh keys), use the following | |
119 | + commands and copy the generated keys into the config file. | |
120 | + | |
121 | + * to generate a new key *dyndns.mydomain.tld*: | |
122 | + | |
123 | + ~~~ | |
124 | + ddns-confgen -a hmac-md5 -k dyndns.mydomain.tld -z dyndns.mydomain.tld | |
125 | + ~~~ | |
126 | + | |
127 | + * generate the required configuration for *siteuser* (or any new user): | |
128 | + | |
129 | + ~~~ | |
130 | + ddns-confgen -a hmac-md5 -k siteuser -s site.dyndns.mydomain.tld | |
131 | + ~~~ | |
132 | + | |
133 | + 6. Generate an initial zone file like the one below for the dyndns domain in | |
134 | + the location specified in the config file above. | |
135 | + | |
136 | + ~~~ | |
137 | + $TTL 3600 ; 1 hour | |
138 | + @ IN SOA auth.dns.mydomain.tld. hostmaster.mydomain.tld. ( | |
139 | + 2015051401 ; serial | |
140 | + 43200 ; refresh (12 hours) | |
141 | + 3600 ; retry (1 hour) | |
142 | + 86400 ; expire (24 hours) | |
143 | + 900 ; minimum (15 minutes) | |
144 | + ) | |
145 | + TXT "Dynamic DNS zone for mydomain.tld" | |
146 | + | |
147 | + site A 1.2.3.4 | |
148 | + ~~~ | |
149 | + | |
150 | + Please note that Bind will rewrite this file and you need to be careful | |
151 | + with it. Entries do not need to exist initially, as long as the signer/key | |
152 | + has access to a hostname, the entry can be created (so the only thing | |
153 | + required to setup a new host is to register a signer/key). | |
154 | + | |
155 | + If you do need to update the zone file to change entries, consider using | |
156 | + the bind `nsupdate` command instead. If that is inconvenient, the following | |
157 | + steps must be followed not to get our of sync with Bind's zone database | |
158 | + (please note that when you have views this works slightly differently): | |
159 | + | |
160 | + * execute the command `rndc freeze [zone]` | |
161 | + * edit the zone file for [zone] | |
162 | + * execute the command `rndc unfreeze [zone]` | |
163 | + | |
164 | + 7. Last step is to instruct bind to reload it's configuration (`rndc reload`) | |
165 | + and test the setup. please see [below how to invoke the script](#invoking). | |
166 | + | |
167 | + URLs / checks to perform are: | |
168 | + | |
169 | + * <http://myserver.mydomain.tld/dyndns/list?domain=dyndns.mydomain.tld> | |
170 | + to list the entries in the domain (requires zone transfer rights!) | |
171 | + * <http://myserver.mydomain.tld/dyndns/update?host=site.dyndns.mydomain.tld&user=siteuser&key=......> | |
172 | + to add/update a site and | |
173 | + * <http://myserver.mydomain.tld/dyndns/delete?host=site.dyndns.mydomain.tld&user=siteuser&key=......> | |
174 | + to delete (clear) it. | |
175 | + | |
176 | +Please read the section below as well on the configuration and different modes | |
177 | +(operations) available. | |
178 | + | |
179 | +<a name=configuration>Configuration</a> | |
180 | +--------------------------------------- | |
181 | + | |
182 | +At the top of the script is a "Configuration" section, which contains the | |
183 | +configurable options of the scripts. | |
184 | + | |
185 | +Parameter | Description | |
186 | +:----------------+:------------------------------------------------------------- | |
187 | +`$DNSServer` | IP address of the DNS Server to send DNS update requests to | |
188 | +`$ExpandCNAMEs` | Max. CNAME lookups for `$host` (0 to disable), see below | |
189 | +`$AllowDebugKey` | Output debug log after result when `debug` parameter equals this value. Set to '' to always enable and to 'off' to disable debugging | |
190 | +`$AuthMode` | Defines how to authenticate DNS update requests, see below | |
191 | +`$StaticSigner` | Static signer ID to be used for AuthMode `static` or `both` | |
192 | +`$StaticKey` | Static signing key to be used for AuthMode `static` or `both` | |
193 | +`$RequireRR` | Require an existing DNS record of this type to allow updates. | |
194 | +`$ExpireAfter` | Expire time for registrations in minutes, hours, weeks or seconds. Format is number optionally followed by m, h, w, s (seconds is default). | |
195 | +`@ReplaceRR` | List of DNS Record types to remove (clear) as part of update. | |
196 | +`$UpdateTXT` | Add host TXT record during update with this text followed by a timestamp. Used for expiry (so don't change!), leave empty to not add this | |
197 | +`$DeleteTXT` | Set TXT record upon deletion with this text and a timestamp. | |
198 | + | |
199 | +Please note that the values must be correctly quoted, etc. not to break the script. | |
200 | + | |
201 | + | |
202 | +#### CNAME Support | |
203 | +The script supports using separate subdomain (e.g. dyndns.mydomain.tld) for | |
204 | +dynamic DNS and CNAMEs to entries in that subdomain from another zone (e.g. | |
205 | +mydomain.tld). The advantage of such a setup is that only one zone (SOA file) | |
206 | +within the domain will have frequent updates (and hence requires a short TTL | |
207 | +so prevent it from being cached) while the rest of the domain's zones can be | |
208 | +cached. | |
209 | + | |
210 | +The user does not have to notice this at all as script supports check whether | |
211 | +the host provided is a CNAME and if so, performs the request for the actual | |
212 | +hostname instead of the provided one. The value of `$ExpandCNAMEs` determines | |
213 | +the maximum number of CNAME lookups supported (so nesting is allowed and this | |
214 | +limits the level of nesting to prevent loops). | |
215 | +To disable lookups for CNAME expansion, set `$ExpandCNAMEs` to 0. | |
216 | + | |
217 | + | |
218 | +#### Authentication Modes | |
219 | +For signing DNS update requests sent to the DNS server the script supports 3 | |
220 | +ways to obtain the signer and key: | |
221 | + | |
222 | +AuthMode | Description | |
223 | +:--------+:--------------------------------------------------------------------- | |
224 | +*static* | use only static authentication information from `$StaticSigner` and`$StaticKey` (and ignore authentication information provided in the request) | |
225 | +*remote* | use only authentication information provided in the request | |
226 | +*both* | use authentication information provided in the request (fields `user` and `secret`) when provided, otherwise use static values from `$StaticSigner` and `$StaticKey`. Please note that this is checked per parameter | |
227 | + | |
228 | + | |
229 | +Supported Operations | |
230 | +-------------------- | |
231 | +The script can perform the following operations (modes): | |
232 | + | |
233 | +Mode | Description | Required Parameters | Optional Parameters | |
234 | +:------+:-------------------------+:--------------------+:---------------------- | |
235 | +list | Show DDNS domain entries | `domain`__**__ | | |
236 | +view | Show DDNS hostname entry | `host` | | |
237 | +update | Update/add a DDNS host | `host` + auth.__*__ | `ipv4addr`, `ipv6addr` | |
238 | +delete | Remove DDNS registration | `host` + auth.__*__ | | |
239 | +expire | Expire registrations | `domain`__**__ + auth.__*__ | |
240 | + | |
241 | +__*__ Modes that change registrations require authentication, depending on the | |
242 | + value of `$AuthMode` the parameters `user` and `secret` may be required | |
243 | + (`$AuthMode` *remote*) required or optional (`$AuthMode` *both*) | |
244 | + | |
245 | +__**__ in case `domain` is omitted, it will be determined using the `host` | |
246 | + parameter, if provided | |
247 | + | |
248 | + | |
249 | +#### Parameters | |
250 | +The script supports the following parameters (please see the table above for which is needed for what mode): | |
251 | + | |
252 | +Parameter | Description | |
253 | +:---------+:-------------------------------------------------------------------- | |
254 | +`mode` | the action to perform (if not provided as part of the path name) | |
255 | +`domain` | domain for list/expire request, determined from `host` if ommitted | |
256 | +`host` | hostname to act on, expand CNAMEs max. `$ExpandCNAMEs` levels deep | |
257 | +`ip` | alias / shortcut for `ipv4addr` | |
258 | +`ipv4addr`| The IPv4 address to register for the host (update mode only) __*__ | |
259 | +`ipv6addr`| The IPv6 address to register for the host (update mode only) __*__ | |
260 | +`user` | signer of the DNS Update, used for `AuthMode` *remote* and *both* | |
261 | +`key` | key to sign the DNS Update, used for `AuthMode` *remote* and *both* | |
262 | +`debug` | debug key, show debug information if this equals `$AllowDebugKey` | |
263 | + | |
264 | +__*__ in update mode, if `ipv4addr` or `ipv6addr` is not provided with the | |
265 | + request, the CGI variable `$REMOTE_ADDR` (the client address), its value | |
266 | + will be used instead as IPv4/IPv6 address. | |
267 | + | |
268 | + | |
269 | +#### <a name="invoking">Invoking the script</a> | |
270 | +The script is implemented using the perl CGI module so for testing purposes it | |
271 | +can be called from the command line with parameters as arguments, i.e. | |
272 | + | |
273 | + ./dyndns.pl mode=expire domain=mydomain.tld debug=.... | |
274 | + | |
275 | +Which is quite handy for debugging purposes. Please note that the Perl CGI | |
276 | +library sets `$REMOTE_ADDR` to 127.0.0.1 and that the output will always be | |
277 | +the HTML-based result. | |
278 | + | |
279 | +The standard way to use the script is to place it in the cgi-bin folder your | |
280 | +server, which allows it to be called as: | |
281 | + | |
282 | + http://myserver.mydomain.tld/cgi-bin/dyndns.pl?mode=list&domain=mydomain.tld&debug=... | |
283 | + | |
284 | +As per the setup instruction above, there are various ways to make the URL | |
285 | +cleaner, i.e. | |
286 | + | |
287 | + http://myserver.mydomain.tld/dyndns?mode=list&domain=mydomain.tld&debug=... | |
288 | + | |
289 | +The script also supports include the mode variable as part of the location | |
290 | +(using and the CGI variable `$PATH_INFO` to set the mode), i.e. | |
291 | + | |
292 | + http://myserver.mydomain.tld/cgi-bin/dyndns.pl/list?domain=mydomain.tld&debug=... | |
293 | + | |
294 | +When combining the setup would become: | |
295 | + | |
296 | + http://myserver.mydomain.tld/dyndns/list?domain=mydomain.tld&debug=... | |
297 | + | |
298 | +Which is how I use it. | |
299 | + | |
300 | + | |
301 | +Name Server Setup Requirements | |
302 | +------------------------------ | |
303 | +As the script is only translating requests, depends heavily on the setup of the | |
304 | +nameserver. The DNS server (obviously) needs to allow DNS updates. In addition | |
305 | +to the setup described above, please note that: | |
306 | + | |
307 | + * For the modes list and expire to work, the script needs to perform a DNS | |
308 | + zone transfer (AXFR). This must be allowed for the host running the script. | |
309 | + * for each DDNS host, a signer and key must have the rights to change the | |
310 | + entry (one signer/key can be setup to change multiple hosts). | |
311 | + * The expire mode requires a signer and key that can change all DDNS hosts | |
312 | + within the domain. | |
313 | + * The script currently only supports HMAC-MD5 type keys (limitation of the | |
314 | + used Perl Net::DNS library). The keys setup in the nameservers must | |
315 | + therefore be of the same time or authentication won't work. | |
316 | + | |
317 | +The solution scales reasonable well, although adding the keys to the nameserver | |
318 | +configuration is still manual in my setup (but since it does not happen that | |
319 | +often, it's no hassle). This setup has been tested against ISC Bind version 9. | |
320 | + | |
321 | + | |
322 | +<a name="license">License</a> | |
323 | +----------------------------- | |
324 | +This script, documentation and configration examples are free software: you can | |
325 | +redistribute and/or modify it under the terms of the GNU General Public License | |
326 | +as published by the Free Software Foundation, either version 3 of the License, | |
327 | +or (at your option) any later version. | |
328 | + | |
329 | +This script, documenatation and configuration examples are distributed in the | |
330 | +hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied | |
331 | +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
332 | +General Public License for more details. | |
333 | + | |
334 | +You should have received a copy of the GNU General Public License along with | |
335 | +this program. If not, download it from <http://www.gnu.org/licenses/>. | |
... | ... |