First description on how to install and available parameters, etc.
This commit is contained in:
335
README.md
Normal file
335
README.md
Normal file
@@ -0,0 +1,335 @@
|
||||
dyndns.pl
|
||||
=========
|
||||
|
||||
Perl CGI-BIN script to handle Dynamic DNS updates through HTTP (e.g. from a
|
||||
router), updating DNS records through secure DNS update statements.
|
||||
|
||||
**Version 1.0**, latest version, documentation and bugtracker available on my
|
||||
[GitLab instance](https://gitlab.lindenaar.net/scripts/dyndns)
|
||||
|
||||
Copyright (c) 2013 - 2015 Frederik Lindenaar. free for distribution under the
|
||||
GNU License, see [below](#license)
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
This script provides a simple interface to allow Dynamic DNS updates for DNS
|
||||
zones. It is intended to be used for routers and (aDSL) modems to register their
|
||||
IP address by simply opening a URL (this is supported by many modern devices)
|
||||
but can also be used by end-users (either directly by using a client). Please
|
||||
bear in mind that this script suits my setup and still might have glitches, but
|
||||
so far turned out to be a quite stable solution for my needs and I use it in a
|
||||
production setup. In case you have any comments / questions or issues, please
|
||||
raise them through my
|
||||
[GitLab instance](https://gitlab.lindenaar.net/scripts/dyndns) so that all
|
||||
users benefit.
|
||||
|
||||
Setup
|
||||
-----
|
||||
This script is to be executed as CGI-BIN script by a web server. As it is
|
||||
written in Perl, it requires that installed (which is pretty standard nowadays
|
||||
on all *nix platforms). This description covers the installation on Apache 2.4,
|
||||
which should be similar for other web servers, with ISC Bind v9. For performance
|
||||
reasons consider using the Apache mod_perl module for highly a volatile domain.
|
||||
|
||||
The setup of this solution consists of the following steps:
|
||||
|
||||
1. Ensure that the Perl modules CGI and Net::DNS are installed.
|
||||
* on Debian/Ubunto linux this can be done by:
|
||||
|
||||
~~~~
|
||||
sudo apt-get install libcgi-pm-perl libnet-dns-perl
|
||||
~~~~
|
||||
|
||||
* or if you have cpan installed:
|
||||
|
||||
~~~
|
||||
cpan CGI Net::DNS
|
||||
~~~
|
||||
|
||||
2. Install the file `dyndns.pl` either in your cgi-bin directory or in a
|
||||
separate folder
|
||||
|
||||
3. Update the configuration section at the top of the script to match your
|
||||
environment (see the section on [configuration](#configuration) below).
|
||||
The least you need to change `$DNSServer` to point to your DNS server and
|
||||
you probably want to have a look at the `$AllowDebugKey` (useful for
|
||||
getting things started but you want to set this to 'off' in production.
|
||||
|
||||
4. To have a nicer URL (or in case the script is not installed in the web
|
||||
server's cgi-bin directory) add the following line to your Apache virtual
|
||||
host configuration (replacing `[INSTALL_DIR]` with the install directory):
|
||||
|
||||
ScriptAlias /dyndns [INSTALL_DIR]/dyndns.pl
|
||||
|
||||
in case you have installed the script in a non-standard folder, you will
|
||||
also need the following to make this work on Apache 2.4 (again replacing
|
||||
`[INSTALL_DIR]` with the install directory):
|
||||
|
||||
~~~
|
||||
<Directory [INSTALL_DIR]/>
|
||||
AllowOverride None
|
||||
Options +ExecCGI -MultiViews -Indexes
|
||||
Require all granted
|
||||
</Directory>
|
||||
~~~
|
||||
|
||||
reload apache with `/etc/init.d/apache reload` to make the script
|
||||
available at <http://myserver.mydomain.tld/dyndns>
|
||||
|
||||
5. To setup your Bind nameserver, either update `named.conf` direcly or create
|
||||
a separate file (e.g. `named.dyndns.conf` in the Bind configuration
|
||||
directory and include that in your setup with the `include` directive
|
||||
(e.g. `include "named.dyndns.conf";`). For a basic dynamic DNS setup a
|
||||
configuration like below is required:
|
||||
|
||||
~~~
|
||||
// Define the keys for DynDNS
|
||||
key "dyndns.mydomain.tld" {
|
||||
algorithm hmac-md5; secret "QdDJC7QVYmsCxgWoSAUmBg==";
|
||||
};
|
||||
|
||||
key "siteuser" {
|
||||
algorithm hmac-md5; secret "R6Xkbn+FP85Hq3EDNmv+GQ==";
|
||||
};
|
||||
|
||||
// Define the DDNS zone
|
||||
zone "dyndns.mydomain.tld" IN {
|
||||
type master;
|
||||
file "dyndns/db.dyndns.mydomain.tld";
|
||||
|
||||
// enable this for list and expire support
|
||||
// allow-transfer { 192.168.0.2; };
|
||||
|
||||
update-policy {
|
||||
grant dyndns.mydomain.tld zonesub ANY;
|
||||
grant siteuser name site.dyndns.mydomain.tld ANY;
|
||||
};
|
||||
};
|
||||
~~~
|
||||
|
||||
The above defines a domain zone file `dyndns/db.dyndns.mydomain.tld` with
|
||||
two signer/keys. *siteuser* only can update `site.dyndns.mydomain.tld`
|
||||
while *dyndns.mydomain.tld* can update all entries in the domain (intended
|
||||
for expiry). If you intend to use expiry or want to be able to retrieve a
|
||||
list of all entries, comment out the `allow-transfer` statement and update
|
||||
the IP adres to that of your web server.
|
||||
|
||||
To seed these entries with fresh keys), use the following
|
||||
commands and copy the generated keys into the config file.
|
||||
|
||||
* to generate a new key *dyndns.mydomain.tld*:
|
||||
|
||||
~~~
|
||||
ddns-confgen -a hmac-md5 -k dyndns.mydomain.tld -z dyndns.mydomain.tld
|
||||
~~~
|
||||
|
||||
* generate the required configuration for *siteuser* (or any new user):
|
||||
|
||||
~~~
|
||||
ddns-confgen -a hmac-md5 -k siteuser -s site.dyndns.mydomain.tld
|
||||
~~~
|
||||
|
||||
6. Generate an initial zone file like the one below for the dyndns domain in
|
||||
the location specified in the config file above.
|
||||
|
||||
~~~
|
||||
$TTL 3600 ; 1 hour
|
||||
@ IN SOA auth.dns.mydomain.tld. hostmaster.mydomain.tld. (
|
||||
2015051401 ; serial
|
||||
43200 ; refresh (12 hours)
|
||||
3600 ; retry (1 hour)
|
||||
86400 ; expire (24 hours)
|
||||
900 ; minimum (15 minutes)
|
||||
)
|
||||
TXT "Dynamic DNS zone for mydomain.tld"
|
||||
|
||||
site A 1.2.3.4
|
||||
~~~
|
||||
|
||||
Please note that Bind will rewrite this file and you need to be careful
|
||||
with it. Entries do not need to exist initially, as long as the signer/key
|
||||
has access to a hostname, the entry can be created (so the only thing
|
||||
required to setup a new host is to register a signer/key).
|
||||
|
||||
If you do need to update the zone file to change entries, consider using
|
||||
the bind `nsupdate` command instead. If that is inconvenient, the following
|
||||
steps must be followed not to get our of sync with Bind's zone database
|
||||
(please note that when you have views this works slightly differently):
|
||||
|
||||
* execute the command `rndc freeze [zone]`
|
||||
* edit the zone file for [zone]
|
||||
* execute the command `rndc unfreeze [zone]`
|
||||
|
||||
7. Last step is to instruct bind to reload it's configuration (`rndc reload`)
|
||||
and test the setup. please see [below how to invoke the script](#invoking).
|
||||
|
||||
URLs / checks to perform are:
|
||||
|
||||
* <http://myserver.mydomain.tld/dyndns/list?domain=dyndns.mydomain.tld>
|
||||
to list the entries in the domain (requires zone transfer rights!)
|
||||
* <http://myserver.mydomain.tld/dyndns/update?host=site.dyndns.mydomain.tld&user=siteuser&key=......>
|
||||
to add/update a site and
|
||||
* <http://myserver.mydomain.tld/dyndns/delete?host=site.dyndns.mydomain.tld&user=siteuser&key=......>
|
||||
to delete (clear) it.
|
||||
|
||||
Please read the section below as well on the configuration and different modes
|
||||
(operations) available.
|
||||
|
||||
<a name=configuration>Configuration</a>
|
||||
---------------------------------------
|
||||
|
||||
At the top of the script is a "Configuration" section, which contains the
|
||||
configurable options of the scripts.
|
||||
|
||||
Parameter | Description
|
||||
:----------------+:-------------------------------------------------------------
|
||||
`$DNSServer` | IP address of the DNS Server to send DNS update requests to
|
||||
`$ExpandCNAMEs` | Max. CNAME lookups for `$host` (0 to disable), see below
|
||||
`$AllowDebugKey` | Output debug log after result when `debug` parameter equals this value. Set to '' to always enable and to 'off' to disable debugging
|
||||
`$AuthMode` | Defines how to authenticate DNS update requests, see below
|
||||
`$StaticSigner` | Static signer ID to be used for AuthMode `static` or `both`
|
||||
`$StaticKey` | Static signing key to be used for AuthMode `static` or `both`
|
||||
`$RequireRR` | Require an existing DNS record of this type to allow updates.
|
||||
`$ExpireAfter` | Expire time for registrations in minutes, hours, weeks or seconds. Format is number optionally followed by m, h, w, s (seconds is default).
|
||||
`@ReplaceRR` | List of DNS Record types to remove (clear) as part of update.
|
||||
`$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
|
||||
`$DeleteTXT` | Set TXT record upon deletion with this text and a timestamp.
|
||||
|
||||
Please note that the values must be correctly quoted, etc. not to break the script.
|
||||
|
||||
|
||||
#### CNAME Support
|
||||
The script supports using separate subdomain (e.g. dyndns.mydomain.tld) for
|
||||
dynamic DNS and CNAMEs to entries in that subdomain from another zone (e.g.
|
||||
mydomain.tld). The advantage of such a setup is that only one zone (SOA file)
|
||||
within the domain will have frequent updates (and hence requires a short TTL
|
||||
so prevent it from being cached) while the rest of the domain's zones can be
|
||||
cached.
|
||||
|
||||
The user does not have to notice this at all as script supports check whether
|
||||
the host provided is a CNAME and if so, performs the request for the actual
|
||||
hostname instead of the provided one. The value of `$ExpandCNAMEs` determines
|
||||
the maximum number of CNAME lookups supported (so nesting is allowed and this
|
||||
limits the level of nesting to prevent loops).
|
||||
To disable lookups for CNAME expansion, set `$ExpandCNAMEs` to 0.
|
||||
|
||||
|
||||
#### Authentication Modes
|
||||
For signing DNS update requests sent to the DNS server the script supports 3
|
||||
ways to obtain the signer and key:
|
||||
|
||||
AuthMode | Description
|
||||
:--------+:---------------------------------------------------------------------
|
||||
*static* | use only static authentication information from `$StaticSigner` and`$StaticKey` (and ignore authentication information provided in the request)
|
||||
*remote* | use only authentication information provided in the request
|
||||
*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
|
||||
|
||||
|
||||
Supported Operations
|
||||
--------------------
|
||||
The script can perform the following operations (modes):
|
||||
|
||||
Mode | Description | Required Parameters | Optional Parameters
|
||||
:------+:-------------------------+:--------------------+:----------------------
|
||||
list | Show DDNS domain entries | `domain`__**__ |
|
||||
view | Show DDNS hostname entry | `host` |
|
||||
update | Update/add a DDNS host | `host` + auth.__*__ | `ipv4addr`, `ipv6addr`
|
||||
delete | Remove DDNS registration | `host` + auth.__*__ |
|
||||
expire | Expire registrations | `domain`__**__ + auth.__*__
|
||||
|
||||
__*__ Modes that change registrations require authentication, depending on the
|
||||
value of `$AuthMode` the parameters `user` and `secret` may be required
|
||||
(`$AuthMode` *remote*) required or optional (`$AuthMode` *both*)
|
||||
|
||||
__**__ in case `domain` is omitted, it will be determined using the `host`
|
||||
parameter, if provided
|
||||
|
||||
|
||||
#### Parameters
|
||||
The script supports the following parameters (please see the table above for which is needed for what mode):
|
||||
|
||||
Parameter | Description
|
||||
:---------+:--------------------------------------------------------------------
|
||||
`mode` | the action to perform (if not provided as part of the path name)
|
||||
`domain` | domain for list/expire request, determined from `host` if ommitted
|
||||
`host` | hostname to act on, expand CNAMEs max. `$ExpandCNAMEs` levels deep
|
||||
`ip` | alias / shortcut for `ipv4addr`
|
||||
`ipv4addr`| The IPv4 address to register for the host (update mode only) __*__
|
||||
`ipv6addr`| The IPv6 address to register for the host (update mode only) __*__
|
||||
`user` | signer of the DNS Update, used for `AuthMode` *remote* and *both*
|
||||
`key` | key to sign the DNS Update, used for `AuthMode` *remote* and *both*
|
||||
`debug` | debug key, show debug information if this equals `$AllowDebugKey`
|
||||
|
||||
__*__ in update mode, if `ipv4addr` or `ipv6addr` is not provided with the
|
||||
request, the CGI variable `$REMOTE_ADDR` (the client address), its value
|
||||
will be used instead as IPv4/IPv6 address.
|
||||
|
||||
|
||||
#### <a name="invoking">Invoking the script</a>
|
||||
The script is implemented using the perl CGI module so for testing purposes it
|
||||
can be called from the command line with parameters as arguments, i.e.
|
||||
|
||||
./dyndns.pl mode=expire domain=mydomain.tld debug=....
|
||||
|
||||
Which is quite handy for debugging purposes. Please note that the Perl CGI
|
||||
library sets `$REMOTE_ADDR` to 127.0.0.1 and that the output will always be
|
||||
the HTML-based result.
|
||||
|
||||
The standard way to use the script is to place it in the cgi-bin folder your
|
||||
server, which allows it to be called as:
|
||||
|
||||
http://myserver.mydomain.tld/cgi-bin/dyndns.pl?mode=list&domain=mydomain.tld&debug=...
|
||||
|
||||
As per the setup instruction above, there are various ways to make the URL
|
||||
cleaner, i.e.
|
||||
|
||||
http://myserver.mydomain.tld/dyndns?mode=list&domain=mydomain.tld&debug=...
|
||||
|
||||
The script also supports include the mode variable as part of the location
|
||||
(using and the CGI variable `$PATH_INFO` to set the mode), i.e.
|
||||
|
||||
http://myserver.mydomain.tld/cgi-bin/dyndns.pl/list?domain=mydomain.tld&debug=...
|
||||
|
||||
When combining the setup would become:
|
||||
|
||||
http://myserver.mydomain.tld/dyndns/list?domain=mydomain.tld&debug=...
|
||||
|
||||
Which is how I use it.
|
||||
|
||||
|
||||
Name Server Setup Requirements
|
||||
------------------------------
|
||||
As the script is only translating requests, depends heavily on the setup of the
|
||||
nameserver. The DNS server (obviously) needs to allow DNS updates. In addition
|
||||
to the setup described above, please note that:
|
||||
|
||||
* For the modes list and expire to work, the script needs to perform a DNS
|
||||
zone transfer (AXFR). This must be allowed for the host running the script.
|
||||
* for each DDNS host, a signer and key must have the rights to change the
|
||||
entry (one signer/key can be setup to change multiple hosts).
|
||||
* The expire mode requires a signer and key that can change all DDNS hosts
|
||||
within the domain.
|
||||
* The script currently only supports HMAC-MD5 type keys (limitation of the
|
||||
used Perl Net::DNS library). The keys setup in the nameservers must
|
||||
therefore be of the same time or authentication won't work.
|
||||
|
||||
The solution scales reasonable well, although adding the keys to the nameserver
|
||||
configuration is still manual in my setup (but since it does not happen that
|
||||
often, it's no hassle). This setup has been tested against ISC Bind version 9.
|
||||
|
||||
|
||||
<a name="license">License</a>
|
||||
-----------------------------
|
||||
This script, documentation and configration examples are free software: you can
|
||||
redistribute and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
This script, documenatation and configuration examples are distributed in the
|
||||
hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program. If not, download it from <http://www.gnu.org/licenses/>.
|
||||
Reference in New Issue
Block a user